DOLFINx 0.8.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
DirichletBC.h
1// Copyright (C) 2007-2021 Michal Habera, Anders Logg, Garth N. Wells
2// and Jørgen S.Dokken
3//
4// This file is part of DOLFINx (https://www.fenicsproject.org)
5//
6// SPDX-License-Identifier: LGPL-3.0-or-later
7
8#pragma once
9
10#include "Constant.h"
11#include "DofMap.h"
12#include "Function.h"
13#include "FunctionSpace.h"
14#include <array>
15#include <concepts>
16#include <dolfinx/common/types.h>
17#include <functional>
18#include <memory>
19#include <span>
20#include <type_traits>
21#include <utility>
22#include <variant>
23#include <vector>
24
25namespace dolfinx::fem
26{
27
53std::vector<std::int32_t>
54locate_dofs_topological(const mesh::Topology& topology, const DofMap& dofmap,
55 int dim, std::span<const std::int32_t> entities,
56 bool remote = true);
57
84std::array<std::vector<std::int32_t>, 2> locate_dofs_topological(
85 const mesh::Topology& topology,
86 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps, int dim,
87 std::span<const std::int32_t> entities, bool remote = true);
88
100template <std::floating_point T, typename U>
101std::vector<std::int32_t> locate_dofs_geometrical(const FunctionSpace<T>& V,
102 U marker_fn)
103{
104 // FIXME: Calling V.tabulate_dof_coordinates() is very expensive,
105 // especially when we usually want the boundary dofs only. Add
106 // interface that computes dofs coordinates only for specified cell.
107
108 assert(V.element());
109 if (V.element()->is_mixed())
110 {
111 throw std::runtime_error(
112 "Cannot locate dofs geometrically for mixed space. Use subspaces.");
113 }
114
115 // Compute dof coordinates
116 const std::vector<T> dof_coordinates = V.tabulate_dof_coordinates(true);
117
118 using cmdspan3x_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
119 const T,
120 MDSPAN_IMPL_STANDARD_NAMESPACE::extents<
121 std::size_t, 3, MDSPAN_IMPL_STANDARD_NAMESPACE::dynamic_extent>>;
122
123 // Compute marker for each dof coordinate
124 cmdspan3x_t x(dof_coordinates.data(), 3, dof_coordinates.size() / 3);
125 const std::vector<std::int8_t> marked_dofs = marker_fn(x);
126
127 std::vector<std::int32_t> dofs;
128 dofs.reserve(std::count(marked_dofs.begin(), marked_dofs.end(), true));
129 for (std::size_t i = 0; i < marked_dofs.size(); ++i)
130 {
131 if (marked_dofs[i])
132 dofs.push_back(i);
133 }
134
135 return dofs;
136}
137
151template <std::floating_point T, typename U>
152std::array<std::vector<std::int32_t>, 2> locate_dofs_geometrical(
153 const std::array<std::reference_wrapper<const FunctionSpace<T>>, 2>& V,
154 U marker_fn)
155{
156 // FIXME: Calling V.tabulate_dof_coordinates() is very expensive,
157 // especially when we usually want the boundary dofs only. Add
158 // interface that computes dofs coordinates only for specified cell.
159
160 // Get function spaces
161 const FunctionSpace<T>& V0 = V.at(0).get();
162 const FunctionSpace<T>& V1 = V.at(1).get();
163
164 // Get mesh
165 auto mesh = V0.mesh();
166 assert(mesh);
167 assert(V1.mesh());
168 if (mesh != V1.mesh())
169 throw std::runtime_error("Meshes are not the same.");
170 const int tdim = mesh->topology()->dim();
171
172 assert(V0.element());
173 assert(V1.element());
174 if (*V0.element() != *V1.element())
175 throw std::runtime_error("Function spaces must have the same element.");
176
177 // Compute dof coordinates
178 const std::vector<T> dof_coordinates = V1.tabulate_dof_coordinates(true);
179
180 using cmdspan3x_t = MDSPAN_IMPL_STANDARD_NAMESPACE::mdspan<
181 const T,
182 MDSPAN_IMPL_STANDARD_NAMESPACE::extents<
183 std::size_t, 3, MDSPAN_IMPL_STANDARD_NAMESPACE::dynamic_extent>>;
184
185 // Evaluate marker for each dof coordinate
186 cmdspan3x_t x(dof_coordinates.data(), 3, dof_coordinates.size() / 3);
187 const std::vector<std::int8_t> marked_dofs = marker_fn(x);
188
189 // Get dofmaps
190 std::shared_ptr<const DofMap> dofmap0 = V0.dofmap();
191 assert(dofmap0);
192 const int bs0 = dofmap0->bs();
193 std::shared_ptr<const DofMap> dofmap1 = V1.dofmap();
194 assert(dofmap1);
195 const int bs1 = dofmap1->bs();
196
197 const int element_bs = dofmap0->element_dof_layout().block_size();
198 assert(element_bs == dofmap1->element_dof_layout().block_size());
199
200 // Iterate over cells
201 auto topology = mesh->topology();
202 assert(topology);
203 std::vector<std::array<std::int32_t, 2>> bc_dofs;
204 for (int c = 0; c < topology->connectivity(tdim, 0)->num_nodes(); ++c)
205 {
206 // Get cell dofmaps
207 auto cell_dofs0 = dofmap0->cell_dofs(c);
208 auto cell_dofs1 = dofmap1->cell_dofs(c);
209
210 // Loop over cell dofs and add to bc_dofs if marked.
211 for (std::size_t i = 0; i < cell_dofs1.size(); ++i)
212 {
213 if (marked_dofs[cell_dofs1[i]])
214 {
215 // Unroll over blocks
216 for (int k = 0; k < element_bs; ++k)
217 {
218 const int local_pos = element_bs * i + k;
219 const std::div_t pos0 = std::div(local_pos, bs0);
220 const std::div_t pos1 = std::div(local_pos, bs1);
221 const std::int32_t dof_index0
222 = bs0 * cell_dofs0[pos0.quot] + pos0.rem;
223 const std::int32_t dof_index1
224 = bs1 * cell_dofs1[pos1.quot] + pos1.rem;
225 bc_dofs.push_back({dof_index0, dof_index1});
226 }
227 }
228 }
229 }
230
231 // Remove duplicates
232 std::sort(bc_dofs.begin(), bc_dofs.end());
233 bc_dofs.erase(std::unique(bc_dofs.begin(), bc_dofs.end()), bc_dofs.end());
234
235 // Copy to separate array
236 std::array dofs = {std::vector<std::int32_t>(bc_dofs.size()),
237 std::vector<std::int32_t>(bc_dofs.size())};
238 std::transform(bc_dofs.cbegin(), bc_dofs.cend(), dofs[0].begin(),
239 [](auto dof) { return dof[0]; });
240 std::transform(bc_dofs.cbegin(), bc_dofs.cend(), dofs[1].begin(),
241 [](auto dof) { return dof[1]; });
242
243 return dofs;
244}
245
256template <dolfinx::scalar T,
257 std::floating_point U = dolfinx::scalar_value_type_t<T>>
259{
260private:
263 std::size_t num_owned(const DofMap& dofmap,
264 std::span<const std::int32_t> dofs)
265 {
266 int bs = dofmap.index_map_bs();
267 std::int32_t map_size = dofmap.index_map->size_local();
268 std::int32_t owned_size = bs * map_size;
269 auto it = std::lower_bound(dofs.begin(), dofs.end(), owned_size);
270 return std::distance(dofs.begin(), it);
271 }
272
274 static std::vector<std::int32_t>
275 unroll_dofs(std::span<const std::int32_t> dofs, int bs)
276 {
277 std::vector<std::int32_t> dofs_unrolled(bs * dofs.size());
278 for (std::size_t i = 0; i < dofs.size(); ++i)
279 for (int k = 0; k < bs; ++k)
280 dofs_unrolled[bs * i + k] = bs * dofs[i] + k;
281 return dofs_unrolled;
282 }
283
284public:
302 template <typename S, typename X,
303 typename
304 = std::enable_if_t<std::is_convertible_v<S, T>
305 or std::is_convertible_v<S, std::span<const T>>>>
306 requires std::is_convertible_v<std::remove_cvref_t<X>,
307 std::vector<std::int32_t>>
308 DirichletBC(const S& g, X&& dofs, std::shared_ptr<const FunctionSpace<U>> V)
309 : DirichletBC(std::make_shared<Constant<T>>(g), dofs, V)
310 {
311 }
312
328 template <typename X>
329 requires std::is_convertible_v<std::remove_cvref_t<X>,
330 std::vector<std::int32_t>>
331 DirichletBC(std::shared_ptr<const Constant<T>> g, X&& dofs,
332 std::shared_ptr<const FunctionSpace<U>> V)
333 : _function_space(V), _g(g), _dofs0(std::forward<X>(dofs)),
334 _owned_indices0(num_owned(*V->dofmap(), _dofs0))
335 {
336 assert(g);
337 assert(V);
338 if (g->shape.size() != V->value_shape().size())
339 {
340 throw std::runtime_error(
341 "Rank mis-match between Constant and function space in DirichletBC");
342 }
343
344 if (g->value.size() != _function_space->dofmap()->bs())
345 {
346 throw std::runtime_error(
347 "Creating a DirichletBC using a Constant is not supported when the "
348 "Constant size is not equal to the block size of the constrained "
349 "(sub-)space. Use a fem::Function to create the fem::DirichletBC.");
350 }
351
352 if (!V->element()->interpolation_ident())
353 {
354 throw std::runtime_error(
355 "Constant can be used only with point-evaluation elements");
356 }
357
358 // Unroll _dofs0 if dofmap block size > 1
359 if (const int bs = V->dofmap()->bs(); bs > 1)
360 {
361 _owned_indices0 *= bs;
362 _dofs0 = unroll_dofs(_dofs0, bs);
363 }
364 }
365
378 template <typename X>
379 requires std::is_convertible_v<std::remove_cvref_t<X>,
380 std::vector<std::int32_t>>
381 DirichletBC(std::shared_ptr<const Function<T, U>> g, X&& dofs)
382 : _function_space(g->function_space()), _g(g),
383 _dofs0(std::forward<X>(dofs)),
384 _owned_indices0(num_owned(*_function_space->dofmap(), _dofs0))
385 {
386 assert(_function_space);
387
388 // Unroll _dofs0 if dofmap block size > 1
389 if (const int bs = _function_space->dofmap()->bs(); bs > 1)
390 {
391 _owned_indices0 *= bs;
392 _dofs0 = unroll_dofs(_dofs0, bs);
393 }
394 }
395
417 template <typename X>
418 DirichletBC(std::shared_ptr<const Function<T, U>> g, X&& V_g_dofs,
419 std::shared_ptr<const FunctionSpace<U>> V)
420 : _function_space(V), _g(g),
421 _dofs0(std::forward<typename X::value_type>(V_g_dofs[0])),
422 _dofs1_g(std::forward<typename X::value_type>(V_g_dofs[1])),
423 _owned_indices0(num_owned(*_function_space->dofmap(), _dofs0))
424 {
425 }
426
429 DirichletBC(const DirichletBC& bc) = default;
430
433 DirichletBC(DirichletBC&& bc) = default;
434
436 ~DirichletBC() = default;
437
440 DirichletBC& operator=(const DirichletBC& bc) = default;
441
444
447 std::shared_ptr<const FunctionSpace<U>> function_space() const
448 {
449 return _function_space;
450 }
451
454 std::variant<std::shared_ptr<const Function<T, U>>,
455 std::shared_ptr<const Constant<T>>>
456 value() const
457 {
458 return _g;
459 }
460
467 std::pair<std::span<const std::int32_t>, std::int32_t> dof_indices() const
468 {
469 return {_dofs0, _owned_indices0};
470 }
471
483 void set(std::span<T> x, T scale = 1) const
484 {
485 if (std::holds_alternative<std::shared_ptr<const Function<T, U>>>(_g))
486 {
487 auto g = std::get<std::shared_ptr<const Function<T, U>>>(_g);
488 assert(g);
489 std::span<const T> values = g->x()->array();
490 auto dofs1_g = _dofs1_g.empty() ? std::span(_dofs0) : std::span(_dofs1_g);
491 std::int32_t x_size = x.size();
492 for (std::size_t i = 0; i < _dofs0.size(); ++i)
493 {
494 if (_dofs0[i] < x_size)
495 {
496 assert(dofs1_g[i] < (std::int32_t)values.size());
497 x[_dofs0[i]] = scale * values[dofs1_g[i]];
498 }
499 }
500 }
501 else if (std::holds_alternative<std::shared_ptr<const Constant<T>>>(_g))
502 {
503 auto g = std::get<std::shared_ptr<const Constant<T>>>(_g);
504 std::vector<T> value = g->value;
505 int bs = _function_space->dofmap()->bs();
506 std::int32_t x_size = x.size();
507 std::for_each(_dofs0.cbegin(), _dofs0.cend(),
508 [x_size, bs, scale, &value, &x](auto dof)
509 {
510 if (dof < x_size)
511 x[dof] = scale * value[dof % bs];
512 });
513 }
514 }
515
520 void set(std::span<T> x, std::span<const T> x0, T scale = 1) const
521 {
522 if (std::holds_alternative<std::shared_ptr<const Function<T, U>>>(_g))
523 {
524 auto g = std::get<std::shared_ptr<const Function<T, U>>>(_g);
525 assert(g);
526 std::span<const T> values = g->x()->array();
527 assert(x.size() <= x0.size());
528 auto dofs1_g = _dofs1_g.empty() ? std::span(_dofs0) : std::span(_dofs1_g);
529 std::int32_t x_size = x.size();
530 for (std::size_t i = 0; i < _dofs0.size(); ++i)
531 {
532 if (_dofs0[i] < x_size)
533 {
534 assert(dofs1_g[i] < (std::int32_t)values.size());
535 x[_dofs0[i]] = scale * (values[dofs1_g[i]] - x0[_dofs0[i]]);
536 }
537 }
538 }
539 else if (std::holds_alternative<std::shared_ptr<const Constant<T>>>(_g))
540 {
541 auto g = std::get<std::shared_ptr<const Constant<T>>>(_g);
542 const std::vector<T>& value = g->value;
543 std::int32_t bs = _function_space->dofmap()->bs();
544 std::for_each(_dofs0.begin(), _dofs0.end(),
545 [&x, &x0, &value, scale, bs](auto dof)
546 {
547 if (dof < (std::int32_t)x.size())
548 x[dof] = scale * (value[dof % bs] - x0[dof]);
549 });
550 }
551 }
552
561 void dof_values(std::span<T> values) const
562 {
563 if (std::holds_alternative<std::shared_ptr<const Function<T, U>>>(_g))
564 {
565 auto g = std::get<std::shared_ptr<const Function<T, U>>>(_g);
566 assert(g);
567 std::span<const T> g_values = g->x()->array();
568 auto dofs1_g = _dofs1_g.empty() ? std::span(_dofs0) : std::span(_dofs1_g);
569 for (std::size_t i = 0; i < dofs1_g.size(); ++i)
570 values[_dofs0[i]] = g_values[dofs1_g[i]];
571 }
572 else if (std::holds_alternative<std::shared_ptr<const Constant<T>>>(_g))
573 {
574 auto g = std::get<std::shared_ptr<const Constant<T>>>(_g);
575 assert(g);
576 const std::vector<T>& g_value = g->value;
577 const std::int32_t bs = _function_space->dofmap()->bs();
578 for (std::size_t i = 0; i < _dofs0.size(); ++i)
579 values[_dofs0[i]] = g_value[_dofs0[i] % bs];
580 }
581 }
582
589 void mark_dofs(std::span<std::int8_t> markers) const
590 {
591 for (std::size_t i = 0; i < _dofs0.size(); ++i)
592 {
593 assert(_dofs0[i] < (std::int32_t)markers.size());
594 markers[_dofs0[i]] = true;
595 }
596 }
597
598private:
599 // The function space (possibly a sub function space)
600 std::shared_ptr<const FunctionSpace<U>> _function_space;
601
602 // The function
603 std::variant<std::shared_ptr<const Function<T, U>>,
604 std::shared_ptr<const Constant<T>>>
605 _g;
606
607 // Dof indices (_dofs0) in _function_space and (_dofs1_g) in the
608 // space of _g. _dofs1_g may be empty if _dofs0 can be re-used
609 std::vector<std::int32_t> _dofs0, _dofs1_g;
610
611 // The first _owned_indices in _dofs are owned by this process
612 std::int32_t _owned_indices0 = -1;
613};
614} // namespace dolfinx::fem
Degree-of-freedom map representations and tools.
Constant value which can be attached to a Form.
Definition Constant.h:23
Definition DirichletBC.h:259
void dof_values(std::span< T > values) const
Definition DirichletBC.h:561
void set(std::span< T > x, T scale=1) const
Definition DirichletBC.h:483
DirichletBC & operator=(const DirichletBC &bc)=default
DirichletBC(std::shared_ptr< const Constant< T > > g, X &&dofs, std::shared_ptr< const FunctionSpace< U > > V)
Create a representation of a Dirichlet boundary condition constrained by a fem::Constant.
Definition DirichletBC.h:331
std::variant< std::shared_ptr< const Function< T, U > >, std::shared_ptr< const Constant< T > > > value() const
Definition DirichletBC.h:456
DirichletBC(const DirichletBC &bc)=default
DirichletBC(DirichletBC &&bc)=default
std::pair< std::span< const std::int32_t >, std::int32_t > dof_indices() const
Definition DirichletBC.h:467
std::shared_ptr< const FunctionSpace< U > > function_space() const
Definition DirichletBC.h:447
void set(std::span< T > x, std::span< const T > x0, T scale=1) const
Definition DirichletBC.h:520
~DirichletBC()=default
Destructor.
DirichletBC(std::shared_ptr< const Function< T, U > > g, X &&dofs)
Create a representation of a Dirichlet boundary condition where the space being constrained is the sa...
Definition DirichletBC.h:381
DirichletBC & operator=(DirichletBC &&bc)=default
Move assignment operator.
DirichletBC(const S &g, X &&dofs, std::shared_ptr< const FunctionSpace< U > > V)
Create a representation of a Dirichlet boundary condition constrained by a scalar- or vector-valued c...
Definition DirichletBC.h:308
void mark_dofs(std::span< std::int8_t > markers) const
Definition DirichletBC.h:589
DirichletBC(std::shared_ptr< const Function< T, U > > g, X &&V_g_dofs, std::shared_ptr< const FunctionSpace< U > > V)
Create a representation of a Dirichlet boundary condition where the space being constrained and the f...
Definition DirichletBC.h:418
Degree-of-freedom map.
Definition DofMap.h:76
std::shared_ptr< const common::IndexMap > index_map
Index map that describes the parallel distribution of the dofmap.
Definition DofMap.h:171
int index_map_bs() const
Block size associated with the index_map.
Definition DofMap.cpp:282
This class represents a finite element function space defined by a mesh, a finite element,...
Definition FunctionSpace.h:34
std::shared_ptr< const DofMap > dofmap() const
The dofmap.
Definition FunctionSpace.h:335
std::shared_ptr< const mesh::Mesh< geometry_type > > mesh() const
The mesh.
Definition FunctionSpace.h:323
std::shared_ptr< const FiniteElement< geometry_type > > element() const
The finite element.
Definition FunctionSpace.h:329
std::vector< geometry_type > tabulate_dof_coordinates(bool transpose) const
Tabulate the physical coordinates of all dofs on this process.
Definition FunctionSpace.h:190
Definition Function.h:45
Definition types.h:20
Finite element method functionality.
Definition assemble_matrix_impl.h:26
std::vector< std::int32_t > locate_dofs_geometrical(const FunctionSpace< T > &V, U marker_fn)
Find degrees of freedom whose geometric coordinate is true for the provided marking function.
Definition DirichletBC.h:101
std::vector< std::int32_t > locate_dofs_topological(const mesh::Topology &topology, const DofMap &dofmap, int dim, std::span< const std::int32_t > entities, bool remote=true)
Find degrees-of-freedom which belong to the provided mesh entities (topological).
Definition DirichletBC.cpp:186