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
utils.h
1 // Copyright (C) 2013-2020 Johan Hake, Jan Blechta and 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 "CoordinateElement.h"
10 #include "DofMap.h"
11 #include "ElementDofLayout.h"
12 #include <dolfinx/common/types.h>
13 #include <dolfinx/fem/Form.h>
14 #include <dolfinx/fem/Function.h>
15 #include <dolfinx/la/SparsityPattern.h>
16 #include <dolfinx/mesh/cell_types.h>
17 #include <memory>
18 #include <set>
19 #include <string>
20 #include <ufc.h>
21 #include <utility>
22 #include <vector>
23 
24 namespace dolfinx
25 {
26 namespace common
27 {
28 class IndexMap;
29 }
30 
31 namespace mesh
32 {
33 class Mesh;
34 class Topology;
35 } // namespace mesh
36 
37 namespace fem
38 {
39 
40 template <typename T>
41 class Constant;
42 template <typename T>
43 class Form;
44 template <typename T>
45 class Function;
46 class FunctionSpace;
47 
55 template <typename T>
56 std::vector<
57  std::vector<std::array<std::shared_ptr<const fem::FunctionSpace>, 2>>>
58 extract_function_spaces(const std::vector<std::vector<const fem::Form<T>*>>& a)
59 {
60  std::vector<
61  std::vector<std::array<std::shared_ptr<const fem::FunctionSpace>, 2>>>
62  spaces(
63  a.size(),
64  std::vector<std::array<std::shared_ptr<const fem::FunctionSpace>, 2>>(
65  a[0].size()));
66  for (std::size_t i = 0; i < a.size(); ++i)
67  {
68  for (std::size_t j = 0; j < a[i].size(); ++j)
69  {
70  if (const fem::Form<T>* form = a[i][j]; form)
71  spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
72  }
73  }
74  return spaces;
75 }
76 
82 template <typename T>
84 {
85  if (a.rank() != 2)
86  {
87  throw std::runtime_error(
88  "Cannot create sparsity pattern. Form is not a bilinear form");
89  }
90 
91  // Get dof maps and mesh
92  std::array<const std::reference_wrapper<const fem::DofMap>, 2> dofmaps{
93  *a.function_spaces().at(0)->dofmap(),
94  *a.function_spaces().at(1)->dofmap()};
95  std::shared_ptr mesh = a.mesh();
96  assert(mesh);
97 
98  const std::set<IntegralType> types = a.integral_types();
99  if (types.find(IntegralType::interior_facet) != types.end()
100  or types.find(IntegralType::exterior_facet) != types.end())
101  {
102  // FIXME: cleanup these calls? Some of the happen internally again.
103  const int tdim = mesh->topology().dim();
104  mesh->topology_mutable().create_entities(tdim - 1);
105  mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
106  }
107 
108  return create_sparsity_pattern(mesh->topology(), dofmaps, types);
109 }
110 
115  const mesh::Topology& topology,
116  const std::array<const std::reference_wrapper<const fem::DofMap>, 2>&
117  dofmaps,
118  const std::set<IntegralType>& integrals);
119 
121 ElementDofLayout create_element_dof_layout(const ufc_dofmap& dofmap,
122  const mesh::CellType cell_type,
123  const std::vector<int>& parent_map
124  = {});
125 
130 DofMap create_dofmap(MPI_Comm comm, const ufc_dofmap& dofmap,
131  mesh::Topology& topology);
132 
136 std::vector<std::string> get_coefficient_names(const ufc_form& ufc_form);
137 
141 std::vector<std::string> get_constant_names(const ufc_form& ufc_form);
142 
150 template <typename T>
152  const ufc_form& ufc_form,
153  const std::vector<std::shared_ptr<const fem::FunctionSpace>>& spaces,
154  const std::vector<std::shared_ptr<const fem::Function<T>>>& coefficients,
155  const std::vector<std::shared_ptr<const fem::Constant<T>>>& constants,
156  const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
157  const std::shared_ptr<const mesh::Mesh>& mesh = nullptr)
158 {
159  if (ufc_form.rank != (int)spaces.size())
160  throw std::runtime_error("Wrong number of argument spaces for Form.");
161  if (ufc_form.num_coefficients != (int)coefficients.size())
162  {
163  throw std::runtime_error(
164  "Mismatch between number of expected and provided Form coefficients.");
165  }
166  if (ufc_form.num_constants != (int)constants.size())
167  {
168  throw std::runtime_error(
169  "Mismatch between number of expected and provided Form constants.");
170  }
171 
172  // Check argument function spaces
173 #ifdef DEBUG
174  for (std::size_t i = 0; i < spaces.size(); ++i)
175  {
176  assert(spaces[i]->element());
177  ufc_finite_element* ufc_element = ufc_form.finite_elements[i];
178  assert(ufc_element);
179  if (std::string(ufc_element->signature)
180  != spaces[i]->element()->signature())
181  {
182  throw std::runtime_error(
183  "Cannot create form. Wrong type of function space for argument.");
184  }
185  }
186 #endif
187 
188  // Get list of integral IDs, and load tabulate tensor into memory for
189  // each
190  using kern
191  = std::function<void(T*, const T*, const T*, const double*, const int*,
192  const std::uint8_t*, const std::uint32_t)>;
193  std::map<IntegralType, std::pair<std::vector<std::pair<int, kern>>,
194  const mesh::MeshTags<int>*>>
195  integral_data;
196 
197  bool needs_permutation_data = false;
198 
199  // Attach cell kernels
200  std::vector<int> cell_integral_ids(ufc_form.integral_ids(cell),
201  ufc_form.integral_ids(cell)
202  + ufc_form.num_integrals(cell));
203  for (int i = 0; i < ufc_form.num_integrals(cell); ++i)
204  {
205  ufc_integral* integral = ufc_form.integrals(cell)[i];
206  assert(integral);
207  if (integral->needs_transformation_data)
208  needs_permutation_data = true;
209  integral_data[IntegralType::cell].first.emplace_back(
210  cell_integral_ids[i], integral->tabulate_tensor);
211  }
212 
213  // Attach cell subdomain data
214  if (auto it = subdomains.find(IntegralType::cell);
215  it != subdomains.end() and !cell_integral_ids.empty())
216  {
217  integral_data[IntegralType::cell].second = it->second;
218  }
219 
220  // FIXME: Can facets be handled better?
221 
222  // Create facets, if required
223  if (ufc_form.num_integrals(exterior_facet) > 0
224  or ufc_form.num_integrals(interior_facet) > 0)
225  {
226  if (!spaces.empty())
227  {
228  auto mesh = spaces[0]->mesh();
229  const int tdim = mesh->topology().dim();
230  spaces[0]->mesh()->topology_mutable().create_entities(tdim - 1);
231  }
232  }
233 
234  // Attach exterior facet kernels
235  std::vector<int> exterior_facet_integral_ids(
236  ufc_form.integral_ids(exterior_facet),
237  ufc_form.integral_ids(exterior_facet)
238  + ufc_form.num_integrals(exterior_facet));
239  for (int i = 0; i < ufc_form.num_integrals(exterior_facet); ++i)
240  {
241  ufc_integral* integral = ufc_form.integrals(exterior_facet)[i];
242  assert(integral);
243  if (integral->needs_transformation_data)
244  needs_permutation_data = true;
245  integral_data[IntegralType::exterior_facet].first.emplace_back(
246  exterior_facet_integral_ids[i], integral->tabulate_tensor);
247  }
248 
249  // Attach exterior facet subdomain data
250  if (auto it = subdomains.find(IntegralType::exterior_facet);
251  it != subdomains.end() and !exterior_facet_integral_ids.empty())
252  {
253  integral_data[IntegralType::exterior_facet].second = it->second;
254  }
255 
256  // Attach interior facet kernels
257  std::vector<int> interior_facet_integral_ids(
258  ufc_form.integral_ids(interior_facet),
259  ufc_form.integral_ids(interior_facet)
260  + ufc_form.num_integrals(interior_facet));
261  for (int i = 0; i < ufc_form.num_integrals(interior_facet); ++i)
262  {
263  ufc_integral* integral = ufc_form.integrals(interior_facet)[i];
264  assert(integral);
265  if (integral->needs_transformation_data)
266  needs_permutation_data = true;
267  integral_data[IntegralType::interior_facet].first.emplace_back(
268  interior_facet_integral_ids[i], integral->tabulate_tensor);
269  }
270 
271  // Attach interior facet subdomain data
272  if (auto it = subdomains.find(IntegralType::interior_facet);
273  it != subdomains.end() and !interior_facet_integral_ids.empty())
274  {
275  integral_data[IntegralType::interior_facet].second = it->second;
276  }
277 
278  return fem::Form(spaces, integral_data, coefficients, constants,
279  needs_permutation_data, mesh);
280 }
281 
291 template <typename T>
293  const ufc_form& ufc_form,
294  const std::vector<std::shared_ptr<const fem::FunctionSpace>>& spaces,
295  const std::map<std::string, std::shared_ptr<const fem::Function<T>>>&
296  coefficients,
297  const std::map<std::string, std::shared_ptr<const fem::Constant<T>>>&
298  constants,
299  const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
300  const std::shared_ptr<const mesh::Mesh>& mesh = nullptr)
301 {
302  // Place coefficients in appropriate order
303  std::vector<std::shared_ptr<const fem::Function<T>>> coeff_map;
304  for (const std::string& name : get_coefficient_names(ufc_form))
305  {
306  if (auto it = coefficients.find(name); it != coefficients.end())
307  coeff_map.push_back(it->second);
308  else
309  {
310  throw std::runtime_error("Form coefficient \"" + name
311  + "\" not provided.");
312  }
313  }
314 
315  // Place constants in appropriate order
316  std::vector<std::shared_ptr<const fem::Constant<T>>> const_map;
317  for (const std::string& name : get_constant_names(ufc_form))
318  {
319  if (auto it = constants.find(name); it != constants.end())
320  const_map.push_back(it->second);
321  else
322  {
323  throw std::runtime_error("Form constant \"" + name + "\" not provided.");
324  }
325  }
326 
327  return create_form(ufc_form, spaces, coeff_map, const_map, subdomains, mesh);
328 }
329 
341 template <typename T>
342 std::shared_ptr<Form<T>> create_form(
343  ufc_form* (*fptr)(),
344  const std::vector<std::shared_ptr<const fem::FunctionSpace>>& spaces,
345  const std::map<std::string, std::shared_ptr<const fem::Function<T>>>&
346  coefficients,
347  const std::map<std::string, std::shared_ptr<const fem::Constant<T>>>&
348  constants,
349  const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
350  const std::shared_ptr<const mesh::Mesh>& mesh = nullptr)
351 {
352  ufc_form* form = fptr();
353  auto L = std::make_shared<fem::Form<T>>(fem::create_form<T>(
354  *form, spaces, coefficients, constants, subdomains, mesh));
355  std::free(form);
356  return L;
357 }
358 
368 std::shared_ptr<fem::FunctionSpace>
369 create_functionspace(ufc_function_space* (*fptr)(const char*),
370  const std::string function_name,
371  std::shared_ptr<mesh::Mesh> mesh);
372 
373 // NOTE: This is subject to change
375 template <typename U>
377 {
378  using T = typename U::scalar_type;
379 
380  // Get form coefficient offsets and dofmaps
381  const std::vector<std::shared_ptr<const fem::Function<T>>> coefficients
382  = u.coefficients();
383  const std::vector<int> offsets = u.coefficient_offsets();
384  std::vector<const fem::DofMap*> dofmaps(coefficients.size());
385  std::vector<int> bs(coefficients.size());
386  std::vector<std::reference_wrapper<const std::vector<T>>> v;
387  v.reserve(coefficients.size());
388  for (std::size_t i = 0; i < coefficients.size(); ++i)
389  {
390  dofmaps[i] = coefficients[i]->function_space()->dofmap().get();
391  bs[i] = dofmaps[i]->bs();
392  v.push_back(coefficients[i]->x()->array());
393  }
394 
395  // Get mesh
396  std::shared_ptr<const mesh::Mesh> mesh = u.mesh();
397  assert(mesh);
398  const int tdim = mesh->topology().dim();
399  const std::int32_t num_cells
400  = mesh->topology().index_map(tdim)->size_local()
401  + mesh->topology().index_map(tdim)->num_ghosts();
402 
403  // Copy data into coefficient array
404  array2d<T> c(num_cells, offsets.back());
405  if (!coefficients.empty())
406  {
407  for (int cell = 0; cell < num_cells; ++cell)
408  {
409  for (std::size_t coeff = 0; coeff < dofmaps.size(); ++coeff)
410  {
411  xtl::span<const std::int32_t> dofs = dofmaps[coeff]->cell_dofs(cell);
412  const std::vector<T>& _v = v[coeff];
413  for (std::size_t i = 0; i < dofs.size(); ++i)
414  {
415  for (int k = 0; k < bs[coeff]; ++k)
416  {
417  c(cell, bs[coeff] * i + k + offsets[coeff])
418  = _v[bs[coeff] * dofs[i] + k];
419  }
420  }
421  }
422  }
423  }
424 
425  return c;
426 }
427 
428 // NOTE: This is subject to change
430 template <typename U>
431 std::vector<typename U::scalar_type> pack_constants(const U& u)
432 {
433  using T = typename U::scalar_type;
434  const std::vector<std::shared_ptr<const fem::Constant<T>>>& constants
435  = u.constants();
436 
437  // Calculate size of array needed to store packed constants
438  std::int32_t size
439  = std::accumulate(constants.begin(), constants.end(), 0,
440  [](std::int32_t sum, const auto& constant) {
441  return sum + constant->value.size();
442  });
443 
444  // Pack constants
445  std::vector<T> constant_values(size);
446  std::int32_t offset = 0;
447  for (const auto& constant : constants)
448  {
449  const std::vector<T>& value = constant->value;
450  for (std::size_t i = 0; i < value.size(); ++i)
451  constant_values[offset + i] = value[i];
452  offset += value.size();
453  }
454 
455  return constant_values;
456 }
457 
458 } // namespace fem
459 } // namespace dolfinx
dolfinx::fem::IntegralType
IntegralType
Type of integral.
Definition: Form.h:26
dolfinx::fem::Function
This class represents a function in a finite element function space , given by.
Definition: Form.h:23
dolfinx::mesh::CellType
CellType
Cell type identifier.
Definition: cell_types.h:21
dolfinx::fem::Form::integral_types
std::set< IntegralType > integral_types() const
Get types of integrals in the form.
Definition: Form.h:175
dolfinx::fem::Form::rank
int rank() const
Rank of the form (bilinear form = 2, linear form = 1, functional = 0, etc)
Definition: Form.h:140
dolfinx::fem::get_constant_names
std::vector< std::string > get_constant_names(const ufc_form &ufc_form)
Get the name of each constant in a UFC form.
Definition: utils.cpp:179
dolfinx::fem::get_coefficient_names
std::vector< std::string > get_coefficient_names(const ufc_form &ufc_form)
Get the name of each coefficient in a UFC form.
Definition: utils.cpp:170
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::la::SparsityPattern
This class provides a sparsity pattern data structure that can be used to initialize sparse matrices.
Definition: SparsityPattern.h:35
dolfinx::fem::Form
Class for variational forms.
Definition: assembler.h:22
dolfinx::mesh::MeshTags
A MeshTags are used to associate mesh entities with values. The entity index (local to process) ident...
Definition: XDMFFile.h:40
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::create_functionspace
std::shared_ptr< fem::FunctionSpace > create_functionspace(ufc_function_space *(*fptr)(const char *), const std::string function_name, std::shared_ptr< mesh::Mesh > mesh)
Create FunctionSpace from UFC.
Definition: utils.cpp:189
dolfinx::fem::create_form
Form< T > create_form(const ufc_form &ufc_form, const std::vector< std::shared_ptr< const fem::FunctionSpace >> &spaces, const std::vector< std::shared_ptr< const fem::Function< T >>> &coefficients, const std::vector< std::shared_ptr< const fem::Constant< T >>> &constants, const std::map< IntegralType, const mesh::MeshTags< int > * > &subdomains, const std::shared_ptr< const mesh::Mesh > &mesh=nullptr)
Create a Form from UFC input.
Definition: utils.h:151
dolfinx::fem::create_element_dof_layout
ElementDofLayout create_element_dof_layout(const ufc_dofmap &dofmap, const mesh::CellType cell_type, const std::vector< int > &parent_map={})
Create an ElementDofLayout from a ufc_dofmap.
Definition: utils.cpp:75
dolfinx::fem::extract_function_spaces
std::vector< std::vector< std::array< std::shared_ptr< const fem::FunctionSpace >, 2 > > > extract_function_spaces(const std::vector< std::vector< const fem::Form< T > * >> &a)
Extract test (0) and trial (1) function spaces pairs for each bilinear form for a rectangular array o...
Definition: utils.h:58
dolfinx::fem::create_dofmap
DofMap create_dofmap(MPI_Comm comm, const ufc_dofmap &dofmap, mesh::Topology &topology)
Create dof map on mesh from a ufc_dofmap.
Definition: utils.cpp:140
dolfinx::fem::Form::mesh
std::shared_ptr< const mesh::Mesh > mesh() const
Extract common mesh for the form.
Definition: Form.h:144
dolfinx::fem::create_sparsity_pattern
la::SparsityPattern create_sparsity_pattern(const Form< T > &a)
Create a sparsity pattern for a given form. The pattern is not finalised, i.e. the caller is responsi...
Definition: utils.h:83
dolfinx::mesh::Topology
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition: Topology.h:56
dolfinx::array2d
This class provides a dynamic 2-dimensional row-wise array data structure.
Definition: array2d.h:20
dolfinx::fem::Constant
A constant value which can be attached to a Form. Constants may be scalar (rank 0),...
Definition: Constant.h:18
dolfinx::fem::Form::function_spaces
const std::vector< std::shared_ptr< const fem::FunctionSpace > > & function_spaces() const
Return function spaces for all arguments.
Definition: Form.h:149