10#include "CoordinateElement.h" 
   12#include "ElementDofLayout.h" 
   13#include "Expression.h" 
   16#include "FunctionSpace.h" 
   17#include "sparsitybuild.h" 
   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> 
   41template <std::
floating_po
int T>
 
   61template <
int num_cells>
 
   62std::array<std::int32_t, 2 * num_cells>
 
   67  assert(cells.size() == num_cells);
 
   68  std::array<std::int32_t, 2 * num_cells> cell_local_facet_pairs;
 
   69  for (
int c = 0; c < num_cells; ++c)
 
   72    std::int32_t 
cell = cells[c];
 
   74    auto facet_it = std::find(cell_facets.begin(), cell_facets.end(), f);
 
   75    assert(facet_it != cell_facets.end());
 
   76    int local_f = std::distance(cell_facets.begin(), facet_it);
 
   77    cell_local_facet_pairs[2 * c] = 
cell;
 
   78    cell_local_facet_pairs[2 * c + 1] = local_f;
 
   81  return cell_local_facet_pairs;
 
 
  108std::vector<std::int32_t>
 
  111                            std::span<const std::int32_t> entities, 
int dim);
 
  120template <dolfinx::scalar T, std::
floating_po
int U>
 
  121std::vector<std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
 
  125      std::vector<std::array<std::shared_ptr<const FunctionSpace<U>>, 2>>>
 
  130  for (std::size_t i = 0; i < a.size(); ++i)
 
  132    for (std::size_t j = 0; j < a[i].size(); ++j)
 
  135        spaces[i][j] = {form->function_spaces()[0], form->function_spaces()[1]};
 
 
  146template <dolfinx::scalar T, std::
floating_po
int U>
 
  151    throw std::runtime_error(
 
  152        "Cannot create sparsity pattern. Form is not a bilinear.");
 
  156  std::array<std::reference_wrapper<const DofMap>, 2> dofmaps{
 
  157      *a.function_spaces().at(0)->dofmap(),
 
  158      *a.function_spaces().at(1)->dofmap()};
 
  159  std::shared_ptr mesh = a.mesh();
 
  162  std::shared_ptr mesh0 = a.function_spaces().at(0)->mesh();
 
  164  std::shared_ptr mesh1 = a.function_spaces().at(1)->mesh();
 
  167  const std::set<IntegralType> types = a.integral_types();
 
  172    int tdim = mesh->topology()->dim();
 
  173    mesh->topology_mutable()->create_entities(tdim - 1);
 
  174    mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
 
  180  const std::array index_maps{dofmaps[0].get().index_map,
 
  181                              dofmaps[1].get().index_map};
 
  183      = {dofmaps[0].get().index_map_bs(), dofmaps[1].get().index_map_bs()};
 
  185  auto extract_cells = [](std::span<const std::int32_t> facets)
 
  187    assert(facets.size() % 2 == 0);
 
  188    std::vector<std::int32_t> cells;
 
  189    cells.reserve(facets.size() / 2);
 
  190    for (std::size_t i = 0; i < facets.size(); i += 2)
 
  191      cells.push_back(facets[i]);
 
  197  for (
auto type : types)
 
  199    std::vector<int> ids = a.integral_ids(type);
 
  206            pattern, {a.domain(type, 
id, *mesh0), a.domain(type, 
id, *mesh1)},
 
  207            {{dofmaps[0], dofmaps[1]}});
 
  215            {extract_cells(a.domain(type, 
id, *mesh0)),
 
  216             extract_cells(a.domain(type, 
id, *mesh1))},
 
  217            {{dofmaps[0], dofmaps[1]}});
 
  224                             {extract_cells(a.domain(type, 
id, *mesh0)),
 
  225                              extract_cells(a.domain(type, 
id, *mesh1))},
 
  226                             {{dofmaps[0], dofmaps[1]}});
 
  230      throw std::runtime_error(
"Unsupported integral type");
 
 
  240template <std::
floating_po
int T>
 
  242                                           const std::vector<int>& parent_map
 
  246  std::vector<int> offsets(1, 0);
 
  247  std::vector<dolfinx::fem::ElementDofLayout> sub_doflayout;
 
  248  int bs = element.block_size();
 
  249  for (
int i = 0; i < element.num_sub_elements(); ++i)
 
  254    std::shared_ptr<const fem::FiniteElement<T>> sub_e
 
  255        = element.sub_elements()[bs > 1 ? 0 : i];
 
  261    std::vector<int> parent_map_sub(sub_e->space_dimension(), offsets.back());
 
  262    for (std::size_t j = 0; j < parent_map_sub.size(); ++j)
 
  263      parent_map_sub[j] += bs * j;
 
  264    offsets.push_back(offsets.back() + (bs > 1 ? 1 : sub_e->space_dimension()));
 
  265    sub_doflayout.push_back(
 
  269  return ElementDofLayout(bs, element.entity_dofs(),
 
  270                          element.entity_closure_dofs(), parent_map,
 
 
  283    MPI_Comm comm, 
const ElementDofLayout& layout, mesh::Topology& topology,
 
  284    std::function<
void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
 
  285    std::function<std::vector<int>(
const graph::AdjacencyList<std::int32_t>&)>
 
  299    MPI_Comm comm, 
const std::vector<ElementDofLayout>& layouts,
 
  300    mesh::Topology& topology,
 
  301    std::function<
void(std::span<std::int32_t>, std::uint32_t)> permute_inv,
 
  302    std::function<std::vector<int>(
const graph::AdjacencyList<std::int32_t>&)>
 
  332template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
 
  334    const ufcx_form& ufcx_form,
 
  336    const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
 
  337    const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
 
  340        std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
 
  343                   std::span<const std::int32_t>>& entity_maps,
 
  346  if (ufcx_form.rank != (
int)spaces.size())
 
  347    throw std::runtime_error(
"Wrong number of argument spaces for Form.");
 
  348  if (ufcx_form.num_coefficients != (
int)coefficients.size())
 
  350    throw std::runtime_error(
 
  351        "Mismatch between number of expected and provided Form coefficients.");
 
  353  if (ufcx_form.num_constants != (
int)constants.size())
 
  355    throw std::runtime_error(
 
  356        "Mismatch between number of expected and provided Form constants.");
 
  360  for (std::size_t i = 0; i < spaces.size(); ++i)
 
  362    assert(spaces[i]->element());
 
  363    if (
auto element_hash = ufcx_form.finite_element_hashes[i];
 
  365        and element_hash != spaces[i]->element()->basix_element().hash())
 
  367      throw std::runtime_error(
"Cannot create form. Elements are different to " 
  368                               "those used to compile the form.");
 
  373  if (!mesh and !spaces.empty())
 
  374    mesh = spaces[0]->mesh();
 
  375  for (
auto& V : spaces)
 
  377    if (mesh != V->mesh() and entity_maps.find(V->mesh()) == entity_maps.end())
 
  378      throw std::runtime_error(
 
  379          "Incompatible mesh. entity_maps must be provided.");
 
  382    throw std::runtime_error(
"No mesh could be associated with the Form.");
 
  384  auto topology = mesh->topology();
 
  386  const int tdim = topology->dim();
 
  388  const int* integral_offsets = ufcx_form.form_integral_offsets;
 
  389  std::vector<int> num_integrals_type(3);
 
  390  for (
int i = 0; i < 3; ++i)
 
  391    num_integrals_type[i] = integral_offsets[i + 1] - integral_offsets[i];
 
  397    mesh->topology_mutable()->create_entities(tdim - 1);
 
  398    mesh->topology_mutable()->create_connectivity(tdim - 1, tdim);
 
  399    mesh->topology_mutable()->create_connectivity(tdim, tdim - 1);
 
  404  using kern_t = std::function<void(T*, 
const T*, 
const T*, 
const U*,
 
  405                                    const int*, 
const std::uint8_t*)>;
 
  406  std::map<IntegralType, std::vector<integral_data<T, U>>> integrals;
 
  409  bool needs_facet_permutations = 
false;
 
  410  std::vector<std::int32_t> default_cells;
 
  412    std::span<const int> ids(ufcx_form.form_integral_ids
 
  413                                 + integral_offsets[
cell],
 
  414                             num_integrals_type[
cell]);
 
  417    for (
int i = 0; i < num_integrals_type[
cell]; ++i)
 
  419      const int id = ids[i];
 
  420      ufcx_integral* integral
 
  421          = ufcx_form.form_integrals[integral_offsets[
cell] + i];
 
  425      std::vector<int> active_coeffs;
 
  426      for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
 
  428        if (integral->enabled_coefficients[j])
 
  429          active_coeffs.push_back(j);
 
  433      if constexpr (std::is_same_v<T, float>)
 
  434        k = integral->tabulate_tensor_float32;
 
  435#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
  436      else if constexpr (std::is_same_v<T, std::complex<float>>)
 
  438        k = 
reinterpret_cast<void (*)(
 
  439            T*, 
const T*, 
const T*,
 
  440            const typename scalar_value_type<T>::value_type*, 
const int*,
 
  441            const unsigned char*)
>(integral->tabulate_tensor_complex64);
 
  444      else if constexpr (std::is_same_v<T, double>)
 
  445        k = integral->tabulate_tensor_float64;
 
  446#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
  447      else if constexpr (std::is_same_v<T, std::complex<double>>)
 
  449        k = 
reinterpret_cast<void (*)(
 
  450            T*, 
const T*, 
const T*,
 
  451            const typename scalar_value_type<T>::value_type*, 
const int*,
 
  452            const unsigned char*)
>(integral->tabulate_tensor_complex128);
 
  458        throw std::runtime_error(
 
  459            "UFCx kernel function is NULL. Check requested types.");
 
  466        assert(topology->index_map(tdim));
 
  467        default_cells.resize(topology->index_map(tdim)->size_local(), 0);
 
  468        std::iota(default_cells.begin(), default_cells.end(), 0);
 
  469        itg.first->second.emplace_back(
id, k, default_cells, active_coeffs);
 
  471      else if (sd != subdomains.end())
 
  475            = std::ranges::lower_bound(sd->second, 
id, std::less<>{},
 
  476                                       [](
const auto& a) { return a.first; });
 
  477        if (it != sd->second.end() and it->first == 
id)
 
  478          itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
 
  481      if (integral->needs_facet_permutations)
 
  482        needs_facet_permutations = 
true;
 
  487  std::vector<std::int32_t> default_facets_ext;
 
  489    std::span<const int> ids(ufcx_form.form_integral_ids
 
  496      const int id = ids[i];
 
  497      ufcx_integral* integral
 
  500      std::vector<int> active_coeffs;
 
  501      for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
 
  503        if (integral->enabled_coefficients[j])
 
  504          active_coeffs.push_back(j);
 
  508      if constexpr (std::is_same_v<T, float>)
 
  509        k = integral->tabulate_tensor_float32;
 
  510#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
  511      else if constexpr (std::is_same_v<T, std::complex<float>>)
 
  513        k = 
reinterpret_cast<void (*)(
 
  514            T*, 
const T*, 
const T*,
 
  515            const typename scalar_value_type<T>::value_type*, 
const int*,
 
  516            const unsigned char*)
>(integral->tabulate_tensor_complex64);
 
  519      else if constexpr (std::is_same_v<T, double>)
 
  520        k = integral->tabulate_tensor_float64;
 
  521#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
  522      else if constexpr (std::is_same_v<T, std::complex<double>>)
 
  524        k = 
reinterpret_cast<void (*)(
 
  525            T*, 
const T*, 
const T*,
 
  526            const typename scalar_value_type<T>::value_type*, 
const int*,
 
  527            const unsigned char*)
>(integral->tabulate_tensor_complex128);
 
  534      auto f_to_c = topology->connectivity(tdim - 1, tdim);
 
  536      auto c_to_f = topology->connectivity(tdim, tdim - 1);
 
  541        default_facets_ext.reserve(2 * bfacets.size());
 
  542        for (std::int32_t f : bfacets)
 
  546              = impl::get_cell_facet_pairs<1>(f, f_to_c->links(f), *c_to_f);
 
  547          default_facets_ext.insert(default_facets_ext.end(), pair.begin(),
 
  550        itg.first->second.emplace_back(
id, k, default_facets_ext,
 
  553      else if (sd != subdomains.end())
 
  557            = std::ranges::lower_bound(sd->second, 
id, std::less<>{},
 
  558                                       [](
const auto& a) { return a.first; });
 
  559        if (it != sd->second.end() and it->first == 
id)
 
  560          itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
 
  563      if (integral->needs_facet_permutations)
 
  564        needs_facet_permutations = 
true;
 
  569  std::vector<std::int32_t> default_facets_int;
 
  571    std::span<const int> ids(ufcx_form.form_integral_ids
 
  578    std::vector<std::int8_t> interprocess_marker;
 
  581      assert(topology->index_map(tdim - 1));
 
  582      const std::vector<std::int32_t>& interprocess_facets
 
  583          = topology->interprocess_facets();
 
  584      std::int32_t num_facets = topology->index_map(tdim - 1)->size_local()
 
  585                                + topology->index_map(tdim - 1)->num_ghosts();
 
  586      interprocess_marker.resize(num_facets, 0);
 
  587      std::ranges::for_each(interprocess_facets, [&interprocess_marker](
auto f)
 
  588                            { interprocess_marker[f] = 1; });
 
  593      const int id = ids[i];
 
  594      ufcx_integral* integral
 
  597      std::vector<int> active_coeffs;
 
  598      for (
int j = 0; j < ufcx_form.num_coefficients; ++j)
 
  600        if (integral->enabled_coefficients[j])
 
  601          active_coeffs.push_back(j);
 
  605      if constexpr (std::is_same_v<T, float>)
 
  606        k = integral->tabulate_tensor_float32;
 
  607#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
  608      else if constexpr (std::is_same_v<T, std::complex<float>>)
 
  610        k = 
reinterpret_cast<void (*)(
 
  611            T*, 
const T*, 
const T*,
 
  612            const typename scalar_value_type<T>::value_type*, 
const int*,
 
  613            const unsigned char*)
>(integral->tabulate_tensor_complex64);
 
  616      else if constexpr (std::is_same_v<T, double>)
 
  617        k = integral->tabulate_tensor_float64;
 
  618#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
  619      else if constexpr (std::is_same_v<T, std::complex<double>>)
 
  621        k = 
reinterpret_cast<void (*)(
 
  622            T*, 
const T*, 
const T*,
 
  623            const typename scalar_value_type<T>::value_type*, 
const int*,
 
  624            const unsigned char*)
>(integral->tabulate_tensor_complex128);
 
  630      auto f_to_c = topology->connectivity(tdim - 1, tdim);
 
  632      auto c_to_f = topology->connectivity(tdim, tdim - 1);
 
  637        assert(topology->index_map(tdim - 1));
 
  638        std::int32_t num_facets = topology->index_map(tdim - 1)->size_local();
 
  639        default_facets_int.reserve(4 * num_facets);
 
  640        for (std::int32_t f = 0; f < num_facets; ++f)
 
  642          if (f_to_c->num_links(f) == 2)
 
  645                = impl::get_cell_facet_pairs<2>(f, f_to_c->links(f), *c_to_f);
 
  646            default_facets_int.insert(default_facets_int.end(), pairs.begin(),
 
  649          else if (interprocess_marker[f])
 
  651            throw std::runtime_error(
 
  652                "Cannot compute interior facet integral over interprocess " 
  653                "facet. Please use ghost mode shared facet when creating the " 
  657        itg.first->second.emplace_back(
id, k, default_facets_int,
 
  660      else if (sd != subdomains.end())
 
  663            = std::ranges::lower_bound(sd->second, 
id, std::less<>{},
 
  664                                       [](
const auto& a) { return a.first; });
 
  665        if (it != sd->second.end() and it->first == 
id)
 
  666          itg.first->second.emplace_back(
id, k, it->second, active_coeffs);
 
  669      if (integral->needs_facet_permutations)
 
  670        needs_facet_permutations = 
true;
 
  675           std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>>>
 
  677  for (
auto& [itg, data] : subdomains)
 
  679    std::vector<std::pair<std::int32_t, std::vector<std::int32_t>>> x;
 
  680    for (
auto& [
id, idx] : data)
 
  681      x.emplace_back(
id, std::vector(idx.data(), idx.data() + idx.size()));
 
  682    sd.insert({itg, std::move(x)});
 
  685  return Form<T, U>(spaces, integrals, coefficients, constants,
 
  686                    needs_facet_permutations, entity_maps, mesh);
 
 
  702template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
 
  704    const ufcx_form& ufcx_form,
 
  706    const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
 
  708    const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
 
  711        std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
 
  714                   std::span<const std::int32_t>>& entity_maps,
 
  718  std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
 
  721    if (
auto it = coefficients.find(name); it != coefficients.end())
 
  722      coeff_map.push_back(it->second);
 
  725      throw std::runtime_error(
"Form coefficient \"" + name
 
  726                               + 
"\" not provided.");
 
  732  std::vector<std::shared_ptr<const Constant<T>>> const_map;
 
  735    if (
auto it = constants.find(name); it != constants.end())
 
  736      const_map.push_back(it->second);
 
  738      throw std::runtime_error(
"Form constant \"" + name + 
"\" not provided.");
 
  742                             subdomains, entity_maps, mesh);
 
 
  762template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
 
  764    ufcx_form* (*fptr)(),
 
  766    const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
 
  768    const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
 
  771        std::vector<std::pair<std::int32_t, std::span<const std::int32_t>>>>&
 
  774                   std::span<const std::int32_t>>& entity_maps,
 
  777  ufcx_form* form = fptr();
 
  779                                   subdomains, entity_maps, mesh);
 
 
  795template <std::
floating_po
int T>
 
  798    const std::vector<std::size_t>& value_shape = {},
 
  803  if (!e.value_shape().empty() and !value_shape.empty())
 
  805    throw std::runtime_error(
 
  806        "Cannot specify value shape for non-scalar base element.");
 
  810      != mesh->topology()->cell_type())
 
  811    throw std::runtime_error(
"Cell type of element and mesh must match.");
 
  813  std::size_t bs = value_shape.empty()
 
  815                       : std::accumulate(value_shape.begin(), value_shape.end(),
 
  816                                         1, std::multiplies{});
 
  819  auto _e = std::make_shared<const FiniteElement<T>>(e, bs);
 
  822  const std::vector<std::size_t> _value_shape
 
  823      = (value_shape.empty() and !e.value_shape().empty())
 
  825                                       mesh->geometry().dim())
 
  829  const int num_sub_elements = _e->num_sub_elements();
 
  830  std::vector<ElementDofLayout> sub_doflayout;
 
  831  sub_doflayout.reserve(num_sub_elements);
 
  832  for (
int i = 0; i < num_sub_elements; ++i)
 
  834    auto sub_element = _e->extract_sub_element({i});
 
  835    std::vector<int> parent_map_sub(sub_element->space_dimension());
 
  836    for (std::size_t j = 0; j < parent_map_sub.size(); ++j)
 
  837      parent_map_sub[j] = i + _e->block_size() * j;
 
  838    sub_doflayout.emplace_back(1, e.entity_dofs(), e.entity_closure_dofs(),
 
  839                               parent_map_sub, std::vector<ElementDofLayout>());
 
  843  ElementDofLayout layout(_e->block_size(), e.entity_dofs(),
 
  844                          e.entity_closure_dofs(), {}, sub_doflayout);
 
  845  std::function<void(std::span<std::int32_t>, std::uint32_t)> permute_inv
 
  847  if (_e->needs_dof_permutations())
 
  848    permute_inv = _e->dof_permutation_fn(
true, 
true);
 
  850  assert(mesh->topology());
 
  852      mesh->comm(), layout, *mesh->topology(), permute_inv, reorder_fn));
 
 
  860template <dolfinx::scalar T, std::
floating_po
int U>
 
  861std::span<const std::uint32_t>
 
  862get_cell_orientation_info(
const Function<T, U>& coefficient)
 
  864  std::span<const std::uint32_t> cell_info;
 
  865  auto element = coefficient.function_space()->element();
 
  866  if (element->needs_dof_transformations())
 
  868    auto mesh = coefficient.function_space()->mesh();
 
  869    mesh->topology_mutable()->create_entity_permutations();
 
  870    cell_info = std::span(mesh->topology()->get_cell_permutation_info());
 
  877template <
int _bs, dolfinx::scalar T>
 
  878void pack(std::span<T> coeffs, std::int32_t 
cell, 
int bs, std::span<const T> v,
 
  879          std::span<const std::uint32_t> cell_info, 
const DofMap& dofmap,
 
  883  for (std::size_t i = 0; i < dofs.size(); ++i)
 
  885    if constexpr (_bs < 0)
 
  887      const int pos_c = bs * i;
 
  888      const int pos_v = bs * dofs[i];
 
  889      for (
int k = 0; k < bs; ++k)
 
  890        coeffs[pos_c + k] = v[pos_v + k];
 
  895      const int pos_c = _bs * i;
 
  896      const int pos_v = _bs * dofs[i];
 
  897      for (
int k = 0; k < _bs; ++k)
 
  898        coeffs[pos_c + k] = v[pos_v + k];
 
  902  transform(coeffs, cell_info, 
cell, 1);
 
 
  908concept FetchCells = 
requires(F&& f, std::span<const std::int32_t> v) {
 
  909  requires std::invocable<F, std::span<const std::int32_t>>;
 
  910  { f(v) } -> std::convertible_to<std::int32_t>;
 
 
  926template <dolfinx::scalar T, std::
floating_po
int U>
 
  929                             std::span<const std::uint32_t> cell_info,
 
  930                             std::span<const std::int32_t> entities,
 
  931                             std::size_t estride, 
FetchCells auto&& fetch_cells,
 
  935  std::span<const T> v = u.x()->array();
 
  936  const DofMap& dofmap = *u.function_space()->dofmap();
 
  937  auto element = u.function_space()->element();
 
  939  int space_dim = element->space_dimension();
 
  945  const int bs = dofmap.
bs();
 
  949    for (std::size_t e = 0; e < entities.size(); e += estride)
 
  951      auto entity = entities.subspan(e, estride);
 
  952      if (std::int32_t 
cell = fetch_cells(entity); 
cell >= 0)
 
  955            = c.subspan((e / estride) * cstride + offset, space_dim);
 
  956        pack<1>(cell_coeff, 
cell, bs, v, cell_info, dofmap, transformation);
 
  961    for (std::size_t e = 0; e < entities.size(); e += estride)
 
  963      auto entity = entities.subspan(e, estride);
 
  964      if (std::int32_t 
cell = fetch_cells(entity); 
cell >= 0)
 
  967            = c.subspan((e / estride) * cstride + offset, space_dim);
 
  968        pack<2>(cell_coeff, 
cell, bs, v, cell_info, dofmap, transformation);
 
  973    for (std::size_t e = 0; e < entities.size(); e += estride)
 
  975      auto entity = entities.subspan(e, estride);
 
  976      if (std::int32_t 
cell = fetch_cells(entity); 
cell >= 0)
 
  978        auto cell_coeff = c.subspan(e / estride * cstride + offset, space_dim);
 
  979        pack<3>(cell_coeff, 
cell, bs, v, cell_info, dofmap, transformation);
 
  984    for (std::size_t e = 0; e < entities.size(); e += estride)
 
  986      auto entity = entities.subspan(e, estride);
 
  987      if (std::int32_t 
cell = fetch_cells(entity); 
cell >= 0)
 
  990            = c.subspan((e / estride) * cstride + offset, space_dim);
 
  991        pack<-1>(cell_coeff, 
cell, bs, v, cell_info, dofmap, transformation);
 
 
 1006template <dolfinx::scalar T, std::
floating_po
int U>
 
 1007std::pair<std::vector<T>, 
int>
 
 1012  const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
 
 1016  std::size_t num_entities = 0;
 
 1018  if (!coefficients.empty())
 
 1020    cstride = offsets.back();
 
 1021    num_entities = form.
domain(integral_type, 
id).size();
 
 1029  return {std::vector<T>(num_entities * cstride), cstride};
 
 
 1036template <dolfinx::scalar T, std::
floating_po
int U>
 
 1037std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, 
int>>
 
 1040  std::map<std::pair<IntegralType, int>, std::pair<std::vector<T>, 
int>> coeffs;
 
 1045      coeffs.emplace_hint(
 
 1046          coeffs.end(), std::pair(integral_type, 
id),
 
 
 1061template <dolfinx::scalar T, std::
floating_po
int U>
 
 1063                       int id, std::span<T> c, 
int cstride)
 
 1066  const std::vector<std::shared_ptr<const Function<T, U>>>& coefficients
 
 1071  std::vector<int> active_coefficient(coefficients.size(), 0);
 
 1072  if (!coefficients.empty())
 
 1074    switch (integral_type)
 
 1083          active_coefficient[idx] = 1;
 
 1087      for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
 
 1089        if (!active_coefficient[coeff])
 
 1093        auto mesh = coefficients[coeff]->function_space()->mesh();
 
 1100            = form.
mesh()->topology()->dim() - mesh->topology()->dim();
 
 1103          throw std::runtime_error(
"Should not be packing coefficients with " 
 1104                                   "codim>0 in a cell integral");
 
 1107        std::vector<std::int32_t> cells
 
 1109        std::span<const std::uint32_t> cell_info
 
 1110            = impl::get_cell_orientation_info(*coefficients[coeff]);
 
 1111        impl::pack_coefficient_entity(
 
 1112            c, cstride, *coefficients[coeff], cell_info, cells, 1,
 
 1113            [](
auto entity) { 
return entity.front(); }, offsets[coeff]);
 
 1121      for (std::size_t i = 0;
 
 1125          active_coefficient[idx] = 1;
 
 1129      for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
 
 1131        if (!active_coefficient[coeff])
 
 1134        auto mesh = coefficients[coeff]->function_space()->mesh();
 
 1135        std::vector<std::int32_t> facets
 
 1137        std::span<const std::uint32_t> cell_info
 
 1138            = impl::get_cell_orientation_info(*coefficients[coeff]);
 
 1139        impl::pack_coefficient_entity(
 
 1140            c, cstride, *coefficients[coeff], cell_info, facets, 2,
 
 1141            [](
auto entity) { 
return entity.front(); }, offsets[coeff]);
 
 1149      for (std::size_t i = 0;
 
 1153          active_coefficient[idx] = 1;
 
 1157      for (std::size_t coeff = 0; coeff < coefficients.size(); ++coeff)
 
 1159        if (!active_coefficient[coeff])
 
 1162        auto mesh = coefficients[coeff]->function_space()->mesh();
 
 1163        std::vector<std::int32_t> facets
 
 1166        std::span<const std::uint32_t> cell_info
 
 1167            = impl::get_cell_orientation_info(*coefficients[coeff]);
 
 1170        impl::pack_coefficient_entity(
 
 1171            c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
 
 1172            [](
auto entity) { 
return entity[0]; }, 2 * offsets[coeff]);
 
 1175        impl::pack_coefficient_entity(
 
 1176            c, 2 * cstride, *coefficients[coeff], cell_info, facets, 4,
 
 1177            [](
auto entity) { 
return entity[2]; },
 
 1178            offsets[coeff] + offsets[coeff + 1]);
 
 1183      throw std::runtime_error(
 
 1184          "Could not pack coefficient. Integral type not supported.");
 
 
 1190template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
 
 1192    const ufcx_expression& e,
 
 1193    const std::vector<std::shared_ptr<
const Function<T, U>>>& coefficients,
 
 1194    const std::vector<std::shared_ptr<
const Constant<T>>>& constants,
 
 1197  if (e.rank > 0 and !argument_function_space)
 
 1199    throw std::runtime_error(
"Expression has Argument but no Argument " 
 1200                             "function space was provided.");
 
 1203  std::vector<U> X(e.points, e.points + e.num_points * e.entity_dimension);
 
 1204  std::array<std::size_t, 2> Xshape
 
 1205      = {
static_cast<std::size_t
>(e.num_points),
 
 1206         static_cast<std::size_t
>(e.entity_dimension)};
 
 1207  std::vector<int> value_shape(e.value_shape, e.value_shape + e.num_components);
 
 1208  std::function<void(T*, 
const T*, 
const T*,
 
 1209                     const typename scalar_value_type<T>::value_type*,
 
 1210                     const int*, 
const std::uint8_t*)>
 
 1211      tabulate_tensor = 
nullptr;
 
 1212  if constexpr (std::is_same_v<T, float>)
 
 1213    tabulate_tensor = e.tabulate_tensor_float32;
 
 1214#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
 1215  else if constexpr (std::is_same_v<T, std::complex<float>>)
 
 1217    tabulate_tensor = 
reinterpret_cast<void (*)(
 
 1218        T*, 
const T*, 
const T*,
 
 1219        const typename scalar_value_type<T>::value_type*, 
const int*,
 
 1220        const unsigned char*)
>(e.tabulate_tensor_complex64);
 
 1223  else if constexpr (std::is_same_v<T, double>)
 
 1224    tabulate_tensor = e.tabulate_tensor_float64;
 
 1225#ifndef DOLFINX_NO_STDC_COMPLEX_KERNELS 
 1226  else if constexpr (std::is_same_v<T, std::complex<double>>)
 
 1228    tabulate_tensor = 
reinterpret_cast<void (*)(
 
 1229        T*, 
const T*, 
const T*,
 
 1230        const typename scalar_value_type<T>::value_type*, 
const int*,
 
 1231        const unsigned char*)
>(e.tabulate_tensor_complex128);
 
 1235    throw std::runtime_error(
"Type not supported.");
 
 1237  assert(tabulate_tensor);
 
 1238  return Expression(coefficients, constants, std::span<const U>(X), Xshape,
 
 1239                    tabulate_tensor, value_shape, argument_function_space);
 
 
 1244template <dolfinx::scalar T, std::
floating_po
int U = scalar_value_type_t<T>>
 
 1246    const ufcx_expression& e,
 
 1247    const std::map<std::string, std::shared_ptr<
const Function<T, U>>>&
 
 1249    const std::map<std::string, std::shared_ptr<
const Constant<T>>>& constants,
 
 1253  std::vector<std::shared_ptr<const Function<T, U>>> coeff_map;
 
 1254  std::vector<std::string> coefficient_names;
 
 1255  for (
int i = 0; i < e.num_coefficients; ++i)
 
 1256    coefficient_names.push_back(e.coefficient_names[i]);
 
 1258  for (
const std::string& name : coefficient_names)
 
 1260    if (
auto it = coefficients.find(name); it != coefficients.end())
 
 1261      coeff_map.push_back(it->second);
 
 1264      throw std::runtime_error(
"Expression coefficient \"" + name
 
 1265                               + 
"\" not provided.");
 
 1270  std::vector<std::shared_ptr<const Constant<T>>> const_map;
 
 1271  std::vector<std::string> constant_names;
 
 1272  for (
int i = 0; i < e.num_constants; ++i)
 
 1273    constant_names.push_back(e.constant_names[i]);
 
 1275  for (
const std::string& name : constant_names)
 
 1277    if (
auto it = constants.find(name); it != constants.end())
 
 1278      const_map.push_back(it->second);
 
 1281      throw std::runtime_error(
"Expression constant \"" + name
 
 1282                               + 
"\" not provided.");
 
 
 1299template <dolfinx::scalar T, std::
floating_po
int U>
 
 1301                       std::map<std::pair<IntegralType, int>,
 
 1302                                std::pair<std::vector<T>, 
int>>& coeffs)
 
 1304  for (
auto& [key, val] : coeffs)
 
 
 1316template <dolfinx::scalar T, std::
floating_po
int U>
 
 1317std::pair<std::vector<T>, 
int>
 
 1319                  std::span<const std::int32_t> entities, std::size_t estride)
 
 1322  const std::vector<std::shared_ptr<const Function<T, U>>>& coeffs
 
 1324  const std::vector<int> offsets = e.coefficient_offsets();
 
 1327  const int cstride = offsets.back();
 
 1328  std::vector<T> c(entities.size() / estride * offsets.back());
 
 1329  if (!coeffs.empty())
 
 1332    for (std::size_t coeff = 0; coeff < coeffs.size(); ++coeff)
 
 1334      std::span<const std::uint32_t> cell_info
 
 1335          = impl::get_cell_orientation_info(*coeffs[coeff]);
 
 1337      impl::pack_coefficient_entity(
 
 1338          std::span(c), cstride, *coeffs[coeff], cell_info, entities, estride,
 
 1339          [](
auto entity) { 
return entity[0]; }, offsets[coeff]);
 
 1342  return {std::move(c), cstride};
 
 
 1347template <
typename U>
 
 1350  using T = 
typename U::scalar_type;
 
 1351  const std::vector<std::shared_ptr<const Constant<T>>>& constants
 
 1355  std::int32_t size = std::accumulate(constants.cbegin(), constants.cend(), 0,
 
 1356                                      [](std::int32_t sum, 
auto& constant)
 
 1357                                      { return sum + constant->value.size(); });
 
 1360  std::vector<T> constant_values(size);
 
 1361  std::int32_t offset = 0;
 
 1362  for (
auto& constant : constants)
 
 1364    const std::vector<T>& value = constant->value;
 
 1365    std::ranges::copy(value, std::next(constant_values.begin(), offset));
 
 1366    offset += value.size();
 
 1369  return constant_values;
 
 
Degree-of-freedom map representations and tools.
double stop()
Definition Timer.cpp:38
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:38
This class represents a finite element function space defined by a mesh, a finite element,...
Definition vtk_utils.h:32
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:44
Concepts for function that returns cell index.
Definition utils.h:908
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:878
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:63
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:927
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:1008
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:333
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
FunctionSpace(U mesh, V element, W dofmap, X value_shape) -> FunctionSpace< typename std::remove_cvref< typename U::element_type >::type::geometry_type::value_type >
Type deduction.
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:122
std::vector< std::int32_t > compute_integration_domains(IntegralType integral_type, const mesh::Topology &topology, std::span< const std::int32_t > entities, int dim)
Given an integral type and a set of entities, compute the entities that should be integrated over.
Definition utils.cpp:131
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:1348
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:1191
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:241
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:703
IntegralType
Type of integral.
Definition Form.h:35
@ interior_facet
Interior facet.
@ exterior_facet
Exterior facet.
FunctionSpace< T > create_functionspace(std::shared_ptr< mesh::Mesh< T > > mesh, const basix::FiniteElement< T > &e, const std::vector< std::size_t > &value_shape={}, std::function< std::vector< int >(const graph::AdjacencyList< std::int32_t > &)> reorder_fn=nullptr)
Create a function space from a Basix element.
Definition utils.h:796
la::SparsityPattern create_sparsity_pattern(const Form< T, U > &a)
Create a sparsity pattern for a given form.
Definition utils.h:147
std::vector< std::size_t > compute_value_shape(std::shared_ptr< const dolfinx::fem::FiniteElement< T > > element, std::size_t tdim, std::size_t gdim)
Compute the physical value shape of an element for a mesh.
Definition FunctionSpace.h:439
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:1062
CellType cell_type_from_basix_type(basix::cell::type celltype)
Get a cell type from a Basix cell type.
Definition cell_types.cpp:237
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