DOLFINx 0.10.0.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 "FunctionSpace.h"
17#include "sparsitybuild.h"
18#include <algorithm>
19#include <array>
20#include <concepts>
21#include <dolfinx/common/types.h>
22#include <dolfinx/la/SparsityPattern.h>
23#include <dolfinx/mesh/Topology.h>
24#include <dolfinx/mesh/cell_types.h>
25#include <dolfinx/mesh/utils.h>
26#include <functional>
27#include <memory>
28#include <optional>
29#include <set>
30#include <span>
31#include <stdexcept>
32#include <string>
33#include <tuple>
34#include <type_traits>
35#include <ufcx.h>
36#include <utility>
37#include <vector>
38
41namespace basix
42{
43template <std::floating_point T>
45}
46
47namespace dolfinx::common
48{
49class IndexMap;
50}
51
52namespace dolfinx::fem
53{
54namespace impl
55{
62template <int num_cells>
63std::array<std::int32_t, 2 * num_cells>
64get_cell_facet_pairs(std::int32_t f, std::span<const std::int32_t> cells,
66{
67 // Loop over cells sharing facet
68 assert(cells.size() == num_cells);
69 std::array<std::int32_t, 2 * num_cells> cell_local_facet_pairs;
70 for (int c = 0; c < num_cells; ++c)
71 {
72 // Get local index of facet with respect to the cell
73 std::int32_t cell = cells[c];
74 auto cell_facets = c_to_f.links(cell);
75 auto facet_it = std::find(cell_facets.begin(), cell_facets.end(), f);
76 assert(facet_it != cell_facets.end());
77 int local_f = std::distance(cell_facets.begin(), facet_it);
78 cell_local_facet_pairs[2 * c] = cell;
79 cell_local_facet_pairs[2 * c + 1] = local_f;
80 }
81
82 return cell_local_facet_pairs;
83}
84
85} // namespace impl
86
113std::vector<std::int32_t>
115 const mesh::Topology& topology,
116 std::span<const std::int32_t> entities);
117
125template <dolfinx::scalar T, std::floating_point U>
126std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
127extract_function_spaces(const std::vector<std::vector<const Form<T, U>*>>& a)
128{
129 std::vector<
130 std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
131 spaces(
132 a.size(),
133 std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>(
134 a.front().size()));
135 for (std::size_t i = 0; i < a.size(); ++i)
136 {
137 for (std::size_t j = 0; j < a[i].size(); ++j)
138 {
139 if (const Form<T, U>* form = a[i][j]; form)
140 spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
141 }
142 }
143 return spaces;
144}
145
151template <dolfinx::scalar T, std::floating_point U>
153{
154 if (a.rank() != 2)
155 {
156 throw std::runtime_error(
157 "Cannot create sparsity pattern. Form is not a bilinear.");
158 }
159
160 // Get dof maps and mesh
161 std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
162 *a.function_spaces().at(0)->dofmap(),
163 *a.function_spaces().at(1)->dofmap()};
164 std::shared_ptr mesh = a.mesh();
165 assert(mesh);
166
167 std::shared_ptr mesh0 = a.function_spaces().at(0)->mesh();
168 assert(mesh0);
169 std::shared_ptr mesh1 = a.function_spaces().at(1)->mesh();
170 assert(mesh1);
171
172 const std::set<IntegralType> types = a.integral_types();
173 if (types.find(IntegralType::interior_facet) != types.end()
174 or types.find(IntegralType::exterior_facet) != types.end())
175 {
176 // FIXME: cleanup these calls? Some of the happen internally again.
177 int tdim = mesh->topology()->dim();
178 mesh->topology_mutable()->create_entities(tdim - 1);
179 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
180 }
181
182 common::Timer t0("Build sparsity");
183
184 // Get common::IndexMaps for each dimension
185 const std::array index_maps{dofmaps[0].get().index_map,
186 dofmaps[1].get().index_map};
187 const std::array bs
188 = {dofmaps[0].get().index_map_bs(), dofmaps[1].get().index_map_bs()};
189
190 auto extract_cells = [](std::span<const std::int32_t> facets)
191 {
192 assert(facets.size() % 2 == 0);
193 std::vector<std::int32_t> cells;
194 cells.reserve(facets.size() / 2);
195 for (std::size_t i = 0; i < facets.size(); i += 2)
196 cells.push_back(facets[i]);
197 return cells;
198 };
199
200 // Create and build sparsity pattern
201 la::SparsityPattern pattern(mesh->comm(), index_maps, bs);
202 for (auto type : types)
203 {
204 std::vector<int> ids = a.integral_ids(type);
205 switch (type)
206 {
208 for (int id : ids)
209 {
211 pattern, {a.domain(type, id, *mesh0), a.domain(type, id, *mesh1)},
212 {{dofmaps[0], dofmaps[1]}});
213 }
214 break;
216 for (int id : ids)
217 {
219 pattern,
220 {extract_cells(a.domain(type, id, *mesh0)),
221 extract_cells(a.domain(type, id, *mesh1))},
222 {{dofmaps[0], dofmaps[1]}});
223 }
224 break;
226 for (int id : ids)
227 {
228 sparsitybuild::cells(pattern,
229 {extract_cells(a.domain(type, id, *mesh0)),
230 extract_cells(a.domain(type, id, *mesh1))},
231 {{dofmaps[0], dofmaps[1]}});
232 }
233 break;
234 default:
235 throw std::runtime_error("Unsupported integral type");
236 }
237 }
238
239 t0.stop();
240
241 return pattern;
242}
243
245template <std::floating_point T>
247 const std::vector<int>& parent_map
248 = {})
249{
250 // Create subdofmaps and compute offset
251 std::vector<int> offsets(1, 0);
252 std::vector<dolfinx::fem::ElementDofLayout> sub_doflayout;
253 int bs = element.block_size();
254 for (int i = 0; i < element.num_sub_elements(); ++i)
255 {
256 // The ith sub-element. For mixed elements this is subelements()[i]. For
257 // blocked elements, the sub-element will always be the same, so we'll use
258 // sub_elements()[0]
259 std::shared_ptr<const fem::FiniteElement<T>> sub_e
260 = element.sub_elements()[bs > 1 ? 0 : i];
261
262 // In a mixed element DOFs are ordered element by element, so the offset to
263 // the next sub-element is sub_e->space_dimension(). Blocked elements use
264 // xxyyzz ordering, so the offset to the next sub-element is 1
265
266 std::vector<int> parent_map_sub(sub_e->space_dimension(), offsets.back());
267 for (std::size_t j = 0; j < parent_map_sub.size(); ++j)
268 parent_map_sub[j] += bs * j;
269 offsets.push_back(offsets.back() + (bs > 1 ? 1 : sub_e->space_dimension()));
270 sub_doflayout.push_back(
271 dolfinx::fem::create_element_dof_layout(*sub_e, parent_map_sub));
272 }
273
274 return ElementDofLayout(bs, element.entity_dofs(),
275 element.entity_closure_dofs(), parent_map,
276 sub_doflayout);
277}
278
287DofMap create_dofmap(
288 MPI_Comm comm, const ElementDofLayout& layout, mesh::Topology& topology,
289 std::function<void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
290 std::function<std::vector<int>(const graph::AdjacencyList<std::int32_t>&)>
291 reorder_fn);
292
303std::vector<DofMap> create_dofmaps(
304 MPI_Comm comm, const std::vector<ElementDofLayout>& layouts,
305 mesh::Topology& topology,
306 std::function<void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
307 std::function<std::vector<int>(const graph::AdjacencyList<std::int32_t>&)>
308 reorder_fn);
309
313std::vector<std::string> get_coefficient_names(const ufcx_form& ufcx_form);
314
318std::vector<std::string> get_constant_names(const ufcx_form& ufcx_form);
319
338template <dolfinx::scalar T, std::floating_point U = scalar_value_type_t<T>>
340 const ufcx_form& ufcx_form,
341 const std::vector<std::shared_ptr<const FunctionSpace<U>>>& spaces,
342 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients,
343 const std::vector<std::shared_ptr<const Constant<T>>>& constants,
344 const std::map<
346 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
347 subdomains,
348 const std::map<std::shared_ptr<const mesh::Mesh<U>>,
349 std::span<const std::int32_t>>& entity_maps,
350 std::shared_ptr<const mesh::Mesh<U>> mesh = nullptr)
351{
352 if (ufcx_form.rank != (int)spaces.size())
353 throw std::runtime_error("Wrong number of argument spaces for Form.");
354 if (ufcx_form.num_coefficients != (int)coefficients.size())
355 {
356 throw std::runtime_error(
357 "Mismatch between number of expected and provided Form coefficients.");
358 }
359 if (ufcx_form.num_constants != (int)constants.size())
360 {
361 throw std::runtime_error(
362 "Mismatch between number of expected and provided Form constants.");
363 }
364
365 // Check argument function spaces
366 for (std::size_t i = 0; i < spaces.size(); ++i)
367 {
368 assert(spaces[i]->element());
369 if (auto element_hash = ufcx_form.finite_element_hashes[i];
370 element_hash != 0
371 and element_hash != spaces[i]->element()->basix_element().hash())
372 {
373 throw std::runtime_error("Cannot create form. Elements are different to "
374 "those used to compile the form.");
375 }
376 }
377
378 // Extract mesh from FunctionSpace, and check they are the same
379 if (!mesh and !spaces.empty())
380 mesh = spaces[0]->mesh();
381 for (auto& V : spaces)
382 {
383 if (mesh != V->mesh() and entity_maps.find(V->mesh()) == entity_maps.end())
384 throw std::runtime_error(
385 "Incompatible mesh. entity_maps must be provided.");
386 }
387 if (!mesh)
388 throw std::runtime_error("No mesh could be associated with the Form.");
389
390 auto topology = mesh->topology();
391 assert(topology);
392 const int tdim = topology->dim();
393
394 const int* integral_offsets = ufcx_form.form_integral_offsets;
395 std::vector<int> num_integrals_type(3);
396 for (int i = 0; i < 3; ++i)
397 num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
398
399 // Create facets, if required
400 if (num_integrals_type[exterior_facet] > 0
401 or num_integrals_type[interior_facet] > 0)
402 {
403 mesh->topology_mutable()->create_entities(tdim - 1);
404 mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
405 mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
406 }
407
408 // Get list of integral IDs, and load tabulate tensor into memory for
409 // each
410 using kern_t = std::function<void(T*, const T*, const T*, const U*,
411 const int*, const std::uint8_t*)>;
412 std::map<IntegralType, std::vector<integral_data<T, U>>> integrals;
413
414 // Attach cell kernels
415 bool needs_facet_permutations = false;
416 std::vector<std::int32_t> default_cells;
417 {
418 std::span<const int> ids(ufcx_form.form_integral_ids
419 + integral_offsets[cell],
420 num_integrals_type[cell]);
421 auto itg = integrals.insert({IntegralType::cell, {}});
422 auto sd = subdomains.find(IntegralType::cell);
423 for (int i = 0; i < num_integrals_type[cell]; ++i)
424 {
425 const int id = ids[i];
426 ufcx_integral* integral
427 = ufcx_form.form_integrals[integral_offsets[cell] + i];
428 assert(integral);
429
430 // Build list of active coefficients
431 std::vector<int> active_coeffs;
432 for (int j = 0; j < ufcx_form.num_coefficients; ++j)
433 {
434 if (integral->enabled_coefficients[j])
435 active_coeffs.push_back(j);
436 }
437
438 kern_t k = nullptr;
439 if constexpr (std::is_same_v<T, float>)
440 k = integral->tabulate_tensor_float32;
441#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
442 else if constexpr (std::is_same_v<T, std::complex<float>>)
443 {
444 k = reinterpret_cast<void (*)(
445 T*, const T*, const T*,
446 const typename scalar_value_type<T>::value_type*, const int*,
447 const unsigned char*)>(integral->tabulate_tensor_complex64);
448 }
449#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
450 else if constexpr (std::is_same_v<T, double>)
451 k = integral->tabulate_tensor_float64;
452#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
453 else if constexpr (std::is_same_v<T, std::complex<double>>)
454 {
455 k = reinterpret_cast<void (*)(
456 T*, const T*, const T*,
457 const typename scalar_value_type<T>::value_type*, const int*,
458 const unsigned char*)>(integral->tabulate_tensor_complex128);
459 }
460#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
461
462 if (!k)
463 {
464 throw std::runtime_error(
465 "UFCx kernel function is NULL. Check requested types.");
466 }
467
468 // Build list of entities to assemble over
469 if (id == -1)
470 {
471 // Default kernel, operates on all (owned) cells
472 assert(topology->index_map(tdim));
473 default_cells.resize(topology->index_map(tdim)->size_local(), 0);
474 std::iota(default_cells.begin(), default_cells.end(), 0);
475 itg.first->second.emplace_back(id, k, default_cells, active_coeffs);
476 }
477 else if (sd != subdomains.end())
478 {
479 // NOTE: This requires that pairs are sorted
480 auto it
481 = std::ranges::lower_bound(sd->second, id, std::less<>{},
482 [](const auto& a) { return a.first; });
483 if (it != sd->second.end() and it->first == id)
484 itg.first->second.emplace_back(id, k, it->second, active_coeffs);
485 }
486
487 if (integral->needs_facet_permutations)
488 needs_facet_permutations = true;
489 }
490 }
491
492 // Attach exterior facet kernels
493 std::vector<std::int32_t> default_facets_ext;
494 {
495 std::span<const int> ids(ufcx_form.form_integral_ids
496 + integral_offsets[exterior_facet],
497 num_integrals_type[exterior_facet]);
498 auto itg = integrals.insert({IntegralType::exterior_facet, {}});
499 auto sd = subdomains.find(IntegralType::exterior_facet);
500 for (int i = 0; i < num_integrals_type[exterior_facet]; ++i)
501 {
502 const int id = ids[i];
503 ufcx_integral* integral
504 = ufcx_form.form_integrals[integral_offsets[exterior_facet] + i];
505 assert(integral);
506 std::vector<int> active_coeffs;
507 for (int j = 0; j < ufcx_form.num_coefficients; ++j)
508 {
509 if (integral->enabled_coefficients[j])
510 active_coeffs.push_back(j);
511 }
512
513 kern_t k = nullptr;
514 if constexpr (std::is_same_v<T, float>)
515 k = integral->tabulate_tensor_float32;
516#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
517 else if constexpr (std::is_same_v<T, std::complex<float>>)
518 {
519 k = reinterpret_cast<void (*)(
520 T*, const T*, const T*,
521 const typename scalar_value_type<T>::value_type*, const int*,
522 const unsigned char*)>(integral->tabulate_tensor_complex64);
523 }
524#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
525 else if constexpr (std::is_same_v<T, double>)
526 k = integral->tabulate_tensor_float64;
527#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
528 else if constexpr (std::is_same_v<T, std::complex<double>>)
529 {
530 k = reinterpret_cast<void (*)(
531 T*, const T*, const T*,
532 const typename scalar_value_type<T>::value_type*, const int*,
533 const unsigned char*)>(integral->tabulate_tensor_complex128);
534 }
535#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
536 assert(k);
537
538 // Build list of entities to assembler over
539 const std::vector bfacets = mesh::exterior_facet_indices(*topology);
540 auto f_to_c = topology->connectivity(tdim - 1, tdim);
541 assert(f_to_c);
542 auto c_to_f = topology->connectivity(tdim, tdim - 1);
543 assert(c_to_f);
544 if (id == -1)
545 {
546 // Default kernel, operates on all (owned) exterior facets
547 default_facets_ext.reserve(2 * bfacets.size());
548 for (std::int32_t f : bfacets)
549 {
550 // There will only be one pair for an exterior facet integral
551 auto pair
552 = impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
553 default_facets_ext.insert(default_facets_ext.end(), pair.begin(),
554 pair.end());
555 }
556 itg.first->second.emplace_back(id, k, default_facets_ext,
557 active_coeffs);
558 }
559 else if (sd != subdomains.end())
560 {
561 // NOTE: This requires that pairs are sorted
562 auto it
563 = std::ranges::lower_bound(sd->second, id, std::less<>{},
564 [](const auto& a) { return a.first; });
565 if (it != sd->second.end() and it->first == id)
566 itg.first->second.emplace_back(id, k, it->second, active_coeffs);
567 }
568
569 if (integral->needs_facet_permutations)
570 needs_facet_permutations = true;
571 }
572 }
573
574 // Attach interior facet kernels
575 std::vector<std::int32_t> default_facets_int;
576 {
577 std::span<const int> ids(ufcx_form.form_integral_ids
578 + integral_offsets[interior_facet],
579 num_integrals_type[interior_facet]);
580 auto itg = integrals.insert({IntegralType::interior_facet, {}});
581 auto sd = subdomains.find(IntegralType::interior_facet);
582
583 // Create indicator for interprocess facets
584 std::vector<std::int8_t> interprocess_marker;
585 if (num_integrals_type[interior_facet] > 0)
586 {
587 assert(topology->index_map(tdim - 1));
588 const std::vector<std::int32_t>& interprocess_facets
589 = topology->interprocess_facets();
590 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
591 + topology->index_map(tdim - 1)->num_ghosts();
592 interprocess_marker.resize(num_facets, 0);
593 std::ranges::for_each(interprocess_facets, [&interprocess_marker](auto f)
594 { interprocess_marker[f] = 1; });
595 }
596
597 for (int i = 0; i < num_integrals_type[interior_facet]; ++i)
598 {
599 const int id = ids[i];
600 ufcx_integral* integral
601 = ufcx_form.form_integrals[integral_offsets[interior_facet] + i];
602 assert(integral);
603 std::vector<int> active_coeffs;
604 for (int j = 0; j < ufcx_form.num_coefficients; ++j)
605 {
606 if (integral->enabled_coefficients[j])
607 active_coeffs.push_back(j);
608 }
609
610 kern_t k = nullptr;
611 if constexpr (std::is_same_v<T, float>)
612 k = integral->tabulate_tensor_float32;
613#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
614 else if constexpr (std::is_same_v<T, std::complex<float>>)
615 {
616 k = reinterpret_cast<void (*)(
617 T*, const T*, const T*,
618 const typename scalar_value_type<T>::value_type*, const int*,
619 const unsigned char*)>(integral->tabulate_tensor_complex64);
620 }
621#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
622 else if constexpr (std::is_same_v<T, double>)
623 k = integral->tabulate_tensor_float64;
624#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
625 else if constexpr (std::is_same_v<T, std::complex<double>>)
626 {
627 k = reinterpret_cast<void (*)(
628 T*, const T*, const T*,
629 const typename scalar_value_type<T>::value_type*, const int*,
630 const unsigned char*)>(integral->tabulate_tensor_complex128);
631 }
632#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
633 assert(k);
634
635 // Build list of entities to assembler over
636 auto f_to_c = topology->connectivity(tdim - 1, tdim);
637 assert(f_to_c);
638 auto c_to_f = topology->connectivity(tdim, tdim - 1);
639 assert(c_to_f);
640 if (id == -1)
641 {
642 // Default kernel, operates on all (owned) interior facets
643 assert(topology->index_map(tdim - 1));
644 std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
645 default_facets_int.reserve(4 * num_facets);
646 for (std::int32_t f = 0; f < num_facets; ++f)
647 {
648 if (f_to_c->num_links(f) == 2)
649 {
650 auto pairs
651 = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
652 default_facets_int.insert(default_facets_int.end(), pairs.begin(),
653 pairs.end());
654 }
655 else if (interprocess_marker[f])
656 {
657 throw std::runtime_error(
658 "Cannot compute interior facet integral over interprocess "
659 "facet. Please use ghost mode shared facet when creating the "
660 "mesh");
661 }
662 }
663 itg.first->second.emplace_back(id, k, default_facets_int,
664 active_coeffs);
665 }
666 else if (sd != subdomains.end())
667 {
668 auto it
669 = std::ranges::lower_bound(sd->second, id, std::less<>{},
670 [](const auto& a) { return a.first; });
671 if (it != sd->second.end() and it->first == id)
672 itg.first->second.emplace_back(id, k, it->second, active_coeffs);
673 }
674
675 if (integral->needs_facet_permutations)
676 needs_facet_permutations = true;
677 }
678 }
679
680 std::map<IntegralType,
681 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>
682 sd;
683 for (auto& [itg, data] : subdomains)
684 {
685 std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>> x;
686 for (auto& [id, idx] : data)
687 x.emplace_back(id, std::vector(idx.data(), idx.data() + idx.size()));
688 sd.insert({itg, std::move(x)});
689 }
690
691 return Form<T, U>(spaces, integrals, coefficients, constants,
692 needs_facet_permutations, entity_maps, mesh);
693}
694
709template <dolfinx::scalar T, std::floating_point U = scalar_value_type_t<T>>
711 const ufcx_form& ufcx_form,
712 const std::vector<std::shared_ptr<const FunctionSpace<U>>>& spaces,
713 const std::map<std::string, std::shared_ptr<const Function<T, U>>>&
714 coefficients,
715 const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
716 const std::map<
718 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
719 subdomains,
720 const std::map<std::shared_ptr<const mesh::Mesh<U>>,
721 std::span<const std::int32_t>>& entity_maps,
722 std::shared_ptr<const mesh::Mesh<U>> mesh = nullptr)
723{
724 // Place coefficients in appropriate order
725 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
726 for (const std::string& name : get_coefficient_names(ufcx_form))
727 {
728 if (auto it = coefficients.find(name); it != coefficients.end())
729 coeff_map.push_back(it->second);
730 else
731 {
732 throw std::runtime_error("Form coefficient \"" + name
733 + "\" not provided.");
734 }
735 }
736
737 // Place constants in appropriate order
738 std::vector<std::shared_ptr<const Constant<T>>> const_map;
739 for (const std::string& name : get_constant_names(ufcx_form))
740 {
741 if (auto it = constants.find(name); it != constants.end())
742 const_map.push_back(it->second);
743 else
744 throw std::runtime_error("Form constant \"" + name + "\" not provided.");
745 }
746
747 return create_form_factory(ufcx_form, spaces, coeff_map, const_map,
748 subdomains, entity_maps, mesh);
749}
750
769template <dolfinx::scalar T, std::floating_point U = scalar_value_type_t<T>>
771 ufcx_form* (*fptr)(),
772 const std::vector<std::shared_ptr<const FunctionSpace<U>>>& spaces,
773 const std::map<std::string, std::shared_ptr<const Function<T, U>>>&
774 coefficients,
775 const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
776 const std::map<
778 std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
779 subdomains,
780 const std::map<std::shared_ptr<const mesh::Mesh<U>>,
781 std::span<const std::int32_t>>& entity_maps,
782 std::shared_ptr<const mesh::Mesh<U>> mesh = nullptr)
783{
784 ufcx_form* form = fptr();
785 Form<T, U> L = create_form<T, U>(*form, spaces, coefficients, constants,
786 subdomains, entity_maps, mesh);
787 std::free(form);
788 return L;
789}
790
792template <std::floating_point T>
794 std::shared_ptr<mesh::Mesh<T>> mesh,
795 std::shared_ptr<const fem::FiniteElement<T>> e,
796 std::function<std::vector<int>(const graph::AdjacencyList<std::int32_t>&)>
797 reorder_fn
798 = nullptr)
799{
800 assert(e);
801
802 // TODO: check cell type of e (need to add method to fem::FiniteElement)
803 assert(mesh);
804 assert(mesh->topology());
805 if (e->cell_type() != mesh->topology()->cell_type())
806 throw std::runtime_error("Cell type of element and mesh must match.");
807
808 // Create element dof layout
810
811 // Create a dofmap
812 std::function<void(std::span<std::int32_t>, std::uint32_t)> permute_inv
813 = e->needs_dof_permutations() ? e->dof_permutation_fn(true, true)
814 : nullptr;
815 auto dofmap = std::make_shared<const DofMap>(create_dofmap(
816 mesh->comm(), layout, *mesh->topology(), permute_inv, reorder_fn));
817
818 return FunctionSpace(mesh, e, dofmap);
819}
820
822namespace impl
823{
825template <dolfinx::scalar T, std::floating_point U>
826std::span<const std::uint32_t>
827get_cell_orientation_info(const Function<T, U>& coefficient)
828{
829 std::span<const std::uint32_t> cell_info;
830 auto element = coefficient.function_space()->element();
831 if (element->needs_dof_transformations())
832 {
833 auto mesh = coefficient.function_space()->mesh();
834 mesh->topology_mutable()->create_entity_permutations();
835 cell_info = std::span(mesh->topology()->get_cell_permutation_info());
836 }
837
838 return cell_info;
839}
840
842template <int _bs, dolfinx::scalar T>
843void pack(std::span<T> coeffs, std::int32_t cell, int bs, std::span<const T> v,
844 std::span<const std::uint32_t> cell_info, const DofMap& dofmap,
845 auto transform)
846{
847 auto dofs = dofmap.cell_dofs(cell);
848 for (std::size_t i = 0; i < dofs.size(); ++i)
849 {
850 if constexpr (_bs < 0)
851 {
852 const int pos_c = bs * i;
853 const int pos_v = bs * dofs[i];
854 for (int k = 0; k < bs; ++k)
855 coeffs[pos_c + k] = v[pos_v + k];
856 }
857 else
858 {
859 assert(_bs == bs);
860 const int pos_c = _bs * i;
861 const int pos_v = _bs * dofs[i];
862 for (int k = 0; k < _bs; ++k)
863 coeffs[pos_c + k] = v[pos_v + k];
864 }
865 }
866
867 transform(coeffs, cell_info, cell, 1);
868}
869
872template <typename F>
873concept FetchCells = requires(F&& f, std::span<const std::int32_t> v) {
874 requires std::invocable<F, std::span<const std::int32_t>>;
875 { f(v) } -> std::convertible_to<std::int32_t>;
876};
877
891template <dolfinx::scalar T, std::floating_point U>
892void pack_coefficient_entity(std::span<T> c, int cstride,
893 const Function<T, U>& u,
894 std::span<const std::uint32_t> cell_info,
895 std::span<const std::int32_t> entities,
896 std::size_t estride, FetchCells auto&& fetch_cells,
897 std::int32_t offset)
898{
899 // Read data from coefficient Function u
900 std::span<const T> v = u.x()->array();
901 const DofMap& dofmap = *u.function_space()->dofmap();
902 auto element = u.function_space()->element();
903 assert(element);
904 int space_dim = element->space_dimension();
905
906 // Transformation from conforming degrees-of-freedom to reference
907 // degrees-of-freedom
908 auto transformation
909 = element->template dof_transformation_fn<T>(doftransform::transpose);
910 const int bs = dofmap.bs();
911 switch (bs)
912 {
913 case 1:
914 for (std::size_t e = 0; e < entities.size(); e += estride)
915 {
916 auto entity = entities.subspan(e, estride);
917 if (std::int32_t cell = fetch_cells(entity); cell >= 0)
918 {
919 auto cell_coeff
920 = c.subspan((e / estride) * cstride + offset, space_dim);
921 pack<1>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
922 }
923 }
924 break;
925 case 2:
926 for (std::size_t e = 0; e < entities.size(); e += estride)
927 {
928 auto entity = entities.subspan(e, estride);
929 if (std::int32_t cell = fetch_cells(entity); cell >= 0)
930 {
931 auto cell_coeff
932 = c.subspan((e / estride) * cstride + offset, space_dim);
933 pack<2>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
934 }
935 }
936 break;
937 case 3:
938 for (std::size_t e = 0; e < entities.size(); e += estride)
939 {
940 auto entity = entities.subspan(e, estride);
941 if (std::int32_t cell = fetch_cells(entity); cell >= 0)
942 {
943 auto cell_coeff = c.subspan(e / estride * cstride + offset, space_dim);
944 pack<3>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
945 }
946 }
947 break;
948 default:
949 for (std::size_t e = 0; e < entities.size(); e += estride)
950 {
951 auto entity = entities.subspan(e, estride);
952 if (std::int32_t cell = fetch_cells(entity); cell >= 0)
953 {
954 auto cell_coeff
955 = c.subspan((e / estride) * cstride + offset, space_dim);
956 pack<-1>(cell_coeff, cell, bs, v, cell_info, dofmap, transformation);
957 }
958 }
959 break;
960 }
961}
962
963} // namespace impl
964
971template <dolfinx::scalar T, std::floating_point U>
972std::pair<std::vector<T>, int>
974 int id)
975{
976 // Get form coefficient offsets and dofmaps
977 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
978 = form.coefficients();
979 const std::vector<int> offsets = form.coefficient_offsets();
980
981 std::size_t num_entities = 0;
982 int cstride = 0;
983 if (!coefficients.empty())
984 {
985 cstride = offsets.back();
986 num_entities = form.domain(integral_type, id).size();
987 if (integral_type == IntegralType::exterior_facet
988 or integral_type == IntegralType::interior_facet)
989 {
990 num_entities /= 2;
991 }
992 }
993
994 return {std::vector<T>(num_entities * cstride), cstride};
995}
996
1001template <dolfinx::scalar T, std::floating_point U>
1002std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, int>>
1004{
1005 std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, int>> coeffs;
1006 for (auto integral_type : form.integral_types())
1007 {
1008 for (int id : form.integral_ids(integral_type))
1009 {
1010 coeffs.emplace_hint(
1011 coeffs.end(), std::pair(integral_type, id),
1012 allocate_coefficient_storage(form, integral_type, id));
1013 }
1014 }
1015
1016 return coeffs;
1017}
1018
1026template <dolfinx::scalar T, std::floating_point U>
1027void pack_coefficients(const Form<T, U>& form, IntegralType integral_type,
1028 int id, std::span<T> c, int cstride)
1029{
1030 // Get form coefficient offsets and dofmaps
1031 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
1032 = form.coefficients();
1033 const std::vector<int> offsets = form.coefficient_offsets();
1034
1035 // Indicator for packing coefficients
1036 std::vector<int> active_coefficient(coefficients.size(), 0);
1037 if (!coefficients.empty())
1038 {
1039 switch (integral_type)
1040 {
1041 case IntegralType::cell:
1042 {
1043 // Get indicator for all coefficients that are active in cell
1044 // integrals
1045 for (std::size_t i = 0; i < form.num_integrals(IntegralType::cell); ++i)
1046 {
1047 for (auto idx : form.active_coeffs(IntegralType::cell, i))
1048 active_coefficient[idx] = 1;
1049 }
1050
1051 // Iterate over coefficients
1052 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1053 {
1054 if (!active_coefficient[coeff])
1055 continue;
1056
1057 // Get coefficient mesh
1058 auto mesh = coefficients[coeff]->function_space()->mesh();
1059 assert(mesh);
1060
1061 // Other integrals in the form might have coefficients defined over
1062 // entities of codim > 0, which don't make sense for cell integrals, so
1063 // don't pack them.
1064 if (const int codim
1065 = form.mesh()->topology()->dim() - mesh->topology()->dim();
1066 codim > 0)
1067 {
1068 throw std::runtime_error("Should not be packing coefficients with "
1069 "codim>0 in a cell integral");
1070 }
1071
1072 std::vector<std::int32_t> cells
1073 = form.domain(IntegralType::cell, id, *mesh);
1074 std::span<const std::uint32_t> cell_info
1075 = impl::get_cell_orientation_info(*coefficients[coeff]);
1076 impl::pack_coefficient_entity(
1077 c, cstride, *coefficients[coeff], cell_info, cells, 1,
1078 [](auto entity) { return entity.front(); }, offsets[coeff]);
1079 }
1080 break;
1081 }
1083 {
1084 // Get indicator for all coefficients that are active in exterior
1085 // facet integrals
1086 for (std::size_t i = 0;
1088 {
1089 for (auto idx : form.active_coeffs(IntegralType::exterior_facet, i))
1090 active_coefficient[idx] = 1;
1091 }
1092
1093 // Iterate over coefficients
1094 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1095 {
1096 if (!active_coefficient[coeff])
1097 continue;
1098
1099 auto mesh = coefficients[coeff]->function_space()->mesh();
1100 std::vector<std::int32_t> facets
1101 = form.domain(IntegralType::exterior_facet, id, *mesh);
1102 std::span<const std::uint32_t> cell_info
1103 = impl::get_cell_orientation_info(*coefficients[coeff]);
1104 impl::pack_coefficient_entity(
1105 c, cstride, *coefficients[coeff], cell_info, facets, 2,
1106 [](auto entity) { return entity.front(); }, offsets[coeff]);
1107 }
1108 break;
1109 }
1111 {
1112 // Get indicator for all coefficients that are active in interior
1113 // facet integrals
1114 for (std::size_t i = 0;
1116 {
1117 for (auto idx : form.active_coeffs(IntegralType::interior_facet, i))
1118 active_coefficient[idx] = 1;
1119 }
1120
1121 // Iterate over coefficients
1122 for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
1123 {
1124 if (!active_coefficient[coeff])
1125 continue;
1126
1127 auto mesh = coefficients[coeff]->function_space()->mesh();
1128 std::vector<std::int32_t> facets
1129 = form.domain(IntegralType::interior_facet, id, *mesh);
1130
1131 std::span<const std::uint32_t> cell_info
1132 = impl::get_cell_orientation_info(*coefficients[coeff]);
1133
1134 // Pack coefficient ['+']
1135 impl::pack_coefficient_entity(
1136 c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
1137 [](auto entity) { return entity[0]; }, 2 * offsets[coeff]);
1138
1139 // Pack coefficient ['-']
1140 impl::pack_coefficient_entity(
1141 c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
1142 [](auto entity) { return entity[2]; },
1143 offsets[coeff] + offsets[coeff + 1]);
1144 }
1145 break;
1146 }
1147 default:
1148 throw std::runtime_error(
1149 "Could not pack coefficient. Integral type not supported.");
1150 }
1151 }
1152}
1153
1155template <dolfinx::scalar T, std::floating_point U = scalar_value_type_t<T>>
1157 const ufcx_expression& e,
1158 const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients,
1159 const std::vector<std::shared_ptr<const Constant<T>>>& constants,
1160 std::shared_ptr<const FunctionSpace<U>> argument_function_space = nullptr)
1161{
1162 if (e.rank > 0 and !argument_function_space)
1163 {
1164 throw std::runtime_error("Expression has Argument but no Argument "
1165 "function space was provided.");
1166 }
1167
1168 std::vector<U> X(e.points, e.points + e.num_points * e.entity_dimension);
1169 std::array<std::size_t, 2> Xshape
1170 = {static_cast<std::size_t>(e.num_points),
1171 static_cast<std::size_t>(e.entity_dimension)};
1172 std::vector<std::size_t> value_shape(e.value_shape,
1173 e.value_shape + e.num_components);
1174 std::function<void(T*, const T*, const T*,
1175 const typename scalar_value_type<T>::value_type*,
1176 const int*, const std::uint8_t*)>
1177 tabulate_tensor = nullptr;
1178 if constexpr (std::is_same_v<T, float>)
1179 tabulate_tensor = e.tabulate_tensor_float32;
1180#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
1181 else if constexpr (std::is_same_v<T, std::complex<float>>)
1182 {
1183 tabulate_tensor = reinterpret_cast<void (*)(
1184 T*, const T*, const T*,
1185 const typename scalar_value_type<T>::value_type*, const int*,
1186 const unsigned char*)>(e.tabulate_tensor_complex64);
1187 }
1188#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
1189 else if constexpr (std::is_same_v<T, double>)
1190 tabulate_tensor = e.tabulate_tensor_float64;
1191#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS
1192 else if constexpr (std::is_same_v<T, std::complex<double>>)
1193 {
1194 tabulate_tensor = reinterpret_cast<void (*)(
1195 T*, const T*, const T*,
1196 const typename scalar_value_type<T>::value_type*, const int*,
1197 const unsigned char*)>(e.tabulate_tensor_complex128);
1198 }
1199#endif // DOLFINX_NO_STDC_COMPLEX_KERNELS
1200 else
1201 throw std::runtime_error("Type not supported.");
1202
1203 assert(tabulate_tensor);
1204 return Expression(coefficients, constants, std::span<const U>(X), Xshape,
1205 tabulate_tensor, value_shape, argument_function_space);
1206}
1207
1210template <dolfinx::scalar T, std::floating_point U = scalar_value_type_t<T>>
1212 const ufcx_expression& e,
1213 const std::map<std::string, std::shared_ptr<const Function<T, U>>>&
1214 coefficients,
1215 const std::map<std::string, std::shared_ptr<const Constant<T>>>& constants,
1216 std::shared_ptr<const FunctionSpace<U>> argument_function_space = nullptr)
1217{
1218 // Place coefficients in appropriate order
1219 std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
1220 std::vector<std::string> coefficient_names;
1221 for (int i = 0; i < e.num_coefficients; ++i)
1222 coefficient_names.push_back(e.coefficient_names[i]);
1223
1224 for (const std::string& name : coefficient_names)
1225 {
1226 if (auto it = coefficients.find(name); it != coefficients.end())
1227 coeff_map.push_back(it->second);
1228 else
1229 {
1230 throw std::runtime_error("Expression coefficient \"" + name
1231 + "\" not provided.");
1232 }
1233 }
1234
1235 // Place constants in appropriate order
1236 std::vector<std::shared_ptr<const Constant<T>>> const_map;
1237 std::vector<std::string> constant_names;
1238 for (int i = 0; i < e.num_constants; ++i)
1239 constant_names.push_back(e.constant_names[i]);
1240
1241 for (const std::string& name : constant_names)
1242 {
1243 if (auto it = constants.find(name); it != constants.end())
1244 const_map.push_back(it->second);
1245 else
1246 {
1247 throw std::runtime_error("Expression constant \"" + name
1248 + "\" not provided.");
1249 }
1250 }
1251
1252 return create_expression(e, coeff_map, const_map, argument_function_space);
1253}
1254
1265template <dolfinx::scalar T, std::floating_point U>
1267 std::map<std::pair<IntegralType, int>,
1268 std::pair<std::vector<T>, int>>& coeffs)
1269{
1270 for (auto& [key, val] : coeffs)
1271 pack_coefficients<T>(form, key.first, key.second, val.first, val.second);
1272}
1273
1282template <dolfinx::scalar T, std::floating_point U>
1283std::pair<std::vector<T>, int>
1285 std::span<const std::int32_t> entities, std::size_t estride)
1286{
1287 // Get form coefficient offsets and dofmaps
1288 const std::vector<std::shared_ptr<const Function<T, U>>>& coeffs
1289 = e.coefficients();
1290 const std::vector<int> offsets = e.coefficient_offsets();
1291
1292 // Copy data into coefficient array
1293 const int cstride = offsets.back();
1294 std::vector<T> c(entities.size() / estride * offsets.back());
1295 if (!coeffs.empty())
1296 {
1297 // Iterate over coefficients
1298 for (std::size_t coeff = 0; coeff < coeffs.size(); ++coeff)
1299 {
1300 std::span<const std::uint32_t> cell_info
1301 = impl::get_cell_orientation_info(*coeffs[coeff]);
1302
1303 impl::pack_coefficient_entity(
1304 std::span(c), cstride, *coeffs[coeff], cell_info, entities, estride,
1305 [](auto entity) { return entity[0]; }, offsets[coeff]);
1306 }
1307 }
1308 return {std::move(c), cstride};
1309}
1310
1313template <typename U>
1314std::vector<typename U::scalar_type> pack_constants(const U& u)
1315{
1316 using T = typename U::scalar_type;
1317 const std::vector<std::shared_ptr<const Constant<T>>>& constants
1318 = u.constants();
1319
1320 // Calculate size of array needed to store packed constants
1321 std::int32_t size = std::accumulate(constants.cbegin(), constants.cend(), 0,
1322 [](std::int32_t sum, auto& constant)
1323 { return sum + constant->value.size(); });
1324
1325 // Pack constants
1326 std::vector<T> constant_values(size);
1327 std::int32_t offset = 0;
1328 for (auto& constant : constants)
1329 {
1330 const std::vector<T>& value = constant->value;
1331 std::ranges::copy(value, std::next(constant_values.begin(), offset));
1332 offset += value.size();
1333 }
1334
1335 return constant_values;
1336}
1337
1338} // namespace dolfinx::fem
Degree-of-freedom map representations and tools.
Definition utils.h:44
Timer for measuring and logging elapsed time durations.
Definition Timer.h:41
std::chrono::duration< double, Period > stop()
Stop timer and return elapsed time.
Definition Timer.h:91
Constant value which can be attached to a Form.
Definition Form.h:29
Degree-of-freedom map.
Definition DofMap.h:76
std::span< const std::int32_t > cell_dofs(std::int32_t c) const
Local-to-global mapping of dofs on a cell.
Definition DofMap.h:130
int bs() const noexcept
Return the block size for the dofmap.
Definition DofMap.cpp:173
Definition ElementDofLayout.h:30
Represents a mathematical expression evaluated at a pre-defined set of points on the reference cell.
Definition Function.h:32
Model of a finite element.
Definition FiniteElement.h:57
A representation of finite element variational forms.
Definition Form.h:139
const std::vector< std::shared_ptr< const Function< scalar_type, geometry_type > > > & coefficients() const
Access coefficients.
Definition Form.h:474
std::vector< int > coefficient_offsets() const
Offset for each coefficient expansion array on a cell.
Definition Form.h:488
std::span< const std::int32_t > domain(IntegralType type, int i) const
Get the list of mesh entity indices for the ith integral (kernel) of a given type.
Definition Form.h:350
std::shared_ptr< const mesh::Mesh< geometry_type > > mesh() const
Extract common mesh for the form.
Definition Form.h:248
std::vector< int > integral_ids(IntegralType type) const
Get the IDs for integrals (kernels) for given integral type.
Definition Form.h:324
std::vector< int > active_coeffs(IntegralType type, std::size_t i) const
Indices of coefficients that are active for a given integral (kernel).
Definition Form.h:311
std::set< IntegralType > integral_types() const
Get types of integrals in the form.
Definition Form.h:281
int num_integrals(IntegralType type) const
Number of integrals on given domain type.
Definition Form.h:296
This class represents a finite element function space defined by a mesh, a finite element,...
Definition vtk_utils.h:32
Definition XDMFFile.h:31
Definition topologycomputation.h:24
std::span< T > links(std::size_t node)
Definition AdjacencyList.h:111
Definition SparsityPattern.h:26
A Mesh consists of a set of connected and numbered mesh topological entities, and geometry data.
Definition Mesh.h:23
Topology stores the topology of a mesh, consisting of mesh entities and connectivity (incidence relat...
Definition Topology.h:45
std::shared_ptr< const common::IndexMap > index_map(int dim) const
Get the IndexMap that described the parallel distribution of the mesh entities.
Definition Topology.cpp:821
std::shared_ptr< const graph::AdjacencyList< std::int32_t > > connectivity(int d0, int d1) const
Return connectivity from entities of dimension d0 to entities of dimension d1. Assumes only one entit...
Definition Topology.cpp:937
const std::vector< std::int32_t > & interprocess_facets() const
List of inter-process facets.
Definition Topology.cpp:1015
int dim() const noexcept
Return the topological dimension of the mesh.
Definition Topology.cpp:800
Concepts for function that returns cell index.
Definition utils.h:873
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:843
std::array< std::int32_t, 2 *num_cells > get_cell_facet_pairs(std::int32_t f, std::span< const std::int32_t > cells, const graph::AdjacencyList< std::int32_t > &c_to_f)
Definition utils.h:64
void pack_coefficient_entity(std::span< T > c, int cstride, const Function< T, U > &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:892
Functions supporting mesh operations.
Miscellaneous classes, functions and types.
Definition dolfinx_common.h:8
void interior_facets(la::SparsityPattern &pattern, std::array< std::span< const std::int32_t >, 2 > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over interior facets and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:28
void cells(la::SparsityPattern &pattern, std::array< std::span< const std::int32_t >, 2 > cells, std::array< std::reference_wrapper< const DofMap >, 2 > dofmaps)
Iterate over cells and insert entries into sparsity pattern.
Definition sparsitybuild.cpp:16
Finite element method functionality.
Definition assemble_matrix_impl.h:26
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:124
std::pair< std::vector< T >, int > allocate_coefficient_storage(const Form< T, U > &form, IntegralType integral_type, int id)
Allocate storage for coefficients of a pair (integral_type, / id) from a Form.
Definition utils.h:973
Form< T, U > create_form_factory(const ufcx_form &ufcx_form, const std::vector< std::shared_ptr< const FunctionSpace< U > > > &spaces, const std::vector< std::shared_ptr< const Function< T, U > > > &coefficients, const std::vector< std::shared_ptr< const Constant< T > > > &constants, const std::map< IntegralType, std::vector< std::pair< std::int32_t, std::span< const std::int32_t > > > > &subdomains, const std::map< std::shared_ptr< const mesh::Mesh< U > >, std::span< const std::int32_t > > &entity_maps, std::shared_ptr< const mesh::Mesh< U > > mesh=nullptr)
Create a Form from UFCx input with coefficients and constants passed in the required order.
Definition utils.h:339
FunctionSpace< T > create_functionspace(std::shared_ptr< mesh::Mesh< T > > mesh, std::shared_ptr< const fem::FiniteElement< T > > e, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn=nullptr)
NEW Create a function space from a fem::FiniteElement.
Definition utils.h:793
std::vector< DofMap > create_dofmaps(MPI_Comm comm, const std::vector< ElementDofLayout > &layouts, mesh::Topology &topology, std::function< void(std::span< std::int32_t >, std::uint32_t)> permute_inv, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn)
Create a set of dofmaps on a given topology.
Definition utils.cpp:68
DofMap create_dofmap(MPI_Comm comm, const ElementDofLayout &layout, mesh::Topology &topology, std::function< void(std::span< std::int32_t >, std::uint32_t)> permute_inv, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn)
Create a dof map on mesh.
Definition utils.cpp:31
std::vector< std::string > get_coefficient_names(const ufcx_form &ufcx_form)
Definition utils.cpp:117
std::vector< std::vector< std::array< std::shared_ptr< const FunctionSpace< U > >, 2 > > > extract_function_spaces(const std::vector< std::vector< const Form< T, U > * > > &a)
Extract test (0) and trial (1) function spaces pairs for each bilinear form for a rectangular array o...
Definition utils.h:127
std::vector< std::int32_t > compute_integration_domains(IntegralType integral_type, const mesh::Topology &topology, std::span< const std::int32_t > entities)
Given an integral type and a set of entities, computes and return data for the entities that should b...
Definition utils.cpp:132
std::vector< typename U::scalar_type > pack_constants(const U &u)
Pack constants of u into a single array ready for assembly.
Definition utils.h:1314
Expression< T, U > create_expression(const ufcx_expression &e, const std::vector< std::shared_ptr< const Function< T, U > > > &coefficients, const std::vector< std::shared_ptr< const Constant< T > > > &constants, std::shared_ptr< const FunctionSpace< U > > argument_function_space=nullptr)
Create Expression from UFC.
Definition utils.h:1156
ElementDofLayout create_element_dof_layout(const fem::FiniteElement< T > &element, const std::vector< int > &parent_map={})
Create an ElementDofLayout from a FiniteElement.
Definition utils.h:246
Form< T, U > create_form(const ufcx_form &ufcx_form, const std::vector< std::shared_ptr< const FunctionSpace< U > > > &spaces, const std::map< std::string, std::shared_ptr< const Function< T, U > > > &coefficients, const std::map< std::string, std::shared_ptr< const Constant< T > > > &constants, const std::map< IntegralType, std::vector< std::pair< std::int32_t, std::span< const std::int32_t > > > > &subdomains, const std::map< std::shared_ptr< const mesh::Mesh< U > >, std::span< const std::int32_t > > &entity_maps, std::shared_ptr< const mesh::Mesh< U > > mesh=nullptr)
Create a Form from UFC input with coefficients and constants resolved by name.
Definition utils.h:710
IntegralType
Type of integral.
Definition Form.h:35
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
la::SparsityPattern create_sparsity_pattern(const Form< T, U > &a)
Create a sparsity pattern for a given form.
Definition utils.h:152
FunctionSpace(U mesh, V element, W dofmap) -> FunctionSpace< typename std::remove_cvref< typename U::element_type >::type::geometry_type::value_type >
Type deduction.
void pack_coefficients(const Form< T, U > &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:1027
std::vector< std::int32_t > exterior_facet_indices(const Topology &topology)
Compute the indices of all exterior facets that are owned by the caller.
Definition utils.cpp:58