Note: this is documentation for an old release. View the latest documentation at docs.fenicsproject.org/dolfinx/v0.9.0/cpp/doxygen/d9/dc0/fem_2utils_8h_source.html
DOLFINx 0.6.0
DOLFINx C++ interface
Loading...
Searching...
No Matches
utils.h
Go to the documentation of this file.
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 "Constant.h"
10#include "CoordinateElement.h"
11#include "DofMap.h"
12#include "ElementDofLayout.h"
13#include "Expression.h"
14#include "Form.h"
15#include "Function.h"
16#include "sparsitybuild.h"
17#include <array>
18#include <concepts>
19#include <dolfinx/la/SparsityPattern.h>
20#include <dolfinx/mesh/cell_types.h>
21#include <functional>
22#include <memory>
23#include <set>
24#include <span>
25#include <stdexcept>
26#include <string>
27#include <type_traits>
28#include <ufcx.h>
29#include <utility>
30#include <vector>
31
34
35namespace basix
36{
37class FiniteElement;
38}
39
40namespace dolfinx::common
41{
42class IndexMap;
43}
44
45namespace dolfinx::mesh
46{
47class Mesh;
48class Topology;
49} // namespace dolfinx::mesh
50
51namespace dolfinx::fem
52{
53class FunctionSpace;
54
55namespace impl
56{
59template <typename T, typename = void>
60struct scalar_value_type
61{
63 typedef T value_type;
64};
66template <typename T>
67struct scalar_value_type<T, std::void_t<typename T::value_type>>
68{
69 typedef typename T::value_type value_type;
70};
72template <typename T>
73using scalar_value_type_t = typename scalar_value_type<T>::value_type;
74
75} // namespace impl
76
81template <class U, class T>
82concept FEkernel = std::is_invocable_v<U, T*, const T*, const T*,
83 const impl::scalar_value_type_t<T>*,
84 const int*, const std::uint8_t*>;
85
93template <typename T>
94std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace>, 2>>>
95extract_function_spaces(const std::vector<std::vector<const Form<T>*>>& a)
96{
97 std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace>, 2>>>
98 spaces(a.size(),
99 std::vector<std::array<std::shared_ptr<const FunctionSpace>, 2>>(
100 a[0].size()));
101 for (std::size_t i = 0; i < a.size(); ++i)
102 {
103 for (std::size_t j = 0; j < a[i].size(); ++j)
104 {
105 if (const Form<T>* form = a[i][j]; form)
106 spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
107 }
108 }
109 return spaces;
110}
111
116 const mesh::Topology& topology,
117 const std::array<std::reference_wrapper<const DofMap>, 2>& dofmaps,
118 const std::set<IntegralType>& integrals);
119
125template <typename T>
127{
128 if (a.rank() != 2)
129 {
130 throw std::runtime_error(
131 "Cannot create sparsity pattern. Form is not a bilinear form");
132 }
133
134 // Get dof maps and mesh
135 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
136 *a.function_spaces().at(0)->dofmap(),
137 *a.function_spaces().at(1)->dofmap()};
138 std::shared_ptr mesh = a.mesh();
139 assert(mesh);
140
141 const std::set<IntegralType> types = a.integral_types();
142 if (types.find(IntegralType::interior_facet) != types.end()
143 or types.find(IntegralType::exterior_facet) != types.end())
144 {
145 // FIXME: cleanup these calls? Some of the happen internally again.
146 const int tdim = mesh->topology().dim();
147 mesh->topology_mutable().create_entities(tdim - 1);
148 mesh->topology_mutable().create_connectivity(tdim - 1, tdim);
149 }
150
151 common::Timer t0("Build sparsity");
152
153 // Get common::IndexMaps for each dimension
154 const std::array index_maps{dofmaps[0].get().index_map,
155 dofmaps[1].get().index_map};
156 const std::array bs
157 = {dofmaps[0].get().index_map_bs(), dofmaps[1].get().index_map_bs()};
158
159 // Create and build sparsity pattern
160 la::SparsityPattern pattern(mesh->comm(), index_maps, bs);
161 for (auto type : types)
162 {
163 std::vector<int> ids = a.integral_ids(type);
164 switch (type)
165 {
167 for (int id : ids)
168 {
169 const std::vector<std::int32_t>& cells = a.cell_domains(id);
170 sparsitybuild::cells(pattern, cells, {{dofmaps[0], dofmaps[1]}});
171 }
172 break;
174 for (int id : ids)
175 {
176 const std::vector<std::int32_t>& facets = a.interior_facet_domains(id);
177 sparsitybuild::interior_facets(pattern, facets,
178 {{dofmaps[0], dofmaps[1]}});
179 }
180 break;
182 for (int id : ids)
183 {
184 const std::vector<std::int32_t>& facets = a.exterior_facet_domains(id);
185 sparsitybuild::exterior_facets(pattern, facets,
186 {{dofmaps[0], dofmaps[1]}});
187 }
188 break;
189 default:
190 throw std::runtime_error("Unsupported integral type");
191 }
192 }
193
194 t0.stop();
195
196 return pattern;
197}
198
200ElementDofLayout create_element_dof_layout(const ufcx_dofmap& dofmap,
201 const mesh::CellType cell_type,
202 const std::vector<int>& parent_map
203 = {});
204
213DofMap
214create_dofmap(MPI_Comm comm, const ElementDofLayout& layout,
215 mesh::Topology& topology,
216 const std::function<std::vector<int>(
217 const graph::AdjacencyList<std::int32_t>&)>& reorder_fn,
218 const FiniteElement& element);
219
223std::vector<std::string> get_coefficient_names(const ufcx_form& ufcx_form);
224
228std::vector<std::string> get_constant_names(const ufcx_form& ufcx_form);
229
237template <typename T>
239 const ufcx_form& ufcx_form,
240 const std::vector<std::shared_ptr<const FunctionSpace>>& spaces,
241 const std::vector<std::shared_ptr<const Function<T>>>& coefficients,
242 const std::vector<std::shared_ptr<const Constant<T>>>& constants,
243 const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
244 std::shared_ptr<const mesh::Mesh> mesh = nullptr)
245{
246 if (ufcx_form.rank != (int)spaces.size())
247 throw std::runtime_error("Wrong number of argument spaces for Form.");
248 if (ufcx_form.num_coefficients != (int)coefficients.size())
249 {
250 throw std::runtime_error(
251 "Mismatch between number of expected and provided Form coefficients.");
252 }
253 if (ufcx_form.num_constants != (int)constants.size())
254 {
255 throw std::runtime_error(
256 "Mismatch between number of expected and provided Form constants.");
257 }
258
259 // Check argument function spaces
260#ifndef NDEBUG
261 for (std::size_t i = 0; i < spaces.size(); ++i)
262 {
263 assert(spaces[i]->element());
264 ufcx_finite_element* ufcx_element = ufcx_form.finite_elements[i];
265 assert(ufcx_element);
266 if (std::string(ufcx_element->signature)
267 != spaces[i]->element()->signature())
268 {
269 throw std::runtime_error(
270 "Cannot create form. Wrong type of function space for argument.");
271 }
272 }
273#endif
274
275 // Get list of integral IDs, and load tabulate tensor into memory for
276 // each
277 using kern = std::function<void(
278 T*, const T*, const T*,
279 const typename impl::scalar_value_type<T>::value_type*, const int*,
280 const std::uint8_t*)>;
281 std::map<IntegralType, std::pair<std::vector<std::pair<int, kern>>,
282 const mesh::MeshTags<int>*>>
283 integral_data;
284
285 bool needs_facet_permutations = false;
286
287 // Attach cell kernels
288 std::vector<int> cell_integral_ids(ufcx_form.integral_ids(cell),
289 ufcx_form.integral_ids(cell)
290 + ufcx_form.num_integrals(cell));
291 for (int i = 0; i < ufcx_form.num_integrals(cell); ++i)
292 {
293 ufcx_integral* integral = ufcx_form.integrals(cell)[i];
294 assert(integral);
295
296 kern k = nullptr;
297 if constexpr (std::is_same_v<T, float>)
298 k = integral->tabulate_tensor_float32;
299 else if constexpr (std::is_same_v<T, std::complex<float>>)
300 {
301 k = reinterpret_cast<void (*)(
302 T*, const T*, const T*,
303 const typename impl::scalar_value_type<T>::value_type*, const int*,
304 const unsigned char*)>(integral->tabulate_tensor_complex64);
305 }
306 else if constexpr (std::is_same_v<T, double>)
307 k = integral->tabulate_tensor_float64;
308 else if constexpr (std::is_same_v<T, std::complex<double>>)
309 {
310 k = reinterpret_cast<void (*)(
311 T*, const T*, const T*,
312 const typename impl::scalar_value_type<T>::value_type*, const int*,
313 const unsigned char*)>(integral->tabulate_tensor_complex128);
314 }
315 assert(k);
316
317 integral_data[IntegralType::cell].first.emplace_back(cell_integral_ids[i],
318 k);
319 if (integral->needs_facet_permutations)
320 needs_facet_permutations = true;
321 }
322
323 // Attach cell subdomain data
324 if (auto it = subdomains.find(IntegralType::cell);
325 it != subdomains.end() and !cell_integral_ids.empty())
326 {
327 integral_data[IntegralType::cell].second = it->second;
328 }
329
330 // FIXME: Can facets be handled better?
331
332 // Create facets, if required
333 if (ufcx_form.num_integrals(exterior_facet) > 0
334 or ufcx_form.num_integrals(interior_facet) > 0)
335 {
336 if (!spaces.empty())
337 {
338 auto mesh = spaces[0]->mesh();
339 const int tdim = mesh->topology().dim();
340 spaces[0]->mesh()->topology_mutable().create_entities(tdim - 1);
341 }
342 }
343
344 // Attach exterior facet kernels
345 std::vector<int> exterior_facet_integral_ids(
346 ufcx_form.integral_ids(exterior_facet),
347 ufcx_form.integral_ids(exterior_facet)
348 + ufcx_form.num_integrals(exterior_facet));
349 for (int i = 0; i < ufcx_form.num_integrals(exterior_facet); ++i)
350 {
351 ufcx_integral* integral = ufcx_form.integrals(exterior_facet)[i];
352 assert(integral);
353
354 kern k = nullptr;
355 if constexpr (std::is_same_v<T, float>)
356 k = integral->tabulate_tensor_float32;
357 else if constexpr (std::is_same_v<T, std::complex<float>>)
358 {
359 k = reinterpret_cast<void (*)(
360 T*, const T*, const T*,
361 const typename impl::scalar_value_type<T>::value_type*, const int*,
362 const unsigned char*)>(integral->tabulate_tensor_complex64);
363 }
364 else if constexpr (std::is_same_v<T, double>)
365 k = integral->tabulate_tensor_float64;
366 else if constexpr (std::is_same_v<T, std::complex<double>>)
367 {
368 k = reinterpret_cast<void (*)(
369 T*, const T*, const T*,
370 const typename impl::scalar_value_type<T>::value_type*, const int*,
371 const unsigned char*)>(integral->tabulate_tensor_complex128);
372 }
373 assert(k);
374
375 integral_data[IntegralType::exterior_facet].first.emplace_back(
376 exterior_facet_integral_ids[i], k);
377 if (integral->needs_facet_permutations)
378 needs_facet_permutations = true;
379 }
380
381 // Attach exterior facet subdomain data
382 if (auto it = subdomains.find(IntegralType::exterior_facet);
383 it != subdomains.end() and !exterior_facet_integral_ids.empty())
384 {
385 integral_data[IntegralType::exterior_facet].second = it->second;
386 }
387
388 // Attach interior facet kernels
389 std::vector<int> interior_facet_integral_ids(
390 ufcx_form.integral_ids(interior_facet),
391 ufcx_form.integral_ids(interior_facet)
392 + ufcx_form.num_integrals(interior_facet));
393 for (int i = 0; i < ufcx_form.num_integrals(interior_facet); ++i)
394 {
395 ufcx_integral* integral = ufcx_form.integrals(interior_facet)[i];
396 assert(integral);
397
398 kern k = nullptr;
399 if constexpr (std::is_same_v<T, float>)
400 k = integral->tabulate_tensor_float32;
401 else if constexpr (std::is_same_v<T, std::complex<float>>)
402 {
403 k = reinterpret_cast<void (*)(
404 T*, const T*, const T*,
405 const typename impl::scalar_value_type<T>::value_type*, const int*,
406 const unsigned char*)>(integral->tabulate_tensor_complex64);
407 }
408 else if constexpr (std::is_same_v<T, double>)
409 k = integral->tabulate_tensor_float64;
410 else if constexpr (std::is_same_v<T, std::complex<double>>)
411 {
412 k = reinterpret_cast<void (*)(
413 T*, const T*, const T*,
414 const typename impl::scalar_value_type<T>::value_type*, const int*,
415 const unsigned char*)>(integral->tabulate_tensor_complex128);
416 }
417 assert(k);
418
419 integral_data[IntegralType::interior_facet].first.emplace_back(
420 interior_facet_integral_ids[i], k);
421 if (integral->needs_facet_permutations)
422 needs_facet_permutations = true;
423 }
424
425 // Attach interior facet subdomain data
426 if (auto it = subdomains.find(IntegralType::interior_facet);
427 it != subdomains.end() and !interior_facet_integral_ids.empty())
428 {
429 integral_data[IntegralType::interior_facet].second = it->second;
430 }
431
432 return Form<T>(spaces, integral_data, coefficients, constants,
433 needs_facet_permutations, mesh);
434}
435
445template <typename T>
447 const ufcx_form& ufcx_form,
448 const std::vector<std::shared_ptr<const FunctionSpace>>& spaces,
449 const std::map<std::string, std::shared_ptr<const Function<T>>>&
450 coefficients,
451 const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
452 const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
453 std::shared_ptr<const mesh::Mesh> mesh = nullptr)
454{
455 // Place coefficients in appropriate order
456 std::vector<std::shared_ptr<const Function<T>>> coeff_map;
457 for (const std::string& name : get_coefficient_names(ufcx_form))
458 {
459 if (auto it = coefficients.find(name); it != coefficients.end())
460 coeff_map.push_back(it->second);
461 else
462 {
463 throw std::runtime_error("Form coefficient \"" + name
464 + "\" not provided.");
465 }
466 }
467
468 // Place constants in appropriate order
469 std::vector<std::shared_ptr<const Constant<T>>> const_map;
470 for (const std::string& name : get_constant_names(ufcx_form))
471 {
472 if (auto it = constants.find(name); it != constants.end())
473 const_map.push_back(it->second);
474 else
475 throw std::runtime_error("Form constant \"" + name + "\" not provided.");
476 }
477
478 return create_form(ufcx_form, spaces, coeff_map, const_map, subdomains, mesh);
479}
480
492template <typename T>
494 ufcx_form* (*fptr)(),
495 const std::vector<std::shared_ptr<const FunctionSpace>>& spaces,
496 const std::map<std::string, std::shared_ptr<const Function<T>>>&
497 coefficients,
498 const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
499 const std::map<IntegralType, const mesh::MeshTags<int>*>& subdomains,
500 std::shared_ptr<const mesh::Mesh> mesh = nullptr)
501{
502 ufcx_form* form = fptr();
503 Form<T> L = create_form<T>(*form, spaces, coefficients, constants, subdomains,
504 mesh);
505 std::free(form);
506 return L;
507}
508
517FunctionSpace create_functionspace(
518 std::shared_ptr<mesh::Mesh> mesh, const basix::FiniteElement& e, int bs,
519 const std::function<
520 std::vector<int>(const graph::AdjacencyList<std::int32_t>&)>& reorder_fn
521 = nullptr);
522
535FunctionSpace create_functionspace(
536 ufcx_function_space* (*fptr)(const char*), const std::string& function_name,
537 std::shared_ptr<mesh::Mesh> mesh,
538 const std::function<
539 std::vector<int>(const graph::AdjacencyList<std::int32_t>&)>& reorder_fn
540 = nullptr);
541
543namespace impl
544{
546template <typename T>
547std::span<const std::uint32_t> get_cell_orientation_info(
548 const std::vector<std::shared_ptr<const Function<T>>>& coefficients)
549{
550 bool needs_dof_transformations = false;
551 for (auto coeff : coefficients)
552 {
553 std::shared_ptr<const FiniteElement> element
554 = coeff->function_space()->element();
555 if (element->needs_dof_transformations())
556 {
557 needs_dof_transformations = true;
558 break;
559 }
560 }
561
562 std::span<const std::uint32_t> cell_info;
563 if (needs_dof_transformations)
564 {
565 auto mesh = coefficients.front()->function_space()->mesh();
566 mesh->topology_mutable().create_entity_permutations();
567 cell_info = std::span(mesh->topology().get_cell_permutation_info());
568 }
569
570 return cell_info;
571}
572
574template <typename T, int _bs>
575void pack(std::span<T> coeffs, std::int32_t cell, int bs, std::span<const T> v,
576 std::span<const std::uint32_t> cell_info, const DofMap& dofmap,
577 auto transform)
578{
579 auto dofs = dofmap.cell_dofs(cell);
580 for (std::size_t i = 0; i < dofs.size(); ++i)
581 {
582 if constexpr (_bs < 0)
583 {
584 const int pos_c = bs * i;
585 const int pos_v = bs * dofs[i];
586 for (int k = 0; k < bs; ++k)
587 coeffs[pos_c + k] = v[pos_v + k];
588 }
589 else
590 {
591 const int pos_c = _bs * i;
592 const int pos_v = _bs * dofs[i];
593 for (int k = 0; k < _bs; ++k)
594 coeffs[pos_c + k] = v[pos_v + k];
595 }
596 }
597
598 transform(coeffs, cell_info, cell, 1);
599}
600
603template <typename F>
604concept FetchCells = requires(F&& f, std::span<const std::int32_t> v) {
605 std::invocable<F, std::span<const std::int32_t>>;
606 {
607 f(v)
608 } -> std::convertible_to<std::int32_t>;
609 };
610
624template <typename T>
625void pack_coefficient_entity(std::span<T> c, int cstride, const Function<T>& u,
626 std::span<const std::uint32_t> cell_info,
627 std::span<const std::int32_t> entities,
628 std::size_t estride, FetchCells auto&& fetch_cells,
629 std::int32_t offset)
630{
631 // Read data from coefficient Function u
632 std::span<const T> v = u.x()->array();
633 const DofMap& dofmap = *u.function_space()->dofmap();
634 std::shared_ptr<const FiniteElement> element = u.function_space()->element();
635 assert(element);
636 int space_dim = element->space_dimension();
637 const auto transformation
638 = element->get_dof_transformation_function<T>(false, true);
639
640 const int bs = dofmap.bs();
641 switch (bs)
642 {
643 case 1:
644 for (std::size_t e = 0; e < entities.size(); e += estride)
645 {
646 auto entity = entities.subspan(e, estride);
647 std::int32_t cell = fetch_cells(entity);
648 auto cell_coeff = c.subspan((e / estride) * cstride + offset, space_dim);
649 pack<T, 1>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
650 }
651 break;
652 case 2:
653 for (std::size_t e = 0; e < entities.size(); e += estride)
654 {
655 auto entity = entities.subspan(e, estride);
656 std::int32_t cell = fetch_cells(entity);
657 auto cell_coeff = c.subspan((e / estride) * cstride + offset, space_dim);
658 pack<T, 2>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
659 }
660 break;
661 case 3:
662 for (std::size_t e = 0; e < entities.size(); e += estride)
663 {
664 auto entity = entities.subspan(e, estride);
665 std::int32_t cell = fetch_cells(entity);
666 auto cell_coeff = c.subspan(e / estride * cstride + offset, space_dim);
667 pack<T, 3>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
668 }
669 break;
670 default:
671 for (std::size_t e = 0; e < entities.size(); e += estride)
672 {
673 auto entity = entities.subspan(e, estride);
674 std::int32_t cell = fetch_cells(entity);
675 auto cell_coeff = c.subspan((e / estride) * cstride + offset, space_dim);
676 pack<T, -1>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
677 }
678 break;
679 }
680}
681
682} // namespace impl
683
690template <typename T>
691std::pair<std::vector<T>, int>
693 int id)
694{
695 // Get form coefficient offsets and dofmaps
696 const std::vector<std::shared_ptr<const Function<T>>>& coefficients
697 = form.coefficients();
698 const std::vector<int> offsets = form.coefficient_offsets();
699
700 std::size_t num_entities = 0;
701 int cstride = 0;
702 if (!coefficients.empty())
703 {
704 cstride = offsets.back();
705 switch (integral_type)
706 {
708 num_entities = form.cell_domains(id).size();
709 break;
711 num_entities = form.exterior_facet_domains(id).size() / 2;
712 break;
714 num_entities = form.interior_facet_domains(id).size() / 2;
715 break;
716 default:
717 throw std::runtime_error(
718 "Could not allocate coefficient data. Integral type not supported.");
719 }
720 }
721
722 return {std::vector<T>(num_entities * cstride), cstride};
723}
724
729template <typename T>
730std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, int>>
732{
733 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, int>> coeffs;
734 for (auto integral_type : form.integral_types())
735 {
736 for (int id : form.integral_ids(integral_type))
737 {
738 coeffs.emplace_hint(
739 coeffs.end(), std::pair(integral_type, id),
740 allocate_coefficient_storage(form, integral_type, id));
741 }
742 }
743
744 return coeffs;
745}
746
754template <typename T>
755void pack_coefficients(const Form<T>& form, IntegralType integral_type, int id,
756 std::span<T> c, int cstride)
757{
758 // Get form coefficient offsets and dofmaps
759 const std::vector<std::shared_ptr<const Function<T>>>& coefficients
760 = form.coefficients();
761 const std::vector<int> offsets = form.coefficient_offsets();
762
763 if (!coefficients.empty())
764 {
765 std::span<const std::uint32_t> cell_info
766 = impl::get_cell_orientation_info(coefficients);
767
768 switch (integral_type)
769 {
771 {
772 auto fetch_cell = [](auto& entity) { return entity.front(); };
773 const std::vector<std::int32_t>& cells = form.cell_domains(id);
774
775 // Iterate over coefficients
776 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
777 {
778 impl::pack_coefficient_entity(c, cstride, *coefficients[coeff],
779 cell_info, cells, 1, fetch_cell,
780 offsets[coeff]);
781 }
782 break;
783 }
785 {
786 const std::vector<std::int32_t>& facets = form.exterior_facet_domains(id);
787
788 // Function to fetch cell index from exterior facet entity
789 auto fetch_cell = [](auto& entity) { return entity.front(); };
790
791 // Iterate over coefficients
792 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
793 {
794 impl::pack_coefficient_entity(c, cstride, *coefficients[coeff],
795 cell_info, facets, 2, fetch_cell,
796 offsets[coeff]);
797 }
798 break;
799 }
801 {
802 const std::vector<std::int32_t>& facets = form.interior_facet_domains(id);
803
804 // Functions to fetch cell indices from interior facet entity
805 auto fetch_cell0 = [](auto& entity) { return entity[0]; };
806 auto fetch_cell1 = [](auto& entity) { return entity[2]; };
807
808 // Iterate over coefficients
809 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
810 {
811 // Pack coefficient ['+']
812 impl::pack_coefficient_entity(c, 2 * cstride, *coefficients[coeff],
813 cell_info, facets, 4, fetch_cell0,
814 2 * offsets[coeff]);
815 // Pack coefficient ['-']
816 impl::pack_coefficient_entity(c, 2 * cstride, *coefficients[coeff],
817 cell_info, facets, 4, fetch_cell1,
818 offsets[coeff] + offsets[coeff + 1]);
819 }
820 break;
821 }
822 default:
823 throw std::runtime_error(
824 "Could not pack coefficient. Integral type not supported.");
825 }
826 }
827}
828
830template <typename T>
832 const ufcx_expression& expression,
833 const std::vector<std::shared_ptr<const Function<T>>>& coefficients,
834 const std::vector<std::shared_ptr<const Constant<T>>>& constants,
835 std::shared_ptr<const mesh::Mesh> mesh = nullptr,
836 std::shared_ptr<const FunctionSpace> argument_function_space = nullptr)
837{
838 if (expression.rank > 0 and !argument_function_space)
839 {
840 throw std::runtime_error(
841 "Expression has Argument but no Argument function space was provided.");
842 }
843
844 const std::size_t size
845 = expression.num_points * expression.topological_dimension;
846 std::span<const double> X(expression.points, size);
847 std::array<std::size_t, 2> Xshape
848 = {static_cast<std::size_t>(expression.num_points),
849 static_cast<std::size_t>(expression.topological_dimension)};
850
851 std::vector<int> value_shape;
852 for (int i = 0; i < expression.num_components; ++i)
853 value_shape.push_back(expression.value_shape[i]);
854
855 std::function<void(T*, const T*, const T*,
856 const typename impl::scalar_value_type<T>::value_type*,
857 const int*, const std::uint8_t*)>
858 tabulate_tensor = nullptr;
859 if constexpr (std::is_same_v<T, float>)
860 tabulate_tensor = expression.tabulate_tensor_float32;
861 else if constexpr (std::is_same_v<T, std::complex<float>>)
862 {
863 tabulate_tensor = reinterpret_cast<void (*)(
864 T*, const T*, const T*,
865 const typename impl::scalar_value_type<T>::value_type*, const int*,
866 const unsigned char*)>(expression.tabulate_tensor_complex64);
867 }
868 else if constexpr (std::is_same_v<T, double>)
869 tabulate_tensor = expression.tabulate_tensor_float64;
870 else if constexpr (std::is_same_v<T, std::complex<double>>)
871 {
872 tabulate_tensor = reinterpret_cast<void (*)(
873 T*, const T*, const T*,
874 const typename impl::scalar_value_type<T>::value_type*, const int*,
875 const unsigned char*)>(expression.tabulate_tensor_complex128);
876 }
877 else
878 throw std::runtime_error("Type not supported.");
879
880 assert(tabulate_tensor);
881 return Expression(coefficients, constants, X, Xshape, tabulate_tensor,
882 value_shape, mesh, argument_function_space);
883}
884
887template <typename T>
889 const ufcx_expression& expression,
890 const std::map<std::string, std::shared_ptr<const Function<T>>>&
891 coefficients,
892 const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
893 std::shared_ptr<const mesh::Mesh> mesh = nullptr,
894 std::shared_ptr<const FunctionSpace> argument_function_space = nullptr)
895{
896 // Place coefficients in appropriate order
897 std::vector<std::shared_ptr<const Function<T>>> coeff_map;
898 std::vector<std::string> coefficient_names;
899 for (int i = 0; i < expression.num_coefficients; ++i)
900 coefficient_names.push_back(expression.coefficient_names[i]);
901
902 for (const std::string& name : coefficient_names)
903 {
904 if (auto it = coefficients.find(name); it != coefficients.end())
905 coeff_map.push_back(it->second);
906 else
907 {
908 throw std::runtime_error("Expression coefficient \"" + name
909 + "\" not provided.");
910 }
911 }
912
913 // Place constants in appropriate order
914 std::vector<std::shared_ptr<const Constant<T>>> const_map;
915 std::vector<std::string> constant_names;
916 for (int i = 0; i < expression.num_constants; ++i)
917 constant_names.push_back(expression.constant_names[i]);
918
919 for (const std::string& name : constant_names)
920 {
921 if (auto it = constants.find(name); it != constants.end())
922 const_map.push_back(it->second);
923 else
924 {
925 throw std::runtime_error("Expression constant \"" + name
926 + "\" not provided.");
927 }
928 }
929
930 return create_expression(expression, coeff_map, const_map, mesh,
931 argument_function_space);
932}
933
939template <typename T>
940void pack_coefficients(const Form<T>& form,
941 std::map<std::pair<IntegralType, int>,
942 std::pair<std::vector<T>, int>>& coeffs)
943{
944 for (auto& [key, val] : coeffs)
945 pack_coefficients<T>(form, key.first, key.second, val.first, val.second);
946}
947
954template <typename T>
955std::pair<std::vector<T>, int>
956pack_coefficients(const Expression<T>& u, std::span<const std::int32_t> cells)
957{
958 // Get form coefficient offsets and dofmaps
959 const std::vector<std::shared_ptr<const Function<T>>>& coefficients
960 = u.coefficients();
961 const std::vector<int> offsets = u.coefficient_offsets();
962
963 // Copy data into coefficient array
964 const int cstride = offsets.back();
965 std::vector<T> c(cells.size() * offsets.back());
966 if (!coefficients.empty())
967 {
968 std::span<const std::uint32_t> cell_info
969 = impl::get_cell_orientation_info(coefficients);
970
971 // Iterate over coefficients
972 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
973 {
974 impl::pack_coefficient_entity(
975 std::span(c), cstride, *coefficients[coeff], cell_info, cells, 1,
976 [](auto entity) { return entity[0]; }, offsets[coeff]);
977 }
978 }
979 return {std::move(c), cstride};
980}
981
984template <typename U>
985std::vector<typename U::scalar_type> pack_constants(const U& u)
986{
987 using T = typename U::scalar_type;
988 const std::vector<std::shared_ptr<const Constant<T>>>& constants
989 = u.constants();
990
991 // Calculate size of array needed to store packed constants
992 std::int32_t size = std::accumulate(constants.cbegin(), constants.cend(), 0,
993 [](std::int32_t sum, auto& constant)
994 { return sum + constant->value.size(); });
995
996 // Pack constants
997 std::vector<T> constant_values(size);
998 std::int32_t offset = 0;
999 for (auto& constant : constants)
1000 {
1001 const std::vector<T>& value = constant->value;
1002 std::copy(value.begin(), value.end(),
1003 std::next(constant_values.begin(), offset));
1004 offset += value.size();
1005 }
1006
1007 return constant_values;
1008}
1009
1010} // namespace dolfinx::fem
Degree-of-freedom map representations and tools.
A timer can be used for timing tasks. The basic usage is.
Definition: Timer.h:31
double stop()
Stop timer, return wall time elapsed and store timing data into logger.
Definition: Timer.cpp:45
Constant value which can be attached to a Form. Constants may be scalar (rank 0), vector (rank 1),...
Definition: Constant.h:20
Degree-of-freedom map.
Definition: DofMap.h:72
std::span< const std::int32_t > cell_dofs(int cell) const
Local-to-global mapping of dofs on a cell.
Definition: DofMap.h:121
int bs() const noexcept
Return the block size for the dofmap.
Definition: DofMap.cpp:183
Represents a mathematical expression evaluated at a pre-defined set of points on the reference cell....
Definition: Expression.h:34
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell. Used to pack data for multiple coefficients in...
Definition: Expression.h:121
const std::vector< std::shared_ptr< const Function< T > > > & coefficients() const
Get coefficients.
Definition: Expression.h:104
A representation of finite element variational forms.
Definition: Form.h:64
int rank() const
Rank of the form (bilinear form = 2, linear form = 1, functional = 0, etc)
Definition: Form.h:173
const std::vector< std::int32_t > & cell_domains(int i) const
Get the list of cell indices for the ith integral (kernel) for the cell domain type.
Definition: Form.h:281
const std::vector< std::int32_t > & exterior_facet_domains(int i) const
List of (cell_index, local_facet_index) pairs for the ith integral (kernel) for the exterior facet do...
Definition: Form.h:294
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell. Used to pack data for multiple coefficients in...
Definition: Form.h:331
const std::vector< std::shared_ptr< const FunctionSpace > > & function_spaces() const
Return function spaces for all arguments.
Definition: Form.h:182
const std::vector< std::shared_ptr< const Function< T > > > & coefficients() const
Access coefficients.
Definition: Form.h:318
std::vector< int > integral_ids(IntegralType type) const
Get the IDs for integrals (kernels) for given integral type. The IDs correspond to the domain IDs whi...
Definition: Form.h:249
std::set< IntegralType > integral_types() const
Get types of integrals in the form.
Definition: Form.h:212
std::shared_ptr< const mesh::Mesh > mesh() const
Extract common mesh for the form.
Definition: Form.h:177
const std::vector< std::int32_t > & interior_facet_domains(int i) const
Get the list of (cell_index_0, local_facet_index_0, cell_index_1, local_facet_index_1) quadruplets fo...
Definition: Form.h:309
This class represents a function in a finite element function space , given by.
Definition: Function.h:43
std::shared_ptr< const FunctionSpace > function_space() const
Access the function space.
Definition: Function.h:134
std::shared_ptr< const la::Vector< T > > x() const
Underlying vector.
Definition: Function.h:140
This class provides a static adjacency list data structure. It is commonly used to store directed gra...
Definition: AdjacencyList.h:27
This class provides a sparsity pattern data structure that can be used to initialize sparse matrices....
Definition: SparsityPattern.h:34
MeshTags associate values with mesh entities.
Definition: MeshTags.h:37
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition: Topology.h:43
Finite element cell kernel concept.
Definition: utils.h:82
Concepts for function that returns cell index.
Definition: utils.h:604
void pack(std::span< T > coeffs, std::int32_t cell, int bs, std::span< const T > v, std::span< const std::uint32_t > cell_info, const DofMap &dofmap, auto transform)
Pack a single coefficient for a single cell.
Definition: utils.h:575
void pack_coefficient_entity(std::span< T > c, int cstride, const Function< T > &u, std::span< const std::uint32_t > cell_info, std::span< const std::int32_t > entities, std::size_t estride, FetchCells auto &&fetch_cells, std::int32_t offset)
Pack a single coefficient for a set of active entities.
Definition: utils.h:625
Miscellaneous classes, functions and types.
void interior_facets(la::SparsityPattern &pattern, const mesh::Topology &topology, const std::array< const std::reference_wrapper< const DofMap >, 2 > &dofmaps)
Iterate over interior facets and insert entries into sparsity pattern.
Definition: sparsitybuild.cpp:43
void cells(la::SparsityPattern &pattern, const mesh::Topology &topology, const std::array< const std::reference_wrapper< const DofMap >, 2 > &dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition: sparsitybuild.cpp:18
void exterior_facets(la::SparsityPattern &pattern, const mesh::Topology &topology, const std::array< const std::reference_wrapper< const DofMap >, 2 > &dofmaps)
Iterate over exterior facets and insert entries into sparsity pattern.
Definition: sparsitybuild.cpp:112
Finite element method functionality.
Definition: assemble_matrix_impl.h:25
std::vector< std::string > get_constant_names(const ufcx_form &ufcx_form)
Get the name of each constant in a UFC form.
Definition: utils.cpp:186
Form< T > create_form(const ufcx_form &ufcx_form, const std::vector< std::shared_ptr< const FunctionSpace > > &spaces, const std::vector< std::shared_ptr< const Function< T > > > &coefficients, const std::vector< std::shared_ptr< const Constant< T > > > &constants, const std::map< IntegralType, const mesh::MeshTags< int > * > &subdomains, std::shared_ptr< const mesh::Mesh > mesh=nullptr)
Create a Form from UFC input.
Definition: utils.h:238
std::vector< std::string > get_coefficient_names(const ufcx_form &ufcx_form)
Get the name of each coefficient in a UFC form.
Definition: utils.cpp:177
Expression< T > create_expression(const ufcx_expression &expression, const std::vector< std::shared_ptr< const Function< T > > > &coefficients, const std::vector< std::shared_ptr< const Constant< T > > > &constants, std::shared_ptr< const mesh::Mesh > mesh=nullptr, std::shared_ptr< const FunctionSpace > argument_function_space=nullptr)
Create Expression from UFC.
Definition: utils.h:831
std::vector< std::vector< std::array< std::shared_ptr< const FunctionSpace >, 2 > > > extract_function_spaces(const std::vector< std::vector< const Form< T > * > > &a)
Extract test (0) and trial (1) function spaces pairs for each bilinear form for a rectangular array o...
Definition: utils.h:95
void pack_coefficients(const Form< T > &form, IntegralType integral_type, int id, std::span< T > c, int cstride)
Pack coefficients of a Form for a given integral type and domain id.
Definition: utils.h:755
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:985
FunctionSpace create_functionspace(std::shared_ptr< mesh::Mesh > mesh, const basix::FiniteElement &e, int bs, const std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> &reorder_fn=nullptr)
Create a FunctionSpace from a Basix element.
Definition: utils.cpp:195
IntegralType
Type of integral.
Definition: Form.h:32
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
la::SparsityPattern create_sparsity_pattern(const mesh::Topology &topology, const std::array< std::reference_wrapper< const DofMap >, 2 > &dofmaps, const std::set< IntegralType > &integrals)
Create a sparsity pattern for a given form.
Definition: utils.cpp:30
ElementDofLayout create_element_dof_layout(const ufcx_dofmap &dofmap, const mesh::CellType cell_type, const std::vector< int > &parent_map={})
Create an ElementDofLayout from a ufcx_dofmap.
Definition: utils.cpp:73
DofMap create_dofmap(MPI_Comm comm, const ElementDofLayout &layout, mesh::Topology &topology, const std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> &reorder_fn, const FiniteElement &element)
Create a dof map on mesh.
Definition: utils.cpp:140
std::pair< std::vector< T >, int > allocate_coefficient_storage(const Form< T > &form, IntegralType integral_type, int id)
Allocate storage for coefficients of a pair (integral_type, id) from a fem::Form form.
Definition: utils.h:692
Mesh data structures and algorithms on meshes.
Definition: DofMap.h:31
CellType
Cell type identifier.
Definition: cell_types.h:22