Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
52 commits
Select commit Hold shift + click to select a range
7ade28f
Make submesh expressions work (codim 0 for now, missing test for codi…
jorgensd Apr 1, 2026
57e9fdd
Minor cleanup
jorgensd Apr 1, 2026
b9ddd8b
Add codim 1 test and fix bug
jorgensd Apr 1, 2026
5c10ffa
Change fffcx ref
jorgensd Apr 1, 2026
322b427
Ruff formatting
jorgensd Apr 1, 2026
0cb61fd
Mypy
jorgensd Apr 1, 2026
bfc5482
Sort imports
jorgensd Apr 1, 2026
97155c2
Remove file
jorgensd Apr 1, 2026
c32e457
Fix C++ demo and test and minor logic change for when to check for co…
jorgensd Apr 1, 2026
2858d12
Try fixing create_expression
jorgensd Apr 1, 2026
0720d7c
Reorder attributes
jorgensd Apr 1, 2026
6067f80
Add docs
jorgensd Apr 1, 2026
4487a75
Fix import for docs
jorgensd Apr 1, 2026
de056d5
Copy data as it is strided when extracted from python
jorgensd Apr 1, 2026
9322220
Fix for parallel test
jorgensd Apr 1, 2026
05d71d4
Further parallel fixes
jorgensd Apr 1, 2026
2a669b1
Merge branch 'main' into dokken/submesh-expression
jorgensd Apr 17, 2026
4a7c72e
Revert to main branch of FFCx
jorgensd Apr 17, 2026
cecaa74
Merge branch 'main' into dokken/submesh-expression
jorgensd Apr 23, 2026
e7161a8
Update API
jorgensd Apr 23, 2026
10a6464
Merge branch 'main' into dokken/submesh-expression
jorgensd May 5, 2026
ecfa3a9
Add some typing
jorgensd May 5, 2026
d6d4396
Merge branch 'main' into dokken/submesh-expression
jorgensd May 21, 2026
f26e03a
Improve docstrings
jorgensd May 26, 2026
9d78d86
Docstring improvement part 2
jorgensd May 26, 2026
cf58cb3
Add constexpr to else if
jorgensd May 26, 2026
dffe7da
Clang format
jorgensd May 26, 2026
893454b
Use switch
jorgensd May 26, 2026
c29d158
Refactor to use extraction of coefficient cells.
jorgensd May 26, 2026
acea85a
Add docs
jorgensd May 26, 2026
41a05b6
Minor doc change to rerun CI
jorgensd May 26, 2026
c5a87d6
Merge branch 'main' into dokken/submesh-expression
jorgensd May 26, 2026
199544f
Merge branch 'main' into dokken/submesh-expression
jorgensd May 28, 2026
bb1915a
Merge branch 'main' into dokken/submesh-expression
jorgensd May 28, 2026
591215d
Use reference
jorgensd May 29, 2026
ddf4ea1
Address comments by @schnellerhase
jorgensd May 29, 2026
76bee61
Merge branch 'main' into dokken/submesh-expression
jorgensd May 29, 2026
393dba1
Simpler to vector trafo
schnellerhase May 29, 2026
5a1e865
Fix: left facet marking
schnellerhase May 29, 2026
32103e2
Fix: test use fdim and analytical expression
schnellerhase May 29, 2026
cf8cad6
Check me: use extent not size
schnellerhase May 29, 2026
7db5dfa
Expose facet permutations to expression on facets
jorgensd May 29, 2026
83e4161
Merge branch 'main' into dokken/submesh-expression
jorgensd May 29, 2026
0b6c615
Ruff format
jorgensd May 29, 2026
d4d3fbd
More ruff
jorgensd May 29, 2026
14c3a1c
Extend tests
jorgensd Jun 1, 2026
5d635a6
Test ffcx branch
jorgensd Jun 1, 2026
603f4d3
Reformat imports in test
jorgensd Jun 1, 2026
8921230
Apply suggestions from code review
jorgensd Jun 1, 2026
ed5210b
Merge with main
jorgensd Jun 1, 2026
41da267
Merge branch 'main' into dokken/submesh-expression
jorgensd Jun 1, 2026
73e9f55
remove new file
jorgensd Jun 1, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cpp/demo/hyperelasticity/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,7 +326,7 @@ int main(int argc, char* argv[])
// Compute Cauchy stress. Construct appropriate Basix element for
// stress.
fem::Expression sigma_expression = fem::create_expression<T, U>(
*expression_hyperelasticity_sigma, {{"u", u}}, {});
*expression_hyperelasticity_sigma, {{"u", u}}, {}, {});
Comment thread
jorgensd marked this conversation as resolved.

constexpr auto family = basix::element::family::P;
auto cell_type
Expand Down
74 changes: 47 additions & 27 deletions cpp/dolfinx/fem/Expression.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
// Copyright (C) 2020-2025 Jack S. Hale, Michal Habera and Garth N. Wells
// Copyright (C) 2020-2026 Jack S. Hale, Michal Habera, Garth N. Wells and
// Jørgen S. Dokken
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
Expand All @@ -12,6 +13,7 @@
#include <array>
#include <concepts>
#include <dolfinx/common/types.h>
#include <dolfinx/mesh/EntityMap.h>
#include <dolfinx/mesh/Mesh.h>
#include <functional>
#include <memory>
Expand Down Expand Up @@ -62,38 +64,35 @@
/// @param[in] fn Function for tabulating the Expression.
/// @param[in] value_shape Shape of Expression evaluated at single
/// point.
/// @param[in] entity_maps Maps between entities of different meshes.
/// @param[in] coordinate_element_hash Hash for coordinate element used
/// to create the expression.
/// @param[in] argument_space Function space for Argument. Used to
/// computed a 1-form expression, e.g. can be used to create a matrix
/// that when applied to a degree-of-freedom vector gives the
/// expression values at the evaluation points.
Expression(const std::vector<std::shared_ptr<
const Function<scalar_type, geometry_type>>>& coefficients,
const std::vector<std::shared_ptr<const Constant<scalar_type>>>&
constants,
std::span<const geometry_type> X,
std::array<std::size_t, 2> Xshape,
std::function<void(scalar_type*, const scalar_type*,
const scalar_type*, const geometry_type*,
const int*, const uint8_t*, void*)>
fn,
const std::vector<std::size_t>& value_shape,
std::shared_ptr<const FunctionSpace<geometry_type>> argument_space
= nullptr)
Expression(

Check warning on line 74 in cpp/dolfinx/fem/Expression.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

This function has 9 parameters, which is greater than the 7 authorized.

See more on https://sonarcloud.io/project/issues?id=FEniCS_dolfinx&issues=AZ33pAfAKvkQ6ozvvR3O&open=AZ33pAfAKvkQ6ozvvR3O&pullRequest=4140
Comment thread
jorgensd marked this conversation as resolved.
const std::vector<std::shared_ptr<
const Function<scalar_type, geometry_type>>>& coefficients,
const std::vector<std::shared_ptr<const Constant<scalar_type>>>&
constants,
std::span<const geometry_type> X, std::array<std::size_t, 2> Xshape,
std::function<void(scalar_type*, const scalar_type*, const scalar_type*,
const geometry_type*, const int*, const uint8_t*,
void*)>

Check failure on line 82 in cpp/dolfinx/fem/Expression.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Replace this use of "void *" with a more meaningful type.

See more on https://sonarcloud.io/project/issues?id=FEniCS_dolfinx&issues=AZ33pAfAKvkQ6ozvvR3P&open=AZ33pAfAKvkQ6ozvvR3P&pullRequest=4140
fn,
const std::vector<std::size_t>& value_shape,
const std::vector<std::reference_wrapper<const dolfinx::mesh::EntityMap>>&
entity_maps,

std::uint64_t coordinate_element_hash,
std::shared_ptr<const FunctionSpace<geometry_type>> argument_space
= nullptr)
: _argument_space(argument_space), _coefficients(coefficients),
_constants(constants), _fn(fn), _value_shape(value_shape),
_x_ref(std::vector<geometry_type>(X.begin(), X.end()), Xshape)

{
for (auto& c : _coefficients)
{
assert(c);
if (c->function_space()->mesh()
!= _coefficients.front()->function_space()->mesh())
{
throw std::runtime_error("Coefficients not all defined on same mesh.");
}
}
}
_x_ref(std::vector<geometry_type>(X.begin(), X.end()), Xshape),
_entity_maps(entity_maps),
_coordinate_element_hash(coordinate_element_hash) {};

/// Move constructor
Expression(Expression&& e) = default;
Expand Down Expand Up @@ -168,6 +167,19 @@
return _x_ref;
}

/// @brief Maps between entities of different meshes.
const std::vector<std::reference_wrapper<const dolfinx::mesh::EntityMap>>&
entity_maps() const
{
return _entity_maps;
}

/// @brief Hash for coordinate element used to create the expression.
std::uint64_t coordinate_element_hash() const
{
return _coordinate_element_hash;
}

private:
// Function space for Argument
std::shared_ptr<const FunctionSpace<geometry_type>> _argument_space;
Expand All @@ -189,5 +201,13 @@

// Evaluation points on reference cell
std::pair<std::vector<geometry_type>, std::array<std::size_t, 2>> _x_ref;

// Set of bidirectional maps of mesh entities (cells, facets, ridges or peaks)
// between meshes and submeshes of any codimension
std::vector<std::reference_wrapper<const dolfinx::mesh::EntityMap>>
_entity_maps;

// Hash for coordinate element used to create the expression
std::uint64_t _coordinate_element_hash;
};
} // namespace dolfinx::fem
25 changes: 20 additions & 5 deletions cpp/dolfinx/fem/assemble_expression_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ namespace dolfinx::fem::impl
/// @param[in] P0 Degree-of-freedom transformation function. Applied when
/// expressions includes an argument function that requires a
/// transformation.
/// @param[in] perms Entity permutation information for use in `fn`.
template <dolfinx::scalar T, std::floating_point U>
void tabulate_expression(
std::span<T> values, fem::FEkernel<T> auto fn,
Expand All @@ -68,7 +69,8 @@ void tabulate_expression(
md::mdspan<const T, md::dextents<std::size_t, 2>> coeffs,
std::span<const T> constants, fem::MDSpan2 auto entities,
std::span<const std::uint32_t> cell_info,
fem::DofTransformKernel<T> auto P0)
fem::DofTransformKernel<T> auto P0,
md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> perms)
{
static_assert(entities.rank() == 1 or entities.rank() == 2);

Expand Down Expand Up @@ -99,15 +101,16 @@ void tabulate_expression(
else
{
std::int32_t entity = entities(e, 0);
std::int32_t local_entity = entities(e, 1);
std::uint8_t perm = perms.empty() ? 0 : perms(entity, local_entity);
auto x_dofs = md::submdspan(x_dofmap, entity, md::full_extent);
for (std::size_t i = 0; i < x_dofs.size(); ++i)
{
std::copy_n(std::next(x.begin(), 3 * x_dofs[i]), 3,
std::next(coord_dofs.begin(), 3 * i));
}
fn(values_local.data(), &coeffs(e, 0), constants.data(),
coord_dofs.data(), &entities(e, 1), nullptr, nullptr);

coord_dofs.data(), &local_entity, &perm, nullptr);
P0(values_local, cell_info, entity, size0);
}

Expand Down Expand Up @@ -183,10 +186,22 @@ void tabulate_expression(
doftransform::transpose);
}
}

// An expression has no notion of requiring a facet permutation.
md::mdspan<const std::uint8_t, md::dextents<std::size_t, 2>> facet_perms;
if constexpr (entities.rank() == 2)
{
mesh::CellType cell_type = mesh.topology()->cell_types()[0];
int num_facets_per_cell
= mesh::cell_num_entities(cell_type, mesh.topology()->dim() - 1);
mesh.topology_mutable()->create_entity_permutations();
const std::vector<std::uint8_t>& p
= mesh.topology()->get_facet_permutations();
facet_perms = md::mdspan(p.data(), p.size() / num_facets_per_cell,
num_facets_per_cell);
}
tabulate_expression<T, U>(values, fn, Xshape, value_size, num_argument_dofs,
mesh.geometry().dofmaps().front(),
mesh.geometry().x(), coeffs, constants, entities,
cell_info, post_dof_transform);
cell_info, post_dof_transform, facet_perms);
}
} // namespace dolfinx::fem::impl
21 changes: 18 additions & 3 deletions cpp/dolfinx/fem/assembler.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Copyright (C) 2018-2025 Garth N. Wells
// Copyright (C) 2018-2026 Garth N. Wells and Jørgen S. Dokken
//
// This file is part of DOLFINx (https://www.fenicsproject.org)
//
Expand All @@ -19,6 +19,7 @@
#include <basix/mdspan.hpp>
#include <cstdint>
#include <dolfinx/common/types.h>
#include <dolfinx/mesh/EntityMap.h>
#include <memory>
#include <optional>
#include <span>
Expand Down Expand Up @@ -70,6 +71,12 @@
std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
element)
{
// Check that domain is the same as mesh of the expression
if (e.coordinate_element_hash() != mesh.geometry().cmaps().front().hash())
{
throw std::runtime_error(
"Expression was created on a different mesh. Cannot tabulate.");

Check warning on line 78 in cpp/dolfinx/fem/assembler.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define and throw a dedicated exception instead of using a generic one.

See more on https://sonarcloud.io/project/issues?id=FEniCS_dolfinx&issues=AZ33pAasKvkQ6ozvvR3M&open=AZ33pAasKvkQ6ozvvR3M&pullRequest=4140
}
auto [X, Xshape] = e.X();
impl::tabulate_expression(values, e.kernel(), Xshape, e.value_size(), coeffs,
constants, mesh, entities, element);
Expand All @@ -95,6 +102,13 @@
void tabulate_expression(std::span<T> values, const fem::Expression<T, U>& e,
const mesh::Mesh<U>& mesh, fem::MDSpan2 auto entities)
{
// Check that domain is the same as mesh of the expression
if (e.coordinate_element_hash() != mesh.geometry().cmaps().front().hash())
{
throw std::runtime_error(
"Expression was created on a different mesh. Cannot tabulate.");

Check warning on line 109 in cpp/dolfinx/fem/assembler.h

View check run for this annotation

SonarQubeCloud / SonarCloud Code Analysis

Define and throw a dedicated exception instead of using a generic one.

See more on https://sonarcloud.io/project/issues?id=FEniCS_dolfinx&issues=AZ33pAasKvkQ6ozvvR3N&open=AZ33pAasKvkQ6ozvvR3N&pullRequest=4140
}

std::optional<
std::pair<std::reference_wrapper<const FiniteElement<U>>, std::size_t>>
element = std::nullopt;
Expand All @@ -115,12 +129,13 @@
std::vector<std::reference_wrapper<const Function<T, U>>> c;
std::ranges::transform(coefficients, std::back_inserter(c),
[](auto c) -> const Function<T, U>& { return *c; });
fem::pack_coefficients(c, coffsets, entities, std::span(coeffs));
fem::pack_coefficients(c, mesh, entities, e.entity_maps(), coffsets,
std::span(coeffs));
}
std::vector<T> constants = fem::pack_constants(e);

tabulate_expression<T, U>(
values, e, md::mdspan(coeffs.data(), entities.size(), cstride),
values, e, md::mdspan(coeffs.data(), entities.extent(0), cstride),
Comment thread
jorgensd marked this conversation as resolved.
std::span<const T>(constants), mesh, entities, element);
}

Expand Down
Loading
Loading