Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
fd8cf04
fem: generalized jacobian measure using the area formula
Pawel024 Jan 15, 2026
3995dab
fem: completed base implementation of segments embedded in 2d
Pawel024 Jan 17, 2026
5ae76d1
fem: copy block_mass and block_grad_grad tests for embedded segments
Pawel024 Jan 20, 2026
e30e749
fem: copy tests from isoparametric_segment.cc for embedded segments
Pawel024 Jan 20, 2026
b943365
fem: add tests for gradient values and arc length to isoparametric_em…
Pawel024 Jan 20, 2026
d408726
fem: update block tests for embedded segments to use a diagonal segment
Pawel024 Jan 20, 2026
01741b6
fem: update paths to match fields redesign
Pawel024 Jan 23, 2026
4fe4832
fem: formatting edits
Pawel024 Jan 23, 2026
c1e17e2
tests/fem: formatting edits
Pawel024 Jan 23, 2026
b313d85
fem: replace hardcoded dimension values with the variable dim
Pawel024 Jan 23, 2026
2b9e098
fem: make base isoparametric segment class a template of the dimension
Pawel024 Jan 23, 2026
f3f3451
fem: update elements api to select the right simplex based on degree …
Pawel024 Jan 27, 2026
e81d32d
fem: expose volume form from manifold and pass it to the element classes
Pawel024 Jan 27, 2026
69a068c
fem: replace the jacobian_measure utility with element.volume_element
Pawel024 Jan 27, 2026
9ce302e
fem: update jacobian calculation in element classes to work for diffe…
Pawel024 Jan 27, 2026
e3210e7
tensor: add as_column_matrix factory, apply in IsoparametricSegmentP1…
Pawel024 Jan 27, 2026
7f96cf6
fem: use pyre::tensor::col and tensor::dyadic properly to avoid repet…
Pawel024 Jan 27, 2026
31c7e73
fem: contravariant gradient computation with the riemannian formula -…
Pawel024 Jan 27, 2026
4a08b11
tests/fem: adapt tests to work with the new elements API
Pawel024 Jan 27, 2026
e6d974a
fem: remove division by factorial in volume element computation, it's…
Pawel024 Jan 28, 2026
ff1f5c4
tests/fem: use a clockwise-rotated normal field to get positive volum…
Pawel024 Jan 28, 2026
4a1daa8
benchmarks: update the poisson benchmark to use the new elements api
Pawel024 Jan 28, 2026
65259dc
fem: update comments to use "n-simplex" instead of "nth order simplex…
Pawel024 Jan 28, 2026
fe3d6fc
Merge remote-tracking branch 'origin/main' into fem-1d-embedded-in-2d
Pawel024 Jan 29, 2026
0f27c1b
test/fem: test integration with volume form on arbitrary segments
Pawel024 Feb 5, 2026
3266552
Merge remote-tracking branch 'origin/main' into fem-1d-embedded-in-2d
Pawel024 Jul 16, 2026
90f52fd
operators: add gradient overload taking a metric field
Pawel024 Jul 19, 2026
f320b0f
fem: remove superseded {gradient.h}
Pawel024 Jul 19, 2026
cb810ae
tensor: remove {as_column_matrix}
Pawel024 Jul 19, 2026
5ec0ac7
fem/elements: generalize {finite_element_family} and discretizers ove…
Pawel024 Jul 19, 2026
96aec06
fem/elements: reimplement isoparametric elements on embedded manifolds
Pawel024 Jul 19, 2026
51df354
tests/fem: adapt embedded segment tests after the manifold redesign PR
Pawel024 Jul 19, 2026
1676150
tests/fem: add tests for embedded triangles equivalent to those for e…
Pawel024 Jul 20, 2026
1baca62
Update cmake-macos.yaml to check out pyre branch {main} instead of {t…
Pawel024 Jul 21, 2026
bc00e48
Update cmake-ubuntu.yaml to check out pyre branch {main} instead of {…
Pawel024 Jul 21, 2026
4a36359
tests/geometry: correction in comments
Pawel024 Jul 21, 2026
3a15afa
fem/blocks: remove unnecessarily added comment
Pawel024 Jul 21, 2026
7107e9a
tensor: remove accidentally added whiteline
Pawel024 Jul 21, 2026
a1a5065
tests/geometry: make a comment clearer
Pawel024 Jul 21, 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
7 changes: 7 additions & 0 deletions .cmake/mito_tests_mito_lib.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ mito_test_driver(tests/mito.lib/geometry/point.cc)
mito_test_driver(tests/mito.lib/geometry/euclidean_metric_1D.cc)
mito_test_driver(tests/mito.lib/geometry/euclidean_metric_2D.cc)
mito_test_driver(tests/mito.lib/geometry/euclidean_metric_3D.cc)
mito_test_driver(tests/mito.lib/geometry/euclidean_submanifold_metric_2D.cc)
mito_test_driver(tests/mito.lib/geometry/euclidean_submanifold_metric_3D.cc)
mito_test_driver(tests/mito.lib/geometry/induced_metric_segment.cc)
mito_test_driver(tests/mito.lib/geometry/induced_metric_triangle.cc)
Expand All @@ -56,15 +57,21 @@ mito_test_driver(tests/mito.lib/discrete/mesh_field.cc)
# fem
mito_test_driver(tests/mito.lib/fem/block_grad_grad.cc)
mito_test_driver(tests/mito.lib/fem/block_grad_grad_segment.cc)
mito_test_driver(tests/mito.lib/fem/block_grad_grad_embedded_segment.cc)
mito_test_driver(tests/mito.lib/fem/block_grad_grad_embedded_triangle.cc)
mito_test_driver(tests/mito.lib/fem/block_mass.cc)
mito_test_driver(tests/mito.lib/fem/block_mass_segment.cc)
mito_test_driver(tests/mito.lib/fem/block_mass_embedded_segment.cc)
mito_test_driver(tests/mito.lib/fem/block_mass_embedded_triangle.cc)
mito_test_driver(tests/mito.lib/fem/shape_functions_triangle_construction.cc)
mito_test_driver(tests/mito.lib/fem/shape_functions_triangle_p1.cc)
mito_test_driver(tests/mito.lib/fem/shape_functions_triangle_p2.cc)
mito_test_driver(tests/mito.lib/fem/isoparametric_triangle.cc)
mito_test_driver(tests/mito.lib/fem/fem_field.cc)
mito_test_driver(tests/mito.lib/fem/shape_functions_segment_p1.cc)
mito_test_driver(tests/mito.lib/fem/isoparametric_segment.cc)
mito_test_driver(tests/mito.lib/fem/isoparametric_embedded_segment.cc)
mito_test_driver(tests/mito.lib/fem/isoparametric_embedded_triangle.cc)

# io
mito_test_driver(tests/mito.lib/io/summit_mesh_reader_2D.cc)
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cmake-macos.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ jobs:
repository: pyre/pyre
fetch-depth: 0
path: ${{github.workspace}}/pyre
ref: tensor
ref: main

- name: retrieve pyre commit SHA
id: pyre-sha
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cmake-ubuntu.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ jobs:
repository: pyre/pyre
fetch-depth: 0
path: ${{github.workspace}}/pyre
ref: tensor
ref: main

- name: retrieve pyre commit SHA
id: pyre-sha
Expand Down
2 changes: 1 addition & 1 deletion lib/mito/fem/blocks/GradGradBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ namespace mito::fem::blocks {
constexpr auto w = measure * quadrature_rule.weight(q);

// precompute the common factor
auto factor = w * tensor::determinant(element.jacobian()(xi));
auto factor = w * element.volume_element()(xi);

// loop on the nodes of the element
tensor::constexpr_for_1<n_nodes>([&]<int a>() {
Expand Down
2 changes: 1 addition & 1 deletion lib/mito/fem/blocks/L2NormBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ namespace mito::fem::blocks {
constexpr auto w = measure * quadrature_rule.weight(q);

// precompute the common factor
auto factor = w * tensor::determinant(element.jacobian()(xi));
auto factor = w * element.volume_element()(xi);

// populate the elementary contribution to the matrix
norm += factor * _function(xi) * _function(xi);
Expand Down
2 changes: 1 addition & 1 deletion lib/mito/fem/blocks/MassBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ namespace mito::fem::blocks {
constexpr auto w = measure * quadrature_rule.weight(q);

// precompute the common factor
auto factor = w * tensor::determinant(element.jacobian()(xi));
auto factor = w * element.volume_element()(xi);

// loop on the nodes of the element
tensor::constexpr_for_1<n_nodes>([&]<int a>() {
Expand Down
2 changes: 1 addition & 1 deletion lib/mito/fem/blocks/SourceTermBlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ namespace mito::fem::blocks {
constexpr auto w = measure * quadrature_rule.weight(q);

// precompute the common factor
auto factor = w * tensor::determinant(element.jacobian()(xi));
auto factor = w * element.volume_element()(xi);

// loop on the nodes of the element
tensor::constexpr_for_1<n_nodes>([&]<int a>() {
Expand Down
7 changes: 4 additions & 3 deletions lib/mito/fem/elements/forward.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@ namespace mito::fem {
template <class elementT, discretization_t discretizationT>
struct Discretizer;

// struct storing the type of an isoparametric simplex of polynomial degree {degree} on a
// geometric simplex of type {geometricSimplexT}
template <int degree, geometry::geometric_simplex_c geometricSimplexT>
// struct storing the type of an isoparametric simplex of polynomial degree {degree}
// on a manifold of type {ManifoldT}
// the manifold type encapsulates the coordinate system, volume form, and cell type
template <int degree, class ManifoldT>
struct isoparametric_simplex;

// concept of {parametrizedElementT} being compatible with finite elements of type
Expand Down
8 changes: 4 additions & 4 deletions lib/mito/fem/elements/seg1/DiscretizerCG.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@

namespace mito::fem {

// discretizer specialization for a segment in 1D with order 1 continuous Galerkin
template <>
struct Discretizer<finite_element_family<geometry::segment_t<1>, 1>, discretization_t::CG> {
// discretizer specialization for a segment in D dimensions with order 1 continuous Galerkin
template <int D>
struct Discretizer<finite_element_family<geometry::segment_t<D>, 1>, discretization_t::CG> {
template <
typename manifoldT, typename constraintsT, typename connectivity_table_type,
typename map_type, typename constrained_nodes_type>
Expand All @@ -21,7 +21,7 @@ namespace mito::fem {
constrained_nodes_type & constrained_nodes)
{
// the finite element type
using finite_element_type = finite_element_family<geometry::segment_t<1>, 1>;
using finite_element_type = finite_element_family<geometry::segment_t<D>, 1>;

// the discretization node type
using discretization_node_type = typename finite_element_type::discretization_node_type;
Expand Down
58 changes: 38 additions & 20 deletions lib/mito/fem/elements/seg1/IsoparametricSegmentP1.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@


// DESIGN NOTES
// Class {IsoparametricSegmentP1} represents a first order simplex (segment) living in 1D cartesian
// space, equipped with linear shape functions defined in the parametric space.
// Class {IsoparametricSegmentP1} represents a 1-simplex (segment) embedded in a D-dimensional
// physical space, equipped with linear shape functions defined in the parametric space.


namespace mito::fem {
Expand All @@ -22,6 +22,14 @@ namespace mito::fem {
using parametrized_element_type = parametrizedElementT;
// the underlying mesh cell type
using mesh_cell_type = typename parametrized_element_type::cell_type;
// the metric volume form type
using metric_volume_form_type = typename parametrized_element_type::metric_volume_form_type;
// the coordinates type of the physical space
using coordinates_type = typename metric_volume_form_type::input_type;
// the dimension of the physical space
static constexpr int dim = coordinates_type::dim;
// the (euclidean) metric of the physical space in {coordinates_type} coordinates
using ambient_metric_type = geometry::euclidean_metric<coordinates_type>;

// the degree of the finite element
static constexpr int degree = 1;
Expand Down Expand Up @@ -99,43 +107,53 @@ namespace mito::fem {
{
// assemble the jacobian as a function of parametric coordinates
auto jacobian_function = functions::function(
[&](const parametric_coordinates_type & xi) -> tensor::matrix_t<1> {
[&](const parametric_coordinates_type & xi) -> tensor::matrix_t<dim, 1> {
// get the shape functions derivatives
constexpr auto dphi_0 = shape_functions.dshape<0>();
constexpr auto dphi_1 = shape_functions.dshape<1>();

// store the coordinates of the vertices of the triangle in physical space
// store the coordinates of the vertices of the segment in physical space
auto x0 = _element.parametrization()({ 0.0 });
auto x1 = _element.parametrization()({ 1.0 });

// compute the jacobian of the isoparametric mapping: dx/dxi
auto dx_dxi = x0 * dphi_0(xi) + x1 * dphi_1(xi);
// wrap the result in a 1x1 matrix
return tensor::matrix_t<1>{ dx_dxi };
return tensor::dyadic(x0, dphi_0(xi)) + tensor::dyadic(x1, dphi_1(xi));
});

// and return it
return jacobian_function;
}

// get the volume element of the isoparametric mapping, i.e. the metric volume form
// contracted with the tangent vector of the element
constexpr auto volume_element() const
{
// assemble the volume element as a function of parametric coordinates
auto volume_element_function = functions::function(
[&](const parametric_coordinates_type & xi) -> tensor::scalar_t {
// the metric volume form at the physical location of {xi}
auto w = _element.metric_volume_form()(_element.parametrization())(xi);
// the tangent vector to the element at {xi}
auto tangent = tensor::column<0>(jacobian()(xi));
// contract the metric volume form with the tangent vector
return w(tangent);
});
// and return it
return volume_element_function;
}
Comment thread
Pawel024 marked this conversation as resolved.

// get the gradient of the a-th shape function as a function of parametric coordinates
template <int a>
requires(a >= 0 && a < n_nodes)
constexpr auto gradient() const
{
// assemble the gradient as a function of parametric coordinates
auto gradient_function = functions::function(
[&](const parametric_coordinates_type & xi) -> tensor::vector_t<1> {
// the jacobian of the mapping from the reference element to the physical
// element evaluated at {xi}
auto J = jacobian()(xi);
// the derivative of the coordinates with respect to the parametric coordinates
auto J_inv = tensor::inverse(J);
// return the spatial gradients of the shape functions evaluated at {xi}
return shape_functions.dshape<a>()(xi) * J_inv;
});
// and return it
return gradient_function;
// the pullback of the ambient metric along the element parametrization
auto g =
geometry::pullback_metric<ambient_metric_type>::field(_element.parametrization());
// the intrinsic gradient of the a-th shape function on the parametric space
auto dphi = operators::gradient(shape_functions.shape<a>(), g);
// push the gradient forward to the physical space with the jacobian
return jacobian() * dphi;
}

private:
Expand Down
6 changes: 3 additions & 3 deletions lib/mito/fem/elements/seg1/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,11 @@
namespace mito::fem {

// specialization of {finite_element_family} for first order segments
template <>
struct finite_element_family<geometry::segment_t<1>, 1> {
template <int D>
struct finite_element_family<geometry::segment_t<D>, 1> {

// the dimension of the physical space
static constexpr int dim = 1;
static constexpr int dim = D;
// the underlying mesh cell type
using mesh_cell_type = geometry::segment_t<dim>;
// the degree of the finite element
Expand Down
6 changes: 3 additions & 3 deletions lib/mito/fem/elements/tri1/DiscretizerCG.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
namespace mito::fem {

// discretizer specialization for {IsoparametricTriangleP1} with continuous Galerkin
template <>
struct Discretizer<finite_element_family<geometry::triangle_t<2>, 1>, discretization_t::CG> {
template <int D>
struct Discretizer<finite_element_family<geometry::triangle_t<D>, 1>, discretization_t::CG> {
template <
typename manifoldT, typename constraintsT, typename connectivity_table_type,
typename map_type, typename constrained_nodes_type>
Expand All @@ -21,7 +21,7 @@ namespace mito::fem {
constrained_nodes_type & constrained_nodes)
{
// the finite element type
using finite_element_type = finite_element_family<geometry::triangle_t<2>, 1>;
using finite_element_type = finite_element_family<geometry::triangle_t<D>, 1>;

// the discretization node type
using discretization_node_type = typename finite_element_type::discretization_node_type;
Expand Down
53 changes: 36 additions & 17 deletions lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@


// DESIGN NOTES
// Class {IsoparametricTriangleP1} represents a second order simplex (triangle) living in 2D
// cartesian space, equipped with linear shape functions defined in the parametric space.
// Class {IsoparametricTriangleP1} represents a 2-simplex (triangle) embedded in a D-dimensional
// physical space, equipped with linear shape functions defined in the parametric space.


namespace mito::fem {
Expand All @@ -22,6 +22,14 @@ namespace mito::fem {
using parametrized_element_type = parametrizedElementT;
// the underlying mesh cell type
using mesh_cell_type = typename parametrized_element_type::cell_type;
// the metric volume form type
using metric_volume_form_type = typename parametrized_element_type::metric_volume_form_type;
// the coordinates type of the physical space
using coordinates_type = typename metric_volume_form_type::input_type;
// the dimension of the physical space
static constexpr int dim = coordinates_type::dim;
// the (euclidean) metric of the physical space in {coordinates_type} coordinates
using ambient_metric_type = geometry::euclidean_metric<coordinates_type>;

// the degree of the finite element
static constexpr int degree = 1;
Expand Down Expand Up @@ -99,7 +107,7 @@ namespace mito::fem {
{
// assemble the jacobian as a function of parametric coordinates
auto jacobian_function = functions::function(
[&](const parametric_coordinates_type & xi) -> tensor::matrix_t<2> {
[&](const parametric_coordinates_type & xi) -> tensor::matrix_t<dim, 2> {
// get the shape functions derivatives
constexpr auto dphi_0 = shape_functions.dshape<0>();
constexpr auto dphi_1 = shape_functions.dshape<1>();
Expand All @@ -120,25 +128,36 @@ namespace mito::fem {
return jacobian_function;
}

// get the volume element of the isoparametric mapping, i.e. the metric volume form
// contracted with the tangent vectors of the element
constexpr auto volume_element() const
{
// assemble the volume element as a function of parametric coordinates
auto volume_element_function = functions::function(
[&](const parametric_coordinates_type & xi) -> tensor::scalar_t {
// the metric volume form at the physical location of {xi}
auto w = _element.metric_volume_form()(_element.parametrization())(xi);
// the tangent vectors to the element at {xi}
auto J = jacobian()(xi);
// contract the metric volume form with the tangent vectors
return w(tensor::column<0>(J), tensor::column<1>(J));
});
// and return it
return volume_element_function;
}
Comment thread
Pawel024 marked this conversation as resolved.

// get the gradient of the a-th shape function as a function of parametric coordinates
template <int a>
requires(a >= 0 && a < n_nodes)
constexpr auto gradient() const
{
// assemble the gradient as a function of parametric coordinates
auto gradient_function = functions::function(
[&](const parametric_coordinates_type & xi) -> tensor::vector_t<2> {
// the jacobian of the mapping from the reference element to the physical
// element evaluated at {xi}
auto J = jacobian()(xi);
// the derivative of the coordinates with respect to the parametric coordinates
auto J_inv = tensor::inverse(J);
// return the spatial gradients of the shape functions evaluated at {xi}
return shape_functions.dshape<a>()(xi) * J_inv;
});

// and return it
return gradient_function;
// the pullback of the ambient metric along the element parametrization
auto g =
geometry::pullback_metric<ambient_metric_type>::field(_element.parametrization());
// the intrinsic gradient of the a-th shape function on the parametric space
auto dphi = operators::gradient(shape_functions.shape<a>(), g);
// push the gradient forward to the physical space with the jacobian
return jacobian() * dphi;
}

private:
Expand Down
7 changes: 4 additions & 3 deletions lib/mito/fem/elements/tri1/api.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@

namespace mito::fem {

template <>
struct finite_element_family<geometry::triangle_t<2>, 1> {
// specialization of {finite_element_family} for first order triangles
template <int D>
struct finite_element_family<geometry::triangle_t<D>, 1> {

// the dimension of the physical space
static constexpr int dim = 2;
static constexpr int dim = D;
// the underlying mesh cell type
using mesh_cell_type = geometry::triangle_t<dim>;
// the degree of the finite element
Expand Down
6 changes: 3 additions & 3 deletions lib/mito/fem/elements/tri2/DiscretizerCG.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
namespace mito::fem {

// discretizer specialization for {IsoparametricTriangleP2} with continuous Galerkin
template <>
struct Discretizer<finite_element_family<geometry::triangle_t<2>, 2>, discretization_t::CG> {
template <int D>
struct Discretizer<finite_element_family<geometry::triangle_t<D>, 2>, discretization_t::CG> {
template <
typename manifoldT, typename constraintsT, typename connectivity_table_type,
typename map_type, typename constrained_nodes_type>
Expand All @@ -21,7 +21,7 @@ namespace mito::fem {
constrained_nodes_type & constrained_nodes)
{
// the finite element type
using finite_element_type = finite_element_family<geometry::triangle_t<2>, 2>;
using finite_element_type = finite_element_family<geometry::triangle_t<D>, 2>;

// assemble the mesh node type
using mesh_node_type = typename manifoldT::mesh_type::node_type;
Expand Down
Loading
Loading