Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/v0.3.0/v0.9.0/cpp
DOLFINx  0.3.0
DOLFINx C++ interface
assemble_scalar_impl.h
1 // Copyright (C) 2019-2020 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 "Form.h"
10 #include "utils.h"
11 #include <dolfinx/common/IndexMap.h>
12 #include <dolfinx/common/types.h>
13 #include <dolfinx/fem/Constant.h>
14 #include <dolfinx/fem/FunctionSpace.h>
15 #include <dolfinx/mesh/Geometry.h>
16 #include <dolfinx/mesh/Mesh.h>
17 #include <dolfinx/mesh/Topology.h>
18 #include <memory>
19 #include <vector>
20 
21 namespace dolfinx::fem::impl
22 {
23 
25 template <typename T>
26 T assemble_cells(const mesh::Geometry& geometry,
27  const xtl::span<const std::int32_t>& active_cells,
28  const std::function<void(T*, const T*, const T*, const double*,
29  const int*, const std::uint8_t*)>& fn,
30  const xtl::span<const T>& constants, const array2d<T>& coeffs)
31 {
32  // Prepare cell geometry
33  const graph::AdjacencyList<std::int32_t>& x_dofmap = geometry.dofmap();
34 
35  // FIXME: Add proper interface for num coordinate dofs
36  const std::size_t num_dofs_g = x_dofmap.num_links(0);
37  const xt::xtensor<double, 2>& x_g = geometry.x();
38 
39  // Create data structures used in assembly
40  std::vector<double> coordinate_dofs(3 * num_dofs_g);
41 
42  // Iterate over all cells
43  T value(0);
44  for (std::int32_t c : active_cells)
45  {
46  // Get cell coordinates/geometry
47  auto x_dofs = x_dofmap.links(c);
48  for (std::size_t i = 0; i < x_dofs.size(); ++i)
49  {
50  std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
51  std::next(coordinate_dofs.begin(), 3 * i));
52  }
53 
54  auto coeff_cell = coeffs.row(c);
55  fn(&value, coeff_cell.data(), constants.data(), coordinate_dofs.data(),
56  nullptr, nullptr);
57  }
58 
59  return value;
60 }
61 
63 template <typename T>
64 T assemble_exterior_facets(
65  const mesh::Mesh& mesh, const xtl::span<const std::int32_t>& active_facets,
66  const std::function<void(T*, const T*, const T*, const double*, const int*,
67  const std::uint8_t*)>& fn,
68  const xtl::span<const T>& constants, const array2d<T>& coeffs,
69  const xtl::span<const std::uint8_t>& perms)
70 {
71  const int tdim = mesh.topology().dim();
72 
73  // Prepare cell geometry
74  const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.geometry().dofmap();
75 
76  // FIXME: Add proper interface for num coordinate dofs
77  const std::size_t num_dofs_g = x_dofmap.num_links(0);
78  const xt::xtensor<double, 2>& x_g = mesh.geometry().x();
79 
80  // Create data structures used in assembly
81  std::vector<double> coordinate_dofs(3 * num_dofs_g);
82 
83  auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
84  assert(f_to_c);
85  auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
86  assert(c_to_f);
87 
88  // Iterate over all facets
89  T value(0);
90  for (std::int32_t facet : active_facets)
91  {
92  // Create attached cell
93  assert(f_to_c->num_links(facet) == 1);
94  const int cell = f_to_c->links(facet)[0];
95 
96  // Get local index of facet with respect to the cell
97  auto facets = c_to_f->links(cell);
98  auto it = std::find(facets.begin(), facets.end(), facet);
99  assert(it != facets.end());
100  const int local_facet = std::distance(facets.data(), it);
101 
102  // Get cell coordinates/geometry
103  auto x_dofs = x_dofmap.links(cell);
104  for (std::size_t i = 0; i < x_dofs.size(); ++i)
105  {
106  std::copy_n(xt::row(x_g, x_dofs[i]).begin(), 3,
107  std::next(coordinate_dofs.begin(), 3 * i));
108  }
109 
110  auto coeff_cell = coeffs.row(cell);
111  fn(&value, coeff_cell.data(), constants.data(), coordinate_dofs.data(),
112  &local_facet, &perms[cell * facets.size() + local_facet]);
113  }
114 
115  return value;
116 }
117 
119 template <typename T>
120 T assemble_interior_facets(
121  const mesh::Mesh& mesh, const xtl::span<const std::int32_t>& active_facets,
122  const std::function<void(T*, const T*, const T*, const double*, const int*,
123  const std::uint8_t*)>& fn,
124  const xtl::span<const T>& constants, const array2d<T>& coeffs,
125  const xtl::span<const int>& offsets,
126  const xtl::span<const std::uint8_t>& perms)
127 {
128  const int tdim = mesh.topology().dim();
129 
130  // Prepare cell geometry
131  const graph::AdjacencyList<std::int32_t>& x_dofmap = mesh.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 = mesh.geometry().x();
136 
137  // Create data structures used in assembly
138  xt::xtensor<double, 3> coordinate_dofs({2, num_dofs_g, 3});
139  std::vector<T> coeff_array(2 * offsets.back());
140  assert(offsets.back() == coeffs.shape[1]);
141 
142  auto f_to_c = mesh.topology().connectivity(tdim - 1, tdim);
143  assert(f_to_c);
144  auto c_to_f = mesh.topology().connectivity(tdim, tdim - 1);
145  assert(c_to_f);
146 
147  // Iterate over all facets
148  T value = 0;
149  for (std::int32_t f : active_facets)
150  {
151  // Create attached cell
152  auto cells = f_to_c->links(f);
153  assert(cells.size() == 2);
154 
155  const int facets_per_cell = c_to_f->num_links(cells[0]);
156 
157  // Get local index of facet with respect to the cell
158  std::array<int, 2> local_facet;
159  for (int i = 0; i < 2; ++i)
160  {
161  auto facets = c_to_f->links(cells[i]);
162  auto it = std::find(facets.begin(), facets.end(), f);
163  assert(it != facets.end());
164  local_facet[i] = std::distance(facets.begin(), it);
165  }
166 
167  // Get cell geometry
168  auto x_dofs0 = x_dofmap.links(cells[0]);
169  for (std::size_t i = 0; i < x_dofs0.size(); ++i)
170  {
171  std::copy_n(xt::view(x_g, x_dofs0[i]).begin(), 3,
172  xt::view(coordinate_dofs, 0, i, xt::all()).begin());
173  }
174  auto x_dofs1 = x_dofmap.links(cells[1]);
175  for (std::size_t i = 0; i < x_dofs1.size(); ++i)
176  {
177  std::copy_n(xt::view(x_g, x_dofs1[i]).begin(), 3,
178  xt::view(coordinate_dofs, 1, i, xt::all()).begin());
179  }
180 
181  // Layout for the restricted coefficients is flattened
182  // w[coefficient][restriction][dof]
183  auto coeff_cell0 = coeffs.row(cells[0]);
184  auto coeff_cell1 = coeffs.row(cells[1]);
185 
186  // Loop over coefficients
187  for (std::size_t i = 0; i < offsets.size() - 1; ++i)
188  {
189  // Loop over entries for coefficient i
190  const int num_entries = offsets[i + 1] - offsets[i];
191  std::copy_n(coeff_cell0.data() + offsets[i], num_entries,
192  std::next(coeff_array.begin(), 2 * offsets[i]));
193  std::copy_n(coeff_cell1.data() + offsets[i], num_entries,
194  std::next(coeff_array.begin(), offsets[i + 1] + offsets[i]));
195  }
196 
197  const std::array perm{perms[cells[0] * facets_per_cell + local_facet[0]],
198  perms[cells[1] * facets_per_cell + local_facet[1]]};
199  fn(&value, coeff_array.data(), constants.data(), coordinate_dofs.data(),
200  local_facet.data(), perm.data());
201  }
202 
203  return value;
204 }
205 
207 template <typename T>
208 T assemble_scalar(const fem::Form<T>& M, const xtl::span<const T>& constants,
209  const array2d<T>& coeffs)
210 {
211  std::shared_ptr<const mesh::Mesh> mesh = M.mesh();
212  assert(mesh);
213  const int tdim = mesh->topology().dim();
214 
215  T value(0);
216  for (int i : M.integral_ids(IntegralType::cell))
217  {
218  const auto& fn = M.kernel(IntegralType::cell, i);
219  const std::vector<std::int32_t>& active_cells
220  = M.domains(IntegralType::cell, i);
221  value += impl::assemble_cells(mesh->geometry(), active_cells, fn, constants,
222  coeffs);
223  }
224 
225  if (M.num_integrals(IntegralType::exterior_facet) > 0
226  or M.num_integrals(IntegralType::interior_facet) > 0)
227  {
228  // FIXME: cleanup these calls? Some of these happen internally again.
229  mesh->topology_mutable().create_entities(tdim - 1);
230  mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
231  mesh->topology_mutable().create_entity_permutations();
232 
233  const std::vector<std::uint8_t>& perms
234  = mesh->topology().get_facet_permutations();
235 
236  for (int i : M.integral_ids(IntegralType::exterior_facet))
237  {
238  const auto& fn = M.kernel(IntegralType::exterior_facet, i);
239  const std::vector<std::int32_t>& active_facets
240  = M.domains(IntegralType::exterior_facet, i);
241  value += impl::assemble_exterior_facets(*mesh, active_facets, fn,
242  constants, coeffs, perms);
243  }
244 
245  const std::vector<int> c_offsets = M.coefficient_offsets();
246  for (int i : M.integral_ids(IntegralType::interior_facet))
247  {
248  const auto& fn = M.kernel(IntegralType::interior_facet, i);
249  const std::vector<std::int32_t>& active_facets
250  = M.domains(IntegralType::interior_facet, i);
251  value += impl::assemble_interior_facets(
252  *mesh, active_facets, fn, constants, coeffs, c_offsets, perms);
253  }
254  }
255 
256  return value;
257 }
258 
259 } // namespace dolfinx::fem::impl
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
T assemble_scalar(const Form< T > &M, const xtl::span< const T > &constants, const array2d< T > &coeffs)
Assemble functional into scalar. The caller supplies the form constants and coefficients for this ver...
Definition: assembler.h:36