12 #include <dolfinx/fem/FunctionSpace.h>
13 #include <dolfinx/graph/AdjacencyList.h>
14 #include <dolfinx/la/utils.h>
15 #include <dolfinx/mesh/Geometry.h>
16 #include <dolfinx/mesh/Mesh.h>
17 #include <dolfinx/mesh/Topology.h>
22 namespace dolfinx::fem::impl
33 const std::function<
int(std::int32_t,
const std::int32_t*, std::int32_t,
34 const std::int32_t*,
const T*)>& mat_set_values,
35 const Form<T>& a,
const xtl::span<const T>& constants,
36 const array2d<T>& coeffs,
const std::vector<bool>& bc0,
37 const std::vector<bool>& bc1);
42 const std::function<
int(std::int32_t,
const std::int32_t*, std::int32_t,
43 const std::int32_t*,
const T*)>& mat_set,
45 const xtl::span<const std::int32_t>& active_cells,
46 const std::function<
void(
const xtl::span<T>&,
47 const xtl::span<const std::uint32_t>&,
48 std::int32_t,
int)>& dof_transform,
50 const std::function<
void(
const xtl::span<T>&,
51 const xtl::span<const std::uint32_t>&,
52 std::int32_t,
int)>& dof_transform_to_transpose,
54 const std::vector<bool>& bc0,
const std::vector<bool>& bc1,
55 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
56 const std::uint8_t*)>& kernel,
57 const array2d<T>& coeffs,
const xtl::span<const T>& constants,
58 const xtl::span<const std::uint32_t>& cell_info)
64 const std::size_t num_dofs_g = x_dofmap.
num_links(0);
65 const xt::xtensor<double, 2>& x_g = geometry.
x();
68 const int num_dofs0 = dofmap0.
links(0).size();
69 const int num_dofs1 = dofmap1.
links(0).size();
70 const int ndim0 = bs0 * num_dofs0;
71 const int ndim1 = bs1 * num_dofs1;
72 std::vector<T> Ae(ndim0 * ndim1);
73 const xtl::span<T> _Ae(Ae);
74 std::vector<double> coordinate_dofs(3 * num_dofs_g);
76 for (std::int32_t c : active_cells)
79 auto x_dofs = x_dofmap.
links(c);
80 for (std::size_t i = 0; i < x_dofs.size(); ++i)
82 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
83 std::next(coordinate_dofs.begin(), 3 * i));
87 std::fill(Ae.begin(), Ae.end(), 0);
88 kernel(Ae.data(), coeffs.
row(c).data(), constants.data(),
89 coordinate_dofs.data(),
nullptr,
nullptr);
91 dof_transform(_Ae, cell_info, c, ndim1);
92 dof_transform_to_transpose(_Ae, cell_info, c, ndim0);
95 auto dofs0 = dofmap0.
links(c);
96 auto dofs1 = dofmap1.
links(c);
99 for (
int i = 0; i < num_dofs0; ++i)
101 for (
int k = 0; k < bs0; ++k)
103 if (bc0[bs0 * dofs0[i] + k])
106 const int row = bs0 * i + k;
107 std::fill_n(std::next(Ae.begin(), ndim1 * row), ndim1, 0.0);
115 for (
int j = 0; j < num_dofs1; ++j)
117 for (
int k = 0; k < bs1; ++k)
119 if (bc1[bs1 * dofs1[j] + k])
122 const int col = bs1 * j + k;
123 for (
int row = 0; row < ndim0; ++row)
124 Ae[row * ndim1 + col] = 0.0;
130 mat_set(dofs0.size(), dofs0.data(), dofs1.size(), dofs1.data(), Ae.data());
135 template <
typename T>
136 void assemble_exterior_facets(
137 const std::function<
int(std::int32_t,
const std::int32_t*, std::int32_t,
138 const std::int32_t*,
const T*)>& mat_set,
139 const mesh::Mesh& mesh,
const xtl::span<const std::int32_t>& active_facets,
140 const std::function<
void(
const xtl::span<T>&,
141 const xtl::span<const std::uint32_t>&,
142 std::int32_t,
int)>& dof_transform,
144 const std::function<
void(
const xtl::span<T>&,
145 const xtl::span<const std::uint32_t>&,
146 std::int32_t,
int)>& dof_transform_to_transpose,
148 const std::vector<bool>& bc0,
const std::vector<bool>& bc1,
149 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
150 const std::uint8_t*)>& kernel,
151 const array2d<T>& coeffs,
const xtl::span<const T>& constants,
152 const xtl::span<const std::uint32_t>& cell_info,
153 const std::function<std::uint8_t(std::size_t)>& get_perm)
161 const std::size_t num_dofs_g = x_dofmap.
num_links(0);
162 const xt::xtensor<double, 2>& x_g = mesh.
geometry().
x();
165 std::vector<double> coordinate_dofs(3 * num_dofs_g);
166 const int num_dofs0 = dofmap0.
links(0).size();
167 const int num_dofs1 = dofmap1.
links(0).size();
168 const int ndim0 = bs0 * num_dofs0;
169 const int ndim1 = bs1 * num_dofs1;
170 std::vector<T> Ae(ndim0 * ndim1);
171 const xtl::span<T> _Ae(Ae);
179 for (std::int32_t f : active_facets)
181 auto cells = f_to_c->links(f);
182 assert(cells.size() == 1);
185 auto facets = c_to_f->links(cells[0]);
186 auto it = std::find(facets.begin(), facets.end(), f);
187 assert(it != facets.end());
188 const int local_facet = std::distance(facets.begin(), it);
191 auto x_dofs = x_dofmap.
links(cells[0]);
192 for (std::size_t i = 0; i < x_dofs.size(); ++i)
194 std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
195 std::next(coordinate_dofs.begin(), 3 * i));
199 std::uint8_t perm = get_perm(cells[0] * facets.size() + local_facet);
200 std::fill(Ae.begin(), Ae.end(), 0);
201 kernel(Ae.data(), coeffs.
row(cells[0]).data(), constants.data(),
202 coordinate_dofs.data(), &local_facet, &perm);
204 dof_transform(_Ae, cell_info, cells[0], ndim1);
205 dof_transform_to_transpose(_Ae, cell_info, cells[0], ndim0);
208 auto dofs0 = dofmap0.
links(cells[0]);
209 auto dofs1 = dofmap1.
links(cells[0]);
212 for (
int i = 0; i < num_dofs0; ++i)
214 for (
int k = 0; k < bs0; ++k)
216 if (bc0[bs0 * dofs0[i] + k])
219 const int row = bs0 * i + k;
220 std::fill_n(std::next(Ae.begin(), ndim1 * row), ndim1, 0.0);
227 for (
int j = 0; j < num_dofs1; ++j)
229 for (
int k = 0; k < bs1; ++k)
231 if (bc1[bs1 * dofs1[j] + k])
234 const int col = bs1 * j + k;
235 for (
int row = 0; row < ndim0; ++row)
236 Ae[row * ndim1 + col] = 0.0;
242 mat_set(dofs0.size(), dofs0.data(), dofs1.size(), dofs1.data(), Ae.data());
247 template <
typename T>
248 void assemble_interior_facets(
249 const std::function<
int(std::int32_t,
const std::int32_t*, std::int32_t,
250 const std::int32_t*,
const T*)>& mat_set,
251 const mesh::Mesh& mesh,
const xtl::span<const std::int32_t>& active_facets,
252 const std::function<
void(
const xtl::span<T>&,
253 const xtl::span<const std::uint32_t>&,
254 std::int32_t,
int)>& dof_transform,
255 const DofMap& dofmap0,
int bs0,
256 const std::function<
void(
const xtl::span<T>&,
257 const xtl::span<const std::uint32_t>&,
258 std::int32_t,
int)>& dof_transform_to_transpose,
259 const DofMap& dofmap1,
int bs1,
const std::vector<bool>& bc0,
260 const std::vector<bool>& bc1,
261 const std::function<
void(T*,
const T*,
const T*,
const double*,
const int*,
262 const std::uint8_t*)>& kernel,
263 const array2d<T>& coeffs,
const xtl::span<const int>& offsets,
264 const xtl::span<const T>& constants,
265 const xtl::span<const std::uint32_t>& cell_info,
266 const std::function<std::uint8_t(std::size_t)>& get_perm)
274 const std::size_t num_dofs_g = x_dofmap.
num_links(0);
275 const xt::xtensor<double, 2>& x_g = mesh.
geometry().
x();
278 xt::xtensor<double, 3> coordinate_dofs({2, num_dofs_g, 3});
279 std::vector<T> Ae, be;
280 std::vector<T> coeff_array(2 * offsets.back());
281 assert(offsets.back() == coeffs.
shape[1]);
284 std::vector<std::int32_t> dmapjoint0, dmapjoint1;
292 for (std::int32_t facet_index : active_facets)
295 auto cells = c->links(facet_index);
296 assert(cells.size() == 2);
299 auto facets0 = c_to_f->links(cells[0]);
300 const auto* it0 = std::find(facets0.begin(), facets0.end(), facet_index);
301 assert(it0 != facets0.end());
302 const int local_facet0 = std::distance(facets0.begin(), it0);
303 auto facets1 = c_to_f->links(cells[1]);
304 const auto* it1 = std::find(facets1.begin(), facets1.end(), facet_index);
305 assert(it1 != facets1.end());
306 const int local_facet1 = std::distance(facets1.begin(), it1);
308 const std::array local_facet = {local_facet0, local_facet1};
311 auto x_dofs0 = x_dofmap.
links(cells[0]);
312 for (std::size_t i = 0; i < x_dofs0.size(); ++i)
314 std::copy_n(xt::view(x_g, x_dofs0[i]).begin(), 3,
315 xt::view(coordinate_dofs, 0, i, xt::all()).begin());
317 auto x_dofs1 = x_dofmap.
links(cells[1]);
318 for (std::size_t i = 0; i < x_dofs1.size(); ++i)
320 std::copy_n(xt::view(x_g, x_dofs1[i]).begin(), 3,
321 xt::view(coordinate_dofs, 1, i, xt::all()).begin());
325 xtl::span<const std::int32_t> dmap0_cell0 = dofmap0.cell_dofs(cells[0]);
326 xtl::span<const std::int32_t> dmap0_cell1 = dofmap0.cell_dofs(cells[1]);
327 dmapjoint0.resize(dmap0_cell0.size() + dmap0_cell1.size());
328 std::copy(dmap0_cell0.begin(), dmap0_cell0.end(), dmapjoint0.begin());
329 std::copy(dmap0_cell1.begin(), dmap0_cell1.end(),
330 std::next(dmapjoint0.begin(), dmap0_cell0.size()));
332 xtl::span<const std::int32_t> dmap1_cell0 = dofmap1.cell_dofs(cells[0]);
333 xtl::span<const std::int32_t> dmap1_cell1 = dofmap1.cell_dofs(cells[1]);
334 dmapjoint1.resize(dmap1_cell0.size() + dmap1_cell1.size());
335 std::copy(dmap1_cell0.begin(), dmap1_cell0.end(), dmapjoint1.begin());
336 std::copy(dmap1_cell1.begin(), dmap1_cell1.end(),
337 std::next(dmapjoint1.begin(), dmap1_cell0.size()));
341 auto coeff_cell0 = coeffs.
row(cells[0]);
342 auto coeff_cell1 = coeffs.
row(cells[1]);
345 for (std::size_t i = 0; i < offsets.size() - 1; ++i)
348 const int num_entries = offsets[i + 1] - offsets[i];
349 std::copy_n(coeff_cell0.data() + offsets[i], num_entries,
350 std::next(coeff_array.begin(), 2 * offsets[i]));
351 std::copy_n(coeff_cell1.data() + offsets[i], num_entries,
352 std::next(coeff_array.begin(), offsets[i + 1] + offsets[i]));
355 const int num_rows = bs0 * dmapjoint0.size();
356 const int num_cols = bs1 * dmapjoint1.size();
359 Ae.resize(num_rows * num_cols);
360 std::fill(Ae.begin(), Ae.end(), 0);
362 const int facets_per_cell = facets0.size();
363 const std::array perm{
364 get_perm(cells[0] * facets_per_cell + local_facet[0]),
365 get_perm(cells[1] * facets_per_cell + local_facet[1])};
366 kernel(Ae.data(), coeff_array.data(), constants.data(),
367 coordinate_dofs.data(), local_facet.data(), perm.data());
369 dof_transform(Ae, cell_info, cells[0], num_cols);
370 dof_transform_to_transpose(Ae, cell_info, cells[0], num_rows);
375 for (std::size_t i = 0; i < dmapjoint0.size(); ++i)
377 for (
int k = 0; k < bs0; ++k)
379 if (bc0[bs0 * dmapjoint0[i] + k])
382 std::fill_n(std::next(Ae.begin(), num_cols * (bs0 * i + k)),
390 for (std::size_t j = 0; j < dmapjoint1.size(); ++j)
392 for (
int k = 0; k < bs1; ++k)
394 if (bc1[bs1 * dmapjoint1[j] + k])
397 for (
int m = 0; m < num_rows; ++m)
398 Ae[m * num_cols + bs1 * j + k] = 0.0;
404 mat_set(dmapjoint0.size(), dmapjoint0.data(), dmapjoint1.size(),
405 dmapjoint1.data(), Ae.data());
409 template <
typename T>
411 const std::function<
int(std::int32_t,
const std::int32_t*, std::int32_t,
412 const std::int32_t*,
const T*)>& mat_set,
413 const Form<T>& a,
const xtl::span<const T>& constants,
414 const array2d<T>& coeffs,
const std::vector<bool>& bc0,
415 const std::vector<bool>& bc1)
417 std::shared_ptr<const mesh::Mesh> mesh = a.
mesh();
419 const int tdim = mesh->topology().dim();
422 std::shared_ptr<const fem::DofMap> dofmap0
424 std::shared_ptr<const fem::DofMap> dofmap1
429 const int bs0 = dofmap0->bs();
431 const int bs1 = dofmap1->bs();
433 std::shared_ptr<const fem::FiniteElement> element0
435 std::shared_ptr<const fem::FiniteElement> element1
437 const std::function<void(
const xtl::span<T>&,
438 const xtl::span<const std::uint32_t>&, std::int32_t,
440 = element0->get_dof_transformation_function<T>();
441 const std::function<void(
const xtl::span<T>&,
442 const xtl::span<const std::uint32_t>&, std::int32_t,
443 int)>& dof_transform_to_transpose
444 = element1->get_dof_transformation_to_transpose_function<T>();
446 const bool needs_transformation_data
447 = element0->needs_dof_transformations()
448 or element1->needs_dof_transformations()
450 xtl::span<const std::uint32_t> cell_info;
451 if (needs_transformation_data)
453 mesh->topology_mutable().create_entity_permutations();
454 cell_info = xtl::span(mesh->topology().get_cell_permutation_info());
459 const auto& fn = a.
kernel(IntegralType::cell, i);
460 const std::vector<std::int32_t>& active_cells
461 = a.
domains(IntegralType::cell, i);
462 impl::assemble_cells<T>(mat_set, mesh->geometry(), active_cells,
463 dof_transform, dofs0, bs0,
464 dof_transform_to_transpose, dofs1, bs1, bc0, bc1,
465 fn, coeffs, constants, cell_info);
471 mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
472 std::function<std::uint8_t(std::size_t)> get_perm;
475 mesh->topology_mutable().create_entity_permutations();
476 const std::vector<std::uint8_t>& perms
477 = mesh->topology().get_facet_permutations();
478 get_perm = [&perms](std::size_t i) {
return perms[i]; };
481 get_perm = [](std::size_t) {
return 0; };
483 for (
int i : a.
integral_ids(IntegralType::exterior_facet))
485 const auto& fn = a.
kernel(IntegralType::exterior_facet, i);
486 const std::vector<std::int32_t>& active_facets
487 = a.
domains(IntegralType::exterior_facet, i);
488 impl::assemble_exterior_facets<T>(
489 mat_set, *mesh, active_facets, dof_transform, dofs0, bs0,
490 dof_transform_to_transpose, dofs1, bs1, bc0, bc1, fn, coeffs,
491 constants, cell_info, get_perm);
495 for (
int i : a.
integral_ids(IntegralType::interior_facet))
497 const auto& fn = a.
kernel(IntegralType::interior_facet, i);
498 const std::vector<std::int32_t>& active_facets
499 = a.
domains(IntegralType::interior_facet, i);
500 impl::assemble_interior_facets<T>(
501 mat_set, *mesh, active_facets, dof_transform, *dofmap0, bs0,
502 dof_transform_to_transpose, *dofmap1, bs1, bc0, bc1, fn, coeffs,
503 c_offsets, constants, cell_info, get_perm);
This class provides a dynamic 2-dimensional row-wise array data structure.
Definition: array2d.h:21
constexpr xtl::span< value_type > row(size_type i)
Access a row in the array.
Definition: array2d.h:114
std::array< size_type, 2 > shape
The shape of the array.
Definition: array2d.h:155
Degree-of-freedom map.
Definition: DofMap.h:68
This class provides a static adjacency list data structure. It is commonly used to store directed gra...
Definition: AdjacencyList.h:47
xtl::span< T > links(int node)
Get the links (edges) for given node.
Definition: AdjacencyList.h:130
int num_links(int node) const
Number of connections for given node.
Definition: AdjacencyList.h:120
Geometry stores the geometry imposed on a mesh.
Definition: Geometry.h:37
const graph::AdjacencyList< std::int32_t > & dofmap() const
DOF map.
Definition: Geometry.cpp:22
xt::xtensor< double, 2 > & x()
Geometry degrees-of-freedom.
Definition: Geometry.cpp:32
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition: Mesh.h:53
Geometry & geometry()
Get mesh geometry.
Definition: Mesh.cpp:179
Topology & topology()
Get mesh topology.
Definition: Mesh.cpp:173
int dim() const noexcept
Return the topological dimension of the mesh.
Definition: Topology.cpp:163
std::shared_ptr< const graph::AdjacencyList< std::int32_t > > connectivity(int d0, int d1) const
Return connectivity from entities of dimension d0 to entities of dimension d1.
Definition: Topology.cpp:253
void assemble_matrix(const std::function< int(std::int32_t, const std::int32_t *, std::int32_t, const std::int32_t *, const T *)> &mat_add, const Form< T > &a, const xtl::span< const T > &constants, const array2d< T > &coeffs, const std::vector< std::shared_ptr< const DirichletBC< T >>> &bcs)
Assemble bilinear form into a matrix.
Definition: assembler.h:166