Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/v0.1.0/v0.9.0/cpp
DOLFINx  0.1.0
DOLFINx C++ interface
assemble_vector_impl.h
1 // Copyright (C) 2018-2019 Garth N. Wells
2 //
3 // This file is part of DOLFINx (https://www.fenicsproject.org)
4 //
5 // SPDX-License-Identifier: LGPL-3.0-or-later
6 
7 #pragma once
8 
9 #include "DirichletBC.h"
10 #include "DofMap.h"
11 #include "Form.h"
12 #include "utils.h"
13 #include <dolfinx/common/IndexMap.h>
14 #include <dolfinx/common/types.h>
15 #include <dolfinx/fem/Constant.h>
16 #include <dolfinx/fem/FunctionSpace.h>
17 #include <dolfinx/graph/AdjacencyList.h>
18 #include <dolfinx/mesh/Geometry.h>
19 #include <dolfinx/mesh/Mesh.h>
20 #include <dolfinx/mesh/Topology.h>
21 #include <functional>
22 #include <memory>
23 #include <vector>
24 #include <xtensor/xbuilder.hpp>
25 #include <xtensor/xtensor.hpp>
26 
27 namespace dolfinx::fem::impl
28 {
29 
31 
36 template <typename T>
37 void assemble_vector(xtl::span<T> b, const Form<T>& L);
38 
40 template <typename T>
41 void assemble_cells(
42  xtl::span<T> b, const mesh::Geometry& geometry,
43  const std::vector<std::int32_t>& active_cells,
44  const graph::AdjacencyList<std::int32_t>& dofmap, const int bs,
45  const std::function<void(T*, const T*, const T*, const double*, const int*,
46  const std::uint8_t*, const std::uint32_t)>& kernel,
47  const array2d<T>& coeffs, const std::vector<T>& constant_values,
48  const std::vector<std::uint32_t>& cell_info);
49 
51 template <typename T>
52 void assemble_exterior_facets(
53  xtl::span<T> b, const mesh::Mesh& mesh,
54  const std::vector<std::int32_t>& active_facets,
55  const graph::AdjacencyList<std::int32_t>& dofmap, const int bs,
56  const std::function<void(T*, const T*, const T*, const double*, const int*,
57  const std::uint8_t*, const std::uint32_t)>& fn,
58  const array2d<T>& coeffs, const std::vector<T>& constant_values,
59  const std::vector<std::uint32_t>& cell_info,
60  const std::vector<std::uint8_t>& perms);
61 
63 template <typename T>
64 void assemble_interior_facets(
65  xtl::span<T> b, const mesh::Mesh& mesh,
66  const std::vector<std::int32_t>& active_facets, const fem::DofMap& dofmap,
67  const std::function<void(T*, const T*, const T*, const double*, const int*,
68  const std::uint8_t*, const std::uint32_t)>& fn,
69  const array2d<T>& coeffs, const std::vector<int>& offsets,
70  const std::vector<T>& constant_values,
71  const std::vector<std::uint32_t>& cell_info,
72  const std::vector<std::uint8_t>& perms);
73 
91 template <typename T>
92 void apply_lifting(
93  xtl::span<T> b, const std::vector<std::shared_ptr<const Form<T>>> a,
94  const std::vector<std::vector<std::shared_ptr<const DirichletBC<T>>>>& bcs1,
95  const xtl::span<const T>& x0, double scale);
96 
109 template <typename T>
110 void lift_bc(xtl::span<T> b, const Form<T>& a,
111  const xtl::span<const T>& bc_values1,
112  const std::vector<bool>& bc_markers1, const xtl::span<const T>& x0,
113  double scale);
114 
115 // Implementation of bc application
116 template <typename T>
117 void _lift_bc_cells(
118  xtl::span<T> b, const mesh::Geometry& geometry,
119  const std::function<void(T*, const T*, const T*, const double*, const int*,
120  const std::uint8_t*, const std::uint32_t)>& kernel,
121  const std::vector<std::int32_t>& active_cells,
122  const graph::AdjacencyList<std::int32_t>& dofmap0, int bs0,
123  const graph::AdjacencyList<std::int32_t>& dofmap1, int bs1,
124  const array2d<T>& coeffs, const std::vector<T>& constant_values,
125  const std::vector<std::uint32_t>& cell_info,
126  const xtl::span<const T>& bc_values1, const std::vector<bool>& bc_markers1,
127  const xtl::span<const T>& x0, double scale)
128 {
129  // Prepare cell geometry
130  const std::size_t gdim = geometry.dim();
131  const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
132 
133  // FIXME: Add proper interface for num coordinate dofs
134  const std::size_t num_dofs_g = x_dofmap.num_links(0);
135  const xt::xtensor<double, 2>& x_g = geometry.x();
136 
137  // Data structures used in bc application
138  std::vector<double> coordinate_dofs(num_dofs_g * gdim);
139  std::vector<T> Ae, be;
140 
141  for (std::int32_t c : active_cells)
142  {
143  // Get dof maps for cell
144  auto dmap1 = dofmap1.links(c);
145 
146  // Check if bc is applied to cell
147  bool has_bc = false;
148  for (std::size_t j = 0; j < dmap1.size(); ++j)
149  {
150  for (int k = 0; k < bs1; ++k)
151  {
152  assert(bs1 * dmap1[j] + k < (int)bc_markers1.size());
153  if (bc_markers1[bs1 * dmap1[j] + k])
154  {
155  has_bc = true;
156  break;
157  }
158  }
159  }
160 
161  if (!has_bc)
162  continue;
163 
164  // Get cell coordinates/geometry
165  auto x_dofs = x_dofmap.links(c);
166  for (std::size_t i = 0; i < x_dofs.size(); ++i)
167  {
168  std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
169  std::next(coordinate_dofs.begin(), i * gdim));
170  }
171 
172  // Size data structure for assembly
173  auto dmap0 = dofmap0.links(c);
174 
175  const int num_rows = bs0 * dmap0.size();
176  const int num_cols = bs1 * dmap1.size();
177 
178  auto coeff_array = coeffs.row(c);
179  Ae.resize(num_rows * num_cols);
180  std::fill(Ae.begin(), Ae.end(), 0);
181  kernel(Ae.data(), coeff_array.data(), constant_values.data(),
182  coordinate_dofs.data(), nullptr, nullptr, cell_info[c]);
183 
184  // Size data structure for assembly
185  be.resize(num_rows);
186  std::fill(be.begin(), be.end(), 0);
187  for (std::size_t j = 0; j < dmap1.size(); ++j)
188  {
189  for (int k = 0; k < bs1; ++k)
190  {
191  const std::int32_t jj = bs1 * dmap1[j] + k;
192  assert(jj < (int)bc_markers1.size());
193  if (bc_markers1[jj])
194  {
195  const T bc = bc_values1[jj];
196  const T _x0 = x0.empty() ? 0.0 : x0[jj];
197  // be -= Ae.col(bs1 * j + k) * scale * (bc - _x0);
198  for (int m = 0; m < num_rows; ++m)
199  be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
200  }
201  }
202  }
203 
204  for (std::size_t i = 0; i < dmap0.size(); ++i)
205  for (int k = 0; k < bs0; ++k)
206  b[bs0 * dmap0[i] + k] += be[bs0 * i + k];
207  }
208 }
209 //----------------------------------------------------------------------------
210 template <typename T>
211 void _lift_bc_exterior_facets(
212  xtl::span<T> b, const mesh::Mesh& mesh,
213  const std::function<void(T*, const T*, const T*, const double*, const int*,
214  const std::uint8_t*, const std::uint32_t)>& kernel,
215  const std::vector<std::int32_t>& active_facets,
216  const graph::AdjacencyList<std::int32_t>& dofmap0, int bs0,
217  const graph::AdjacencyList<std::int32_t>& dofmap1, int bs1,
218  const array2d<T>& coeffs, const std::vector<T>& constant_values,
219  const std::vector<std::uint32_t>& cell_info,
220  const std::vector<std::uint8_t>& perms,
221  const xtl::span<const T>& bc_values1, const std::vector<bool>& bc_markers1,
222  const xtl::span<const T>& x0, double scale)
223 {
224  const std::size_t gdim = mesh.geometry().dim();
225  const int tdim = mesh.topology().dim();
226 
227  // Prepare cell geometry
228  const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
229 
230  // FIXME: Add proper interface for num coordinate dofs
231  const std::size_t num_dofs_g = x_dofmap.num_links(0);
232  const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
233 
234  // Data structures used in bc application
235  std::vector<double> coordinate_dofs(num_dofs_g * gdim);
236  std::vector<T> Ae, be;
237 
238  // Iterate over owned facets
239  const mesh::Topology& topology = mesh.topology();
240  auto connectivity = topology.connectivity(tdim - 1, tdim);
241  assert(connectivity);
242  auto c_to_f = topology.connectivity(tdim, tdim - 1);
243  assert(c_to_f);
244  auto map = topology.index_map(tdim - 1);
245  assert(map);
246 
247  for (std::int32_t f : active_facets)
248  {
249  // Create attached cell
250  assert(connectivity->num_links(f) == 1);
251  const std::int32_t cell = connectivity->links(f)[0];
252 
253  // Get local index of facet with respect to the cell
254  auto facets = c_to_f->links(cell);
255  auto it = std::find(facets.begin(), facets.end(), f);
256  assert(it != facets.end());
257  const int local_facet = std::distance(facets.begin(), it);
258 
259  // Get dof maps for cell
260  auto dmap1 = dofmap1.links(cell);
261 
262  // Check if bc is applied to cell
263  bool has_bc = false;
264  for (std::size_t j = 0; j < dmap1.size(); ++j)
265  {
266  for (int k = 0; k < bs1; ++k)
267  {
268  if (bc_markers1[bs1 * dmap1[j] + k])
269  {
270  has_bc = true;
271  break;
272  }
273  }
274  }
275 
276  if (!has_bc)
277  continue;
278 
279  // Get cell coordinates/geometry
280  auto x_dofs = x_dofmap.links(cell);
281  for (std::size_t i = 0; i < x_dofs.size(); ++i)
282  {
283  std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
284  std::next(coordinate_dofs.begin(), i * gdim));
285  }
286 
287  // Size data structure for assembly
288  auto dmap0 = dofmap0.links(cell);
289 
290  const int num_rows = bs0 * dmap0.size();
291  const int num_cols = bs1 * dmap1.size();
292 
293  auto coeff_array = coeffs.row(cell);
294  Ae.resize(num_rows * num_cols);
295  std::fill(Ae.begin(), Ae.end(), 0);
296  kernel(Ae.data(), coeff_array.data(), constant_values.data(),
297  coordinate_dofs.data(), &local_facet,
298  &perms[cell * facets.size() + local_facet], cell_info[cell]);
299 
300  // Size data structure for assembly
301  be.resize(num_rows);
302  std::fill(be.begin(), be.end(), 0);
303  for (std::size_t j = 0; j < dmap1.size(); ++j)
304  {
305  for (int k = 0; k < bs1; ++k)
306  {
307  const std::int32_t jj = bs1 * dmap1[j] + k;
308  if (bc_markers1[jj])
309  {
310 
311  const T bc = bc_values1[jj];
312  const T _x0 = x0.empty() ? 0.0 : x0[jj];
313  // be -= Ae.col(bs1 * j + k) * scale * (bc - _x0);
314  for (int m = 0; m < num_rows; ++m)
315  be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
316  }
317  }
318  }
319 
320  for (std::size_t i = 0; i < dmap0.size(); ++i)
321  for (int k = 0; k < bs0; ++k)
322  b[bs0 * dmap0[i] + k] += be[bs0 * i + k];
323  }
324 }
325 //----------------------------------------------------------------------------
326 template <typename T>
327 void _lift_bc_interior_facets(
328  xtl::span<T> b, const mesh::Mesh& mesh,
329  const std::function<void(T*, const T*, const T*, const double*, const int*,
330  const std::uint8_t*, const std::uint32_t)>& kernel,
331  const std::vector<std::int32_t>& active_facets,
332  const graph::AdjacencyList<std::int32_t>& dofmap0, int bs0,
333  const graph::AdjacencyList<std::int32_t>& dofmap1, int bs1,
334  const array2d<T>& coeffs, const std::vector<int>& offsets,
335  const std::vector<T>& constant_values,
336  const std::vector<std::uint32_t>& cell_info,
337  const std::vector<std::uint8_t>& perms,
338  const xtl::span<const T>& bc_values1, const std::vector<bool>& bc_markers1,
339  const xtl::span<const T>& x0, double scale)
340 {
341  const std::size_t gdim = mesh.geometry().dim();
342  const int tdim = mesh.topology().dim();
343 
344  // Prepare cell geometry
345  const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
346 
347  // FIXME: Add proper interface for num coordinate dofs
348  const std::size_t num_dofs_g = x_dofmap.num_links(0);
349  const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
350 
351  // Data structures used in assembly
352  xt::xtensor<double, 3> coordinate_dofs({2, num_dofs_g, gdim});
353  std::vector<T> coeff_array(2 * offsets.back());
354  assert(offsets.back() == int(coeffs.shape[1]));
355  std::vector<T> Ae, be;
356 
357  // Temporaries for joint dofmaps
358  std::vector<std::int32_t> dmapjoint0, dmapjoint1;
359 
360  const mesh::Topology& topology = mesh.topology();
361  auto connectivity = topology.connectivity(tdim - 1, tdim);
362  assert(connectivity);
363  auto c_to_f = topology.connectivity(tdim, tdim - 1);
364  assert(c_to_f);
365  auto f_to_c = topology.connectivity(tdim - 1, tdim);
366  assert(f_to_c);
367  auto map = topology.index_map(tdim - 1);
368  assert(map);
369 
370  for (std::int32_t f : active_facets)
371  {
372  // Create attached cells
373  auto cells = f_to_c->links(f);
374  assert(cells.size() == 2);
375 
376  // Get local index of facet with respect to the cell
377  auto facets0 = c_to_f->links(cells[0]);
378  auto it0 = std::find(facets0.begin(), facets0.end(), f);
379  assert(it0 != facets0.end());
380  const int local_facet0 = std::distance(facets0.begin(), it0);
381  auto facets1 = c_to_f->links(cells[1]);
382  auto it1 = std::find(facets1.begin(), facets1.end(), f);
383  assert(it1 != facets1.end());
384  const int local_facet1 = std::distance(facets1.begin(), it1);
385 
386  const std::array local_facet{local_facet0, local_facet1};
387 
388  // Get cell geometry
389  auto x_dofs0 = x_dofmap.links(cells[0]);
390  for (std::size_t i = 0; i < x_dofs0.size(); ++i)
391  {
392  std::copy_n(xt::view(x_g, x_dofs0[i]).begin(), gdim,
393  xt::view(coordinate_dofs, 0, i, xt::all()).begin());
394  }
395  auto x_dofs1 = x_dofmap.links(cells[1]);
396  for (std::size_t i = 0; i < x_dofs1.size(); ++i)
397  {
398  std::copy_n(xt::view(x_g, x_dofs1[i]).begin(), gdim,
399  xt::view(coordinate_dofs, 1, i, xt::all()).begin());
400  }
401 
402  // Get dof maps for cells and pack
403  const xtl::span<const std::int32_t> dmap0_cell0 = dofmap0.links(cells[0]);
404  const xtl::span<const std::int32_t> dmap0_cell1 = dofmap0.links(cells[1]);
405  dmapjoint0.resize(dmap0_cell0.size() + dmap0_cell1.size());
406  std::copy(dmap0_cell0.begin(), dmap0_cell0.end(), dmapjoint0.begin());
407  std::copy(dmap0_cell1.begin(), dmap0_cell1.end(),
408  std::next(dmapjoint0.begin(), dmap0_cell0.size()));
409 
410  const xtl::span<const std::int32_t> dmap1_cell0 = dofmap1.links(cells[0]);
411  const xtl::span<const std::int32_t> dmap1_cell1 = dofmap1.links(cells[1]);
412  dmapjoint1.resize(dmap1_cell0.size() + dmap1_cell1.size());
413  std::copy(dmap1_cell0.begin(), dmap1_cell0.end(), dmapjoint1.begin());
414  std::copy(dmap1_cell1.begin(), dmap1_cell1.end(),
415  std::next(dmapjoint1.begin(), dmap1_cell0.size()));
416 
417  // Check if bc is applied to cell0
418  bool has_bc = false;
419  for (std::size_t j = 0; j < dmap1_cell0.size(); ++j)
420  {
421  for (int k = 0; k < bs1; ++k)
422  {
423  if (bc_markers1[bs1 * dmap1_cell0[j] + k])
424  {
425  has_bc = true;
426  break;
427  }
428  }
429  }
430 
431  // Check if bc is applied to cell1
432  for (std::size_t j = 0; j < dmap1_cell1.size(); ++j)
433  {
434  for (int k = 0; k < bs1; ++k)
435  {
436  if (bc_markers1[bs1 * dmap1_cell1[j] + k])
437  {
438  has_bc = true;
439  break;
440  }
441  }
442  }
443 
444  if (!has_bc)
445  continue;
446 
447  // Layout for the restricted coefficients is flattened
448  // w[coefficient][restriction][dof]
449  const auto coeff_cell0 = coeffs.row(cells[0]);
450  const auto coeff_cell1 = coeffs.row(cells[1]);
451 
452  // Loop over coefficients
453  for (std::size_t i = 0; i < offsets.size() - 1; ++i)
454  {
455  // Loop over entries for coefficient i
456  const int num_entries = offsets[i + 1] - offsets[i];
457  std::copy_n(coeff_cell0.data() + offsets[i], num_entries,
458  std::next(coeff_array.begin(), 2 * offsets[i]));
459  std::copy_n(coeff_cell1.data() + offsets[i], num_entries,
460  std::next(coeff_array.begin(), offsets[i + 1] + offsets[i]));
461  }
462 
463  const int num_rows = bs0 * dmapjoint0.size();
464  const int num_cols = bs1 * dmapjoint1.size();
465 
466  // Tabulate tensor
467  Ae.resize(num_rows * num_cols);
468  std::fill(Ae.begin(), Ae.end(), 0);
469  const int facets_per_cell = facets0.size();
470  const std::array perm{perms[cells[0] * facets_per_cell + local_facet[0]],
471  perms[cells[1] * facets_per_cell + local_facet[1]]};
472  kernel(Ae.data(), coeff_array.data(), constant_values.data(),
473  coordinate_dofs.data(), local_facet.data(), perm.data(),
474  cell_info[cells[0]]);
475 
476  be.resize(num_rows);
477  std::fill(be.begin(), be.end(), 0);
478 
479  // Compute b = b - A*b for cell0
480  for (std::size_t j = 0; j < dmap1_cell0.size(); ++j)
481  {
482  for (int k = 0; k < bs1; ++k)
483  {
484  const std::int32_t jj = bs1 * dmap1_cell0[j] + k;
485  if (bc_markers1[jj])
486  {
487  const T bc = bc_values1[jj];
488  const T _x0 = x0.empty() ? 0.0 : x0[jj];
489  // be -= Ae.col(bs1 * j + k) * scale * (bc - _x0);
490  for (int m = 0; m < num_rows; ++m)
491  be[m] -= Ae[m * num_cols + bs1 * j + k] * scale * (bc - _x0);
492  }
493  }
494  }
495 
496  // Compute b = b - A*b for cell1
497  const int offset = bs1 * dmap1_cell0.size();
498  for (std::size_t j = 0; j < dmap1_cell1.size(); ++j)
499  {
500  for (int k = 0; k < bs1; ++k)
501  {
502  const std::int32_t jj = bs1 * dmap1_cell1[j] + k;
503  if (bc_markers1[jj])
504  {
505  const T bc = bc_values1[jj];
506  const T _x0 = x0.empty() ? 0.0 : x0[jj];
507  // be -= Ae.col(offset + bs1 * j + k) * scale * (bc - x0[jj]);
508  for (int m = 0; m < num_rows; ++m)
509  {
510  be[m]
511  -= Ae[m * num_cols + offset + bs1 * j + k] * scale * (bc - _x0);
512  }
513  }
514  }
515  }
516 
517  for (std::size_t i = 0; i < dmap0_cell0.size(); ++i)
518  for (int k = 0; k < bs0; ++k)
519  b[bs0 * dmap0_cell0[i] + k] += be[bs0 * i + k];
520 
521  for (std::size_t i = 0; i < dmap0_cell1.size(); ++i)
522  for (int k = 0; k < bs0; ++k)
523  b[bs0 * dmap0_cell1[i] + k] += be[offset + bs0 * i + k];
524  }
525 }
526 //-----------------------------------------------------------------------------
527 template <typename T>
528 void assemble_vector(xtl::span<T> b, const Form<T>& L)
529 {
530  std::shared_ptr<const mesh::Mesh> mesh = L.mesh();
531  assert(mesh);
532  const int tdim = mesh->topology().dim();
533  const std::int32_t num_cells
534  = mesh->topology().connectivity(tdim, 0)->num_nodes();
535 
536  // Get dofmap data
537  assert(L.function_spaces().at(0));
538  std::shared_ptr<const fem::DofMap> dofmap
539  = L.function_spaces().at(0)->dofmap();
540  assert(dofmap);
541  const graph::AdjacencyList<std::int32_t>& dofs = dofmap->list();
542  const int bs = dofmap->bs();
543 
544  // Prepare constants
545  const std::vector<T> constant_values = pack_constants(L);
546 
547  // Prepare coefficients
548  const array2d<T> coeffs = pack_coefficients(L);
549 
550  const bool needs_permutation_data = L.needs_permutation_data();
551  if (needs_permutation_data)
552  mesh->topology_mutable().create_entity_permutations();
553  const std::vector<std::uint32_t>& cell_info
554  = needs_permutation_data ? mesh->topology().get_cell_permutation_info()
555  : std::vector<std::uint32_t>(num_cells);
556 
557  for (int i : L.integral_ids(IntegralType::cell))
558  {
559  const auto& fn = L.kernel(IntegralType::cell, i);
560  const std::vector<std::int32_t>& active_cells
561  = L.domains(IntegralType::cell, i);
562  fem::impl::assemble_cells(b, mesh->geometry(), active_cells, dofs, bs, fn,
563  coeffs, constant_values, cell_info);
564  }
565 
566  if (L.num_integrals(IntegralType::exterior_facet) > 0
567  or L.num_integrals(IntegralType::interior_facet) > 0)
568  {
569  // FIXME: cleanup these calls? Some of the happen internally again.
570  mesh->topology_mutable().create_entities(tdim - 1);
571  mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
572  mesh->topology_mutable().create_entity_permutations();
573 
574  const std::vector<std::uint8_t>& perms
575  = mesh->topology().get_facet_permutations();
576  for (int i : L.integral_ids(IntegralType::exterior_facet))
577  {
578  const auto& fn = L.kernel(IntegralType::exterior_facet, i);
579  const std::vector<std::int32_t>& active_facets
580  = L.domains(IntegralType::exterior_facet, i);
581  fem::impl::assemble_exterior_facets(b, *mesh, active_facets, dofs, bs, fn,
582  coeffs, constant_values, cell_info,
583  perms);
584  }
585 
586  const std::vector<int> c_offsets = L.coefficient_offsets();
587  for (int i : L.integral_ids(IntegralType::interior_facet))
588  {
589  const auto& fn = L.kernel(IntegralType::interior_facet, i);
590  const std::vector<std::int32_t>& active_facets
591  = L.domains(IntegralType::interior_facet, i);
592  fem::impl::assemble_interior_facets(b, *mesh, active_facets, *dofmap, fn,
593  coeffs, c_offsets, constant_values,
594  cell_info, perms);
595  }
596  }
597 }
598 //-----------------------------------------------------------------------------
599 template <typename T>
600 void assemble_cells(
601  xtl::span<T> b, const mesh::Geometry& geometry,
602  const std::vector<std::int32_t>& active_cells,
603  const graph::AdjacencyList<std::int32_t>& dofmap, const int bs,
604  const std::function<void(T*, const T*, const T*, const double*, const int*,
605  const std::uint8_t*, const std::uint32_t)>& kernel,
606  const array2d<T>& coeffs, const std::vector<T>& constant_values,
607  const std::vector<std::uint32_t>& cell_info)
608 {
609  const std::size_t gdim = geometry.dim();
610 
611  // Prepare cell geometry
612  const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
613 
614  // FIXME: Add proper interface for num coordinate dofs
615  const int num_dofs_g = x_dofmap.num_links(0);
616  const xt::xtensor<double, 2>& x_g = geometry.x();
617 
618  // FIXME: Add proper interface for num_dofs
619  // Create data structures used in assembly
620  const int num_dofs = dofmap.links(0).size();
621  std::vector<double> coordinate_dofs(num_dofs_g * gdim);
622  std::vector<T> be(bs * num_dofs);
623 
624  // Iterate over active cells
625  for (std::int32_t c : active_cells)
626  {
627  // Get cell coordinates/geometry
628  auto x_dofs = x_dofmap.links(c);
629  for (std::size_t i = 0; i < x_dofs.size(); ++i)
630  {
631  std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
632  std::next(coordinate_dofs.begin(), i * gdim));
633  }
634 
635  // Tabulate vector for cell
636  std::fill(be.begin(), be.end(), 0);
637  kernel(be.data(), coeffs.row(c).data(), constant_values.data(),
638  coordinate_dofs.data(), nullptr, nullptr, cell_info[c]);
639 
640  // Scatter cell vector to 'global' vector array
641  auto dofs = dofmap.links(c);
642  for (int i = 0; i < num_dofs; ++i)
643  for (int k = 0; k < bs; ++k)
644  b[bs * dofs[i] + k] += be[bs * i + k];
645  }
646 }
647 //-----------------------------------------------------------------------------
648 template <typename T>
649 void assemble_exterior_facets(
650  xtl::span<T> b, const mesh::Mesh& mesh,
651  const std::vector<std::int32_t>& active_facets,
652  const graph::AdjacencyList<std::int32_t>& dofmap, const int bs,
653  const std::function<void(T*, const T*, const T*, const double*, const int*,
654  const std::uint8_t*, const std::uint32_t)>& fn,
655  const array2d<T>& coeffs, const std::vector<T>& constant_values,
656  const std::vector<std::uint32_t>& cell_info,
657  const std::vector<std::uint8_t>& perms)
658 {
659  const std::size_t gdim = mesh.geometry().dim();
660  const int tdim = mesh.topology().dim();
661 
662  // Prepare cell geometry
663  const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
664 
665  // FIXME: Add proper interface for num coordinate dofs
666  const std::size_t num_dofs_g = x_dofmap.num_links(0);
667  const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
668 
669  // FIXME: Add proper interface for num_dofs
670  // Create data structures used in assembly
671  const int num_dofs = dofmap.links(0).size();
672  std::vector<double> coordinate_dofs(num_dofs_g * gdim);
673  std::vector<T> be(bs * num_dofs);
674 
675  auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
676  assert(f_to_c);
677  auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
678  assert(c_to_f);
679  for (std::int32_t f : active_facets)
680  {
681  // Get index of first attached cell
682  assert(f_to_c->num_links(f) > 0);
683  const std::int32_t cell = f_to_c->links(f)[0];
684 
685  // Get local index of facet with respect to the cell
686  auto facets = c_to_f->links(cell);
687  auto it = std::find(facets.begin(), facets.end(), f);
688  assert(it != facets.end());
689  const int local_facet = std::distance(facets.begin(), it);
690 
691  // Get cell coordinates/geometry
692  auto x_dofs = x_dofmap.links(cell);
693  for (std::size_t i = 0; i < x_dofs.size(); ++i)
694  {
695  std::copy_n(xt::row(x_g, x_dofs[i]).begin(), gdim,
696  std::next(coordinate_dofs.begin(), i * gdim));
697  }
698 
699  // Tabulate element vector
700  std::fill(be.begin(), be.end(), 0);
701  fn(be.data(), coeffs.row(cell).data(), constant_values.data(),
702  coordinate_dofs.data(), &local_facet,
703  &perms[cell * facets.size() + local_facet], cell_info[cell]);
704 
705  // Add element vector to global vector
706  auto dofs = dofmap.links(cell);
707  for (int i = 0; i < num_dofs; ++i)
708  for (int k = 0; k < bs; ++k)
709  b[bs * dofs[i] + k] += be[bs * i + k];
710  }
711 }
712 //-----------------------------------------------------------------------------
713 template <typename T>
714 void assemble_interior_facets(
715  xtl::span<T> b, const mesh::Mesh& mesh,
716  const std::vector<std::int32_t>& active_facets, const fem::DofMap& dofmap,
717  const std::function<void(T*, const T*, const T*, const double*, const int*,
718  const std::uint8_t*, const std::uint32_t)>& fn,
719  const array2d<T>& coeffs, const std::vector<int>& offsets,
720  const std::vector<T>& constant_values,
721  const std::vector<std::uint32_t>& cell_info,
722  const std::vector<std::uint8_t>& perms)
723 {
724  const std::size_t gdim = mesh.geometry().dim();
725  const int tdim = mesh.topology().dim();
726 
727  // Prepare cell geometry
728  const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
729 
730  // FIXME: Add proper interface for num coordinate dofs
731  const std::size_t num_dofs_g = x_dofmap.num_links(0);
732  const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
733 
734  // Create data structures used in assembly
735  xt::xtensor<double, 3> coordinate_dofs({2, num_dofs_g, gdim});
736  std::vector<T> be;
737  std::vector<T> coeff_array(2 * offsets.back());
738  assert(offsets.back() == int(coeffs.shape[1]));
739 
740  const int bs = dofmap.bs();
741  auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
742  assert(f_to_c);
743  auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
744  assert(c_to_f);
745  for (std::int32_t f : active_facets)
746  {
747  // Get attached cell indices
748  auto cells = f_to_c->links(f);
749  assert(cells.size() == 2);
750 
751  const int facets_per_cell = c_to_f->num_links(cells[0]);
752 
753  // Create attached cells
754  std::array<int, 2> local_facet;
755  for (int i = 0; i < 2; ++i)
756  {
757  auto facets = c_to_f->links(cells[i]);
758  auto it = std::find(facets.begin(), facets.end(), f);
759  assert(it != facets.end());
760  local_facet[i] = std::distance(facets.begin(), it);
761  }
762 
763  // Get cell geometry
764  auto x_dofs0 = x_dofmap.links(cells[0]);
765  for (std::size_t i = 0; i < x_dofs0.size(); ++i)
766  {
767  std::copy_n(xt::view(x_g, x_dofs0[i]).begin(), gdim,
768  xt::view(coordinate_dofs, 0, i, xt::all()).begin());
769  }
770  auto x_dofs1 = x_dofmap.links(cells[1]);
771  for (std::size_t i = 0; i < x_dofs1.size(); ++i)
772  {
773  std::copy_n(xt::view(x_g, x_dofs1[i]).begin(), gdim,
774  xt::view(coordinate_dofs, 1, i, xt::all()).begin());
775  }
776 
777  // Layout for the restricted coefficients is flattened
778  // w[coefficient][restriction][dof]
779  auto coeff_cell0 = coeffs.row(cells[0]);
780  auto coeff_cell1 = coeffs.row(cells[1]);
781 
782  // Loop over coefficients
783  for (std::size_t i = 0; i < offsets.size() - 1; ++i)
784  {
785  // Loop over entries for coefficient i
786  const int num_entries = offsets[i + 1] - offsets[i];
787  std::copy_n(coeff_cell0.data() + offsets[i], num_entries,
788  std::next(coeff_array.begin(), 2 * offsets[i]));
789  std::copy_n(coeff_cell1.data() + offsets[i], num_entries,
790  std::next(coeff_array.begin(), offsets[i + 1] + offsets[i]));
791  }
792 
793  // Get dofmaps for cells
794  xtl::span<const std::int32_t> dmap0 = dofmap.cell_dofs(cells[0]);
795  xtl::span<const std::int32_t> dmap1 = dofmap.cell_dofs(cells[1]);
796 
797  // Tabulate element vector
798  be.resize(bs * (dmap0.size() + dmap1.size()));
799  std::fill(be.begin(), be.end(), 0);
800  const std::array perm{perms[cells[0] * facets_per_cell + local_facet[0]],
801  perms[cells[1] * facets_per_cell + local_facet[1]]};
802  fn(be.data(), coeff_array.data(), constant_values.data(),
803  coordinate_dofs.data(), local_facet.data(), perm.data(),
804  cell_info[cells[0]]);
805 
806  // Add element vector to global vector
807  for (std::size_t i = 0; i < dmap0.size(); ++i)
808  for (int k = 0; k < bs; ++k)
809  b[bs * dmap0[i] + k] += be[bs * i + k];
810  for (std::size_t i = 0; i < dmap1.size(); ++i)
811  for (int k = 0; k < bs; ++k)
812  b[bs * dmap1[i] + k] += be[bs * (i + dmap0.size()) + k];
813  }
814 }
815 //-----------------------------------------------------------------------------
816 template <typename T>
817 void apply_lifting(
818  xtl::span<T> b, const std::vector<std::shared_ptr<const Form<T>>> a,
819  const std::vector<std::vector<std::shared_ptr<const DirichletBC<T>>>>& bcs1,
820  const std::vector<xtl::span<const T>>& x0, double scale)
821 {
822  // FIXME: make changes to reactivate this check
823  if (!x0.empty() and x0.size() != a.size())
824  {
825  throw std::runtime_error(
826  "Mismatch in size between x0 and bilinear form in assembler.");
827  }
828 
829  if (a.size() != bcs1.size())
830  {
831  throw std::runtime_error(
832  "Mismatch in size between a and bcs in assembler.");
833  }
834 
835  for (std::size_t j = 0; j < a.size(); ++j)
836  {
837  std::vector<bool> bc_markers1;
838  std::vector<T> bc_values1;
839  if (a[j] and !bcs1[j].empty())
840  {
841  auto V1 = a[j]->function_spaces()[1];
842  assert(V1);
843  auto map1 = V1->dofmap()->index_map;
844  const int bs1 = V1->dofmap()->index_map_bs();
845  assert(map1);
846  const int crange = bs1 * (map1->size_local() + map1->num_ghosts());
847  bc_markers1.assign(crange, false);
848  bc_values1.assign(crange, 0.0);
849  for (const std::shared_ptr<const DirichletBC<T>>& bc : bcs1[j])
850  {
851  bc->mark_dofs(bc_markers1);
852  bc->dof_values(bc_values1);
853  }
854 
855  if (!x0.empty())
856  lift_bc<T>(b, *a[j], bc_values1, bc_markers1, x0[j], scale);
857  else
858  {
859  lift_bc<T>(b, *a[j], bc_values1, bc_markers1, xtl::span<const T>(),
860  scale);
861  }
862  }
863  }
864 }
865 //-----------------------------------------------------------------------------
866 template <typename T>
867 void lift_bc(xtl::span<T> b, const Form<T>& a,
868  const xtl::span<const T>& bc_values1,
869  const std::vector<bool>& bc_markers1, const xtl::span<const T>& x0,
870  double scale)
871 {
872  std::shared_ptr<const mesh::Mesh> mesh = a.mesh();
873  assert(mesh);
874  const int tdim = mesh->topology().dim();
875  const std::int32_t num_cells
876  = mesh->topology().connectivity(tdim, 0)->num_nodes();
877 
878  // Get dofmap for columns and rows of a
879  assert(a.function_spaces().at(0));
880  assert(a.function_spaces().at(1));
881  const graph::AdjacencyList<std::int32_t>& dofmap0
882  = a.function_spaces()[0]->dofmap()->list();
883  const int bs0 = a.function_spaces()[0]->dofmap()->bs();
884  const graph::AdjacencyList<std::int32_t>& dofmap1
885  = a.function_spaces()[1]->dofmap()->list();
886  const int bs1 = a.function_spaces()[1]->dofmap()->bs();
887 
888  // Prepare constants
889  const std::vector<T> constant_values = pack_constants(a);
890 
891  // Prepare coefficients
892  const array2d<T> coeffs = pack_coefficients(a);
893 
894  const bool needs_permutation_data = a.needs_permutation_data();
895  if (needs_permutation_data)
896  mesh->topology_mutable().create_entity_permutations();
897  const std::vector<std::uint32_t>& cell_info
898  = needs_permutation_data ? mesh->topology().get_cell_permutation_info()
899  : std::vector<std::uint32_t>(num_cells);
900 
901  for (int i : a.integral_ids(IntegralType::cell))
902  {
903  const auto& kernel = a.kernel(IntegralType::cell, i);
904  const std::vector<std::int32_t>& active_cells
905  = a.domains(IntegralType::cell, i);
906  _lift_bc_cells(b, mesh->geometry(), kernel, active_cells, dofmap0, bs0,
907  dofmap1, bs1, coeffs, constant_values, cell_info, bc_values1,
908  bc_markers1, x0, scale);
909  }
910 
911  if (a.num_integrals(IntegralType::exterior_facet) > 0
912  or a.num_integrals(IntegralType::interior_facet) > 0)
913  {
914  // FIXME: cleanup these calls? Some of the happen internally again.
915  mesh->topology_mutable().create_entities(tdim - 1);
916  mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
917  mesh->topology_mutable().create_entity_permutations();
918 
919  const std::vector<std::uint8_t>& perms
920  = mesh->topology().get_facet_permutations();
921  for (int i : a.integral_ids(IntegralType::exterior_facet))
922  {
923  const auto& kernel = a.kernel(IntegralType::exterior_facet, i);
924  const std::vector<std::int32_t>& active_facets
925  = a.domains(IntegralType::exterior_facet, i);
926  _lift_bc_exterior_facets(b, *mesh, kernel, active_facets, dofmap0, bs0,
927  dofmap1, bs1, coeffs, constant_values, cell_info,
928  perms, bc_values1, bc_markers1, x0, scale);
929  }
930 
931  const std::vector<int> c_offsets = a.coefficient_offsets();
932  for (int i : a.integral_ids(IntegralType::interior_facet))
933  {
934  const auto& kernel = a.kernel(IntegralType::interior_facet, i);
935  const std::vector<std::int32_t>& active_facets
936  = a.domains(IntegralType::interior_facet, i);
937  _lift_bc_interior_facets(b, *mesh, kernel, active_facets, dofmap0, bs0,
938  dofmap1, bs1, coeffs, c_offsets, constant_values,
939  cell_info, perms, bc_values1, bc_markers1, x0,
940  scale);
941  }
942  }
943 }
944 //-----------------------------------------------------------------------------
945 } // namespace dolfinx::fem::impl
dolfinx::fem::sparsitybuild::cells
void cells(la::SparsityPattern &pattern, const mesh::Topology &topology, const std::array< const std::reference_wrapper< const fem::DofMap >, 2 > &dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition: sparsitybuild.cpp:18
dolfinx::fem::pack_constants
std::vector< typename U::scalar_type > pack_constants(const U &u)
Pack constants of u of generic type U ready for assembly.
Definition: utils.h:431
dolfinx::fem::assemble_vector
void assemble_vector(xtl::span< T > b, const Form< T > &L)
Assemble linear form into a vector.
Definition: assembler.h:45
dolfinx::fem::pack_coefficients
array2d< typename U::scalar_type > pack_coefficients(const U &u)
Pack coefficients of u of generic type U ready for assembly.
Definition: utils.h:376
dolfinx::fem::apply_lifting
void apply_lifting(xtl::span< T > b, const std::vector< std::shared_ptr< const Form< T >>> &a, const std::vector< std::vector< std::shared_ptr< const DirichletBC< T >>>> &bcs1, const std::vector< xtl::span< const T >> &x0, double scale)
Modify b such that:
Definition: assembler.h:69