From f27d4861ff597990b570c3f3171be3d705f1b1d0 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 4 Mar 2025 16:31:37 +0100 Subject: [PATCH 001/273] tests/mito.lib/discretization: add test for the Poisson equation on the unit square --- .cmake/mito_tests_mito_lib.cmake | 1 + tests/mito.lib/discretization/poisson.cc | 349 +++++++++++++++++++++++ 2 files changed, 350 insertions(+) create mode 100644 tests/mito.lib/discretization/poisson.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index b3a8b9a84..516538323 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -38,6 +38,7 @@ mito_test_driver(tests/mito.lib/geometry/spherical_metric_space.cc) # discretization mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) mito_test_driver(tests/mito.lib/discretization/nodal_field.cc) +mito_test_driver(tests/mito.lib/discretization/poisson.cc) # io mito_test_driver(tests/mito.lib/io/summit_mesh_reader_2D.cc) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc new file mode 100644 index 000000000..abfdd5c8e --- /dev/null +++ b/tests/mito.lib/discretization/poisson.cc @@ -0,0 +1,349 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; +// the type of cell +using cell_t = mito::geometry::triangle_t<2>; +// the type of node +using node_t = cell_t::node_type; +// the type of simplex +using simplex_t = cell_t::simplex_type; +// Gauss quadrature on triangles with degree of exactness 1 +using quadrature_rule_t = + mito::quadrature::quadrature_rule_t; +// TOFIX: the correct dimension of the parametric space +// // the dimension of the parametric space +// static constexpr int parametricDim = mito::manifolds::parametric_dim(); +// // the type of parametric coordinates +// using parametric_point_t = mito::manifolds::parametric_point_t; +// the type of parametric coordinates +using parametric_point_t = mito::manifolds::parametric_point_t<2>; + +// the function extracting the x component of a 2D vector +constexpr auto x = mito::functions::component; +// the function extracting the y component of a 2D vector +constexpr auto y = mito::functions::component; + +TEST(Fem, PoissonSquare) +{ + // make a channel + journal::info_t channel("tests.poisson_square"); + + // the coordinate system + auto coord_system = mito::geometry::coordinate_system(); + + // read the mesh of a square in 2D + std::ifstream fileStream("square.summit"); + auto mesh = mito::io::summit::reader(fileStream, coord_system); + + // // TOFIX: tetra does not work with the current implementation + // // do one tetra mesh refinement + // const auto subdivisions = 1; + // auto mesh = mito::mesh::tetra(original_mesh, coord_system, subdivisions); + +#if 0 + // TOFIX: this does not work as the nodes are copied into new nodes to construct the boundary + // cells, therefore the set difference is not aware of the node equality. Therefore we need to + // back up to the spatial search implementation + + // get all the nodes in the mesh + std::set nodes; + mito::mesh::get_nodes(mesh, nodes); + channel << "Number of total cells: " << std::size(mesh.cells()) << journal::endl; + channel << "Number of total nodes: " << std::size(nodes) << journal::endl; + for (const auto & node : nodes) { + // print the coordinates of the node + channel << coord_system.coordinates(node->point()) << journal::endl; + } + + // get all the nodes on the mesh boundary + auto boundary_mesh = mito::mesh::boundary(mesh); + std::set boundary_nodes; + mito::mesh::get_nodes(boundary_mesh, boundary_nodes); + channel << "Number of boundary cells: " << std::size(boundary_mesh.cells()) << journal::endl; + channel << "Number of boundary nodes: " << std::size(boundary_nodes) << journal::endl; + for (const auto & node : boundary_nodes) { + // node.vertex() + // print the coordinates of the node + channel << coord_system.coordinates(node->point()) << journal::endl; + } + + // get all the interior nodes as the difference between all the nodes and the boundary nodes + std::set interior_nodes; + std::set_difference( + nodes.begin(), nodes.end(), boundary_nodes.begin(), boundary_nodes.end(), + std::inserter(interior_nodes, interior_nodes.begin())); + channel << "Number of interior nodes: " << std::size(interior_nodes) << journal::endl; + + // populate the equation map (from node to equation, one equations per node) + std::map equation_map; + int equation = 0; + + // loop on all the nodes of the cell + for (const auto & node : interior_nodes) { + // check if the node is already in the equation map + if (equation_map.find(node) == equation_map.end()) { + // add the node to the equation map + equation_map[node] = equation; + // increment the equation number + equation++; + } + } +#else + std::set nodes; + mito::mesh::get_nodes(mesh, nodes); + + // populate the equation map (from node to equation, one equations per node) + std::map equation_map; + int equation = 0; + + // loop on all the nodes of the cell + for (const auto & node : nodes) { + // get the coordinates of the node + auto coord = coord_system.coordinates(node->point()); + // if the node is on the boundary + if (coord[0] == 0.0 || coord[0] == 1.0 || coord[1] == 0.0 || coord[1] == 1.0) { + // check if the node is already in the equation map + if (equation_map.find(node) == equation_map.end()) { + // add the node to the equation map with a -1 indicating that the node is on the + // boundary + equation_map[node] = -1; + } + } + + // check if the node is already in the equation map + if (equation_map.find(node) == equation_map.end()) { + // add the node to the equation map + equation_map[node] = equation; + // increment the equation number + equation++; + } + } + + // the number of equations + int N_equations = equation; +#endif + channel << "Number of equations: " << equation << journal::endl; + + // create a linear system of equations (PETSc Krylov solver) + auto solver = mito::solvers::petsc::ksp("mysolver"); + solver.initialize(N_equations); + solver.set_options("-ksp_monitor -ksp_converged_reason"); + + // create the body manifold + auto manifold = mito::manifolds::manifold(mesh, coord_system); + + // instantiate the quadrature rule + constexpr auto quadrature_rule = quadrature_rule_t(); + static_assert(quadrature_rule_t::npoints == 1); + + // the {area} of the mesh + auto area = 0.0; + + // the right hand side + auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) + * mito::functions::sin(std::numbers::pi * y); + // channel << "Right hand side: " << f(coordinates_t{ 0.5, 0.5 }) << journal::endl; + + // loop on all the cells of the mesh + for (const auto & cell : manifold.elements()) { + + // QUESTION: does this work? + // auto nodes = cell.nodes(); + // the nodes of the cell + const auto & nodes = cell.nodes(); + + // the origin of the coordinate system + auto origin = coordinates_t{}; + + // the coordinates of the nodes of the triangle + auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; + auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; + auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; + + // linear shape functions on the triangle + constexpr auto phi_1 = mito::functions::component; + constexpr auto phi_2 = mito::functions::component; + constexpr auto phi_0 = 1.0 - phi_1 - phi_2; + + // the isoparametric mapping from the barycentric coordinates to the actual coordinates + // on the cell {cell} + auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; + + // the only quadrature point of the quadrature rule + constexpr auto xi = + parametric_point_t{ quadrature_rule.point(0)[0], quadrature_rule.point(0)[1] }; + + // report (print the barycenter of the mesh cell) + // channel << x_cell(xi) << journal::endl; + + // the derivative of the coordinates with respect to the barycentric coordinates + auto J = mito::tensor::matrix_t<2>(); + J[{ 0, 0 }] = mito::functions::derivative<0>(x_cell)(xi)[0]; + J[{ 1, 0 }] = mito::functions::derivative<0>(x_cell)(xi)[1]; + J[{ 0, 1 }] = mito::functions::derivative<1>(x_cell)(xi)[0]; + J[{ 1, 1 }] = mito::functions::derivative<1>(x_cell)(xi)[1]; + + // TODO: make this syntax work and return a matrix function + // J = mito::functions::derivative(x_cell); + + // add up the area of the cell + area += 1.0 / 2.0 * mito::tensor::determinant(J); + + // TODO: make this syntax work: + // J[{ 0, 0 }] = mito::functions::derivative<0>(x_cell)[0]; + // J(xi); + + // the derivative of the shape functions with respect to the parametric coordinates + auto dphi_xi = mito::tensor::matrix_t<3, 2>(); + dphi_xi[{ 0, 0 }] = mito::functions::derivative<0>(phi_0)(xi); + dphi_xi[{ 0, 1 }] = mito::functions::derivative<1>(phi_0)(xi); + dphi_xi[{ 1, 0 }] = mito::functions::derivative<0>(phi_1)(xi); + dphi_xi[{ 1, 1 }] = mito::functions::derivative<1>(phi_1)(xi); + dphi_xi[{ 2, 0 }] = mito::functions::derivative<0>(phi_2)(xi); + dphi_xi[{ 2, 1 }] = mito::functions::derivative<1>(phi_2)(xi); + + // the derivative of the shape functions with respect to the physical coordinates + auto dphi = dphi_xi * mito::tensor::inverse(J); + + auto factor = quadrature_rule.weight(0) * manifold.volume(cell); + + // populate the linear system of equations + int a = 0; + for (const auto & node_a : nodes) { + int b = 0; + // get the equation number of {node_a} + int eq_a = equation_map.at(node_a); + assert(eq_a < N_equations); + if (eq_a == -1) { + // skip boundary nodes + continue; + } + for (const auto & node_b : nodes) { + // get the equation number of {node_b} + int eq_b = equation_map.at(node_b); + assert(eq_b < N_equations); + if (eq_b == -1) { + // skip boundary nodes + continue; + } + auto entry = + factor * (dphi[{ a, 0 }] * dphi[{ b, 0 }] + dphi[{ a, 1 }] * dphi[{ b, 1 }]); + + solver.add_matrix_value(eq_a, eq_b, entry); + + ++b; + } + ++a; + } + + auto coord = manifold.parametrization(cell, quadrature_rule.point(0)); + int eq = equation_map.at(nodes[0]); + if (eq != -1) { + solver.add_rhs_value(eq, factor * f(coord) * phi_0(xi)); + } + eq = equation_map.at(nodes[1]); + if (eq != -1) { + solver.add_rhs_value(eq, factor * f(coord) * phi_1(xi)); + } + eq = equation_map.at(nodes[2]); + if (eq != -1) { + solver.add_rhs_value(eq, factor * f(coord) * phi_2(xi)); + } + + // report (print gradients of the shape functions) + // channel << dphi << journal::endl; + } + + // check that the area of the unit square is 1.0 + EXPECT_DOUBLE_EQ(1.0, area); + + solver.solve(); + + // read the solution + auto u = std::vector(N_equations); + solver.get_solution(u); + + // the numerical solution nodal field on the mesh + auto solution = + mito::discretization::nodal_field>(mesh, "numerical solution"); + // fill information in nodal field + for (auto & [node, value] : solution) { + // get the equation number of {node} + int eq = equation_map.at(node); + if (eq != -1) { + // read the solution at {eq} + value[0] = u[eq]; + } + } + + // the forcing term nodal field on the mesh + auto forcing = + mito::discretization::nodal_field>(mesh, "forcing term"); + // fill information in nodal field + for (auto & [node, value] : forcing) { + // get the position of {node} + auto coord = coord_system.coordinates(node->point()); + // evaluate the forcing at {coord} + value[0] = f(coord); + } + + // the exact solution nodal field on the mesh + auto exact_solution = + mito::discretization::nodal_field>(mesh, "exact solution"); + auto u_ex = + mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y); + // fill information in nodal field + for (auto & [node, value] : exact_solution) { + // get the position of {node} + auto coord = coord_system.coordinates(node->point()); + // evaluate the forcing at {coord} + value[0] = u_ex(coord); + } + +#ifdef WITH_VTK + // write mesh to vtk file + auto writer = mito::io::vtk::field_writer("poisson_square", mesh, coord_system); + // sign {forcing} up with the writer + writer.record(forcing); + // sign {solution} up with the writer + writer.record(solution); + // sign {exact_solution} up with the writer + writer.record(exact_solution); + // write output file + writer.write(); +#endif + + // compute the error + auto error = 0.0; + // loop on all the nodes of the cell + for (const auto & node : nodes) { + // get the exact solution at {coord} + auto u_exact = exact_solution(node)[0]; + // get the numerical solution at {coord} + auto u_numerical = solution(node)[0]; + // get the error + error += (u_exact - u_numerical) * (u_exact - u_numerical); + } + error = std::sqrt(error); + + // report + channel << "l2 error: " << error << journal::endl; + + // check that the l2 error is reasonable + EXPECT_TRUE(error < 0.1); + + // TODO: add norm calculation for convergence study + + // finalize the solver + solver.finalize(); +} + +// end of file From f277cc35898c1e4329596aa1e9d2095f3c710e27 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 08:02:13 +0100 Subject: [PATCH 002/273] discretization: add const iterators to class {DiscreteField} --- lib/mito/discretization/DiscreteField.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/mito/discretization/DiscreteField.h b/lib/mito/discretization/DiscreteField.h index 77431396a..f2f5287a7 100644 --- a/lib/mito/discretization/DiscreteField.h +++ b/lib/mito/discretization/DiscreteField.h @@ -89,6 +89,8 @@ namespace mito::discretization { inline auto end() const { return std::cend(_map_entry_to_values); } inline auto begin() { return std::begin(_map_entry_to_values); } inline auto end() { return std::end(_map_entry_to_values); } + inline auto cbegin() const { return std::cbegin(_map_entry_to_values); } + inline auto cend() const { return std::cend(_map_entry_to_values); } private: // the underlying mapping of entries to nodal values From d9006d7d26b294ddc93282ec3f1f076d0392b336 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 08:02:47 +0100 Subject: [PATCH 003/273] discretization: readability improvement Add {value_type} type alias. --- lib/mito/discretization/DiscreteField.h | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/lib/mito/discretization/DiscreteField.h b/lib/mito/discretization/DiscreteField.h index f2f5287a7..19286d27c 100644 --- a/lib/mito/discretization/DiscreteField.h +++ b/lib/mito/discretization/DiscreteField.h @@ -9,15 +9,18 @@ namespace mito::discretization { - template + template class DiscreteField { private: // the key type using key_type = keyT; + // the value type + using value_type = valueT; - // a map from {key_type} to {Y} values - using map_type = std::unordered_map>; + // a map from {key_type} to {value_type} values + using map_type = + std::unordered_map>; public: // constructor @@ -52,7 +55,7 @@ namespace mito::discretization { /** * accessor for the value of a given entry */ - inline auto operator()(const key_type & key) const -> const Y & + inline auto operator()(const key_type & key) const -> const value_type & { return _map_entry_to_values.at(key); } @@ -60,12 +63,15 @@ namespace mito::discretization { /** * mutator for the value of a given entry */ - inline auto operator()(const key_type & key) -> Y & { return _map_entry_to_values.at(key); } + inline auto operator()(const key_type & key) -> value_type & + { + return _map_entry_to_values.at(key); + } /** * insert a new entry to the field */ - inline auto insert(const key_type & key, const Y & entry = Y()) -> void + inline auto insert(const key_type & key, const value_type & entry = value_type()) -> void { // add a new entry to the field _map_entry_to_values[key] = entry; From fb2aaa3cfb5e6581368097a29c1a68c04a976233 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 10:31:27 +0100 Subject: [PATCH 004/273] tests/mito.lib/discretization: reorder shape functions --- tests/mito.lib/discretization/poisson.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index abfdd5c8e..5e2478a92 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -169,9 +169,9 @@ TEST(Fem, PoissonSquare) auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; // linear shape functions on the triangle - constexpr auto phi_1 = mito::functions::component; - constexpr auto phi_2 = mito::functions::component; - constexpr auto phi_0 = 1.0 - phi_1 - phi_2; + constexpr auto phi_0 = mito::functions::component; + constexpr auto phi_1 = mito::functions::component; + constexpr auto phi_2 = 1.0 - phi_0 - phi_1; // the isoparametric mapping from the barycentric coordinates to the actual coordinates // on the cell {cell} From 376dc76915b98ac2f11c4ead4d675bc853de614d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 12:25:54 +0100 Subject: [PATCH 005/273] fields/differential: add {gradient} operator for vector fields and {divergence} operator for (2nd order) tensor fields --- .cmake/mito_tests_mito_lib.cmake | 1 + lib/mito/fields/differential.h | 60 ++++++++++++++++ .../mito.lib/fields/calculus_scalar_field.cc | 2 +- .../mito.lib/fields/calculus_vector_field.cc | 70 +++++++++++++++++++ 4 files changed, 132 insertions(+), 1 deletion(-) create mode 100644 tests/mito.lib/fields/calculus_vector_field.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 516538323..b15986c10 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -80,6 +80,7 @@ mito_test_driver(tests/mito.lib/tensor/tensor_product_forms.cc) mito_test_driver(tests/mito.lib/fields/fields.cc) mito_test_driver(tests/mito.lib/fields/fields_traits.cc) mito_test_driver(tests/mito.lib/fields/calculus_scalar_field.cc) +mito_test_driver(tests/mito.lib/fields/calculus_vector_field.cc) mito_test_driver(tests/mito.lib/fields/polar_metric_field.cc) mito_test_driver(tests/mito.lib/fields/spherical_metric_field.cc) diff --git a/lib/mito/fields/differential.h b/lib/mito/fields/differential.h index 92788518d..d122352b3 100644 --- a/lib/mito/fields/differential.h +++ b/lib/mito/fields/differential.h @@ -36,6 +36,35 @@ namespace mito::fields { return _grad(field, std::make_index_sequence{}); } + // function to compute the gradient of a vector field + template + constexpr auto gradient(const F & field) + { + // the type of coordinate + using coordinate_t = F::coordinates_type; + // the spatial dimension of the field + constexpr int D = coordinate_t::dim; + + // helper function to compute the gradient of a scalar + constexpr auto _grad = [](const F & field, std::index_sequence) { + constexpr auto _grad_with_respect_to = []( + const F & field, std::index_sequence) { + // the tensor of the partial derivatives + // (\partial field_I / \partial x_K ) * e_IK + return ( + (derivative(field * uniform_field(tensor::e)) + * uniform_field(tensor::unit, I, K>)) + + ...); + }; + + return ( + (_grad_with_respect_to.template operator()(field, std::make_index_sequence{})) + + ...); + }; + + return _grad(field, std::make_index_sequence{}); + } + // function to compute the divergence of a vector field template constexpr auto divergence(const F & field) @@ -54,6 +83,37 @@ namespace mito::fields { // all done return _div(field, std::make_index_sequence{}); } + + // function to compute the divergence of a tensor field + template + constexpr auto divergence(const F & field) + { + // the type of coordinate + using coordinate_t = F::coordinates_type; + // the spatial dimension of the field + constexpr int D = coordinate_t::dim; + + // helper function to compute the gradient of a scalar + constexpr auto _div = [](const F & field, std::index_sequence) { + constexpr auto _div_with_respect_to = []( + const F & field, std::index_sequence) { + // the vector of the partial derivatives + // (\partial field_KI / \partial x_I) * e_K + return ( + (derivative( + (field * uniform_field(tensor::e)) + * uniform_field(tensor::e)) + * uniform_field(tensor::e)) + + ...); + }; + + return ( + (_div_with_respect_to.template operator()(field, std::make_index_sequence{})) + + ...); + }; + + return _div(field, std::make_index_sequence{}); + } } diff --git a/tests/mito.lib/fields/calculus_scalar_field.cc b/tests/mito.lib/fields/calculus_scalar_field.cc index ee416c81d..bd49d1852 100644 --- a/tests/mito.lib/fields/calculus_scalar_field.cc +++ b/tests/mito.lib/fields/calculus_scalar_field.cc @@ -19,7 +19,7 @@ static constexpr auto e_1 = mito::tensor::e_1<2>; constexpr auto pi_sixth = std::numbers::pi / 6.0; -TEST(Fields, Gradient) +TEST(Laplacian, ScalarFields) { // the sine function constexpr auto sin = mito::functions::sin; diff --git a/tests/mito.lib/fields/calculus_vector_field.cc b/tests/mito.lib/fields/calculus_vector_field.cc new file mode 100644 index 000000000..a31ec88c9 --- /dev/null +++ b/tests/mito.lib/fields/calculus_vector_field.cc @@ -0,0 +1,70 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; + + +// the basis for vectors in 2D +static constexpr auto e_0 = mito::tensor::e_0<2>; +static constexpr auto e_1 = mito::tensor::e_1<2>; + +// the basis for tensors in 2D +static constexpr auto e_00 = mito::tensor::e_00<2>; +static constexpr auto e_01 = mito::tensor::e_01<2>; +static constexpr auto e_10 = mito::tensor::e_10<2>; +static constexpr auto e_11 = mito::tensor::e_11<2>; + +// pi sixth +constexpr auto pi_sixth = std::numbers::pi / 6.0; +// pi fourth +constexpr auto pi_fourth = std::numbers::pi / 4.0; + + +TEST(Laplacian, VectorFields) +{ + // the field returning the constant {e_0} unit vector in 2D + constexpr auto e0 = mito::fields::uniform_field(e_0); + + // the field returning the constant {e_1} unit vector in 2D + constexpr auto e1 = mito::fields::uniform_field(e_1); + + // the sine function + constexpr auto sin = mito::functions::sin; + + // the cosine function + constexpr auto cos = mito::functions::cos; + + // the function extracting the x_0 component of a 2D vector + constexpr auto x0 = mito::functions::component; + + // the function extracting the x_1 component of a 2D vector + constexpr auto x1 = mito::functions::component; + + // a vector field + constexpr auto g = sin(x0 * x1) * e0 + cos(x0 * x1) * e1; + + // a point in space + constexpr auto x = mito::geometry::coordinates({ pi_sixth, pi_fourth }); + + // the gradient of {g} + constexpr auto gradient = mito::fields::gradient(g); + + // check result + static_assert( + gradient(x) + == (cos(x0 * x1) * x1 * e_00 + cos(x0 * x1) * x0 * e_01 - sin(x0 * x1) * x1 * e_10 + - sin(x0 * x1) * x0 * e_11)(x)); + + // the laplacian (divergence of gradient) + constexpr auto laplacian = mito::fields::divergence(gradient); + + // check result + static_assert(laplacian(x) == (-(x0 * x0 + x1 * x1) * g)(x)); +} From b8b558332a3bc921a7b382de44b689e883b62475 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 12:26:11 +0100 Subject: [PATCH 006/273] tests: fix typo in comment --- tests/mito.lib/integration/divergence_theorem.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mito.lib/integration/divergence_theorem.cc b/tests/mito.lib/integration/divergence_theorem.cc index 460fe3be5..36d3cb105 100644 --- a/tests/mito.lib/integration/divergence_theorem.cc +++ b/tests/mito.lib/integration/divergence_theorem.cc @@ -28,7 +28,7 @@ TEST(DivergenceTheorem, Mesh2D) // make a channel journal::info_t channel("tests.divergence_theorem"); - // a scalar field + // a vector field constexpr auto f = x0 * x1 * e0 + x0 * x0 * e1; // build a scalar field with divergence of field From 7ebb9807955ca1a0b6cf670bb88f956bd5e7d8b1 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 14:05:23 +0100 Subject: [PATCH 007/273] tests/mito.lib/discretization: increased abstraction level using gradients of vector fields instead of simple partial derivatives --- tests/mito.lib/discretization/poisson.cc | 52 +++++++++--------------- 1 file changed, 20 insertions(+), 32 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 5e2478a92..4d3fe17f3 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -31,6 +31,11 @@ constexpr auto x = mito::functions::component; // the function extracting the y component of a 2D vector constexpr auto y = mito::functions::component; +// the function extracting the 0 component of a parametric point +constexpr auto xi_0 = mito::functions::component; +// the function extracting the y component of a 2D vector +constexpr auto xi_1 = mito::functions::component; + TEST(Fem, PoissonSquare) { // make a channel @@ -169,49 +174,33 @@ TEST(Fem, PoissonSquare) auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; // linear shape functions on the triangle - constexpr auto phi_0 = mito::functions::component; - constexpr auto phi_1 = mito::functions::component; + constexpr auto phi_0 = mito::fields::field(xi_0); + constexpr auto phi_1 = mito::fields::field(xi_1); constexpr auto phi_2 = 1.0 - phi_0 - phi_1; // the isoparametric mapping from the barycentric coordinates to the actual coordinates // on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; - // the only quadrature point of the quadrature rule + // the derivative of the coordinates with respect to the barycentric coordinates + auto J = mito::fields::gradient(x_cell); + + // the barycentric coordinates of the only quadrature point of the quadrature rule constexpr auto xi = - parametric_point_t{ quadrature_rule.point(0)[0], quadrature_rule.point(0)[1] }; + coordinates_t{ quadrature_rule.point(0)[0], quadrature_rule.point(0)[1] }; // report (print the barycenter of the mesh cell) // channel << x_cell(xi) << journal::endl; - // the derivative of the coordinates with respect to the barycentric coordinates - auto J = mito::tensor::matrix_t<2>(); - J[{ 0, 0 }] = mito::functions::derivative<0>(x_cell)(xi)[0]; - J[{ 1, 0 }] = mito::functions::derivative<0>(x_cell)(xi)[1]; - J[{ 0, 1 }] = mito::functions::derivative<1>(x_cell)(xi)[0]; - J[{ 1, 1 }] = mito::functions::derivative<1>(x_cell)(xi)[1]; - - // TODO: make this syntax work and return a matrix function - // J = mito::functions::derivative(x_cell); - // add up the area of the cell - area += 1.0 / 2.0 * mito::tensor::determinant(J); - - // TODO: make this syntax work: - // J[{ 0, 0 }] = mito::functions::derivative<0>(x_cell)[0]; - // J(xi); - - // the derivative of the shape functions with respect to the parametric coordinates - auto dphi_xi = mito::tensor::matrix_t<3, 2>(); - dphi_xi[{ 0, 0 }] = mito::functions::derivative<0>(phi_0)(xi); - dphi_xi[{ 0, 1 }] = mito::functions::derivative<1>(phi_0)(xi); - dphi_xi[{ 1, 0 }] = mito::functions::derivative<0>(phi_1)(xi); - dphi_xi[{ 1, 1 }] = mito::functions::derivative<1>(phi_1)(xi); - dphi_xi[{ 2, 0 }] = mito::functions::derivative<0>(phi_2)(xi); - dphi_xi[{ 2, 1 }] = mito::functions::derivative<1>(phi_2)(xi); + area += 1.0 / 2.0 * mito::tensor::determinant(J(xi)); - // the derivative of the shape functions with respect to the physical coordinates - auto dphi = dphi_xi * mito::tensor::inverse(J); + // compute the gradients of the shape functions with respect to the actual coordinates + using vector_type = mito::tensor::vector_t<2>; + std::array dphi; + dphi[0] = mito::fields::gradient(phi_0)(xi) * mito::tensor::inverse(J(xi)); + dphi[1] = mito::fields::gradient(phi_1)(xi) * mito::tensor::inverse(J(xi)); + dphi[2] = mito::fields::gradient(phi_2)(xi) * mito::tensor::inverse(J(xi)); auto factor = quadrature_rule.weight(0) * manifold.volume(cell); @@ -234,8 +223,7 @@ TEST(Fem, PoissonSquare) // skip boundary nodes continue; } - auto entry = - factor * (dphi[{ a, 0 }] * dphi[{ b, 0 }] + dphi[{ a, 1 }] * dphi[{ b, 1 }]); + auto entry = factor * (dphi[a] * dphi[b]); solver.add_matrix_value(eq_a, eq_b, entry); From 95c604ad4fb82afc4ed1d538d73639ce934356a4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 14:20:43 +0100 Subject: [PATCH 008/273] tests/mito.lib/discretization: remove question It does work! --- tests/mito.lib/discretization/poisson.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 4d3fe17f3..06f4cd5c8 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -160,8 +160,6 @@ TEST(Fem, PoissonSquare) // loop on all the cells of the mesh for (const auto & cell : manifold.elements()) { - // QUESTION: does this work? - // auto nodes = cell.nodes(); // the nodes of the cell const auto & nodes = cell.nodes(); From 0d3a24db5bc203cbeb4cfed288aee75883c20209 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 14:21:28 +0100 Subject: [PATCH 009/273] tests/mito.lib/discretization: improve conciseness --- tests/mito.lib/discretization/poisson.cc | 32 +++++++++++------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 06f4cd5c8..cdaca35ff 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -193,7 +193,14 @@ TEST(Fem, PoissonSquare) // add up the area of the cell area += 1.0 / 2.0 * mito::tensor::determinant(J(xi)); - // compute the gradients of the shape functions with respect to the actual coordinates + // evaluate the shape functions at {xi} + using scalar_type = mito::tensor::scalar_t; + std::array phi; + phi[0] = phi_0(xi); + phi[1] = phi_1(xi); + phi[2] = phi_2(xi); + + // evaluate the gradients of the shape functions at {xi} using vector_type = mito::tensor::vector_t<2>; std::array dphi; dphi[0] = mito::fields::gradient(phi_0)(xi) * mito::tensor::inverse(J(xi)); @@ -202,6 +209,9 @@ TEST(Fem, PoissonSquare) auto factor = quadrature_rule.weight(0) * manifold.volume(cell); + // the coordinates of the quadrature point + auto coord = manifold.parametrization(cell, quadrature_rule.point(0)); + // populate the linear system of equations int a = 0; for (const auto & node_a : nodes) { @@ -227,25 +237,11 @@ TEST(Fem, PoissonSquare) ++b; } - ++a; - } - auto coord = manifold.parametrization(cell, quadrature_rule.point(0)); - int eq = equation_map.at(nodes[0]); - if (eq != -1) { - solver.add_rhs_value(eq, factor * f(coord) * phi_0(xi)); - } - eq = equation_map.at(nodes[1]); - if (eq != -1) { - solver.add_rhs_value(eq, factor * f(coord) * phi_1(xi)); - } - eq = equation_map.at(nodes[2]); - if (eq != -1) { - solver.add_rhs_value(eq, factor * f(coord) * phi_2(xi)); - } + solver.add_rhs_value(eq_a, factor * f(coord) * phi[a]); - // report (print gradients of the shape functions) - // channel << dphi << journal::endl; + ++a; + } } // check that the area of the unit square is 1.0 From 2f5583ca0e1dae479ffbe08a9aa764187310c445 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 14:22:23 +0100 Subject: [PATCH 010/273] tests/mito.lib/discretization: remove unused {area} calculation --- tests/mito.lib/discretization/poisson.cc | 9 --------- 1 file changed, 9 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index cdaca35ff..9e54e9dfd 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -149,9 +149,6 @@ TEST(Fem, PoissonSquare) constexpr auto quadrature_rule = quadrature_rule_t(); static_assert(quadrature_rule_t::npoints == 1); - // the {area} of the mesh - auto area = 0.0; - // the right hand side auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y); @@ -190,9 +187,6 @@ TEST(Fem, PoissonSquare) // report (print the barycenter of the mesh cell) // channel << x_cell(xi) << journal::endl; - // add up the area of the cell - area += 1.0 / 2.0 * mito::tensor::determinant(J(xi)); - // evaluate the shape functions at {xi} using scalar_type = mito::tensor::scalar_t; std::array phi; @@ -244,9 +238,6 @@ TEST(Fem, PoissonSquare) } } - // check that the area of the unit square is 1.0 - EXPECT_DOUBLE_EQ(1.0, area); - solver.solve(); // read the solution From ddd71719de14a65ffe6767b4c09cbbcea1f96fd3 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 14:35:28 +0100 Subject: [PATCH 011/273] tests/mito.lib/discretization: mark {constexpr} those quantities known at compile time --- tests/mito.lib/discretization/poisson.cc | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 9e54e9dfd..3654b434b 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -177,9 +177,6 @@ TEST(Fem, PoissonSquare) // on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; - // the derivative of the coordinates with respect to the barycentric coordinates - auto J = mito::fields::gradient(x_cell); - // the barycentric coordinates of the only quadrature point of the quadrature rule constexpr auto xi = coordinates_t{ quadrature_rule.point(0)[0], quadrature_rule.point(0)[1] }; @@ -189,18 +186,18 @@ TEST(Fem, PoissonSquare) // evaluate the shape functions at {xi} using scalar_type = mito::tensor::scalar_t; - std::array phi; - phi[0] = phi_0(xi); - phi[1] = phi_1(xi); - phi[2] = phi_2(xi); + constexpr auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; // evaluate the gradients of the shape functions at {xi} using vector_type = mito::tensor::vector_t<2>; - std::array dphi; - dphi[0] = mito::fields::gradient(phi_0)(xi) * mito::tensor::inverse(J(xi)); - dphi[1] = mito::fields::gradient(phi_1)(xi) * mito::tensor::inverse(J(xi)); - dphi[2] = mito::fields::gradient(phi_2)(xi) * mito::tensor::inverse(J(xi)); + constexpr auto dphi = std::array{ mito::fields::gradient(phi_0)(xi), + mito::fields::gradient(phi_1)(xi), + mito::fields::gradient(phi_2)(xi) }; + + // the derivative of the coordinates with respect to the barycentric coordinates + auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi)); + // precompute the common factor auto factor = quadrature_rule.weight(0) * manifold.volume(cell); // the coordinates of the quadrature point @@ -225,7 +222,7 @@ TEST(Fem, PoissonSquare) // skip boundary nodes continue; } - auto entry = factor * (dphi[a] * dphi[b]); + auto entry = factor * (dphi[a] * J_inv) * (dphi[b] * J_inv); solver.add_matrix_value(eq_a, eq_b, entry); From ea4e146d3e8f9b25edd7ba37b55e2553d7163995 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 14:36:15 +0100 Subject: [PATCH 012/273] tests/mito.lib/discretization: remove unused {typedef}s --- tests/mito.lib/discretization/poisson.cc | 7 ------- 1 file changed, 7 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 3654b434b..096167be5 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -18,13 +18,6 @@ using simplex_t = cell_t::simplex_type; // Gauss quadrature on triangles with degree of exactness 1 using quadrature_rule_t = mito::quadrature::quadrature_rule_t; -// TOFIX: the correct dimension of the parametric space -// // the dimension of the parametric space -// static constexpr int parametricDim = mito::manifolds::parametric_dim(); -// // the type of parametric coordinates -// using parametric_point_t = mito::manifolds::parametric_point_t; -// the type of parametric coordinates -using parametric_point_t = mito::manifolds::parametric_point_t<2>; // the function extracting the x component of a 2D vector constexpr auto x = mito::functions::component; From bf34792c04b7a31446cda044832ab1adde5ae3a7 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 15:37:07 +0100 Subject: [PATCH 013/273] vtk: {vtk} writers can now write scalar fields --- lib/mito/io/vtk/FieldVTKWriter.h | 62 ++++++++++++++++++++++---------- 1 file changed, 43 insertions(+), 19 deletions(-) diff --git a/lib/mito/io/vtk/FieldVTKWriter.h b/lib/mito/io/vtk/FieldVTKWriter.h index 002b3a28c..fdd3f6ed2 100644 --- a/lib/mito/io/vtk/FieldVTKWriter.h +++ b/lib/mito/io/vtk/FieldVTKWriter.h @@ -9,23 +9,47 @@ namespace mito::io::vtk { - // the type of the grid writer depending on the type of grid and on the coordinate system - template - struct field_type; - - // specialization to {mesh_c} case - template - struct field_type { - template - using type = discretization::nodal_field_t; - }; + namespace { + // the type of the grid writer depending on the type of grid and on the coordinate system + template + struct field_type; + + // specialization to {mesh_c} case + template + struct field_type { + template + using type = discretization::nodal_field_t; + }; + + // specialization to {point_cloud_c} case + template + struct field_type { + template + using type = discretization::point_field_t; + }; + + // utility function to get the data pointer + template + constexpr auto dim() -> int + { + if constexpr (std::is_arithmetic_v) { + return 1; + } else { + return Y::size; + } + } - // specialization to {point_cloud_c} case - template - struct field_type { - template - using type = discretization::point_field_t; - }; + // utility function to get the data pointer + template + auto begin(Y & value) + { + if constexpr (std::is_arithmetic_v) { + return &value; + } else { + return std::begin(value); + } + } + } template class FieldVTKWriter { @@ -65,7 +89,7 @@ namespace mito::io::vtk { // initialize a vtk array auto vtkArray = vtkSmartPointer::New(); vtkArray->SetName(fieldname.data()); - vtkArray->SetNumberOfComponents(Y::size); + vtkArray->SetNumberOfComponents(dim()); vtkArray->SetNumberOfTuples(field_size); // populate the array @@ -76,7 +100,7 @@ namespace mito::io::vtk { // populate the array with the nodal values for (const auto & [node, index] : nodes) { // get the index corresponding to the current node - vtkArray->SetTuple(index, field(node).begin()); + vtkArray->SetTuple(index, begin(field(node))); } } else if constexpr (geometry::point_cloud_c) { // get the points in the grid @@ -86,7 +110,7 @@ namespace mito::io::vtk { int index = 0; for (const auto & point : points) { // get the index corresponding to the current point - vtkArray->SetTuple(index++, field(point).begin()); + vtkArray->SetTuple(index++, begin(field(point))); } } From 123fe3940a227b6ba82213db6348f31045c1ff51 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 15:42:10 +0100 Subject: [PATCH 014/273] tests/mito.lib/discretization: readability improvements --- tests/mito.lib/discretization/poisson.cc | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 096167be5..39ffb89e5 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -7,6 +7,10 @@ #include +// the scalar type +using scalar_t = mito::tensor::scalar_t; +// the vector type +using vector_t = mito::tensor::vector_t<2>; // the type of coordinates using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; // the type of cell @@ -178,14 +182,12 @@ TEST(Fem, PoissonSquare) // channel << x_cell(xi) << journal::endl; // evaluate the shape functions at {xi} - using scalar_type = mito::tensor::scalar_t; - constexpr auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; + constexpr auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; // evaluate the gradients of the shape functions at {xi} - using vector_type = mito::tensor::vector_t<2>; - constexpr auto dphi = std::array{ mito::fields::gradient(phi_0)(xi), - mito::fields::gradient(phi_1)(xi), - mito::fields::gradient(phi_2)(xi) }; + constexpr auto dphi = std::array{ mito::fields::gradient(phi_0)(xi), + mito::fields::gradient(phi_1)(xi), + mito::fields::gradient(phi_2)(xi) }; // the derivative of the coordinates with respect to the barycentric coordinates auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi)); From 2b6417e4e063ec857ff9ac3cc95a73c938d7a325 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 15:42:57 +0100 Subject: [PATCH 015/273] tests/mito.lib/discretization: no longer need to pretend with {vtk} that scalars are 1D vectors --- tests/mito.lib/discretization/poisson.cc | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 39ffb89e5..35a1f0f2e 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -237,32 +237,29 @@ TEST(Fem, PoissonSquare) solver.get_solution(u); // the numerical solution nodal field on the mesh - auto solution = - mito::discretization::nodal_field>(mesh, "numerical solution"); + auto solution = mito::discretization::nodal_field(mesh, "numerical solution"); // fill information in nodal field for (auto & [node, value] : solution) { // get the equation number of {node} int eq = equation_map.at(node); if (eq != -1) { // read the solution at {eq} - value[0] = u[eq]; + value = u[eq]; } } // the forcing term nodal field on the mesh - auto forcing = - mito::discretization::nodal_field>(mesh, "forcing term"); + auto forcing = mito::discretization::nodal_field(mesh, "forcing term"); // fill information in nodal field for (auto & [node, value] : forcing) { // get the position of {node} auto coord = coord_system.coordinates(node->point()); // evaluate the forcing at {coord} - value[0] = f(coord); + value = f(coord); } // the exact solution nodal field on the mesh - auto exact_solution = - mito::discretization::nodal_field>(mesh, "exact solution"); + auto exact_solution = mito::discretization::nodal_field(mesh, "exact solution"); auto u_ex = mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y); // fill information in nodal field @@ -270,7 +267,7 @@ TEST(Fem, PoissonSquare) // get the position of {node} auto coord = coord_system.coordinates(node->point()); // evaluate the forcing at {coord} - value[0] = u_ex(coord); + value = u_ex(coord); } #ifdef WITH_VTK @@ -291,9 +288,9 @@ TEST(Fem, PoissonSquare) // loop on all the nodes of the cell for (const auto & node : nodes) { // get the exact solution at {coord} - auto u_exact = exact_solution(node)[0]; + auto u_exact = exact_solution(node); // get the numerical solution at {coord} - auto u_numerical = solution(node)[0]; + auto u_numerical = solution(node); // get the error error += (u_exact - u_numerical) * (u_exact - u_numerical); } From 908567d96b65598adb7fda1773090f88f850a38d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 16:12:49 +0100 Subject: [PATCH 016/273] tests/mito.lib/discretization: generalization to a quadrature rule with more than one point --- tests/mito.lib/discretization/poisson.cc | 82 ++++++++++++------------ 1 file changed, 41 insertions(+), 41 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 35a1f0f2e..d8f9ceab7 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -144,7 +144,6 @@ TEST(Fem, PoissonSquare) // instantiate the quadrature rule constexpr auto quadrature_rule = quadrature_rule_t(); - static_assert(quadrature_rule_t::npoints == 1); // the right hand side auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) @@ -174,59 +173,60 @@ TEST(Fem, PoissonSquare) // on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; - // the barycentric coordinates of the only quadrature point of the quadrature rule - constexpr auto xi = - coordinates_t{ quadrature_rule.point(0)[0], quadrature_rule.point(0)[1] }; + // loop on the quadrature points + for (int q = 0; q < quadrature_rule_t::npoints; ++q) { - // report (print the barycenter of the mesh cell) - // channel << x_cell(xi) << journal::endl; + // the barycentric coordinates of the quadrature point + /*constexpr*/ auto xi = + coordinates_t{ quadrature_rule.point(q)[0], quadrature_rule.point(q)[1] }; - // evaluate the shape functions at {xi} - constexpr auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; + // evaluate the shape functions at {xi} + /*constexpr*/ auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; - // evaluate the gradients of the shape functions at {xi} - constexpr auto dphi = std::array{ mito::fields::gradient(phi_0)(xi), - mito::fields::gradient(phi_1)(xi), - mito::fields::gradient(phi_2)(xi) }; + // evaluate the gradients of the shape functions at {xi} + /*constexpr*/ auto dphi = std::array{ mito::fields::gradient(phi_0)(xi), + mito::fields::gradient(phi_1)(xi), + mito::fields::gradient(phi_2)(xi) }; - // the derivative of the coordinates with respect to the barycentric coordinates - auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi)); + // the derivative of the coordinates with respect to the barycentric coordinates + auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi)); - // precompute the common factor - auto factor = quadrature_rule.weight(0) * manifold.volume(cell); + // precompute the common factor + auto factor = quadrature_rule.weight(q) * manifold.volume(cell); - // the coordinates of the quadrature point - auto coord = manifold.parametrization(cell, quadrature_rule.point(0)); + // the coordinates of the quadrature point + auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); - // populate the linear system of equations - int a = 0; - for (const auto & node_a : nodes) { - int b = 0; - // get the equation number of {node_a} - int eq_a = equation_map.at(node_a); - assert(eq_a < N_equations); - if (eq_a == -1) { - // skip boundary nodes - continue; - } - for (const auto & node_b : nodes) { - // get the equation number of {node_b} - int eq_b = equation_map.at(node_b); - assert(eq_b < N_equations); - if (eq_b == -1) { + // populate the linear system of equations + int a = 0; + for (const auto & node_a : nodes) { + int b = 0; + // get the equation number of {node_a} + int eq_a = equation_map.at(node_a); + assert(eq_a < N_equations); + if (eq_a == -1) { // skip boundary nodes continue; } - auto entry = factor * (dphi[a] * J_inv) * (dphi[b] * J_inv); + for (const auto & node_b : nodes) { + // get the equation number of {node_b} + int eq_b = equation_map.at(node_b); + assert(eq_b < N_equations); + if (eq_b == -1) { + // skip boundary nodes + continue; + } + auto entry = factor * (dphi[a] * J_inv) * (dphi[b] * J_inv); + + solver.add_matrix_value(eq_a, eq_b, entry); + + ++b; + } - solver.add_matrix_value(eq_a, eq_b, entry); + solver.add_rhs_value(eq_a, factor * f(coord) * phi[a]); - ++b; + ++a; } - - solver.add_rhs_value(eq_a, factor * f(coord) * phi[a]); - - ++a; } } From 05ea543c61850e6844b775bfc93f54d49a922881 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 16:19:26 +0100 Subject: [PATCH 017/273] tests/mito.lib/discretization: move solver finalization as early as possible --- tests/mito.lib/discretization/poisson.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index d8f9ceab7..bab379023 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -236,6 +236,9 @@ TEST(Fem, PoissonSquare) auto u = std::vector(N_equations); solver.get_solution(u); + // finalize the solver + solver.finalize(); + // the numerical solution nodal field on the mesh auto solution = mito::discretization::nodal_field(mesh, "numerical solution"); // fill information in nodal field @@ -303,9 +306,6 @@ TEST(Fem, PoissonSquare) EXPECT_TRUE(error < 0.1); // TODO: add norm calculation for convergence study - - // finalize the solver - solver.finalize(); } // end of file From c24e6037075636b9462c7629a3f8abbe1aa663dd Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 16:20:56 +0100 Subject: [PATCH 018/273] tests/mito.lib/discretization: shape functions and quadrature rule can be factored out of main --- tests/mito.lib/discretization/poisson.cc | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index bab379023..e4b9ee442 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -23,6 +23,10 @@ using simplex_t = cell_t::simplex_type; using quadrature_rule_t = mito::quadrature::quadrature_rule_t; + +// instantiate the quadrature rule +constexpr auto quadrature_rule = quadrature_rule_t(); + // the function extracting the x component of a 2D vector constexpr auto x = mito::functions::component; // the function extracting the y component of a 2D vector @@ -32,6 +36,11 @@ constexpr auto y = mito::functions::component; constexpr auto xi_0 = mito::functions::component; // the function extracting the y component of a 2D vector constexpr auto xi_1 = mito::functions::component; +// linear shape functions on the triangle +constexpr auto phi_0 = mito::fields::field(xi_0); +constexpr auto phi_1 = mito::fields::field(xi_1); +constexpr auto phi_2 = 1.0 - phi_0 - phi_1; + TEST(Fem, PoissonSquare) { @@ -142,9 +151,6 @@ TEST(Fem, PoissonSquare) // create the body manifold auto manifold = mito::manifolds::manifold(mesh, coord_system); - // instantiate the quadrature rule - constexpr auto quadrature_rule = quadrature_rule_t(); - // the right hand side auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y); @@ -164,11 +170,6 @@ TEST(Fem, PoissonSquare) auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; - // linear shape functions on the triangle - constexpr auto phi_0 = mito::fields::field(xi_0); - constexpr auto phi_1 = mito::fields::field(xi_1); - constexpr auto phi_2 = 1.0 - phi_0 - phi_1; - // the isoparametric mapping from the barycentric coordinates to the actual coordinates // on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; From d0773a5c0391c0883c073094ff72e05d66106129 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Mar 2025 17:49:14 +0100 Subject: [PATCH 019/273] tests/mito.lib/discretization: add calculation of error in L2 norm --- tests/mito.lib/discretization/poisson.cc | 46 +++++++++++++++++------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index e4b9ee442..ca0b352b8 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -21,7 +21,7 @@ using node_t = cell_t::node_type; using simplex_t = cell_t::simplex_type; // Gauss quadrature on triangles with degree of exactness 1 using quadrature_rule_t = - mito::quadrature::quadrature_rule_t; + mito::quadrature::quadrature_rule_t; // instantiate the quadrature rule @@ -288,23 +288,43 @@ TEST(Fem, PoissonSquare) #endif // compute the error - auto error = 0.0; - // loop on all the nodes of the cell - for (const auto & node : nodes) { - // get the exact solution at {coord} - auto u_exact = exact_solution(node); - // get the numerical solution at {coord} - auto u_numerical = solution(node); - // get the error - error += (u_exact - u_numerical) * (u_exact - u_numerical); + auto error_L2 = 0.0; + // loop on all the cells of the mesh + for (const auto & cell : manifold.elements()) { + // volume of the cell + auto volume = manifold.volume(cell); + // loop on the quadrature points + for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + // the barycentric coordinates of the quadrature point + /*constexpr*/ auto xi = + coordinates_t{ quadrature_rule.point(q)[0], quadrature_rule.point(q)[1] }; + // evaluate the shape functions at {xi} + /*constexpr*/ auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; + // the coordinates of the quadrature point + auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); + // get the exact solution at {coord} + auto u_exact = u_ex(coord); + // assemble the numerical solution at {coord} + auto u_numerical = 0.0; + int a = 0; + // loop on all the nodes of the cell + for (const auto & node : cell.nodes()) { + // get the numerical solution at {coord} + u_numerical += solution(node) * phi[a]; + ++a; + } + // get the error + error_L2 += (u_exact - u_numerical) * (u_exact - u_numerical) + * quadrature_rule.weight(q) * volume; + } } - error = std::sqrt(error); + error_L2 = std::sqrt(error_L2); // report - channel << "l2 error: " << error << journal::endl; + channel << "L2 error: " << error_L2 << journal::endl; // check that the l2 error is reasonable - EXPECT_TRUE(error < 0.1); + EXPECT_TRUE(error_L2 < 0.02); // TODO: add norm calculation for convergence study } From 8fbb0d0065315c43d141783a184cf8eecc31d1a6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Mar 2025 09:00:07 +0100 Subject: [PATCH 020/273] =?UTF-8?q?functions=20and=20fields:=20add=20deriv?= =?UTF-8?q?ation=20rule=C2=A0for=20the=20transpose=20of=20functions=20and?= =?UTF-8?q?=20fields?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .cmake/mito_tests_mito_lib.cmake | 1 + lib/mito/fields/fields_algebra.h | 7 +++ lib/mito/functions/algebra.h | 6 ++ lib/mito/functions/derivation_rules.h | 8 +++ lib/mito/functions/function.h | 37 ++++++++++++ lib/mito/functions/traits.h | 12 ++++ tests/mito.lib/fields/calculus_identities.cc | 59 ++++++++++++++++++++ 7 files changed, 130 insertions(+) create mode 100644 tests/mito.lib/fields/calculus_identities.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index b15986c10..e0ea66c44 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -79,6 +79,7 @@ mito_test_driver(tests/mito.lib/tensor/tensor_product_forms.cc) # fields mito_test_driver(tests/mito.lib/fields/fields.cc) mito_test_driver(tests/mito.lib/fields/fields_traits.cc) +mito_test_driver(tests/mito.lib/fields/calculus_identities.cc) mito_test_driver(tests/mito.lib/fields/calculus_scalar_field.cc) mito_test_driver(tests/mito.lib/fields/calculus_vector_field.cc) mito_test_driver(tests/mito.lib/fields/polar_metric_field.cc) diff --git a/lib/mito/fields/fields_algebra.h b/lib/mito/fields/fields_algebra.h index 282f95718..b9c1dece7 100644 --- a/lib/mito/fields/fields_algebra.h +++ b/lib/mito/fields/fields_algebra.h @@ -29,6 +29,13 @@ namespace mito::fields { })); } + // f transpose + template + constexpr auto transpose(const F & f) + { + return field(functions::transpose(f.function())); + } + // sqrt(f) template constexpr auto sqrt(const F & f) diff --git a/lib/mito/functions/algebra.h b/lib/mito/functions/algebra.h index e4da29a64..29a063f4d 100644 --- a/lib/mito/functions/algebra.h +++ b/lib/mito/functions/algebra.h @@ -90,6 +90,12 @@ namespace mito::functions { { return f1 * Reciprocal(f2); } + + // f transposed + constexpr auto transpose(const function_c auto & f) + { + return Transpose(f); + } } diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index 46cbb9a4a..514b03abe 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -60,6 +60,14 @@ namespace mito::functions { { return derivative(f.f1())(f.f2()) * derivative(f.f2()); } + + // the derivative of the transpose of a function + template + constexpr auto derivative(const Transpose & f) + { + // the derivative of the transpose is the transpose of the derivative + return functions::transpose(derivative(f.f())); + } } diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 982d28df5..e238da09c 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -356,6 +356,43 @@ namespace mito::functions { const F _f; const G _g; }; + + // function transposing a function of a second order tensor + template + requires(tensor::matrix_c) + class Transpose : public function_transpose::type { + + public: + // the transpose function type + using transpose_type = function_transpose::type; + // the input type + using input_type = transpose_type::input_type; + // the output type + using output_type = transpose_type::output_type; + + public: + // constructor + constexpr Transpose(const F & f) : _f(f) {} + + // call operator for function composition + template + constexpr auto operator()(const H & f) const + { + return Composition(*this, f); + } + + // call operator + constexpr auto operator()(const input_type & x) const -> output_type + { + return tensor::transpose(_f(x)); + } + + // the function to transpose + constexpr auto f() const -> const F & { return _f; } + + private: + const F _f; + }; } diff --git a/lib/mito/functions/traits.h b/lib/mito/functions/traits.h index be8243f02..236c3feac 100644 --- a/lib/mito/functions/traits.h +++ b/lib/mito/functions/traits.h @@ -45,6 +45,18 @@ namespace mito::functions { using type = Function; }; + // the type of the transpose of a function... + template + // with matrix values... + requires(tensor::matrix_c) + struct function_transpose { + // ... is the function that takes {input_type} in input and returns the type of the + // transposed of the output matrix type + using type = Function< + typename F::input_type, + typename tensor::traits::transpose::type>; + }; + // the type of function for a function of class {F} template using function_type = Function; diff --git a/tests/mito.lib/fields/calculus_identities.cc b/tests/mito.lib/fields/calculus_identities.cc new file mode 100644 index 000000000..ba7458e20 --- /dev/null +++ b/tests/mito.lib/fields/calculus_identities.cc @@ -0,0 +1,59 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; + + +// the basis for vectors in 2D +static constexpr auto e_0 = mito::tensor::e_0<2>; +static constexpr auto e_1 = mito::tensor::e_1<2>; + +// pi sixth +constexpr auto pi_sixth = std::numbers::pi / 6.0; +// pi fourth +constexpr auto pi_fourth = std::numbers::pi / 4.0; + + +TEST(Identities, DivGrad) +{ + // the field returning the constant {e_0} unit vector in 2D + constexpr auto e0 = mito::fields::uniform_field(e_0); + + // the field returning the constant {e_1} unit vector in 2D + constexpr auto e1 = mito::fields::uniform_field(e_1); + + // the sine function + constexpr auto sin = mito::functions::sin; + + // the cosine function + constexpr auto cos = mito::functions::cos; + + // the function extracting the x_0 component of a 2D vector + constexpr auto x0 = mito::functions::component; + + // the function extracting the x_1 component of a 2D vector + constexpr auto x1 = mito::functions::component; + + // a vector field + constexpr auto f = sin(x0 * x1) * e0 + cos(x0 * x1) * e1; + + // a point in space + constexpr auto x = mito::geometry::coordinates({ pi_sixth, pi_fourth }); + + // the divergence of the gradient transposed of {f} + constexpr auto div_grad_T = + mito::fields::divergence(mito::fields::transpose(mito::fields::gradient(f))); + + // the gradient of the divergence of {f} + constexpr auto grad_div = mito::fields::gradient(mito::fields::divergence(f)); + + // check result + static_assert(div_grad_T(x) == grad_div(x)); +} From 5ee5025cbd828b0eaaf9f745c20b8f0cf3fe1a73 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Mar 2025 09:15:14 +0100 Subject: [PATCH 021/273] fields: generalize gradient of vector-valued fields to the case that input dimension and output dimension are different --- .cmake/mito_tests_mito_lib.cmake | 1 + lib/mito/fields/differential.h | 10 +-- tests/mito.lib/fields/gradient_non_square.cc | 75 ++++++++++++++++++++ 3 files changed, 82 insertions(+), 4 deletions(-) create mode 100644 tests/mito.lib/fields/gradient_non_square.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index e0ea66c44..b84497c6f 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -82,6 +82,7 @@ mito_test_driver(tests/mito.lib/fields/fields_traits.cc) mito_test_driver(tests/mito.lib/fields/calculus_identities.cc) mito_test_driver(tests/mito.lib/fields/calculus_scalar_field.cc) mito_test_driver(tests/mito.lib/fields/calculus_vector_field.cc) +mito_test_driver(tests/mito.lib/fields/gradient_non_square.cc) mito_test_driver(tests/mito.lib/fields/polar_metric_field.cc) mito_test_driver(tests/mito.lib/fields/spherical_metric_field.cc) diff --git a/lib/mito/fields/differential.h b/lib/mito/fields/differential.h index d122352b3..e18646475 100644 --- a/lib/mito/fields/differential.h +++ b/lib/mito/fields/differential.h @@ -44,21 +44,23 @@ namespace mito::fields { using coordinate_t = F::coordinates_type; // the spatial dimension of the field constexpr int D = coordinate_t::dim; + // the number of components of the vector field + constexpr int N = F::output_type::size; // helper function to compute the gradient of a scalar constexpr auto _grad = [](const F & field, std::index_sequence) { constexpr auto _grad_with_respect_to = []( const F & field, std::index_sequence) { // the tensor of the partial derivatives - // (\partial field_I / \partial x_K ) * e_IK + // (\partial field_I / \partial x_K ) * e_IK, I = 0, ..., N-1, K = 0, ..., D-1 return ( - (derivative(field * uniform_field(tensor::e)) - * uniform_field(tensor::unit, I, K>)) + (derivative(field * uniform_field(tensor::e)) + * uniform_field(tensor::unit, I, K>)) + ...); }; return ( - (_grad_with_respect_to.template operator()(field, std::make_index_sequence{})) + (_grad_with_respect_to.template operator()(field, std::make_index_sequence{})) + ...); }; diff --git a/tests/mito.lib/fields/gradient_non_square.cc b/tests/mito.lib/fields/gradient_non_square.cc new file mode 100644 index 000000000..8cabe2471 --- /dev/null +++ b/tests/mito.lib/fields/gradient_non_square.cc @@ -0,0 +1,75 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<3, mito::geometry::CARTESIAN>; + + +// the basis for vectors in 2D +static constexpr auto e_0 = mito::tensor::e_0<2>; +static constexpr auto e_1 = mito::tensor::e_1<2>; + +// the basis for 2x3 tensors +static constexpr auto e_00 = mito::tensor::unit, 0, 0>; +static constexpr auto e_01 = mito::tensor::unit, 0, 1>; +static constexpr auto e_02 = mito::tensor::unit, 0, 2>; +static constexpr auto e_10 = mito::tensor::unit, 1, 0>; +static constexpr auto e_11 = mito::tensor::unit, 1, 1>; +static constexpr auto e_12 = mito::tensor::unit, 1, 2>; + +// pi sixth +constexpr auto pi_sixth = std::numbers::pi / 6.0; +// pi fourth +constexpr auto pi_fourth = std::numbers::pi / 4.0; + + +TEST(Gradient, NonSquare) +{ + // the field returning the constant {e_0} unit vector in 2D + constexpr auto e0 = mito::fields::uniform_field(e_0); + + // the field returning the constant {e_1} unit vector in 2D + constexpr auto e1 = mito::fields::uniform_field(e_1); + + // the sine function + constexpr auto sin = mito::functions::sin; + + // the cosine function + constexpr auto cos = mito::functions::cos; + + // the function extracting the x_0 component of {coordinates_t} + constexpr auto x0 = mito::functions::component; + + // the function extracting the x_1 component of {coordinates_t} + constexpr auto x1 = mito::functions::component; + + // the function extracting the x_1 component of {coordinates_t} + constexpr auto x2 = mito::functions::component; + + // a vector field + constexpr auto f = (sin(x0 * x1) + x2) * e0 + (cos(x0 * x1) - x2) * e1; + + // a point in space + constexpr auto x = mito::geometry::coordinates({ pi_sixth, pi_fourth, 1.0 }); + + // the gradient of {f} + constexpr auto gradient = mito::fields::gradient(f); + + // create a channel + journal::info_t channel("tests.gradient_non_square"); + + // report on the gradient at {x} + channel << "Gradient at x = " << x << " is " << gradient(x) << journal::endl; + + // check result + static_assert( + gradient(x) + == (cos(x0 * x1) * x1 * e_00 + cos(x0 * x1) * x0 * e_01 - sin(x0 * x1) * x1 * e_10 + - sin(x0 * x1) * x0 * e_11 + e_02 - e_12)(x)); +} From 0018a6d79699430303a4767c576700d1ae9820d1 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Mar 2025 09:20:17 +0100 Subject: [PATCH 022/273] tensor: generalize unit matrices in the api to the nonsquare case --- lib/mito/tensor/api.h | 54 ++++++++++---------- tests/mito.lib/fields/gradient_non_square.cc | 12 ++--- 2 files changed, 33 insertions(+), 33 deletions(-) diff --git a/lib/mito/tensor/api.h b/lib/mito/tensor/api.h index b5822d00f..45c1e602b 100644 --- a/lib/mito/tensor/api.h +++ b/lib/mito/tensor/api.h @@ -42,41 +42,41 @@ namespace mito::tensor { template constexpr auto e_2 = e<2, D>; - template - requires(D > 0) - constexpr auto e_00 = unit, 0, 0>; + template + requires(D1 > 0 && D2 > 0) + constexpr auto e_00 = unit, 0, 0>; - template - requires(D > 1) - constexpr auto e_01 = unit, 0, 1>; + template + requires(D1 > 0 && D2 > 1) + constexpr auto e_01 = unit, 0, 1>; - template - requires(D > 1) - constexpr auto e_10 = unit, 1, 0>; + template + requires(D1 > 1 && D2 > 0) + constexpr auto e_10 = unit, 1, 0>; - template - requires(D > 1) - constexpr auto e_11 = unit, 1, 1>; + template + requires(D1 > 1 && D2 > 1) + constexpr auto e_11 = unit, 1, 1>; - template - requires(D > 2) - constexpr auto e_02 = unit, 0, 2>; + template + requires(D1 > 0 && D2 > 2) + constexpr auto e_02 = unit, 0, 2>; - template - requires(D > 2) - constexpr auto e_20 = unit, 2, 0>; + template + requires(D1 > 2 && D2 > 0) + constexpr auto e_20 = unit, 2, 0>; - template - requires(D > 2) - constexpr auto e_12 = unit, 1, 2>; + template + requires(D1 > 1 && D2 > 2) + constexpr auto e_12 = unit, 1, 2>; - template - requires(D > 2) - constexpr auto e_21 = unit, 2, 1>; + template + requires(D1 > 2 && D2 > 1) + constexpr auto e_21 = unit, 2, 1>; - template - requires(D > 2) - constexpr auto e_22 = unit, 2, 2>; + template + requires(D1 > 2 && D2 > 2) + constexpr auto e_22 = unit, 2, 2>; template requires(D > 0) diff --git a/tests/mito.lib/fields/gradient_non_square.cc b/tests/mito.lib/fields/gradient_non_square.cc index 8cabe2471..ef37f2845 100644 --- a/tests/mito.lib/fields/gradient_non_square.cc +++ b/tests/mito.lib/fields/gradient_non_square.cc @@ -16,12 +16,12 @@ static constexpr auto e_0 = mito::tensor::e_0<2>; static constexpr auto e_1 = mito::tensor::e_1<2>; // the basis for 2x3 tensors -static constexpr auto e_00 = mito::tensor::unit, 0, 0>; -static constexpr auto e_01 = mito::tensor::unit, 0, 1>; -static constexpr auto e_02 = mito::tensor::unit, 0, 2>; -static constexpr auto e_10 = mito::tensor::unit, 1, 0>; -static constexpr auto e_11 = mito::tensor::unit, 1, 1>; -static constexpr auto e_12 = mito::tensor::unit, 1, 2>; +static constexpr auto e_00 = mito::tensor::e_00<2, 3>; +static constexpr auto e_01 = mito::tensor::e_01<2, 3>; +static constexpr auto e_02 = mito::tensor::e_02<2, 3>; +static constexpr auto e_10 = mito::tensor::e_10<2, 3>; +static constexpr auto e_11 = mito::tensor::e_11<2, 3>; +static constexpr auto e_12 = mito::tensor::e_12<2, 3>; // pi sixth constexpr auto pi_sixth = std::numbers::pi / 6.0; From cbb17f1e643b20ba0e8619bd2c65c6de7650160e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 8 Apr 2025 18:09:41 +0200 Subject: [PATCH 023/273] discretization: implement class {IsoparametricSimplex} This class represents the reference finite element simplex in the parametric space. --- .../discretization/IsoparametricSimplex.h | 100 ++++++++++++++++++ lib/mito/discretization/api.h | 5 + lib/mito/discretization/factories.h | 8 ++ lib/mito/discretization/forward.h | 3 + lib/mito/discretization/public.h | 1 + tests/mito.lib/discretization/poisson.cc | 34 +++--- 6 files changed, 131 insertions(+), 20 deletions(-) create mode 100644 lib/mito/discretization/IsoparametricSimplex.h diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h new file mode 100644 index 000000000..73a93c43e --- /dev/null +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -0,0 +1,100 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// DESIGN NOTES +// Class {IsoparametricSimplex} represents the reference simplex in the parametric space + +namespace mito::discretization { + + // TODO: add concept of geometric simplex and require that {geomtricSimplexT} is a geometric + // simplex + template + class IsoparametricSimplex { + + private: + // the geometric simplex type + using geometric_simplex_type = geometricSimplexT; + // TOFIX: this should be defined based on the order of the simplex (e.g. 1 for segments, 2 + // for triangles, 3 for tetrahedra, etc.) + // the type of coordinates + using parametric_coordinates_type = + mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; + + private: + // TOFIX: these should be defined based on the order of the element and on the type of + // simplex (for example here it's 3 of them because we use linear elements on a triangle) + // the function extracting the 0 component of a parametric point + static constexpr auto xi_0 = mito::functions::component; + // the function extracting the y component of a parametric point + static constexpr auto xi_1 = mito::functions::component; + + // linear shape functions on the triangle + static constexpr auto phi_0 = mito::fields::field(xi_0); + static constexpr auto phi_1 = mito::fields::field(xi_1); + static constexpr auto phi_2 = 1.0 - phi_0 - phi_1; + + // the shape functions + static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); + + // the gradients of the shape functions + static constexpr auto dphi = std::make_tuple( + mito::fields::gradient(phi_0), mito::fields::gradient(phi_1), + mito::fields::gradient(phi_2)); + + public: + // the default constructor + constexpr IsoparametricSimplex() = default; + + public: + // get the I-th shape function + template + constexpr auto shape() const + { + // return the I-th shape function + return std::get(phi); + } + + // get the gradient of the I-th shape function + template + constexpr auto gradient() const + { + // return the gradient of I-th shape function + return std::get(dphi); + } + + // get the the isoparametric mapping from barycentric to actual coordinates + template + constexpr auto isoparametric_mapping( + const geometric_simplex_type & simplex, + const coordinateSystemT & coordinate_system) const + { + // the nodes of the simplex + const auto & nodes = simplex.nodes(); + + // the origin of the coordinate system + auto origin = typename coordinateSystemT::coordinates_type{}; + + // the coordinates of the nodes of the triangle + auto x_0 = coordinate_system.coordinates(nodes[0]->point()) - origin; + auto x_1 = coordinate_system.coordinates(nodes[1]->point()) - origin; + auto x_2 = coordinate_system.coordinates(nodes[2]->point()) - origin; + + // assemble the isoparametric mapping from the barycentric coordinates to the actual + // coordinates on the cell {cell} + auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; + + // return the isoparametric mapping + return x_cell; + } + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 2240b1a4b..f5a44bdea 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -32,6 +32,11 @@ namespace mito::discretization { // point field factory template constexpr auto point_field(const cloudT & cloud, std::string name); + + // isoparametric simplex alias + template + using isoparametric_simplex_t = IsoparametricSimplex; + } diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 94f9b307f..215a2a714 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -41,6 +41,14 @@ namespace mito::discretization { // build a point field on the points collected from the cloud return point_field_t(cloud.points(), name); } + + // isoparametric simplex factory + template + constexpr auto isoparametric_simplex() + { + // build an isoparametric simplex and return it + return isoparametric_simplex_t(); + } } diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 8187f62d1..dd6b20a7d 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -13,6 +13,9 @@ namespace mito::discretization { template class DiscreteField; + // class isoparametric simplex + template + class IsoparametricSimplex; } diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index cbda855c1..6ba8dd0b2 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -18,6 +18,7 @@ // classes implementation #include "DiscreteField.h" +#include "IsoparametricSimplex.h" // factories implementation #include "factories.h" diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index ca0b352b8..ea39d6058 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -32,14 +32,18 @@ constexpr auto x = mito::functions::component; // the function extracting the y component of a 2D vector constexpr auto y = mito::functions::component; -// the function extracting the 0 component of a parametric point -constexpr auto xi_0 = mito::functions::component; -// the function extracting the y component of a 2D vector -constexpr auto xi_1 = mito::functions::component; -// linear shape functions on the triangle -constexpr auto phi_0 = mito::fields::field(xi_0); -constexpr auto phi_1 = mito::fields::field(xi_1); -constexpr auto phi_2 = 1.0 - phi_0 - phi_1; +// the isoparametric simplex +constexpr auto isoparametric_simplex = mito::discretization::isoparametric_simplex(); + +// shape functions +constexpr auto phi_0 = isoparametric_simplex.shape<0>(); +constexpr auto phi_1 = isoparametric_simplex.shape<1>(); +constexpr auto phi_2 = isoparametric_simplex.shape<2>(); + +// shape functions derivatives +constexpr auto dphi_0 = isoparametric_simplex.gradient<0>(); +constexpr auto dphi_1 = isoparametric_simplex.gradient<1>(); +constexpr auto dphi_2 = isoparametric_simplex.gradient<2>(); TEST(Fem, PoissonSquare) @@ -162,17 +166,9 @@ TEST(Fem, PoissonSquare) // the nodes of the cell const auto & nodes = cell.nodes(); - // the origin of the coordinate system - auto origin = coordinates_t{}; - - // the coordinates of the nodes of the triangle - auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; - auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; - auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; - // the isoparametric mapping from the barycentric coordinates to the actual coordinates // on the cell {cell} - auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; + auto x_cell = isoparametric_simplex.isoparametric_mapping(cell, coord_system); // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -185,9 +181,7 @@ TEST(Fem, PoissonSquare) /*constexpr*/ auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; // evaluate the gradients of the shape functions at {xi} - /*constexpr*/ auto dphi = std::array{ mito::fields::gradient(phi_0)(xi), - mito::fields::gradient(phi_1)(xi), - mito::fields::gradient(phi_2)(xi) }; + /*constexpr*/ auto dphi = std::array{ dphi_0(xi), dphi_1(xi), dphi_2(xi) }; // the derivative of the coordinates with respect to the barycentric coordinates auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi)); From 72eb4dc5743c1049e1233967c6c380e7d89676d8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 10 Apr 2025 15:41:45 +0200 Subject: [PATCH 024/273] discretization: methods {shape} and {dshape} of class {IsoparametricSimplex} now take in input the barycentric coordinates --- .../discretization/IsoparametricSimplex.h | 35 +++++++++++++------ 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index 73a93c43e..a00c2626b 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -22,9 +22,12 @@ namespace mito::discretization { using geometric_simplex_type = geometricSimplexT; // TOFIX: this should be defined based on the order of the simplex (e.g. 1 for segments, 2 // for triangles, 3 for tetrahedra, etc.) - // the type of coordinates + // the parametric coordinates type using parametric_coordinates_type = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; + // TOFIX: see above + using evaluated_shape_functions_type = std::array; + using evaluated_shape_functions_gradients_type = std::array, 3>; private: // TOFIX: these should be defined based on the order of the element and on the type of @@ -52,20 +55,30 @@ namespace mito::discretization { constexpr IsoparametricSimplex() = default; public: - // get the I-th shape function - template - constexpr auto shape() const + // QUESTION: is there a way to enforce that {barycentricCoordinatesT} are indeed barycentric + // coordinates + // get all the shape functions evaluated at the point {xi} in barycentric coordinates + template + auto shape(const barycentricCoordinatesT & xi) const -> evaluated_shape_functions_type { - // return the I-th shape function - return std::get(phi); + // the parametric coordinates of the quadrature point + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + + // return the shape functions evaluated at {xi} + return { std::get<0>(phi)(xi_p), std::get<1>(phi)(xi_p), std::get<2>(phi)(xi_p) }; } - // get the gradient of the I-th shape function - template - constexpr auto gradient() const + // get all the shape functions gradients evaluated at the point {xi} in barycentric + // coordinates + template + auto gradient(const barycentricCoordinatesT & xi) const + -> evaluated_shape_functions_gradients_type { - // return the gradient of I-th shape function - return std::get(dphi); + // the parametric coordinates of the quadrature point + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + + // return the shape functions gradients evaluated at {xi} + return { std::get<0>(dphi)(xi_p), std::get<1>(dphi)(xi_p), std::get<2>(dphi)(xi_p) }; } // get the the isoparametric mapping from barycentric to actual coordinates From 6b3a276ef76ae60a7f423d24ce4406835cac2c89 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 10 Apr 2025 15:42:41 +0200 Subject: [PATCH 025/273] tests/discretization/poisson: this test now reads the shape functions from the isoparametric simplex --- tests/mito.lib/discretization/poisson.cc | 29 ++++++++---------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index ea39d6058..2aacaadf3 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -9,8 +9,6 @@ // the scalar type using scalar_t = mito::tensor::scalar_t; -// the vector type -using vector_t = mito::tensor::vector_t<2>; // the type of coordinates using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; // the type of cell @@ -35,16 +33,6 @@ constexpr auto y = mito::functions::component; // the isoparametric simplex constexpr auto isoparametric_simplex = mito::discretization::isoparametric_simplex(); -// shape functions -constexpr auto phi_0 = isoparametric_simplex.shape<0>(); -constexpr auto phi_1 = isoparametric_simplex.shape<1>(); -constexpr auto phi_2 = isoparametric_simplex.shape<2>(); - -// shape functions derivatives -constexpr auto dphi_0 = isoparametric_simplex.gradient<0>(); -constexpr auto dphi_1 = isoparametric_simplex.gradient<1>(); -constexpr auto dphi_2 = isoparametric_simplex.gradient<2>(); - TEST(Fem, PoissonSquare) { @@ -174,17 +162,19 @@ TEST(Fem, PoissonSquare) for (int q = 0; q < quadrature_rule_t::npoints; ++q) { // the barycentric coordinates of the quadrature point - /*constexpr*/ auto xi = - coordinates_t{ quadrature_rule.point(q)[0], quadrature_rule.point(q)[1] }; + /*constexpr*/ auto xi = quadrature_rule.point(q); // evaluate the shape functions at {xi} - /*constexpr*/ auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; + /*constexpr*/ auto phi = isoparametric_simplex.shape(xi); // evaluate the gradients of the shape functions at {xi} - /*constexpr*/ auto dphi = std::array{ dphi_0(xi), dphi_1(xi), dphi_2(xi) }; + /*constexpr*/ auto dphi = isoparametric_simplex.gradient(xi); + + /*constexpr*/ auto xi_2 = + coordinates_t{ quadrature_rule.point(q)[0], quadrature_rule.point(q)[1] }; // the derivative of the coordinates with respect to the barycentric coordinates - auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi)); + auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi_2)); // precompute the common factor auto factor = quadrature_rule.weight(q) * manifold.volume(cell); @@ -290,10 +280,9 @@ TEST(Fem, PoissonSquare) // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { // the barycentric coordinates of the quadrature point - /*constexpr*/ auto xi = - coordinates_t{ quadrature_rule.point(q)[0], quadrature_rule.point(q)[1] }; + /*constexpr*/ auto xi = quadrature_rule.point(q); // evaluate the shape functions at {xi} - /*constexpr*/ auto phi = std::array{ phi_0(xi), phi_1(xi), phi_2(xi) }; + /*constexpr*/ auto phi = isoparametric_simplex.shape(xi); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // get the exact solution at {coord} From c449df68f2ca82414418fe1d13763010f8a90b47 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 14 Apr 2025 14:35:12 +0200 Subject: [PATCH 026/273] discretization: add defaulted and deleted metamethods in {IsoparametricSimplex} --- lib/mito/discretization/IsoparametricSimplex.h | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index a00c2626b..ead9a0e33 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -54,6 +54,21 @@ namespace mito::discretization { // the default constructor constexpr IsoparametricSimplex() = default; + // destructor + constexpr ~IsoparametricSimplex() = default; + + // delete move constructor + constexpr IsoparametricSimplex(IsoparametricSimplex &&) noexcept = delete; + + // delete copy constructor + constexpr IsoparametricSimplex(const IsoparametricSimplex &) = delete; + + // delete assignment operator + constexpr IsoparametricSimplex & operator=(const IsoparametricSimplex &) = delete; + + // delete move assignment operator + constexpr IsoparametricSimplex & operator=(IsoparametricSimplex &&) noexcept = delete; + public: // QUESTION: is there a way to enforce that {barycentricCoordinatesT} are indeed barycentric // coordinates From e5fda604117bc53407e8514bb8845b273dba9cca Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 14 Apr 2025 14:37:14 +0200 Subject: [PATCH 027/273] discretization: improve refactoring of jacobian calculation --- .../discretization/IsoparametricSimplex.h | 32 ++++++++----------- tests/mito.lib/discretization/poisson.cc | 16 ++++++---- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index ead9a0e33..d480b545a 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -20,6 +20,8 @@ namespace mito::discretization { private: // the geometric simplex type using geometric_simplex_type = geometricSimplexT; + // the vector type + using vector_type = tensor::vector_t<2>; // TOFIX: this should be defined based on the order of the simplex (e.g. 1 for segments, 2 // for triangles, 3 for tetrahedra, etc.) // the parametric coordinates type @@ -96,29 +98,23 @@ namespace mito::discretization { return { std::get<0>(dphi)(xi_p), std::get<1>(dphi)(xi_p), std::get<2>(dphi)(xi_p) }; } - // get the the isoparametric mapping from barycentric to actual coordinates - template - constexpr auto isoparametric_mapping( - const geometric_simplex_type & simplex, - const coordinateSystemT & coordinate_system) const + // get the jacobian of the isoparametric mapping from barycentric to actual coordinates + template + constexpr auto jacobian( + const vector_type & x_0, const vector_type & x_1, const vector_type & x_2, + const barycentricCoordinatesT & xi) const { - // the nodes of the simplex - const auto & nodes = simplex.nodes(); - - // the origin of the coordinate system - auto origin = typename coordinateSystemT::coordinates_type{}; - - // the coordinates of the nodes of the triangle - auto x_0 = coordinate_system.coordinates(nodes[0]->point()) - origin; - auto x_1 = coordinate_system.coordinates(nodes[1]->point()) - origin; - auto x_2 = coordinate_system.coordinates(nodes[2]->point()) - origin; - // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; - // return the isoparametric mapping - return x_cell; + // the parametric coordinates of the quadrature point + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + + auto J = mito::fields::gradient(x_cell)(xi_p); + + // return the jacobian of the isoparametric mapping + return J; } }; diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 2aacaadf3..978711483 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -154,9 +154,13 @@ TEST(Fem, PoissonSquare) // the nodes of the cell const auto & nodes = cell.nodes(); - // the isoparametric mapping from the barycentric coordinates to the actual coordinates - // on the cell {cell} - auto x_cell = isoparametric_simplex.isoparametric_mapping(cell, coord_system); + // the origin of the coordinate system + auto origin = coordinates_t{}; + + // the coordinates of the nodes of the triangle + auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; + auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; + auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -170,11 +174,11 @@ TEST(Fem, PoissonSquare) // evaluate the gradients of the shape functions at {xi} /*constexpr*/ auto dphi = isoparametric_simplex.gradient(xi); - /*constexpr*/ auto xi_2 = - coordinates_t{ quadrature_rule.point(q)[0], quadrature_rule.point(q)[1] }; + // the jacobian of the mapping from the reference element to the physical element + auto J = isoparametric_simplex.jacobian(x_0, x_1, x_2, xi); // the derivative of the coordinates with respect to the barycentric coordinates - auto J_inv = mito::tensor::inverse(mito::fields::gradient(x_cell)(xi_2)); + auto J_inv = mito::tensor::inverse(J); // precompute the common factor auto factor = quadrature_rule.weight(q) * manifold.volume(cell); From 1466eb965968ccd12bd996604edb0e9a88d76250 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 14 Apr 2025 14:54:17 +0200 Subject: [PATCH 028/273] discretization: implement class {FunctionSpace} This class represents the space of finite element shape functions in the physical space. --- lib/mito/discretization/FunctionSpace.h | 103 +++++++++++++++++++++++ lib/mito/discretization/api.h | 11 +++ lib/mito/discretization/factories.h | 8 ++ lib/mito/discretization/forward.h | 4 + lib/mito/discretization/public.h | 1 + tests/mito.lib/discretization/poisson.cc | 22 ++--- 6 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 lib/mito/discretization/FunctionSpace.h diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h new file mode 100644 index 000000000..84052bdc2 --- /dev/null +++ b/lib/mito/discretization/FunctionSpace.h @@ -0,0 +1,103 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + template + class FunctionSpace { + + private: + // the mesh type + using mesh_type = meshT; + // the cell type + using cell_type = typename mesh_type::cell_type; + // the coordinate system type + using coord_system_type = coordSystemT; + // TOFIX: how do we inject this in the class? + // the canonical simplex type + static constexpr auto canonical_element = isoparametric_simplex(); + // TOFIX + using evaluated_shape_functions_type = std::array; + using evaluated_shape_functions_gradients_type = std::array, 3>; + + public: + // the default constructor + constexpr FunctionSpace(const mesh_type & mesh, const coord_system_type & coord_system) : + _mesh(mesh), + _coord_system(coord_system) {}; + + // destructor + constexpr ~FunctionSpace() = default; + + // delete move constructor + constexpr FunctionSpace(FunctionSpace &&) noexcept = delete; + + // delete copy constructor + constexpr FunctionSpace(const FunctionSpace &) = delete; + + // delete assignment operator + constexpr FunctionSpace & operator=(const FunctionSpace &) = delete; + + // delete move assignment operator + constexpr FunctionSpace & operator=(FunctionSpace &&) noexcept = delete; + + public: + // TOFIX: {barycentricCoordinatesT} should be read from the cell type traits + // get all the shape functions evaluated at the point {xi} in barycentric coordinates + template + auto shape(/*const cell_type & cell,*/ const barycentricCoordinatesT & xi) const + -> evaluated_shape_functions_type + { + // return the shape functions evaluated at {xi} + return canonical_element.shape(xi); + } + + // get all the shape functions gradients evaluated at the point {xi} in barycentric + // coordinates + template + auto gradient(const cell_type & cell, const barycentricCoordinatesT & xi) const + -> evaluated_shape_functions_gradients_type + { + // the nodes of the cell + const auto & nodes = cell.nodes(); + + // the origin of the coordinate system + auto origin = typename coord_system_type::coordinates_type{}; + + // the coordinates of the nodes of the triangle + auto x_0 = _coord_system.coordinates(nodes[0]->point()) - origin; + auto x_1 = _coord_system.coordinates(nodes[1]->point()) - origin; + auto x_2 = _coord_system.coordinates(nodes[2]->point()) - origin; + + // the jacobian of the mapping from the reference element to the physical element + // evaluated at {xi} + auto J = canonical_element.jacobian(x_0, x_1, x_2, xi); + + // the derivative of the coordinates with respect to the barycentric coordinates + auto J_inv = mito::tensor::inverse(J); + + // get the shape functions derivatives at {xi} + /*constexpr*/ auto dphi = canonical_element.gradient(xi); + + // return the spatial gradients of the shape functions evaluated at {xi} + return { dphi[0] * J_inv, dphi[1] * J_inv, dphi[2] * J_inv }; + } + + private: + // a const reference to the mesh + const mesh_type & _mesh; + + // a const reference to the coordinate system + const coord_system_type & _coord_system; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index f5a44bdea..95a93ced5 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -37,6 +37,17 @@ namespace mito::discretization { template using isoparametric_simplex_t = IsoparametricSimplex; + // isoparametric simplex factory + template + constexpr auto isoparametric_simplex(); + + // function space alias + template + using function_space_t = FunctionSpace; + + // function space factory + template + constexpr auto function_space(const meshT &, const coordSystemT &); } diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 215a2a714..642c13eeb 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -49,6 +49,14 @@ namespace mito::discretization { // build an isoparametric simplex and return it return isoparametric_simplex_t(); } + + // function space factory + template + constexpr auto function_space(const meshT & mesh, const coordSystemT & coord_system) + { + // build a function space on the mesh and return it + return function_space_t(mesh, coord_system); + } } diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index dd6b20a7d..cdd117a3f 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -16,6 +16,10 @@ namespace mito::discretization { // class isoparametric simplex template class IsoparametricSimplex; + + // class function space + template + class FunctionSpace; } diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 6ba8dd0b2..736242ef8 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -19,6 +19,7 @@ // classes implementation #include "DiscreteField.h" #include "IsoparametricSimplex.h" +#include "FunctionSpace.h" // factories implementation #include "factories.h" diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 978711483..abe1faabb 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -30,9 +30,6 @@ constexpr auto x = mito::functions::component; // the function extracting the y component of a 2D vector constexpr auto y = mito::functions::component; -// the isoparametric simplex -constexpr auto isoparametric_simplex = mito::discretization::isoparametric_simplex(); - TEST(Fem, PoissonSquare) { @@ -143,6 +140,9 @@ TEST(Fem, PoissonSquare) // create the body manifold auto manifold = mito::manifolds::manifold(mesh, coord_system); + // the function space + auto function_space = mito::discretization::function_space(mesh, coord_system); + // the right hand side auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y); @@ -169,16 +169,10 @@ TEST(Fem, PoissonSquare) /*constexpr*/ auto xi = quadrature_rule.point(q); // evaluate the shape functions at {xi} - /*constexpr*/ auto phi = isoparametric_simplex.shape(xi); - - // evaluate the gradients of the shape functions at {xi} - /*constexpr*/ auto dphi = isoparametric_simplex.gradient(xi); - - // the jacobian of the mapping from the reference element to the physical element - auto J = isoparametric_simplex.jacobian(x_0, x_1, x_2, xi); + /*constexpr*/ auto phi = function_space.shape(xi); - // the derivative of the coordinates with respect to the barycentric coordinates - auto J_inv = mito::tensor::inverse(J); + // evaluate the spatial gradients of the shape functions at {xi} + auto dphi = function_space.gradient(cell, xi); // precompute the common factor auto factor = quadrature_rule.weight(q) * manifold.volume(cell); @@ -205,7 +199,7 @@ TEST(Fem, PoissonSquare) // skip boundary nodes continue; } - auto entry = factor * (dphi[a] * J_inv) * (dphi[b] * J_inv); + auto entry = factor * dphi[a] * dphi[b]; solver.add_matrix_value(eq_a, eq_b, entry); @@ -286,7 +280,7 @@ TEST(Fem, PoissonSquare) // the barycentric coordinates of the quadrature point /*constexpr*/ auto xi = quadrature_rule.point(q); // evaluate the shape functions at {xi} - /*constexpr*/ auto phi = isoparametric_simplex.shape(xi); + /*constexpr*/ auto phi = function_space.shape(xi); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // get the exact solution at {coord} From f8b3b989a57e7cb041f488a222a7e41f6e6f3e7d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Apr 2025 10:31:55 +0200 Subject: [PATCH 029/273] geometry: improve type traits on simplices Moved the definition of type {parametric_point_t} from the manifolds api to the {OrientedSimplex} class. Now an oriented simplex knows the type of its parametric coordinates. This information can now be shared with those who need to know, including the {IsoparametricSimplex}, the {Manifold} and the {QuadratureTable} classes. --- .../discretization/IsoparametricSimplex.h | 11 ++++--- lib/mito/geometry/GeometricSimplex.h | 5 ++++ lib/mito/manifolds/Manifold.h | 6 ++-- lib/mito/manifolds/api.h | 4 --- lib/mito/manifolds/parametric.h | 29 ------------------- lib/mito/manifolds/public.h | 1 - lib/mito/quadrature/QuadratureTable.h | 6 ++-- lib/mito/topology/OrientedSimplex.h | 3 ++ 8 files changed, 17 insertions(+), 48 deletions(-) delete mode 100644 lib/mito/manifolds/parametric.h diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index d480b545a..c9defd19b 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -27,6 +27,8 @@ namespace mito::discretization { // the parametric coordinates type using parametric_coordinates_type = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = geometricSimplexT::barycentric_coordinates_type; // TOFIX: see above using evaluated_shape_functions_type = std::array; using evaluated_shape_functions_gradients_type = std::array, 3>; @@ -75,8 +77,7 @@ namespace mito::discretization { // QUESTION: is there a way to enforce that {barycentricCoordinatesT} are indeed barycentric // coordinates // get all the shape functions evaluated at the point {xi} in barycentric coordinates - template - auto shape(const barycentricCoordinatesT & xi) const -> evaluated_shape_functions_type + auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type { // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -87,8 +88,7 @@ namespace mito::discretization { // get all the shape functions gradients evaluated at the point {xi} in barycentric // coordinates - template - auto gradient(const barycentricCoordinatesT & xi) const + auto gradient(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_gradients_type { // the parametric coordinates of the quadrature point @@ -99,10 +99,9 @@ namespace mito::discretization { } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - template constexpr auto jacobian( const vector_type & x_0, const vector_type & x_1, const vector_type & x_2, - const barycentricCoordinatesT & xi) const + const barycentric_coordinates_type & xi) const { // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} diff --git a/lib/mito/geometry/GeometricSimplex.h b/lib/mito/geometry/GeometricSimplex.h index d45996fb9..6df65337b 100644 --- a/lib/mito/geometry/GeometricSimplex.h +++ b/lib/mito/geometry/GeometricSimplex.h @@ -54,6 +54,10 @@ namespace mito::geometry { template using cell_topological_family_type = typename topology::cell_family; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = + typename simplex_type::resource_type::barycentric_coordinates_type; + private: constexpr auto _sanity_check() const -> bool { @@ -89,6 +93,7 @@ namespace mito::geometry { assert(_sanity_check()); } + // QUESTION: do we need this method? // constructor with an existing oriented simplex and a collection of nodes constexpr GeometricSimplex(const nodes_type & nodes) : Invalidatable(), diff --git a/lib/mito/manifolds/Manifold.h b/lib/mito/manifolds/Manifold.h index ba53b15ca..21023b4d5 100644 --- a/lib/mito/manifolds/Manifold.h +++ b/lib/mito/manifolds/Manifold.h @@ -22,10 +22,6 @@ namespace mito::manifolds { static constexpr int D = cellT::dim; // the dimension of the manifold (that is that of the cell) static constexpr int N = cellT::order; - // the dimension of the parametric space - static constexpr int parametricDim = parametric_dim(); - // typedef for a point in parametric coordinates - using parametric_point_type = manifolds::parametric_point_t; public: // typedef for cell type @@ -38,6 +34,8 @@ namespace mito::manifolds { using coordinates_type = coordsT; // typedef for a coordinates system using coordinate_system_type = geometry::coordinate_system_t; + // typedef for a point in parametric coordinates + using parametric_point_type = typename cell_type::barycentric_coordinates_type; public: constexpr Manifold( diff --git a/lib/mito/manifolds/api.h b/lib/mito/manifolds/api.h index a5e824bfc..bcb81f125 100644 --- a/lib/mito/manifolds/api.h +++ b/lib/mito/manifolds/api.h @@ -9,10 +9,6 @@ namespace mito::manifolds { - // a point in parametric coordinates - template - using parametric_point_t = std::array; - // manifold alias template using manifold_t = Manifold; diff --git a/lib/mito/manifolds/parametric.h b/lib/mito/manifolds/parametric.h deleted file mode 100644 index 49b703751..000000000 --- a/lib/mito/manifolds/parametric.h +++ /dev/null @@ -1,29 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - - -namespace mito::manifolds { - - template - constexpr auto parametric_dim() noexcept -> int; - - template <> - constexpr auto parametric_dim() noexcept -> int - { - return 2; - } - - template <> - constexpr auto parametric_dim() noexcept -> int - { - return 3; - } - - template <> - constexpr auto parametric_dim() noexcept -> int - { - return 4; - } -} \ No newline at end of file diff --git a/lib/mito/manifolds/public.h b/lib/mito/manifolds/public.h index 9e7ad2335..abf2bc8b6 100644 --- a/lib/mito/manifolds/public.h +++ b/lib/mito/manifolds/public.h @@ -17,7 +17,6 @@ #include "api.h" // classes implementation -#include "parametric.h" #include "Manifold.h" // factories implementation diff --git a/lib/mito/quadrature/QuadratureTable.h b/lib/mito/quadrature/QuadratureTable.h index f8bb33be6..aca86bd0b 100644 --- a/lib/mito/quadrature/QuadratureTable.h +++ b/lib/mito/quadrature/QuadratureTable.h @@ -12,13 +12,11 @@ namespace mito::quadrature { // a table to store quadrature rules in terms of their point-weight pairings template class Table { - private: - // the dimension of the parametric space - static constexpr int parametricDim = manifolds::parametric_dim(); public: // the type of quadrature points' parametric coordinates - using quadrature_point_type = manifolds::parametric_point_t; + using quadrature_point_type = + typename elementT::resource_type::barycentric_coordinates_type; // the type of quadrature weights using quadrature_weight_type = double; // the type of quadrature point-weight pairing diff --git a/lib/mito/topology/OrientedSimplex.h b/lib/mito/topology/OrientedSimplex.h index 5896c9e6d..71d90ca02 100644 --- a/lib/mito/topology/OrientedSimplex.h +++ b/lib/mito/topology/OrientedSimplex.h @@ -34,6 +34,9 @@ namespace mito::topology { template using cell_family_type = simplex_t; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = std::array; + // private constructors: only the OrientedSimplexFactory has the right to instantiate // oriented simplices private: From 94169dc07994b81b8f0fc4355e56ccf24b2fab7a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Apr 2025 16:27:40 +0200 Subject: [PATCH 030/273] discretization: class {FunctionSpace} now reads {barycentric_coordinates_type} from the {cell_type} --- lib/mito/discretization/FunctionSpace.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 84052bdc2..85d2c366c 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -22,6 +22,8 @@ namespace mito::discretization { // TOFIX: how do we inject this in the class? // the canonical simplex type static constexpr auto canonical_element = isoparametric_simplex(); + // type of a point in barycentric coordinates + using barycentric_coordinates_type = cell_type::barycentric_coordinates_type; // TOFIX using evaluated_shape_functions_type = std::array; using evaluated_shape_functions_gradients_type = std::array, 3>; @@ -50,8 +52,7 @@ namespace mito::discretization { public: // TOFIX: {barycentricCoordinatesT} should be read from the cell type traits // get all the shape functions evaluated at the point {xi} in barycentric coordinates - template - auto shape(/*const cell_type & cell,*/ const barycentricCoordinatesT & xi) const + auto shape(/*const cell_type & cell,*/ const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type { // return the shape functions evaluated at {xi} @@ -60,8 +61,7 @@ namespace mito::discretization { // get all the shape functions gradients evaluated at the point {xi} in barycentric // coordinates - template - auto gradient(const cell_type & cell, const barycentricCoordinatesT & xi) const + auto gradient(const cell_type & cell, const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_gradients_type { // the nodes of the cell @@ -90,6 +90,7 @@ namespace mito::discretization { } private: + // TOFIX: this is unused for now // a const reference to the mesh const mesh_type & _mesh; From 5dffe12a2c510328f9d21b17706e8e9674f8d59f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Apr 2025 17:03:33 +0200 Subject: [PATCH 031/273] discretization: minor refactoring in {IsoparametricSimplex} class --- lib/mito/discretization/IsoparametricSimplex.h | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index c9defd19b..235febefd 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -37,14 +37,18 @@ namespace mito::discretization { // TOFIX: these should be defined based on the order of the element and on the type of // simplex (for example here it's 3 of them because we use linear elements on a triangle) // the function extracting the 0 component of a parametric point - static constexpr auto xi_0 = mito::functions::component; - // the function extracting the y component of a parametric point - static constexpr auto xi_1 = mito::functions::component; + static constexpr auto xi_0 = + mito::fields::field(mito::functions::component); + // the function extracting the 1 component of a parametric point + static constexpr auto xi_1 = + mito::fields::field(mito::functions::component); + // the function extracting the 2 component of a parametric point + static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; // linear shape functions on the triangle - static constexpr auto phi_0 = mito::fields::field(xi_0); - static constexpr auto phi_1 = mito::fields::field(xi_1); - static constexpr auto phi_2 = 1.0 - phi_0 - phi_1; + static constexpr auto phi_0 = xi_0; + static constexpr auto phi_1 = xi_1; + static constexpr auto phi_2 = xi_2; // the shape functions static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); From 24e2e17f9ff843258d171adba1ccaaee4f15ccac Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Apr 2025 14:00:24 +0200 Subject: [PATCH 032/273] manifolds: add concept for manifold --- lib/mito/manifolds/forward.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/mito/manifolds/forward.h b/lib/mito/manifolds/forward.h index 2f71ab19f..940a26c99 100644 --- a/lib/mito/manifolds/forward.h +++ b/lib/mito/manifolds/forward.h @@ -13,6 +13,15 @@ namespace mito::manifolds { template requires(cellT::dim == coordsT::dim) class Manifold; + + // concept of a manifold + template + concept manifold_c = requires(F c) { + // require that F only binds to {Manifold} specializations + []( + const Manifold &) { + }(c); + }; } From a36570d31d031b433b3154a8fedec03d3bf55c4d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Apr 2025 14:02:28 +0200 Subject: [PATCH 033/273] discretization: {FunctionSpace} instances are now built from manifolds, instead of a mesh and a coordinate system --- lib/mito/discretization/FunctionSpace.h | 24 ++++++++++-------------- lib/mito/discretization/api.h | 8 ++++---- lib/mito/discretization/externals.h | 3 +-- lib/mito/discretization/factories.h | 8 ++++---- lib/mito/discretization/forward.h | 2 +- tests/mito.lib/discretization/poisson.cc | 2 +- 6 files changed, 21 insertions(+), 26 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 85d2c366c..47c703084 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -9,16 +9,18 @@ namespace mito::discretization { - template + template class FunctionSpace { private: + // the manifold type + using manifold_type = manifoldT; // the mesh type - using mesh_type = meshT; + using mesh_type = typename manifold_type::mesh_type; // the cell type using cell_type = typename mesh_type::cell_type; // the coordinate system type - using coord_system_type = coordSystemT; + using coord_system_type = typename manifold_type::coordinate_system_type; // TOFIX: how do we inject this in the class? // the canonical simplex type static constexpr auto canonical_element = isoparametric_simplex(); @@ -30,9 +32,7 @@ namespace mito::discretization { public: // the default constructor - constexpr FunctionSpace(const mesh_type & mesh, const coord_system_type & coord_system) : - _mesh(mesh), - _coord_system(coord_system) {}; + constexpr FunctionSpace(const manifold_type & manifold) : _manifold(manifold) {}; // destructor constexpr ~FunctionSpace() = default; @@ -71,9 +71,9 @@ namespace mito::discretization { auto origin = typename coord_system_type::coordinates_type{}; // the coordinates of the nodes of the triangle - auto x_0 = _coord_system.coordinates(nodes[0]->point()) - origin; - auto x_1 = _coord_system.coordinates(nodes[1]->point()) - origin; - auto x_2 = _coord_system.coordinates(nodes[2]->point()) - origin; + auto x_0 = _manifold.coordinates(nodes[0]) - origin; + auto x_1 = _manifold.coordinates(nodes[1]) - origin; + auto x_2 = _manifold.coordinates(nodes[2]) - origin; // the jacobian of the mapping from the reference element to the physical element // evaluated at {xi} @@ -90,12 +90,8 @@ namespace mito::discretization { } private: - // TOFIX: this is unused for now // a const reference to the mesh - const mesh_type & _mesh; - - // a const reference to the coordinate system - const coord_system_type & _coord_system; + const manifold_type & _manifold; }; } // namespace mito diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 95a93ced5..1d49665f6 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -42,12 +42,12 @@ namespace mito::discretization { constexpr auto isoparametric_simplex(); // function space alias - template - using function_space_t = FunctionSpace; + template + using function_space_t = FunctionSpace; // function space factory - template - constexpr auto function_space(const meshT &, const coordSystemT &); + template + constexpr auto function_space(const manifoldT &); } diff --git a/lib/mito/discretization/externals.h b/lib/mito/discretization/externals.h index 34ea18fe1..66f533ad7 100644 --- a/lib/mito/discretization/externals.h +++ b/lib/mito/discretization/externals.h @@ -12,8 +12,7 @@ // support #include "../journal.h" -#include "../tensor.h" -#include "../mesh.h" +#include "../manifolds.h" // end of file diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 642c13eeb..ac8612227 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -51,11 +51,11 @@ namespace mito::discretization { } // function space factory - template - constexpr auto function_space(const meshT & mesh, const coordSystemT & coord_system) + template + constexpr auto function_space(const manifoldT & manifold) { - // build a function space on the mesh and return it - return function_space_t(mesh, coord_system); + // build a function space on the manifold and return it + return function_space_t(manifold); } } diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index cdd117a3f..6025118e7 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -18,7 +18,7 @@ namespace mito::discretization { class IsoparametricSimplex; // class function space - template + template class FunctionSpace; } diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index abe1faabb..7a00e3a17 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -141,7 +141,7 @@ TEST(Fem, PoissonSquare) auto manifold = mito::manifolds::manifold(mesh, coord_system); // the function space - auto function_space = mito::discretization::function_space(mesh, coord_system); + auto function_space = mito::discretization::function_space(manifold); // the right hand side auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) From 822d99e7bf903d5c488d28b25d69f17ec287146f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Apr 2025 14:04:54 +0200 Subject: [PATCH 034/273] discretization: remove addressed {QUESTION} --- lib/mito/discretization/IsoparametricSimplex.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index 235febefd..e0f6cad2c 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -78,8 +78,6 @@ namespace mito::discretization { constexpr IsoparametricSimplex & operator=(IsoparametricSimplex &&) noexcept = delete; public: - // QUESTION: is there a way to enforce that {barycentricCoordinatesT} are indeed barycentric - // coordinates // get all the shape functions evaluated at the point {xi} in barycentric coordinates auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type { From 25b133f32a4573bff13ef7edf94cf8085cdfa87d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Apr 2025 14:36:32 +0200 Subject: [PATCH 035/273] discretization: remove unused variables from poisson test driver --- tests/mito.lib/discretization/poisson.cc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 7a00e3a17..b2d5e4e97 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -154,14 +154,6 @@ TEST(Fem, PoissonSquare) // the nodes of the cell const auto & nodes = cell.nodes(); - // the origin of the coordinate system - auto origin = coordinates_t{}; - - // the coordinates of the nodes of the triangle - auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; - auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; - auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; - // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { From ed27042d9560546312db32626fff302297965b1a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Apr 2025 15:02:26 +0200 Subject: [PATCH 036/273] discretization: minor refactoring in poisson test driver --- tests/mito.lib/discretization/poisson.cc | 30 +++++++++++++++++------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index b2d5e4e97..67724ef48 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -160,17 +160,11 @@ TEST(Fem, PoissonSquare) // the barycentric coordinates of the quadrature point /*constexpr*/ auto xi = quadrature_rule.point(q); - // evaluate the shape functions at {xi} - /*constexpr*/ auto phi = function_space.shape(xi); - - // evaluate the spatial gradients of the shape functions at {xi} - auto dphi = function_space.gradient(cell, xi); - // precompute the common factor auto factor = quadrature_rule.weight(q) * manifold.volume(cell); - // the coordinates of the quadrature point - auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); + // evaluate the spatial gradients of the shape functions at {xi} + auto dphi = function_space.gradient(cell, xi); // populate the linear system of equations int a = 0; @@ -198,6 +192,26 @@ TEST(Fem, PoissonSquare) ++b; } + ++a; + } + + // evaluate the shape functions at {xi} + /*constexpr*/ auto phi = function_space.shape(xi); + + // the coordinates of the quadrature point + auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); + + // populate the right hand side + a = 0; + for (const auto & node_a : nodes) { + // get the equation number of {node_a} + int eq_a = equation_map.at(node_a); + assert(eq_a < N_equations); + if (eq_a == -1) { + // skip boundary nodes + continue; + } + solver.add_rhs_value(eq_a, factor * f(coord) * phi[a]); ++a; From 05a24cd6408c8dd33f9313d0c77b61d9488793d0 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Apr 2025 15:27:20 +0200 Subject: [PATCH 037/273] discretization: opt for cholesky solver in poisson test driver --- tests/mito.lib/discretization/poisson.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 67724ef48..ca8e64a2b 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -135,7 +135,7 @@ TEST(Fem, PoissonSquare) // create a linear system of equations (PETSc Krylov solver) auto solver = mito::solvers::petsc::ksp("mysolver"); solver.initialize(N_equations); - solver.set_options("-ksp_monitor -ksp_converged_reason"); + solver.set_options("-ksp_type preonly -pc_type cholesky"); // create the body manifold auto manifold = mito::manifolds::manifold(mesh, coord_system); From 77bde82560ed867260a2b9d27eb8955800bc4c6c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Apr 2025 17:01:34 +0200 Subject: [PATCH 038/273] discretization: bugfix Corrected misalignment of nodes numbering between equation map and shape function on the elements involving nodes with attached Dirichlet boundary conditions. --- tests/mito.lib/discretization/poisson.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index ca8e64a2b..d95249073 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -174,6 +174,7 @@ TEST(Fem, PoissonSquare) int eq_a = equation_map.at(node_a); assert(eq_a < N_equations); if (eq_a == -1) { + ++a; // skip boundary nodes continue; } @@ -182,6 +183,7 @@ TEST(Fem, PoissonSquare) int eq_b = equation_map.at(node_b); assert(eq_b < N_equations); if (eq_b == -1) { + ++b; // skip boundary nodes continue; } @@ -208,6 +210,7 @@ TEST(Fem, PoissonSquare) int eq_a = equation_map.at(node_a); assert(eq_a < N_equations); if (eq_a == -1) { + ++a; // skip boundary nodes continue; } From c24d062003b3b197b1dbe5e933b15d5561b77cfb Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Apr 2025 17:16:45 +0200 Subject: [PATCH 039/273] solvers: add {print} method to class {PETScKrylovSolver} --- .../solvers/backend/petsc/PETScKrylovSolver.cc | 17 +++++++++++++++++ .../solvers/backend/petsc/PETScKrylovSolver.h | 3 +++ lib/mito/solvers/backend/petsc/externals.h | 3 +++ 3 files changed, 23 insertions(+) diff --git a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc index 22f6cb538..97f385385 100644 --- a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc +++ b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc @@ -246,5 +246,22 @@ mito::solvers::petsc::PETScKrylovSolver::solve() -> void return; } +// print the linear system of equations of the petsc solver +auto +mito::solvers::petsc::PETScKrylovSolver::print() -> void +{ + // create a reporting channel + journal::info_t channel("mito.solvers.petsc.PETScKrylovSolver"); + + // print the matrix + channel << "Matrix:" << journal::endl; + PetscCallVoid(MatView(_matrix, PETSC_VIEWER_STDOUT_WORLD)); + // print the right-hand side + channel << "Right-hand side:" << journal::endl; + PetscCallVoid(VecView(_rhs, PETSC_VIEWER_STDOUT_WORLD)); + + // all done + return; +} // end of file diff --git a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h index f878ada6b..4f5a9e1e6 100644 --- a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h +++ b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h @@ -71,6 +71,9 @@ namespace mito::solvers::petsc { // solve the linear system auto solve() -> void; + // print the linear system of equations of the petsc solver + auto print() -> void; + // get the solution vector template auto get_solution(solutionT & solution) const -> void; diff --git a/lib/mito/solvers/backend/petsc/externals.h b/lib/mito/solvers/backend/petsc/externals.h index cdea5cbf7..2b375f08d 100644 --- a/lib/mito/solvers/backend/petsc/externals.h +++ b/lib/mito/solvers/backend/petsc/externals.h @@ -12,6 +12,9 @@ #include #include +// support +#include "../../../journal.h" + // petsc support #include From c8674233d1431b5f59fded8638303e5f56714dfe Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Apr 2025 16:48:50 +0200 Subject: [PATCH 040/273] discretization: the {FunctionSpace} now returns the shape functions in terms of {std::map} Methods {shape} and {gradient} now return maps from nodes to the corresponding evaluated shape functions and gradients, respectively. --- lib/mito/discretization/FunctionSpace.h | 27 ++++++++++---- tests/mito.lib/discretization/poisson.cc | 47 ++++++++---------------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 47c703084..3250eea54 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -19,6 +19,8 @@ namespace mito::discretization { using mesh_type = typename manifold_type::mesh_type; // the cell type using cell_type = typename mesh_type::cell_type; + // the node type + using node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; // TOFIX: how do we inject this in the class? @@ -27,8 +29,9 @@ namespace mito::discretization { // type of a point in barycentric coordinates using barycentric_coordinates_type = cell_type::barycentric_coordinates_type; // TOFIX - using evaluated_shape_functions_type = std::array; - using evaluated_shape_functions_gradients_type = std::array, 3>; + using evaluated_shape_functions_type = std::map; + using evaluated_shape_functions_gradients_type = + std::map>; public: // the default constructor @@ -50,13 +53,21 @@ namespace mito::discretization { constexpr FunctionSpace & operator=(FunctionSpace &&) noexcept = delete; public: - // TOFIX: {barycentricCoordinatesT} should be read from the cell type traits - // get all the shape functions evaluated at the point {xi} in barycentric coordinates - auto shape(/*const cell_type & cell,*/ const barycentric_coordinates_type & xi) const + // get all the shape functions of cell {cell} evaluated at the point {xi} in barycentric + // coordinates + auto shape(const cell_type & cell, const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type { + // get the shape functions of the canonical element + auto shape_functions = canonical_element.shape(xi); + + // the nodes of the cell + const auto & nodes = cell.nodes(); + // return the shape functions evaluated at {xi} - return canonical_element.shape(xi); + return { { nodes[0], shape_functions[0] }, + { nodes[1], shape_functions[1] }, + { nodes[2], shape_functions[2] } }; } // get all the shape functions gradients evaluated at the point {xi} in barycentric @@ -86,7 +97,9 @@ namespace mito::discretization { /*constexpr*/ auto dphi = canonical_element.gradient(xi); // return the spatial gradients of the shape functions evaluated at {xi} - return { dphi[0] * J_inv, dphi[1] * J_inv, dphi[2] * J_inv }; + return { { nodes[0], dphi[0] * J_inv }, + { nodes[1], dphi[1] * J_inv }, + { nodes[2], dphi[2] * J_inv } }; } private: diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index d95249073..e14cc4f94 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -151,9 +151,6 @@ TEST(Fem, PoissonSquare) // loop on all the cells of the mesh for (const auto & cell : manifold.elements()) { - // the nodes of the cell - const auto & nodes = cell.nodes(); - // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -163,61 +160,51 @@ TEST(Fem, PoissonSquare) // precompute the common factor auto factor = quadrature_rule.weight(q) * manifold.volume(cell); - // evaluate the spatial gradients of the shape functions at {xi} + // evaluate the spatial gradients of the element shape functions at {xi} auto dphi = function_space.gradient(cell, xi); // populate the linear system of equations - int a = 0; - for (const auto & node_a : nodes) { - int b = 0; + for (const auto & [node_a, dphi_a] : dphi) { // get the equation number of {node_a} int eq_a = equation_map.at(node_a); assert(eq_a < N_equations); if (eq_a == -1) { - ++a; // skip boundary nodes continue; } - for (const auto & node_b : nodes) { + for (const auto & [node_b, dphi_b] : dphi) { // get the equation number of {node_b} int eq_b = equation_map.at(node_b); assert(eq_b < N_equations); if (eq_b == -1) { - ++b; // skip boundary nodes continue; } - auto entry = factor * dphi[a] * dphi[b]; - + // compute the entry of the stiffness matrix + auto entry = factor * dphi_a * dphi_b; + // assemble the value in the stiffness matrix solver.add_matrix_value(eq_a, eq_b, entry); - - ++b; } - - ++a; } - // evaluate the shape functions at {xi} - /*constexpr*/ auto phi = function_space.shape(xi); + // evaluate the element shape functions at {xi} + auto phi = function_space.shape(cell, xi); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // populate the right hand side - a = 0; - for (const auto & node_a : nodes) { + for (const auto & [node_a, phi_a] : phi) { // get the equation number of {node_a} int eq_a = equation_map.at(node_a); assert(eq_a < N_equations); if (eq_a == -1) { - ++a; // skip boundary nodes continue; } - solver.add_rhs_value(eq_a, factor * f(coord) * phi[a]); - - ++a; + // assemble the value in the right hand side + solver.add_rhs_value(eq_a, factor * f(coord) * phi_a); } } } @@ -288,20 +275,18 @@ TEST(Fem, PoissonSquare) for (int q = 0; q < quadrature_rule_t::npoints; ++q) { // the barycentric coordinates of the quadrature point /*constexpr*/ auto xi = quadrature_rule.point(q); - // evaluate the shape functions at {xi} - /*constexpr*/ auto phi = function_space.shape(xi); + // evaluate the element shape functions at {xi} + auto phi = function_space.shape(cell, xi); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // get the exact solution at {coord} auto u_exact = u_ex(coord); // assemble the numerical solution at {coord} auto u_numerical = 0.0; - int a = 0; - // loop on all the nodes of the cell - for (const auto & node : cell.nodes()) { + // loop on all the shape functions + for (const auto & [node_a, phi_a] : phi) { // get the numerical solution at {coord} - u_numerical += solution(node) * phi[a]; - ++a; + u_numerical += solution(node_a) * phi_a; } // get the error error_L2 += (u_exact - u_numerical) * (u_exact - u_numerical) From 61a252366dabcac67bcbc0dd9db93a41bc0c5ed8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Apr 2025 17:26:52 +0200 Subject: [PATCH 041/273] geometry: bugfix in {geometric_simplex} factories Before this commit, the methods that build geometric simplices on top of a given simplex and a collection of nodes made copies of the nodes to be stored in the geometric simplex. The unwanted behaviour was causing a bug in the extraction of the boundary simplices of a mesh as it led to the duplication of all the boundary nodes in the boundary simplices. This has now been fixed. The methods that build geometric simplices on top of a given simplex and a collection of nodes do not make copies of nodes any more. --- lib/mito/geometry/utilities.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/mito/geometry/utilities.h b/lib/mito/geometry/utilities.h index a59fdff2a..cd4c28189 100644 --- a/lib/mito/geometry/utilities.h +++ b/lib/mito/geometry/utilities.h @@ -102,9 +102,8 @@ namespace mito::geometry { }; // return the geometric simplex - return geometric_simplex_type({ node_type( - vertices[K], - (*std::ranges::find_if(nodes, has_vertex(vertices[K])))->point())... }); + return geometric_simplex_type( + { (*std::ranges::find_if(nodes, has_vertex(vertices[K])))... }); }; // build a geometric simplex based on {simplex} with the vertex-point pair as appears in @@ -134,7 +133,7 @@ namespace mito::geometry { }; // return the node - return node_type(vertex, (*std::ranges::find_if(nodes, has_vertex(vertex)))->point()); + return *std::ranges::find_if(nodes, has_vertex(vertex)); } // returns the geometric simplex with opposite orientation to {simplex} From 07946b1c78fa58b871b7b623092cb8360d5a215e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Apr 2025 18:02:59 +0200 Subject: [PATCH 042/273] discretization: fix a few bugs in the geometric-agnostic boundary conditions in poisson test driver This implementation now works correctly after rev. 61a2523 and the fixing of a few glitches (namely, setting -1 in the equation map for boundary nodes and declaring/defining the {N_equations} variable) --- tests/mito.lib/discretization/poisson.cc | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index e14cc4f94..29dad1b68 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -49,10 +49,6 @@ TEST(Fem, PoissonSquare) // auto mesh = mito::mesh::tetra(original_mesh, coord_system, subdivisions); #if 0 - // TOFIX: this does not work as the nodes are copied into new nodes to construct the boundary - // cells, therefore the set difference is not aware of the node equality. Therefore we need to - // back up to the spatial search implementation - // get all the nodes in the mesh std::set nodes; mito::mesh::get_nodes(mesh, nodes); @@ -86,7 +82,17 @@ TEST(Fem, PoissonSquare) std::map equation_map; int equation = 0; - // loop on all the nodes of the cell + // loop on all the boundary nodes of the mesh + for (const auto & node : boundary_nodes) { + // check if the node is already in the equation map + if (equation_map.find(node) == equation_map.end()) { + // add the node to the equation map with a -1 indicating that the node is on the + // boundary + equation_map[node] = -1; + } + } + + // loop on all the interior nodes of the mesh for (const auto & node : interior_nodes) { // check if the node is already in the equation map if (equation_map.find(node) == equation_map.end()) { @@ -96,6 +102,10 @@ TEST(Fem, PoissonSquare) equation++; } } + + // the number of equations + int N_equations = equation; + #else std::set nodes; mito::mesh::get_nodes(mesh, nodes); From 48a411c74753d671ec30b87c97b4a7a53314fc5a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Apr 2025 18:05:37 +0200 Subject: [PATCH 043/273] discretization: switch to geometric-agnostic boundary conditions in poisson test driver --- tests/mito.lib/discretization/poisson.cc | 48 +----------------------- 1 file changed, 1 insertion(+), 47 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 29dad1b68..433870f65 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -48,28 +48,16 @@ TEST(Fem, PoissonSquare) // const auto subdivisions = 1; // auto mesh = mito::mesh::tetra(original_mesh, coord_system, subdivisions); -#if 0 // get all the nodes in the mesh std::set nodes; mito::mesh::get_nodes(mesh, nodes); - channel << "Number of total cells: " << std::size(mesh.cells()) << journal::endl; - channel << "Number of total nodes: " << std::size(nodes) << journal::endl; - for (const auto & node : nodes) { - // print the coordinates of the node - channel << coord_system.coordinates(node->point()) << journal::endl; - } + channel << "Number of nodes: " << std::size(nodes) << journal::endl; // get all the nodes on the mesh boundary auto boundary_mesh = mito::mesh::boundary(mesh); std::set boundary_nodes; mito::mesh::get_nodes(boundary_mesh, boundary_nodes); - channel << "Number of boundary cells: " << std::size(boundary_mesh.cells()) << journal::endl; channel << "Number of boundary nodes: " << std::size(boundary_nodes) << journal::endl; - for (const auto & node : boundary_nodes) { - // node.vertex() - // print the coordinates of the node - channel << coord_system.coordinates(node->point()) << journal::endl; - } // get all the interior nodes as the difference between all the nodes and the boundary nodes std::set interior_nodes; @@ -106,40 +94,6 @@ TEST(Fem, PoissonSquare) // the number of equations int N_equations = equation; -#else - std::set nodes; - mito::mesh::get_nodes(mesh, nodes); - - // populate the equation map (from node to equation, one equations per node) - std::map equation_map; - int equation = 0; - - // loop on all the nodes of the cell - for (const auto & node : nodes) { - // get the coordinates of the node - auto coord = coord_system.coordinates(node->point()); - // if the node is on the boundary - if (coord[0] == 0.0 || coord[0] == 1.0 || coord[1] == 0.0 || coord[1] == 1.0) { - // check if the node is already in the equation map - if (equation_map.find(node) == equation_map.end()) { - // add the node to the equation map with a -1 indicating that the node is on the - // boundary - equation_map[node] = -1; - } - } - - // check if the node is already in the equation map - if (equation_map.find(node) == equation_map.end()) { - // add the node to the equation map - equation_map[node] = equation; - // increment the equation number - equation++; - } - } - - // the number of equations - int N_equations = equation; -#endif channel << "Number of equations: " << equation << journal::endl; // create a linear system of equations (PETSc Krylov solver) From f7c2928089e2793852dbefb2c13f8c9bb2b982a1 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Apr 2025 18:12:16 +0200 Subject: [PATCH 044/273] constraints: implement class for a Dirichlet constraint on a portion of the domain --- .cmake/mito_tests_mito_lib.cmake | 3 ++ lib/mito/constraints.h | 15 +++++++ lib/mito/constraints/Dirichlet.h | 43 ++++++++++++++++++ lib/mito/constraints/api.h | 23 ++++++++++ lib/mito/constraints/externals.h | 18 ++++++++ lib/mito/constraints/factories.h | 23 ++++++++++ lib/mito/constraints/forward.h | 26 +++++++++++ lib/mito/constraints/public.h | 26 +++++++++++ lib/mito/public.h | 1 + tests/mito.lib/constraints/dirichlet.cc | 60 +++++++++++++++++++++++++ 10 files changed, 238 insertions(+) create mode 100644 lib/mito/constraints.h create mode 100644 lib/mito/constraints/Dirichlet.h create mode 100644 lib/mito/constraints/api.h create mode 100644 lib/mito/constraints/externals.h create mode 100644 lib/mito/constraints/factories.h create mode 100644 lib/mito/constraints/forward.h create mode 100644 lib/mito/constraints/public.h create mode 100644 tests/mito.lib/constraints/dirichlet.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index b84497c6f..dc4d7541a 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -35,6 +35,9 @@ mito_test_driver(tests/mito.lib/geometry/euclidean_metric_space.cc) mito_test_driver(tests/mito.lib/geometry/polar_metric_space.cc) mito_test_driver(tests/mito.lib/geometry/spherical_metric_space.cc) +# constraints +mito_test_driver(tests/mito.lib/constraints/dirichlet.cc) + # discretization mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) mito_test_driver(tests/mito.lib/discretization/nodal_field.cc) diff --git a/lib/mito/constraints.h b/lib/mito/constraints.h new file mode 100644 index 000000000..dfdb50804 --- /dev/null +++ b/lib/mito/constraints.h @@ -0,0 +1,15 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// publish the interface +// the api is in "constraints/api.h" +#include "constraints/public.h" + + +// end of file diff --git a/lib/mito/constraints/Dirichlet.h b/lib/mito/constraints/Dirichlet.h new file mode 100644 index 000000000..95f5982f6 --- /dev/null +++ b/lib/mito/constraints/Dirichlet.h @@ -0,0 +1,43 @@ + +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + + +// code guard +#pragma once + + +namespace mito::constraints { + + // class Dirichlet boundary condition + template + class Dirichlet { + // types + public: + using domain_type = meshT; + using function_type = fieldT; + using cells_type = domain_type::cells_type; + + // interface + public: + // constructor + Dirichlet(const domain_type & domain, const function_type & function) : + _domain(domain), + _function(function) + {} + + // destructor + ~Dirichlet() = default; + + // accessors + auto cells() const -> const cells_type & { return _domain.cells(); } + auto function() const -> const function_type & { return _function; } + + private: + const domain_type & _domain; + function_type _function; + }; + +} // namespace mito::constraints \ No newline at end of file diff --git a/lib/mito/constraints/api.h b/lib/mito/constraints/api.h new file mode 100644 index 000000000..e56b13376 --- /dev/null +++ b/lib/mito/constraints/api.h @@ -0,0 +1,23 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::constraints { + + // Dirichlet class alias + template + using dirichlet_bc_t = Dirichlet; + + // factory for Dirichlet boundary conditions + template + constexpr auto dirichlet_bc(const meshT & mesh, const fieldT & function) + -> dirichlet_bc_t; +} + + +// end of file diff --git a/lib/mito/constraints/externals.h b/lib/mito/constraints/externals.h new file mode 100644 index 000000000..cb4f544dc --- /dev/null +++ b/lib/mito/constraints/externals.h @@ -0,0 +1,18 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// externals + +// support +#include "../journal.h" +#include "../mesh.h" +#include "../fields.h" + + +// end of file diff --git a/lib/mito/constraints/factories.h b/lib/mito/constraints/factories.h new file mode 100644 index 000000000..f11ac75eb --- /dev/null +++ b/lib/mito/constraints/factories.h @@ -0,0 +1,23 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::constraints { + + // factory for Dirichlet boundary conditions + template + constexpr auto dirichlet_bc(const meshT & mesh, const fieldT & function) + -> dirichlet_bc_t + { + return dirichlet_bc_t(mesh, function); + } + +} + + +// end of file diff --git a/lib/mito/constraints/forward.h b/lib/mito/constraints/forward.h new file mode 100644 index 000000000..9a9182fd5 --- /dev/null +++ b/lib/mito/constraints/forward.h @@ -0,0 +1,26 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::constraints { + + // class Dirichlet boundary condition + template + class Dirichlet; + + // concept of a constraint + template + concept constraint_c = requires(F c) { + // require that F only binds to {Dirichlet} specializations + [](const Dirichlet &) { + }(c); + }; +} + + +// end of file diff --git a/lib/mito/constraints/public.h b/lib/mito/constraints/public.h new file mode 100644 index 000000000..880fc3fe8 --- /dev/null +++ b/lib/mito/constraints/public.h @@ -0,0 +1,26 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// external packages +#include "externals.h" + +// get the forward declarations +#include "forward.h" + +// published types factories; this is the file you are looking for... +#include "api.h" + +// classes implementation +#include "Dirichlet.h" + +// factories implementation +#include "factories.h" + + +// end of file diff --git a/lib/mito/public.h b/lib/mito/public.h index 363d52d32..f051122a9 100644 --- a/lib/mito/public.h +++ b/lib/mito/public.h @@ -12,6 +12,7 @@ #include "tensor.h" #include "functions.h" #include "discretization.h" +#include "constraints.h" #include "coordinates.h" #include "geometry.h" #include "io.h" diff --git a/tests/mito.lib/constraints/dirichlet.cc b/tests/mito.lib/constraints/dirichlet.cc new file mode 100644 index 000000000..e8edd7f42 --- /dev/null +++ b/tests/mito.lib/constraints/dirichlet.cc @@ -0,0 +1,60 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; +// the type of cell +using cell_t = mito::geometry::triangle_t<2>; + + +// the function extracting the x component of a 2D vector +constexpr auto x = mito::functions::component; +// the function extracting the y component of a 2D vector +constexpr auto y = mito::functions::component; + + +TEST(Constraints, Dirichlet) +{ + // make a channel + journal::info_t channel("tests.dirichlet_constraints"); + + // the coordinate system + auto coord_system = mito::geometry::coordinate_system(); + + // read the mesh of a unit disk in 2D + std::ifstream fileStream("disk_cartesian.summit"); + auto mesh = mito::io::summit::reader(fileStream, coord_system); + + // the value of the Dirichlet boundary condition + auto bc_value = mito::fields::field(mito::functions::sqrt(x * x + y * y)); + + // get all the nodes on the mesh boundary + auto boundary_mesh = mito::mesh::boundary(mesh); + + // the Dirichlet boundary condition + auto constraints = mito::constraints::dirichlet_bc(boundary_mesh, bc_value); + + // loop on all the constrained nodes + for (const auto & cell : constraints.cells()) { + // get all the nodes of the cell + auto nodes = cell.nodes(); + // loop on all the nodes of the cell + for (const auto & node : nodes) { + // get the position of the node + auto position = coord_system.coordinates(node->point()); + // expect that the value of the Dirichlet boundary condition is equal to the radius of + // the disk up to a reasonable tolerance + EXPECT_NEAR(bc_value(position), 1.0, 1.e-12); + } + } +} + +// end of file From bdd35bf2a98da224a2601525304dec7d46a92d9e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 5 May 2025 19:49:15 +0200 Subject: [PATCH 045/273] constraints: implement class for a Dirichlet constraint on a portion of the domain --- lib/mito/constraints/Dirichlet.h | 3 +-- tests/mito.lib/constraints/dirichlet.cc | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/lib/mito/constraints/Dirichlet.h b/lib/mito/constraints/Dirichlet.h index 95f5982f6..00979c680 100644 --- a/lib/mito/constraints/Dirichlet.h +++ b/lib/mito/constraints/Dirichlet.h @@ -18,7 +18,6 @@ namespace mito::constraints { public: using domain_type = meshT; using function_type = fieldT; - using cells_type = domain_type::cells_type; // interface public: @@ -32,7 +31,7 @@ namespace mito::constraints { ~Dirichlet() = default; // accessors - auto cells() const -> const cells_type & { return _domain.cells(); } + auto domain() const -> const domain_type & { return _domain; } auto function() const -> const function_type & { return _function; } private: diff --git a/tests/mito.lib/constraints/dirichlet.cc b/tests/mito.lib/constraints/dirichlet.cc index e8edd7f42..871ef62a6 100644 --- a/tests/mito.lib/constraints/dirichlet.cc +++ b/tests/mito.lib/constraints/dirichlet.cc @@ -43,7 +43,7 @@ TEST(Constraints, Dirichlet) auto constraints = mito::constraints::dirichlet_bc(boundary_mesh, bc_value); // loop on all the constrained nodes - for (const auto & cell : constraints.cells()) { + for (const auto & cell : constraints.domain().cells()) { // get all the nodes of the cell auto nodes = cell.nodes(); // loop on all the nodes of the cell From e6ac44afd1314d436275d4ab8bd04cd331f279a8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 5 May 2025 19:50:53 +0200 Subject: [PATCH 046/273] constraints: implement method to retrieve the constrained nodes for a Dirichlet constraint --- lib/mito/constraints/Dirichlet.h | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/mito/constraints/Dirichlet.h b/lib/mito/constraints/Dirichlet.h index 00979c680..8c8042657 100644 --- a/lib/mito/constraints/Dirichlet.h +++ b/lib/mito/constraints/Dirichlet.h @@ -18,6 +18,8 @@ namespace mito::constraints { public: using domain_type = meshT; using function_type = fieldT; + using node_type = typename domain_type::node_type; + using nodes_type = std::set; // interface public: @@ -34,6 +36,15 @@ namespace mito::constraints { auto domain() const -> const domain_type & { return _domain; } auto function() const -> const function_type & { return _function; } + // get the constrained nodes + auto nodes() const -> nodes_type + { + // get all the nodes in the domain + nodes_type nodes; + mito::mesh::get_nodes(_domain, nodes); + return nodes; + } + private: const domain_type & _domain; function_type _function; From 6f8ca749b5511426d93b5df28f0bd83a545e90c4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 5 May 2025 20:01:59 +0200 Subject: [PATCH 047/273] manifolds: add accessors for mesh and coordinate system attributes in class {Manifold} --- lib/mito/manifolds/Manifold.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/mito/manifolds/Manifold.h b/lib/mito/manifolds/Manifold.h index 21023b4d5..80f29aac7 100644 --- a/lib/mito/manifolds/Manifold.h +++ b/lib/mito/manifolds/Manifold.h @@ -66,6 +66,15 @@ namespace mito::manifolds { Manifold & operator=(Manifold &&) noexcept = delete; public: + // accessor for the mesh + constexpr auto mesh() const noexcept -> const mesh_type & { return _mesh; } + + // accessor for the coordinate system + constexpr auto coordinate_system() const noexcept -> const coordinate_system_type & + { + return _coordinate_system; + } + constexpr auto elements() const noexcept -> const cells_type & { return _mesh.cells(); } constexpr auto nElements() const noexcept -> int { return std::size(_mesh.cells()); } From a4683c4017427abfd1cb0669bea2d39522a3a3dc Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 5 May 2025 20:01:29 +0200 Subject: [PATCH 048/273] discretization: implement class {DiscreteSystem} as a function space equipped with an equation map This class should also be aware of the 'weakform bricks' that constitute the system. Each brick containing a piece of the weakform to be assembled. --- lib/mito/discretization/DiscreteSystem.h | 136 +++++++++++++++++++++++ lib/mito/discretization/api.h | 8 ++ lib/mito/discretization/factories.h | 7 ++ lib/mito/discretization/forward.h | 4 + lib/mito/discretization/public.h | 1 + 5 files changed, 156 insertions(+) create mode 100644 lib/mito/discretization/DiscreteSystem.h diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h new file mode 100644 index 000000000..1a24a079a --- /dev/null +++ b/lib/mito/discretization/DiscreteSystem.h @@ -0,0 +1,136 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + template + class DiscreteSystem { + + private: + // the function space type + using function_space_type = functionSpaceT; + // the type of node + using node_type = typename function_space_type::node_type; + // QUESTION: is std::map the best choice for {equation_map_type}? + // the equation map type (map associating an equation number to each node degree of freedom) + using equation_map_type = std::map; + + public: + // the default constructor + constexpr DiscreteSystem(const function_space_type & function_space) : + _function_space(function_space), + _equation_map(), + _n_equations(0) + { + _build_equation_map(); + } + + // destructor + constexpr ~DiscreteSystem() = default; + + // delete move constructor + constexpr DiscreteSystem(DiscreteSystem &&) noexcept = delete; + + // delete copy constructor + constexpr DiscreteSystem(const DiscreteSystem &) = delete; + + // delete assignment operator + constexpr DiscreteSystem & operator=(const DiscreteSystem &) = delete; + + // delete move assignment operator + constexpr DiscreteSystem & operator=(DiscreteSystem &&) noexcept = delete; + + private: + // build the equation map + void _build_equation_map() + { + // make a channel + journal::info_t channel("discretization.discrete_system"); + + // get the mesh of the function space + const auto & mesh = _function_space.manifold().mesh(); + + // get all the nodes in the mesh + std::set nodes; + mito::mesh::get_nodes(mesh, nodes); + channel << "Number of nodes: " << std::size(nodes) << journal::endl; + + // get the domain that is constrained + const auto & constrained_nodes = _function_space.constraints().nodes(); + channel << "Number of constrained nodes: " << std::size(constrained_nodes) + << journal::endl; + + // get all the interior nodes as the difference between all the nodes and the boundary + // nodes + std::set interior_nodes; + std::set_difference( + nodes.begin(), nodes.end(), constrained_nodes.begin(), constrained_nodes.end(), + std::inserter(interior_nodes, interior_nodes.begin())); + channel << "Number of interior nodes: " << std::size(interior_nodes) << journal::endl; + + // populate the equation map (from node to equation, one equations per node) + int equation = 0; + + // loop on all the boundary nodes of the mesh + for (const auto & node : constrained_nodes) { + // check if the node is already in the equation map + if (_equation_map.find(node) == _equation_map.end()) { + // add the node to the equation map with a -1 indicating that the node is on the + // boundary + _equation_map[node] = -1; + } + } + + // loop on all the interior nodes of the mesh + for (const auto & node : interior_nodes) { + // check if the node is already in the equation map + if (_equation_map.find(node) == _equation_map.end()) { + // add the node to the equation map + _equation_map[node] = equation; + // increment the equation number + equation++; + } + } + + // the number of equations + int _n_equations = equation; + + // print the number of equations + channel << "Number of equations: " << _n_equations << journal::endl; + } + + public: + // accessor to the equation map + constexpr auto equation_map() const noexcept -> const equation_map_type & + { + return _equation_map; + } + + // accessor to the number of equations + constexpr auto n_equations() const noexcept -> int { return _n_equations; } + + private: + // QUESTION: do we need the function space to be an attribute or do we only need it in the + // constructor? Also, for sure we should have an attribute that is aware of the 'bricks' to + // be assembled in the system. Either these bricks should be aware of the function space, or + // the function space should know how to discretize the bricks with its own shape functions + // a const reference to the function space + const function_space_type & _function_space; + + // the equation map + equation_map_type _equation_map; + + // the number of equations + int _n_equations; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 1d49665f6..526b8c775 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -48,6 +48,14 @@ namespace mito::discretization { // function space factory template constexpr auto function_space(const manifoldT &); + + // discrete system alias + template + using discrete_system_t = DiscreteSystem; + + // discrete system factory + template + constexpr auto discrete_system(const functionSpaceT & function_space); } diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index ac8612227..533f434e7 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -57,6 +57,13 @@ namespace mito::discretization { // build a function space on the manifold and return it return function_space_t(manifold); } + + // discrete system factory + template + constexpr auto discrete_system(const functionSpaceT & function_space) + { + return discrete_system_t(function_space); + } } diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 6025118e7..ec62f6b5e 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -20,6 +20,10 @@ namespace mito::discretization { // class function space template class FunctionSpace; + + // class discrete system + template + class DiscreteSystem; } diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 736242ef8..3caff8ee8 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -20,6 +20,7 @@ #include "DiscreteField.h" #include "IsoparametricSimplex.h" #include "FunctionSpace.h" +#include "DiscreteSystem.h" // factories implementation #include "factories.h" From eeffc9cf58336b00e47c9b76dcda517af411f900 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 5 May 2025 20:03:18 +0200 Subject: [PATCH 049/273] discretization: add accessor to manifold in class {FunctionSpace} --- lib/mito/discretization/FunctionSpace.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 3250eea54..7c83a2cc1 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -53,6 +53,9 @@ namespace mito::discretization { constexpr FunctionSpace & operator=(FunctionSpace &&) noexcept = delete; public: + // accessor for the manifold + constexpr auto manifold() const noexcept -> const manifold_type & { return _manifold; } + // get all the shape functions of cell {cell} evaluated at the point {xi} in barycentric // coordinates auto shape(const cell_type & cell, const barycentric_coordinates_type & xi) const From 0bbb27788ff960dd2b3b58cbff9897f07b550dec Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 5 May 2025 20:09:50 +0200 Subject: [PATCH 050/273] =?UTF-8?q?discretization:=20class=20{FunctionSpac?= =?UTF-8?q?e}=20is=20now=C2=A0aware=20of=20constraints=20on=20the=20discre?= =?UTF-8?q?tized=20variable?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/mito/discretization/FunctionSpace.h | 29 +++++++++-- lib/mito/discretization/api.h | 8 +-- lib/mito/discretization/externals.h | 1 + lib/mito/discretization/factories.h | 8 +-- lib/mito/discretization/forward.h | 2 +- tests/mito.lib/discretization/poisson.cc | 64 ++++++------------------ 6 files changed, 51 insertions(+), 61 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 7c83a2cc1..e78eccde6 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -9,12 +9,14 @@ namespace mito::discretization { - template + template class FunctionSpace { - private: + public: // the manifold type using manifold_type = manifoldT; + // the constraints type + using constraints_type = constraintsT; // the mesh type using mesh_type = typename manifold_type::mesh_type; // the cell type @@ -23,6 +25,8 @@ namespace mito::discretization { using node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; + + private: // TOFIX: how do we inject this in the class? // the canonical simplex type static constexpr auto canonical_element = isoparametric_simplex(); @@ -34,8 +38,11 @@ namespace mito::discretization { std::map>; public: - // the default constructor - constexpr FunctionSpace(const manifold_type & manifold) : _manifold(manifold) {}; + // the constructor + constexpr FunctionSpace( + const manifold_type & manifold, const constraints_type & constraints) : + _manifold(manifold), + _constraints(constraints) {}; // destructor constexpr ~FunctionSpace() = default; @@ -56,6 +63,12 @@ namespace mito::discretization { // accessor for the manifold constexpr auto manifold() const noexcept -> const manifold_type & { return _manifold; } + // accessor for the constraints + constexpr auto constraints() const noexcept -> const constraints_type & + { + return _constraints; + } + // get all the shape functions of cell {cell} evaluated at the point {xi} in barycentric // coordinates auto shape(const cell_type & cell, const barycentric_coordinates_type & xi) const @@ -108,6 +121,14 @@ namespace mito::discretization { private: // a const reference to the mesh const manifold_type & _manifold; + + // TOFIX: this should be a collection of constraints. Also, constraints may involve + // different degrees of freedom (e.g. periodic boundary conditions to impose relations + // between beam rotations). Therefore, the function space should be aware of the spatial + // dimension of the shape functions. + // + // the constraints + const constraints_type & _constraints; }; } // namespace mito diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 526b8c775..e5b9a67ef 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -42,12 +42,12 @@ namespace mito::discretization { constexpr auto isoparametric_simplex(); // function space alias - template - using function_space_t = FunctionSpace; + template + using function_space_t = FunctionSpace; // function space factory - template - constexpr auto function_space(const manifoldT &); + template + constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); // discrete system alias template diff --git a/lib/mito/discretization/externals.h b/lib/mito/discretization/externals.h index 66f533ad7..7d5bc025f 100644 --- a/lib/mito/discretization/externals.h +++ b/lib/mito/discretization/externals.h @@ -13,6 +13,7 @@ // support #include "../journal.h" #include "../manifolds.h" +#include "../constraints.h" // end of file diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 533f434e7..e7ebe7434 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -50,12 +50,14 @@ namespace mito::discretization { return isoparametric_simplex_t(); } + // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a + // single constraint // function space factory - template - constexpr auto function_space(const manifoldT & manifold) + template + constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) { // build a function space on the manifold and return it - return function_space_t(manifold); + return function_space_t(manifold, constraints); } // discrete system factory diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index ec62f6b5e..549503fd4 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -18,7 +18,7 @@ namespace mito::discretization { class IsoparametricSimplex; // class function space - template + template class FunctionSpace; // class discrete system diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 433870f65..a2296a8e0 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -13,8 +13,6 @@ using scalar_t = mito::tensor::scalar_t; using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; // the type of cell using cell_t = mito::geometry::triangle_t<2>; -// the type of node -using node_t = cell_t::node_type; // the type of simplex using simplex_t = cell_t::simplex_type; // Gauss quadrature on triangles with degree of exactness 1 @@ -48,65 +46,31 @@ TEST(Fem, PoissonSquare) // const auto subdivisions = 1; // auto mesh = mito::mesh::tetra(original_mesh, coord_system, subdivisions); - // get all the nodes in the mesh - std::set nodes; - mito::mesh::get_nodes(mesh, nodes); - channel << "Number of nodes: " << std::size(nodes) << journal::endl; + // the zero field + auto zero = mito::fields::field(mito::functions::zero); // get all the nodes on the mesh boundary auto boundary_mesh = mito::mesh::boundary(mesh); - std::set boundary_nodes; - mito::mesh::get_nodes(boundary_mesh, boundary_nodes); - channel << "Number of boundary nodes: " << std::size(boundary_nodes) << journal::endl; - - // get all the interior nodes as the difference between all the nodes and the boundary nodes - std::set interior_nodes; - std::set_difference( - nodes.begin(), nodes.end(), boundary_nodes.begin(), boundary_nodes.end(), - std::inserter(interior_nodes, interior_nodes.begin())); - channel << "Number of interior nodes: " << std::size(interior_nodes) << journal::endl; - - // populate the equation map (from node to equation, one equations per node) - std::map equation_map; - int equation = 0; - - // loop on all the boundary nodes of the mesh - for (const auto & node : boundary_nodes) { - // check if the node is already in the equation map - if (equation_map.find(node) == equation_map.end()) { - // add the node to the equation map with a -1 indicating that the node is on the - // boundary - equation_map[node] = -1; - } - } - // loop on all the interior nodes of the mesh - for (const auto & node : interior_nodes) { - // check if the node is already in the equation map - if (equation_map.find(node) == equation_map.end()) { - // add the node to the equation map - equation_map[node] = equation; - // increment the equation number - equation++; - } - } + // the Dirichlet boundary condition + auto constraints = mito::constraints::dirichlet_bc(boundary_mesh, zero); - // the number of equations - int N_equations = equation; + // create the body manifold + auto manifold = mito::manifolds::manifold(mesh, coord_system); - channel << "Number of equations: " << equation << journal::endl; + // the function space + auto function_space = mito::discretization::function_space(manifold, constraints); + + // the discrete system + auto discrete_system = mito::discretization::discrete_system(function_space); + const auto & equation_map = discrete_system.equation_map(); + int N_equations = discrete_system.n_equations(); // create a linear system of equations (PETSc Krylov solver) auto solver = mito::solvers::petsc::ksp("mysolver"); solver.initialize(N_equations); solver.set_options("-ksp_type preonly -pc_type cholesky"); - // create the body manifold - auto manifold = mito::manifolds::manifold(mesh, coord_system); - - // the function space - auto function_space = mito::discretization::function_space(manifold); - // the right hand side auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y); @@ -182,6 +146,8 @@ TEST(Fem, PoissonSquare) // finalize the solver solver.finalize(); + // TOFIX: the solution should be assembled by the function space, which is aware of the + // constraints and can populate the constrained nodes appropriately // the numerical solution nodal field on the mesh auto solution = mito::discretization::nodal_field(mesh, "numerical solution"); // fill information in nodal field From bf489cdb9cbe61cb457887a7b195cedaade25e2b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 7 May 2025 10:42:44 +0200 Subject: [PATCH 051/273] discretization: bugfix in {DiscreteSystem} Fix initialization of the number of equations in class {DiscreteSystem}. --- lib/mito/discretization/DiscreteSystem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 1a24a079a..95c6489fb 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -99,7 +99,7 @@ namespace mito::discretization { } // the number of equations - int _n_equations = equation; + _n_equations = equation; // print the number of equations channel << "Number of equations: " << _n_equations << journal::endl; From f7f4403fe4c1310d41c11832d8829144550f0962 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 8 May 2025 15:53:59 +0200 Subject: [PATCH 052/273] discretization: require that the template parameter of class {IsoparametricSimplex} satisfies concept {geometric_simplex_c} --- lib/mito/discretization/IsoparametricSimplex.h | 4 +--- lib/mito/discretization/api.h | 4 ++-- lib/mito/discretization/factories.h | 2 +- lib/mito/discretization/forward.h | 2 +- 4 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index e0f6cad2c..db62375f6 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -12,9 +12,7 @@ namespace mito::discretization { - // TODO: add concept of geometric simplex and require that {geomtricSimplexT} is a geometric - // simplex - template + template class IsoparametricSimplex { private: diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index e5b9a67ef..14a58dfa5 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -34,11 +34,11 @@ namespace mito::discretization { constexpr auto point_field(const cloudT & cloud, std::string name); // isoparametric simplex alias - template + template using isoparametric_simplex_t = IsoparametricSimplex; // isoparametric simplex factory - template + template constexpr auto isoparametric_simplex(); // function space alias diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index e7ebe7434..1c1728056 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -43,7 +43,7 @@ namespace mito::discretization { } // isoparametric simplex factory - template + template constexpr auto isoparametric_simplex() { // build an isoparametric simplex and return it diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 549503fd4..7c47aa7f0 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -14,7 +14,7 @@ namespace mito::discretization { class DiscreteField; // class isoparametric simplex - template + template class IsoparametricSimplex; // class function space From 5eb9250c2ebca077df10d1d3560f9afc189fefe8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 8 May 2025 15:54:53 +0200 Subject: [PATCH 053/273] discretization: fix typo in class {FunctionSpace} --- lib/mito/discretization/FunctionSpace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index e78eccde6..4090eaa46 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -119,7 +119,7 @@ namespace mito::discretization { } private: - // a const reference to the mesh + // a const reference to the manifold const manifold_type & _manifold; // TOFIX: this should be a collection of constraints. Also, constraints may involve From 2c8d47df69f2e39ef43fd97f1db716f9216b863c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 8 May 2025 15:56:04 +0200 Subject: [PATCH 054/273] discretization: fix typo in class {IsoparametricSimplex} --- lib/mito/discretization/IsoparametricSimplex.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index db62375f6..98125b198 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -26,7 +26,7 @@ namespace mito::discretization { using parametric_coordinates_type = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; // type of a point in barycentric coordinates - using barycentric_coordinates_type = geometricSimplexT::barycentric_coordinates_type; + using barycentric_coordinates_type = geometric_simplex_type::barycentric_coordinates_type; // TOFIX: see above using evaluated_shape_functions_type = std::array; using evaluated_shape_functions_gradients_type = std::array, 3>; From 6c9f0189e2b97471f5d13b6363e55e13aca7ca70 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 8 May 2025 15:59:08 +0200 Subject: [PATCH 055/273] discretization: add sanity check in {IsoparametricSimplex} shape, gradient and jacobian --- lib/mito/discretization/IsoparametricSimplex.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index 98125b198..820bcb01a 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -79,6 +79,9 @@ namespace mito::discretization { // get all the shape functions evaluated at the point {xi} in barycentric coordinates auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type { + // check that the barycentric coordinates are valid + assert(1.0 - (xi[0] + xi[1]) == xi[2]); + // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -91,6 +94,9 @@ namespace mito::discretization { auto gradient(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_gradients_type { + // check that the barycentric coordinates are valid + assert(1.0 - (xi[0] + xi[1]) == xi[2]); + // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -103,6 +109,9 @@ namespace mito::discretization { const vector_type & x_0, const vector_type & x_1, const vector_type & x_2, const barycentric_coordinates_type & xi) const { + // check that the barycentric coordinates are valid + assert(1.0 - (xi[0] + xi[1]) == xi[2]); + // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; From 57b6632d14e14531b6a63ffe42d06b7724439b59 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 09:30:00 +0200 Subject: [PATCH 056/273] Revert "discretization: add sanity check in {IsoparametricSimplex} shape, gradient and jacobian" This reverts commit 6c9f0189e2b97471f5d13b6363e55e13aca7ca70. --- lib/mito/discretization/IsoparametricSimplex.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index 820bcb01a..98125b198 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -79,9 +79,6 @@ namespace mito::discretization { // get all the shape functions evaluated at the point {xi} in barycentric coordinates auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type { - // check that the barycentric coordinates are valid - assert(1.0 - (xi[0] + xi[1]) == xi[2]); - // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -94,9 +91,6 @@ namespace mito::discretization { auto gradient(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_gradients_type { - // check that the barycentric coordinates are valid - assert(1.0 - (xi[0] + xi[1]) == xi[2]); - // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -109,9 +103,6 @@ namespace mito::discretization { const vector_type & x_0, const vector_type & x_1, const vector_type & x_2, const barycentric_coordinates_type & xi) const { - // check that the barycentric coordinates are valid - assert(1.0 - (xi[0] + xi[1]) == xi[2]); - // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; From c17c31d52df2c40a2020859452d9b876c77a035a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 09:38:52 +0200 Subject: [PATCH 057/273] discretization: major redesign of {FunctionSpace} and {IsoparametricSimplex} Class {IsoparametricSimplex} is not a {static} class anymore. It now represents a full-fledged discretized simplex with nodes and shape functions. Class {FunctionSpace} now represents a collection of discretized simplices (which have knowledge of the shape functions) equipped with a set of constraints. --- lib/mito/discretization/DiscreteSystem.h | 7 +- lib/mito/discretization/FunctionSpace.h | 91 +++++---------- .../discretization/IsoparametricSimplex.h | 106 ++++++++++++++---- lib/mito/discretization/api.h | 10 +- lib/mito/discretization/factories.h | 8 -- lib/mito/discretization/forward.h | 4 +- lib/mito/discretization/public.h | 2 + lib/mito/discretization/utilities.h | 29 +++++ tests/mito.lib/discretization/poisson.cc | 16 ++- 9 files changed, 158 insertions(+), 115 deletions(-) create mode 100644 lib/mito/discretization/utilities.h diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 95c6489fb..11d6406d8 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -53,12 +53,9 @@ namespace mito::discretization { // make a channel journal::info_t channel("discretization.discrete_system"); - // get the mesh of the function space - const auto & mesh = _function_space.manifold().mesh(); - - // get all the nodes in the mesh + // get all the nodes in the function space std::set nodes; - mito::mesh::get_nodes(mesh, nodes); + get_nodes(_function_space, nodes); channel << "Number of nodes: " << std::size(nodes) << journal::endl; // get the domain that is constrained diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 4090eaa46..5875895ae 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -25,24 +25,31 @@ namespace mito::discretization { using node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; - - private: - // TOFIX: how do we inject this in the class? - // the canonical simplex type - static constexpr auto canonical_element = isoparametric_simplex(); - // type of a point in barycentric coordinates - using barycentric_coordinates_type = cell_type::barycentric_coordinates_type; - // TOFIX - using evaluated_shape_functions_type = std::map; - using evaluated_shape_functions_gradients_type = - std::map>; + // TOFIX: how to properly inject the element type information into the function space? + // typedef for a finite element + using element_type = isoparametric_simplex_t; + // typedef for a collection of finite elements + using elements_type = utilities::segmented_vector_t; public: // the constructor constexpr FunctionSpace( const manifold_type & manifold, const constraints_type & constraints) : - _manifold(manifold), - _constraints(constraints) {}; + _elements(100), + _constraints(constraints) + { + // get the coordinate system of the manifold + const auto & coord_system = manifold.coordinate_system(); + + // loop on the cells of the mesh + for (const auto & cell : manifold.elements()) { + // create a finite element for each cell and add it to the pile + _elements.emplace(cell, coord_system); + } + + // all done + return; + }; // destructor constexpr ~FunctionSpace() = default; @@ -60,67 +67,19 @@ namespace mito::discretization { constexpr FunctionSpace & operator=(FunctionSpace &&) noexcept = delete; public: - // accessor for the manifold - constexpr auto manifold() const noexcept -> const manifold_type & { return _manifold; } - + // TOFIX: not sure this should be constexpr // accessor for the constraints constexpr auto constraints() const noexcept -> const constraints_type & { return _constraints; } - // get all the shape functions of cell {cell} evaluated at the point {xi} in barycentric - // coordinates - auto shape(const cell_type & cell, const barycentric_coordinates_type & xi) const - -> evaluated_shape_functions_type - { - // get the shape functions of the canonical element - auto shape_functions = canonical_element.shape(xi); - - // the nodes of the cell - const auto & nodes = cell.nodes(); - - // return the shape functions evaluated at {xi} - return { { nodes[0], shape_functions[0] }, - { nodes[1], shape_functions[1] }, - { nodes[2], shape_functions[2] } }; - } - - // get all the shape functions gradients evaluated at the point {xi} in barycentric - // coordinates - auto gradient(const cell_type & cell, const barycentric_coordinates_type & xi) const - -> evaluated_shape_functions_gradients_type - { - // the nodes of the cell - const auto & nodes = cell.nodes(); - - // the origin of the coordinate system - auto origin = typename coord_system_type::coordinates_type{}; - - // the coordinates of the nodes of the triangle - auto x_0 = _manifold.coordinates(nodes[0]) - origin; - auto x_1 = _manifold.coordinates(nodes[1]) - origin; - auto x_2 = _manifold.coordinates(nodes[2]) - origin; - - // the jacobian of the mapping from the reference element to the physical element - // evaluated at {xi} - auto J = canonical_element.jacobian(x_0, x_1, x_2, xi); - - // the derivative of the coordinates with respect to the barycentric coordinates - auto J_inv = mito::tensor::inverse(J); - - // get the shape functions derivatives at {xi} - /*constexpr*/ auto dphi = canonical_element.gradient(xi); - - // return the spatial gradients of the shape functions evaluated at {xi} - return { { nodes[0], dphi[0] * J_inv }, - { nodes[1], dphi[1] * J_inv }, - { nodes[2], dphi[2] * J_inv } }; - } + // get the finite elements + auto elements() const noexcept -> const elements_type & { return _elements; } private: - // a const reference to the manifold - const manifold_type & _manifold; + // a collection of finite elements + elements_type _elements; // TOFIX: this should be a collection of constraints. Also, constraints may involve // different degrees of freedom (e.g. periodic boundary conditions to impose relations diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricSimplex.h index 98125b198..2c08aaea3 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricSimplex.h @@ -10,26 +10,43 @@ // DESIGN NOTES // Class {IsoparametricSimplex} represents the reference simplex in the parametric space + +// TODO: rename to IsoparametricTriangle1. IsoparametricTriangle1 and IsoparametricTriangle2 can be +// derived from a common base class IsoparametricTriangle that has the barycentric coordinates types +// and the isoparametric mapping namespace mito::discretization { - template - class IsoparametricSimplex { + template < + geometry::geometric_simplex_c geometricSimplexT, + geometry::coordinate_system_c coordinateSystemT> + class IsoparametricSimplex : public utilities::Invalidatable { private: // the geometric simplex type using geometric_simplex_type = geometricSimplexT; - // the vector type - using vector_type = tensor::vector_t<2>; + // TOFIX: we need to come up with another notion for the discretization node as the + // {geometry::node_t} implies the presence of a vertex the node type + using node_type = typename geometric_simplex_type::node_type; + // the number of discretization nodes + static constexpr int n_nodes = 3; + // a collection of discretization nodes + using nodes_type = std::array; + // the global coordinate system type + using coordinate_system_type = coordinateSystemT; // TOFIX: this should be defined based on the order of the simplex (e.g. 1 for segments, 2 // for triangles, 3 for tetrahedra, etc.) + // the parametric dimension + static constexpr int dim = 2; // the parametric coordinates type using parametric_coordinates_type = - mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; + mito::geometry::coordinates_t; // type of a point in barycentric coordinates using barycentric_coordinates_type = geometric_simplex_type::barycentric_coordinates_type; - // TOFIX: see above - using evaluated_shape_functions_type = std::array; - using evaluated_shape_functions_gradients_type = std::array, 3>; + // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick + // another data structure + using evaluated_shape_functions_type = std::map; + using evaluated_shape_functions_gradients_type = + std::map>; private: // TOFIX: these should be defined based on the order of the element and on the type of @@ -58,7 +75,13 @@ namespace mito::discretization { public: // the default constructor - constexpr IsoparametricSimplex() = default; + constexpr IsoparametricSimplex( + const geometric_simplex_type & geometric_simplex, + const coordinate_system_type & coordinate_system) : + _geometric_simplex(geometric_simplex), + _coordinate_system(coordinate_system), + _nodes{ geometric_simplex.nodes() } + {} // destructor constexpr ~IsoparametricSimplex() = default; @@ -76,6 +99,15 @@ namespace mito::discretization { constexpr IsoparametricSimplex & operator=(IsoparametricSimplex &&) noexcept = delete; public: + // get the geometric simplex + constexpr auto geometric_simplex() const noexcept -> const geometric_simplex_type & + { + return _geometric_simplex; + } + + // get the nodes + constexpr auto nodes() const noexcept -> const nodes_type & { return _nodes; } + // get all the shape functions evaluated at the point {xi} in barycentric coordinates auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type { @@ -83,26 +115,22 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the shape functions evaluated at {xi} - return { std::get<0>(phi)(xi_p), std::get<1>(phi)(xi_p), std::get<2>(phi)(xi_p) }; + return { { _nodes[0], std::get<0>(phi)(xi_p) }, + { _nodes[1], std::get<1>(phi)(xi_p) }, + { _nodes[2], std::get<2>(phi)(xi_p) } }; } - // get all the shape functions gradients evaluated at the point {xi} in barycentric - // coordinates - auto gradient(const barycentric_coordinates_type & xi) const - -> evaluated_shape_functions_gradients_type + // get the jacobian of the isoparametric mapping from barycentric to actual coordinates + constexpr auto jacobian(const barycentric_coordinates_type & xi) const { - // the parametric coordinates of the quadrature point - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // the origin of the coordinate system + auto origin = typename coordinate_system_type::coordinates_type{}; - // return the shape functions gradients evaluated at {xi} - return { std::get<0>(dphi)(xi_p), std::get<1>(dphi)(xi_p), std::get<2>(dphi)(xi_p) }; - } + // the coordinates of the nodes of the triangle + auto x_0 = _coordinate_system.coordinates(_nodes[0]->point()) - origin; + auto x_1 = _coordinate_system.coordinates(_nodes[1]->point()) - origin; + auto x_2 = _coordinate_system.coordinates(_nodes[2]->point()) - origin; - // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - constexpr auto jacobian( - const vector_type & x_0, const vector_type & x_1, const vector_type & x_2, - const barycentric_coordinates_type & xi) const - { // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; @@ -110,11 +138,41 @@ namespace mito::discretization { // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // compute the gradient of the isoparametric mapping auto J = mito::fields::gradient(x_cell)(xi_p); // return the jacobian of the isoparametric mapping return J; } + + // get all the shape functions gradients evaluated at the point {xi} in barycentric + // coordinates + auto gradient(const barycentric_coordinates_type & xi) const + -> evaluated_shape_functions_gradients_type + { + // 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 barycentric coordinates + auto J_inv = mito::tensor::inverse(J); + + // the parametric coordinates of the quadrature point + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + + // return the spatial gradients of the shape functions evaluated at {xi} + return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv } }; + } + + private: + // a const reference to the geometric simplex + const geometric_simplex_type & _geometric_simplex; + // a const reference to the coordinate system + const coordinate_system_type & _coordinate_system; + // the nodes of the simplex + const nodes_type _nodes; }; } // namespace mito diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 14a58dfa5..1897558c3 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -34,12 +34,10 @@ namespace mito::discretization { constexpr auto point_field(const cloudT & cloud, std::string name); // isoparametric simplex alias - template - using isoparametric_simplex_t = IsoparametricSimplex; - - // isoparametric simplex factory - template - constexpr auto isoparametric_simplex(); + template < + geometry::geometric_simplex_c geometricSimplexT, + geometry::coordinate_system_c coordinateSystemT> + using isoparametric_simplex_t = IsoparametricSimplex; // function space alias template diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 1c1728056..1d81f8da5 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -42,14 +42,6 @@ namespace mito::discretization { return point_field_t(cloud.points(), name); } - // isoparametric simplex factory - template - constexpr auto isoparametric_simplex() - { - // build an isoparametric simplex and return it - return isoparametric_simplex_t(); - } - // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a // single constraint // function space factory diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 7c47aa7f0..63816e029 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -14,7 +14,9 @@ namespace mito::discretization { class DiscreteField; // class isoparametric simplex - template + template < + geometry::geometric_simplex_c geometricSimplexT, + geometry::coordinate_system_c coordinateSystemT> class IsoparametricSimplex; // class function space diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 3caff8ee8..29aa83c81 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -25,5 +25,7 @@ // factories implementation #include "factories.h" +// utilities implementation +#include "utilities.h" // end of file diff --git a/lib/mito/discretization/utilities.h b/lib/mito/discretization/utilities.h new file mode 100644 index 000000000..273b44de4 --- /dev/null +++ b/lib/mito/discretization/utilities.h @@ -0,0 +1,29 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + // populate a container with a collection of all nodes in a function space + template + inline auto get_nodes(const functionSpaceT & function_space, nodesCollectionT & nodes) -> void + { + for (const auto & element : function_space.elements()) { + for (const auto & node : element.nodes()) { + nodes.insert(node); + } + } + + // all done + return; + } + +} + + +// end of file diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index a2296a8e0..190ee846d 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -77,7 +77,11 @@ TEST(Fem, PoissonSquare) // channel << "Right hand side: " << f(coordinates_t{ 0.5, 0.5 }) << journal::endl; // loop on all the cells of the mesh - for (const auto & cell : manifold.elements()) { + for (const auto & element : function_space.elements()) { + + // QUESTION: is accessing the geometric simplex really needed? + // get the corresponding cell + const auto & cell = element.geometric_simplex(); // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -89,7 +93,7 @@ TEST(Fem, PoissonSquare) auto factor = quadrature_rule.weight(q) * manifold.volume(cell); // evaluate the spatial gradients of the element shape functions at {xi} - auto dphi = function_space.gradient(cell, xi); + auto dphi = element.gradient(xi); // populate the linear system of equations for (const auto & [node_a, dphi_a] : dphi) { @@ -116,7 +120,7 @@ TEST(Fem, PoissonSquare) } // evaluate the element shape functions at {xi} - auto phi = function_space.shape(cell, xi); + auto phi = element.shape(xi); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); @@ -198,7 +202,9 @@ TEST(Fem, PoissonSquare) // compute the error auto error_L2 = 0.0; // loop on all the cells of the mesh - for (const auto & cell : manifold.elements()) { + for (const auto & element : function_space.elements()) { + // get the corresponding cell + const auto & cell = element.geometric_simplex(); // volume of the cell auto volume = manifold.volume(cell); // loop on the quadrature points @@ -206,7 +212,7 @@ TEST(Fem, PoissonSquare) // the barycentric coordinates of the quadrature point /*constexpr*/ auto xi = quadrature_rule.point(q); // evaluate the element shape functions at {xi} - auto phi = function_space.shape(cell, xi); + auto phi = element.shape(xi); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // get the exact solution at {coord} From b93d4131e2a80e9542b7ac54503cf044436bb64f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 10:14:24 +0200 Subject: [PATCH 058/273] discretization: improve injection of the element type in the {FunctionSpace} class --- lib/mito/discretization/FunctionSpace.h | 6 ++-- ...tricSimplex.h => IsoparametricTriangle1.h} | 17 +++++----- lib/mito/discretization/api.h | 5 --- lib/mito/discretization/forward.h | 2 +- .../isoparametric_simplex_library.h | 31 +++++++++++++++++++ lib/mito/discretization/public.h | 3 +- 6 files changed, 47 insertions(+), 17 deletions(-) rename lib/mito/discretization/{IsoparametricSimplex.h => IsoparametricTriangle1.h} (91%) create mode 100644 lib/mito/discretization/isoparametric_simplex_library.h diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 5875895ae..269d46e95 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -25,9 +25,11 @@ namespace mito::discretization { using node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; - // TOFIX: how to properly inject the element type information into the function space? + // TOFIX: order and degree are hard coded here for now. Eventually, we should make them + // template parameters for the class // typedef for a finite element - using element_type = isoparametric_simplex_t; + using element_type = + typename isoparametric_simplex<2, 1, cell_type, coord_system_type>::type; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; diff --git a/lib/mito/discretization/IsoparametricSimplex.h b/lib/mito/discretization/IsoparametricTriangle1.h similarity index 91% rename from lib/mito/discretization/IsoparametricSimplex.h rename to lib/mito/discretization/IsoparametricTriangle1.h index 2c08aaea3..f025dacc4 100644 --- a/lib/mito/discretization/IsoparametricSimplex.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -8,7 +8,8 @@ // DESIGN NOTES -// Class {IsoparametricSimplex} represents the reference simplex in the parametric space +// Class {IsoparametricTriangle1} represents a second order simplex equipped with linear shape +// functions defined in the parametric space. // TODO: rename to IsoparametricTriangle1. IsoparametricTriangle1 and IsoparametricTriangle2 can be @@ -19,7 +20,7 @@ namespace mito::discretization { template < geometry::geometric_simplex_c geometricSimplexT, geometry::coordinate_system_c coordinateSystemT> - class IsoparametricSimplex : public utilities::Invalidatable { + class IsoparametricTriangle1 : public utilities::Invalidatable { private: // the geometric simplex type @@ -75,7 +76,7 @@ namespace mito::discretization { public: // the default constructor - constexpr IsoparametricSimplex( + constexpr IsoparametricTriangle1( const geometric_simplex_type & geometric_simplex, const coordinate_system_type & coordinate_system) : _geometric_simplex(geometric_simplex), @@ -84,19 +85,19 @@ namespace mito::discretization { {} // destructor - constexpr ~IsoparametricSimplex() = default; + constexpr ~IsoparametricTriangle1() = default; // delete move constructor - constexpr IsoparametricSimplex(IsoparametricSimplex &&) noexcept = delete; + constexpr IsoparametricTriangle1(IsoparametricTriangle1 &&) noexcept = delete; // delete copy constructor - constexpr IsoparametricSimplex(const IsoparametricSimplex &) = delete; + constexpr IsoparametricTriangle1(const IsoparametricTriangle1 &) = delete; // delete assignment operator - constexpr IsoparametricSimplex & operator=(const IsoparametricSimplex &) = delete; + constexpr IsoparametricTriangle1 & operator=(const IsoparametricTriangle1 &) = delete; // delete move assignment operator - constexpr IsoparametricSimplex & operator=(IsoparametricSimplex &&) noexcept = delete; + constexpr IsoparametricTriangle1 & operator=(IsoparametricTriangle1 &&) noexcept = delete; public: // get the geometric simplex diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 1897558c3..99a6845e9 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -33,11 +33,6 @@ namespace mito::discretization { template constexpr auto point_field(const cloudT & cloud, std::string name); - // isoparametric simplex alias - template < - geometry::geometric_simplex_c geometricSimplexT, - geometry::coordinate_system_c coordinateSystemT> - using isoparametric_simplex_t = IsoparametricSimplex; // function space alias template diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 63816e029..9d0569465 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -17,7 +17,7 @@ namespace mito::discretization { template < geometry::geometric_simplex_c geometricSimplexT, geometry::coordinate_system_c coordinateSystemT> - class IsoparametricSimplex; + class IsoparametricTriangle1; // class function space template diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h new file mode 100644 index 000000000..f6624c616 --- /dev/null +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -0,0 +1,31 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + // struct storing the type of an isoparametric simplex of order {order} and polynomial degree + // {degree} on a geometric simplex of type {geometricSimplexT} and coordinate system + // {coordinateSystemT} + template < + int order, int degree, geometry::geometric_simplex_c geometricSimplexT, + geometry::coordinate_system_c coordinateSystemT> + struct isoparametric_simplex {}; + + // linear shape functions on triangles + template < + geometry::geometric_simplex_c geometricSimplexT, + geometry::coordinate_system_c coordinateSystemT> + struct isoparametric_simplex<2, 1, geometricSimplexT, coordinateSystemT> { + using type = IsoparametricTriangle1; + }; + +} + + +// end of file diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 29aa83c81..83676f753 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -18,7 +18,8 @@ // classes implementation #include "DiscreteField.h" -#include "IsoparametricSimplex.h" +#include "IsoparametricTriangle1.h" +#include "isoparametric_simplex_library.h" #include "FunctionSpace.h" #include "DiscreteSystem.h" From 650c111d01bc70bcba942b7d24ea296f2b0143ee Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 10:24:57 +0200 Subject: [PATCH 059/273] discretization: remove redundant specification of the isoparametric simplex {order} in the {isoparametric_simplex} struct The simplex order information is already contained in the geometric simplex type template parameter. --- lib/mito/discretization/FunctionSpace.h | 5 ++--- .../discretization/IsoparametricTriangle1.h | 3 +++ .../isoparametric_simplex_library.h | 20 +++++++++---------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 269d46e95..d708f4178 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -25,11 +25,10 @@ namespace mito::discretization { using node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; - // TOFIX: order and degree are hard coded here for now. Eventually, we should make them + // TOFIX: polynomial degree is hard coded here for now. Eventually, we should make them // template parameters for the class // typedef for a finite element - using element_type = - typename isoparametric_simplex<2, 1, cell_type, coord_system_type>::type; + using element_type = typename isoparametric_simplex<1, cell_type, coord_system_type>::type; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index f025dacc4..26b2513cd 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -17,6 +17,9 @@ // and the isoparametric mapping namespace mito::discretization { + // QUESTION: should we enforce the use of a cartesian coordinate system for this type of + // isoparametric simplex? In this case, the coordinate system type can be sinthesized from the + // geometric simplex type (which has knowledge of the dimension of the embedding space) template < geometry::geometric_simplex_c geometricSimplexT, geometry::coordinate_system_c coordinateSystemT> diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h index f6624c616..2c7c3805a 100644 --- a/lib/mito/discretization/isoparametric_simplex_library.h +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -9,22 +9,22 @@ namespace mito::discretization { - // struct storing the type of an isoparametric simplex of order {order} and polynomial degree - // {degree} on a geometric simplex of type {geometricSimplexT} and coordinate system - // {coordinateSystemT} + // TOFIX: add requirement that the geometric simplex spatial dimension matches that of the + // coordinate system + // struct storing the type of an isoparametric simplex of polynomial degree {degree} on a + // geometric simplex of type {geometricSimplexT} and coordinate system {coordinateSystemT} template < - int order, int degree, geometry::geometric_simplex_c geometricSimplexT, + int degree, geometry::geometric_simplex_c geometricSimplexT, geometry::coordinate_system_c coordinateSystemT> struct isoparametric_simplex {}; // linear shape functions on triangles - template < - geometry::geometric_simplex_c geometricSimplexT, - geometry::coordinate_system_c coordinateSystemT> - struct isoparametric_simplex<2, 1, geometricSimplexT, coordinateSystemT> { - using type = IsoparametricTriangle1; + template + struct isoparametric_simplex< + 1, geometry::triangle_t, coordinateSystemT> { + using type = + IsoparametricTriangle1, coordinateSystemT>; }; - } From f6f1ef2e569bb02256cc5c151f840b1ea2a42fc0 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 10:26:34 +0200 Subject: [PATCH 060/273] discretization: formatting edit --- lib/mito/discretization/api.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 99a6845e9..8d8eb3a0a 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -33,7 +33,6 @@ namespace mito::discretization { template constexpr auto point_field(const cloudT & cloud, std::string name); - // function space alias template using function_space_t = FunctionSpace; From 2b79f9eb7fdb5257ee537d32d1170650693cdaa7 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 10:31:02 +0200 Subject: [PATCH 061/273] discretization: the order of the finite elements is now a template parameter of class {FunctionSpace} --- lib/mito/discretization/FunctionSpace.h | 11 +++++++---- lib/mito/discretization/api.h | 4 ++-- lib/mito/discretization/factories.h | 4 ++-- lib/mito/discretization/forward.h | 2 +- tests/mito.lib/discretization/poisson.cc | 4 ++-- 5 files changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index d708f4178..d82140b19 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -9,7 +9,9 @@ namespace mito::discretization { - template + // Class {FunctionSpace} represents a collection of finite elements of order {p} defined on a + // manifold and subjected to a set of constraints. + template class FunctionSpace { public: @@ -25,10 +27,11 @@ namespace mito::discretization { using node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; - // TOFIX: polynomial degree is hard coded here for now. Eventually, we should make them - // template parameters for the class + // the order of the finite element + static constexpr int order = p; // typedef for a finite element - using element_type = typename isoparametric_simplex<1, cell_type, coord_system_type>::type; + using element_type = + typename isoparametric_simplex::type; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 8d8eb3a0a..3f1cd51f5 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -34,8 +34,8 @@ namespace mito::discretization { constexpr auto point_field(const cloudT & cloud, std::string name); // function space alias - template - using function_space_t = FunctionSpace; + template + using function_space_t = FunctionSpace; // function space factory template diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 1d81f8da5..de0e335b8 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -45,11 +45,11 @@ namespace mito::discretization { // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a // single constraint // function space factory - template + template constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) { // build a function space on the manifold and return it - return function_space_t(manifold, constraints); + return function_space_t(manifold, constraints); } // discrete system factory diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 9d0569465..62feebd03 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -20,7 +20,7 @@ namespace mito::discretization { class IsoparametricTriangle1; // class function space - template + template class FunctionSpace; // class discrete system diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 190ee846d..b0e55dedf 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -58,8 +58,8 @@ TEST(Fem, PoissonSquare) // create the body manifold auto manifold = mito::manifolds::manifold(mesh, coord_system); - // the function space - auto function_space = mito::discretization::function_space(manifold, constraints); + // the function space (linear elements on the manifold) + auto function_space = mito::discretization::function_space<1>(manifold, constraints); // the discrete system auto discrete_system = mito::discretization::discrete_system(function_space); From 50f5ef30cfc9bf9ccbec27488e5802a772b2346d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 10:33:34 +0200 Subject: [PATCH 062/273] discretization: add requirement that the geometric simplex spatial dimension matches that of the coordinate system in struct {isoparametric_simplex} --- lib/mito/discretization/isoparametric_simplex_library.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h index 2c7c3805a..b215d358d 100644 --- a/lib/mito/discretization/isoparametric_simplex_library.h +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -9,13 +9,13 @@ namespace mito::discretization { - // TOFIX: add requirement that the geometric simplex spatial dimension matches that of the - // coordinate system // struct storing the type of an isoparametric simplex of polynomial degree {degree} on a // geometric simplex of type {geometricSimplexT} and coordinate system {coordinateSystemT} template < int degree, geometry::geometric_simplex_c geometricSimplexT, geometry::coordinate_system_c coordinateSystemT> + // require that the geometric simplex spatial dimension matches that of the coordinate system + requires(coordinateSystemT::dim == geometricSimplexT::dim) struct isoparametric_simplex {}; // linear shape functions on triangles From 4bd57ee64dc1688242b178b889e1588ff190939e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 11:08:12 +0200 Subject: [PATCH 063/273] discretization: minor redesign of isoparametric triangles Class {IsoparametricTriangle1} is split into two classes: {IsoparametricTriangle} represents a second order simplex in parametric space, while class {IsoparametricTriangle1} equips the triangle with the (linear) shape functions. --- .../discretization/IsoparametricTriangle.h | 77 +++++++++++++++++++ .../discretization/IsoparametricTriangle1.h | 72 ++++++++--------- lib/mito/discretization/public.h | 1 + 3 files changed, 108 insertions(+), 42 deletions(-) create mode 100644 lib/mito/discretization/IsoparametricTriangle.h diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h new file mode 100644 index 000000000..017368c9f --- /dev/null +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -0,0 +1,77 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// DESIGN NOTES +// Class {IsoparametricTriangle} represents a second order simplex equipped parametric coordinates. + + +namespace mito::discretization { + + + template + class IsoparametricTriangle : public utilities::Invalidatable { + + protected: + // the geometric simplex type + using geometric_simplex_type = geometricSimplexT; + // the parametric dimension + static constexpr int dim = 2; + // the parametric coordinates type + using parametric_coordinates_type = + mito::geometry::coordinates_t; + + protected: + // TOFIX: these should be defined based on the order of the element and on the type of + // simplex (for example here it's 3 of them because we use linear elements on a triangle) + // the function extracting the 0 component of a parametric point + static constexpr auto xi_0 = + mito::fields::field(mito::functions::component); + // the function extracting the 1 component of a parametric point + static constexpr auto xi_1 = + mito::fields::field(mito::functions::component); + // the function extracting the 2 component of a parametric point + static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; + + public: + // the default constructor + constexpr IsoparametricTriangle(const geometric_simplex_type & geometric_simplex) : + _geometric_simplex(geometric_simplex) + {} + + // destructor + constexpr ~IsoparametricTriangle() = default; + + // delete move constructor + constexpr IsoparametricTriangle(IsoparametricTriangle &&) noexcept = delete; + + // delete copy constructor + constexpr IsoparametricTriangle(const IsoparametricTriangle &) = delete; + + // delete assignment operator + constexpr IsoparametricTriangle & operator=(const IsoparametricTriangle &) = delete; + + // delete move assignment operator + constexpr IsoparametricTriangle & operator=(IsoparametricTriangle &&) noexcept = delete; + + public: + // get the geometric simplex + constexpr auto geometric_simplex() const noexcept -> const geometric_simplex_type & + { + return _geometric_simplex; + } + + protected: + // a const reference to the geometric simplex + const geometric_simplex_type & _geometric_simplex; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 26b2513cd..aadbb1c28 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -12,9 +12,6 @@ // functions defined in the parametric space. -// TODO: rename to IsoparametricTriangle1. IsoparametricTriangle1 and IsoparametricTriangle2 can be -// derived from a common base class IsoparametricTriangle that has the barycentric coordinates types -// and the isoparametric mapping namespace mito::discretization { // QUESTION: should we enforce the use of a cartesian coordinate system for this type of @@ -23,11 +20,22 @@ namespace mito::discretization { template < geometry::geometric_simplex_c geometricSimplexT, geometry::coordinate_system_c coordinateSystemT> - class IsoparametricTriangle1 : public utilities::Invalidatable { + class IsoparametricTriangle1 : public IsoparametricTriangle { private: // the geometric simplex type using geometric_simplex_type = geometricSimplexT; + // the global coordinate system type + using coordinate_system_type = coordinateSystemT; + // the base class + using isoparametric_triangle_type = IsoparametricTriangle; + // the parametric coordinates type + using parametric_coordinates_type = + typename isoparametric_triangle_type::parametric_coordinates_type; + + private: + // the point type + using point_type = typename coordinate_system_type::point_type; // TOFIX: we need to come up with another notion for the discretization node as the // {geometry::node_t} implies the presence of a vertex the node type using node_type = typename geometric_simplex_type::node_type; @@ -35,39 +43,20 @@ namespace mito::discretization { static constexpr int n_nodes = 3; // a collection of discretization nodes using nodes_type = std::array; - // the global coordinate system type - using coordinate_system_type = coordinateSystemT; - // TOFIX: this should be defined based on the order of the simplex (e.g. 1 for segments, 2 - // for triangles, 3 for tetrahedra, etc.) - // the parametric dimension - static constexpr int dim = 2; - // the parametric coordinates type - using parametric_coordinates_type = - mito::geometry::coordinates_t; // type of a point in barycentric coordinates - using barycentric_coordinates_type = geometric_simplex_type::barycentric_coordinates_type; + using barycentric_coordinates_type = + typename geometric_simplex_type::barycentric_coordinates_type; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure using evaluated_shape_functions_type = std::map; using evaluated_shape_functions_gradients_type = - std::map>; + std::map>; private: - // TOFIX: these should be defined based on the order of the element and on the type of - // simplex (for example here it's 3 of them because we use linear elements on a triangle) - // the function extracting the 0 component of a parametric point - static constexpr auto xi_0 = - mito::fields::field(mito::functions::component); - // the function extracting the 1 component of a parametric point - static constexpr auto xi_1 = - mito::fields::field(mito::functions::component); - // the function extracting the 2 component of a parametric point - static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; - // linear shape functions on the triangle - static constexpr auto phi_0 = xi_0; - static constexpr auto phi_1 = xi_1; - static constexpr auto phi_2 = xi_2; + static constexpr auto phi_0 = isoparametric_triangle_type::xi_0; + static constexpr auto phi_1 = isoparametric_triangle_type::xi_1; + static constexpr auto phi_2 = isoparametric_triangle_type::xi_2; // the shape functions static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); @@ -82,7 +71,7 @@ namespace mito::discretization { constexpr IsoparametricTriangle1( const geometric_simplex_type & geometric_simplex, const coordinate_system_type & coordinate_system) : - _geometric_simplex(geometric_simplex), + IsoparametricTriangle(geometric_simplex), _coordinate_system(coordinate_system), _nodes{ geometric_simplex.nodes() } {} @@ -102,13 +91,17 @@ namespace mito::discretization { // delete move assignment operator constexpr IsoparametricTriangle1 & operator=(IsoparametricTriangle1 &&) noexcept = delete; - public: - // get the geometric simplex - constexpr auto geometric_simplex() const noexcept -> const geometric_simplex_type & + private: + // get the coordinates of a point + constexpr auto coordinates(const point_type & point) const noexcept { - return _geometric_simplex; + // the origin of the coordinate system + auto origin = typename coordinate_system_type::coordinates_type{}; + // delegate to the coordinate system + return _coordinate_system.coordinates(point) - origin; } + public: // get the nodes constexpr auto nodes() const noexcept -> const nodes_type & { return _nodes; } @@ -127,13 +120,10 @@ namespace mito::discretization { // get the jacobian of the isoparametric mapping from barycentric to actual coordinates constexpr auto jacobian(const barycentric_coordinates_type & xi) const { - // the origin of the coordinate system - auto origin = typename coordinate_system_type::coordinates_type{}; - // the coordinates of the nodes of the triangle - auto x_0 = _coordinate_system.coordinates(_nodes[0]->point()) - origin; - auto x_1 = _coordinate_system.coordinates(_nodes[1]->point()) - origin; - auto x_2 = _coordinate_system.coordinates(_nodes[2]->point()) - origin; + auto x_0 = coordinates(_nodes[0]->point()); + auto x_1 = coordinates(_nodes[1]->point()); + auto x_2 = coordinates(_nodes[2]->point()); // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} @@ -171,8 +161,6 @@ namespace mito::discretization { } private: - // a const reference to the geometric simplex - const geometric_simplex_type & _geometric_simplex; // a const reference to the coordinate system const coordinate_system_type & _coordinate_system; // the nodes of the simplex diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 83676f753..877cbf49e 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -18,6 +18,7 @@ // classes implementation #include "DiscreteField.h" +#include "IsoparametricTriangle.h" #include "IsoparametricTriangle1.h" #include "isoparametric_simplex_library.h" #include "FunctionSpace.h" From f1aecca44db607ee495445968f597bff2270a594 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 12 May 2025 14:03:20 +0200 Subject: [PATCH 064/273] geometry: remove obsolete implementation of {operator==} for {GeometricSimplex} of order 0 --- lib/mito/geometry/GeometricSimplex.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/lib/mito/geometry/GeometricSimplex.h b/lib/mito/geometry/GeometricSimplex.h index 6df65337b..2f95056fb 100644 --- a/lib/mito/geometry/GeometricSimplex.h +++ b/lib/mito/geometry/GeometricSimplex.h @@ -196,14 +196,6 @@ namespace mito::geometry { point_type _point; }; - // operator== for nodes - template - constexpr auto operator==( - const GeometricSimplex<0, D> & node_a, const GeometricSimplex<0, D> & node_b) -> bool - { - // two nodes are the same if they have the same id - return node_a.id() == node_b.id(); - } } From cad60187e2b158b89790d242b4fedaf5f6921256 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 14 May 2025 20:02:38 +0200 Subject: [PATCH 065/273] discretization: major redesign of {FunctionSpace} based on the concept of discretization node This commit introduces the notion of {DiscretizationNode} as separate from mesh node. While a mesh node is a pairing of a mesh vertex with a point, a {DiscretizationNode} may or may not correspond to a vertex. For example, in higher order discretizations, we have discretization nodes internal to (sub)simplices. Also, in case of discontinuous finite elements, we may have several discretization nodes for each mesh node. Class {DiscretizationNode} is for now an empty class, only used to store the node label (which corresponds to the memory address of the node instance). --- lib/mito/constraints/Dirichlet.h | 9 --- lib/mito/discretization/DiscreteSystem.h | 6 +- lib/mito/discretization/DiscretizationNode.h | 42 +++++++++++ lib/mito/discretization/FunctionSpace.h | 74 ++++++++++++++++++- .../discretization/IsoparametricTriangle1.h | 58 +++++++-------- lib/mito/discretization/api.h | 3 + lib/mito/discretization/externals.h | 1 + lib/mito/discretization/forward.h | 3 + lib/mito/discretization/public.h | 1 + tests/mito.lib/discretization/poisson.cc | 13 +++- 10 files changed, 160 insertions(+), 50 deletions(-) create mode 100644 lib/mito/discretization/DiscretizationNode.h diff --git a/lib/mito/constraints/Dirichlet.h b/lib/mito/constraints/Dirichlet.h index 8c8042657..7feb05a34 100644 --- a/lib/mito/constraints/Dirichlet.h +++ b/lib/mito/constraints/Dirichlet.h @@ -36,15 +36,6 @@ namespace mito::constraints { auto domain() const -> const domain_type & { return _domain; } auto function() const -> const function_type & { return _function; } - // get the constrained nodes - auto nodes() const -> nodes_type - { - // get all the nodes in the domain - nodes_type nodes; - mito::mesh::get_nodes(_domain, nodes); - return nodes; - } - private: const domain_type & _domain; function_type _function; diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 11d6406d8..6ec610fda 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -16,7 +16,7 @@ namespace mito::discretization { // the function space type using function_space_type = functionSpaceT; // the type of node - using node_type = typename function_space_type::node_type; + using node_type = typename function_space_type::discretization_node_type; // QUESTION: is std::map the best choice for {equation_map_type}? // the equation map type (map associating an equation number to each node degree of freedom) using equation_map_type = std::map; @@ -58,8 +58,8 @@ namespace mito::discretization { get_nodes(_function_space, nodes); channel << "Number of nodes: " << std::size(nodes) << journal::endl; - // get the domain that is constrained - const auto & constrained_nodes = _function_space.constraints().nodes(); + // get the constrained nodes in the function space + const auto & constrained_nodes = _function_space.constrained_nodes(); channel << "Number of constrained nodes: " << std::size(constrained_nodes) << journal::endl; diff --git a/lib/mito/discretization/DiscretizationNode.h b/lib/mito/discretization/DiscretizationNode.h new file mode 100644 index 000000000..1ab3a80c0 --- /dev/null +++ b/lib/mito/discretization/DiscretizationNode.h @@ -0,0 +1,42 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + + +// code guard +#pragma once + +/* + * This class represents a discretization node in D-dimensional space. + * + */ + +namespace mito::discretization { + + class DiscretizationNode : public utilities::Invalidatable { + + public: + // default constructor + constexpr DiscretizationNode() = default; + + // move constructor + constexpr DiscretizationNode(DiscretizationNode &&) noexcept = default; + + // copy constructor + constexpr DiscretizationNode(const DiscretizationNode &) = default; + + // destructor + constexpr ~DiscretizationNode() = default; + + // default assignment operator + constexpr DiscretizationNode & operator=(const DiscretizationNode &) = default; + + // default move assignment operator + constexpr DiscretizationNode & operator=(DiscretizationNode &&) noexcept = default; + }; + +} + + +// end of file diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index d82140b19..54e3b5e89 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -23,8 +23,8 @@ namespace mito::discretization { using mesh_type = typename manifold_type::mesh_type; // the cell type using cell_type = typename mesh_type::cell_type; - // the node type - using node_type = typename cell_type::node_type; + // the mesh node type + using mesh_node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; // the order of the finite element @@ -34,21 +34,66 @@ namespace mito::discretization { typename isoparametric_simplex::type; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; + // the node type + using discretization_node_type = typename element_type::node_type; + // the nodes type + using discretization_nodes_type = typename element_type::nodes_type; + // the constrained nodes type + using constrained_nodes_type = std::set; + + private: + // the type of a map between the mesh nodes and discretization nodes + using map_type = std::unordered_map< + mesh_node_type, discretization_node_type, utilities::hash_function>; + public: // the constructor constexpr FunctionSpace( const manifold_type & manifold, const constraints_type & constraints) : _elements(100), - _constraints(constraints) + _constraints(constraints), + _node_map() { // get the coordinate system of the manifold const auto & coord_system = manifold.coordinate_system(); // loop on the cells of the mesh for (const auto & cell : manifold.elements()) { + + // get the nodes of the cell + const auto & nodes = cell.nodes(); + + // the origin of the coordinate system + auto origin = typename coord_system_type::coordinates_type{}; + + // the coordinates of the nodes of the triangle + auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; + auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; + auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; + + // add the nodes to the map (if the mesh node is already present in the map, then + // the present discretization node is used) + auto node_0 = + _node_map.insert({ nodes[0], discretization_node_type() }).first->second; + auto node_1 = + _node_map.insert({ nodes[1], discretization_node_type() }).first->second; + auto node_2 = + _node_map.insert({ nodes[2], discretization_node_type() }).first->second; + // create a finite element for each cell and add it to the pile - _elements.emplace(cell, coord_system); + _elements.emplace( + cell, discretization_nodes_type{ node_0, node_1, node_2 }, x_0, x_1, x_2); + } + + // populate the constrained nodes + for (const auto & cell : constraints.domain().cells()) { + for (const auto & node : cell.nodes()) { + // get the discretization node associated with the mesh node from the map + auto it = _node_map.find(node); + // add the node to the constrained nodes + _constrained_nodes.insert(it->second); + } } // all done @@ -81,6 +126,15 @@ namespace mito::discretization { // get the finite elements auto elements() const noexcept -> const elements_type & { return _elements; } + // get the constrained nodes + constexpr auto constrained_nodes() const noexcept -> const constrained_nodes_type & + { + return _constrained_nodes; + } + + // accessor for the node map + constexpr auto node_map() const noexcept -> const map_type & { return _node_map; } + private: // a collection of finite elements elements_type _elements; @@ -90,8 +144,20 @@ namespace mito::discretization { // between beam rotations). Therefore, the function space should be aware of the spatial // dimension of the shape functions. // + // QUESTION: do we need to maintain a reference to the constraints? + // // the constraints const constraints_type & _constraints; + + // the constrained nodes + constrained_nodes_type _constrained_nodes; + + // QUESTION: the reason why we need this map is to write the solution in the vtk writer file + // (we need to know how the solution maps to the mesh nodes). I am not sure this is a good + // reason to build and store this map, though. Also, if we plan to keep this map, we should + // come up with a better name + // a map between the mesh nodes and discretization nodes + map_type _node_map; }; } // namespace mito diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index aadbb1c28..d553e8b73 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -22,6 +22,16 @@ namespace mito::discretization { geometry::coordinate_system_c coordinateSystemT> class IsoparametricTriangle1 : public IsoparametricTriangle { + public: + // the number of discretization nodes + static constexpr int n_nodes = 3; + // the number of vertices + static constexpr int n_vertices = 3; + // the node type + using node_type = discretization_node_t; + // a collection of discretization nodes + using nodes_type = std::array; + private: // the geometric simplex type using geometric_simplex_type = geometricSimplexT; @@ -34,15 +44,8 @@ namespace mito::discretization { typename isoparametric_triangle_type::parametric_coordinates_type; private: - // the point type - using point_type = typename coordinate_system_type::point_type; - // TOFIX: we need to come up with another notion for the discretization node as the - // {geometry::node_t} implies the presence of a vertex the node type - using node_type = typename geometric_simplex_type::node_type; - // the number of discretization nodes - static constexpr int n_nodes = 3; - // a collection of discretization nodes - using nodes_type = std::array; + // + using vector_type = tensor::vector_t; // type of a point in barycentric coordinates using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; @@ -69,11 +72,13 @@ namespace mito::discretization { public: // the default constructor constexpr IsoparametricTriangle1( - const geometric_simplex_type & geometric_simplex, - const coordinate_system_type & coordinate_system) : + const geometric_simplex_type & geometric_simplex, const nodes_type & nodes, + const vector_type & x0, const vector_type & x1, const vector_type & x2) : IsoparametricTriangle(geometric_simplex), - _coordinate_system(coordinate_system), - _nodes{ geometric_simplex.nodes() } + _nodes(nodes), + _x0(x0), + _x1(x1), + _x2(x2) {} // destructor @@ -91,16 +96,6 @@ namespace mito::discretization { // delete move assignment operator constexpr IsoparametricTriangle1 & operator=(IsoparametricTriangle1 &&) noexcept = delete; - private: - // get the coordinates of a point - constexpr auto coordinates(const point_type & point) const noexcept - { - // the origin of the coordinate system - auto origin = typename coordinate_system_type::coordinates_type{}; - // delegate to the coordinate system - return _coordinate_system.coordinates(point) - origin; - } - public: // get the nodes constexpr auto nodes() const noexcept -> const nodes_type & { return _nodes; } @@ -120,14 +115,9 @@ namespace mito::discretization { // get the jacobian of the isoparametric mapping from barycentric to actual coordinates constexpr auto jacobian(const barycentric_coordinates_type & xi) const { - // the coordinates of the nodes of the triangle - auto x_0 = coordinates(_nodes[0]->point()); - auto x_1 = coordinates(_nodes[1]->point()); - auto x_2 = coordinates(_nodes[2]->point()); - // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} - auto x_cell = x_0 * phi_0 + x_1 * phi_1 + x_2 * phi_2; + auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -161,10 +151,16 @@ namespace mito::discretization { } private: - // a const reference to the coordinate system - const coordinate_system_type & _coordinate_system; // the nodes of the simplex const nodes_type _nodes; + // QUESTION: alternatively to the coordinates of the vertices, we could store the points + // associated with the vertices of the triangle, so the coordinates can be fetched from the + // coordinate system + // + // the coordinates of the nodes of the triangle + const vector_type _x0; + const vector_type _x1; + const vector_type _x2; }; } // namespace mito diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 3f1cd51f5..6e9052dd9 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -9,6 +9,9 @@ namespace mito::discretization { + // discretization node alias + using discretization_node_t = utilities::std_shared_ptr; + // nodal field template using nodal_field_t = DiscreteField, Y>; diff --git a/lib/mito/discretization/externals.h b/lib/mito/discretization/externals.h index 7d5bc025f..6ba9ad0c5 100644 --- a/lib/mito/discretization/externals.h +++ b/lib/mito/discretization/externals.h @@ -14,6 +14,7 @@ #include "../journal.h" #include "../manifolds.h" #include "../constraints.h" +#include "../utilities.h" // end of file diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 62feebd03..7c8c85adc 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -9,6 +9,9 @@ namespace mito::discretization { + // class discretization node + class DiscretizationNode; + // class discrete field template class DiscreteField; diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 877cbf49e..1e34b84e5 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -18,6 +18,7 @@ // classes implementation #include "DiscreteField.h" +#include "DiscretizationNode.h" #include "IsoparametricTriangle.h" #include "IsoparametricTriangle1.h" #include "isoparametric_simplex_library.h" diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index b0e55dedf..3ac03f68f 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -154,10 +154,13 @@ TEST(Fem, PoissonSquare) // constraints and can populate the constrained nodes appropriately // the numerical solution nodal field on the mesh auto solution = mito::discretization::nodal_field(mesh, "numerical solution"); + // get the node map from the function space + auto node_map = function_space.node_map(); // fill information in nodal field for (auto & [node, value] : solution) { + auto discretization_node = node_map.at(node); // get the equation number of {node} - int eq = equation_map.at(node); + int eq = equation_map.at(discretization_node); if (eq != -1) { // read the solution at {eq} value = u[eq]; @@ -221,8 +224,12 @@ TEST(Fem, PoissonSquare) auto u_numerical = 0.0; // loop on all the shape functions for (const auto & [node_a, phi_a] : phi) { - // get the numerical solution at {coord} - u_numerical += solution(node_a) * phi_a; + // get the equation number of {node} + int eq = equation_map.at(node_a); + if (eq != -1) { + // get the numerical solution at {coord} + u_numerical += u[eq] * phi_a; + } } // get the error error_L2 += (u_exact - u_numerical) * (u_exact - u_numerical) From 79b97169618957a888eaac211d60083ec3095706 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 14 May 2025 20:03:19 +0200 Subject: [PATCH 066/273] discretization: remove obsolete {TOFIX} item --- lib/mito/discretization/IsoparametricTriangle.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index 017368c9f..574669139 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -27,8 +27,6 @@ namespace mito::discretization { mito::geometry::coordinates_t; protected: - // TOFIX: these should be defined based on the order of the element and on the type of - // simplex (for example here it's 3 of them because we use linear elements on a triangle) // the function extracting the 0 component of a parametric point static constexpr auto xi_0 = mito::fields::field(mito::functions::component); @@ -67,6 +65,7 @@ namespace mito::discretization { } protected: + // QUESTION: do we need to maintain a reference to the geometric simplex? // a const reference to the geometric simplex const geometric_simplex_type & _geometric_simplex; }; From a0bef54f70fa1151e33457e64d21c5f86530a28f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 14 May 2025 20:04:31 +0200 Subject: [PATCH 067/273] discretization: rename {order} to {degree} in class {FunctionSpace} With 'order' we mean simplicial order, while with 'degree' we refer to the discretization polynomial degree. --- lib/mito/discretization/FunctionSpace.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 54e3b5e89..ca1aac946 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -27,11 +27,11 @@ namespace mito::discretization { using mesh_node_type = typename cell_type::node_type; // the coordinate system type using coord_system_type = typename manifold_type::coordinate_system_type; - // the order of the finite element - static constexpr int order = p; + // the degree of the finite element + static constexpr int degree = p; // typedef for a finite element using element_type = - typename isoparametric_simplex::type; + typename isoparametric_simplex::type; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; // the node type From 1d840618e79f7ee9ce6d8cf454ddcfdeaab60858 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 14 May 2025 20:04:44 +0200 Subject: [PATCH 068/273] discretization: narrative edits --- lib/mito/discretization/forward.h | 2 +- lib/mito/discretization/isoparametric_simplex_library.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 7c8c85adc..4902f4212 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -16,7 +16,7 @@ namespace mito::discretization { template class DiscreteField; - // class isoparametric simplex + // class isoparametric triangle with linear shape functions in D dimensions template < geometry::geometric_simplex_c geometricSimplexT, geometry::coordinate_system_c coordinateSystemT> diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h index b215d358d..28d9a89ba 100644 --- a/lib/mito/discretization/isoparametric_simplex_library.h +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -18,7 +18,7 @@ namespace mito::discretization { requires(coordinateSystemT::dim == geometricSimplexT::dim) struct isoparametric_simplex {}; - // linear shape functions on triangles + // specialization for linear shape functions on triangles template struct isoparametric_simplex< 1, geometry::triangle_t, coordinateSystemT> { From daf34ca76dc1cddc564b5d90d021d2e3ae01fc88 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 15 May 2025 08:39:37 +0200 Subject: [PATCH 069/273] discretization: remove unused attribute in class {IsoparametricTriangle1} --- lib/mito/discretization/IsoparametricTriangle1.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index d553e8b73..e4ba460a4 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -25,8 +25,6 @@ namespace mito::discretization { public: // the number of discretization nodes static constexpr int n_nodes = 3; - // the number of vertices - static constexpr int n_vertices = 3; // the node type using node_type = discretization_node_t; // a collection of discretization nodes From a71ff529644ea9ba9e4079d7350b0b56a0a59a74 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 15 May 2025 08:45:43 +0200 Subject: [PATCH 070/273] discretization: move isoparametric simplex class headers to the isoparametric simplex library header --- lib/mito/discretization/isoparametric_simplex_library.h | 4 ++++ lib/mito/discretization/public.h | 2 -- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h index 28d9a89ba..4a034be6d 100644 --- a/lib/mito/discretization/isoparametric_simplex_library.h +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -7,6 +7,10 @@ #pragma once +#include "IsoparametricTriangle.h" +#include "IsoparametricTriangle1.h" + + namespace mito::discretization { // struct storing the type of an isoparametric simplex of polynomial degree {degree} on a diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 1e34b84e5..4abe76368 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -19,8 +19,6 @@ // classes implementation #include "DiscreteField.h" #include "DiscretizationNode.h" -#include "IsoparametricTriangle.h" -#include "IsoparametricTriangle1.h" #include "isoparametric_simplex_library.h" #include "FunctionSpace.h" #include "DiscreteSystem.h" From 620d35e2975b564ff36f31fa970a0a24e9e75a08 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 15 May 2025 09:00:54 +0200 Subject: [PATCH 071/273] discretization: implement quadratic shape functions on the triangle --- .../discretization/IsoparametricTriangle2.h | 185 ++++++++++++++++++ .../isoparametric_simplex_library.h | 9 + 2 files changed, 194 insertions(+) create mode 100644 lib/mito/discretization/IsoparametricTriangle2.h diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h new file mode 100644 index 000000000..a3aad4908 --- /dev/null +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -0,0 +1,185 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// DESIGN NOTES +// Class {IsoparametricTriangle2} represents a second order simplex equipped with quadratic shape +// functions defined in the parametric space. + +// TODO: rename to {IsoparametricTriangleP1}, {IsoparametricTriangleP2}, ... + +namespace mito::discretization { + + template < + geometry::geometric_simplex_c geometricSimplexT, + geometry::coordinate_system_c coordinateSystemT> + class IsoparametricTriangle2 : public IsoparametricTriangle { + + public: + // the number of discretization nodes + static constexpr int n_nodes = 6; + // the node type + using node_type = discretization_node_t; + // a collection of discretization nodes + using nodes_type = std::array; + + private: + // the geometric simplex type + using geometric_simplex_type = geometricSimplexT; + // the global coordinate system type + using coordinate_system_type = coordinateSystemT; + // the base class + using isoparametric_triangle_type = IsoparametricTriangle; + // the parametric coordinates type + using parametric_coordinates_type = + typename isoparametric_triangle_type::parametric_coordinates_type; + + private: + // QUESTION: will we use the same class for triangles embedded in 3D? If not, we can assume + // that the coordinates are in 2D space. Also, we would need to add a {requires} clause to + // ensure that the geometric simplex is embedded in 2D. + using vector_type = tensor::vector_t; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = + typename geometric_simplex_type::barycentric_coordinates_type; + // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick + // another data structure + using evaluated_shape_functions_type = std::map; + using evaluated_shape_functions_gradients_type = + std::map>; + + private: + // strip the namespace + static constexpr auto xi_0 = isoparametric_triangle_type::xi_0; + static constexpr auto xi_1 = isoparametric_triangle_type::xi_1; + static constexpr auto xi_2 = isoparametric_triangle_type::xi_2; + + // quadratic shape functions on the triangle + static constexpr auto phi_3 = 4.0 * xi_0 * xi_2; + static constexpr auto phi_4 = 4.0 * xi_0 * xi_1; + static constexpr auto phi_5 = 4.0 * xi_1 * xi_2; + static constexpr auto phi_0 = xi_2 - 0.5 * phi_3 - 0.5 * phi_5; + static constexpr auto phi_1 = xi_0 - 0.5 * phi_3 - 0.5 * phi_4; + static constexpr auto phi_2 = xi_1 - 0.5 * phi_4 - 0.5 * phi_5; + + // the shape functions + static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); + + // the gradients of the shape functions + static constexpr auto dphi = std::make_tuple( + mito::fields::gradient(phi_0), mito::fields::gradient(phi_1), + mito::fields::gradient(phi_2), mito::fields::gradient(phi_3), + mito::fields::gradient(phi_4), mito::fields::gradient(phi_5)); + + public: + // the default constructor + constexpr IsoparametricTriangle2( + const geometric_simplex_type & geometric_simplex, const nodes_type & nodes, + const vector_type & x0, const vector_type & x1, const vector_type & x2) : + IsoparametricTriangle(geometric_simplex), + _nodes(nodes), + _x0(x0), + _x1(x1), + _x2(x2) + {} + + // destructor + constexpr ~IsoparametricTriangle2() = default; + + // delete move constructor + constexpr IsoparametricTriangle2(IsoparametricTriangle2 &&) noexcept = delete; + + // delete copy constructor + constexpr IsoparametricTriangle2(const IsoparametricTriangle2 &) = delete; + + // delete assignment operator + constexpr IsoparametricTriangle2 & operator=(const IsoparametricTriangle2 &) = delete; + + // delete move assignment operator + constexpr IsoparametricTriangle2 & operator=(IsoparametricTriangle2 &&) noexcept = delete; + + public: + // get the nodes + constexpr auto nodes() const noexcept -> const nodes_type & { return _nodes; } + + // get all the shape functions evaluated at the point {xi} in barycentric coordinates + auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type + { + // the parametric coordinates of the quadrature point + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + + // return the shape functions evaluated at {xi} + return { { _nodes[0], std::get<0>(phi)(xi_p) }, { _nodes[1], std::get<1>(phi)(xi_p) }, + { _nodes[2], std::get<2>(phi)(xi_p) }, { _nodes[3], std::get<3>(phi)(xi_p) }, + { _nodes[4], std::get<4>(phi)(xi_p) }, { _nodes[5], std::get<5>(phi)(xi_p) } }; + } + + // get the jacobian of the isoparametric mapping from barycentric to actual coordinates + constexpr auto jacobian(const barycentric_coordinates_type & xi) const + { + auto x3 = 0.5 * (_x0 + _x1); + auto x4 = 0.5 * (_x1 + _x2); + auto x5 = 0.5 * (_x2 + _x0); + + // assemble the isoparametric mapping from the barycentric coordinates to the actual + // coordinates on the cell {cell} + auto x_cell = + _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; + + // the parametric coordinates of the quadrature point + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + + // compute the gradient of the isoparametric mapping + auto J = mito::fields::gradient(x_cell)(xi_p); + + // return the jacobian of the isoparametric mapping + return J; + } + + // get all the shape functions gradients evaluated at the point {xi} in barycentric + // coordinates + auto gradient(const barycentric_coordinates_type & xi) const + -> evaluated_shape_functions_gradients_type + { + // 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 barycentric coordinates + auto J_inv = mito::tensor::inverse(J); + + // the parametric coordinates of the quadrature point + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + + // return the spatial gradients of the shape functions evaluated at {xi} + return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, + { _nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, + { _nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, + { _nodes[5], std::get<5>(dphi)(xi_p) * J_inv } }; + } + + private: + // the nodes of the simplex + const nodes_type _nodes; + // QUESTION: alternatively to the coordinates of the vertices, we could store the points + // associated with the vertices of the triangle, so the coordinates can be fetched from the + // coordinate system + // + // TOFIX: perhaps these can be stored in the base class? + // the coordinates of the nodes of the triangle + const vector_type _x0; + const vector_type _x1; + const vector_type _x2; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h index 4a034be6d..9d2cf0041 100644 --- a/lib/mito/discretization/isoparametric_simplex_library.h +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -9,6 +9,7 @@ #include "IsoparametricTriangle.h" #include "IsoparametricTriangle1.h" +#include "IsoparametricTriangle2.h" namespace mito::discretization { @@ -29,6 +30,14 @@ namespace mito::discretization { using type = IsoparametricTriangle1, coordinateSystemT>; }; + + // specialization for quadratic shape functions on triangles + template + struct isoparametric_simplex< + 2, geometry::triangle_t, coordinateSystemT> { + using type = + IsoparametricTriangle2, coordinateSystemT>; + }; } From 066e1fcd40a400eb084ecae698cdf7d63b9fca8b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 18 May 2025 16:25:06 +0200 Subject: [PATCH 072/273] discretization: add test of linear and quadratic shape functions on the isoparametric triangle --- .cmake/mito_tests_mito_lib.cmake | 1 + .../discretization/isoparametric_triangle.cc | 108 ++++++++++++++++++ 2 files changed, 109 insertions(+) create mode 100644 tests/mito.lib/discretization/isoparametric_triangle.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index dc4d7541a..a869e3513 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -42,6 +42,7 @@ mito_test_driver(tests/mito.lib/constraints/dirichlet.cc) mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) mito_test_driver(tests/mito.lib/discretization/nodal_field.cc) mito_test_driver(tests/mito.lib/discretization/poisson.cc) +mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle.cc) # io mito_test_driver(tests/mito.lib/io/summit_mesh_reader_2D.cc) diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc new file mode 100644 index 000000000..08c39f299 --- /dev/null +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -0,0 +1,108 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; +// the type of coordinate system +using coord_system_t = mito::geometry::coordinate_system_t; +// the type of discretization node +using discretization_node_t = mito::discretization::discretization_node_t; +// the type of cell +using cell_t = mito::geometry::triangle_t<2>; +// Gauss quadrature on triangles with degree of exactness 2 +using quadrature_rule_t = + mito::quadrature::quadrature_rule_t; + + +// instantiate the quadrature rule +constexpr auto quadrature_rule = quadrature_rule_t(); + + +// test that all shape functions sum to 1.0 at any quadrature point +auto +test_shape_functions(const auto & element) +{ + // loop on the quadrature points + for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + + // the barycentric coordinates of the quadrature point + auto xi = quadrature_rule.point(q); + + // evaluate the element shape functions at {xi} + auto phi = element.shape(xi); + + // the sum of the shape functions + auto sum = 0.0; + + // populate the linear system of equations + for (const auto & [_, phi_a] : phi) { + sum += phi_a; + } + + // check the sum of the shape functions + EXPECT_DOUBLE_EQ(1.0, sum); + } + + // all done + return; +} + +TEST(Fem, IsoparametricTriangle) +{ + // the coordinate system + auto coord_system = coord_system_t(); + + // the origin of the coordinate system + auto origin = typename coord_system_t::coordinates_type{}; + + // build nodes + auto coord_0 = coordinates_t{ 0.0, 0.0 }; + auto node_0 = mito::geometry::node(coord_system, coord_0); + auto coord_1 = coordinates_t{ 1.0, 0.0 }; + auto node_1 = mito::geometry::node(coord_system, coord_1); + auto coord_2 = coordinates_t{ 1.0, 1.0 }; + auto node_2 = mito::geometry::node(coord_system, coord_2); + + // make a geometric simplex + auto geometric_simplex = mito::geometry::triangle<2>({ node_0, node_1, node_2 }); + + { + // first order isoparametric triangle + using element_p1_t = + typename mito::discretization::isoparametric_simplex<1, cell_t, coord_system_t>::type; + + // a finite element + auto element_p1 = element_p1_t( + geometric_simplex, + { discretization_node_t(), discretization_node_t(), discretization_node_t() }, + coord_0 - origin, coord_1 - origin, coord_2 - origin); + + // run test for second order finite elements + test_shape_functions(element_p1); + } + + { + // second order isoparametric triangle + using element_p2_t = + typename mito::discretization::isoparametric_simplex<2, cell_t, coord_system_t>::type; + + // a finite element + auto element_p2 = element_p2_t( + geometric_simplex, + { discretization_node_t(), discretization_node_t(), discretization_node_t(), + discretization_node_t(), discretization_node_t(), discretization_node_t() }, + coord_0 - origin, coord_1 - origin, coord_2 - origin); + + // run test for second order finite elements + test_shape_functions(element_p2); + } + + // all done + return; +} \ No newline at end of file From 3d430ba50069784f7a13c2fbee6f8e7d45e3807a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 18 May 2025 16:27:27 +0200 Subject: [PATCH 073/273] discretization: remove forward declaration of {IsoparametricTriangle1} --- lib/mito/discretization/forward.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 4902f4212..4a3cc9687 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -16,12 +16,6 @@ namespace mito::discretization { template class DiscreteField; - // class isoparametric triangle with linear shape functions in D dimensions - template < - geometry::geometric_simplex_c geometricSimplexT, - geometry::coordinate_system_c coordinateSystemT> - class IsoparametricTriangle1; - // class function space template class FunctionSpace; From 1848ee1c796b0440b87ac99a1ec7715da07b05b3 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 20 May 2025 21:00:57 +0200 Subject: [PATCH 074/273] discretization: add unit tests for isoparametric P1 and P2 elements --- .cmake/mito_tests_mito_lib.cmake | 2 + .../discretization/IsoparametricTriangle1.h | 6 +- .../discretization/IsoparametricTriangle2.h | 6 +- .../isoparametric_triangle_p1.cc | 106 +++++++++++ .../isoparametric_triangle_p2.cc | 178 ++++++++++++++++++ 5 files changed, 292 insertions(+), 6 deletions(-) create mode 100644 tests/mito.lib/discretization/isoparametric_triangle_p1.cc create mode 100644 tests/mito.lib/discretization/isoparametric_triangle_p2.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index a869e3513..795a98c2a 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -43,6 +43,8 @@ mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) mito_test_driver(tests/mito.lib/discretization/nodal_field.cc) mito_test_driver(tests/mito.lib/discretization/poisson.cc) mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle.cc) +mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle_p1.cc) +mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle_p2.cc) # io mito_test_driver(tests/mito.lib/io/summit_mesh_reader_2D.cc) diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index e4ba460a4..6e5e81a40 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -29,6 +29,9 @@ namespace mito::discretization { using node_type = discretization_node_t; // a collection of discretization nodes using nodes_type = std::array; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = + typename geometricSimplexT::barycentric_coordinates_type; private: // the geometric simplex type @@ -44,9 +47,6 @@ namespace mito::discretization { private: // using vector_type = tensor::vector_t; - // type of a point in barycentric coordinates - using barycentric_coordinates_type = - typename geometric_simplex_type::barycentric_coordinates_type; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure using evaluated_shape_functions_type = std::map; diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index a3aad4908..be8ed6436 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -27,6 +27,9 @@ namespace mito::discretization { using node_type = discretization_node_t; // a collection of discretization nodes using nodes_type = std::array; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = + typename geometricSimplexT::barycentric_coordinates_type; private: // the geometric simplex type @@ -44,9 +47,6 @@ namespace mito::discretization { // that the coordinates are in 2D space. Also, we would need to add a {requires} clause to // ensure that the geometric simplex is embedded in 2D. using vector_type = tensor::vector_t; - // type of a point in barycentric coordinates - using barycentric_coordinates_type = - typename geometric_simplex_type::barycentric_coordinates_type; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure using evaluated_shape_functions_type = std::map; diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc new file mode 100644 index 000000000..6d1c0a4df --- /dev/null +++ b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc @@ -0,0 +1,106 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; +// the type of coordinate system +using coord_system_t = mito::geometry::coordinate_system_t; +// the type of discretization node +using discretization_node_t = mito::discretization::discretization_node_t; +// the type of cell +using cell_t = mito::geometry::triangle_t<2>; +// first order isoparametric triangle +using element_t = + typename mito::discretization::isoparametric_simplex<1, cell_t, coord_system_t>::type; +// the barycentric coordinates type +using barycentric_coordinates_t = typename element_t::barycentric_coordinates_type; + + +TEST(Fem, IsoparametricTriangleP1) +{ + /** + * The reference triangle in barycentic coordinates: + (0,1,0) + 2 + xi_1 + + | . + | . + | . + | . + | . + | . + | . + +---------------+ xi_0 + 0 1 + (0,0,1) (1,0,0) + */ + + // the coordinate system + auto coord_system = coord_system_t(); + + // the origin of the coordinate system + auto origin = typename coord_system_t::coordinates_type{}; + + // build nodes + auto coord_0 = coordinates_t{ 0.0, 0.0 }; + auto v0 = mito::geometry::node(coord_system, coord_0); + auto coord_1 = coordinates_t{ 1.0, 0.0 }; + auto v1 = mito::geometry::node(coord_system, coord_1); + auto coord_2 = coordinates_t{ 1.0, 1.0 }; + auto v2 = mito::geometry::node(coord_system, coord_2); + + // make a geometric simplex + auto geometric_simplex = mito::geometry::triangle<2>({ v0, v1, v2 }); + + // build the discretization nodes + auto node_0 = discretization_node_t(); + auto node_1 = discretization_node_t(); + auto node_2 = discretization_node_t(); + + // a finite element + auto element = element_t( + geometric_simplex, { node_0, node_1, node_2 }, coord_0 - origin, coord_1 - origin, + coord_2 - origin); + + // node 0 in barycentric coordinates + auto n0 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + // the shape functions at node 0 + auto phi_0 = element.shape(n0); + // check that the shape function at node 0 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_0.at(node_0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_2)); + + // node 1 in barycentric coordinates + auto n1 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + // the shape functions at node 1 + auto phi_1 = element.shape(n1); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_0)); + // check that the shape function at node 1 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_1.at(node_1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_2)); + + // node 2 in barycentric coordinates + auto n2 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + // the shape functions at node 2 + auto phi_2 = element.shape(n2); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_1)); + // check that the shape function at node 2 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_2.at(node_2)); + + // all done + return; +} \ No newline at end of file diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc new file mode 100644 index 000000000..9719371a1 --- /dev/null +++ b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc @@ -0,0 +1,178 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; +// the type of coordinate system +using coord_system_t = mito::geometry::coordinate_system_t; +// the type of discretization node +using discretization_node_t = mito::discretization::discretization_node_t; +// the type of cell +using cell_t = mito::geometry::triangle_t<2>; +// second order isoparametric triangle +using element_t = + typename mito::discretization::isoparametric_simplex<2, cell_t, coord_system_t>::type; +// the barycentric coordinates type +using barycentric_coordinates_t = typename element_t::barycentric_coordinates_type; + + +TEST(Fem, IsoparametricTriangleP2) +{ + /** + * The reference triangle in barycentic coordinates: + (0,1,0) + 2 + xi_1 + + | . + | . + | . + (0, 1/2, 1/2) 5 + + 4 (1/2, 1/2, 0) + | . + | . + | . + +-------+-------+ xi_0 + 0 3 1 + (0,0,1) (1/2, 0, 1/2) (1,0,0) + */ + + // the coordinate system + auto coord_system = coord_system_t(); + + // the origin of the coordinate system + auto origin = typename coord_system_t::coordinates_type{}; + + // build nodes + auto coord_0 = coordinates_t{ 0.0, 0.0 }; + auto v0 = mito::geometry::node(coord_system, coord_0); + auto coord_1 = coordinates_t{ 1.0, 0.0 }; + auto v1 = mito::geometry::node(coord_system, coord_1); + auto coord_2 = coordinates_t{ 1.0, 1.0 }; + auto v2 = mito::geometry::node(coord_system, coord_2); + + // make a geometric simplex + auto geometric_simplex = mito::geometry::triangle<2>({ v0, v1, v2 }); + + // build the discretization nodes + auto node_0 = discretization_node_t(); + auto node_1 = discretization_node_t(); + auto node_2 = discretization_node_t(); + auto node_3 = discretization_node_t(); + auto node_4 = discretization_node_t(); + auto node_5 = discretization_node_t(); + + // a finite element + auto element = element_t( + geometric_simplex, { node_0, node_1, node_2, node_3, node_4, node_5 }, coord_0 - origin, + coord_1 - origin, coord_2 - origin); + + // node 0 in barycentric coordinates + auto n0 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + // the shape functions at node 0 + auto phi_0 = element.shape(n0); + // check that the shape function at node 0 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_0.at(node_0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_2)); + // check that the shape function at node 3 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_3)); + // check that the shape function at node 4 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_4)); + // check that the shape function at node 5 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_5)); + + // node 1 in barycentric coordinates + auto n1 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + // the shape functions at node 1 + auto phi_1 = element.shape(n1); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_0)); + // check that the shape function at node 1 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_1.at(node_1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_2)); + // check that the shape function at node 3 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_3)); + // check that the shape function at node 4 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_4)); + // check that the shape function at node 5 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_5)); + + // node 2 in barycentric coordinates + auto n2 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + // the shape functions at node 2 + auto phi_2 = element.shape(n2); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_1)); + // check that the shape function at node 2 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_2.at(node_2)); + // check that the shape function at node 3 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_3)); + // check that the shape function at node 4 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_4)); + // check that the shape function at node 5 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_5)); + + // node 3 in barycentric coordinates + auto n3 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; + // the shape functions at node 3 + auto phi_3 = element.shape(n3); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_2)); + // check that the shape function at node 3 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_3.at(node_3)); + // check that the shape function at node 4 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_4)); + // check that the shape function at node 5 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_5)); + + // node 4 in barycentric coordinates + auto n4 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; + // the shape functions at node 4 + auto phi_4 = element.shape(n4); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_2)); + // check that the shape function at node 3 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_3)); + // check that the shape function at node 4 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_4.at(node_4)); + // check that the shape function at node 5 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_5)); + + // node 5 in barycentric coordinates + auto n5 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; + // the shape functions at node 5 + auto phi_5 = element.shape(n5); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_2)); + // check that the shape function at node 3 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_3)); + // check that the shape function at node 4 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_4)); + // check that the shape function at node 5 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_5.at(node_5)); + + // all done + return; +} \ No newline at end of file From 4af2b8f13f13987dfd7d5f5c9b898bb9f260acca Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 20 May 2025 21:01:50 +0200 Subject: [PATCH 075/273] discretization: bugfix in isoparametric P1 elements (wrong ordering of shape functions) --- lib/mito/discretization/IsoparametricTriangle1.h | 6 +++--- tests/mito.lib/discretization/poisson.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 6e5e81a40..9396f10dc 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -55,9 +55,9 @@ namespace mito::discretization { private: // linear shape functions on the triangle - static constexpr auto phi_0 = isoparametric_triangle_type::xi_0; - static constexpr auto phi_1 = isoparametric_triangle_type::xi_1; - static constexpr auto phi_2 = isoparametric_triangle_type::xi_2; + static constexpr auto phi_0 = isoparametric_triangle_type::xi_2; + static constexpr auto phi_1 = isoparametric_triangle_type::xi_0; + static constexpr auto phi_2 = isoparametric_triangle_type::xi_1; // the shape functions static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 3ac03f68f..98f6eda3d 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -242,7 +242,7 @@ TEST(Fem, PoissonSquare) channel << "L2 error: " << error_L2 << journal::endl; // check that the l2 error is reasonable - EXPECT_TRUE(error_L2 < 0.02); + EXPECT_TRUE(error_L2 < 0.1); // TODO: add norm calculation for convergence study } From 5697c5169522c66a4f5f0e1313e1baa056960f7f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 23 May 2025 20:11:03 +0200 Subject: [PATCH 076/273] Revert "discretization: bugfix in isoparametric P1 elements (wrong ordering of shape functions)" This reverts commit 4af2b8f13f13987dfd7d5f5c9b898bb9f260acca. --- lib/mito/discretization/IsoparametricTriangle1.h | 6 +++--- tests/mito.lib/discretization/poisson.cc | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 9396f10dc..6e5e81a40 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -55,9 +55,9 @@ namespace mito::discretization { private: // linear shape functions on the triangle - static constexpr auto phi_0 = isoparametric_triangle_type::xi_2; - static constexpr auto phi_1 = isoparametric_triangle_type::xi_0; - static constexpr auto phi_2 = isoparametric_triangle_type::xi_1; + static constexpr auto phi_0 = isoparametric_triangle_type::xi_0; + static constexpr auto phi_1 = isoparametric_triangle_type::xi_1; + static constexpr auto phi_2 = isoparametric_triangle_type::xi_2; // the shape functions static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 98f6eda3d..3ac03f68f 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -242,7 +242,7 @@ TEST(Fem, PoissonSquare) channel << "L2 error: " << error_L2 << journal::endl; // check that the l2 error is reasonable - EXPECT_TRUE(error_L2 < 0.1); + EXPECT_TRUE(error_L2 < 0.02); // TODO: add norm calculation for convergence study } From bd1b0a5f86a1d1788efca7588b65d2021c9addaf Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 24 May 2025 16:43:32 +0200 Subject: [PATCH 077/273] discretization: reorder shape functions consistently across P1 and P2 --- .../discretization/IsoparametricTriangle2.h | 12 +++++----- .../isoparametric_triangle_p1.cc | 14 ++++++------ .../isoparametric_triangle_p2.cc | 22 +++++++++---------- 3 files changed, 24 insertions(+), 24 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index be8ed6436..2316a3fcf 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -60,12 +60,12 @@ namespace mito::discretization { static constexpr auto xi_2 = isoparametric_triangle_type::xi_2; // quadratic shape functions on the triangle - static constexpr auto phi_3 = 4.0 * xi_0 * xi_2; - static constexpr auto phi_4 = 4.0 * xi_0 * xi_1; - static constexpr auto phi_5 = 4.0 * xi_1 * xi_2; - static constexpr auto phi_0 = xi_2 - 0.5 * phi_3 - 0.5 * phi_5; - static constexpr auto phi_1 = xi_0 - 0.5 * phi_3 - 0.5 * phi_4; - static constexpr auto phi_2 = xi_1 - 0.5 * phi_4 - 0.5 * phi_5; + static constexpr auto phi_3 = 4.0 * xi_0 * xi_1; + static constexpr auto phi_4 = 4.0 * xi_1 * xi_2; + static constexpr auto phi_5 = 4.0 * xi_0 * xi_2; + static constexpr auto phi_0 = xi_0 - 0.5 * phi_5 - 0.5 * phi_3; + static constexpr auto phi_1 = xi_1 - 0.5 * phi_3 - 0.5 * phi_4; + static constexpr auto phi_2 = xi_2 - 0.5 * phi_5 - 0.5 * phi_4; // the shape functions static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc index 6d1c0a4df..ac2d318fd 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc @@ -26,9 +26,9 @@ TEST(Fem, IsoparametricTriangleP1) { /** * The reference triangle in barycentic coordinates: - (0,1,0) + (0,0,1) 2 - xi_1 + + xi_2 + | . | . | . @@ -36,9 +36,9 @@ TEST(Fem, IsoparametricTriangleP1) | . | . | . - +---------------+ xi_0 + +---------------+ xi_1 0 1 - (0,0,1) (1,0,0) + (1,0,0) (0,1,0) */ // the coordinate system @@ -69,7 +69,7 @@ TEST(Fem, IsoparametricTriangleP1) coord_2 - origin); // node 0 in barycentric coordinates - auto n0 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; // the shape functions at node 0 auto phi_0 = element.shape(n0); // check that the shape function at node 0 is 1.0 @@ -80,7 +80,7 @@ TEST(Fem, IsoparametricTriangleP1) EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_2)); // node 1 in barycentric coordinates - auto n1 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; // the shape functions at node 1 auto phi_1 = element.shape(n1); // check that the shape function at node 0 is 0.0 @@ -91,7 +91,7 @@ TEST(Fem, IsoparametricTriangleP1) EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_2)); // node 2 in barycentric coordinates - auto n2 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; // the shape functions at node 2 auto phi_2 = element.shape(n2); // check that the shape function at node 0 is 0.0 diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc index 9719371a1..fdb6ae722 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc @@ -26,19 +26,19 @@ TEST(Fem, IsoparametricTriangleP2) { /** * The reference triangle in barycentic coordinates: - (0,1,0) + (0,0,1) 2 - xi_1 + + xi_2 + | . | . | . - (0, 1/2, 1/2) 5 + + 4 (1/2, 1/2, 0) + (1/2, 0, 1/2) 5 + + 4 (0, 1/2, 1/2) | . | . | . - +-------+-------+ xi_0 + +-------+-------+ xi_1 0 3 1 - (0,0,1) (1/2, 0, 1/2) (1,0,0) + (1,0,0) (1/2, 1/2, 0) (0,1,0) */ // the coordinate system @@ -72,7 +72,7 @@ TEST(Fem, IsoparametricTriangleP2) coord_1 - origin, coord_2 - origin); // node 0 in barycentric coordinates - auto n0 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; // the shape functions at node 0 auto phi_0 = element.shape(n0); // check that the shape function at node 0 is 1.0 @@ -89,7 +89,7 @@ TEST(Fem, IsoparametricTriangleP2) EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_5)); // node 1 in barycentric coordinates - auto n1 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; // the shape functions at node 1 auto phi_1 = element.shape(n1); // check that the shape function at node 0 is 0.0 @@ -106,7 +106,7 @@ TEST(Fem, IsoparametricTriangleP2) EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_5)); // node 2 in barycentric coordinates - auto n2 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; // the shape functions at node 2 auto phi_2 = element.shape(n2); // check that the shape function at node 0 is 0.0 @@ -123,7 +123,7 @@ TEST(Fem, IsoparametricTriangleP2) EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_5)); // node 3 in barycentric coordinates - auto n3 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; + auto n3 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; // the shape functions at node 3 auto phi_3 = element.shape(n3); // check that the shape function at node 0 is 0.0 @@ -140,7 +140,7 @@ TEST(Fem, IsoparametricTriangleP2) EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_5)); // node 4 in barycentric coordinates - auto n4 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; + auto n4 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; // the shape functions at node 4 auto phi_4 = element.shape(n4); // check that the shape function at node 0 is 0.0 @@ -157,7 +157,7 @@ TEST(Fem, IsoparametricTriangleP2) EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_5)); // node 5 in barycentric coordinates - auto n5 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; + auto n5 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; // the shape functions at node 5 auto phi_5 = element.shape(n5); // check that the shape function at node 0 is 0.0 From 539206fcc2ee72fafbd5013e0323192b68bbdb64 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 24 May 2025 16:50:36 +0200 Subject: [PATCH 078/273] discretization: narrative improvements to test {isoparametric_triangle.cc} --- .../mito.lib/discretization/isoparametric_triangle.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 08c39f299..8f9c20052 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -26,7 +26,7 @@ constexpr auto quadrature_rule = quadrature_rule_t(); // test that all shape functions sum to 1.0 at any quadrature point auto -test_shape_functions(const auto & element) +test_partition_of_unity(const auto & element) { // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -83,8 +83,8 @@ TEST(Fem, IsoparametricTriangle) { discretization_node_t(), discretization_node_t(), discretization_node_t() }, coord_0 - origin, coord_1 - origin, coord_2 - origin); - // run test for second order finite elements - test_shape_functions(element_p1); + // check that first order shape functions are a partition of unity + test_partition_of_unity(element_p1); } { @@ -99,8 +99,8 @@ TEST(Fem, IsoparametricTriangle) discretization_node_t(), discretization_node_t(), discretization_node_t() }, coord_0 - origin, coord_1 - origin, coord_2 - origin); - // run test for second order finite elements - test_shape_functions(element_p2); + // check that second order shape functions are a partition of unity + test_partition_of_unity(element_p2); } // all done From b77cb18a58324971486064ec8ddd699641887b81 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 24 May 2025 16:55:32 +0200 Subject: [PATCH 079/273] discretization: add gradients consistency check to test {isoparametric_triangle.cc} for P1 and P2 --- .../discretization/isoparametric_triangle.cc | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 8f9c20052..0068bc823 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -53,6 +53,36 @@ test_partition_of_unity(const auto & element) return; } +// test that the gradients of all shape functions sum to 0.0 at any quadrature point +auto +test_gradient_consistency(const auto & element) +{ + // loop on the quadrature points + for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + + // the barycentric coordinates of the quadrature point + auto xi = quadrature_rule.point(q); + + // evaluate the element shape functions gradients at {xi} + auto dphi = element.gradient(xi); + + // the sum of the shape functions + auto sum = mito::tensor::vector_t<2>{ 0.0, 0.0 }; + + // populate the linear system of equations + for (const auto & [_, dphi_a] : dphi) { + sum += dphi_a; + } + + // check the sum of the shape functions gradients + EXPECT_NEAR(0.0, sum[0], 3.0e-16); + EXPECT_NEAR(0.0, sum[1], 3.0e-16); + } + + // all done + return; +} + TEST(Fem, IsoparametricTriangle) { // the coordinate system @@ -85,6 +115,9 @@ TEST(Fem, IsoparametricTriangle) // check that first order shape functions are a partition of unity test_partition_of_unity(element_p1); + + // check that the gradients of first order shape functions sum to 0.0 + test_gradient_consistency(element_p1); } { @@ -101,6 +134,9 @@ TEST(Fem, IsoparametricTriangle) // check that second order shape functions are a partition of unity test_partition_of_unity(element_p2); + + // check that the gradients of second order shape functions sum to 0.0 + test_gradient_consistency(element_p2); } // all done From 1f324adf24e186716153a85f419426d622cd4eee Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 24 May 2025 18:56:09 +0200 Subject: [PATCH 080/273] quadrature: narrative improvements --- tests/mito.lib/quadrature/quadrature_parametric_triangle.cc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc b/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc index 355ca474e..a290896c6 100644 --- a/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc +++ b/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc @@ -74,7 +74,7 @@ TEST(ParametricTriangle, Order3) // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; - // a quadratic function of the parametric coordinates x_0^2 + // a quadratic function of the parametric coordinates x_0^3 constexpr auto f = [](const point_t & x) -> mito::tensor::scalar_t { return x[0] * x[0] * x[0]; }; @@ -82,7 +82,7 @@ TEST(ParametricTriangle, Order3) // area of the parametric triangle constexpr auto area = 0.5; - // integral of f on the parametric triangle [0, 1] + // integral of f on the parametric triangle constexpr auto integral = area * (quadrature_rule.weight(0) * f(quadrature_rule.point(0)) + quadrature_rule.weight(1) * f(quadrature_rule.point(1)) @@ -91,7 +91,7 @@ TEST(ParametricTriangle, Order3) + quadrature_rule.weight(4) * f(quadrature_rule.point(4)) + quadrature_rule.weight(5) * f(quadrature_rule.point(5))); - // exact solution (1/3 x^3) at x = 1 + // exact solution constexpr auto exact = 1.0 / 20.0; // check result From cb6c8d15f320a236dc0b3573ece9380686656cee Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 2 Jun 2025 20:57:38 +0200 Subject: [PATCH 081/273] discretization: add check of elementary stiffness and mass matrices to test {isoparametric_triangle.cc} for P1 --- .../discretization/isoparametric_triangle.cc | 120 +++++++++++++++++- 1 file changed, 119 insertions(+), 1 deletion(-) diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 0068bc823..afc427c54 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -83,6 +83,110 @@ test_gradient_consistency(const auto & element) return; } +// test that the elementary stiffness matrix is computed correctly +template +auto +test_stiffness_matrix( + const elementT & element, + const mito::tensor::matrix_t & analytical_stiffness_matrix) -> void +{ + // create reporting channel + journal::info_t channel("test_stiffness_matrix"); + + // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix + auto elementary_stiffness_matrix = mito::tensor::matrix_t(); + + // loop on the quadrature points + for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + + // the barycentric coordinates of the quadrature point + auto xi = quadrature_rule.point(q); + + // area of the cell + auto area = 0.5 * mito::tensor::determinant(element.jacobian(xi)); + + // evaluate the element shape functions gradients at {xi} + auto dphi = element.gradient(xi); + + // precompute the common factor for integration + auto factor = quadrature_rule.weight(q) * area; + + // populate the mass matrix + int i = 0; + for (const auto & [node_a, dphi_a] : dphi) { + int j = 0; + for (const auto & [node_b, dphi_b] : dphi) { + // assemble the {node_a, node_b} contribution to the mass matrix + elementary_stiffness_matrix[{ i, j }] += factor * dphi_a * dphi_b; + // increment the column index + ++j; + } + // increment the row index + ++i; + } + } + + // compute the error + auto error = mito::tensor::norm(elementary_stiffness_matrix - analytical_stiffness_matrix); + + // check the error is reasonable + EXPECT_NEAR(0.0, error, 1.e-14); + + // all done + return; +} + +// test that the elementary mass matrix is computed correctly +template +auto +test_mass_matrix( + const elementT & element, + const mito::tensor::matrix_t & analytical_mass_matrix) -> void +{ + // create reporting channel + journal::info_t channel("test_mass_matrix"); + + // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix + auto elementary_mass_matrix = mito::tensor::matrix_t(); + + // loop on the quadrature points + for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + + // the barycentric coordinates of the quadrature point + auto xi = quadrature_rule.point(q); + + // evaluate the element shape functions at {xi} + auto phi = element.shape(xi); + + // area of the cell + auto factor = + 0.5 * mito::tensor::determinant(element.jacobian(xi)) * quadrature_rule.weight(q); + + // populate the mass matrix + int i = 0; + for (const auto & [_, phi_a] : phi) { + int j = 0; + for (const auto & [_, phi_b] : phi) { + // assemble the {node_a, node_b} contribution to the mass matrix + elementary_mass_matrix[{ i, j }] += factor * phi_a * phi_b; + // increment the column index + ++j; + } + // increment the row index + ++i; + } + } + + // compute the error + auto error = mito::tensor::norm(elementary_mass_matrix - analytical_mass_matrix); + + // check the error is reasonable + EXPECT_NEAR(0.0, error, 1.e-14); + + // all done + return; +} + TEST(Fem, IsoparametricTriangle) { // the coordinate system @@ -96,7 +200,7 @@ TEST(Fem, IsoparametricTriangle) auto node_0 = mito::geometry::node(coord_system, coord_0); auto coord_1 = coordinates_t{ 1.0, 0.0 }; auto node_1 = mito::geometry::node(coord_system, coord_1); - auto coord_2 = coordinates_t{ 1.0, 1.0 }; + auto coord_2 = coordinates_t{ 0.0, 1.0 }; auto node_2 = mito::geometry::node(coord_system, coord_2); // make a geometric simplex @@ -118,6 +222,20 @@ TEST(Fem, IsoparametricTriangle) // check that the gradients of first order shape functions sum to 0.0 test_gradient_consistency(element_p1); + + // the analytical elementary stiffness matrix + auto analytical_stiffness_matrix = + 1.0 / 2.0 + * mito::tensor::matrix_t<3>({ 2.0, -1.0, -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0 }); + + // check that the elementary stiffness matrix is computed correctly + test_stiffness_matrix(element_p1, analytical_stiffness_matrix); + + // the analytical elementary mass matrix + auto analytical_mass_matrix = + 1.0 / 24.0 * mito::tensor::matrix_t<3>({ 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0 }); + + test_mass_matrix(element_p1, analytical_mass_matrix); } { From cc2a9e9a48786bd7e670efd7709172dea681b4e2 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 2 Jun 2025 21:00:32 +0200 Subject: [PATCH 082/273] discretization: fix typos --- tests/mito.lib/discretization/isoparametric_triangle_p1.cc | 2 +- tests/mito.lib/discretization/isoparametric_triangle_p2.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc index ac2d318fd..338527eb6 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc @@ -25,7 +25,7 @@ using barycentric_coordinates_t = typename element_t::barycentric_coordinates_ty TEST(Fem, IsoparametricTriangleP1) { /** - * The reference triangle in barycentic coordinates: + * The reference triangle in barycentric coordinates: (0,0,1) 2 xi_2 + diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc index fdb6ae722..189e14a42 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc @@ -25,7 +25,7 @@ using barycentric_coordinates_t = typename element_t::barycentric_coordinates_ty TEST(Fem, IsoparametricTriangleP2) { /** - * The reference triangle in barycentic coordinates: + * The reference triangle in barycentric coordinates: (0,0,1) 2 xi_2 + From 92c2a20d6ebc56b79f9497dbe4afd1200d884999 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 3 Jun 2025 10:39:06 +0200 Subject: [PATCH 083/273] quadrature: add quadrature formula on triangles with degree of exactness 4 --- .../quadrature_tables_triangles.icc | 24 ++++++++++++++ .../quadrature_parametric_triangle.cc | 33 +++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/lib/mito/quadrature/quadrature_tables_triangles.icc b/lib/mito/quadrature/quadrature_tables_triangles.icc index e985467e6..9272be380 100644 --- a/lib/mito/quadrature/quadrature_tables_triangles.icc +++ b/lib/mito/quadrature/quadrature_tables_triangles.icc @@ -55,6 +55,30 @@ namespace mito::quadrature { point_weight_pair_type({ b, b, 1.0 - 2.0 * b }, w2) }); } + // Dunavant's Rule #4, Hammer–Stroud-type rule + template <> + constexpr auto QuadratureTable() -> auto + { + constexpr int Q = 6; + using table_type = Table; + using point_weight_pair_type = table_type::point_weight_pair_type; + + constexpr auto a = 0.816847572980458513080857; + constexpr auto b = 0.091576213509770743459571; + constexpr auto c = 0.108103018168070227363167; + constexpr auto d = 0.445948490915964886318329; + constexpr auto w1 = 0.109951743655321867638326; + constexpr auto w2 = 0.223381589678011465695007; + + return table_type({ /*{point}, weight*/ + point_weight_pair_type({ a, b, 1.0 - a - b }, w1), + point_weight_pair_type({ b, a, 1.0 - a - b }, w1), + point_weight_pair_type({ b, b, 1.0 - 2.0 * b }, w1), + point_weight_pair_type({ c, d, 1.0 - c - d }, w2), + point_weight_pair_type({ d, c, 1.0 - c - d }, w2), + point_weight_pair_type({ d, d, 1.0 - 2.0 * d }, w2) }); + } + } // namespace mito diff --git a/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc b/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc index a290896c6..3d7d76e59 100644 --- a/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc +++ b/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc @@ -98,4 +98,37 @@ TEST(ParametricTriangle, Order3) static_assert(std::fabs(integral - exact) < 1.e-16); } +TEST(ParametricTriangle, Order4) +{ + // a Gauss quadrature rule on triangles with degree of exactness 4 + constexpr auto quadrature_rule = + mito::quadrature::quadrature_rule(); + + // the parametric point type + using point_t = decltype(quadrature_rule)::quadrature_point_type; + + // a polynomial of degree 4 in parametric coordinates + constexpr auto f = [](const point_t & x) -> mito::tensor::scalar_t { + return x[0] * x[0] * x[0] * x[0]; + }; + + // area of the parametric triangle + constexpr auto area = 0.5; + + // integral of f on the parametric triangle + constexpr auto integral = area + * (quadrature_rule.weight(0) * f(quadrature_rule.point(0)) + + quadrature_rule.weight(1) * f(quadrature_rule.point(1)) + + quadrature_rule.weight(2) * f(quadrature_rule.point(2)) + + quadrature_rule.weight(3) * f(quadrature_rule.point(3)) + + quadrature_rule.weight(4) * f(quadrature_rule.point(4)) + + quadrature_rule.weight(5) * f(quadrature_rule.point(5))); + + // exact solution + constexpr auto exact = 1.0 / 30.0; + + // check result + static_assert(std::fabs(integral - exact) < 1.e-16); +} + // end of file From 6a8d0ca5a41544c88e59573ac60e9eebef93b821 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 3 Jun 2025 11:12:58 +0200 Subject: [PATCH 084/273] quadrature: fix error in calculation of integrals on the reference tetrahedron --- .../quadrature/quadrature_parametric_tetrahedron.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc b/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc index 3e6a6b7f0..99420a13e 100644 --- a/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc +++ b/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc @@ -23,13 +23,13 @@ TEST(ParametricTetrahedron, Order1) }; // area of the parametric tetrahedron - constexpr auto area = 1.0 / 3.0; + constexpr auto area = 1.0 / 6.0; // integral of f on the parametric tetrahedron constexpr auto integral = area * quadrature_rule.weight(0) * f(quadrature_rule.point(0)); // exact solution - constexpr auto exact = 1.0 / 12.0; + constexpr auto exact = 1.0 / 24.0; // check result static_assert(std::fabs(integral - exact) < 1.e-16); @@ -50,7 +50,7 @@ TEST(ParametricTetrahedron, Order2) }; // area of the parametric tetrahedron - constexpr auto area = 1.0 / 3.0; + constexpr auto area = 1.0 / 6.0; // integral of f on the parametric tetrahedron constexpr auto integral = area @@ -60,7 +60,7 @@ TEST(ParametricTetrahedron, Order2) + quadrature_rule.weight(3) * f(quadrature_rule.point(3))); // exact solution - constexpr auto exact = 1.0 / 30.0; + constexpr auto exact = 1.0 / 60.0; // check result static_assert(std::fabs(integral - exact) < 1.e-16); From afcfaa755d779fdb1b6ef637db08c379d1351559 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 3 Jun 2025 19:53:51 +0200 Subject: [PATCH 085/273] discretization: change data structure for evaluated shape functions and gradients From {std::map} to {std::array}. --- .../discretization/IsoparametricTriangle1.h | 21 ++++++------- .../discretization/IsoparametricTriangle2.h | 30 +++++++++++-------- 2 files changed, 28 insertions(+), 23 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 6e5e81a40..4b1e98483 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -47,11 +47,12 @@ namespace mito::discretization { private: // using vector_type = tensor::vector_t; - // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick - // another data structure - using evaluated_shape_functions_type = std::map; + // the type for a collection of evaluated shape functions + using evaluated_shape_functions_type = + std::array, n_nodes>; + // the type for a collection of evaluated shape functions gradients using evaluated_shape_functions_gradients_type = - std::map>; + std::array>, n_nodes>; private: // linear shape functions on the triangle @@ -105,9 +106,9 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(phi)(xi_p) }, - { _nodes[1], std::get<1>(phi)(xi_p) }, - { _nodes[2], std::get<2>(phi)(xi_p) } }; + return { { { _nodes[0], std::get<0>(phi)(xi_p) }, + { _nodes[1], std::get<1>(phi)(xi_p) }, + { _nodes[2], std::get<2>(phi)(xi_p) } } }; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -143,9 +144,9 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv } }; + return { { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv } } }; } private: diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index 2316a3fcf..cf6b5c73c 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -47,11 +47,12 @@ namespace mito::discretization { // that the coordinates are in 2D space. Also, we would need to add a {requires} clause to // ensure that the geometric simplex is embedded in 2D. using vector_type = tensor::vector_t; - // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick - // another data structure - using evaluated_shape_functions_type = std::map; + // the type for a collection of evaluated shape functions + using evaluated_shape_functions_type = + std::array, n_nodes>; + // the type for a collection of evaluated shape functions gradients using evaluated_shape_functions_gradients_type = - std::map>; + std::array>, n_nodes>; private: // strip the namespace @@ -114,9 +115,12 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(phi)(xi_p) }, { _nodes[1], std::get<1>(phi)(xi_p) }, - { _nodes[2], std::get<2>(phi)(xi_p) }, { _nodes[3], std::get<3>(phi)(xi_p) }, - { _nodes[4], std::get<4>(phi)(xi_p) }, { _nodes[5], std::get<5>(phi)(xi_p) } }; + return { { { _nodes[0], std::get<0>(phi)(xi_p) }, + { _nodes[1], std::get<1>(phi)(xi_p) }, + { _nodes[2], std::get<2>(phi)(xi_p) }, + { _nodes[3], std::get<3>(phi)(xi_p) }, + { _nodes[4], std::get<4>(phi)(xi_p) }, + { _nodes[5], std::get<5>(phi)(xi_p) } } }; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -157,12 +161,12 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, - { _nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, - { _nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, - { _nodes[5], std::get<5>(dphi)(xi_p) * J_inv } }; + return { { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, + { _nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, + { _nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, + { _nodes[5], std::get<5>(dphi)(xi_p) * J_inv } } }; } private: From c87cba80f4c78abf30454b90a257b4d3c66745cd Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 3 Jun 2025 19:55:35 +0200 Subject: [PATCH 086/273] discretization: add test for elementary mass and stiffness matrices for P2 shape functions Also, added python scripts with symbolic calculation of the analytical matrix entries. --- .../discretization/isoparametric_triangle.cc | 27 ++++++++++- .../discretization/verification_p1.py | 40 ++++++++++++++++ .../discretization/verification_p2.py | 46 +++++++++++++++++++ 3 files changed, 111 insertions(+), 2 deletions(-) create mode 100644 tests/mito.lib/discretization/verification_p1.py create mode 100644 tests/mito.lib/discretization/verification_p2.py diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index afc427c54..b51357197 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -15,9 +15,9 @@ using coord_system_t = mito::geometry::coordinate_system_t; using discretization_node_t = mito::discretization::discretization_node_t; // the type of cell using cell_t = mito::geometry::triangle_t<2>; -// Gauss quadrature on triangles with degree of exactness 2 +// Gauss quadrature on triangles with degree of exactness 4 using quadrature_rule_t = - mito::quadrature::quadrature_rule_t; + mito::quadrature::quadrature_rule_t; // instantiate the quadrature rule @@ -255,6 +255,29 @@ TEST(Fem, IsoparametricTriangle) // check that the gradients of second order shape functions sum to 0.0 test_gradient_consistency(element_p2); + + // the analytical elementary stiffness matrix + auto analytical_stiffness_matrix = mito::tensor::matrix_t<6>( + { 1.0, 1.0 / 6.0, 1.0 / 6.0, -2.0 / 3.0, 0.0, -2.0 / 3.0, + 1.0 / 6.0, 1.0 / 2.0, 0.0, -2.0 / 3.0, 0.0, 0.0, + 1.0 / 6.0, 0.0, 1.0 / 2.0, 0.0, 0.0, -2.0 / 3.0, + -2.0 / 3.0, -2.0 / 3.0, 0.0, 8.0 / 3.0, -4.0 / 3.0, 0.0, + 0.0, 0.0, 0.0, -4.0 / 3.0, 8.0 / 3.0, -4.0 / 3.0, + -2.0 / 3.0, 0.0, -2.0 / 3.0, 0.0, -4.0 / 3.0, 8.0 / 3.0 }); + + // check that the elementary stiffness matrix is computed correctly + test_stiffness_matrix(element_p2, analytical_stiffness_matrix); + + // the analytical elementary mass matrix + auto analytical_mass_matrix = mito::tensor::matrix_t<6>( + { 1.0 / 60.0, -1.0 / 360.0, -1.0 / 360.0, 0.0, -1.0 / 90.0, 0.0, + -1.0 / 360.0, 1.0 / 60.0, -1.0 / 360.0, 0.0, 0.0, -1.0 / 90.0, + -1.0 / 360.0, -1.0 / 360.0, 1.0 / 60.0, -1.0 / 90.0, 0.0, 0.0, + 0.0, 0.0, -1.0 / 90.0, 4.0 / 45.0, 2.0 / 45.0, 2.0 / 45.0, + -1.0 / 90.0, 0.0, 0.0, 2.0 / 45.0, 4.0 / 45.0, 2.0 / 45.0, + 0.0, -1.0 / 90.0, 0.0, 2.0 / 45.0, 2.0 / 45.0, 4.0 / 45.0 }); + + test_mass_matrix(element_p2, analytical_mass_matrix); } // all done diff --git a/tests/mito.lib/discretization/verification_p1.py b/tests/mito.lib/discretization/verification_p1.py new file mode 100644 index 000000000..ae0ebef0d --- /dev/null +++ b/tests/mito.lib/discretization/verification_p1.py @@ -0,0 +1,40 @@ +import sympy +from sympy.vector import CoordSys3D, gradient + +# define the coordinate system +C = CoordSys3D('C') + +# define the scalar field +x, y, _ = C.base_scalars() + +# define the shape functions +phi0 = (1 - x - y) +phi1 = x +phi2 = y + +# report +print("Computing the mass matrix for the 3 shape functions of a triangular element:") + +# compute the mass matrix via double integration +phis = [phi0, phi1, phi2] +print("Mass matrix:") +for i, phi_i in enumerate(phis): + for j, phi_j in enumerate(phis): + integral = sympy.integrate(phi_i * phi_j, (y, 0, 1-x), (x, 0, 1)) + print(f"M[{i},{j}] = {integral}") + +# report +print("Computing the stiffness matrix for the 3 shape functions of a triangular element:") + +# compute the shape functions gradients +dphi0 = gradient(phi0) +dphi1 = gradient(phi1) +dphi2 = gradient(phi2) + +# compute the stiffness matrix via double integration +dphis = [dphi0, dphi1, dphi2] +print("Stiffness matrix:") +for i, dphi_i in enumerate(dphis): + for j, dphi_j in enumerate(dphis): + integral = sympy.integrate(dphi_i & dphi_j, (y, 0, 1-x), (x, 0, 1)) + print(f"K[{i},{j}] = {integral}") diff --git a/tests/mito.lib/discretization/verification_p2.py b/tests/mito.lib/discretization/verification_p2.py new file mode 100644 index 000000000..3e997c30f --- /dev/null +++ b/tests/mito.lib/discretization/verification_p2.py @@ -0,0 +1,46 @@ +import sympy +from sympy.vector import CoordSys3D, gradient + +# define the coordinate system +C = CoordSys3D('C') + +# define the scalar field +x, y, _ = C.base_scalars() + +# define the shape functions +phi0 = (1 - x - y) * (1 - 2*x - 2*y) +phi1 = x * (2*x - 1) +phi2 = y * (2*y - 1) +phi3 = 4 * x * (1 - x - y) +phi4 = 4 * x * y +phi5 = 4 * y * (1 - x - y) + +# report +print("Computing the mass matrix for the 6 shape functions of a triangular element:") + +# compute the mass matrix via double integration +phis = [phi0, phi1, phi2, phi3, phi4, phi5] +print("Mass matrix:") +for i, phi_i in enumerate(phis): + for j, phi_j in enumerate(phis): + integral = sympy.integrate(phi_i * phi_j, (y, 0, 1-x), (x, 0, 1)) + print(f"M[{i},{j}] = {integral}") + +# report +print("Computing the stiffness matrix for the 6 shape functions of a triangular element:") + +# compute the shape functions gradients +dphi0 = gradient(phi0) +dphi1 = gradient(phi1) +dphi2 = gradient(phi2) +dphi3 = gradient(phi3) +dphi4 = gradient(phi4) +dphi5 = gradient(phi5) + +# compute the stiffness matrix via double integration +dphis = [dphi0, dphi1, dphi2, dphi3, dphi4, dphi5] +print("Stiffness matrix:") +for i, dphi_i in enumerate(dphis): + for j, dphi_j in enumerate(dphis): + integral = sympy.integrate(dphi_i & dphi_j, (y, 0, 1-x), (x, 0, 1)) + print(f"K[{i},{j}] = {integral}") From c8f29066b2930877e56ed861dcdc604b11e26eae Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 7 Jun 2025 09:04:13 +0200 Subject: [PATCH 087/273] Revert "discretization: change data structure for evaluated shape functions and gradients" This reverts commit afcfaa755d779fdb1b6ef637db08c379d1351559. --- .../discretization/IsoparametricTriangle1.h | 21 +++++++------ .../discretization/IsoparametricTriangle2.h | 30 ++++++++----------- 2 files changed, 23 insertions(+), 28 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 4b1e98483..6e5e81a40 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -47,12 +47,11 @@ namespace mito::discretization { private: // using vector_type = tensor::vector_t; - // the type for a collection of evaluated shape functions - using evaluated_shape_functions_type = - std::array, n_nodes>; - // the type for a collection of evaluated shape functions gradients + // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick + // another data structure + using evaluated_shape_functions_type = std::map; using evaluated_shape_functions_gradients_type = - std::array>, n_nodes>; + std::map>; private: // linear shape functions on the triangle @@ -106,9 +105,9 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the shape functions evaluated at {xi} - return { { { _nodes[0], std::get<0>(phi)(xi_p) }, - { _nodes[1], std::get<1>(phi)(xi_p) }, - { _nodes[2], std::get<2>(phi)(xi_p) } } }; + return { { _nodes[0], std::get<0>(phi)(xi_p) }, + { _nodes[1], std::get<1>(phi)(xi_p) }, + { _nodes[2], std::get<2>(phi)(xi_p) } }; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -144,9 +143,9 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return { { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv } } }; + return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv } }; } private: diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index cf6b5c73c..2316a3fcf 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -47,12 +47,11 @@ namespace mito::discretization { // that the coordinates are in 2D space. Also, we would need to add a {requires} clause to // ensure that the geometric simplex is embedded in 2D. using vector_type = tensor::vector_t; - // the type for a collection of evaluated shape functions - using evaluated_shape_functions_type = - std::array, n_nodes>; - // the type for a collection of evaluated shape functions gradients + // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick + // another data structure + using evaluated_shape_functions_type = std::map; using evaluated_shape_functions_gradients_type = - std::array>, n_nodes>; + std::map>; private: // strip the namespace @@ -115,12 +114,9 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the shape functions evaluated at {xi} - return { { { _nodes[0], std::get<0>(phi)(xi_p) }, - { _nodes[1], std::get<1>(phi)(xi_p) }, - { _nodes[2], std::get<2>(phi)(xi_p) }, - { _nodes[3], std::get<3>(phi)(xi_p) }, - { _nodes[4], std::get<4>(phi)(xi_p) }, - { _nodes[5], std::get<5>(phi)(xi_p) } } }; + return { { _nodes[0], std::get<0>(phi)(xi_p) }, { _nodes[1], std::get<1>(phi)(xi_p) }, + { _nodes[2], std::get<2>(phi)(xi_p) }, { _nodes[3], std::get<3>(phi)(xi_p) }, + { _nodes[4], std::get<4>(phi)(xi_p) }, { _nodes[5], std::get<5>(phi)(xi_p) } }; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -161,12 +157,12 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return { { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, - { _nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, - { _nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, - { _nodes[5], std::get<5>(dphi)(xi_p) * J_inv } } }; + return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, + { _nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, + { _nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, + { _nodes[5], std::get<5>(dphi)(xi_p) * J_inv } }; } private: From 25c6913f15f259c9604559213ce0c70cf59d8bbe Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 7 Jun 2025 09:13:35 +0200 Subject: [PATCH 088/273] discretization: add equation map to test for elementary mass and stiffness matrices The equation map in this test ensures consistency between the order of equations in the analytical matrices and in those computed in the test. --- .../discretization/isoparametric_triangle.cc | 76 +++++++++++++------ 1 file changed, 53 insertions(+), 23 deletions(-) diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index b51357197..2b2439fe3 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -18,6 +18,8 @@ using cell_t = mito::geometry::triangle_t<2>; // Gauss quadrature on triangles with degree of exactness 4 using quadrature_rule_t = mito::quadrature::quadrature_rule_t; +// the equation map type (map associating an equation number to each node degree of freedom) +using equation_map_type = std::map; // instantiate the quadrature rule @@ -87,7 +89,7 @@ test_gradient_consistency(const auto & element) template auto test_stiffness_matrix( - const elementT & element, + const elementT & element, const equation_map_type & equation_map, const mito::tensor::matrix_t & analytical_stiffness_matrix) -> void { // create reporting channel @@ -112,17 +114,15 @@ test_stiffness_matrix( auto factor = quadrature_rule.weight(q) * area; // populate the mass matrix - int i = 0; for (const auto & [node_a, dphi_a] : dphi) { - int j = 0; + // get the equation number of {node_a} + int i = equation_map.at(node_a); for (const auto & [node_b, dphi_b] : dphi) { + // get the equation number of {node_b} + int j = equation_map.at(node_b); // assemble the {node_a, node_b} contribution to the mass matrix elementary_stiffness_matrix[{ i, j }] += factor * dphi_a * dphi_b; - // increment the column index - ++j; } - // increment the row index - ++i; } } @@ -140,7 +140,7 @@ test_stiffness_matrix( template auto test_mass_matrix( - const elementT & element, + const elementT & element, const equation_map_type & equation_map, const mito::tensor::matrix_t & analytical_mass_matrix) -> void { // create reporting channel @@ -163,17 +163,15 @@ test_mass_matrix( 0.5 * mito::tensor::determinant(element.jacobian(xi)) * quadrature_rule.weight(q); // populate the mass matrix - int i = 0; - for (const auto & [_, phi_a] : phi) { - int j = 0; - for (const auto & [_, phi_b] : phi) { + for (const auto & [node_a, phi_a] : phi) { + // get the equation number of {node_a} + int i = equation_map.at(node_a); + for (const auto & [node_b, phi_b] : phi) { + // get the equation number of {node_b} + int j = equation_map.at(node_b); // assemble the {node_a, node_b} contribution to the mass matrix elementary_mass_matrix[{ i, j }] += factor * phi_a * phi_b; - // increment the column index - ++j; } - // increment the row index - ++i; } } @@ -211,10 +209,15 @@ TEST(Fem, IsoparametricTriangle) using element_p1_t = typename mito::discretization::isoparametric_simplex<1, cell_t, coord_system_t>::type; + // build the discretization nodes + auto discretization_node_0 = discretization_node_t(); + auto discretization_node_1 = discretization_node_t(); + auto discretization_node_2 = discretization_node_t(); + // a finite element auto element_p1 = element_p1_t( geometric_simplex, - { discretization_node_t(), discretization_node_t(), discretization_node_t() }, + { discretization_node_0, discretization_node_1, discretization_node_2 }, coord_0 - origin, coord_1 - origin, coord_2 - origin); // check that first order shape functions are a partition of unity @@ -223,19 +226,27 @@ TEST(Fem, IsoparametricTriangle) // check that the gradients of first order shape functions sum to 0.0 test_gradient_consistency(element_p1); + // the map between the discretization nodes and the equation numbers + equation_map_type equation_map; + + // populate the equation map + equation_map[discretization_node_0] = 0; + equation_map[discretization_node_1] = 1; + equation_map[discretization_node_2] = 2; + // the analytical elementary stiffness matrix auto analytical_stiffness_matrix = 1.0 / 2.0 * mito::tensor::matrix_t<3>({ 2.0, -1.0, -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0 }); // check that the elementary stiffness matrix is computed correctly - test_stiffness_matrix(element_p1, analytical_stiffness_matrix); + test_stiffness_matrix(element_p1, equation_map, analytical_stiffness_matrix); // the analytical elementary mass matrix auto analytical_mass_matrix = 1.0 / 24.0 * mito::tensor::matrix_t<3>({ 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0 }); - test_mass_matrix(element_p1, analytical_mass_matrix); + test_mass_matrix(element_p1, equation_map, analytical_mass_matrix); } { @@ -243,11 +254,19 @@ TEST(Fem, IsoparametricTriangle) using element_p2_t = typename mito::discretization::isoparametric_simplex<2, cell_t, coord_system_t>::type; + // build the discretization nodes + auto discretization_node_0 = discretization_node_t(); + auto discretization_node_1 = discretization_node_t(); + auto discretization_node_2 = discretization_node_t(); + auto discretization_node_3 = discretization_node_t(); + auto discretization_node_4 = discretization_node_t(); + auto discretization_node_5 = discretization_node_t(); + // a finite element auto element_p2 = element_p2_t( geometric_simplex, - { discretization_node_t(), discretization_node_t(), discretization_node_t(), - discretization_node_t(), discretization_node_t(), discretization_node_t() }, + { discretization_node_0, discretization_node_1, discretization_node_2, + discretization_node_3, discretization_node_4, discretization_node_5 }, coord_0 - origin, coord_1 - origin, coord_2 - origin); // check that second order shape functions are a partition of unity @@ -256,6 +275,17 @@ TEST(Fem, IsoparametricTriangle) // check that the gradients of second order shape functions sum to 0.0 test_gradient_consistency(element_p2); + // the map between the discretization nodes and the equation numbers + equation_map_type equation_map; + + // populate the equation map + equation_map[discretization_node_0] = 0; + equation_map[discretization_node_1] = 1; + equation_map[discretization_node_2] = 2; + equation_map[discretization_node_3] = 3; + equation_map[discretization_node_4] = 4; + equation_map[discretization_node_5] = 5; + // the analytical elementary stiffness matrix auto analytical_stiffness_matrix = mito::tensor::matrix_t<6>( { 1.0, 1.0 / 6.0, 1.0 / 6.0, -2.0 / 3.0, 0.0, -2.0 / 3.0, @@ -266,7 +296,7 @@ TEST(Fem, IsoparametricTriangle) -2.0 / 3.0, 0.0, -2.0 / 3.0, 0.0, -4.0 / 3.0, 8.0 / 3.0 }); // check that the elementary stiffness matrix is computed correctly - test_stiffness_matrix(element_p2, analytical_stiffness_matrix); + test_stiffness_matrix(element_p2, equation_map, analytical_stiffness_matrix); // the analytical elementary mass matrix auto analytical_mass_matrix = mito::tensor::matrix_t<6>( @@ -277,7 +307,7 @@ TEST(Fem, IsoparametricTriangle) -1.0 / 90.0, 0.0, 0.0, 2.0 / 45.0, 4.0 / 45.0, 2.0 / 45.0, 0.0, -1.0 / 90.0, 0.0, 2.0 / 45.0, 2.0 / 45.0, 4.0 / 45.0 }); - test_mass_matrix(element_p2, analytical_mass_matrix); + test_mass_matrix(element_p2, equation_map, analytical_mass_matrix); } // all done From b47a31d8a35e787e65164b45c1094521bd24c3e6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 7 Jun 2025 16:59:02 +0200 Subject: [PATCH 089/273] discretization: fix typo in comment --- tests/mito.lib/discretization/poisson.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 3ac03f68f..7edd24dbc 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -15,7 +15,7 @@ using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN using cell_t = mito::geometry::triangle_t<2>; // the type of simplex using simplex_t = cell_t::simplex_type; -// Gauss quadrature on triangles with degree of exactness 1 +// Gauss quadrature on triangles with degree of exactness 2 using quadrature_rule_t = mito::quadrature::quadrature_rule_t; From 4ebef5325208bfc3110aa0d0a9aa4a41e6c26751 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 7 Jun 2025 17:13:17 +0200 Subject: [PATCH 090/273] discretization: implement discretization with second order Galerkin finite elements --- lib/mito/discretization/FunctionSpace.h | 160 ++++++++++++++++++----- tests/mito.lib/discretization/poisson.cc | 2 +- 2 files changed, 126 insertions(+), 36 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index ca1aac946..b2c5871d6 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -55,44 +55,134 @@ namespace mito::discretization { _constraints(constraints), _node_map() { - // get the coordinate system of the manifold - const auto & coord_system = manifold.coordinate_system(); - - // loop on the cells of the mesh - for (const auto & cell : manifold.elements()) { - - // get the nodes of the cell - const auto & nodes = cell.nodes(); - - // the origin of the coordinate system - auto origin = typename coord_system_type::coordinates_type{}; - - // the coordinates of the nodes of the triangle - auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; - auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; - auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; - - // add the nodes to the map (if the mesh node is already present in the map, then - // the present discretization node is used) - auto node_0 = - _node_map.insert({ nodes[0], discretization_node_type() }).first->second; - auto node_1 = - _node_map.insert({ nodes[1], discretization_node_type() }).first->second; - auto node_2 = - _node_map.insert({ nodes[2], discretization_node_type() }).first->second; - - // create a finite element for each cell and add it to the pile - _elements.emplace( - cell, discretization_nodes_type{ node_0, node_1, node_2 }, x_0, x_1, x_2); + // TOFIX: the following code is for a CG discretization, we should define this as a + // function some place else and just call it here + + // first order discretization + if constexpr (degree == 1) { + + // get the coordinate system of the manifold + const auto & coord_system = manifold.coordinate_system(); + + // loop on the cells of the mesh + for (const auto & cell : manifold.elements()) { + + // get the nodes of the cell + const auto & nodes = cell.nodes(); + + // the origin of the coordinate system + auto origin = typename coord_system_type::coordinates_type{}; + + // the coordinates of the nodes of the triangle + auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; + auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; + auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; + + // add the nodes to the map (if the mesh node is already present in the map, + // then the present discretization node is used) + auto node_0 = + _node_map.insert({ nodes[0], discretization_node_type() }).first->second; + auto node_1 = + _node_map.insert({ nodes[1], discretization_node_type() }).first->second; + auto node_2 = + _node_map.insert({ nodes[2], discretization_node_type() }).first->second; + + // create a finite element for each cell and add it to the pile + _elements.emplace( + cell, discretization_nodes_type{ node_0, node_1, node_2 }, x_0, x_1, x_2); + } + + // populate the constrained nodes + for (const auto & cell : constraints.domain().cells()) { + for (const auto & node : cell.nodes()) { + // get the discretization node associated with the mesh node from the map + auto it = _node_map.find(node); + // add the node to the constrained nodes + _constrained_nodes.insert(it->second); + } + } } - // populate the constrained nodes - for (const auto & cell : constraints.domain().cells()) { - for (const auto & node : cell.nodes()) { - // get the discretization node associated with the mesh node from the map - auto it = _node_map.find(node); + // second order discretization + if constexpr (degree == 2) { + // id type of mesh nodes + using mesh_node_id_t = utilities::index_t; + + // the type of a map between the two vertices and the middle discretization nodes + using mid_nodes_map_type = + std::map, discretization_node_type>; + + // create a map to store the mid nodes + auto mid_nodes_map = mid_nodes_map_type(); + + // get the coordinate system of the manifold + const auto & coord_system = manifold.coordinate_system(); + + // loop on the cells of the mesh + for (const auto & cell : manifold.elements()) { + + // get the nodes of the cell + const auto & nodes = cell.nodes(); + + // the origin of the coordinate system + auto origin = typename coord_system_type::coordinates_type{}; + + // the coordinates of the nodes of the triangle + auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; + auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; + auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; + + // add the nodes to the map (if the mesh node is already present in the map, + // then the present discretization node is used) + auto node_0 = + _node_map.insert({ nodes[0], discretization_node_type() }).first->second; + auto node_1 = + _node_map.insert({ nodes[1], discretization_node_type() }).first->second; + auto node_2 = + _node_map.insert({ nodes[2], discretization_node_type() }).first->second; + + auto ordered_nodes_3 = (node_0.id() < node_1.id()) ? + std::array{ node_0.id(), node_1.id() } : + std::array{ node_1.id(), node_0.id() }; + auto node_3 = + mid_nodes_map.insert({ ordered_nodes_3, discretization_node_type() }) + .first->second; + auto ordered_nodes_4 = (node_1.id() < node_2.id()) ? + std::array{ node_1.id(), node_2.id() } : + std::array{ node_2.id(), node_1.id() }; + auto node_4 = + mid_nodes_map.insert({ ordered_nodes_4, discretization_node_type() }) + .first->second; + auto ordered_nodes_5 = (node_2.id() < node_0.id()) ? + std::array{ node_2.id(), node_0.id() } : + std::array{ node_0.id(), node_2.id() }; + auto node_5 = + mid_nodes_map.insert({ ordered_nodes_5, discretization_node_type() }) + .first->second; + + // create a finite element for each cell and add it to the pile + _elements.emplace( + cell, + discretization_nodes_type{ node_0, node_1, node_2, node_3, node_4, node_5 }, + x_0, x_1, x_2); + } + + // populate the constrained nodes + for (const auto & cell : constraints.domain().cells()) { + for (const auto & node : cell.nodes()) { + // get the discretization node associated with the mesh node from the map + auto it = _node_map.find(node); + // add the node to the constrained nodes + _constrained_nodes.insert(it->second); + } + auto node_0 = _node_map.at(cell.nodes()[0]); + auto node_1 = _node_map.at(cell.nodes()[1]); + auto ordered_nodes = (node_0.id() < node_1.id()) ? + std::array{ node_0.id(), node_1.id() } : + std::array{ node_1.id(), node_0.id() }; + auto node = mid_nodes_map.at(ordered_nodes); // add the node to the constrained nodes - _constrained_nodes.insert(it->second); + _constrained_nodes.insert(node); } } diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 7edd24dbc..d0822c6c6 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -59,7 +59,7 @@ TEST(Fem, PoissonSquare) auto manifold = mito::manifolds::manifold(mesh, coord_system); // the function space (linear elements on the manifold) - auto function_space = mito::discretization::function_space<1>(manifold, constraints); + auto function_space = mito::discretization::function_space<2>(manifold, constraints); // the discrete system auto discrete_system = mito::discretization::discrete_system(function_space); From f9f65afd36bb780b8d7ecee7447e0c153f565a85 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 8 Jun 2025 09:50:23 +0200 Subject: [PATCH 091/273] discretization: narrative edits --- lib/mito/discretization/FunctionSpace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index b2c5871d6..683f41c5b 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -34,7 +34,7 @@ namespace mito::discretization { typename isoparametric_simplex::type; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; - // the node type + // the discretization node type using discretization_node_type = typename element_type::node_type; // the nodes type using discretization_nodes_type = typename element_type::nodes_type; From 82358e0a653d4cd2bb431b88793a06594f3e93e8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 8 Jun 2025 09:55:18 +0200 Subject: [PATCH 092/273] discretization: in class {IsoparametricTriangle}, rename {dim} to {parametric_dim} --- lib/mito/discretization/IsoparametricTriangle.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index 574669139..a436b9af3 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -21,10 +21,10 @@ namespace mito::discretization { // the geometric simplex type using geometric_simplex_type = geometricSimplexT; // the parametric dimension - static constexpr int dim = 2; + static constexpr int parametric_dim = 2; // the parametric coordinates type using parametric_coordinates_type = - mito::geometry::coordinates_t; + mito::geometry::coordinates_t; protected: // the function extracting the 0 component of a parametric point From bcb6193b773015a270c7f9b97e4161065b2b3e0c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 8 Jun 2025 15:19:32 +0200 Subject: [PATCH 093/273] discretization: class {IsoparametricTriangle}, is not template wrt the geometric simplex type any more It is conceptually wrong for this class to be templated on the geometric simplex type, because the geometric simplex concept is general with respect to the simplex order, while a triangle is a 2-simplex. --- lib/mito/discretization/FunctionSpace.h | 3 +- .../discretization/IsoparametricTriangle.h | 9 +-- .../discretization/IsoparametricTriangle1.h | 56 +++++++----------- .../discretization/IsoparametricTriangle2.h | 57 +++++++------------ .../isoparametric_simplex_library.h | 28 ++++----- .../discretization/isoparametric_triangle.cc | 6 +- .../isoparametric_triangle_p1.cc | 3 +- .../isoparametric_triangle_p2.cc | 3 +- 8 files changed, 58 insertions(+), 107 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 683f41c5b..df2a2bc5a 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -30,8 +30,7 @@ namespace mito::discretization { // the degree of the finite element static constexpr int degree = p; // typedef for a finite element - using element_type = - typename isoparametric_simplex::type; + using element_type = typename isoparametric_simplex::type; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; // the discretization node type diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index a436b9af3..37db9b961 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -13,18 +13,13 @@ namespace mito::discretization { - - template class IsoparametricTriangle : public utilities::Invalidatable { protected: // the geometric simplex type - using geometric_simplex_type = geometricSimplexT; - // the parametric dimension - static constexpr int parametric_dim = 2; + using geometric_simplex_type = geometry::triangle_t<2>; // the parametric coordinates type - using parametric_coordinates_type = - mito::geometry::coordinates_t; + using parametric_coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; protected: // the function extracting the 0 component of a parametric point diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 6e5e81a40..f6ab8bff9 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -8,19 +8,13 @@ // DESIGN NOTES -// Class {IsoparametricTriangle1} represents a second order simplex equipped with linear shape -// functions defined in the parametric space. +// Class {IsoparametricTriangle1} represents a second order simplex living in 2D cartesian space, +// equipped with linear shape functions defined in the parametric space. namespace mito::discretization { - // QUESTION: should we enforce the use of a cartesian coordinate system for this type of - // isoparametric simplex? In this case, the coordinate system type can be sinthesized from the - // geometric simplex type (which has knowledge of the dimension of the embedding space) - template < - geometry::geometric_simplex_c geometricSimplexT, - geometry::coordinate_system_c coordinateSystemT> - class IsoparametricTriangle1 : public IsoparametricTriangle { + class IsoparametricTriangle1 : public IsoparametricTriangle { public: // the number of discretization nodes @@ -31,22 +25,11 @@ namespace mito::discretization { using nodes_type = std::array; // type of a point in barycentric coordinates using barycentric_coordinates_type = - typename geometricSimplexT::barycentric_coordinates_type; - - private: - // the geometric simplex type - using geometric_simplex_type = geometricSimplexT; - // the global coordinate system type - using coordinate_system_type = coordinateSystemT; - // the base class - using isoparametric_triangle_type = IsoparametricTriangle; - // the parametric coordinates type - using parametric_coordinates_type = - typename isoparametric_triangle_type::parametric_coordinates_type; + typename geometric_simplex_type::barycentric_coordinates_type; private: // - using vector_type = tensor::vector_t; + using vector_type = tensor::vector_t<2>; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure using evaluated_shape_functions_type = std::map; @@ -55,9 +38,9 @@ namespace mito::discretization { private: // linear shape functions on the triangle - static constexpr auto phi_0 = isoparametric_triangle_type::xi_0; - static constexpr auto phi_1 = isoparametric_triangle_type::xi_1; - static constexpr auto phi_2 = isoparametric_triangle_type::xi_2; + static constexpr auto phi_0 = xi_0; + static constexpr auto phi_1 = xi_1; + static constexpr auto phi_2 = xi_2; // the shape functions static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); @@ -69,10 +52,10 @@ namespace mito::discretization { public: // the default constructor - constexpr IsoparametricTriangle1( + inline IsoparametricTriangle1( const geometric_simplex_type & geometric_simplex, const nodes_type & nodes, const vector_type & x0, const vector_type & x1, const vector_type & x2) : - IsoparametricTriangle(geometric_simplex), + IsoparametricTriangle(geometric_simplex), _nodes(nodes), _x0(x0), _x1(x1), @@ -80,26 +63,27 @@ namespace mito::discretization { {} // destructor - constexpr ~IsoparametricTriangle1() = default; + inline ~IsoparametricTriangle1() = default; // delete move constructor - constexpr IsoparametricTriangle1(IsoparametricTriangle1 &&) noexcept = delete; + inline IsoparametricTriangle1(IsoparametricTriangle1 &&) noexcept = delete; // delete copy constructor - constexpr IsoparametricTriangle1(const IsoparametricTriangle1 &) = delete; + inline IsoparametricTriangle1(const IsoparametricTriangle1 &) = delete; // delete assignment operator - constexpr IsoparametricTriangle1 & operator=(const IsoparametricTriangle1 &) = delete; + inline IsoparametricTriangle1 & operator=(const IsoparametricTriangle1 &) = delete; // delete move assignment operator - constexpr IsoparametricTriangle1 & operator=(IsoparametricTriangle1 &&) noexcept = delete; + inline IsoparametricTriangle1 & operator=(IsoparametricTriangle1 &&) noexcept = delete; public: // get the nodes - constexpr auto nodes() const noexcept -> const nodes_type & { return _nodes; } + inline auto nodes() const noexcept -> const nodes_type & { return _nodes; } // get all the shape functions evaluated at the point {xi} in barycentric coordinates - auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type + inline auto shape(const barycentric_coordinates_type & xi) const + -> evaluated_shape_functions_type { // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -111,7 +95,7 @@ namespace mito::discretization { } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - constexpr auto jacobian(const barycentric_coordinates_type & xi) const + inline auto jacobian(const barycentric_coordinates_type & xi) const { // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} @@ -129,7 +113,7 @@ namespace mito::discretization { // get all the shape functions gradients evaluated at the point {xi} in barycentric // coordinates - auto gradient(const barycentric_coordinates_type & xi) const + inline auto gradient(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_gradients_type { // the jacobian of the mapping from the reference element to the physical element diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index 2316a3fcf..82239e265 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -8,17 +8,14 @@ // DESIGN NOTES -// Class {IsoparametricTriangle2} represents a second order simplex equipped with quadratic shape -// functions defined in the parametric space. +// Class {IsoparametricTriangle2} represents a second order simplex living in 2D cartesian space +// equipped with quadratic shape functions defined in the parametric space. // TODO: rename to {IsoparametricTriangleP1}, {IsoparametricTriangleP2}, ... namespace mito::discretization { - template < - geometry::geometric_simplex_c geometricSimplexT, - geometry::coordinate_system_c coordinateSystemT> - class IsoparametricTriangle2 : public IsoparametricTriangle { + class IsoparametricTriangle2 : public IsoparametricTriangle { public: // the number of discretization nodes @@ -29,24 +26,11 @@ namespace mito::discretization { using nodes_type = std::array; // type of a point in barycentric coordinates using barycentric_coordinates_type = - typename geometricSimplexT::barycentric_coordinates_type; + typename geometric_simplex_type::barycentric_coordinates_type; private: - // the geometric simplex type - using geometric_simplex_type = geometricSimplexT; - // the global coordinate system type - using coordinate_system_type = coordinateSystemT; - // the base class - using isoparametric_triangle_type = IsoparametricTriangle; - // the parametric coordinates type - using parametric_coordinates_type = - typename isoparametric_triangle_type::parametric_coordinates_type; - - private: - // QUESTION: will we use the same class for triangles embedded in 3D? If not, we can assume - // that the coordinates are in 2D space. Also, we would need to add a {requires} clause to - // ensure that the geometric simplex is embedded in 2D. - using vector_type = tensor::vector_t; + // + using vector_type = tensor::vector_t<2>; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure using evaluated_shape_functions_type = std::map; @@ -55,9 +39,9 @@ namespace mito::discretization { private: // strip the namespace - static constexpr auto xi_0 = isoparametric_triangle_type::xi_0; - static constexpr auto xi_1 = isoparametric_triangle_type::xi_1; - static constexpr auto xi_2 = isoparametric_triangle_type::xi_2; + static constexpr auto xi_0 = xi_0; + static constexpr auto xi_1 = xi_1; + static constexpr auto xi_2 = xi_2; // quadratic shape functions on the triangle static constexpr auto phi_3 = 4.0 * xi_0 * xi_1; @@ -78,10 +62,10 @@ namespace mito::discretization { public: // the default constructor - constexpr IsoparametricTriangle2( + inline IsoparametricTriangle2( const geometric_simplex_type & geometric_simplex, const nodes_type & nodes, const vector_type & x0, const vector_type & x1, const vector_type & x2) : - IsoparametricTriangle(geometric_simplex), + IsoparametricTriangle(geometric_simplex), _nodes(nodes), _x0(x0), _x1(x1), @@ -89,26 +73,27 @@ namespace mito::discretization { {} // destructor - constexpr ~IsoparametricTriangle2() = default; + inline ~IsoparametricTriangle2() = default; // delete move constructor - constexpr IsoparametricTriangle2(IsoparametricTriangle2 &&) noexcept = delete; + inline IsoparametricTriangle2(IsoparametricTriangle2 &&) noexcept = delete; // delete copy constructor - constexpr IsoparametricTriangle2(const IsoparametricTriangle2 &) = delete; + inline IsoparametricTriangle2(const IsoparametricTriangle2 &) = delete; // delete assignment operator - constexpr IsoparametricTriangle2 & operator=(const IsoparametricTriangle2 &) = delete; + inline IsoparametricTriangle2 & operator=(const IsoparametricTriangle2 &) = delete; // delete move assignment operator - constexpr IsoparametricTriangle2 & operator=(IsoparametricTriangle2 &&) noexcept = delete; + inline IsoparametricTriangle2 & operator=(IsoparametricTriangle2 &&) noexcept = delete; public: // get the nodes - constexpr auto nodes() const noexcept -> const nodes_type & { return _nodes; } + inline auto nodes() const noexcept -> const nodes_type & { return _nodes; } // get all the shape functions evaluated at the point {xi} in barycentric coordinates - auto shape(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_type + inline auto shape(const barycentric_coordinates_type & xi) const + -> evaluated_shape_functions_type { // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; @@ -120,7 +105,7 @@ namespace mito::discretization { } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - constexpr auto jacobian(const barycentric_coordinates_type & xi) const + inline auto jacobian(const barycentric_coordinates_type & xi) const { auto x3 = 0.5 * (_x0 + _x1); auto x4 = 0.5 * (_x1 + _x2); @@ -143,7 +128,7 @@ namespace mito::discretization { // get all the shape functions gradients evaluated at the point {xi} in barycentric // coordinates - auto gradient(const barycentric_coordinates_type & xi) const + inline auto gradient(const barycentric_coordinates_type & xi) const -> evaluated_shape_functions_gradients_type { // the jacobian of the mapping from the reference element to the physical element diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h index 9d2cf0041..aee5b09cc 100644 --- a/lib/mito/discretization/isoparametric_simplex_library.h +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -15,28 +15,20 @@ namespace mito::discretization { // struct storing the type of an isoparametric simplex of polynomial degree {degree} on a - // geometric simplex of type {geometricSimplexT} and coordinate system {coordinateSystemT} - template < - int degree, geometry::geometric_simplex_c geometricSimplexT, - geometry::coordinate_system_c coordinateSystemT> - // require that the geometric simplex spatial dimension matches that of the coordinate system - requires(coordinateSystemT::dim == geometricSimplexT::dim) + // geometric simplex of type {geometricSimplexT} + template struct isoparametric_simplex {}; - // specialization for linear shape functions on triangles - template - struct isoparametric_simplex< - 1, geometry::triangle_t, coordinateSystemT> { - using type = - IsoparametricTriangle1, coordinateSystemT>; + // specialization for linear shape functions on triangles in 2D + template <> + struct isoparametric_simplex<1, geometry::triangle_t<2>> { + using type = IsoparametricTriangle1; }; - // specialization for quadratic shape functions on triangles - template - struct isoparametric_simplex< - 2, geometry::triangle_t, coordinateSystemT> { - using type = - IsoparametricTriangle2, coordinateSystemT>; + // specialization for quadratic shape functions on triangles in 2D + template <> + struct isoparametric_simplex<2, geometry::triangle_t<2>> { + using type = IsoparametricTriangle2; }; } diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 2b2439fe3..e1fb1b63d 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -206,8 +206,7 @@ TEST(Fem, IsoparametricTriangle) { // first order isoparametric triangle - using element_p1_t = - typename mito::discretization::isoparametric_simplex<1, cell_t, coord_system_t>::type; + using element_p1_t = mito::discretization::isoparametric_simplex<1, cell_t>::type; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); @@ -251,8 +250,7 @@ TEST(Fem, IsoparametricTriangle) { // second order isoparametric triangle - using element_p2_t = - typename mito::discretization::isoparametric_simplex<2, cell_t, coord_system_t>::type; + using element_p2_t = mito::discretization::isoparametric_simplex<2, cell_t>::type; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc index 338527eb6..c64c1fe96 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc @@ -16,8 +16,7 @@ using discretization_node_t = mito::discretization::discretization_node_t; // the type of cell using cell_t = mito::geometry::triangle_t<2>; // first order isoparametric triangle -using element_t = - typename mito::discretization::isoparametric_simplex<1, cell_t, coord_system_t>::type; +using element_t = mito::discretization::isoparametric_simplex<1, cell_t>::type; // the barycentric coordinates type using barycentric_coordinates_t = typename element_t::barycentric_coordinates_type; diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc index 189e14a42..b4160cd4f 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc @@ -16,8 +16,7 @@ using discretization_node_t = mito::discretization::discretization_node_t; // the type of cell using cell_t = mito::geometry::triangle_t<2>; // second order isoparametric triangle -using element_t = - typename mito::discretization::isoparametric_simplex<2, cell_t, coord_system_t>::type; +using element_t = mito::discretization::isoparametric_simplex<2, cell_t>::type; // the barycentric coordinates type using barycentric_coordinates_t = typename element_t::barycentric_coordinates_type; From 7e5a65b9e5dae9fc3d963a2f911d0787be9f8d78 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 8 Jun 2025 15:21:50 +0200 Subject: [PATCH 094/273] .cmake: suppress compiler warning "parameter passing ... when C++17 is enabled changed to match C++14 in GCC 10.1" --- .cmake/mito_init.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.cmake/mito_init.cmake b/.cmake/mito_init.cmake index 31d5997a3..e75e725eb 100644 --- a/.cmake/mito_init.cmake +++ b/.cmake/mito_init.cmake @@ -35,7 +35,7 @@ function(mito_cxxInit) set(CMAKE_CXX_STANDARD_REQUIRED True PARENT_SCOPE) # additional compilation flags - set(CMAKE_CXX_FLAGS "-fdiagnostics-color=always -Wall -Wextra -pedantic -Werror" PARENT_SCOPE) + set(CMAKE_CXX_FLAGS "-fdiagnostics-color=always -Wall -Wextra -pedantic -Werror -Wno-psabi" PARENT_SCOPE) # all done endfunction(mito_cxxInit) From 2c5d27357e8579f6db6bb4a89433a9317a18793e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 21 Jun 2025 13:19:05 +0200 Subject: [PATCH 095/273] discretization: move {node_type} alias to parent class {IsoparametricTriangle} --- lib/mito/discretization/IsoparametricTriangle.h | 3 +++ lib/mito/discretization/IsoparametricTriangle1.h | 2 -- lib/mito/discretization/IsoparametricTriangle2.h | 2 -- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index 37db9b961..0693d7d87 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -14,6 +14,9 @@ namespace mito::discretization { class IsoparametricTriangle : public utilities::Invalidatable { + public: + // the discretization node type + using node_type = discretization_node_t; protected: // the geometric simplex type diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index f6ab8bff9..80eed7518 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -19,8 +19,6 @@ namespace mito::discretization { public: // the number of discretization nodes static constexpr int n_nodes = 3; - // the node type - using node_type = discretization_node_t; // a collection of discretization nodes using nodes_type = std::array; // type of a point in barycentric coordinates diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index 82239e265..bd0759f3a 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -20,8 +20,6 @@ namespace mito::discretization { public: // the number of discretization nodes static constexpr int n_nodes = 6; - // the node type - using node_type = discretization_node_t; // a collection of discretization nodes using nodes_type = std::array; // type of a point in barycentric coordinates From e2d8cfdcbbc4e4d2ca28e7af7308873e27412f50 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 21 Jun 2025 15:48:36 +0200 Subject: [PATCH 096/273] discretization: rename nodes to discretization nodes --- lib/mito/discretization/FunctionSpace.h | 4 +- .../discretization/IsoparametricTriangle.h | 2 +- .../discretization/IsoparametricTriangle1.h | 43 +++++++++-------- .../discretization/IsoparametricTriangle2.h | 48 +++++++++++-------- lib/mito/discretization/utilities.h | 2 +- 5 files changed, 56 insertions(+), 43 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index df2a2bc5a..e1ab1a0ad 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -34,9 +34,9 @@ namespace mito::discretization { // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; // the discretization node type - using discretization_node_type = typename element_type::node_type; + using discretization_node_type = typename element_type::discretization_node_type; // the nodes type - using discretization_nodes_type = typename element_type::nodes_type; + using discretization_nodes_type = typename element_type::discretization_nodes_type; // the constrained nodes type using constrained_nodes_type = std::set; diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index 0693d7d87..483f74cfd 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -16,7 +16,7 @@ namespace mito::discretization { class IsoparametricTriangle : public utilities::Invalidatable { public: // the discretization node type - using node_type = discretization_node_t; + using discretization_node_type = discretization_node_t; protected: // the geometric simplex type diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 80eed7518..19cb807a9 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -17,10 +17,10 @@ namespace mito::discretization { class IsoparametricTriangle1 : public IsoparametricTriangle { public: - // the number of discretization nodes + // the number of discretization discretization nodes static constexpr int n_nodes = 3; - // a collection of discretization nodes - using nodes_type = std::array; + // a collection of discretization discretization nodes + using discretization_nodes_type = std::array; // type of a point in barycentric coordinates using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; @@ -30,9 +30,10 @@ namespace mito::discretization { using vector_type = tensor::vector_t<2>; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure - using evaluated_shape_functions_type = std::map; + using evaluated_shape_functions_type = + std::map; using evaluated_shape_functions_gradients_type = - std::map>; + std::map>; private: // linear shape functions on the triangle @@ -51,10 +52,11 @@ namespace mito::discretization { public: // the default constructor inline IsoparametricTriangle1( - const geometric_simplex_type & geometric_simplex, const nodes_type & nodes, - const vector_type & x0, const vector_type & x1, const vector_type & x2) : + const geometric_simplex_type & geometric_simplex, + const discretization_nodes_type & discretization_nodes, const vector_type & x0, + const vector_type & x1, const vector_type & x2) : IsoparametricTriangle(geometric_simplex), - _nodes(nodes), + _discretization_nodes(discretization_nodes), _x0(x0), _x1(x1), _x2(x2) @@ -76,8 +78,11 @@ namespace mito::discretization { inline IsoparametricTriangle1 & operator=(IsoparametricTriangle1 &&) noexcept = delete; public: - // get the nodes - inline auto nodes() const noexcept -> const nodes_type & { return _nodes; } + // get the discretization nodes + inline auto discretization_nodes() const noexcept -> const discretization_nodes_type & + { + return _discretization_nodes; + } // get all the shape functions evaluated at the point {xi} in barycentric coordinates inline auto shape(const barycentric_coordinates_type & xi) const @@ -87,9 +92,9 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(phi)(xi_p) }, - { _nodes[1], std::get<1>(phi)(xi_p) }, - { _nodes[2], std::get<2>(phi)(xi_p) } }; + return { { _discretization_nodes[0], std::get<0>(phi)(xi_p) }, + { _discretization_nodes[1], std::get<1>(phi)(xi_p) }, + { _discretization_nodes[2], std::get<2>(phi)(xi_p) } }; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -125,19 +130,19 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv } }; + return { { _discretization_nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _discretization_nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _discretization_nodes[2], std::get<2>(dphi)(xi_p) * J_inv } }; } private: - // the nodes of the simplex - const nodes_type _nodes; + // the discretization nodes of the simplex + const discretization_nodes_type _discretization_nodes; // QUESTION: alternatively to the coordinates of the vertices, we could store the points // associated with the vertices of the triangle, so the coordinates can be fetched from the // coordinate system // - // the coordinates of the nodes of the triangle + // the coordinates of the discretization nodes of the triangle const vector_type _x0; const vector_type _x1; const vector_type _x2; diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index bd0759f3a..198888b95 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -21,7 +21,7 @@ namespace mito::discretization { // the number of discretization nodes static constexpr int n_nodes = 6; // a collection of discretization nodes - using nodes_type = std::array; + using discretization_nodes_type = std::array; // type of a point in barycentric coordinates using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; @@ -31,9 +31,10 @@ namespace mito::discretization { using vector_type = tensor::vector_t<2>; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure - using evaluated_shape_functions_type = std::map; + using evaluated_shape_functions_type = + std::map; using evaluated_shape_functions_gradients_type = - std::map>; + std::map>; private: // strip the namespace @@ -61,10 +62,11 @@ namespace mito::discretization { public: // the default constructor inline IsoparametricTriangle2( - const geometric_simplex_type & geometric_simplex, const nodes_type & nodes, - const vector_type & x0, const vector_type & x1, const vector_type & x2) : + const geometric_simplex_type & geometric_simplex, + const discretization_nodes_type & discretization_nodes, const vector_type & x0, + const vector_type & x1, const vector_type & x2) : IsoparametricTriangle(geometric_simplex), - _nodes(nodes), + _discretization_nodes(discretization_nodes), _x0(x0), _x1(x1), _x2(x2) @@ -86,8 +88,11 @@ namespace mito::discretization { inline IsoparametricTriangle2 & operator=(IsoparametricTriangle2 &&) noexcept = delete; public: - // get the nodes - inline auto nodes() const noexcept -> const nodes_type & { return _nodes; } + // get the discretization nodes + inline auto discretization_nodes() const noexcept -> const discretization_nodes_type & + { + return _discretization_nodes; + } // get all the shape functions evaluated at the point {xi} in barycentric coordinates inline auto shape(const barycentric_coordinates_type & xi) const @@ -97,9 +102,12 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(phi)(xi_p) }, { _nodes[1], std::get<1>(phi)(xi_p) }, - { _nodes[2], std::get<2>(phi)(xi_p) }, { _nodes[3], std::get<3>(phi)(xi_p) }, - { _nodes[4], std::get<4>(phi)(xi_p) }, { _nodes[5], std::get<5>(phi)(xi_p) } }; + return { { _discretization_nodes[0], std::get<0>(phi)(xi_p) }, + { _discretization_nodes[1], std::get<1>(phi)(xi_p) }, + { _discretization_nodes[2], std::get<2>(phi)(xi_p) }, + { _discretization_nodes[3], std::get<3>(phi)(xi_p) }, + { _discretization_nodes[4], std::get<4>(phi)(xi_p) }, + { _discretization_nodes[5], std::get<5>(phi)(xi_p) } }; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -140,23 +148,23 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return { { _nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, - { _nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, - { _nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, - { _nodes[5], std::get<5>(dphi)(xi_p) * J_inv } }; + return { { _discretization_nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, + { _discretization_nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, + { _discretization_nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, + { _discretization_nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, + { _discretization_nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, + { _discretization_nodes[5], std::get<5>(dphi)(xi_p) * J_inv } }; } private: - // the nodes of the simplex - const nodes_type _nodes; + // the discretization nodes of the simplex + const discretization_nodes_type _discretization_nodes; // QUESTION: alternatively to the coordinates of the vertices, we could store the points // associated with the vertices of the triangle, so the coordinates can be fetched from the // coordinate system // // TOFIX: perhaps these can be stored in the base class? - // the coordinates of the nodes of the triangle + // the coordinates of the discretization nodes of the triangle const vector_type _x0; const vector_type _x1; const vector_type _x2; diff --git a/lib/mito/discretization/utilities.h b/lib/mito/discretization/utilities.h index 273b44de4..19cb5ed25 100644 --- a/lib/mito/discretization/utilities.h +++ b/lib/mito/discretization/utilities.h @@ -14,7 +14,7 @@ namespace mito::discretization { inline auto get_nodes(const functionSpaceT & function_space, nodesCollectionT & nodes) -> void { for (const auto & element : function_space.elements()) { - for (const auto & node : element.nodes()) { + for (const auto & node : element.discretization_nodes()) { nodes.insert(node); } } From f55cae778e1e855b90da7d49c0129c489131e52f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 23 Jun 2025 09:56:18 +0200 Subject: [PATCH 097/273] geometry: {constexpr} class {CoordinateSystem} --- lib/mito/geometry/CoordinateSystem.h | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/lib/mito/geometry/CoordinateSystem.h b/lib/mito/geometry/CoordinateSystem.h index aab0c82fb..3e9b3d947 100644 --- a/lib/mito/geometry/CoordinateSystem.h +++ b/lib/mito/geometry/CoordinateSystem.h @@ -28,12 +28,13 @@ namespace mito::geometry { public: // constructor - CoordinateSystem() : _coordinates_map() {} + constexpr CoordinateSystem() : _coordinates_map() {} // constructor for change of coordinates template requires(coordT::dim == otherCoordT::dim) - CoordinateSystem(const CoordinateSystem & other_coord_sys) : _coordinates_map() + constexpr CoordinateSystem(const CoordinateSystem & other_coord_sys) : + _coordinates_map() { // loop on the points and coordinates of the other coordinate system for (const auto & [point, coord] : other_coord_sys) { @@ -43,24 +44,24 @@ namespace mito::geometry { } // destructor - ~CoordinateSystem() = default; + constexpr ~CoordinateSystem() = default; private: // delete copy constructor - CoordinateSystem(const CoordinateSystem &) = delete; + constexpr CoordinateSystem(const CoordinateSystem &) = delete; // delete move constructor - CoordinateSystem(CoordinateSystem &&) noexcept = delete; + constexpr CoordinateSystem(CoordinateSystem &&) noexcept = delete; // delete assignment operator - void operator=(const CoordinateSystem &) = delete; + constexpr void operator=(const CoordinateSystem &) = delete; // delete move assignment operator - void operator=(CoordinateSystem &&) noexcept = delete; + constexpr void operator=(CoordinateSystem &&) noexcept = delete; public: // place the {point} at location {coord} - auto place(const point_type & point, const coordinates_type & coord) -> void + constexpr auto place(const point_type & point, const coordinates_type & coord) -> void { // record the new point-coordinates pair auto ret = _coordinates_map.emplace(point, coord); @@ -81,14 +82,14 @@ namespace mito::geometry { } // fetch the coordinates at point {point} - auto coordinates(const point_type & point) const -> const coordinates_type & + constexpr auto coordinates(const point_type & point) const -> const coordinates_type & { // look-up the coordinates of the point in the map return _coordinates_map.at(point); } // get the coordinates of the midpoint between {point_a} and {point_b} - auto midpoint(const point_type & point_a, const point_type & point_b) const + constexpr auto midpoint(const point_type & point_a, const point_type & point_b) const -> coordinates_type { // easy enough @@ -96,8 +97,8 @@ namespace mito::geometry { } // support for ranged for loops - inline auto begin() const { return std::begin(_coordinates_map); } - inline auto end() const { return std::end(_coordinates_map); } + constexpr auto begin() const { return std::begin(_coordinates_map); } + constexpr auto end() const { return std::end(_coordinates_map); } private: // the coordinates of all points From 29fc55d4da6208a375b8335a3ac5403e313f394a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 23 Jun 2025 09:56:54 +0200 Subject: [PATCH 098/273] geometry: {constexpr} point and vertex accessors in class {GeometricSimplex<0, D>} --- lib/mito/geometry/GeometricSimplex.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mito/geometry/GeometricSimplex.h b/lib/mito/geometry/GeometricSimplex.h index 2f95056fb..78e626f54 100644 --- a/lib/mito/geometry/GeometricSimplex.h +++ b/lib/mito/geometry/GeometricSimplex.h @@ -184,10 +184,10 @@ namespace mito::geometry { public: // accessor for the underlying vertex - auto vertex() const noexcept -> const vertex_type & { return _vertex; } + constexpr auto vertex() const noexcept -> const vertex_type & { return _vertex; } // accessor for the underlying point - auto point() const noexcept -> const point_type & { return _point; } + constexpr auto point() const noexcept -> const point_type & { return _point; } private: // the vertex that this node is attached to From d5fc46b09e0e9dc9dea524e445c427c9c88003d3 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 23 Jun 2025 09:58:28 +0200 Subject: [PATCH 099/273] utilities: {constexpr} classes {SharedPointer} and {StdSharedPointer} --- lib/mito/utilities/SharedPointer.h | 32 ++++++++++++------------ lib/mito/utilities/SharedPointer.icc | 33 +++++++++++++------------ lib/mito/utilities/StdSharedPointer.h | 20 +++++++-------- lib/mito/utilities/StdSharedPointer.icc | 6 ++--- 4 files changed, 46 insertions(+), 45 deletions(-) diff --git a/lib/mito/utilities/SharedPointer.h b/lib/mito/utilities/SharedPointer.h index e1e1a9b16..44c22b69d 100644 --- a/lib/mito/utilities/SharedPointer.h +++ b/lib/mito/utilities/SharedPointer.h @@ -23,16 +23,16 @@ namespace mito::utilities { // interface public: // returns the id of this (oriented) simplex - inline auto id() const -> index_t; + constexpr auto id() const -> index_t; // accessor for the number of outstanding references - inline auto references() const -> int; + constexpr auto references() const -> int; // check if the handle is the null pointer - inline auto is_nullptr() const noexcept -> bool; + constexpr auto is_nullptr() const noexcept -> bool; // operator-> - auto operator->() const noexcept -> handle_type; + constexpr auto operator->() const noexcept -> handle_type; // // operator* // auto operator*() const -> const resource_type &; @@ -40,40 +40,40 @@ namespace mito::utilities { // meta methods public: // destructor - inline ~SharedPointer(); + constexpr ~SharedPointer(); // default constructor - inline SharedPointer(); + constexpr SharedPointer(); // constructor - inline SharedPointer(handle_type); + constexpr SharedPointer(handle_type); // copy constructor - inline SharedPointer(const shared_ptr_type &); + constexpr SharedPointer(const shared_ptr_type &); // move constructor - inline SharedPointer(shared_ptr_type &&) noexcept; + constexpr SharedPointer(shared_ptr_type &&) noexcept; // assignment operator - inline shared_ptr_type & operator=(const shared_ptr_type &); + constexpr shared_ptr_type & operator=(const shared_ptr_type &); // move assignment operator - inline shared_ptr_type & operator=(shared_ptr_type &&) noexcept; + constexpr shared_ptr_type & operator=(shared_ptr_type &&) noexcept; private: // accessor for {handle} - inline auto handle() const noexcept -> handle_type; + constexpr auto handle() const noexcept -> handle_type; // returns the resource corresponding to this resource id - static inline auto resource(index_t) -> handle_type; + static constexpr auto resource(index_t) -> handle_type; // reset the shared pointer - inline auto reset() -> void; + constexpr auto reset() -> void; // increment the reference count - inline auto _acquire() const -> void; + constexpr auto _acquire() const -> void; // decrement the reference count - inline auto _release() const -> void; + constexpr auto _release() const -> void; // data members private: diff --git a/lib/mito/utilities/SharedPointer.icc b/lib/mito/utilities/SharedPointer.icc index b2db41614..45f933311 100644 --- a/lib/mito/utilities/SharedPointer.icc +++ b/lib/mito/utilities/SharedPointer.icc @@ -9,7 +9,7 @@ #else template -auto +constexpr auto mito::utilities::SharedPointer::id() const -> index_t { // the id is the (immutable) address of this object @@ -17,7 +17,7 @@ mito::utilities::SharedPointer::id() const -> index_t } template -auto +constexpr auto mito::utilities::SharedPointer::resource(index_t index) -> handle_type { // the id is the (immutable) address of this object @@ -26,7 +26,7 @@ mito::utilities::SharedPointer::resource(index_t index) -> // interface template -auto +constexpr auto mito::utilities::SharedPointer::handle() const noexcept -> mito::utilities::SharedPointer::handle_type { @@ -35,7 +35,7 @@ mito::utilities::SharedPointer::handle() const noexcept } template -auto +constexpr auto mito::utilities::SharedPointer::references() const -> int { // return the count of outstanding references @@ -43,7 +43,7 @@ mito::utilities::SharedPointer::references() const -> int } template -auto +constexpr auto mito::utilities::SharedPointer::reset() -> void { // release my current handle @@ -57,7 +57,7 @@ mito::utilities::SharedPointer::reset() -> void } template -auto +constexpr auto mito::utilities::SharedPointer::is_nullptr() const noexcept -> bool { // all done @@ -66,7 +66,7 @@ mito::utilities::SharedPointer::is_nullptr() const noexcept -> bool // operator-> template -auto +constexpr auto mito::utilities::SharedPointer::operator->() const noexcept -> mito::utilities::SharedPointer::handle_type { @@ -86,7 +86,7 @@ mito::utilities::SharedPointer::operator->() const noexcept // destructor template -mito::utilities::SharedPointer::~SharedPointer() +constexpr mito::utilities::SharedPointer::~SharedPointer() { // release my current handle _release(); @@ -94,12 +94,13 @@ mito::utilities::SharedPointer::~SharedPointer() // default constructor (invalid shared handle) template -mito::utilities::SharedPointer::SharedPointer() : _handle(nullptr) +constexpr mito::utilities::SharedPointer::SharedPointer() : _handle(nullptr) {} // the constructor template -mito::utilities::SharedPointer::SharedPointer(handle_type resource) : _handle(resource) +constexpr mito::utilities::SharedPointer::SharedPointer(handle_type resource) : + _handle(resource) { // grab a reference to the shared handle _acquire(); @@ -107,7 +108,7 @@ mito::utilities::SharedPointer::SharedPointer(handle_type resource) : // the copy constructor template -mito::utilities::SharedPointer::SharedPointer( +constexpr mito::utilities::SharedPointer::SharedPointer( const mito::utilities::SharedPointer & other) : _handle(other._handle) { @@ -117,7 +118,7 @@ mito::utilities::SharedPointer::SharedPointer( // the move constructor template -mito::utilities::SharedPointer::SharedPointer( +constexpr mito::utilities::SharedPointer::SharedPointer( mito::utilities::SharedPointer && other) noexcept : _handle(std::move(other._handle)) { @@ -127,7 +128,7 @@ mito::utilities::SharedPointer::SharedPointer( // assignment operator template -mito::utilities::SharedPointer & +constexpr mito::utilities::SharedPointer & mito::utilities::SharedPointer::operator=( const mito::utilities::SharedPointer & other) { @@ -147,7 +148,7 @@ mito::utilities::SharedPointer::operator=( // move assignment operator template -mito::utilities::SharedPointer & +constexpr mito::utilities::SharedPointer & mito::utilities::SharedPointer::operator=( mito::utilities::SharedPointer && other) noexcept { @@ -168,7 +169,7 @@ mito::utilities::SharedPointer::operator=( // interface template -auto +constexpr auto mito::utilities::SharedPointer::_acquire() const -> void { // acquire resource (increment reference count) @@ -178,7 +179,7 @@ mito::utilities::SharedPointer::_acquire() const -> void } template -auto +constexpr auto mito::utilities::SharedPointer::_release() const -> void { // if the handle is in valid state diff --git a/lib/mito/utilities/StdSharedPointer.h b/lib/mito/utilities/StdSharedPointer.h index 97b3666a4..e4f7c94de 100644 --- a/lib/mito/utilities/StdSharedPointer.h +++ b/lib/mito/utilities/StdSharedPointer.h @@ -22,32 +22,32 @@ namespace mito::utilities { // interface public: // returns the id of this (oriented) simplex - inline auto id() const -> index_t; + constexpr auto id() const -> index_t; // operator-> - auto operator->() const noexcept -> handle_type; + constexpr auto operator->() const noexcept -> handle_type; // meta methods public: // constructor template requires(std::is_constructible_v) - inline StdSharedPointer(Args &&... args); + constexpr StdSharedPointer(Args &&... args); // destructor - inline ~StdSharedPointer() = default; + constexpr ~StdSharedPointer() = default; // copy constructor - inline StdSharedPointer(const shared_ptr_type &) = default; + constexpr StdSharedPointer(const shared_ptr_type &) = default; // move constructor - inline StdSharedPointer(shared_ptr_type &&) noexcept = default; + constexpr StdSharedPointer(shared_ptr_type &&) noexcept = default; // assignment operator - inline StdSharedPointer & operator=(const shared_ptr_type &) = default; + constexpr StdSharedPointer & operator=(const shared_ptr_type &) = default; // move assignment operator - inline StdSharedPointer & operator=(shared_ptr_type &&) noexcept = default; + constexpr StdSharedPointer & operator=(shared_ptr_type &&) noexcept = default; // data members private: @@ -55,14 +55,14 @@ namespace mito::utilities { }; template - inline bool operator==( + constexpr bool operator==( const StdSharedPointer & lhs, const StdSharedPointer & rhs) { return lhs.id() == rhs.id(); } template - inline auto operator<=>( + constexpr auto operator<=>( const StdSharedPointer & lhs, const StdSharedPointer & rhs) { // delegate to ids diff --git a/lib/mito/utilities/StdSharedPointer.icc b/lib/mito/utilities/StdSharedPointer.icc index dccfbcc6d..e5f4cc17f 100644 --- a/lib/mito/utilities/StdSharedPointer.icc +++ b/lib/mito/utilities/StdSharedPointer.icc @@ -9,7 +9,7 @@ #else template -auto +constexpr auto mito::utilities::StdSharedPointer::id() const -> index_t { // the id is the (immutable) address of this object @@ -19,13 +19,13 @@ mito::utilities::StdSharedPointer::id() const -> index_t template template requires(std::is_constructible_v) -mito::utilities::StdSharedPointer::StdSharedPointer(Args &&... args) : +constexpr mito::utilities::StdSharedPointer::StdSharedPointer(Args &&... args) : _ptr(std::make_shared(std::forward(args)...)) {} // operator-> template -auto +constexpr auto mito::utilities::StdSharedPointer::operator->() const noexcept -> mito::utilities::StdSharedPointer::handle_type { From 17909cde300710f2f48ae579731acf3691a90ac8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 23 Jun 2025 10:03:04 +0200 Subject: [PATCH 100/273] discretization: refactoring The nodal coordinates of an {IsoparametricTriangleP} are now computed within the constructor of the parent class {IsoparametricTriangle} based on the nodes of the corresponding {GeometricSimplex} and on the {CoordinateSystem}. --- lib/mito/discretization/FunctionSpace.h | 24 ++++--------------- .../discretization/IsoparametricTriangle.h | 23 ++++++++++++++++-- .../discretization/IsoparametricTriangle1.h | 21 ++++------------ .../discretization/IsoparametricTriangle2.h | 22 ++++------------- .../discretization/isoparametric_triangle.cc | 22 ++++++----------- .../isoparametric_triangle_p1.cc | 16 ++++--------- .../isoparametric_triangle_p2.cc | 15 ++++-------- 7 files changed, 48 insertions(+), 95 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index e1ab1a0ad..bf4e3d940 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -69,14 +69,6 @@ namespace mito::discretization { // get the nodes of the cell const auto & nodes = cell.nodes(); - // the origin of the coordinate system - auto origin = typename coord_system_type::coordinates_type{}; - - // the coordinates of the nodes of the triangle - auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; - auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; - auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; - // add the nodes to the map (if the mesh node is already present in the map, // then the present discretization node is used) auto node_0 = @@ -88,7 +80,7 @@ namespace mito::discretization { // create a finite element for each cell and add it to the pile _elements.emplace( - cell, discretization_nodes_type{ node_0, node_1, node_2 }, x_0, x_1, x_2); + cell, coord_system, discretization_nodes_type{ node_0, node_1, node_2 }); } // populate the constrained nodes @@ -123,14 +115,6 @@ namespace mito::discretization { // get the nodes of the cell const auto & nodes = cell.nodes(); - // the origin of the coordinate system - auto origin = typename coord_system_type::coordinates_type{}; - - // the coordinates of the nodes of the triangle - auto x_0 = coord_system.coordinates(nodes[0]->point()) - origin; - auto x_1 = coord_system.coordinates(nodes[1]->point()) - origin; - auto x_2 = coord_system.coordinates(nodes[2]->point()) - origin; - // add the nodes to the map (if the mesh node is already present in the map, // then the present discretization node is used) auto node_0 = @@ -161,9 +145,9 @@ namespace mito::discretization { // create a finite element for each cell and add it to the pile _elements.emplace( - cell, - discretization_nodes_type{ node_0, node_1, node_2, node_3, node_4, node_5 }, - x_0, x_1, x_2); + cell, coord_system, + discretization_nodes_type{ node_0, node_1, node_2, node_3, node_4, + node_5 }); } // populate the constrained nodes diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index 483f74cfd..efb328b00 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -23,6 +23,12 @@ namespace mito::discretization { using geometric_simplex_type = geometry::triangle_t<2>; // the parametric coordinates type using parametric_coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; + // cartesian coordinates in 2D + using coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; + // the coordinate system type + using coordinate_system_type = geometry::coordinate_system_t; + // the vector type + using vector_type = tensor::vector_t<2>; protected: // the function extracting the 0 component of a parametric point @@ -36,8 +42,16 @@ namespace mito::discretization { public: // the default constructor - constexpr IsoparametricTriangle(const geometric_simplex_type & geometric_simplex) : - _geometric_simplex(geometric_simplex) + constexpr IsoparametricTriangle( + const geometric_simplex_type & geometric_simplex, + const coordinate_system_type & coord_system) : + _geometric_simplex(geometric_simplex), + _x0{ coord_system.coordinates(geometric_simplex.nodes()[0]->point()) + - coordinates_type{} }, + _x1{ coord_system.coordinates(geometric_simplex.nodes()[1]->point()) + - coordinates_type{} }, + _x2{ coord_system.coordinates(geometric_simplex.nodes()[2]->point()) + - coordinates_type{} } {} // destructor @@ -66,6 +80,11 @@ namespace mito::discretization { // QUESTION: do we need to maintain a reference to the geometric simplex? // a const reference to the geometric simplex const geometric_simplex_type & _geometric_simplex; + + // the coordinates of the discretization nodes of the triangle + const vector_type _x0; + const vector_type _x1; + const vector_type _x2; }; } // namespace mito diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangle1.h index 19cb807a9..396d21c74 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangle1.h @@ -26,8 +26,6 @@ namespace mito::discretization { typename geometric_simplex_type::barycentric_coordinates_type; private: - // - using vector_type = tensor::vector_t<2>; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure using evaluated_shape_functions_type = @@ -53,13 +51,10 @@ namespace mito::discretization { // the default constructor inline IsoparametricTriangle1( const geometric_simplex_type & geometric_simplex, - const discretization_nodes_type & discretization_nodes, const vector_type & x0, - const vector_type & x1, const vector_type & x2) : - IsoparametricTriangle(geometric_simplex), - _discretization_nodes(discretization_nodes), - _x0(x0), - _x1(x1), - _x2(x2) + const coordinate_system_type & coord_system, + const discretization_nodes_type & discretization_nodes) : + IsoparametricTriangle(geometric_simplex, coord_system), + _discretization_nodes(discretization_nodes) {} // destructor @@ -138,14 +133,6 @@ namespace mito::discretization { private: // the discretization nodes of the simplex const discretization_nodes_type _discretization_nodes; - // QUESTION: alternatively to the coordinates of the vertices, we could store the points - // associated with the vertices of the triangle, so the coordinates can be fetched from the - // coordinate system - // - // the coordinates of the discretization nodes of the triangle - const vector_type _x0; - const vector_type _x1; - const vector_type _x2; }; } // namespace mito diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangle2.h index 198888b95..12fb5f9ab 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangle2.h @@ -27,8 +27,6 @@ namespace mito::discretization { typename geometric_simplex_type::barycentric_coordinates_type; private: - // - using vector_type = tensor::vector_t<2>; // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure using evaluated_shape_functions_type = @@ -63,13 +61,10 @@ namespace mito::discretization { // the default constructor inline IsoparametricTriangle2( const geometric_simplex_type & geometric_simplex, - const discretization_nodes_type & discretization_nodes, const vector_type & x0, - const vector_type & x1, const vector_type & x2) : - IsoparametricTriangle(geometric_simplex), - _discretization_nodes(discretization_nodes), - _x0(x0), - _x1(x1), - _x2(x2) + const coordinate_system_type & coord_system, + const discretization_nodes_type & discretization_nodes) : + IsoparametricTriangle(geometric_simplex, coord_system), + _discretization_nodes(discretization_nodes) {} // destructor @@ -159,15 +154,6 @@ namespace mito::discretization { private: // the discretization nodes of the simplex const discretization_nodes_type _discretization_nodes; - // QUESTION: alternatively to the coordinates of the vertices, we could store the points - // associated with the vertices of the triangle, so the coordinates can be fetched from the - // coordinate system - // - // TOFIX: perhaps these can be stored in the base class? - // the coordinates of the discretization nodes of the triangle - const vector_type _x0; - const vector_type _x1; - const vector_type _x2; }; } // namespace mito diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index e1fb1b63d..283094c35 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -190,16 +190,10 @@ TEST(Fem, IsoparametricTriangle) // the coordinate system auto coord_system = coord_system_t(); - // the origin of the coordinate system - auto origin = typename coord_system_t::coordinates_type{}; - // build nodes - auto coord_0 = coordinates_t{ 0.0, 0.0 }; - auto node_0 = mito::geometry::node(coord_system, coord_0); - auto coord_1 = coordinates_t{ 1.0, 0.0 }; - auto node_1 = mito::geometry::node(coord_system, coord_1); - auto coord_2 = coordinates_t{ 0.0, 1.0 }; - auto node_2 = mito::geometry::node(coord_system, coord_2); + auto node_0 = mito::geometry::node(coord_system, { 0.0, 0.0 }); + auto node_1 = mito::geometry::node(coord_system, { 1.0, 0.0 }); + auto node_2 = mito::geometry::node(coord_system, { 0.0, 1.0 }); // make a geometric simplex auto geometric_simplex = mito::geometry::triangle<2>({ node_0, node_1, node_2 }); @@ -215,9 +209,8 @@ TEST(Fem, IsoparametricTriangle) // a finite element auto element_p1 = element_p1_t( - geometric_simplex, - { discretization_node_0, discretization_node_1, discretization_node_2 }, - coord_0 - origin, coord_1 - origin, coord_2 - origin); + geometric_simplex, coord_system, + { discretization_node_0, discretization_node_1, discretization_node_2 }); // check that first order shape functions are a partition of unity test_partition_of_unity(element_p1); @@ -262,10 +255,9 @@ TEST(Fem, IsoparametricTriangle) // a finite element auto element_p2 = element_p2_t( - geometric_simplex, + geometric_simplex, coord_system, { discretization_node_0, discretization_node_1, discretization_node_2, - discretization_node_3, discretization_node_4, discretization_node_5 }, - coord_0 - origin, coord_1 - origin, coord_2 - origin); + discretization_node_3, discretization_node_4, discretization_node_5 }); // check that second order shape functions are a partition of unity test_partition_of_unity(element_p2); diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc index c64c1fe96..11092dd10 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc @@ -43,16 +43,10 @@ TEST(Fem, IsoparametricTriangleP1) // the coordinate system auto coord_system = coord_system_t(); - // the origin of the coordinate system - auto origin = typename coord_system_t::coordinates_type{}; - // build nodes - auto coord_0 = coordinates_t{ 0.0, 0.0 }; - auto v0 = mito::geometry::node(coord_system, coord_0); - auto coord_1 = coordinates_t{ 1.0, 0.0 }; - auto v1 = mito::geometry::node(coord_system, coord_1); - auto coord_2 = coordinates_t{ 1.0, 1.0 }; - auto v2 = mito::geometry::node(coord_system, coord_2); + auto v0 = mito::geometry::node(coord_system, { 0.0, 0.0 }); + auto v1 = mito::geometry::node(coord_system, { 1.0, 0.0 }); + auto v2 = mito::geometry::node(coord_system, { 1.0, 1.0 }); // make a geometric simplex auto geometric_simplex = mito::geometry::triangle<2>({ v0, v1, v2 }); @@ -63,9 +57,7 @@ TEST(Fem, IsoparametricTriangleP1) auto node_2 = discretization_node_t(); // a finite element - auto element = element_t( - geometric_simplex, { node_0, node_1, node_2 }, coord_0 - origin, coord_1 - origin, - coord_2 - origin); + auto element = element_t(geometric_simplex, coord_system, { node_0, node_1, node_2 }); // node 0 in barycentric coordinates auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc index b4160cd4f..f280783d5 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc @@ -43,16 +43,10 @@ TEST(Fem, IsoparametricTriangleP2) // the coordinate system auto coord_system = coord_system_t(); - // the origin of the coordinate system - auto origin = typename coord_system_t::coordinates_type{}; - // build nodes - auto coord_0 = coordinates_t{ 0.0, 0.0 }; - auto v0 = mito::geometry::node(coord_system, coord_0); - auto coord_1 = coordinates_t{ 1.0, 0.0 }; - auto v1 = mito::geometry::node(coord_system, coord_1); - auto coord_2 = coordinates_t{ 1.0, 1.0 }; - auto v2 = mito::geometry::node(coord_system, coord_2); + auto v0 = mito::geometry::node(coord_system, { 0.0, 0.0 }); + auto v1 = mito::geometry::node(coord_system, { 1.0, 0.0 }); + auto v2 = mito::geometry::node(coord_system, { 1.0, 1.0 }); // make a geometric simplex auto geometric_simplex = mito::geometry::triangle<2>({ v0, v1, v2 }); @@ -67,8 +61,7 @@ TEST(Fem, IsoparametricTriangleP2) // a finite element auto element = element_t( - geometric_simplex, { node_0, node_1, node_2, node_3, node_4, node_5 }, coord_0 - origin, - coord_1 - origin, coord_2 - origin); + geometric_simplex, coord_system, { node_0, node_1, node_2, node_3, node_4, node_5 }); // node 0 in barycentric coordinates auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; From 465f09e023a2a5695f1e652d045af4626dabb4eb Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 23 Jun 2025 10:08:46 +0200 Subject: [PATCH 101/273] discretization: rename classes {IsoparametricTriangle1,2} to {IsoparametricTriangleP1,2} --- ...ricTriangle1.h => IsoparametricTriangleP1.h} | 16 ++++++++-------- ...ricTriangle2.h => IsoparametricTriangleP2.h} | 17 ++++++++--------- .../isoparametric_simplex_library.h | 8 ++++---- 3 files changed, 20 insertions(+), 21 deletions(-) rename lib/mito/discretization/{IsoparametricTriangle1.h => IsoparametricTriangleP1.h} (89%) rename lib/mito/discretization/{IsoparametricTriangle2.h => IsoparametricTriangleP2.h} (90%) diff --git a/lib/mito/discretization/IsoparametricTriangle1.h b/lib/mito/discretization/IsoparametricTriangleP1.h similarity index 89% rename from lib/mito/discretization/IsoparametricTriangle1.h rename to lib/mito/discretization/IsoparametricTriangleP1.h index 396d21c74..3e4edd8fb 100644 --- a/lib/mito/discretization/IsoparametricTriangle1.h +++ b/lib/mito/discretization/IsoparametricTriangleP1.h @@ -8,13 +8,13 @@ // DESIGN NOTES -// Class {IsoparametricTriangle1} represents a second order simplex living in 2D cartesian space, +// Class {IsoparametricTriangleP1} represents a second order simplex living in 2D cartesian space, // equipped with linear shape functions defined in the parametric space. namespace mito::discretization { - class IsoparametricTriangle1 : public IsoparametricTriangle { + class IsoparametricTriangleP1 : public IsoparametricTriangle { public: // the number of discretization discretization nodes @@ -49,7 +49,7 @@ namespace mito::discretization { public: // the default constructor - inline IsoparametricTriangle1( + inline IsoparametricTriangleP1( const geometric_simplex_type & geometric_simplex, const coordinate_system_type & coord_system, const discretization_nodes_type & discretization_nodes) : @@ -58,19 +58,19 @@ namespace mito::discretization { {} // destructor - inline ~IsoparametricTriangle1() = default; + inline ~IsoparametricTriangleP1() = default; // delete move constructor - inline IsoparametricTriangle1(IsoparametricTriangle1 &&) noexcept = delete; + inline IsoparametricTriangleP1(IsoparametricTriangleP1 &&) noexcept = delete; // delete copy constructor - inline IsoparametricTriangle1(const IsoparametricTriangle1 &) = delete; + inline IsoparametricTriangleP1(const IsoparametricTriangleP1 &) = delete; // delete assignment operator - inline IsoparametricTriangle1 & operator=(const IsoparametricTriangle1 &) = delete; + inline IsoparametricTriangleP1 & operator=(const IsoparametricTriangleP1 &) = delete; // delete move assignment operator - inline IsoparametricTriangle1 & operator=(IsoparametricTriangle1 &&) noexcept = delete; + inline IsoparametricTriangleP1 & operator=(IsoparametricTriangleP1 &&) noexcept = delete; public: // get the discretization nodes diff --git a/lib/mito/discretization/IsoparametricTriangle2.h b/lib/mito/discretization/IsoparametricTriangleP2.h similarity index 90% rename from lib/mito/discretization/IsoparametricTriangle2.h rename to lib/mito/discretization/IsoparametricTriangleP2.h index 12fb5f9ab..cab202e30 100644 --- a/lib/mito/discretization/IsoparametricTriangle2.h +++ b/lib/mito/discretization/IsoparametricTriangleP2.h @@ -8,14 +8,13 @@ // DESIGN NOTES -// Class {IsoparametricTriangle2} represents a second order simplex living in 2D cartesian space +// Class {IsoparametricTriangleP2} represents a second order simplex living in 2D cartesian space // equipped with quadratic shape functions defined in the parametric space. -// TODO: rename to {IsoparametricTriangleP1}, {IsoparametricTriangleP2}, ... namespace mito::discretization { - class IsoparametricTriangle2 : public IsoparametricTriangle { + class IsoparametricTriangleP2 : public IsoparametricTriangle { public: // the number of discretization nodes @@ -59,7 +58,7 @@ namespace mito::discretization { public: // the default constructor - inline IsoparametricTriangle2( + inline IsoparametricTriangleP2( const geometric_simplex_type & geometric_simplex, const coordinate_system_type & coord_system, const discretization_nodes_type & discretization_nodes) : @@ -68,19 +67,19 @@ namespace mito::discretization { {} // destructor - inline ~IsoparametricTriangle2() = default; + inline ~IsoparametricTriangleP2() = default; // delete move constructor - inline IsoparametricTriangle2(IsoparametricTriangle2 &&) noexcept = delete; + inline IsoparametricTriangleP2(IsoparametricTriangleP2 &&) noexcept = delete; // delete copy constructor - inline IsoparametricTriangle2(const IsoparametricTriangle2 &) = delete; + inline IsoparametricTriangleP2(const IsoparametricTriangleP2 &) = delete; // delete assignment operator - inline IsoparametricTriangle2 & operator=(const IsoparametricTriangle2 &) = delete; + inline IsoparametricTriangleP2 & operator=(const IsoparametricTriangleP2 &) = delete; // delete move assignment operator - inline IsoparametricTriangle2 & operator=(IsoparametricTriangle2 &&) noexcept = delete; + inline IsoparametricTriangleP2 & operator=(IsoparametricTriangleP2 &&) noexcept = delete; public: // get the discretization nodes diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/isoparametric_simplex_library.h index aee5b09cc..1e9467959 100644 --- a/lib/mito/discretization/isoparametric_simplex_library.h +++ b/lib/mito/discretization/isoparametric_simplex_library.h @@ -8,8 +8,8 @@ #include "IsoparametricTriangle.h" -#include "IsoparametricTriangle1.h" -#include "IsoparametricTriangle2.h" +#include "IsoparametricTriangleP1.h" +#include "IsoparametricTriangleP2.h" namespace mito::discretization { @@ -22,13 +22,13 @@ namespace mito::discretization { // specialization for linear shape functions on triangles in 2D template <> struct isoparametric_simplex<1, geometry::triangle_t<2>> { - using type = IsoparametricTriangle1; + using type = IsoparametricTriangleP1; }; // specialization for quadratic shape functions on triangles in 2D template <> struct isoparametric_simplex<2, geometry::triangle_t<2>> { - using type = IsoparametricTriangle2; + using type = IsoparametricTriangleP2; }; } From 7bf4076066c04b33715208d86e578f20222ae024 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 23 Jun 2025 10:15:30 +0200 Subject: [PATCH 102/273] discretization: remove redundant {mito} namespace specifications in isoparametric triangle classes --- lib/mito/discretization/IsoparametricTriangle.h | 4 ++-- lib/mito/discretization/IsoparametricTriangleP1.h | 12 +++++------- lib/mito/discretization/IsoparametricTriangleP2.h | 14 ++++++-------- 3 files changed, 13 insertions(+), 17 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index efb328b00..e927c1c48 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -33,10 +33,10 @@ namespace mito::discretization { protected: // the function extracting the 0 component of a parametric point static constexpr auto xi_0 = - mito::fields::field(mito::functions::component); + fields::field(functions::component); // the function extracting the 1 component of a parametric point static constexpr auto xi_1 = - mito::fields::field(mito::functions::component); + fields::field(functions::component); // the function extracting the 2 component of a parametric point static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; diff --git a/lib/mito/discretization/IsoparametricTriangleP1.h b/lib/mito/discretization/IsoparametricTriangleP1.h index 3e4edd8fb..6ab88e15a 100644 --- a/lib/mito/discretization/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/IsoparametricTriangleP1.h @@ -28,10 +28,9 @@ namespace mito::discretization { private: // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure - using evaluated_shape_functions_type = - std::map; + using evaluated_shape_functions_type = std::map; using evaluated_shape_functions_gradients_type = - std::map>; + std::map>; private: // linear shape functions on the triangle @@ -44,8 +43,7 @@ namespace mito::discretization { // the gradients of the shape functions static constexpr auto dphi = std::make_tuple( - mito::fields::gradient(phi_0), mito::fields::gradient(phi_1), - mito::fields::gradient(phi_2)); + fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2)); public: // the default constructor @@ -103,7 +101,7 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // compute the gradient of the isoparametric mapping - auto J = mito::fields::gradient(x_cell)(xi_p); + auto J = fields::gradient(x_cell)(xi_p); // return the jacobian of the isoparametric mapping return J; @@ -119,7 +117,7 @@ namespace mito::discretization { auto J = jacobian(xi); // the derivative of the coordinates with respect to the barycentric coordinates - auto J_inv = mito::tensor::inverse(J); + auto J_inv = tensor::inverse(J); // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; diff --git a/lib/mito/discretization/IsoparametricTriangleP2.h b/lib/mito/discretization/IsoparametricTriangleP2.h index cab202e30..d786d30ab 100644 --- a/lib/mito/discretization/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/IsoparametricTriangleP2.h @@ -28,10 +28,9 @@ namespace mito::discretization { private: // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick // another data structure - using evaluated_shape_functions_type = - std::map; + using evaluated_shape_functions_type = std::map; using evaluated_shape_functions_gradients_type = - std::map>; + std::map>; private: // strip the namespace @@ -52,9 +51,8 @@ namespace mito::discretization { // the gradients of the shape functions static constexpr auto dphi = std::make_tuple( - mito::fields::gradient(phi_0), mito::fields::gradient(phi_1), - mito::fields::gradient(phi_2), mito::fields::gradient(phi_3), - mito::fields::gradient(phi_4), mito::fields::gradient(phi_5)); + fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2), + fields::gradient(phi_3), fields::gradient(phi_4), fields::gradient(phi_5)); public: // the default constructor @@ -120,7 +118,7 @@ namespace mito::discretization { auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // compute the gradient of the isoparametric mapping - auto J = mito::fields::gradient(x_cell)(xi_p); + auto J = fields::gradient(x_cell)(xi_p); // return the jacobian of the isoparametric mapping return J; @@ -136,7 +134,7 @@ namespace mito::discretization { auto J = jacobian(xi); // the derivative of the coordinates with respect to the barycentric coordinates - auto J_inv = mito::tensor::inverse(J); + auto J_inv = tensor::inverse(J); // the parametric coordinates of the quadrature point auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; From 8910b423b97f085abc30cdbf2a0adda39a9c3ed7 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 23 Jun 2025 23:40:02 +0200 Subject: [PATCH 103/273] discretization: narrative improvements --- tests/mito.lib/discretization/isoparametric_triangle.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 283094c35..df28def24 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -42,7 +42,7 @@ test_partition_of_unity(const auto & element) // the sum of the shape functions auto sum = 0.0; - // populate the linear system of equations + // add together all the shape functions at {xi} for (const auto & [_, phi_a] : phi) { sum += phi_a; } @@ -71,7 +71,7 @@ test_gradient_consistency(const auto & element) // the sum of the shape functions auto sum = mito::tensor::vector_t<2>{ 0.0, 0.0 }; - // populate the linear system of equations + // add together all the shape functions gradients at {xi} for (const auto & [_, dphi_a] : dphi) { sum += dphi_a; } From 64b4330cbbf2b625eb99da43dbda49e83f6b8587 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 15:53:24 +0200 Subject: [PATCH 104/273] discretization: redesign access to shape functions in isoparametric triangle classes Instead of returning a collection of evaluated shape functions, allow to access each shape function independently, as a function of the parametric coordinates. --- .../discretization/IsoparametricTriangleP1.h | 97 +++++++-------- .../discretization/IsoparametricTriangleP2.h | 114 +++++++++--------- .../discretization/isoparametric_triangle.cc | 76 +++++++----- .../isoparametric_triangle_p1.cc | 35 +++--- .../isoparametric_triangle_p2.cc | 105 ++++++++-------- tests/mito.lib/discretization/poisson.cc | 85 +++++++------ 6 files changed, 269 insertions(+), 243 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangleP1.h b/lib/mito/discretization/IsoparametricTriangleP1.h index 6ab88e15a..0b0b6544d 100644 --- a/lib/mito/discretization/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/IsoparametricTriangleP1.h @@ -25,13 +25,6 @@ namespace mito::discretization { using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; - private: - // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick - // another data structure - using evaluated_shape_functions_type = std::map; - using evaluated_shape_functions_gradients_type = - std::map>; - private: // linear shape functions on the triangle static constexpr auto phi_0 = xi_0; @@ -77,55 +70,63 @@ namespace mito::discretization { return _discretization_nodes; } - // get all the shape functions evaluated at the point {xi} in barycentric coordinates - inline auto shape(const barycentric_coordinates_type & xi) const - -> evaluated_shape_functions_type + // get the shape function associated with local node {a} + template + requires(a >= 0 && a < n_nodes) + inline auto shape() const { - // the parametric coordinates of the quadrature point - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; - - // return the shape functions evaluated at {xi} - return { { _discretization_nodes[0], std::get<0>(phi)(xi_p) }, - { _discretization_nodes[1], std::get<1>(phi)(xi_p) }, - { _discretization_nodes[2], std::get<2>(phi)(xi_p) } }; + // assemble the shape function associated with local node {a} as a function of + // barycentric coordinates + auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { + // strip the third barycentric coordinate + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // return the a-th shape function evaluated at {xi} + return std::get(phi)(xi_p); + }; + + // and return it + return shape_function; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - inline auto jacobian(const barycentric_coordinates_type & xi) const + inline auto jacobian() const { - // assemble the isoparametric mapping from the barycentric coordinates to the actual - // coordinates on the cell {cell} - auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; - - // the parametric coordinates of the quadrature point - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; - - // compute the gradient of the isoparametric mapping - auto J = fields::gradient(x_cell)(xi_p); - - // return the jacobian of the isoparametric mapping - return J; + // assemble the jacobian as a function of barycentric coordinates + auto jacobian_function = + [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { + // assemble the isoparametric mapping from the barycentric coordinates to the actual + // coordinates on the cell {cell} + auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; + // strip the third barycentric coordinate + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // compute the gradient of the isoparametric mapping + return fields::gradient(x_cell)(xi_p); + }; + + // and return it + return jacobian_function; } - // get all the shape functions gradients evaluated at the point {xi} in barycentric - // coordinates - inline auto gradient(const barycentric_coordinates_type & xi) const - -> evaluated_shape_functions_gradients_type + // get the gradient of the a-th shape function as a function of barycentric coordinates + template + requires(a >= 0 && a < n_nodes) + inline auto gradient() const { - // 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 barycentric coordinates - auto J_inv = tensor::inverse(J); - - // the parametric coordinates of the quadrature point - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; - - // return the spatial gradients of the shape functions evaluated at {xi} - return { { _discretization_nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _discretization_nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _discretization_nodes[2], std::get<2>(dphi)(xi_p) * J_inv } }; + // assemble the gradient as a function of barycentric coordinates + auto gradient_function = + [&](const barycentric_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 barycentric coordinates + auto J_inv = tensor::inverse(J); + // strip the third barycentric coordinate + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // return the spatial gradients of the shape functions evaluated at {xi} + return std::get(dphi)(xi_p) * J_inv; + }; + // and return it + return gradient_function; } private: diff --git a/lib/mito/discretization/IsoparametricTriangleP2.h b/lib/mito/discretization/IsoparametricTriangleP2.h index d786d30ab..f13258b8f 100644 --- a/lib/mito/discretization/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/IsoparametricTriangleP2.h @@ -25,13 +25,6 @@ namespace mito::discretization { using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; - private: - // TOFIX: the number of entries in the map is known at complie time, so maybe we should pick - // another data structure - using evaluated_shape_functions_type = std::map; - using evaluated_shape_functions_gradients_type = - std::map>; - private: // strip the namespace static constexpr auto xi_0 = xi_0; @@ -86,66 +79,69 @@ namespace mito::discretization { return _discretization_nodes; } - // get all the shape functions evaluated at the point {xi} in barycentric coordinates - inline auto shape(const barycentric_coordinates_type & xi) const - -> evaluated_shape_functions_type + // get the shape function associated with local node {a} + template + requires(a >= 0 && a < n_nodes) + inline auto shape() const { - // the parametric coordinates of the quadrature point - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; - - // return the shape functions evaluated at {xi} - return { { _discretization_nodes[0], std::get<0>(phi)(xi_p) }, - { _discretization_nodes[1], std::get<1>(phi)(xi_p) }, - { _discretization_nodes[2], std::get<2>(phi)(xi_p) }, - { _discretization_nodes[3], std::get<3>(phi)(xi_p) }, - { _discretization_nodes[4], std::get<4>(phi)(xi_p) }, - { _discretization_nodes[5], std::get<5>(phi)(xi_p) } }; + // assemble the shape function associated with local node {a} as a function of + // barycentric coordinates + auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { + // strip the third barycentric coordinate + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // return the a-th shape function evaluated at {xi} + return std::get(phi)(xi_p); + }; + + // and return it + return shape_function; } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - inline auto jacobian(const barycentric_coordinates_type & xi) const + inline auto jacobian() const { - auto x3 = 0.5 * (_x0 + _x1); - auto x4 = 0.5 * (_x1 + _x2); - auto x5 = 0.5 * (_x2 + _x0); - - // assemble the isoparametric mapping from the barycentric coordinates to the actual - // coordinates on the cell {cell} - auto x_cell = - _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; - - // the parametric coordinates of the quadrature point - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; - - // compute the gradient of the isoparametric mapping - auto J = fields::gradient(x_cell)(xi_p); - - // return the jacobian of the isoparametric mapping - return J; + // assemble the jacobian as a function of barycentric coordinates + auto jacobian_function = + [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { + auto x3 = 0.5 * (_x0 + _x1); + auto x4 = 0.5 * (_x1 + _x2); + auto x5 = 0.5 * (_x2 + _x0); + + // assemble the isoparametric mapping from the barycentric coordinates to the actual + // coordinates on the cell {cell} + auto x_cell = + _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; + + // strip the third barycentric coordinate + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // compute the gradient of the isoparametric mapping + return fields::gradient(x_cell)(xi_p); + }; + + // and return it + return jacobian_function; } - // get all the shape functions gradients evaluated at the point {xi} in barycentric - // coordinates - inline auto gradient(const barycentric_coordinates_type & xi) const - -> evaluated_shape_functions_gradients_type + // get the gradient of the a-th shape function as a function of barycentric coordinates + template + requires(a >= 0 && a < n_nodes) + inline auto gradient() const { - // 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 barycentric coordinates - auto J_inv = tensor::inverse(J); - - // the parametric coordinates of the quadrature point - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; - - // return the spatial gradients of the shape functions evaluated at {xi} - return { { _discretization_nodes[0], std::get<0>(dphi)(xi_p) * J_inv }, - { _discretization_nodes[1], std::get<1>(dphi)(xi_p) * J_inv }, - { _discretization_nodes[2], std::get<2>(dphi)(xi_p) * J_inv }, - { _discretization_nodes[3], std::get<3>(dphi)(xi_p) * J_inv }, - { _discretization_nodes[4], std::get<4>(dphi)(xi_p) * J_inv }, - { _discretization_nodes[5], std::get<5>(dphi)(xi_p) * J_inv } }; + // assemble the gradient as a function of barycentric coordinates + auto gradient_function = + [&](const barycentric_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 barycentric coordinates + auto J_inv = tensor::inverse(J); + // strip the third barycentric coordinate + auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; + // return the spatial gradients of the shape functions evaluated at {xi} + return std::get(dphi)(xi_p) * J_inv; + }; + // and return it + return gradient_function; } private: diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index df28def24..8c4124f85 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -30,22 +30,21 @@ constexpr auto quadrature_rule = quadrature_rule_t(); auto test_partition_of_unity(const auto & element) { + // the number of nodes per element + constexpr int n_nodes = mito::utilities::base_type::n_nodes; + // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { // the barycentric coordinates of the quadrature point auto xi = quadrature_rule.point(q); - // evaluate the element shape functions at {xi} - auto phi = element.shape(xi); - // the sum of the shape functions auto sum = 0.0; // add together all the shape functions at {xi} - for (const auto & [_, phi_a] : phi) { - sum += phi_a; - } + mito::tensor::constexpr_for_1( + [&]() { sum += element.template shape()(xi); }); // check the sum of the shape functions EXPECT_DOUBLE_EQ(1.0, sum); @@ -59,22 +58,21 @@ test_partition_of_unity(const auto & element) auto test_gradient_consistency(const auto & element) { + // the number of nodes per element + constexpr int n_nodes = mito::utilities::base_type::n_nodes; + // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { // the barycentric coordinates of the quadrature point auto xi = quadrature_rule.point(q); - // evaluate the element shape functions gradients at {xi} - auto dphi = element.gradient(xi); - // the sum of the shape functions auto sum = mito::tensor::vector_t<2>{ 0.0, 0.0 }; // add together all the shape functions gradients at {xi} - for (const auto & [_, dphi_a] : dphi) { - sum += dphi_a; - } + mito::tensor::constexpr_for_1( + [&]() { sum += element.template gradient()(xi); }); // check the sum of the shape functions gradients EXPECT_NEAR(0.0, sum[0], 3.0e-16); @@ -95,8 +93,11 @@ test_stiffness_matrix( // create reporting channel journal::info_t channel("test_stiffness_matrix"); + // the number of nodes per element + constexpr int n_nodes = elementT::n_nodes; + // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix - auto elementary_stiffness_matrix = mito::tensor::matrix_t(); + auto elementary_stiffness_matrix = mito::tensor::matrix_t(); // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -105,25 +106,30 @@ test_stiffness_matrix( auto xi = quadrature_rule.point(q); // area of the cell - auto area = 0.5 * mito::tensor::determinant(element.jacobian(xi)); - - // evaluate the element shape functions gradients at {xi} - auto dphi = element.gradient(xi); + auto area = 0.5 * mito::tensor::determinant(element.jacobian()(xi)); // precompute the common factor for integration auto factor = quadrature_rule.weight(q) * area; - // populate the mass matrix - for (const auto & [node_a, dphi_a] : dphi) { + // populate the stiffness matrix + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.discretization_nodes()[a]; + // evaluate the spatial gradient of the element's a-th shape function at {xi} + auto dphi_a = element.template gradient()(xi); // get the equation number of {node_a} int i = equation_map.at(node_a); - for (const auto & [node_b, dphi_b] : dphi) { + mito::tensor::constexpr_for_1([&]() { + // get the b-th discretization node of the element + const auto & node_b = element.discretization_nodes()[b]; + // evaluate the spatial gradient of the element's b-th shape function at {xi} + auto dphi_b = element.template gradient()(xi); // get the equation number of {node_b} int j = equation_map.at(node_b); // assemble the {node_a, node_b} contribution to the mass matrix elementary_stiffness_matrix[{ i, j }] += factor * dphi_a * dphi_b; - } - } + }); + }); } // compute the error @@ -146,8 +152,11 @@ test_mass_matrix( // create reporting channel journal::info_t channel("test_mass_matrix"); + // the number of nodes per element + constexpr int n_nodes = elementT::n_nodes; + // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix - auto elementary_mass_matrix = mito::tensor::matrix_t(); + auto elementary_mass_matrix = mito::tensor::matrix_t(); // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -155,24 +164,29 @@ test_mass_matrix( // the barycentric coordinates of the quadrature point auto xi = quadrature_rule.point(q); - // evaluate the element shape functions at {xi} - auto phi = element.shape(xi); - // area of the cell auto factor = - 0.5 * mito::tensor::determinant(element.jacobian(xi)) * quadrature_rule.weight(q); + 0.5 * mito::tensor::determinant(element.jacobian()(xi)) * quadrature_rule.weight(q); // populate the mass matrix - for (const auto & [node_a, phi_a] : phi) { + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.discretization_nodes()[a]; + // evaluate element's a-th shape function at {xi} + auto phi_a = element.template shape()(xi); // get the equation number of {node_a} int i = equation_map.at(node_a); - for (const auto & [node_b, phi_b] : phi) { + mito::tensor::constexpr_for_1([&]() { + // get the b-th discretization node of the element + const auto & node_b = element.discretization_nodes()[b]; + // evaluate element's b-th shape function at {xi} + auto phi_b = element.template shape()(xi); // get the equation number of {node_b} int j = equation_map.at(node_b); // assemble the {node_a, node_b} contribution to the mass matrix elementary_mass_matrix[{ i, j }] += factor * phi_a * phi_b; - } - } + }); + }); } // compute the error diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc index 11092dd10..6afe507eb 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc @@ -61,36 +61,37 @@ TEST(Fem, IsoparametricTriangleP1) // node 0 in barycentric coordinates auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; - // the shape functions at node 0 - auto phi_0 = element.shape(n0); + // node 1 in barycentric coordinates + auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + // node 2 in barycentric coordinates + auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + + // the shape function associated with local node {0} + auto phi_0 = element.shape<0>(); // check that the shape function at node 0 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_0.at(node_0)); + EXPECT_DOUBLE_EQ(1.0, phi_0(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_1)); + EXPECT_DOUBLE_EQ(0.0, phi_0(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_2)); + EXPECT_DOUBLE_EQ(0.0, phi_0(n2)); - // node 1 in barycentric coordinates - auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; // the shape functions at node 1 - auto phi_1 = element.shape(n1); + auto phi_1 = element.shape<1>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_0)); + EXPECT_DOUBLE_EQ(0.0, phi_1(n0)); // check that the shape function at node 1 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_1.at(node_1)); + EXPECT_DOUBLE_EQ(1.0, phi_1(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_2)); + EXPECT_DOUBLE_EQ(0.0, phi_1(n2)); - // node 2 in barycentric coordinates - auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; // the shape functions at node 2 - auto phi_2 = element.shape(n2); + auto phi_2 = element.shape<2>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_0)); + EXPECT_DOUBLE_EQ(0.0, phi_2(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_1)); + EXPECT_DOUBLE_EQ(0.0, phi_2(n1)); // check that the shape function at node 2 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_2.at(node_2)); + EXPECT_DOUBLE_EQ(1.0, phi_2(n2)); // all done return; diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc index f280783d5..d4c954245 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle_p2.cc @@ -65,105 +65,106 @@ TEST(Fem, IsoparametricTriangleP2) // node 0 in barycentric coordinates auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + // node 1 in barycentric coordinates + auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + // node 2 in barycentric coordinates + auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + // node 3 in barycentric coordinates + auto n3 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; + // node 4 in barycentric coordinates + auto n4 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; + // node 5 in barycentric coordinates + auto n5 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; + // the shape functions at node 0 - auto phi_0 = element.shape(n0); + auto phi_0 = element.shape<0>(); // check that the shape function at node 0 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_0.at(node_0)); + EXPECT_DOUBLE_EQ(1.0, phi_0(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_1)); + EXPECT_DOUBLE_EQ(0.0, phi_0(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_2)); + EXPECT_DOUBLE_EQ(0.0, phi_0(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_3)); + EXPECT_DOUBLE_EQ(0.0, phi_0(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_4)); + EXPECT_DOUBLE_EQ(0.0, phi_0(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0.at(node_5)); + EXPECT_DOUBLE_EQ(0.0, phi_0(n5)); - // node 1 in barycentric coordinates - auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; // the shape functions at node 1 - auto phi_1 = element.shape(n1); + auto phi_1 = element.shape<1>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_0)); + EXPECT_DOUBLE_EQ(0.0, phi_1(n0)); // check that the shape function at node 1 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_1.at(node_1)); + EXPECT_DOUBLE_EQ(1.0, phi_1(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_2)); + EXPECT_DOUBLE_EQ(0.0, phi_1(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_3)); + EXPECT_DOUBLE_EQ(0.0, phi_1(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_4)); + EXPECT_DOUBLE_EQ(0.0, phi_1(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1.at(node_5)); + EXPECT_DOUBLE_EQ(0.0, phi_1(n5)); - // node 2 in barycentric coordinates - auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; // the shape functions at node 2 - auto phi_2 = element.shape(n2); + auto phi_2 = element.shape<2>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_0)); + EXPECT_DOUBLE_EQ(0.0, phi_2(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_1)); + EXPECT_DOUBLE_EQ(0.0, phi_2(n1)); // check that the shape function at node 2 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_2.at(node_2)); + EXPECT_DOUBLE_EQ(1.0, phi_2(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_3)); + EXPECT_DOUBLE_EQ(0.0, phi_2(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_4)); + EXPECT_DOUBLE_EQ(0.0, phi_2(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2.at(node_5)); + EXPECT_DOUBLE_EQ(0.0, phi_2(n5)); - // node 3 in barycentric coordinates - auto n3 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; // the shape functions at node 3 - auto phi_3 = element.shape(n3); + auto phi_3 = element.shape<3>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_0)); + EXPECT_DOUBLE_EQ(0.0, phi_3(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_1)); + EXPECT_DOUBLE_EQ(0.0, phi_3(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_2)); + EXPECT_DOUBLE_EQ(0.0, phi_3(n2)); // check that the shape function at node 3 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_3.at(node_3)); + EXPECT_DOUBLE_EQ(1.0, phi_3(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_4)); + EXPECT_DOUBLE_EQ(0.0, phi_3(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3.at(node_5)); + EXPECT_DOUBLE_EQ(0.0, phi_3(n5)); - // node 4 in barycentric coordinates - auto n4 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; // the shape functions at node 4 - auto phi_4 = element.shape(n4); + auto phi_4 = element.shape<4>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_0)); + EXPECT_DOUBLE_EQ(0.0, phi_4(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_1)); + EXPECT_DOUBLE_EQ(0.0, phi_4(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_2)); + EXPECT_DOUBLE_EQ(0.0, phi_4(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_3)); + EXPECT_DOUBLE_EQ(0.0, phi_4(n3)); // check that the shape function at node 4 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_4.at(node_4)); + EXPECT_DOUBLE_EQ(1.0, phi_4(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4.at(node_5)); + EXPECT_DOUBLE_EQ(0.0, phi_4(n5)); - // node 5 in barycentric coordinates - auto n5 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; // the shape functions at node 5 - auto phi_5 = element.shape(n5); + auto phi_5 = element.shape<5>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_0)); + EXPECT_DOUBLE_EQ(0.0, phi_5(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_1)); + EXPECT_DOUBLE_EQ(0.0, phi_5(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_2)); + EXPECT_DOUBLE_EQ(0.0, phi_5(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_3)); + EXPECT_DOUBLE_EQ(0.0, phi_5(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5.at(node_4)); + EXPECT_DOUBLE_EQ(0.0, phi_5(n4)); // check that the shape function at node 5 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_5.at(node_5)); + EXPECT_DOUBLE_EQ(1.0, phi_5(n5)); // all done return; diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index d0822c6c6..04b349ad6 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -76,6 +76,10 @@ TEST(Fem, PoissonSquare) * mito::functions::sin(std::numbers::pi * y); // channel << "Right hand side: " << f(coordinates_t{ 0.5, 0.5 }) << journal::endl; + // the number of nodes per element + constexpr int n_nodes = + mito::utilities::base_type::element_type::n_nodes; + // loop on all the cells of the mesh for (const auto & element : function_space.elements()) { @@ -92,52 +96,59 @@ TEST(Fem, PoissonSquare) // precompute the common factor auto factor = quadrature_rule.weight(q) * manifold.volume(cell); - // evaluate the spatial gradients of the element shape functions at {xi} - auto dphi = element.gradient(xi); - // populate the linear system of equations - for (const auto & [node_a, dphi_a] : dphi) { + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.discretization_nodes()[a]; + // evaluate the spatial gradient of the element's a-th shape function at {xi} + auto dphi_a = element.gradient()(xi); // get the equation number of {node_a} int eq_a = equation_map.at(node_a); assert(eq_a < N_equations); - if (eq_a == -1) { - // skip boundary nodes - continue; + if (eq_a != -1) { + mito::tensor::constexpr_for_1([&]() { + // get the b-th discretization node of the element + const auto & node_b = element.discretization_nodes()[b]; + // evaluate the spatial gradient of the element's b-th shape + // function at {xi} + auto dphi_b = element.gradient()(xi); + // get the equation number of {node_b} + int eq_b = equation_map.at(node_b); + assert(eq_b < N_equations); + // compute the entry of the stiffness matrix + auto entry = 0.0; + // non boundary nodes + if (eq_b != -1) { + entry = factor * dphi_a * dphi_b; + } + // assemble the value in the stiffness matrix + solver.add_matrix_value(eq_a, eq_b, entry); + }); } - for (const auto & [node_b, dphi_b] : dphi) { - // get the equation number of {node_b} - int eq_b = equation_map.at(node_b); - assert(eq_b < N_equations); - if (eq_b == -1) { - // skip boundary nodes - continue; - } - // compute the entry of the stiffness matrix - auto entry = factor * dphi_a * dphi_b; - // assemble the value in the stiffness matrix - solver.add_matrix_value(eq_a, eq_b, entry); - } - } - - // evaluate the element shape functions at {xi} - auto phi = element.shape(xi); + }); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // populate the right hand side - for (const auto & [node_a, phi_a] : phi) { + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.discretization_nodes()[a]; + // evaluate the a-th shape function at {xi} + auto phi_a = element.shape()(xi); + // get the equation number of {node_a} int eq_a = equation_map.at(node_a); assert(eq_a < N_equations); - if (eq_a == -1) { - // skip boundary nodes - continue; + // compute the entry of the right hand side + auto entry = 0.0; + // non boundary nodes + if (eq_a != -1) { + entry = factor * f(coord) * phi_a; } - // assemble the value in the right hand side - solver.add_rhs_value(eq_a, factor * f(coord) * phi_a); - } + solver.add_rhs_value(eq_a, entry); + }); } } @@ -214,8 +225,6 @@ TEST(Fem, PoissonSquare) for (int q = 0; q < quadrature_rule_t::npoints; ++q) { // the barycentric coordinates of the quadrature point /*constexpr*/ auto xi = quadrature_rule.point(q); - // evaluate the element shape functions at {xi} - auto phi = element.shape(xi); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // get the exact solution at {coord} @@ -223,14 +232,18 @@ TEST(Fem, PoissonSquare) // assemble the numerical solution at {coord} auto u_numerical = 0.0; // loop on all the shape functions - for (const auto & [node_a, phi_a] : phi) { - // get the equation number of {node} + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.discretization_nodes()[a]; + // evaluate the a-th shape function at {xi} + auto phi_a = element.shape()(xi); + // get the equation number of {node_a} int eq = equation_map.at(node_a); if (eq != -1) { // get the numerical solution at {coord} u_numerical += u[eq] * phi_a; } - } + }); // get the error error_L2 += (u_exact - u_numerical) * (u_exact - u_numerical) * quadrature_rule.weight(q) * volume; From cb6da47c12545be8173a4bf52b712ba1a5071146 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 16:04:09 +0200 Subject: [PATCH 105/273] discretization: improve conciseness --- lib/mito/discretization/IsoparametricTriangleP1.h | 12 +++--------- lib/mito/discretization/IsoparametricTriangleP2.h | 12 +++--------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangleP1.h b/lib/mito/discretization/IsoparametricTriangleP1.h index 0b0b6544d..21adb6a99 100644 --- a/lib/mito/discretization/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/IsoparametricTriangleP1.h @@ -78,10 +78,8 @@ namespace mito::discretization { // assemble the shape function associated with local node {a} as a function of // barycentric coordinates auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { - // strip the third barycentric coordinate - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the a-th shape function evaluated at {xi} - return std::get(phi)(xi_p); + return std::get(phi)({ xi[0], xi[1] }); }; // and return it @@ -97,10 +95,8 @@ namespace mito::discretization { // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; - // strip the third barycentric coordinate - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // compute the gradient of the isoparametric mapping - return fields::gradient(x_cell)(xi_p); + return fields::gradient(x_cell)({ xi[0], xi[1] }); }; // and return it @@ -120,10 +116,8 @@ namespace mito::discretization { auto J = jacobian()(xi); // the derivative of the coordinates with respect to the barycentric coordinates auto J_inv = tensor::inverse(J); - // strip the third barycentric coordinate - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return std::get(dphi)(xi_p) * J_inv; + return std::get(dphi)({ xi[0], xi[1] }) * J_inv; }; // and return it return gradient_function; diff --git a/lib/mito/discretization/IsoparametricTriangleP2.h b/lib/mito/discretization/IsoparametricTriangleP2.h index f13258b8f..8e3cde555 100644 --- a/lib/mito/discretization/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/IsoparametricTriangleP2.h @@ -87,10 +87,8 @@ namespace mito::discretization { // assemble the shape function associated with local node {a} as a function of // barycentric coordinates auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { - // strip the third barycentric coordinate - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the a-th shape function evaluated at {xi} - return std::get(phi)(xi_p); + return std::get(phi)({ xi[0], xi[1] }); }; // and return it @@ -112,10 +110,8 @@ namespace mito::discretization { auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; - // strip the third barycentric coordinate - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // compute the gradient of the isoparametric mapping - return fields::gradient(x_cell)(xi_p); + return fields::gradient(x_cell)({ xi[0], xi[1] }); }; // and return it @@ -135,10 +131,8 @@ namespace mito::discretization { auto J = jacobian()(xi); // the derivative of the coordinates with respect to the barycentric coordinates auto J_inv = tensor::inverse(J); - // strip the third barycentric coordinate - auto xi_p = parametric_coordinates_type{ xi[0], xi[1] }; // return the spatial gradients of the shape functions evaluated at {xi} - return std::get(dphi)(xi_p) * J_inv; + return std::get(dphi)({ xi[0], xi[1] }) * J_inv; }; // and return it return gradient_function; From 4da85718dcb1968febaa632a3cfe69a352bc99d5 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 17:19:42 +0200 Subject: [PATCH 106/273] discretization: refactoring Add classes {ReferenceTriangle}, {ShapeTriangleP1} and {ShapeTriangleP2}. --- .../discretization/IsoparametricTriangle.h | 12 ---- .../discretization/IsoparametricTriangleP1.h | 27 +++----- .../discretization/IsoparametricTriangleP2.h | 41 ++++-------- lib/mito/discretization/ReferenceTriangle.h | 31 +++++++++ lib/mito/discretization/ShapeTriangleP1.h | 63 +++++++++++++++++ lib/mito/discretization/ShapeTriangleP2.h | 67 +++++++++++++++++++ lib/mito/discretization/public.h | 3 + 7 files changed, 189 insertions(+), 55 deletions(-) create mode 100644 lib/mito/discretization/ReferenceTriangle.h create mode 100644 lib/mito/discretization/ShapeTriangleP1.h create mode 100644 lib/mito/discretization/ShapeTriangleP2.h diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index e927c1c48..7ed767ff0 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -21,8 +21,6 @@ namespace mito::discretization { protected: // the geometric simplex type using geometric_simplex_type = geometry::triangle_t<2>; - // the parametric coordinates type - using parametric_coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; // cartesian coordinates in 2D using coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; // the coordinate system type @@ -30,16 +28,6 @@ namespace mito::discretization { // the vector type using vector_type = tensor::vector_t<2>; - protected: - // the function extracting the 0 component of a parametric point - static constexpr auto xi_0 = - fields::field(functions::component); - // the function extracting the 1 component of a parametric point - static constexpr auto xi_1 = - fields::field(functions::component); - // the function extracting the 2 component of a parametric point - static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; - public: // the default constructor constexpr IsoparametricTriangle( diff --git a/lib/mito/discretization/IsoparametricTriangleP1.h b/lib/mito/discretization/IsoparametricTriangleP1.h index 21adb6a99..e03b90787 100644 --- a/lib/mito/discretization/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/IsoparametricTriangleP1.h @@ -17,27 +17,18 @@ namespace mito::discretization { class IsoparametricTriangleP1 : public IsoparametricTriangle { public: + // the type of shape functions + using shape_functions_type = ShapeTriangleP1; + // the linear shape functions + static constexpr auto shape_functions = shape_functions_type(); // the number of discretization discretization nodes - static constexpr int n_nodes = 3; + static constexpr int n_nodes = shape_functions_type::N; // a collection of discretization discretization nodes using discretization_nodes_type = std::array; // type of a point in barycentric coordinates using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; - private: - // linear shape functions on the triangle - static constexpr auto phi_0 = xi_0; - static constexpr auto phi_1 = xi_1; - static constexpr auto phi_2 = xi_2; - - // the shape functions - static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); - - // the gradients of the shape functions - static constexpr auto dphi = std::make_tuple( - fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2)); - public: // the default constructor inline IsoparametricTriangleP1( @@ -79,7 +70,7 @@ namespace mito::discretization { // barycentric coordinates auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { // return the a-th shape function evaluated at {xi} - return std::get(phi)({ xi[0], xi[1] }); + return shape_functions.shape()({ xi[0], xi[1] }); }; // and return it @@ -92,6 +83,10 @@ namespace mito::discretization { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { + // get the shape functions + auto phi_0 = shape_functions.shape<0>(); + auto phi_1 = shape_functions.shape<1>(); + auto phi_2 = shape_functions.shape<2>(); // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; @@ -117,7 +112,7 @@ namespace mito::discretization { // the derivative of the coordinates with respect to the barycentric coordinates auto J_inv = tensor::inverse(J); // return the spatial gradients of the shape functions evaluated at {xi} - return std::get(dphi)({ xi[0], xi[1] }) * J_inv; + return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; }; // and return it return gradient_function; diff --git a/lib/mito/discretization/IsoparametricTriangleP2.h b/lib/mito/discretization/IsoparametricTriangleP2.h index 8e3cde555..5b6157e8f 100644 --- a/lib/mito/discretization/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/IsoparametricTriangleP2.h @@ -17,36 +17,18 @@ namespace mito::discretization { class IsoparametricTriangleP2 : public IsoparametricTriangle { public: + // the type of shape functions + using shape_functions_type = ShapeTriangleP2; + // the linear shape functions + static constexpr auto shape_functions = shape_functions_type(); // the number of discretization nodes - static constexpr int n_nodes = 6; + static constexpr int n_nodes = shape_functions_type::N; // a collection of discretization nodes using discretization_nodes_type = std::array; // type of a point in barycentric coordinates using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; - private: - // strip the namespace - static constexpr auto xi_0 = xi_0; - static constexpr auto xi_1 = xi_1; - static constexpr auto xi_2 = xi_2; - - // quadratic shape functions on the triangle - static constexpr auto phi_3 = 4.0 * xi_0 * xi_1; - static constexpr auto phi_4 = 4.0 * xi_1 * xi_2; - static constexpr auto phi_5 = 4.0 * xi_0 * xi_2; - static constexpr auto phi_0 = xi_0 - 0.5 * phi_5 - 0.5 * phi_3; - static constexpr auto phi_1 = xi_1 - 0.5 * phi_3 - 0.5 * phi_4; - static constexpr auto phi_2 = xi_2 - 0.5 * phi_5 - 0.5 * phi_4; - - // the shape functions - static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); - - // the gradients of the shape functions - static constexpr auto dphi = std::make_tuple( - fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2), - fields::gradient(phi_3), fields::gradient(phi_4), fields::gradient(phi_5)); - public: // the default constructor inline IsoparametricTriangleP2( @@ -88,7 +70,7 @@ namespace mito::discretization { // barycentric coordinates auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { // return the a-th shape function evaluated at {xi} - return std::get(phi)({ xi[0], xi[1] }); + return shape_functions.shape()({ xi[0], xi[1] }); }; // and return it @@ -104,12 +86,17 @@ namespace mito::discretization { auto x3 = 0.5 * (_x0 + _x1); auto x4 = 0.5 * (_x1 + _x2); auto x5 = 0.5 * (_x2 + _x0); - + // get the shape functions + auto phi_0 = shape_functions.shape<0>(); + auto phi_1 = shape_functions.shape<1>(); + auto phi_2 = shape_functions.shape<2>(); + auto phi_3 = shape_functions.shape<3>(); + auto phi_4 = shape_functions.shape<4>(); + auto phi_5 = shape_functions.shape<5>(); // assemble the isoparametric mapping from the barycentric coordinates to the actual // coordinates on the cell {cell} auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; - // compute the gradient of the isoparametric mapping return fields::gradient(x_cell)({ xi[0], xi[1] }); }; @@ -132,7 +119,7 @@ namespace mito::discretization { // the derivative of the coordinates with respect to the barycentric coordinates auto J_inv = tensor::inverse(J); // return the spatial gradients of the shape functions evaluated at {xi} - return std::get(dphi)({ xi[0], xi[1] }) * J_inv; + return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; }; // and return it return gradient_function; diff --git a/lib/mito/discretization/ReferenceTriangle.h b/lib/mito/discretization/ReferenceTriangle.h new file mode 100644 index 000000000..ae3dbe18b --- /dev/null +++ b/lib/mito/discretization/ReferenceTriangle.h @@ -0,0 +1,31 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + class ReferenceTriangle { + + public: + // the parametric coordinates type + using parametric_coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; + + // the function extracting the 0 component of a parametric point + static constexpr auto xi_0 = + fields::field(functions::component); + // the function extracting the 1 component of a parametric point + static constexpr auto xi_1 = + fields::field(functions::component); + // the function extracting the 2 component of a parametric point + static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/ShapeTriangleP1.h b/lib/mito/discretization/ShapeTriangleP1.h new file mode 100644 index 000000000..ead431e37 --- /dev/null +++ b/lib/mito/discretization/ShapeTriangleP1.h @@ -0,0 +1,63 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + class ShapeTriangleP1 { + + private: + // the reference element + using reference_element_type = ReferenceTriangle; + + public: + // the number of shape functions + static constexpr int N = 3; + + private: + // get the parametric coordinates from the reference element + static constexpr auto xi_0 = reference_element_type::xi_0; + static constexpr auto xi_1 = reference_element_type::xi_1; + static constexpr auto xi_2 = reference_element_type::xi_2; + + // linear shape functions on the triangle + static constexpr auto phi_0 = xi_0; + static constexpr auto phi_1 = xi_1; + static constexpr auto phi_2 = xi_2; + + // the shape functions + static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); + + // the gradients of the shape functions + static constexpr auto dphi = std::make_tuple( + fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2)); + + public: + // get the a-th shape function + template + requires(a >= 0 && a < N) + inline auto shape() const + { + // return the a-th shape function + return std::get(phi); + } + + // get the a-th shape function's gradient + template + requires(a >= 0 && a < N) + inline auto dshape() const + { + // return the a-th shape function's gradient + return std::get(dphi); + } + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/ShapeTriangleP2.h b/lib/mito/discretization/ShapeTriangleP2.h new file mode 100644 index 000000000..bc582dacd --- /dev/null +++ b/lib/mito/discretization/ShapeTriangleP2.h @@ -0,0 +1,67 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + class ShapeTriangleP2 { + + private: + // the reference element + using reference_element_type = ReferenceTriangle; + + public: + // the number of shape functions + static constexpr int N = 6; + + private: + // get the parametric coordinates from the reference element + static constexpr auto xi_0 = reference_element_type::xi_0; + static constexpr auto xi_1 = reference_element_type::xi_1; + static constexpr auto xi_2 = reference_element_type::xi_2; + + // quadratic shape functions on the triangle + static constexpr auto phi_3 = 4.0 * xi_0 * xi_1; + static constexpr auto phi_4 = 4.0 * xi_1 * xi_2; + static constexpr auto phi_5 = 4.0 * xi_0 * xi_2; + static constexpr auto phi_0 = xi_0 - 0.5 * phi_5 - 0.5 * phi_3; + static constexpr auto phi_1 = xi_1 - 0.5 * phi_3 - 0.5 * phi_4; + static constexpr auto phi_2 = xi_2 - 0.5 * phi_5 - 0.5 * phi_4; + + // the shape functions + static constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); + + // the gradients of the shape functions + static constexpr auto dphi = std::make_tuple( + fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2), + fields::gradient(phi_3), fields::gradient(phi_4), fields::gradient(phi_5)); + + public: + // get the a-th shape function + template + requires(a >= 0 && a < N) + inline auto shape() const + { + // return the a-th shape function + return std::get(phi); + } + + // get the a-th shape function's gradient + template + requires(a >= 0 && a < N) + inline auto dshape() const + { + // return the a-th shape function's gradient + return std::get(dphi); + } + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 4abe76368..c1badc803 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -17,6 +17,9 @@ #include "api.h" // classes implementation +#include "ReferenceTriangle.h" +#include "ShapeTriangleP1.h" +#include "ShapeTriangleP2.h" #include "DiscreteField.h" #include "DiscretizationNode.h" #include "isoparametric_simplex_library.h" From 13d9d3c31a7e8d7d9b59aac45df5c095596dbc2e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 17:25:33 +0200 Subject: [PATCH 107/273] discretization: refactoring Moved {barycentric_coordinates_type} definition to base class {IsoparametricTriangle}. --- lib/mito/discretization/IsoparametricTriangle.h | 7 +++++-- lib/mito/discretization/IsoparametricTriangleP1.h | 3 --- lib/mito/discretization/IsoparametricTriangleP2.h | 3 --- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/IsoparametricTriangle.h index 7ed767ff0..80758d1f7 100644 --- a/lib/mito/discretization/IsoparametricTriangle.h +++ b/lib/mito/discretization/IsoparametricTriangle.h @@ -17,10 +17,13 @@ namespace mito::discretization { public: // the discretization node type using discretization_node_type = discretization_node_t; - - protected: // the geometric simplex type using geometric_simplex_type = geometry::triangle_t<2>; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = + typename geometric_simplex_type::barycentric_coordinates_type; + + protected: // cartesian coordinates in 2D using coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; // the coordinate system type diff --git a/lib/mito/discretization/IsoparametricTriangleP1.h b/lib/mito/discretization/IsoparametricTriangleP1.h index e03b90787..60fb5df90 100644 --- a/lib/mito/discretization/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/IsoparametricTriangleP1.h @@ -25,9 +25,6 @@ namespace mito::discretization { static constexpr int n_nodes = shape_functions_type::N; // a collection of discretization discretization nodes using discretization_nodes_type = std::array; - // type of a point in barycentric coordinates - using barycentric_coordinates_type = - typename geometric_simplex_type::barycentric_coordinates_type; public: // the default constructor diff --git a/lib/mito/discretization/IsoparametricTriangleP2.h b/lib/mito/discretization/IsoparametricTriangleP2.h index 5b6157e8f..db938622b 100644 --- a/lib/mito/discretization/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/IsoparametricTriangleP2.h @@ -25,9 +25,6 @@ namespace mito::discretization { static constexpr int n_nodes = shape_functions_type::N; // a collection of discretization nodes using discretization_nodes_type = std::array; - // type of a point in barycentric coordinates - using barycentric_coordinates_type = - typename geometric_simplex_type::barycentric_coordinates_type; public: // the default constructor From ed5e0ec6770a932a7d5dd277c62f6b039e7ea804 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 17:35:35 +0200 Subject: [PATCH 108/273] discretization: rename {discretization_nodes} to {connectivity} --- lib/mito/discretization/FunctionSpace.h | 7 +++---- lib/mito/discretization/IsoparametricTriangleP1.h | 13 ++++++------- lib/mito/discretization/IsoparametricTriangleP2.h | 13 ++++++------- lib/mito/discretization/utilities.h | 2 +- .../discretization/isoparametric_triangle.cc | 8 ++++---- tests/mito.lib/discretization/poisson.cc | 8 ++++---- 6 files changed, 24 insertions(+), 27 deletions(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index bf4e3d940..6f1e36370 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -36,7 +36,7 @@ namespace mito::discretization { // the discretization node type using discretization_node_type = typename element_type::discretization_node_type; // the nodes type - using discretization_nodes_type = typename element_type::discretization_nodes_type; + using connectivity_type = typename element_type::connectivity_type; // the constrained nodes type using constrained_nodes_type = std::set; @@ -80,7 +80,7 @@ namespace mito::discretization { // create a finite element for each cell and add it to the pile _elements.emplace( - cell, coord_system, discretization_nodes_type{ node_0, node_1, node_2 }); + cell, coord_system, connectivity_type{ node_0, node_1, node_2 }); } // populate the constrained nodes @@ -146,8 +146,7 @@ namespace mito::discretization { // create a finite element for each cell and add it to the pile _elements.emplace( cell, coord_system, - discretization_nodes_type{ node_0, node_1, node_2, node_3, node_4, - node_5 }); + connectivity_type{ node_0, node_1, node_2, node_3, node_4, node_5 }); } // populate the constrained nodes diff --git a/lib/mito/discretization/IsoparametricTriangleP1.h b/lib/mito/discretization/IsoparametricTriangleP1.h index 60fb5df90..5aa24d404 100644 --- a/lib/mito/discretization/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/IsoparametricTriangleP1.h @@ -24,16 +24,15 @@ namespace mito::discretization { // the number of discretization discretization nodes static constexpr int n_nodes = shape_functions_type::N; // a collection of discretization discretization nodes - using discretization_nodes_type = std::array; + using connectivity_type = std::array; public: // the default constructor inline IsoparametricTriangleP1( const geometric_simplex_type & geometric_simplex, - const coordinate_system_type & coord_system, - const discretization_nodes_type & discretization_nodes) : + const coordinate_system_type & coord_system, const connectivity_type & connectivity) : IsoparametricTriangle(geometric_simplex, coord_system), - _discretization_nodes(discretization_nodes) + _connectivity(connectivity) {} // destructor @@ -53,9 +52,9 @@ namespace mito::discretization { public: // get the discretization nodes - inline auto discretization_nodes() const noexcept -> const discretization_nodes_type & + inline auto connectivity() const noexcept -> const connectivity_type & { - return _discretization_nodes; + return _connectivity; } // get the shape function associated with local node {a} @@ -117,7 +116,7 @@ namespace mito::discretization { private: // the discretization nodes of the simplex - const discretization_nodes_type _discretization_nodes; + const connectivity_type _connectivity; }; } // namespace mito diff --git a/lib/mito/discretization/IsoparametricTriangleP2.h b/lib/mito/discretization/IsoparametricTriangleP2.h index db938622b..8ee2d9842 100644 --- a/lib/mito/discretization/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/IsoparametricTriangleP2.h @@ -24,16 +24,15 @@ namespace mito::discretization { // the number of discretization nodes static constexpr int n_nodes = shape_functions_type::N; // a collection of discretization nodes - using discretization_nodes_type = std::array; + using connectivity_type = std::array; public: // the default constructor inline IsoparametricTriangleP2( const geometric_simplex_type & geometric_simplex, - const coordinate_system_type & coord_system, - const discretization_nodes_type & discretization_nodes) : + const coordinate_system_type & coord_system, const connectivity_type & connectivity) : IsoparametricTriangle(geometric_simplex, coord_system), - _discretization_nodes(discretization_nodes) + _connectivity(connectivity) {} // destructor @@ -53,9 +52,9 @@ namespace mito::discretization { public: // get the discretization nodes - inline auto discretization_nodes() const noexcept -> const discretization_nodes_type & + inline auto connectivity() const noexcept -> const connectivity_type & { - return _discretization_nodes; + return _connectivity; } // get the shape function associated with local node {a} @@ -124,7 +123,7 @@ namespace mito::discretization { private: // the discretization nodes of the simplex - const discretization_nodes_type _discretization_nodes; + const connectivity_type _connectivity; }; } // namespace mito diff --git a/lib/mito/discretization/utilities.h b/lib/mito/discretization/utilities.h index 19cb5ed25..f002d1ec9 100644 --- a/lib/mito/discretization/utilities.h +++ b/lib/mito/discretization/utilities.h @@ -14,7 +14,7 @@ namespace mito::discretization { inline auto get_nodes(const functionSpaceT & function_space, nodesCollectionT & nodes) -> void { for (const auto & element : function_space.elements()) { - for (const auto & node : element.discretization_nodes()) { + for (const auto & node : element.connectivity()) { nodes.insert(node); } } diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 8c4124f85..e1e956878 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -114,14 +114,14 @@ test_stiffness_matrix( // populate the stiffness matrix mito::tensor::constexpr_for_1([&]() { // get the a-th discretization node of the element - const auto & node_a = element.discretization_nodes()[a]; + const auto & node_a = element.connectivity()[a]; // evaluate the spatial gradient of the element's a-th shape function at {xi} auto dphi_a = element.template gradient()(xi); // get the equation number of {node_a} int i = equation_map.at(node_a); mito::tensor::constexpr_for_1([&]() { // get the b-th discretization node of the element - const auto & node_b = element.discretization_nodes()[b]; + const auto & node_b = element.connectivity()[b]; // evaluate the spatial gradient of the element's b-th shape function at {xi} auto dphi_b = element.template gradient()(xi); // get the equation number of {node_b} @@ -171,14 +171,14 @@ test_mass_matrix( // populate the mass matrix mito::tensor::constexpr_for_1([&]() { // get the a-th discretization node of the element - const auto & node_a = element.discretization_nodes()[a]; + const auto & node_a = element.connectivity()[a]; // evaluate element's a-th shape function at {xi} auto phi_a = element.template shape()(xi); // get the equation number of {node_a} int i = equation_map.at(node_a); mito::tensor::constexpr_for_1([&]() { // get the b-th discretization node of the element - const auto & node_b = element.discretization_nodes()[b]; + const auto & node_b = element.connectivity()[b]; // evaluate element's b-th shape function at {xi} auto phi_b = element.template shape()(xi); // get the equation number of {node_b} diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 04b349ad6..7b84dffe7 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -99,7 +99,7 @@ TEST(Fem, PoissonSquare) // populate the linear system of equations mito::tensor::constexpr_for_1([&]() { // get the a-th discretization node of the element - const auto & node_a = element.discretization_nodes()[a]; + const auto & node_a = element.connectivity()[a]; // evaluate the spatial gradient of the element's a-th shape function at {xi} auto dphi_a = element.gradient()(xi); // get the equation number of {node_a} @@ -108,7 +108,7 @@ TEST(Fem, PoissonSquare) if (eq_a != -1) { mito::tensor::constexpr_for_1([&]() { // get the b-th discretization node of the element - const auto & node_b = element.discretization_nodes()[b]; + const auto & node_b = element.connectivity()[b]; // evaluate the spatial gradient of the element's b-th shape // function at {xi} auto dphi_b = element.gradient()(xi); @@ -133,7 +133,7 @@ TEST(Fem, PoissonSquare) // populate the right hand side mito::tensor::constexpr_for_1([&]() { // get the a-th discretization node of the element - const auto & node_a = element.discretization_nodes()[a]; + const auto & node_a = element.connectivity()[a]; // evaluate the a-th shape function at {xi} auto phi_a = element.shape()(xi); @@ -234,7 +234,7 @@ TEST(Fem, PoissonSquare) // loop on all the shape functions mito::tensor::constexpr_for_1([&]() { // get the a-th discretization node of the element - const auto & node_a = element.discretization_nodes()[a]; + const auto & node_a = element.connectivity()[a]; // evaluate the a-th shape function at {xi} auto phi_a = element.shape()(xi); // get the equation number of {node_a} From 0f4f4d5bfaff6492979a064da7684c971df45daf Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 17:54:40 +0200 Subject: [PATCH 109/273] discretization: make {reference_element_type} definition public in {ShapeTrianglePN} classes --- lib/mito/discretization/ShapeTriangleP1.h | 4 +--- lib/mito/discretization/ShapeTriangleP2.h | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/lib/mito/discretization/ShapeTriangleP1.h b/lib/mito/discretization/ShapeTriangleP1.h index ead431e37..c46c96c59 100644 --- a/lib/mito/discretization/ShapeTriangleP1.h +++ b/lib/mito/discretization/ShapeTriangleP1.h @@ -11,11 +11,9 @@ namespace mito::discretization { class ShapeTriangleP1 { - private: + public: // the reference element using reference_element_type = ReferenceTriangle; - - public: // the number of shape functions static constexpr int N = 3; diff --git a/lib/mito/discretization/ShapeTriangleP2.h b/lib/mito/discretization/ShapeTriangleP2.h index bc582dacd..9d6ed7ffb 100644 --- a/lib/mito/discretization/ShapeTriangleP2.h +++ b/lib/mito/discretization/ShapeTriangleP2.h @@ -11,11 +11,9 @@ namespace mito::discretization { class ShapeTriangleP2 { - private: + public: // the reference element using reference_element_type = ReferenceTriangle; - - public: // the number of shape functions static constexpr int N = 6; From 21b47216df06ec7b16544eb1bc5ffaad5eb2d896 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 18:05:22 +0200 Subject: [PATCH 110/273] tests/discretization: simplify tests on shape functions No need to build a finite element to test the shape functions individually. --- .cmake/mito_tests_mito_lib.cmake | 4 +- .../isoparametric_triangle_p1.cc | 98 ------------------- .../shape_functions_triangle_p1.cc | 57 +++++++++++ ...e_p2.cc => shape_functions_triangle_p2.cc} | 70 +++---------- 4 files changed, 72 insertions(+), 157 deletions(-) delete mode 100644 tests/mito.lib/discretization/isoparametric_triangle_p1.cc create mode 100644 tests/mito.lib/discretization/shape_functions_triangle_p1.cc rename tests/mito.lib/discretization/{isoparametric_triangle_p2.cc => shape_functions_triangle_p2.cc} (64%) diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 795a98c2a..debab268f 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -42,9 +42,9 @@ mito_test_driver(tests/mito.lib/constraints/dirichlet.cc) mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) mito_test_driver(tests/mito.lib/discretization/nodal_field.cc) mito_test_driver(tests/mito.lib/discretization/poisson.cc) +mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p1.cc) +mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p2.cc) mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle.cc) -mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle_p1.cc) -mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle_p2.cc) # io mito_test_driver(tests/mito.lib/io/summit_mesh_reader_2D.cc) diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc b/tests/mito.lib/discretization/isoparametric_triangle_p1.cc deleted file mode 100644 index 6afe507eb..000000000 --- a/tests/mito.lib/discretization/isoparametric_triangle_p1.cc +++ /dev/null @@ -1,98 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - -#include -#include - - -// the type of coordinates -using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; -// the type of coordinate system -using coord_system_t = mito::geometry::coordinate_system_t; -// the type of discretization node -using discretization_node_t = mito::discretization::discretization_node_t; -// the type of cell -using cell_t = mito::geometry::triangle_t<2>; -// first order isoparametric triangle -using element_t = mito::discretization::isoparametric_simplex<1, cell_t>::type; -// the barycentric coordinates type -using barycentric_coordinates_t = typename element_t::barycentric_coordinates_type; - - -TEST(Fem, IsoparametricTriangleP1) -{ - /** - * The reference triangle in barycentric coordinates: - (0,0,1) - 2 - xi_2 + - | . - | . - | . - | . - | . - | . - | . - +---------------+ xi_1 - 0 1 - (1,0,0) (0,1,0) - */ - - // the coordinate system - auto coord_system = coord_system_t(); - - // build nodes - auto v0 = mito::geometry::node(coord_system, { 0.0, 0.0 }); - auto v1 = mito::geometry::node(coord_system, { 1.0, 0.0 }); - auto v2 = mito::geometry::node(coord_system, { 1.0, 1.0 }); - - // make a geometric simplex - auto geometric_simplex = mito::geometry::triangle<2>({ v0, v1, v2 }); - - // build the discretization nodes - auto node_0 = discretization_node_t(); - auto node_1 = discretization_node_t(); - auto node_2 = discretization_node_t(); - - // a finite element - auto element = element_t(geometric_simplex, coord_system, { node_0, node_1, node_2 }); - - // node 0 in barycentric coordinates - auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; - // node 1 in barycentric coordinates - auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; - // node 2 in barycentric coordinates - auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; - - // the shape function associated with local node {0} - auto phi_0 = element.shape<0>(); - // check that the shape function at node 0 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_0(n0)); - // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n1)); - // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n2)); - - // the shape functions at node 1 - auto phi_1 = element.shape<1>(); - // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n0)); - // check that the shape function at node 1 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_1(n1)); - // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n2)); - - // the shape functions at node 2 - auto phi_2 = element.shape<2>(); - // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n0)); - // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n1)); - // check that the shape function at node 2 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_2(n2)); - - // all done - return; -} \ No newline at end of file diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc new file mode 100644 index 000000000..d54fb0296 --- /dev/null +++ b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc @@ -0,0 +1,57 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// first order shape functions type +using shape_t = mito::discretization::ShapeTriangleP1; +// the parametric coordinates type +using parametric_coordinates_t = shape_t::reference_element_type::parametric_coordinates_type; + + +TEST(Fem, ShapeTriangleP1) +{ + // first order shape functions + auto element = shape_t(); + + // node 0 in barycentric coordinates + auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; + // node 1 in barycentric coordinates + auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; + // node 2 in barycentric coordinates + auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; + + // the shape function associated with local node {0} + auto phi_0 = element.shape<0>(); + // check that the shape function at node 0 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_0(n0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0(n1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_0(n2)); + + // the shape functions at node 1 + auto phi_1 = element.shape<1>(); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1(n0)); + // check that the shape function at node 1 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_1(n1)); + // check that the shape function at node 2 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_1(n2)); + + // the shape functions at node 2 + auto phi_2 = element.shape<2>(); + // check that the shape function at node 0 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2(n0)); + // check that the shape function at node 1 is 0.0 + EXPECT_DOUBLE_EQ(0.0, phi_2(n1)); + // check that the shape function at node 2 is 1.0 + EXPECT_DOUBLE_EQ(1.0, phi_2(n2)); + + // all done + return; +} \ No newline at end of file diff --git a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc similarity index 64% rename from tests/mito.lib/discretization/isoparametric_triangle_p2.cc rename to tests/mito.lib/discretization/shape_functions_triangle_p2.cc index d4c954245..e57cf7bc4 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle_p2.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc @@ -7,74 +7,30 @@ #include -// the type of coordinates -using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; -// the type of coordinate system -using coord_system_t = mito::geometry::coordinate_system_t; -// the type of discretization node -using discretization_node_t = mito::discretization::discretization_node_t; -// the type of cell -using cell_t = mito::geometry::triangle_t<2>; -// second order isoparametric triangle -using element_t = mito::discretization::isoparametric_simplex<2, cell_t>::type; -// the barycentric coordinates type -using barycentric_coordinates_t = typename element_t::barycentric_coordinates_type; +// second order shape functions type +using shape_t = mito::discretization::ShapeTriangleP2; +// the parametric coordinates type +using parametric_coordinates_t = shape_t::reference_element_type::parametric_coordinates_type; -TEST(Fem, IsoparametricTriangleP2) +TEST(Fem, ShapeTriangleP2) { - /** - * The reference triangle in barycentric coordinates: - (0,0,1) - 2 - xi_2 + - | . - | . - | . - (1/2, 0, 1/2) 5 + + 4 (0, 1/2, 1/2) - | . - | . - | . - +-------+-------+ xi_1 - 0 3 1 - (1,0,0) (1/2, 1/2, 0) (0,1,0) - */ - // the coordinate system - auto coord_system = coord_system_t(); - - // build nodes - auto v0 = mito::geometry::node(coord_system, { 0.0, 0.0 }); - auto v1 = mito::geometry::node(coord_system, { 1.0, 0.0 }); - auto v2 = mito::geometry::node(coord_system, { 1.0, 1.0 }); - - // make a geometric simplex - auto geometric_simplex = mito::geometry::triangle<2>({ v0, v1, v2 }); - - // build the discretization nodes - auto node_0 = discretization_node_t(); - auto node_1 = discretization_node_t(); - auto node_2 = discretization_node_t(); - auto node_3 = discretization_node_t(); - auto node_4 = discretization_node_t(); - auto node_5 = discretization_node_t(); - - // a finite element - auto element = element_t( - geometric_simplex, coord_system, { node_0, node_1, node_2, node_3, node_4, node_5 }); + // second order shape functions + auto element = shape_t(); // node 0 in barycentric coordinates - auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; // node 1 in barycentric coordinates - auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; // node 2 in barycentric coordinates - auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; // node 3 in barycentric coordinates - auto n3 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; + auto n3 = parametric_coordinates_t{ 0.5, 0.5 }; // node 4 in barycentric coordinates - auto n4 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; + auto n4 = parametric_coordinates_t{ 0.0, 0.5 }; // node 5 in barycentric coordinates - auto n5 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; + auto n5 = parametric_coordinates_t{ 0.5, 0.0 }; // the shape functions at node 0 auto phi_0 = element.shape<0>(); From 4379080b0337d66a84cc67653e79c957e3741a55 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 18:39:33 +0200 Subject: [PATCH 111/273] discretization: collected fem classes in {fem} subdirectory --- lib/mito/discretization/api.h | 11 ----------- lib/mito/discretization/factories.h | 10 ---------- lib/mito/discretization/fem.h | 14 ++++++++++++++ lib/mito/discretization/{ => fem}/FunctionSpace.h | 0 .../{ => fem}/IsoparametricTriangle.h | 0 .../{ => fem}/IsoparametricTriangleP1.h | 0 .../{ => fem}/IsoparametricTriangleP2.h | 0 .../discretization/{ => fem}/ReferenceTriangle.h | 0 .../discretization/{ => fem}/ShapeTriangleP1.h | 0 .../discretization/{ => fem}/ShapeTriangleP2.h | 0 .../{ => fem}/isoparametric_simplex_library.h | 0 lib/mito/discretization/{ => fem}/utilities.h | 0 lib/mito/discretization/forward.h | 7 ------- lib/mito/discretization/public.h | 11 +++-------- 14 files changed, 17 insertions(+), 36 deletions(-) create mode 100644 lib/mito/discretization/fem.h rename lib/mito/discretization/{ => fem}/FunctionSpace.h (100%) rename lib/mito/discretization/{ => fem}/IsoparametricTriangle.h (100%) rename lib/mito/discretization/{ => fem}/IsoparametricTriangleP1.h (100%) rename lib/mito/discretization/{ => fem}/IsoparametricTriangleP2.h (100%) rename lib/mito/discretization/{ => fem}/ReferenceTriangle.h (100%) rename lib/mito/discretization/{ => fem}/ShapeTriangleP1.h (100%) rename lib/mito/discretization/{ => fem}/ShapeTriangleP2.h (100%) rename lib/mito/discretization/{ => fem}/isoparametric_simplex_library.h (100%) rename lib/mito/discretization/{ => fem}/utilities.h (100%) diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 6e9052dd9..e362593d0 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -9,9 +9,6 @@ namespace mito::discretization { - // discretization node alias - using discretization_node_t = utilities::std_shared_ptr; - // nodal field template using nodal_field_t = DiscreteField, Y>; @@ -36,14 +33,6 @@ namespace mito::discretization { template constexpr auto point_field(const cloudT & cloud, std::string name); - // function space alias - template - using function_space_t = FunctionSpace; - - // function space factory - template - constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); - // discrete system alias template using discrete_system_t = DiscreteSystem; diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index de0e335b8..c3214b9f3 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -42,16 +42,6 @@ namespace mito::discretization { return point_field_t(cloud.points(), name); } - // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a - // single constraint - // function space factory - template - constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) - { - // build a function space on the manifold and return it - return function_space_t(manifold, constraints); - } - // discrete system factory template constexpr auto discrete_system(const functionSpaceT & function_space) diff --git a/lib/mito/discretization/fem.h b/lib/mito/discretization/fem.h new file mode 100644 index 000000000..3da96c16a --- /dev/null +++ b/lib/mito/discretization/fem.h @@ -0,0 +1,14 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// publish the interface +#include "fem/public.h" + + +// end of file diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/fem/FunctionSpace.h similarity index 100% rename from lib/mito/discretization/FunctionSpace.h rename to lib/mito/discretization/fem/FunctionSpace.h diff --git a/lib/mito/discretization/IsoparametricTriangle.h b/lib/mito/discretization/fem/IsoparametricTriangle.h similarity index 100% rename from lib/mito/discretization/IsoparametricTriangle.h rename to lib/mito/discretization/fem/IsoparametricTriangle.h diff --git a/lib/mito/discretization/IsoparametricTriangleP1.h b/lib/mito/discretization/fem/IsoparametricTriangleP1.h similarity index 100% rename from lib/mito/discretization/IsoparametricTriangleP1.h rename to lib/mito/discretization/fem/IsoparametricTriangleP1.h diff --git a/lib/mito/discretization/IsoparametricTriangleP2.h b/lib/mito/discretization/fem/IsoparametricTriangleP2.h similarity index 100% rename from lib/mito/discretization/IsoparametricTriangleP2.h rename to lib/mito/discretization/fem/IsoparametricTriangleP2.h diff --git a/lib/mito/discretization/ReferenceTriangle.h b/lib/mito/discretization/fem/ReferenceTriangle.h similarity index 100% rename from lib/mito/discretization/ReferenceTriangle.h rename to lib/mito/discretization/fem/ReferenceTriangle.h diff --git a/lib/mito/discretization/ShapeTriangleP1.h b/lib/mito/discretization/fem/ShapeTriangleP1.h similarity index 100% rename from lib/mito/discretization/ShapeTriangleP1.h rename to lib/mito/discretization/fem/ShapeTriangleP1.h diff --git a/lib/mito/discretization/ShapeTriangleP2.h b/lib/mito/discretization/fem/ShapeTriangleP2.h similarity index 100% rename from lib/mito/discretization/ShapeTriangleP2.h rename to lib/mito/discretization/fem/ShapeTriangleP2.h diff --git a/lib/mito/discretization/isoparametric_simplex_library.h b/lib/mito/discretization/fem/isoparametric_simplex_library.h similarity index 100% rename from lib/mito/discretization/isoparametric_simplex_library.h rename to lib/mito/discretization/fem/isoparametric_simplex_library.h diff --git a/lib/mito/discretization/utilities.h b/lib/mito/discretization/fem/utilities.h similarity index 100% rename from lib/mito/discretization/utilities.h rename to lib/mito/discretization/fem/utilities.h diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 4a3cc9687..ad6d05f61 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -9,17 +9,10 @@ namespace mito::discretization { - // class discretization node - class DiscretizationNode; - // class discrete field template class DiscreteField; - // class function space - template - class FunctionSpace; - // class discrete system template class DiscreteSystem; diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index c1badc803..fae5a7502 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -17,19 +17,14 @@ #include "api.h" // classes implementation -#include "ReferenceTriangle.h" -#include "ShapeTriangleP1.h" -#include "ShapeTriangleP2.h" #include "DiscreteField.h" #include "DiscretizationNode.h" -#include "isoparametric_simplex_library.h" -#include "FunctionSpace.h" #include "DiscreteSystem.h" +// finite elements implementation +#include "fem.h" + // factories implementation #include "factories.h" -// utilities implementation -#include "utilities.h" - // end of file From 6a28518b36659c5e503a6e5c42cd396e2a930ae6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 18:44:48 +0200 Subject: [PATCH 112/273] discretization: improve structure of {fem} directory --- lib/mito/discretization/fem/api.h | 26 ++++++++++++++++ lib/mito/discretization/fem/externals.h | 10 ++++++ lib/mito/discretization/fem/factories.h | 27 ++++++++++++++++ lib/mito/discretization/fem/forward.h | 21 +++++++++++++ .../fem/isoparametric_simplex_library.h | 5 ++- lib/mito/discretization/fem/public.h | 31 +++++++++++++++++++ .../fem/{ => tri1}/IsoparametricTriangleP1.h | 0 .../fem/{ => tri1}/ShapeTriangleP1.h | 0 lib/mito/discretization/fem/tri1/public.h | 15 +++++++++ .../fem/{ => tri2}/IsoparametricTriangleP2.h | 0 .../fem/{ => tri2}/ShapeTriangleP2.h | 0 lib/mito/discretization/fem/tri2/public.h | 15 +++++++++ 12 files changed, 147 insertions(+), 3 deletions(-) create mode 100644 lib/mito/discretization/fem/api.h create mode 100644 lib/mito/discretization/fem/externals.h create mode 100644 lib/mito/discretization/fem/factories.h create mode 100644 lib/mito/discretization/fem/forward.h create mode 100644 lib/mito/discretization/fem/public.h rename lib/mito/discretization/fem/{ => tri1}/IsoparametricTriangleP1.h (100%) rename lib/mito/discretization/fem/{ => tri1}/ShapeTriangleP1.h (100%) create mode 100644 lib/mito/discretization/fem/tri1/public.h rename lib/mito/discretization/fem/{ => tri2}/IsoparametricTriangleP2.h (100%) rename lib/mito/discretization/fem/{ => tri2}/ShapeTriangleP2.h (100%) create mode 100644 lib/mito/discretization/fem/tri2/public.h diff --git a/lib/mito/discretization/fem/api.h b/lib/mito/discretization/fem/api.h new file mode 100644 index 000000000..c5e5dd260 --- /dev/null +++ b/lib/mito/discretization/fem/api.h @@ -0,0 +1,26 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + // discretization node alias + using discretization_node_t = utilities::std_shared_ptr; + + // function space alias + template + using function_space_t = FunctionSpace; + + // function space factory + template + constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); + +} + + +// end of file diff --git a/lib/mito/discretization/fem/externals.h b/lib/mito/discretization/fem/externals.h new file mode 100644 index 000000000..bdd89b728 --- /dev/null +++ b/lib/mito/discretization/fem/externals.h @@ -0,0 +1,10 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// end of file diff --git a/lib/mito/discretization/fem/factories.h b/lib/mito/discretization/fem/factories.h new file mode 100644 index 000000000..49d74132d --- /dev/null +++ b/lib/mito/discretization/fem/factories.h @@ -0,0 +1,27 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + // TOFIX: create a constructor that takes no constraints + + // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a + // single constraint + // function space factory + template + constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) + { + // build a function space on the manifold and return it + return function_space_t(manifold, constraints); + } + +} + + +// end of file diff --git a/lib/mito/discretization/fem/forward.h b/lib/mito/discretization/fem/forward.h new file mode 100644 index 000000000..d7fce7bcd --- /dev/null +++ b/lib/mito/discretization/fem/forward.h @@ -0,0 +1,21 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization { + + // class discretization node + class DiscretizationNode; + + // class function space + template + class FunctionSpace; +} + + +// end of file diff --git a/lib/mito/discretization/fem/isoparametric_simplex_library.h b/lib/mito/discretization/fem/isoparametric_simplex_library.h index 1e9467959..d9a900eb5 100644 --- a/lib/mito/discretization/fem/isoparametric_simplex_library.h +++ b/lib/mito/discretization/fem/isoparametric_simplex_library.h @@ -7,9 +7,8 @@ #pragma once -#include "IsoparametricTriangle.h" -#include "IsoparametricTriangleP1.h" -#include "IsoparametricTriangleP2.h" +#include "tri1/public.h" +#include "tri2/public.h" namespace mito::discretization { diff --git a/lib/mito/discretization/fem/public.h b/lib/mito/discretization/fem/public.h new file mode 100644 index 000000000..5d0aa83a0 --- /dev/null +++ b/lib/mito/discretization/fem/public.h @@ -0,0 +1,31 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// external packages +#include "externals.h" + +// get the forward declarations +#include "forward.h" + +// published types factories; this is the file you are looking for... +#include "api.h" + +// classes implementation +#include "ReferenceTriangle.h" +#include "IsoparametricTriangle.h" +#include "isoparametric_simplex_library.h" +#include "FunctionSpace.h" + +// factories implementation +#include "factories.h" + +// utilities implementation +#include "utilities.h" + +// end of file diff --git a/lib/mito/discretization/fem/IsoparametricTriangleP1.h b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h similarity index 100% rename from lib/mito/discretization/fem/IsoparametricTriangleP1.h rename to lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h diff --git a/lib/mito/discretization/fem/ShapeTriangleP1.h b/lib/mito/discretization/fem/tri1/ShapeTriangleP1.h similarity index 100% rename from lib/mito/discretization/fem/ShapeTriangleP1.h rename to lib/mito/discretization/fem/tri1/ShapeTriangleP1.h diff --git a/lib/mito/discretization/fem/tri1/public.h b/lib/mito/discretization/fem/tri1/public.h new file mode 100644 index 000000000..5c7941d17 --- /dev/null +++ b/lib/mito/discretization/fem/tri1/public.h @@ -0,0 +1,15 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// classes implementation +#include "ShapeTriangleP1.h" +#include "IsoparametricTriangleP1.h" + + +// end of file diff --git a/lib/mito/discretization/fem/IsoparametricTriangleP2.h b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h similarity index 100% rename from lib/mito/discretization/fem/IsoparametricTriangleP2.h rename to lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h diff --git a/lib/mito/discretization/fem/ShapeTriangleP2.h b/lib/mito/discretization/fem/tri2/ShapeTriangleP2.h similarity index 100% rename from lib/mito/discretization/fem/ShapeTriangleP2.h rename to lib/mito/discretization/fem/tri2/ShapeTriangleP2.h diff --git a/lib/mito/discretization/fem/tri2/public.h b/lib/mito/discretization/fem/tri2/public.h new file mode 100644 index 000000000..5354259a8 --- /dev/null +++ b/lib/mito/discretization/fem/tri2/public.h @@ -0,0 +1,15 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// classes implementation +#include "ShapeTriangleP2.h" +#include "IsoparametricTriangleP2.h" + + +// end of file From fc0d959fa2d3b7ce520a793b03eaae660112f9bc Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 5 Jul 2025 19:32:55 +0200 Subject: [PATCH 113/273] tests/discretization: add calculation of the H1 norm to the poisson test --- tests/mito.lib/discretization/poisson.cc | 49 ++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 7b84dffe7..3b49ff83e 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -190,8 +190,8 @@ TEST(Fem, PoissonSquare) // the exact solution nodal field on the mesh auto exact_solution = mito::discretization::nodal_field(mesh, "exact solution"); - auto u_ex = - mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y); + auto u_ex = mito::fields::field( + mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y)); // fill information in nodal field for (auto & [node, value] : exact_solution) { // get the position of {node} @@ -213,7 +213,7 @@ TEST(Fem, PoissonSquare) writer.write(); #endif - // compute the error + // compute the L2 error auto error_L2 = 0.0; // loop on all the cells of the mesh for (const auto & element : function_space.elements()) { @@ -257,7 +257,48 @@ TEST(Fem, PoissonSquare) // check that the l2 error is reasonable EXPECT_TRUE(error_L2 < 0.02); - // TODO: add norm calculation for convergence study + // compute the H1 error + auto error_H1 = 0.0; + // loop on all the cells of the mesh + for (const auto & element : function_space.elements()) { + // get the corresponding cell + const auto & cell = element.geometric_simplex(); + // volume of the cell + auto volume = manifold.volume(cell); + for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + // the barycentric coordinates of the quadrature point + auto xi = quadrature_rule.point(q); + // the coordinates of the quadrature point + auto coord = manifold.parametrization(cell, xi); + // exact solution gradient at {coord} + auto grad_u_exact = mito::fields::gradient(u_ex)(coord); + // assemble the numerical solution gradient at {coord} + auto grad_u_numerical = mito::tensor::vector_t<2>{ 0.0, 0.0 }; + // loop on all the shape functions + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.connectivity()[a]; + // evaluate the a-th shape function gradient at {xi} + auto dphi_a = element.gradient()(xi); + // get the equation number of {node_a} + int eq = equation_map.at(node_a); + if (eq != -1) { + // get the numerical solution gradient at {coord} + grad_u_numerical += u[eq] * dphi_a; + } + }); + // get the error + auto diff = grad_u_exact - grad_u_numerical; + error_H1 += mito::tensor::dot(diff, diff) * quadrature_rule.weight(q) * volume; + } + } + error_H1 = std::sqrt(error_H1); + + // report + channel << "H1 error: " << error_H1 << journal::endl; + + // check that the h1 error is reasonable + EXPECT_TRUE(error_H1 < 0.02); } // end of file From 2eb921d0e9d8d7ed1a14654901527f53f280df05 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 7 Jul 2025 10:03:57 +0200 Subject: [PATCH 114/273] discretization: rename {get_nodes} to {get_discretization_nodes} --- lib/mito/discretization/DiscreteSystem.h | 2 +- lib/mito/discretization/fem/utilities.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 6ec610fda..9e441eaed 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -55,7 +55,7 @@ namespace mito::discretization { // get all the nodes in the function space std::set nodes; - get_nodes(_function_space, nodes); + get_discretization_nodes(_function_space, nodes); channel << "Number of nodes: " << std::size(nodes) << journal::endl; // get the constrained nodes in the function space diff --git a/lib/mito/discretization/fem/utilities.h b/lib/mito/discretization/fem/utilities.h index f002d1ec9..acf30cc79 100644 --- a/lib/mito/discretization/fem/utilities.h +++ b/lib/mito/discretization/fem/utilities.h @@ -11,7 +11,8 @@ namespace mito::discretization { // populate a container with a collection of all nodes in a function space template - inline auto get_nodes(const functionSpaceT & function_space, nodesCollectionT & nodes) -> void + inline auto get_discretization_nodes( + const functionSpaceT & function_space, nodesCollectionT & nodes) -> void { for (const auto & element : function_space.elements()) { for (const auto & node : element.connectivity()) { From 31b1a1f6b617599d13353291c37dbeb658a67cdd Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 7 Jul 2025 10:05:52 +0200 Subject: [PATCH 115/273] discretization: remove unused type alias in class {FunctionSpace} --- lib/mito/discretization/fem/FunctionSpace.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mito/discretization/fem/FunctionSpace.h b/lib/mito/discretization/fem/FunctionSpace.h index 6f1e36370..f9e548434 100644 --- a/lib/mito/discretization/fem/FunctionSpace.h +++ b/lib/mito/discretization/fem/FunctionSpace.h @@ -25,8 +25,6 @@ namespace mito::discretization { using cell_type = typename mesh_type::cell_type; // the mesh node type using mesh_node_type = typename cell_type::node_type; - // the coordinate system type - using coord_system_type = typename manifold_type::coordinate_system_type; // the degree of the finite element static constexpr int degree = p; // typedef for a finite element From 34bc5313f89cf10229544da791ace5666be8472a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 7 Jul 2025 10:33:14 +0200 Subject: [PATCH 116/273] constraints: add class {Constraint}, parent class for {Dirichlet} --- lib/mito/constraints/Constraint.h | 17 +++++++++++++++++ lib/mito/constraints/Dirichlet.h | 2 +- lib/mito/constraints/public.h | 1 + 3 files changed, 19 insertions(+), 1 deletion(-) create mode 100644 lib/mito/constraints/Constraint.h diff --git a/lib/mito/constraints/Constraint.h b/lib/mito/constraints/Constraint.h new file mode 100644 index 000000000..2d062d469 --- /dev/null +++ b/lib/mito/constraints/Constraint.h @@ -0,0 +1,17 @@ + +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + + +// code guard +#pragma once + + +namespace mito::constraints { + + // class Constraint + class Constraint {}; + +} // namespace mito::constraints \ No newline at end of file diff --git a/lib/mito/constraints/Dirichlet.h b/lib/mito/constraints/Dirichlet.h index 7feb05a34..d328b61e9 100644 --- a/lib/mito/constraints/Dirichlet.h +++ b/lib/mito/constraints/Dirichlet.h @@ -13,7 +13,7 @@ namespace mito::constraints { // class Dirichlet boundary condition template - class Dirichlet { + class Dirichlet : Constraint { // types public: using domain_type = meshT; diff --git a/lib/mito/constraints/public.h b/lib/mito/constraints/public.h index 880fc3fe8..c351b0b41 100644 --- a/lib/mito/constraints/public.h +++ b/lib/mito/constraints/public.h @@ -17,6 +17,7 @@ #include "api.h" // classes implementation +#include "Constraint.h" #include "Dirichlet.h" // factories implementation From 35bbe99419beb58679debe5dda77f91ef428a0c4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 14 Jul 2025 15:46:40 +0200 Subject: [PATCH 117/273] discretization: fix typos in comments --- lib/mito/discretization/fem/IsoparametricTriangle.h | 2 +- .../discretization/shape_functions_triangle_p1.cc | 6 +++--- .../discretization/shape_functions_triangle_p2.cc | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/mito/discretization/fem/IsoparametricTriangle.h b/lib/mito/discretization/fem/IsoparametricTriangle.h index 80758d1f7..2f9ef28b9 100644 --- a/lib/mito/discretization/fem/IsoparametricTriangle.h +++ b/lib/mito/discretization/fem/IsoparametricTriangle.h @@ -8,7 +8,7 @@ // DESIGN NOTES -// Class {IsoparametricTriangle} represents a second order simplex equipped parametric coordinates. +// Class {IsoparametricTriangle} represents a second order simplex equipped barycentric coordinates. namespace mito::discretization { diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc index d54fb0296..e8aaedfe9 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc @@ -18,11 +18,11 @@ TEST(Fem, ShapeTriangleP1) // first order shape functions auto element = shape_t(); - // node 0 in barycentric coordinates + // node 0 in parametric coordinates auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; - // node 1 in barycentric coordinates + // node 1 in parametric coordinates auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; - // node 2 in barycentric coordinates + // node 2 in parametric coordinates auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; // the shape function associated with local node {0} diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p2.cc b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc index e57cf7bc4..70449a85d 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_p2.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc @@ -19,17 +19,17 @@ TEST(Fem, ShapeTriangleP2) // second order shape functions auto element = shape_t(); - // node 0 in barycentric coordinates + // node 0 in parametric coordinates auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; - // node 1 in barycentric coordinates + // node 1 in parametric coordinates auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; - // node 2 in barycentric coordinates + // node 2 in parametric coordinates auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; - // node 3 in barycentric coordinates + // node 3 in parametric coordinates auto n3 = parametric_coordinates_t{ 0.5, 0.5 }; - // node 4 in barycentric coordinates + // node 4 in parametric coordinates auto n4 = parametric_coordinates_t{ 0.0, 0.5 }; - // node 5 in barycentric coordinates + // node 5 in parametric coordinates auto n5 = parametric_coordinates_t{ 0.5, 0.0 }; // the shape functions at node 0 From 8915f1c1112c4f6f8ef624b92a15062289f61467 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 21 Jul 2025 11:19:37 +0200 Subject: [PATCH 118/273] discretization: add {degree} static attribute in classes {IsoparametricTriangleP} --- lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h | 2 ++ lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h | 2 ++ 2 files changed, 4 insertions(+) diff --git a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h index 5aa24d404..ef8515398 100644 --- a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h @@ -17,6 +17,8 @@ namespace mito::discretization { class IsoparametricTriangleP1 : public IsoparametricTriangle { public: + // the degree of the finite element + static constexpr int degree = 1; // the type of shape functions using shape_functions_type = ShapeTriangleP1; // the linear shape functions diff --git a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h index 8ee2d9842..04d3ecfa7 100644 --- a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h @@ -17,6 +17,8 @@ namespace mito::discretization { class IsoparametricTriangleP2 : public IsoparametricTriangle { public: + // the degree of the finite element + static constexpr int degree = 2; // the type of shape functions using shape_functions_type = ShapeTriangleP2; // the linear shape functions From f4c8e6611256ddb8ca69ed5b8cd7cf9b9299cddb Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 21 Jul 2025 11:19:51 +0200 Subject: [PATCH 119/273] discretization: add {dim} static attribute in class {IsoparametricTriangle} --- lib/mito/discretization/fem/IsoparametricTriangle.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/mito/discretization/fem/IsoparametricTriangle.h b/lib/mito/discretization/fem/IsoparametricTriangle.h index 2f9ef28b9..727333ed2 100644 --- a/lib/mito/discretization/fem/IsoparametricTriangle.h +++ b/lib/mito/discretization/fem/IsoparametricTriangle.h @@ -15,10 +15,12 @@ namespace mito::discretization { class IsoparametricTriangle : public utilities::Invalidatable { public: + // the dimension of the physical space + static constexpr int dim = 2; // the discretization node type using discretization_node_type = discretization_node_t; // the geometric simplex type - using geometric_simplex_type = geometry::triangle_t<2>; + using geometric_simplex_type = geometry::triangle_t; // type of a point in barycentric coordinates using barycentric_coordinates_type = typename geometric_simplex_type::barycentric_coordinates_type; From 4f3b9194bd0314c8ed0a421a41fa3782d3640e50 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 21 Jul 2025 11:21:01 +0200 Subject: [PATCH 120/273] discretization: class {FunctionSpace} is now template with respect to the element type Class {FunctionSpace} is now template with respect to the element type as opposed to the manifold type. --- lib/mito/discretization/fem/FunctionSpace.h | 31 +++++++++++---------- lib/mito/discretization/fem/api.h | 4 +-- lib/mito/discretization/fem/factories.h | 13 ++++++++- lib/mito/discretization/fem/forward.h | 2 +- 4 files changed, 31 insertions(+), 19 deletions(-) diff --git a/lib/mito/discretization/fem/FunctionSpace.h b/lib/mito/discretization/fem/FunctionSpace.h index f9e548434..6e376e36e 100644 --- a/lib/mito/discretization/fem/FunctionSpace.h +++ b/lib/mito/discretization/fem/FunctionSpace.h @@ -11,26 +11,23 @@ namespace mito::discretization { // Class {FunctionSpace} represents a collection of finite elements of order {p} defined on a // manifold and subjected to a set of constraints. - template + // TOFIX: add concept for element type + template class FunctionSpace { public: - // the manifold type - using manifold_type = manifoldT; // the constraints type using constraints_type = constraintsT; - // the mesh type - using mesh_type = typename manifold_type::mesh_type; - // the cell type - using cell_type = typename mesh_type::cell_type; - // the mesh node type - using mesh_node_type = typename cell_type::node_type; - // the degree of the finite element - static constexpr int degree = p; - // typedef for a finite element - using element_type = typename isoparametric_simplex::type; + // my template parameter, the finite element type + using element_type = elementT; // typedef for a collection of finite elements using elements_type = utilities::segmented_vector_t; + // the degree of the finite element + static constexpr int degree = element_type::degree; + // the dimension of the physical space + static constexpr int dim = element_type::dim; + // assemble the mesh node type + using mesh_node_type = geometry::node_t; // the discretization node type using discretization_node_type = typename element_type::discretization_node_type; // the nodes type @@ -46,8 +43,12 @@ namespace mito::discretization { public: // the constructor - constexpr FunctionSpace( - const manifold_type & manifold, const constraints_type & constraints) : + template + // require compatibility between the manifold cell and the finite element cell + requires(std::is_same_v< + typename manifoldT::mesh_type::cell_type, + typename element_type::geometric_simplex_type>) + constexpr FunctionSpace(const manifoldT & manifold, const constraints_type & constraints) : _elements(100), _constraints(constraints), _node_map() diff --git a/lib/mito/discretization/fem/api.h b/lib/mito/discretization/fem/api.h index c5e5dd260..8ff7c7e34 100644 --- a/lib/mito/discretization/fem/api.h +++ b/lib/mito/discretization/fem/api.h @@ -13,8 +13,8 @@ namespace mito::discretization { using discretization_node_t = utilities::std_shared_ptr; // function space alias - template - using function_space_t = FunctionSpace; + template + using function_space_t = FunctionSpace; // function space factory template diff --git a/lib/mito/discretization/fem/factories.h b/lib/mito/discretization/fem/factories.h index 49d74132d..c2950d35e 100644 --- a/lib/mito/discretization/fem/factories.h +++ b/lib/mito/discretization/fem/factories.h @@ -17,8 +17,19 @@ namespace mito::discretization { template constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) { + // the manifold type + using manifold_type = manifoldT; + // the mesh type + using mesh_type = typename manifold_type::mesh_type; + // the cell type + using cell_type = typename mesh_type::cell_type; + // the degree of the finite element + constexpr int degree = p; + // typedef for a finite element + using element_type = typename isoparametric_simplex::type; + // build a function space on the manifold and return it - return function_space_t(manifold, constraints); + return function_space_t(manifold, constraints); } } diff --git a/lib/mito/discretization/fem/forward.h b/lib/mito/discretization/fem/forward.h index d7fce7bcd..be5d69b4a 100644 --- a/lib/mito/discretization/fem/forward.h +++ b/lib/mito/discretization/fem/forward.h @@ -13,7 +13,7 @@ namespace mito::discretization { class DiscretizationNode; // class function space - template + template class FunctionSpace; } From acea217227e0133b8993b3e06227496b249eea82 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 21 Jul 2025 14:46:16 +0200 Subject: [PATCH 121/273] discretization: factor out grad-grad and rhs elementary blocks calculation --- tests/mito.lib/discretization/poisson.cc | 191 +++++++++++++++-------- 1 file changed, 126 insertions(+), 65 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 3b49ff83e..276d3bbb2 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -29,6 +29,92 @@ constexpr auto x = mito::functions::component; constexpr auto y = mito::functions::component; +auto +fem_grad_grad_block(const auto & element, const auto & quadrature_rule) -> auto +{ + // the number of nodes per element + constexpr int n_nodes = mito::utilities::base_type::n_nodes; + + // the number of quadrature points per element + constexpr int n_quads = mito::utilities::base_type::npoints; + + // a mito matrix type for the elementary matrix + using matrix_type = mito::tensor::matrix_t; + matrix_type elementary_grad_grad; + + // loop on the quadrature points + for (int q = 0; q < n_quads; ++q) { + + // the barycentric coordinates of the quadrature point + /*constexpr*/ auto xi = quadrature_rule.point(q); + + // precompute the common factor + auto factor = quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); + + // loop on the nodes of the element + mito::tensor::constexpr_for_1([&]() { + // evaluate the spatial gradient of the element's a-th shape function at {xi} + auto dphi_a = element.template gradient()(xi); + // loop on the nodes of the element + mito::tensor::constexpr_for_1([&]() { + // evaluate the spatial gradient of the element's b-th shape + // function at {xi} + auto dphi_b = element.template gradient()(xi); + // populate the elementary contribution to the matrix + elementary_grad_grad[{ a, b }] += factor * dphi_a * dphi_b; + }); + }); + } + + // all done + return elementary_grad_grad; +} + +auto +fem_rhs_block( + const auto & element, const auto & quadrature_rule, const auto & function, + const auto & manifold /*TOFIX: do we really need the manifold?*/) -> auto +{ + // the number of nodes per element + constexpr int n_nodes = mito::utilities::base_type::n_nodes; + + // the number of quadrature points per element + constexpr int n_quads = mito::utilities::base_type::npoints; + + // a mito vector type for the elementary rhs + using vector_type = mito::tensor::vector_t; + vector_type elementary_rhs; + + // loop on the quadrature points + for (int q = 0; q < n_quads; ++q) { + + // the barycentric coordinates of the quadrature point + /*constexpr*/ auto xi = quadrature_rule.point(q); + + // QUESTION: is accessing the geometric simplex really needed? + // get the corresponding cell + const auto & cell = element.geometric_simplex(); + + // the coordinates of the quadrature point + auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); + + // precompute the common factor + auto factor = quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); + + // loop on the nodes of the element + mito::tensor::constexpr_for_1([&]() { + // evaluate the a-th shape function at {xi} + auto phi_a = element.template shape()(xi); + // populate the elementary contribution to the rhs + elementary_rhs[{ a }] += factor * function(coord) * phi_a; + }); + } + + // all done + return elementary_rhs; +} + + TEST(Fem, PoissonSquare) { // make a channel @@ -83,73 +169,48 @@ TEST(Fem, PoissonSquare) // loop on all the cells of the mesh for (const auto & element : function_space.elements()) { - // QUESTION: is accessing the geometric simplex really needed? - // get the corresponding cell - const auto & cell = element.geometric_simplex(); - - // loop on the quadrature points - for (int q = 0; q < quadrature_rule_t::npoints; ++q) { - - // the barycentric coordinates of the quadrature point - /*constexpr*/ auto xi = quadrature_rule.point(q); - - // precompute the common factor - auto factor = quadrature_rule.weight(q) * manifold.volume(cell); - - // populate the linear system of equations - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // evaluate the spatial gradient of the element's a-th shape function at {xi} - auto dphi_a = element.gradient()(xi); - // get the equation number of {node_a} - int eq_a = equation_map.at(node_a); - assert(eq_a < N_equations); - if (eq_a != -1) { - mito::tensor::constexpr_for_1([&]() { - // get the b-th discretization node of the element - const auto & node_b = element.connectivity()[b]; - // evaluate the spatial gradient of the element's b-th shape - // function at {xi} - auto dphi_b = element.gradient()(xi); - // get the equation number of {node_b} - int eq_b = equation_map.at(node_b); - assert(eq_b < N_equations); - // compute the entry of the stiffness matrix - auto entry = 0.0; - // non boundary nodes - if (eq_b != -1) { - entry = factor * dphi_a * dphi_b; - } + // assemble the elementary stiffness matrix + auto elementary_stiffness_matrix = fem_grad_grad_block(element, quadrature_rule); + + // populate the linear system of equations + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.connectivity()[a]; + // get the equation number of {node_a} + int eq_a = equation_map.at(node_a); + assert(eq_a < N_equations); + if (eq_a != -1) { + mito::tensor::constexpr_for_1([&]() { + // get the b-th discretization node of the element + const auto & node_b = element.connectivity()[b]; + // get the equation number of {node_b} + int eq_b = equation_map.at(node_b); + assert(eq_b < N_equations); + // non boundary nodes + if (eq_b != -1) { // assemble the value in the stiffness matrix - solver.add_matrix_value(eq_a, eq_b, entry); - }); - } - }); - - // the coordinates of the quadrature point - auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); - - // populate the right hand side - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // evaluate the a-th shape function at {xi} - auto phi_a = element.shape()(xi); - - // get the equation number of {node_a} - int eq_a = equation_map.at(node_a); - assert(eq_a < N_equations); - // compute the entry of the right hand side - auto entry = 0.0; - // non boundary nodes - if (eq_a != -1) { - entry = factor * f(coord) * phi_a; - } + solver.add_matrix_value(eq_a, eq_b, elementary_stiffness_matrix[{ a, b }]); + } + }); + } + }); + + // assemble the elementary right hand side + auto elementary_rhs = fem_rhs_block(element, quadrature_rule, f, manifold); + + // populate the right hand side + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.connectivity()[a]; + // get the equation number of {node_a} + int eq_a = equation_map.at(node_a); + assert(eq_a < N_equations); + // non boundary nodes + if (eq_a != -1) { // assemble the value in the right hand side - solver.add_rhs_value(eq_a, entry); - }); - } + solver.add_rhs_value(eq_a, elementary_rhs[{ a }]); + } + }); } solver.solve(); From a5432fae5e98d47e6d91cca7082b79e83eb99515 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 21 Jul 2025 14:46:45 +0200 Subject: [PATCH 122/273] discretization: {constexpr} loop on quadrature points for block assembly --- tests/mito.lib/discretization/poisson.cc | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 276d3bbb2..5de520ddb 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -43,10 +43,9 @@ fem_grad_grad_block(const auto & element, const auto & quadrature_rule) -> auto matrix_type elementary_grad_grad; // loop on the quadrature points - for (int q = 0; q < n_quads; ++q) { - + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - /*constexpr*/ auto xi = quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); // precompute the common factor auto factor = quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); @@ -64,7 +63,7 @@ fem_grad_grad_block(const auto & element, const auto & quadrature_rule) -> auto elementary_grad_grad[{ a, b }] += factor * dphi_a * dphi_b; }); }); - } + }); // all done return elementary_grad_grad; @@ -86,10 +85,9 @@ fem_rhs_block( vector_type elementary_rhs; // loop on the quadrature points - for (int q = 0; q < n_quads; ++q) { - + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - /*constexpr*/ auto xi = quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); // QUESTION: is accessing the geometric simplex really needed? // get the corresponding cell @@ -108,7 +106,7 @@ fem_rhs_block( // populate the elementary contribution to the rhs elementary_rhs[{ a }] += factor * function(coord) * phi_a; }); - } + }); // all done return elementary_rhs; From 5dee0596c62c8f9dfc91e9bb79e1860d10a9f731 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 21 Jul 2025 16:41:59 +0200 Subject: [PATCH 123/273] discretization: narrative edit --- tests/mito.lib/discretization/poisson.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 5de520ddb..497a9c988 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -56,8 +56,7 @@ fem_grad_grad_block(const auto & element, const auto & quadrature_rule) -> auto auto dphi_a = element.template gradient()(xi); // loop on the nodes of the element mito::tensor::constexpr_for_1([&]() { - // evaluate the spatial gradient of the element's b-th shape - // function at {xi} + // evaluate the spatial gradient of the element's b-th shape function at {xi} auto dphi_b = element.template gradient()(xi); // populate the elementary contribution to the matrix elementary_grad_grad[{ a, b }] += factor * dphi_a * dphi_b; From f93548b109ff99e75fc2f69bc5c03ab3904072b0 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 22 Jul 2025 10:11:42 +0200 Subject: [PATCH 124/273] discretization: draft implementation of assembly blocks --- lib/mito/discretization/blocks.h | 14 +++ lib/mito/discretization/blocks/MatrixBlock.h | 110 +++++++++++++++++++ lib/mito/discretization/blocks/VectorBlock.h | 97 ++++++++++++++++ lib/mito/discretization/blocks/api.h | 30 +++++ lib/mito/discretization/blocks/externals.h | 18 +++ lib/mito/discretization/blocks/factories.h | 31 ++++++ lib/mito/discretization/blocks/forward.h | 22 ++++ lib/mito/discretization/blocks/public.h | 26 +++++ lib/mito/discretization/public.h | 3 + tests/mito.lib/discretization/poisson.cc | 104 +++--------------- 10 files changed, 367 insertions(+), 88 deletions(-) create mode 100644 lib/mito/discretization/blocks.h create mode 100644 lib/mito/discretization/blocks/MatrixBlock.h create mode 100644 lib/mito/discretization/blocks/VectorBlock.h create mode 100644 lib/mito/discretization/blocks/api.h create mode 100644 lib/mito/discretization/blocks/externals.h create mode 100644 lib/mito/discretization/blocks/factories.h create mode 100644 lib/mito/discretization/blocks/forward.h create mode 100644 lib/mito/discretization/blocks/public.h diff --git a/lib/mito/discretization/blocks.h b/lib/mito/discretization/blocks.h new file mode 100644 index 000000000..213fd9643 --- /dev/null +++ b/lib/mito/discretization/blocks.h @@ -0,0 +1,14 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// publish the interface +#include "blocks/public.h" + + +// end of file diff --git a/lib/mito/discretization/blocks/MatrixBlock.h b/lib/mito/discretization/blocks/MatrixBlock.h new file mode 100644 index 000000000..2da61ed8c --- /dev/null +++ b/lib/mito/discretization/blocks/MatrixBlock.h @@ -0,0 +1,110 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + // TODO: unify vector and matrix block and allow distinction through a template parameter + + // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in + // the same elementary type) + + template + class MatrixBlock { + + public: + // my template parameters + using manifold_type = manifoldT; + using quadrature_rule_type = quadratureRuleT; + + // instantiate the quadrature rule + static constexpr auto quadrature_rule = quadrature_rule_type(); + + public: + // the constructor + constexpr MatrixBlock(const manifold_type & manifold) : _manifold(manifold) {} + + // destructor + constexpr ~MatrixBlock() = default; + + // delete move constructor + constexpr MatrixBlock(MatrixBlock &&) noexcept = delete; + + // delete copy constructor + constexpr MatrixBlock(const MatrixBlock &) = delete; + + // delete assignment operator + constexpr MatrixBlock & operator=(const MatrixBlock &) = delete; + + // delete move assignment operator + constexpr MatrixBlock & operator=(MatrixBlock &&) noexcept = delete; + + public: + // TODO: this represents a matrix block because here the return type is a matrix. How shall + // we make it general to a vector? Shall we have two classes: one MatrixBlock and one + // VectorBlock? + + // TODO: for now this represents a grad-grad block but we should generalize it to represent + // any block + + // compute the elementary contribution of this block + template + auto compute(const elementT & element) const -> tensor::matrix_t + { + // the number of nodes per element + constexpr int n_nodes = elementT::n_nodes; + + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_type::npoints; + + // a mito matrix type for the elementary matrix + using matrix_type = tensor::matrix_t; + matrix_type elementary_matrix; + + // get the corresponding cell + const auto & cell = element.geometric_simplex(); + + // compute the volume of the cell + auto volume = _manifold.volume(cell); + + // loop on the quadrature points + tensor::constexpr_for_1([&]() { + // the barycentric coordinates of the quadrature point + constexpr auto xi = quadrature_rule.point(q); + + // precompute the common factor + auto factor = quadrature_rule.weight(q) * volume; + + // loop on the nodes of the element + tensor::constexpr_for_1([&]() { + // evaluate the spatial gradient of the element's a-th shape function at {xi} + auto dphi_a = element.template gradient()(xi); + // loop on the nodes of the element + tensor::constexpr_for_1([&]() { + // evaluate the spatial gradient of the element's b-th shape function at + // {xi} + auto dphi_b = element.template gradient()(xi); + // populate the elementary contribution to the matrix + elementary_matrix[{ a, b }] += factor * dphi_a * dphi_b; + }); + }); + }); + + // all done + return elementary_matrix; + } + + private: + // the manifold + const manifold_type & _manifold; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/blocks/VectorBlock.h b/lib/mito/discretization/blocks/VectorBlock.h new file mode 100644 index 000000000..5b7299e05 --- /dev/null +++ b/lib/mito/discretization/blocks/VectorBlock.h @@ -0,0 +1,97 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + template + class VectorBlock { + + public: + // my template parameters + using manifold_type = manifoldT; + using quadrature_rule_type = quadratureRuleT; + + // instantiate the quadrature rule + static constexpr auto quadrature_rule = quadrature_rule_type(); + + public: + // the constructor + constexpr VectorBlock(const manifold_type & manifold) : _manifold(manifold) {} + + // destructor + constexpr ~VectorBlock() = default; + + // delete move constructor + constexpr VectorBlock(VectorBlock &&) noexcept = delete; + + // delete copy constructor + constexpr VectorBlock(const VectorBlock &) = delete; + + // delete assignment operator + constexpr VectorBlock & operator=(const VectorBlock &) = delete; + + // delete move assignment operator + constexpr VectorBlock & operator=(VectorBlock &&) noexcept = delete; + + public: + // TOFIX: fix {f} dependency + // compute the elementary contribution of this block + template + auto compute(const elementT & element, const auto & function) const + -> tensor::vector_t + { + // the number of nodes per element + constexpr int n_nodes = elementT::n_nodes; + + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_type::npoints; + + // a mito vector type for the elementary rhs + using vector_type = tensor::vector_t; + vector_type elementary_rhs; + + // get the corresponding cell + const auto & cell = element.geometric_simplex(); + + // compute the volume of the cell + auto volume = _manifold.volume(cell); + + // loop on the quadrature points + tensor::constexpr_for_1([&]() { + // the barycentric coordinates of the quadrature point + constexpr auto xi = quadrature_rule.point(q); + + // the coordinates of the quadrature point + auto coord = _manifold.parametrization(cell, quadrature_rule.point(q)); + + // precompute the common factor + auto factor = quadrature_rule.weight(q) * volume; + + // loop on the nodes of the element + tensor::constexpr_for_1([&]() { + // evaluate the a-th shape function at {xi} + auto phi_a = element.template shape()(xi); + // populate the elementary contribution to the rhs + elementary_rhs[{ a }] += factor * function(coord) * phi_a; + }); + }); + + // all done + return elementary_rhs; + } + + private: + // the manifold + const manifold_type & _manifold; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/blocks/api.h b/lib/mito/discretization/blocks/api.h new file mode 100644 index 000000000..4424192b8 --- /dev/null +++ b/lib/mito/discretization/blocks/api.h @@ -0,0 +1,30 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + // matrix block + template + using matrix_block_t = MatrixBlock; + + // matrix block factory + template + constexpr auto matrix_block(const manifoldT & manifold); + + // vector block + template + using vector_block_t = VectorBlock; + + // vector block factory + template + constexpr auto vector_block(const manifoldT & manifold); +} + + +// end of file diff --git a/lib/mito/discretization/blocks/externals.h b/lib/mito/discretization/blocks/externals.h new file mode 100644 index 000000000..d3746bcb8 --- /dev/null +++ b/lib/mito/discretization/blocks/externals.h @@ -0,0 +1,18 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// externals + +// support +#include "../../tensor.h" +#include "../../manifolds.h" +#include "../../quadrature.h" + + +// end of file diff --git a/lib/mito/discretization/blocks/factories.h b/lib/mito/discretization/blocks/factories.h new file mode 100644 index 000000000..e2f774fd8 --- /dev/null +++ b/lib/mito/discretization/blocks/factories.h @@ -0,0 +1,31 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + // matrix block factory + template + constexpr auto matrix_block(const manifoldT & manifold) + { + // all done + return matrix_block_t(manifold); + } + + // rhs block factory + template + constexpr auto vector_block(const manifoldT & manifold) + { + // all done + return vector_block_t(manifold); + } + +} + + +// end of file diff --git a/lib/mito/discretization/blocks/forward.h b/lib/mito/discretization/blocks/forward.h new file mode 100644 index 000000000..4c5faee46 --- /dev/null +++ b/lib/mito/discretization/blocks/forward.h @@ -0,0 +1,22 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + // matrix block + template + class MatrixBlock; + + // rhs block + template + class VectorBlock; +} + + +// end of file diff --git a/lib/mito/discretization/blocks/public.h b/lib/mito/discretization/blocks/public.h new file mode 100644 index 000000000..69244bfd6 --- /dev/null +++ b/lib/mito/discretization/blocks/public.h @@ -0,0 +1,26 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// external packages +#include "externals.h" + +// get the forward declarations +#include "forward.h" + +// published types factories; this is the file you are looking for... +#include "api.h" + +// classes implementation +#include "MatrixBlock.h" +#include "VectorBlock.h" + +// factories implementation +#include "factories.h" + +// end of file diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index fae5a7502..f1f25148a 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -24,6 +24,9 @@ // finite elements implementation #include "fem.h" +// blocks implementation +#include "blocks.h" + // factories implementation #include "factories.h" diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 497a9c988..38aefddc0 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -20,98 +20,12 @@ using quadrature_rule_t = mito::quadrature::quadrature_rule_t; -// instantiate the quadrature rule -constexpr auto quadrature_rule = quadrature_rule_t(); - // the function extracting the x component of a 2D vector constexpr auto x = mito::functions::component; // the function extracting the y component of a 2D vector constexpr auto y = mito::functions::component; -auto -fem_grad_grad_block(const auto & element, const auto & quadrature_rule) -> auto -{ - // the number of nodes per element - constexpr int n_nodes = mito::utilities::base_type::n_nodes; - - // the number of quadrature points per element - constexpr int n_quads = mito::utilities::base_type::npoints; - - // a mito matrix type for the elementary matrix - using matrix_type = mito::tensor::matrix_t; - matrix_type elementary_grad_grad; - - // loop on the quadrature points - mito::tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point - constexpr auto xi = quadrature_rule.point(q); - - // precompute the common factor - auto factor = quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); - - // loop on the nodes of the element - mito::tensor::constexpr_for_1([&]() { - // evaluate the spatial gradient of the element's a-th shape function at {xi} - auto dphi_a = element.template gradient()(xi); - // loop on the nodes of the element - mito::tensor::constexpr_for_1([&]() { - // evaluate the spatial gradient of the element's b-th shape function at {xi} - auto dphi_b = element.template gradient()(xi); - // populate the elementary contribution to the matrix - elementary_grad_grad[{ a, b }] += factor * dphi_a * dphi_b; - }); - }); - }); - - // all done - return elementary_grad_grad; -} - -auto -fem_rhs_block( - const auto & element, const auto & quadrature_rule, const auto & function, - const auto & manifold /*TOFIX: do we really need the manifold?*/) -> auto -{ - // the number of nodes per element - constexpr int n_nodes = mito::utilities::base_type::n_nodes; - - // the number of quadrature points per element - constexpr int n_quads = mito::utilities::base_type::npoints; - - // a mito vector type for the elementary rhs - using vector_type = mito::tensor::vector_t; - vector_type elementary_rhs; - - // loop on the quadrature points - mito::tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point - constexpr auto xi = quadrature_rule.point(q); - - // QUESTION: is accessing the geometric simplex really needed? - // get the corresponding cell - const auto & cell = element.geometric_simplex(); - - // the coordinates of the quadrature point - auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); - - // precompute the common factor - auto factor = quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); - - // loop on the nodes of the element - mito::tensor::constexpr_for_1([&]() { - // evaluate the a-th shape function at {xi} - auto phi_a = element.template shape()(xi); - // populate the elementary contribution to the rhs - elementary_rhs[{ a }] += factor * function(coord) * phi_a; - }); - }); - - // all done - return elementary_rhs; -} - - TEST(Fem, PoissonSquare) { // make a channel @@ -149,6 +63,17 @@ TEST(Fem, PoissonSquare) const auto & equation_map = discrete_system.equation_map(); int N_equations = discrete_system.n_equations(); + // TODO: blocks should be signed up with the discrete system. Then the loop on the elements + // should be handled by the system + + // QUESTION: perhaps add the possibility to have a label for the blocks + // a grad-grad matrix block + auto fem_grad_grad_block = + mito::discretization::blocks::matrix_block(manifold); + + // a rhs block + auto fem_rhs_block = mito::discretization::blocks::vector_block(manifold); + // create a linear system of equations (PETSc Krylov solver) auto solver = mito::solvers::petsc::ksp("mysolver"); solver.initialize(N_equations); @@ -167,7 +92,7 @@ TEST(Fem, PoissonSquare) for (const auto & element : function_space.elements()) { // assemble the elementary stiffness matrix - auto elementary_stiffness_matrix = fem_grad_grad_block(element, quadrature_rule); + auto elementary_stiffness_matrix = fem_grad_grad_block.compute(element); // populate the linear system of equations mito::tensor::constexpr_for_1([&]() { @@ -193,7 +118,7 @@ TEST(Fem, PoissonSquare) }); // assemble the elementary right hand side - auto elementary_rhs = fem_rhs_block(element, quadrature_rule, f, manifold); + auto elementary_rhs = fem_rhs_block.compute(element, f); // populate the right hand side mito::tensor::constexpr_for_1([&]() { @@ -271,6 +196,9 @@ TEST(Fem, PoissonSquare) writer.write(); #endif + // instantiate the quadrature rule + auto quadrature_rule = quadrature_rule_t(); + // compute the L2 error auto error_L2 = 0.0; // loop on all the cells of the mesh From 958de4e833cc668750e3350c6d939cb3d5d967e5 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 22 Jul 2025 10:58:28 +0200 Subject: [PATCH 125/273] discretization: add method {parametrization} to classes {IsoparametricTriangleP} --- .../fem/tri1/IsoparametricTriangleP1.h | 35 ++++++++++--- .../fem/tri2/IsoparametricTriangleP2.h | 49 +++++++++++++------ 2 files changed, 61 insertions(+), 23 deletions(-) diff --git a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h index ef8515398..3501a961d 100644 --- a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h @@ -52,6 +52,19 @@ namespace mito::discretization { // delete move assignment operator inline IsoparametricTriangleP1 & operator=(IsoparametricTriangleP1 &&) noexcept = delete; + private: + // the isoparametric mapping from barycentric coordinates to physical coordinates + inline auto _x_cell() const + { + // get the shape functions + auto phi_0 = shape_functions.shape<0>(); + auto phi_1 = shape_functions.shape<1>(); + auto phi_2 = shape_functions.shape<2>(); + + // return the isoparametric mapping from barycentric to physical coordinates + return _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; + } + public: // get the discretization nodes inline auto connectivity() const noexcept -> const connectivity_type & @@ -59,6 +72,19 @@ namespace mito::discretization { return _connectivity; } + // get the isoparametric mapping from barycentric coordinates to physical coordinates + inline auto parametrization() const + { + // assemble the physical coordinates from the barycentric coordinates + auto x_cell = [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { + // compute the gradient of the isoparametric mapping + return _x_cell()({ xi[0], xi[1] }); + }; + + // and return it + return x_cell; + } + // get the shape function associated with local node {a} template requires(a >= 0 && a < n_nodes) @@ -81,15 +107,8 @@ namespace mito::discretization { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { - // get the shape functions - auto phi_0 = shape_functions.shape<0>(); - auto phi_1 = shape_functions.shape<1>(); - auto phi_2 = shape_functions.shape<2>(); - // assemble the isoparametric mapping from the barycentric coordinates to the actual - // coordinates on the cell {cell} - auto x_cell = _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; // compute the gradient of the isoparametric mapping - return fields::gradient(x_cell)({ xi[0], xi[1] }); + return fields::gradient(_x_cell())({ xi[0], xi[1] }); }; // and return it diff --git a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h index 04d3ecfa7..d78ab44fb 100644 --- a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h @@ -52,6 +52,26 @@ namespace mito::discretization { // delete move assignment operator inline IsoparametricTriangleP2 & operator=(IsoparametricTriangleP2 &&) noexcept = delete; + private: + // the isoparametric mapping from barycentric coordinates to physical coordinates + inline auto _x_cell() const + { + auto x3 = 0.5 * (_x0 + _x1); + auto x4 = 0.5 * (_x1 + _x2); + auto x5 = 0.5 * (_x2 + _x0); + + // get the shape functions + auto phi_0 = shape_functions.shape<0>(); + auto phi_1 = shape_functions.shape<1>(); + auto phi_2 = shape_functions.shape<2>(); + auto phi_3 = shape_functions.shape<3>(); + auto phi_4 = shape_functions.shape<4>(); + auto phi_5 = shape_functions.shape<5>(); + + // return the isoparametric mapping from barycentric to physical coordinates + return _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; + } + public: // get the discretization nodes inline auto connectivity() const noexcept -> const connectivity_type & @@ -59,6 +79,19 @@ namespace mito::discretization { return _connectivity; } + // get the isoparametric mapping from barycentric coordinates to physical coordinates + inline auto parametrization() const + { + // assemble the physical coordinates from the barycentric coordinates + auto x_cell = [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { + // compute the gradient of the isoparametric mapping + return _x_cell()({ xi[0], xi[1] }); + }; + + // and return it + return x_cell; + } + // get the shape function associated with local node {a} template requires(a >= 0 && a < n_nodes) @@ -81,22 +114,8 @@ namespace mito::discretization { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { - auto x3 = 0.5 * (_x0 + _x1); - auto x4 = 0.5 * (_x1 + _x2); - auto x5 = 0.5 * (_x2 + _x0); - // get the shape functions - auto phi_0 = shape_functions.shape<0>(); - auto phi_1 = shape_functions.shape<1>(); - auto phi_2 = shape_functions.shape<2>(); - auto phi_3 = shape_functions.shape<3>(); - auto phi_4 = shape_functions.shape<4>(); - auto phi_5 = shape_functions.shape<5>(); - // assemble the isoparametric mapping from the barycentric coordinates to the actual - // coordinates on the cell {cell} - auto x_cell = - _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; // compute the gradient of the isoparametric mapping - return fields::gradient(x_cell)({ xi[0], xi[1] }); + return fields::gradient(_x_cell())({ xi[0], xi[1] }); }; // and return it From 473abc8c0812dd2fdf6fc909e0a53c5bb84f1aad Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 22 Jul 2025 11:03:28 +0200 Subject: [PATCH 126/273] discretization: remove dependency on manifold from blocks implementation --- lib/mito/discretization/blocks/MatrixBlock.h | 20 +++++--------------- lib/mito/discretization/blocks/VectorBlock.h | 20 +++++--------------- lib/mito/discretization/blocks/api.h | 16 ++++++++-------- lib/mito/discretization/blocks/factories.h | 12 ++++++------ lib/mito/discretization/blocks/forward.h | 4 ++-- tests/mito.lib/discretization/poisson.cc | 5 ++--- 6 files changed, 28 insertions(+), 49 deletions(-) diff --git a/lib/mito/discretization/blocks/MatrixBlock.h b/lib/mito/discretization/blocks/MatrixBlock.h index 2da61ed8c..24fad4437 100644 --- a/lib/mito/discretization/blocks/MatrixBlock.h +++ b/lib/mito/discretization/blocks/MatrixBlock.h @@ -14,12 +14,11 @@ namespace mito::discretization::blocks { // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in // the same elementary type) - template + template class MatrixBlock { public: - // my template parameters - using manifold_type = manifoldT; + // my template parameter using quadrature_rule_type = quadratureRuleT; // instantiate the quadrature rule @@ -27,7 +26,7 @@ namespace mito::discretization::blocks { public: // the constructor - constexpr MatrixBlock(const manifold_type & manifold) : _manifold(manifold) {} + constexpr MatrixBlock() {} // destructor constexpr ~MatrixBlock() = default; @@ -66,19 +65,14 @@ namespace mito::discretization::blocks { using matrix_type = tensor::matrix_t; matrix_type elementary_matrix; - // get the corresponding cell - const auto & cell = element.geometric_simplex(); - - // compute the volume of the cell - auto volume = _manifold.volume(cell); - // loop on the quadrature points tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); // precompute the common factor - auto factor = quadrature_rule.weight(q) * volume; + auto factor = + quadrature_rule.weight(q) * tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { @@ -98,10 +92,6 @@ namespace mito::discretization::blocks { // all done return elementary_matrix; } - - private: - // the manifold - const manifold_type & _manifold; }; } // namespace mito diff --git a/lib/mito/discretization/blocks/VectorBlock.h b/lib/mito/discretization/blocks/VectorBlock.h index 5b7299e05..0cab1714b 100644 --- a/lib/mito/discretization/blocks/VectorBlock.h +++ b/lib/mito/discretization/blocks/VectorBlock.h @@ -9,12 +9,11 @@ namespace mito::discretization::blocks { - template + template class VectorBlock { public: // my template parameters - using manifold_type = manifoldT; using quadrature_rule_type = quadratureRuleT; // instantiate the quadrature rule @@ -22,7 +21,7 @@ namespace mito::discretization::blocks { public: // the constructor - constexpr VectorBlock(const manifold_type & manifold) : _manifold(manifold) {} + constexpr VectorBlock() {} // destructor constexpr ~VectorBlock() = default; @@ -56,22 +55,17 @@ namespace mito::discretization::blocks { using vector_type = tensor::vector_t; vector_type elementary_rhs; - // get the corresponding cell - const auto & cell = element.geometric_simplex(); - - // compute the volume of the cell - auto volume = _manifold.volume(cell); - // loop on the quadrature points tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point - auto coord = _manifold.parametrization(cell, quadrature_rule.point(q)); + auto coord = element.parametrization()(quadrature_rule.point(q)); // precompute the common factor - auto factor = quadrature_rule.weight(q) * volume; + auto factor = + quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { @@ -85,10 +79,6 @@ namespace mito::discretization::blocks { // all done return elementary_rhs; } - - private: - // the manifold - const manifold_type & _manifold; }; } // namespace mito diff --git a/lib/mito/discretization/blocks/api.h b/lib/mito/discretization/blocks/api.h index 4424192b8..52d598e1a 100644 --- a/lib/mito/discretization/blocks/api.h +++ b/lib/mito/discretization/blocks/api.h @@ -10,20 +10,20 @@ namespace mito::discretization::blocks { // matrix block - template - using matrix_block_t = MatrixBlock; + template + using matrix_block_t = MatrixBlock; // matrix block factory - template - constexpr auto matrix_block(const manifoldT & manifold); + template + constexpr auto matrix_block(); // vector block - template - using vector_block_t = VectorBlock; + template + using vector_block_t = VectorBlock; // vector block factory - template - constexpr auto vector_block(const manifoldT & manifold); + template + constexpr auto vector_block(); } diff --git a/lib/mito/discretization/blocks/factories.h b/lib/mito/discretization/blocks/factories.h index e2f774fd8..d173ba2fc 100644 --- a/lib/mito/discretization/blocks/factories.h +++ b/lib/mito/discretization/blocks/factories.h @@ -10,19 +10,19 @@ namespace mito::discretization::blocks { // matrix block factory - template - constexpr auto matrix_block(const manifoldT & manifold) + template + constexpr auto matrix_block() { // all done - return matrix_block_t(manifold); + return matrix_block_t(); } // rhs block factory - template - constexpr auto vector_block(const manifoldT & manifold) + template + constexpr auto vector_block() { // all done - return vector_block_t(manifold); + return vector_block_t(); } } diff --git a/lib/mito/discretization/blocks/forward.h b/lib/mito/discretization/blocks/forward.h index 4c5faee46..a72700a21 100644 --- a/lib/mito/discretization/blocks/forward.h +++ b/lib/mito/discretization/blocks/forward.h @@ -10,11 +10,11 @@ namespace mito::discretization::blocks { // matrix block - template + template class MatrixBlock; // rhs block - template + template class VectorBlock; } diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 38aefddc0..e34a866fb 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -68,11 +68,10 @@ TEST(Fem, PoissonSquare) // QUESTION: perhaps add the possibility to have a label for the blocks // a grad-grad matrix block - auto fem_grad_grad_block = - mito::discretization::blocks::matrix_block(manifold); + auto fem_grad_grad_block = mito::discretization::blocks::matrix_block(); // a rhs block - auto fem_rhs_block = mito::discretization::blocks::vector_block(manifold); + auto fem_rhs_block = mito::discretization::blocks::vector_block(); // create a linear system of equations (PETSc Krylov solver) auto solver = mito::solvers::petsc::ksp("mysolver"); From b529769395d57445d878f29e737505558e8df7a4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Jul 2025 11:11:06 +0200 Subject: [PATCH 127/273] discretization: source term of poisson's problem is now a {field} (not a {function}) --- tests/mito.lib/discretization/poisson.cc | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index e34a866fb..2c8fe9422 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -79,8 +79,9 @@ TEST(Fem, PoissonSquare) solver.set_options("-ksp_type preonly -pc_type cholesky"); // the right hand side - auto f = 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) - * mito::functions::sin(std::numbers::pi * y); + auto f = mito::fields::field( + 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) + * mito::functions::sin(std::numbers::pi * y)); // channel << "Right hand side: " << f(coordinates_t{ 0.5, 0.5 }) << journal::endl; // the number of nodes per element From a9fd207869d08c52066d2e62b57a553d2c9b05ed Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Jul 2025 12:00:43 +0200 Subject: [PATCH 128/273] discretization: refactoring of assembly blocks Now both grad-grad block and source term block derive from the same parent class {AssemblyBlock}. --- .../discretization/blocks/AssemblyBlock.h | 55 ++++++++++++ .../blocks/{MatrixBlock.h => GradGradBlock.h} | 58 ++++--------- .../discretization/blocks/SourceTermBlock.h | 79 +++++++++++++++++ lib/mito/discretization/blocks/VectorBlock.h | 87 ------------------- lib/mito/discretization/blocks/api.h | 24 ++--- lib/mito/discretization/blocks/factories.h | 14 +-- lib/mito/discretization/blocks/forward.h | 16 ++-- lib/mito/discretization/blocks/public.h | 5 +- tests/mito.lib/discretization/poisson.cc | 25 ++++-- 9 files changed, 199 insertions(+), 164 deletions(-) create mode 100644 lib/mito/discretization/blocks/AssemblyBlock.h rename lib/mito/discretization/blocks/{MatrixBlock.h => GradGradBlock.h} (51%) create mode 100644 lib/mito/discretization/blocks/SourceTermBlock.h delete mode 100644 lib/mito/discretization/blocks/VectorBlock.h diff --git a/lib/mito/discretization/blocks/AssemblyBlock.h b/lib/mito/discretization/blocks/AssemblyBlock.h new file mode 100644 index 000000000..82138f597 --- /dev/null +++ b/lib/mito/discretization/blocks/AssemblyBlock.h @@ -0,0 +1,55 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in + // the same elementary type) + + template + class AssemblyBlock { + + public: + // my template parameters + using element_type = elementT; + using elementary_block_type = blockT; + using quadrature_rule_type = quadratureRuleT; + + public: + // instantiate the quadrature rule + static constexpr auto quadrature_rule = quadrature_rule_type(); + + public: + // the constructor + constexpr AssemblyBlock() {} + + // destructor + constexpr ~AssemblyBlock() = default; + + // delete move constructor + constexpr AssemblyBlock(AssemblyBlock &&) noexcept = delete; + + // delete copy constructor + constexpr AssemblyBlock(const AssemblyBlock &) = delete; + + // delete assignment operator + constexpr AssemblyBlock & operator=(const AssemblyBlock &) = delete; + + // delete move assignment operator + constexpr AssemblyBlock & operator=(AssemblyBlock &&) noexcept = delete; + + public: + // compute the elementary contribution of this block + virtual auto compute(const element_type & element) const -> elementary_block_type = 0; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/blocks/MatrixBlock.h b/lib/mito/discretization/blocks/GradGradBlock.h similarity index 51% rename from lib/mito/discretization/blocks/MatrixBlock.h rename to lib/mito/discretization/blocks/GradGradBlock.h index 24fad4437..d03a3d040 100644 --- a/lib/mito/discretization/blocks/MatrixBlock.h +++ b/lib/mito/discretization/blocks/GradGradBlock.h @@ -14,65 +14,41 @@ namespace mito::discretization::blocks { // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in // the same elementary type) - template - class MatrixBlock { + template + class GradGradBlock : + public AssemblyBlock, quadratureRuleT> { public: - // my template parameter - using quadrature_rule_type = quadratureRuleT; + // my parent class + using parent_type = + AssemblyBlock, quadratureRuleT>; - // instantiate the quadrature rule - static constexpr auto quadrature_rule = quadrature_rule_type(); + // my template parameters + using element_type = typename parent_type::element_type; + using elementary_block_type = typename parent_type::elementary_block_type; + using quadrature_rule_type = typename parent_type::quadrature_rule_type; public: - // the constructor - constexpr MatrixBlock() {} - - // destructor - constexpr ~MatrixBlock() = default; - - // delete move constructor - constexpr MatrixBlock(MatrixBlock &&) noexcept = delete; - - // delete copy constructor - constexpr MatrixBlock(const MatrixBlock &) = delete; - - // delete assignment operator - constexpr MatrixBlock & operator=(const MatrixBlock &) = delete; - - // delete move assignment operator - constexpr MatrixBlock & operator=(MatrixBlock &&) noexcept = delete; - - public: - // TODO: this represents a matrix block because here the return type is a matrix. How shall - // we make it general to a vector? Shall we have two classes: one MatrixBlock and one - // VectorBlock? - - // TODO: for now this represents a grad-grad block but we should generalize it to represent - // any block - // compute the elementary contribution of this block - template - auto compute(const elementT & element) const -> tensor::matrix_t + auto compute(const element_type & element) const -> elementary_block_type override { // the number of nodes per element - constexpr int n_nodes = elementT::n_nodes; + constexpr int n_nodes = element_type::n_nodes; // the number of quadrature points per element constexpr int n_quads = quadrature_rule_type::npoints; - // a mito matrix type for the elementary matrix - using matrix_type = tensor::matrix_t; - matrix_type elementary_matrix; + // the elementary matrix + elementary_block_type elementary_matrix; // loop on the quadrature points tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - constexpr auto xi = quadrature_rule.point(q); + constexpr auto xi = parent_type::quadrature_rule.point(q); // precompute the common factor - auto factor = - quadrature_rule.weight(q) * tensor::determinant(element.jacobian()(xi)); + auto factor = parent_type::quadrature_rule.weight(q) + * tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { diff --git a/lib/mito/discretization/blocks/SourceTermBlock.h b/lib/mito/discretization/blocks/SourceTermBlock.h new file mode 100644 index 000000000..ed705aa37 --- /dev/null +++ b/lib/mito/discretization/blocks/SourceTermBlock.h @@ -0,0 +1,79 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + template + class SourceTermBlock : + public AssemblyBlock, quadratureRuleT> { + + public: + // my parent class + using parent_type = + AssemblyBlock, quadratureRuleT>; + + // my template parameters + using element_type = typename parent_type::element_type; + using elementary_block_type = typename parent_type::elementary_block_type; + using quadrature_rule_type = typename parent_type::quadrature_rule_type; + + // the type of the source term function + using source_field_type = sourceFieldT; + + public: + // constructor + SourceTermBlock(const source_field_type & source_field) : _source_field(source_field) {} + + public: + // compute the elementary contribution of this block + auto compute(const element_type & element) const -> elementary_block_type override + { + // the number of nodes per element + constexpr int n_nodes = element_type::n_nodes; + + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_type::npoints; + + // the elementary rhs + elementary_block_type elementary_rhs; + + // loop on the quadrature points + tensor::constexpr_for_1([&]() { + // the barycentric coordinates of the quadrature point + constexpr auto xi = parent_type::quadrature_rule.point(q); + + // the coordinates of the quadrature point + auto coord = element.parametrization()(parent_type::quadrature_rule.point(q)); + + // precompute the common factor + auto factor = parent_type::quadrature_rule.weight(q) + * mito::tensor::determinant(element.jacobian()(xi)); + + // loop on the nodes of the element + tensor::constexpr_for_1([&]() { + // evaluate the a-th shape function at {xi} + auto phi_a = element.template shape()(xi); + // populate the elementary contribution to the rhs + elementary_rhs[{ a }] += factor * _source_field(coord) * phi_a; + }); + }); + + // all done + return elementary_rhs; + } + + private: + // the source term field + const source_field_type & _source_field; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/blocks/VectorBlock.h b/lib/mito/discretization/blocks/VectorBlock.h deleted file mode 100644 index 0cab1714b..000000000 --- a/lib/mito/discretization/blocks/VectorBlock.h +++ /dev/null @@ -1,87 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - -// code guard -#pragma once - - -namespace mito::discretization::blocks { - - template - class VectorBlock { - - public: - // my template parameters - using quadrature_rule_type = quadratureRuleT; - - // instantiate the quadrature rule - static constexpr auto quadrature_rule = quadrature_rule_type(); - - public: - // the constructor - constexpr VectorBlock() {} - - // destructor - constexpr ~VectorBlock() = default; - - // delete move constructor - constexpr VectorBlock(VectorBlock &&) noexcept = delete; - - // delete copy constructor - constexpr VectorBlock(const VectorBlock &) = delete; - - // delete assignment operator - constexpr VectorBlock & operator=(const VectorBlock &) = delete; - - // delete move assignment operator - constexpr VectorBlock & operator=(VectorBlock &&) noexcept = delete; - - public: - // TOFIX: fix {f} dependency - // compute the elementary contribution of this block - template - auto compute(const elementT & element, const auto & function) const - -> tensor::vector_t - { - // the number of nodes per element - constexpr int n_nodes = elementT::n_nodes; - - // the number of quadrature points per element - constexpr int n_quads = quadrature_rule_type::npoints; - - // a mito vector type for the elementary rhs - using vector_type = tensor::vector_t; - vector_type elementary_rhs; - - // loop on the quadrature points - tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point - constexpr auto xi = quadrature_rule.point(q); - - // the coordinates of the quadrature point - auto coord = element.parametrization()(quadrature_rule.point(q)); - - // precompute the common factor - auto factor = - quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); - - // loop on the nodes of the element - tensor::constexpr_for_1([&]() { - // evaluate the a-th shape function at {xi} - auto phi_a = element.template shape()(xi); - // populate the elementary contribution to the rhs - elementary_rhs[{ a }] += factor * function(coord) * phi_a; - }); - }); - - // all done - return elementary_rhs; - } - }; - -} // namespace mito - - -// end of file diff --git a/lib/mito/discretization/blocks/api.h b/lib/mito/discretization/blocks/api.h index 52d598e1a..7270b254e 100644 --- a/lib/mito/discretization/blocks/api.h +++ b/lib/mito/discretization/blocks/api.h @@ -9,21 +9,21 @@ namespace mito::discretization::blocks { - // matrix block - template - using matrix_block_t = MatrixBlock; + // grad grad block + template + using grad_grad_block_t = GradGradBlock; - // matrix block factory - template - constexpr auto matrix_block(); + // grad grad block factory + template + constexpr auto grad_grad_block(); - // vector block - template - using vector_block_t = VectorBlock; + // source term block + template + using source_term_block_t = SourceTermBlock; - // vector block factory - template - constexpr auto vector_block(); + // source term block factory + template + constexpr auto source_term_block(const sourceFieldT & f); } diff --git a/lib/mito/discretization/blocks/factories.h b/lib/mito/discretization/blocks/factories.h index d173ba2fc..1329daa4f 100644 --- a/lib/mito/discretization/blocks/factories.h +++ b/lib/mito/discretization/blocks/factories.h @@ -10,19 +10,19 @@ namespace mito::discretization::blocks { // matrix block factory - template - constexpr auto matrix_block() + template + constexpr auto grad_grad_block() { // all done - return matrix_block_t(); + return grad_grad_block_t(); } - // rhs block factory - template - constexpr auto vector_block() + // source term block factory + template + constexpr auto source_term_block(const sourceFieldT & f) { // all done - return vector_block_t(); + return source_term_block_t(f); } } diff --git a/lib/mito/discretization/blocks/forward.h b/lib/mito/discretization/blocks/forward.h index a72700a21..66edc19d9 100644 --- a/lib/mito/discretization/blocks/forward.h +++ b/lib/mito/discretization/blocks/forward.h @@ -9,13 +9,17 @@ namespace mito::discretization::blocks { - // matrix block - template - class MatrixBlock; + // assembly block + template + class AssemblyBlock; - // rhs block - template - class VectorBlock; + // grad grad block + template + class GradGradBlock; + + // source term block + template + class SourceTermBlock; } diff --git a/lib/mito/discretization/blocks/public.h b/lib/mito/discretization/blocks/public.h index 69244bfd6..49ab2d34d 100644 --- a/lib/mito/discretization/blocks/public.h +++ b/lib/mito/discretization/blocks/public.h @@ -17,8 +17,9 @@ #include "api.h" // classes implementation -#include "MatrixBlock.h" -#include "VectorBlock.h" +#include "AssemblyBlock.h" +#include "GradGradBlock.h" +#include "SourceTermBlock.h" // factories implementation #include "factories.h" diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 2c8fe9422..6f0d89d9d 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -19,6 +19,11 @@ using simplex_t = cell_t::simplex_type; using quadrature_rule_t = mito::quadrature::quadrature_rule_t; +// the degree of the finite element +constexpr int degree = 2; +// TOFIX: I don't like this syntax +// typedef for a finite element +using finite_element_t = typename mito::discretization::isoparametric_simplex::type; // the function extracting the x component of a 2D vector constexpr auto x = mito::functions::component; @@ -56,6 +61,7 @@ TEST(Fem, PoissonSquare) auto manifold = mito::manifolds::manifold(mesh, coord_system); // the function space (linear elements on the manifold) + // TOFIX: function space should be template with respect to the finite element type auto function_space = mito::discretization::function_space<2>(manifold, constraints); // the discrete system @@ -66,24 +72,25 @@ TEST(Fem, PoissonSquare) // TODO: blocks should be signed up with the discrete system. Then the loop on the elements // should be handled by the system - // QUESTION: perhaps add the possibility to have a label for the blocks - // a grad-grad matrix block - auto fem_grad_grad_block = mito::discretization::blocks::matrix_block(); - - // a rhs block - auto fem_rhs_block = mito::discretization::blocks::vector_block(); - // create a linear system of equations (PETSc Krylov solver) auto solver = mito::solvers::petsc::ksp("mysolver"); solver.initialize(N_equations); solver.set_options("-ksp_type preonly -pc_type cholesky"); + // a grad-grad matrix block + auto fem_lhs_block = + mito::discretization::blocks::grad_grad_block(); + // the right hand side auto f = mito::fields::field( 2.0 * std::numbers::pi * std::numbers::pi * mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y)); // channel << "Right hand side: " << f(coordinates_t{ 0.5, 0.5 }) << journal::endl; + // a source term block + auto fem_rhs_block = + mito::discretization::blocks::source_term_block(f); + // the number of nodes per element constexpr int n_nodes = mito::utilities::base_type::element_type::n_nodes; @@ -92,7 +99,7 @@ TEST(Fem, PoissonSquare) for (const auto & element : function_space.elements()) { // assemble the elementary stiffness matrix - auto elementary_stiffness_matrix = fem_grad_grad_block.compute(element); + auto elementary_stiffness_matrix = fem_lhs_block.compute(element); // populate the linear system of equations mito::tensor::constexpr_for_1([&]() { @@ -118,7 +125,7 @@ TEST(Fem, PoissonSquare) }); // assemble the elementary right hand side - auto elementary_rhs = fem_rhs_block.compute(element, f); + auto elementary_rhs = fem_rhs_block.compute(element); // populate the right hand side mito::tensor::constexpr_for_1([&]() { From 761985416718731bfd787e7837655977cb141dc8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Jul 2025 12:04:24 +0200 Subject: [PATCH 129/273] discretization: narrative edits --- lib/mito/discretization/blocks/GradGradBlock.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/mito/discretization/blocks/GradGradBlock.h b/lib/mito/discretization/blocks/GradGradBlock.h index d03a3d040..bd598a63d 100644 --- a/lib/mito/discretization/blocks/GradGradBlock.h +++ b/lib/mito/discretization/blocks/GradGradBlock.h @@ -9,8 +9,6 @@ namespace mito::discretization::blocks { - // TODO: unify vector and matrix block and allow distinction through a template parameter - // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in // the same elementary type) From 1006caae57439753936866268df14af81fb94364 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Jul 2025 12:24:41 +0200 Subject: [PATCH 130/273] discretization: introduce type alias for isoparametric simplex and simplify finite element typedef in test driver --- lib/mito/discretization/fem/isoparametric_simplex_library.h | 4 ++++ tests/mito.lib/discretization/poisson.cc | 3 +-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/fem/isoparametric_simplex_library.h b/lib/mito/discretization/fem/isoparametric_simplex_library.h index d9a900eb5..ba89ef900 100644 --- a/lib/mito/discretization/fem/isoparametric_simplex_library.h +++ b/lib/mito/discretization/fem/isoparametric_simplex_library.h @@ -29,6 +29,10 @@ namespace mito::discretization { struct isoparametric_simplex<2, geometry::triangle_t<2>> { using type = IsoparametricTriangleP2; }; + + // type alias for convenient access to the isoparametric simplex type + template + using isoparametric_simplex_t = typename isoparametric_simplex::type; } diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 6f0d89d9d..04e059370 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -21,9 +21,8 @@ using quadrature_rule_t = // the degree of the finite element constexpr int degree = 2; -// TOFIX: I don't like this syntax // typedef for a finite element -using finite_element_t = typename mito::discretization::isoparametric_simplex::type; +using finite_element_t = mito::discretization::isoparametric_simplex_t; // the function extracting the x component of a 2D vector constexpr auto x = mito::functions::component; From f29a59b9dea2d402022b3945392a1ecb9704dd81 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 23 Jul 2025 12:27:28 +0200 Subject: [PATCH 131/273] discretization: {constexpr} quadrature points {for} loops in test driver --- tests/mito.lib/discretization/poisson.cc | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 04e059370..27c8dfa1f 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -214,9 +214,9 @@ TEST(Fem, PoissonSquare) // volume of the cell auto volume = manifold.volume(cell); // loop on the quadrature points - for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - /*constexpr*/ auto xi = quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); // get the exact solution at {coord} @@ -239,7 +239,7 @@ TEST(Fem, PoissonSquare) // get the error error_L2 += (u_exact - u_numerical) * (u_exact - u_numerical) * quadrature_rule.weight(q) * volume; - } + }); } error_L2 = std::sqrt(error_L2); @@ -257,7 +257,7 @@ TEST(Fem, PoissonSquare) const auto & cell = element.geometric_simplex(); // volume of the cell auto volume = manifold.volume(cell); - for (int q = 0; q < quadrature_rule_t::npoints; ++q) { + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point @@ -282,7 +282,7 @@ TEST(Fem, PoissonSquare) // get the error auto diff = grad_u_exact - grad_u_numerical; error_H1 += mito::tensor::dot(diff, diff) * quadrature_rule.weight(q) * volume; - } + }); } error_H1 = std::sqrt(error_H1); From ff8820b019bc12557db26c62d0f9bdfe88259e99 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Jul 2025 11:50:23 +0200 Subject: [PATCH 132/273] solvers: major redesign of the {petsc} wrappers Split class {PETScKrylovSolver} into a solver and a linear system class. Also, moved PETSc initialization and finalization outside of these classes. Let's quit fighting PETSc on this. --- .cmake/mito_sources.cmake | 3 +- .cmake/mito_tests_mito_lib.cmake | 5 +- lib/mito/solvers/backend/petsc.h | 14 ++ .../backend/petsc/PETScKrylovSolver.cc | 173 ++---------------- .../solvers/backend/petsc/PETScKrylovSolver.h | 69 ++----- .../backend/petsc/PETScLinearSystem.cc | 146 +++++++++++++++ .../solvers/backend/petsc/PETScLinearSystem.h | 90 +++++++++ ...KrylovSolver.icc => PETScLinearSystem.icc} | 8 +- lib/mito/solvers/backend/petsc/api.h | 3 + lib/mito/solvers/backend/petsc/externals.h | 17 ++ lib/mito/solvers/backend/petsc/factories.h | 11 +- lib/mito/solvers/backend/petsc/forward.h | 3 + lib/mito/solvers/backend/petsc/public.h | 1 + lib/mito/solvers/public.h | 2 +- tests/mito.lib/discretization/poisson.cc | 29 ++- .../solvers/petsc_external_initialize.cc | 31 ---- .../solvers/petsc_initialize_finalize.cc | 21 +++ .../solvers/petsc_internal_initialize.cc | 25 --- ...sc_solve_linear_system.cc => petsc_ksp.cc} | 35 ++-- 19 files changed, 383 insertions(+), 303 deletions(-) create mode 100644 lib/mito/solvers/backend/petsc.h create mode 100644 lib/mito/solvers/backend/petsc/PETScLinearSystem.cc create mode 100644 lib/mito/solvers/backend/petsc/PETScLinearSystem.h rename lib/mito/solvers/backend/petsc/{PETScKrylovSolver.icc => PETScLinearSystem.icc} (78%) delete mode 100644 tests/mito.lib/solvers/petsc_external_initialize.cc create mode 100644 tests/mito.lib/solvers/petsc_initialize_finalize.cc delete mode 100644 tests/mito.lib/solvers/petsc_internal_initialize.cc rename tests/mito.lib/solvers/{petsc_solve_linear_system.cc => petsc_ksp.cc} (58%) diff --git a/.cmake/mito_sources.cmake b/.cmake/mito_sources.cmake index 3095b5fea..63d092c89 100644 --- a/.cmake/mito_sources.cmake +++ b/.cmake/mito_sources.cmake @@ -10,7 +10,8 @@ set(MITO_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/lib/mito/version.cc) # the mito petsc backend if (WITH_PETSC) set(MITO_SOURCES ${MITO_SOURCES} - lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc +lib/mito/solvers/backend/petsc/PETScLinearSystem.cc +lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc ) endif() diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index debab268f..2f80f4d7a 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -71,9 +71,8 @@ endif() # solvers if(WITH_PETSC) - mito_test_driver(tests/mito.lib/solvers/petsc_external_initialize.cc) - mito_test_driver(tests/mito.lib/solvers/petsc_internal_initialize.cc) - mito_test_driver(tests/mito.lib/solvers/petsc_solve_linear_system.cc) + mito_test_driver(tests/mito.lib/solvers/petsc_initialize_finalize.cc) + mito_test_driver(tests/mito.lib/solvers/petsc_ksp.cc) endif() # tensor diff --git a/lib/mito/solvers/backend/petsc.h b/lib/mito/solvers/backend/petsc.h new file mode 100644 index 000000000..f6d8f7ce4 --- /dev/null +++ b/lib/mito/solvers/backend/petsc.h @@ -0,0 +1,14 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// publish the interface +#include "petsc/public.h" + + +// end of file \ No newline at end of file diff --git a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc index 97f385385..708d84d7f 100644 --- a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc +++ b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc @@ -4,120 +4,45 @@ // -#include "public.h" +#include "forward.h" +#include "externals.h" +#include "PETScLinearSystem.h" +#include "PETScKrylovSolver.h" // constructor -mito::solvers::petsc::PETScKrylovSolver::PETScKrylovSolver(const label_type & name) : - _options_prefix(name + "_"), - _initialized_petsc(false) +mito::solvers::petsc::PETScKrylovSolver::PETScKrylovSolver(linear_system_type & linear_system) : + _linear_system(linear_system), + _options_prefix(linear_system.label() + "_") {} // destructor mito::solvers::petsc::PETScKrylovSolver::~PETScKrylovSolver() {} -// initialize PETSc if it has not been initialized before +// create the Krylov solver auto -mito::solvers::petsc::PETScKrylovSolver::_initialize_petsc() -> void +mito::solvers::petsc::PETScKrylovSolver::create() -> void { - // check if PETSc has been initialized - PetscBool petsc_already_initialized; - PetscCallVoid(PetscInitialized(&petsc_already_initialized)); - - // if PETSc has not been initialized before - if (petsc_already_initialized == PETSC_FALSE) { - // initialize PETSc - PetscCallVoid(PetscInitializeNoArguments()); - // and remember that you have initialized PETSc - _initialized_petsc = true; - } - - // all done - return; -} - -// finalize PETSc if it has been initialized by this instance -auto -mito::solvers::petsc::PETScKrylovSolver::_finalize_petsc() -> void -{ - // if PETSc was initialized by this instance - if (_initialized_petsc) { - // finalize PETSc - PetscCallVoid(PetscFinalize()); - } - - // all done - return; -} - -auto -mito::solvers::petsc::PETScKrylovSolver::_create_linear_system(index_type size) -> void -{ - // create the vectors - PetscCallVoid(VecCreate(PETSC_COMM_WORLD, &_solution)); - PetscCallVoid(VecSetSizes(_solution, PETSC_DECIDE, size)); - PetscCallVoid(VecCreate(PETSC_COMM_WORLD, &_rhs)); - PetscCallVoid(VecSetSizes(_rhs, PETSC_DECIDE, size)); - - // create the matrix - PetscCallVoid(MatCreate(PETSC_COMM_WORLD, &_matrix)); - PetscCallVoid(MatSetSizes(_matrix, PETSC_DECIDE, PETSC_DECIDE, size, size)); - // create the Krylov solver PetscCallVoid(KSPCreate(PETSC_COMM_WORLD, &_ksp)); - PetscCallVoid(KSPSetOperators(_ksp, _matrix, _matrix)); + PetscCallVoid(KSPSetOperators(_ksp, _linear_system._matrix, _linear_system._matrix)); PetscCallVoid(KSPSetOptionsPrefix(_ksp, _options_prefix.c_str())); - // set the default options (do not allow the user to control the options for matrix and vectors) - PetscCallVoid(MatSetFromOptions(_matrix)); - PetscCallVoid(VecSetFromOptions(_rhs)); - PetscCallVoid(VecSetFromOptions(_solution)); - // all done return; } +// destroy the Krylov solver auto -mito::solvers::petsc::PETScKrylovSolver::_destroy_linear_system() -> void +mito::solvers::petsc::PETScKrylovSolver::destroy() -> void { - // destroy the matrix, right-hand side, solution, and Krylov solver - PetscCallVoid(MatDestroy(&_matrix)); - PetscCallVoid(VecDestroy(&_solution)); - PetscCallVoid(VecDestroy(&_rhs)); + // destroy the Krylov solver PetscCallVoid(KSPDestroy(&_ksp)); // all done return; } -// initialize the petsc solver -auto -mito::solvers::petsc::PETScKrylovSolver::initialize(index_type size) -> void -{ - // initialize PETSc if it has not been initialized before - _initialize_petsc(); - - // create the matrix, right-hand side, solution, and Krylov solver - _create_linear_system(size); - - // all done - return; -} - -// finalize the petsc solver -auto -mito::solvers::petsc::PETScKrylovSolver::finalize() -> void -{ - // destroy the memory for the matrix, right-hand side, solution, and Krylov solver - _destroy_linear_system(); - - // finalize petsc if it has been initialized by this instance - _finalize_petsc(); - - // all done - return; -} - namespace { // helper function to prepend the prefix {prefix} to each of the space-separated // options leading with '-' @@ -176,71 +101,15 @@ mito::solvers::petsc::PETScKrylovSolver::set_options(const options_type & option return; } -// set the matrix entry at ({row}, {col}) to {value} -auto -mito::solvers::petsc::PETScKrylovSolver::insert_matrix_value( - index_type row, index_type col, const scalar_type & value) -> void -{ - // delegate to PETSc - PetscCallVoid(MatSetValue(_matrix, row, col, value, INSERT_VALUES)); - - // all done - return; -} - -// add {value} to matrix entry at ({row}, {col}) -auto -mito::solvers::petsc::PETScKrylovSolver::add_matrix_value( - index_type row, index_type col, const scalar_type & value) -> void -{ - // delegate to PETSc - PetscCallVoid(MatSetValue(_matrix, row, col, value, ADD_VALUES)); - - // all done - return; -} - -// set the right-hand side entry at {row} to {value} -auto -mito::solvers::petsc::PETScKrylovSolver::insert_rhs_value(index_type row, const scalar_type & value) - -> void -{ - // delegate to PETSc - PetscCallVoid(VecSetValue(_rhs, row, value, INSERT_VALUES)); - - // all done - return; -} - -// add {value} to right-hand side entry at {row} -auto -mito::solvers::petsc::PETScKrylovSolver::add_rhs_value(index_type row, const scalar_type & value) - -> void -{ - // delegate to PETSc - PetscCallVoid(VecSetValue(_rhs, row, value, ADD_VALUES)); - - // all done - return; -} - // solve the linear system auto mito::solvers::petsc::PETScKrylovSolver::solve() -> void { - // assemble matrix - PetscCallVoid(MatAssemblyBegin(_matrix, MAT_FINAL_ASSEMBLY)); - PetscCallVoid(MatAssemblyEnd(_matrix, MAT_FINAL_ASSEMBLY)); - - // // show the matrix and the right-hand-side - // PetscCallVoid(MatView(_matrix, PETSC_VIEWER_STDOUT_WORLD)); - // PetscCallVoid(VecView(_rhs, PETSC_VIEWER_STDOUT_WORLD)); + // assemble the linear system + _linear_system.assemble(); // solve the linear system - PetscCallVoid(KSPSolve(_ksp, _rhs, _solution)); - - // // show the solution - // PetscCallVoid(VecView(_solution, PETSC_VIEWER_STDOUT_WORLD)); + PetscCallVoid(KSPSolve(_ksp, _linear_system._rhs, _linear_system._solution)); // all done return; @@ -248,17 +117,13 @@ mito::solvers::petsc::PETScKrylovSolver::solve() -> void // print the linear system of equations of the petsc solver auto -mito::solvers::petsc::PETScKrylovSolver::print() -> void +mito::solvers::petsc::PETScKrylovSolver::print() const -> void { // create a reporting channel journal::info_t channel("mito.solvers.petsc.PETScKrylovSolver"); - // print the matrix - channel << "Matrix:" << journal::endl; - PetscCallVoid(MatView(_matrix, PETSC_VIEWER_STDOUT_WORLD)); - // print the right-hand side - channel << "Right-hand side:" << journal::endl; - PetscCallVoid(VecView(_rhs, PETSC_VIEWER_STDOUT_WORLD)); + // print the linear system + _linear_system.print(); // all done return; diff --git a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h index 4f5a9e1e6..539e76ecd 100644 --- a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h +++ b/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h @@ -13,82 +13,41 @@ namespace mito::solvers::petsc { private: // the index type using index_type = PetscInt; - // the scalar type - using scalar_type = PetscScalar; - // the vector type - using vector_type = Vec; - // the matrix type - using matrix_type = Mat; + // the linear system type + using linear_system_type = PETScLinearSystem; // the solver type using solver_type = KSP; // the options type using options_type = std::string; - // the label type - using label_type = std::string; public: // constructor - PETScKrylovSolver(const label_type &); + PETScKrylovSolver(linear_system_type &); // destructor ~PETScKrylovSolver(); - private: - // initialize PETSc if it has not been initialized before - auto _initialize_petsc() -> void; - - // finalize PETSc if it has been initialized by this instance - auto _finalize_petsc() -> void; - - // create the matrix, right-hand side, solution, and Krylov solver - auto _create_linear_system(index_type) -> void; - - // destroy the matrix, right-hand side, solution, and Krylov solver - auto _destroy_linear_system() -> void; - public: - // initialize the petsc solver - auto initialize(index_type size) -> void; + // create the Krylov solver + auto create() -> void; - // finalize the petsc solver - auto finalize() -> void; + // destroy the Krylov solver + auto destroy() -> void; // set petsc options auto set_options(const options_type &) -> void; - // set the value of a matrix entry - auto insert_matrix_value(index_type, index_type, const scalar_type &) -> void; - - // add a value to a matrix entry - auto add_matrix_value(index_type, index_type, const scalar_type &) -> void; - - // set the value of a right-hand side entry - auto insert_rhs_value(index_type, const scalar_type &) -> void; - - // add a value to a right-hand side entry - auto add_rhs_value(index_type, const scalar_type &) -> void; - // solve the linear system auto solve() -> void; // print the linear system of equations of the petsc solver - auto print() -> void; - - // get the solution vector - template - auto get_solution(solutionT & solution) const -> void; + auto print() const -> void; private: + // the linear system + linear_system_type & _linear_system; // the prefix for the PETSc options - label_type _options_prefix; - // a flag to recall if this instance has initialized PETSc - bool _initialized_petsc; - // the matrix - matrix_type _matrix; - // the right-hand side vector - vector_type _rhs; - // the solution vector - vector_type _solution; + options_type _options_prefix; // the Krylov solver solver_type _ksp; }; @@ -96,10 +55,4 @@ namespace mito::solvers::petsc { } // namespace mito -// get the template definitions -#define mito_solvers_backend_petsc_PETScKrylovSolver_icc -#include "PETScKrylovSolver.icc" -#undef mito_solvers_backend_petsc_PETScKrylovSolver_icc - - // end of file diff --git a/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc b/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc new file mode 100644 index 000000000..66011792f --- /dev/null +++ b/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc @@ -0,0 +1,146 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + + +#include "forward.h" +#include "externals.h" +#include "PETScLinearSystem.h" + + +// constructor +mito::solvers::petsc::PETScLinearSystem::PETScLinearSystem(const label_type & label) : _label(label) +{} + +// destructor +mito::solvers::petsc::PETScLinearSystem::~PETScLinearSystem() {} + +// allocate memory for the matrix, right-hand side, and solution +auto +mito::solvers::petsc::PETScLinearSystem::create(index_type size) -> void +{ + // create the vectors + PetscCallVoid(VecCreate(PETSC_COMM_WORLD, &_solution)); + PetscCallVoid(VecSetSizes(_solution, PETSC_DECIDE, size)); + PetscCallVoid(VecCreate(PETSC_COMM_WORLD, &_rhs)); + PetscCallVoid(VecSetSizes(_rhs, PETSC_DECIDE, size)); + + // create the matrix + PetscCallVoid(MatCreate(PETSC_COMM_WORLD, &_matrix)); + PetscCallVoid(MatSetSizes(_matrix, PETSC_DECIDE, PETSC_DECIDE, size, size)); + + // set the default options (do not allow the user to control the options for matrix and + // vectors) + PetscCallVoid(MatSetFromOptions(_matrix)); + PetscCallVoid(VecSetFromOptions(_rhs)); + PetscCallVoid(VecSetFromOptions(_solution)); + + // all done + return; +} + +// free memory for the matrix, right-hand side, and solution +auto +mito::solvers::petsc::PETScLinearSystem::destroy() -> void +{ + // destroy the matrix, right-hand side, solution + PetscCallVoid(MatDestroy(&_matrix)); + PetscCallVoid(VecDestroy(&_solution)); + PetscCallVoid(VecDestroy(&_rhs)); + + // all done + return; +} + +// get the label of the linear system +auto +mito::solvers::petsc::PETScLinearSystem::label() const -> label_type +{ + // easy enough + return _label; +} + +// assemble the linear system +auto +mito::solvers::petsc::PETScLinearSystem::assemble() -> void +{ + // assemble matrix + PetscCallVoid(MatAssemblyBegin(_matrix, MAT_FINAL_ASSEMBLY)); + PetscCallVoid(MatAssemblyEnd(_matrix, MAT_FINAL_ASSEMBLY)); + + // // show the matrix and the right-hand-side + // PetscCallVoid(MatView(_matrix, PETSC_VIEWER_STDOUT_WORLD)); + // PetscCallVoid(VecView(_rhs, PETSC_VIEWER_STDOUT_WORLD)); + + // all done + return; +} + +// set the matrix entry at ({row}, {col}) to {value} +auto +mito::solvers::petsc::PETScLinearSystem::insert_matrix_value( + index_type row, index_type col, const scalar_type & value) -> void +{ + // delegate to PETSc + PetscCallVoid(MatSetValue(_matrix, row, col, value, INSERT_VALUES)); + + // all done + return; +} + +// add {value} to matrix entry at ({row}, {col}) +auto +mito::solvers::petsc::PETScLinearSystem::add_matrix_value( + index_type row, index_type col, const scalar_type & value) -> void +{ + // delegate to PETSc + PetscCallVoid(MatSetValue(_matrix, row, col, value, ADD_VALUES)); + + // all done + return; +} + +// set the right-hand side entry at {row} to {value} +auto +mito::solvers::petsc::PETScLinearSystem::insert_rhs_value(index_type row, const scalar_type & value) + -> void +{ + // delegate to PETSc + PetscCallVoid(VecSetValue(_rhs, row, value, INSERT_VALUES)); + + // all done + return; +} + +// add {value} to right-hand side entry at {row} +auto +mito::solvers::petsc::PETScLinearSystem::add_rhs_value(index_type row, const scalar_type & value) + -> void +{ + // delegate to PETSc + PetscCallVoid(VecSetValue(_rhs, row, value, ADD_VALUES)); + + // all done + return; +} + +// print the linear system of equations of the petsc solver +auto +mito::solvers::petsc::PETScLinearSystem::print() const -> void +{ + // create a reporting channel + journal::info_t channel("mito.solvers.petsc.PETScLinearSystem"); + + // print the matrix + channel << "Matrix:" << journal::endl; + PetscCallVoid(MatView(_matrix, PETSC_VIEWER_STDOUT_WORLD)); + // print the right-hand side + channel << "Right-hand side:" << journal::endl; + PetscCallVoid(VecView(_rhs, PETSC_VIEWER_STDOUT_WORLD)); + + // all done + return; +} + +// end of file diff --git a/lib/mito/solvers/backend/petsc/PETScLinearSystem.h b/lib/mito/solvers/backend/petsc/PETScLinearSystem.h new file mode 100644 index 000000000..34284521f --- /dev/null +++ b/lib/mito/solvers/backend/petsc/PETScLinearSystem.h @@ -0,0 +1,90 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::solvers::petsc { + + class PETScLinearSystem { + + // friend declarations + friend class PETScKrylovSolver; + + private: + // the index type + using index_type = PetscInt; + // the scalar type + using scalar_type = PetscScalar; + // the vector type + using vector_type = Vec; + // the matrix type + using matrix_type = Mat; + // the label type + using label_type = std::string; + + public: + // constructor + PETScLinearSystem(const label_type &); + + // destructor + ~PETScLinearSystem(); + + public: + // create the matrix, right-hand side, and solution + auto create(index_type) -> void; + + // destroy the matrix, right-hand side, and solution + auto destroy() -> void; + + // get the label of the linear system + auto label() const -> label_type; + + // assemble the linear system + auto assemble() -> void; + + // set the value of a matrix entry + auto insert_matrix_value(index_type, index_type, const scalar_type &) -> void; + + // add a value to a matrix entry + auto add_matrix_value(index_type, index_type, const scalar_type &) -> void; + + // set the value of a right-hand side entry + auto insert_rhs_value(index_type, const scalar_type &) -> void; + + // add a value to a right-hand side entry + auto add_rhs_value(index_type, const scalar_type &) -> void; + + // get the solution vector + template + auto get_solution(solutionT & solution) const -> void; + + // print the linear system + auto print() const -> void; + + private: + // a flag to recall if this instance has initialized PETSc + bool _initialized_petsc; + // the label for the linear system (this is used to prefix PETSc options) + label_type _label; + // the matrix + matrix_type _matrix; + // the right-hand side vector + vector_type _rhs; + // the solution vector + vector_type _solution; + }; + +} // namespace mito + + +// get the template definitions +#define mito_solvers_backend_petsc_PETScLinearSystem_icc +#include "PETScLinearSystem.icc" +#undef mito_solvers_backend_petsc_PETScLinearSystem_icc + + +// end of file diff --git a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.icc b/lib/mito/solvers/backend/petsc/PETScLinearSystem.icc similarity index 78% rename from lib/mito/solvers/backend/petsc/PETScKrylovSolver.icc rename to lib/mito/solvers/backend/petsc/PETScLinearSystem.icc index 5247c9c49..a6e17b461 100644 --- a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.icc +++ b/lib/mito/solvers/backend/petsc/PETScLinearSystem.icc @@ -4,15 +4,15 @@ // -#if !defined(mito_solvers_backend_petsc_PETScKrylovSolver_icc) -#error This header file contains implementation details of class mito::solvers::petsc::PETScKrylovSolver +#if !defined(mito_solvers_backend_petsc_PETScLinearSystem_icc) +#error This header file contains implementation details of class mito::solvers::petsc::PETScLinearSystem #else // get the solution at entry {row} template auto -mito::solvers::petsc::PETScKrylovSolver::get_solution(solutionT & solution) const -> void +mito::solvers::petsc::PETScLinearSystem::get_solution(solutionT & solution) const -> void { // get a pointer to the beginning of {_solution} const scalar_type * u; @@ -36,6 +36,6 @@ mito::solvers::petsc::PETScKrylovSolver::get_solution(solutionT & solution) cons } -#endif // mito_solvers_backend_petsc_PETScKrylovSolver_icc +#endif // mito_solvers_backend_petsc_PETScLinearSystem_icc // end of file diff --git a/lib/mito/solvers/backend/petsc/api.h b/lib/mito/solvers/backend/petsc/api.h index 3079671e5..086262adf 100644 --- a/lib/mito/solvers/backend/petsc/api.h +++ b/lib/mito/solvers/backend/petsc/api.h @@ -9,6 +9,9 @@ namespace mito::solvers::petsc { + // petsc linear system + using linear_system_t = PETScLinearSystem; + // petsc Krlov solver using ksp_t = PETScKrylovSolver; diff --git a/lib/mito/solvers/backend/petsc/externals.h b/lib/mito/solvers/backend/petsc/externals.h index 2b375f08d..2d5cc5618 100644 --- a/lib/mito/solvers/backend/petsc/externals.h +++ b/lib/mito/solvers/backend/petsc/externals.h @@ -19,4 +19,21 @@ #include +namespace mito::solvers::petsc { + + // initialize petsc + inline auto initialize() -> void + { + PetscCallVoid(PetscInitializeNoArguments()); + } + + // finalize petsc + inline auto finalize() -> void + { + PetscCallVoid(PetscFinalize()); + } + +} + + // end of file diff --git a/lib/mito/solvers/backend/petsc/factories.h b/lib/mito/solvers/backend/petsc/factories.h index 97f16969d..fb5546078 100644 --- a/lib/mito/solvers/backend/petsc/factories.h +++ b/lib/mito/solvers/backend/petsc/factories.h @@ -9,12 +9,17 @@ namespace mito::solvers::petsc { - // petsc ksp solver - auto ksp(const std::string & name) + // petsc linear system + auto linear_system(const std::string & name) { - return ksp_t(name); + return linear_system_t(name); } + // petsc Krylov solver + auto ksp(linear_system_t & linear_system) + { + return ksp_t(linear_system); + } } diff --git a/lib/mito/solvers/backend/petsc/forward.h b/lib/mito/solvers/backend/petsc/forward.h index 1a07ea09c..c3c876e5e 100644 --- a/lib/mito/solvers/backend/petsc/forward.h +++ b/lib/mito/solvers/backend/petsc/forward.h @@ -9,6 +9,9 @@ namespace mito::solvers::petsc { + // class for PETSc linear system + class PETScLinearSystem; + // class for PETSc Krylov solver class PETScKrylovSolver; diff --git a/lib/mito/solvers/backend/petsc/public.h b/lib/mito/solvers/backend/petsc/public.h index b04e2251f..1e19efdc6 100644 --- a/lib/mito/solvers/backend/petsc/public.h +++ b/lib/mito/solvers/backend/petsc/public.h @@ -17,6 +17,7 @@ #include "api.h" // classes +#include "PETScLinearSystem.h" #include "PETScKrylovSolver.h" // factories implementation diff --git a/lib/mito/solvers/public.h b/lib/mito/solvers/public.h index aca9e6a46..13c8ba2fa 100644 --- a/lib/mito/solvers/public.h +++ b/lib/mito/solvers/public.h @@ -8,7 +8,7 @@ #ifdef WITH_PETSC -#include "backend/petsc/public.h" +#include "backend/petsc.h" #endif // WITH_PETSC diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 27c8dfa1f..31ec80f39 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -71,9 +71,14 @@ TEST(Fem, PoissonSquare) // TODO: blocks should be signed up with the discrete system. Then the loop on the elements // should be handled by the system - // create a linear system of equations (PETSc Krylov solver) - auto solver = mito::solvers::petsc::ksp("mysolver"); - solver.initialize(N_equations); + // initialize PETSc + mito::solvers::petsc::initialize(); + + // create a PETSc linear system of equations and a Krylov solver + auto linear_system = mito::solvers::petsc::linear_system("mysystem"); + linear_system.create(N_equations); + auto solver = mito::solvers::petsc::ksp(linear_system); + solver.create(); solver.set_options("-ksp_type preonly -pc_type cholesky"); // a grad-grad matrix block @@ -117,7 +122,8 @@ TEST(Fem, PoissonSquare) // non boundary nodes if (eq_b != -1) { // assemble the value in the stiffness matrix - solver.add_matrix_value(eq_a, eq_b, elementary_stiffness_matrix[{ a, b }]); + linear_system.add_matrix_value( + eq_a, eq_b, elementary_stiffness_matrix[{ a, b }]); } }); } @@ -136,19 +142,17 @@ TEST(Fem, PoissonSquare) // non boundary nodes if (eq_a != -1) { // assemble the value in the right hand side - solver.add_rhs_value(eq_a, elementary_rhs[{ a }]); + linear_system.add_rhs_value(eq_a, elementary_rhs[{ a }]); } }); } solver.solve(); + solver.destroy(); // read the solution auto u = std::vector(N_equations); - solver.get_solution(u); - - // finalize the solver - solver.finalize(); + linear_system.get_solution(u); // TOFIX: the solution should be assembled by the function space, which is aware of the // constraints and can populate the constrained nodes appropriately @@ -291,6 +295,13 @@ TEST(Fem, PoissonSquare) // check that the h1 error is reasonable EXPECT_TRUE(error_H1 < 0.02); + + // destroy the linear system + linear_system.destroy(); + + // TOFIX: move this to the class owning the petsc instance + // finalize PETSc + mito::solvers::petsc::finalize(); } // end of file diff --git a/tests/mito.lib/solvers/petsc_external_initialize.cc b/tests/mito.lib/solvers/petsc_external_initialize.cc deleted file mode 100644 index 31ce390b2..000000000 --- a/tests/mito.lib/solvers/petsc_external_initialize.cc +++ /dev/null @@ -1,31 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - - -#include -#include - - -TEST(Solvers, PETScKSPExternalInitialize) -{ - // initialize PETSc - PetscInitializeNoArguments(); - - // the size of the linear system - int N = 10; - - // instantiate a PETSc Krylov solver for a linear system of size {N} - auto solver = mito::solvers::petsc::ksp("mysolver"); - solver.initialize(N); - - // finalize the solver - solver.finalize(); - - // finalize PETSc - PetscFinalize(); -} - - -// end of file diff --git a/tests/mito.lib/solvers/petsc_initialize_finalize.cc b/tests/mito.lib/solvers/petsc_initialize_finalize.cc new file mode 100644 index 000000000..2f9cdfc09 --- /dev/null +++ b/tests/mito.lib/solvers/petsc_initialize_finalize.cc @@ -0,0 +1,21 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + + +#include +#include + + +TEST(Solvers, PETScInitializeFinalize) +{ + // initialize PETSc + mito::solvers::petsc::initialize(); + + // finalize PETSc + mito::solvers::petsc::finalize(); +} + + +// end of file diff --git a/tests/mito.lib/solvers/petsc_internal_initialize.cc b/tests/mito.lib/solvers/petsc_internal_initialize.cc deleted file mode 100644 index 9930302dd..000000000 --- a/tests/mito.lib/solvers/petsc_internal_initialize.cc +++ /dev/null @@ -1,25 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - - -#include -#include - - -TEST(Solvers, PETScKSPInternalInitialize) -{ - // the size of the linear system - int N = 10; - - // instantiate a PETSc Krylov solver for a linear system of size {N} - auto solver = mito::solvers::petsc::ksp("mysolver"); - solver.initialize(N); - - // finalize the solver - solver.finalize(); -} - - -// end of file diff --git a/tests/mito.lib/solvers/petsc_solve_linear_system.cc b/tests/mito.lib/solvers/petsc_ksp.cc similarity index 58% rename from tests/mito.lib/solvers/petsc_solve_linear_system.cc rename to tests/mito.lib/solvers/petsc_ksp.cc index bbd7a6e05..0eebcd866 100644 --- a/tests/mito.lib/solvers/petsc_solve_linear_system.cc +++ b/tests/mito.lib/solvers/petsc_ksp.cc @@ -13,21 +13,25 @@ TEST(Solvers, PETScKSPSolver) // the size of the linear system int N = 10; - // instantiate a PETSc Krylov solver for a linear system of size {N} - auto solver = mito::solvers::petsc::ksp("mysolver"); - solver.initialize(N); + // instantiate a PETSc linear system of size {N} + auto linear_system = mito::solvers::petsc::linear_system("mysystem"); + linear_system.create(N); + + // instantiate a PETSc Krylov solver for the linear system + auto solver = mito::solvers::petsc::ksp(linear_system); + solver.create(); solver.set_options("-ksp_monitor"); // set matrix and right-hand side entries for (int i = 0; i < N; i++) { - solver.insert_matrix_value(i, i, 2.0); + linear_system.insert_matrix_value(i, i, 2.0); if (i > 0) { - solver.insert_matrix_value(i, i - 1, -1.0); + linear_system.insert_matrix_value(i, i - 1, -1.0); } if (i < N - 1) { - solver.insert_matrix_value(i, i + 1, -1.0); + linear_system.insert_matrix_value(i, i + 1, -1.0); } - solver.insert_rhs_value(i, 1.0); + linear_system.insert_rhs_value(i, 1.0); } // solve the linear system @@ -35,7 +39,7 @@ TEST(Solvers, PETScKSPSolver) // read the solution auto x = std::vector(N); - solver.get_solution(x); + linear_system.get_solution(x); // check the solution EXPECT_DOUBLE_EQ(x[0], 5.0); @@ -49,8 +53,11 @@ TEST(Solvers, PETScKSPSolver) EXPECT_DOUBLE_EQ(x[8], 9.0); EXPECT_DOUBLE_EQ(x[9], 5.0); - // finalize the solver - solver.finalize(); + // destroy the system + linear_system.destroy(); + + // destroy the solver + solver.destroy(); // all done return; @@ -60,14 +67,14 @@ TEST(Solvers, PETScKSPSolver) int main(int argc, char ** argv) { - // initialize petsc - PetscInitialize(&argc, &argv, PETSC_NULLPTR, PETSC_NULLPTR); + // initialize PETSc + mito::solvers::petsc::initialize(); ::testing::InitGoogleTest(&argc, argv); auto result = RUN_ALL_TESTS(); - // finalize petsc - PetscFinalize(); + // finalize PETSc + mito::solvers::petsc::finalize(); // all done return result; From 600e39527b6fed000c75ec7a72d2b40ab9910652 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Jul 2025 18:57:44 +0200 Subject: [PATCH 133/273] discretization: use element parametrization to determine physical coordinates of quadrature points --- tests/mito.lib/discretization/poisson.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 31ec80f39..735a18d8b 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -222,7 +222,7 @@ TEST(Fem, PoissonSquare) // the barycentric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point - auto coord = manifold.parametrization(cell, quadrature_rule.point(q)); + auto coord = element.parametrization()(xi); // get the exact solution at {coord} auto u_exact = u_ex(coord); // assemble the numerical solution at {coord} @@ -265,7 +265,7 @@ TEST(Fem, PoissonSquare) // the barycentric coordinates of the quadrature point auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point - auto coord = manifold.parametrization(cell, xi); + auto coord = element.parametrization()(xi); // exact solution gradient at {coord} auto grad_u_exact = mito::fields::gradient(u_ex)(coord); // assemble the numerical solution gradient at {coord} From c69a7403d569294fe6802225ae7a06e130772ba4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Jul 2025 19:02:39 +0200 Subject: [PATCH 134/273] solvers: add attribute with number of equations to class {PETScLinearSystem} --- .../solvers/backend/petsc/PETScLinearSystem.cc | 14 +++++++++++++- lib/mito/solvers/backend/petsc/PETScLinearSystem.h | 5 +++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc b/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc index 66011792f..11cfb9b4b 100644 --- a/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc +++ b/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc @@ -10,7 +10,9 @@ // constructor -mito::solvers::petsc::PETScLinearSystem::PETScLinearSystem(const label_type & label) : _label(label) +mito::solvers::petsc::PETScLinearSystem::PETScLinearSystem(const label_type & label) : + _label(label), + _n_equations(0) {} // destructor @@ -20,6 +22,9 @@ mito::solvers::petsc::PETScLinearSystem::~PETScLinearSystem() {} auto mito::solvers::petsc::PETScLinearSystem::create(index_type size) -> void { + // take note of the number of equations + _n_equations = size; + // create the vectors PetscCallVoid(VecCreate(PETSC_COMM_WORLD, &_solution)); PetscCallVoid(VecSetSizes(_solution, PETSC_DECIDE, size)); @@ -125,6 +130,13 @@ mito::solvers::petsc::PETScLinearSystem::add_rhs_value(index_type row, const sca return; } +auto +mito::solvers::petsc::PETScLinearSystem::n_equations() const -> int +{ + return _n_equations; +} + + // print the linear system of equations of the petsc solver auto mito::solvers::petsc::PETScLinearSystem::print() const -> void diff --git a/lib/mito/solvers/backend/petsc/PETScLinearSystem.h b/lib/mito/solvers/backend/petsc/PETScLinearSystem.h index 34284521f..444f86cb1 100644 --- a/lib/mito/solvers/backend/petsc/PETScLinearSystem.h +++ b/lib/mito/solvers/backend/petsc/PETScLinearSystem.h @@ -58,6 +58,9 @@ namespace mito::solvers::petsc { // add a value to a right-hand side entry auto add_rhs_value(index_type, const scalar_type &) -> void; + // accessor to the number of equations + auto n_equations() const -> int; + // get the solution vector template auto get_solution(solutionT & solution) const -> void; @@ -76,6 +79,8 @@ namespace mito::solvers::petsc { vector_type _rhs; // the solution vector vector_type _solution; + // the number of equations + int _n_equations; }; } // namespace mito From 0daed987c7ed555121e01b40b6a3ce4ce47fe35b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 24 Jul 2025 19:18:54 +0200 Subject: [PATCH 135/273] discretization: class {AssemblyBlock} is not template any more wrt the type of quadrature rule --- .../discretization/blocks/AssemblyBlock.h | 7 +------ .../discretization/blocks/GradGradBlock.h | 18 +++++++++-------- .../discretization/blocks/SourceTermBlock.h | 20 ++++++++++--------- lib/mito/discretization/blocks/forward.h | 2 +- 4 files changed, 23 insertions(+), 24 deletions(-) diff --git a/lib/mito/discretization/blocks/AssemblyBlock.h b/lib/mito/discretization/blocks/AssemblyBlock.h index 82138f597..3a852a02e 100644 --- a/lib/mito/discretization/blocks/AssemblyBlock.h +++ b/lib/mito/discretization/blocks/AssemblyBlock.h @@ -12,18 +12,13 @@ namespace mito::discretization::blocks { // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in // the same elementary type) - template + template class AssemblyBlock { public: // my template parameters using element_type = elementT; using elementary_block_type = blockT; - using quadrature_rule_type = quadratureRuleT; - - public: - // instantiate the quadrature rule - static constexpr auto quadrature_rule = quadrature_rule_type(); public: // the constructor diff --git a/lib/mito/discretization/blocks/GradGradBlock.h b/lib/mito/discretization/blocks/GradGradBlock.h index bd598a63d..533b2624a 100644 --- a/lib/mito/discretization/blocks/GradGradBlock.h +++ b/lib/mito/discretization/blocks/GradGradBlock.h @@ -13,18 +13,20 @@ namespace mito::discretization::blocks { // the same elementary type) template - class GradGradBlock : - public AssemblyBlock, quadratureRuleT> { + class GradGradBlock : public AssemblyBlock> { public: // my parent class - using parent_type = - AssemblyBlock, quadratureRuleT>; + using parent_type = AssemblyBlock>; // my template parameters using element_type = typename parent_type::element_type; using elementary_block_type = typename parent_type::elementary_block_type; - using quadrature_rule_type = typename parent_type::quadrature_rule_type; + using quadrature_rule_type = quadratureRuleT; + + public: + // instantiate the quadrature rule + static constexpr auto quadrature_rule = quadrature_rule_type(); public: // compute the elementary contribution of this block @@ -42,11 +44,11 @@ namespace mito::discretization::blocks { // loop on the quadrature points tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - constexpr auto xi = parent_type::quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); // precompute the common factor - auto factor = parent_type::quadrature_rule.weight(q) - * tensor::determinant(element.jacobian()(xi)); + auto factor = + quadrature_rule.weight(q) * tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { diff --git a/lib/mito/discretization/blocks/SourceTermBlock.h b/lib/mito/discretization/blocks/SourceTermBlock.h index ed705aa37..4375b2b90 100644 --- a/lib/mito/discretization/blocks/SourceTermBlock.h +++ b/lib/mito/discretization/blocks/SourceTermBlock.h @@ -10,22 +10,24 @@ namespace mito::discretization::blocks { template - class SourceTermBlock : - public AssemblyBlock, quadratureRuleT> { + class SourceTermBlock : public AssemblyBlock> { public: // my parent class - using parent_type = - AssemblyBlock, quadratureRuleT>; + using parent_type = AssemblyBlock>; // my template parameters using element_type = typename parent_type::element_type; using elementary_block_type = typename parent_type::elementary_block_type; - using quadrature_rule_type = typename parent_type::quadrature_rule_type; + using quadrature_rule_type = quadratureRuleT; // the type of the source term function using source_field_type = sourceFieldT; + public: + // instantiate the quadrature rule + static constexpr auto quadrature_rule = quadrature_rule_type(); + public: // constructor SourceTermBlock(const source_field_type & source_field) : _source_field(source_field) {} @@ -46,14 +48,14 @@ namespace mito::discretization::blocks { // loop on the quadrature points tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - constexpr auto xi = parent_type::quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point - auto coord = element.parametrization()(parent_type::quadrature_rule.point(q)); + auto coord = element.parametrization()(quadrature_rule.point(q)); // precompute the common factor - auto factor = parent_type::quadrature_rule.weight(q) - * mito::tensor::determinant(element.jacobian()(xi)); + auto factor = + quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { diff --git a/lib/mito/discretization/blocks/forward.h b/lib/mito/discretization/blocks/forward.h index 66edc19d9..8d0d5da84 100644 --- a/lib/mito/discretization/blocks/forward.h +++ b/lib/mito/discretization/blocks/forward.h @@ -10,7 +10,7 @@ namespace mito::discretization::blocks { // assembly block - template + template class AssemblyBlock; // grad grad block From a2c49168dbd8f47a355bb3f67154505e53a169ce Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 26 Jul 2025 17:37:31 +0200 Subject: [PATCH 136/273] discretization: add {assembly_block_t} alias to api --- lib/mito/discretization/blocks/api.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mito/discretization/blocks/api.h b/lib/mito/discretization/blocks/api.h index 7270b254e..c4683ae1f 100644 --- a/lib/mito/discretization/blocks/api.h +++ b/lib/mito/discretization/blocks/api.h @@ -9,6 +9,10 @@ namespace mito::discretization::blocks { + // assembly block + template + using assembly_block_t = AssemblyBlock; + // grad grad block template using grad_grad_block_t = GradGradBlock; From f5710e6b0f5f5d744863f0e2c9421f06ba05937b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 26 Jul 2025 17:58:07 +0200 Subject: [PATCH 137/273] discretization: add block to compute the L2 norm of a field --- lib/mito/discretization/blocks/L2NormBlock.h | 75 ++++++++++++++++++++ lib/mito/discretization/blocks/api.h | 8 +++ lib/mito/discretization/blocks/factories.h | 8 +++ lib/mito/discretization/blocks/forward.h | 5 ++ lib/mito/discretization/blocks/public.h | 1 + 5 files changed, 97 insertions(+) create mode 100644 lib/mito/discretization/blocks/L2NormBlock.h diff --git a/lib/mito/discretization/blocks/L2NormBlock.h b/lib/mito/discretization/blocks/L2NormBlock.h new file mode 100644 index 000000000..5fc0dc58c --- /dev/null +++ b/lib/mito/discretization/blocks/L2NormBlock.h @@ -0,0 +1,75 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discretization::blocks { + + // TOFIX: the source does not need to be necessarily a scalar field, it can be some other field + template + class L2NormBlock : public AssemblyBlock { + + public: + // my parent class + using parent_type = AssemblyBlock; + + // my template parameters + using element_type = typename parent_type::element_type; + using elementary_block_type = typename parent_type::elementary_block_type; + using quadrature_rule_type = quadratureRuleT; + + // the type of the function to compute the L2 norm of + using field_type = fieldT; + + public: + // instantiate the quadrature rule + static constexpr auto quadrature_rule = quadrature_rule_type(); + + public: + // constructor + L2NormBlock(const field_type & field) : _field(field) {} + + public: + // compute the elementary contribution of this block + auto compute(const element_type & element) const -> elementary_block_type override + { + // the number of nodes per element + constexpr int n_nodes = element_type::n_nodes; + + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_type::npoints; + + // the elementary contribution to the L2 norm + elementary_block_type elementary_contribution; + + // loop on the quadrature points + tensor::constexpr_for_1([&]() { + // the barycentric coordinates of the quadrature point + constexpr auto xi = quadrature_rule.point(q); + + // the coordinates of the quadrature point + auto coord = element.parametrization()(xi); + + // populate the elementary contribution to the matrix + elementary_contribution += quadrature_rule.weight(q) + * tensor::determinant(element.jacobian()(xi)) + * _field(coord); + }); + + // all done + return elementary_contribution; + } + + private: + // the field to compute the L2 norm of + const field_type & _field; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/discretization/blocks/api.h b/lib/mito/discretization/blocks/api.h index c4683ae1f..d004530b9 100644 --- a/lib/mito/discretization/blocks/api.h +++ b/lib/mito/discretization/blocks/api.h @@ -28,6 +28,14 @@ namespace mito::discretization::blocks { // source term block factory template constexpr auto source_term_block(const sourceFieldT & f); + + // L2 norm block + template + using l2_norm_block_t = L2NormBlock; + + // L2 norm block factory + template + constexpr auto l2_norm_block(const fieldT & f); } diff --git a/lib/mito/discretization/blocks/factories.h b/lib/mito/discretization/blocks/factories.h index 1329daa4f..333a5115c 100644 --- a/lib/mito/discretization/blocks/factories.h +++ b/lib/mito/discretization/blocks/factories.h @@ -25,6 +25,14 @@ namespace mito::discretization::blocks { return source_term_block_t(f); } + // L2 norm block factory + template + constexpr auto l2_norm_block(const fieldT & f) + { + // all done + return l2_norm_block_t(f); + } + } diff --git a/lib/mito/discretization/blocks/forward.h b/lib/mito/discretization/blocks/forward.h index 8d0d5da84..fca708d3f 100644 --- a/lib/mito/discretization/blocks/forward.h +++ b/lib/mito/discretization/blocks/forward.h @@ -20,6 +20,11 @@ namespace mito::discretization::blocks { // source term block template class SourceTermBlock; + + // L2 norm block + template + class L2NormBlock; + } diff --git a/lib/mito/discretization/blocks/public.h b/lib/mito/discretization/blocks/public.h index 49ab2d34d..a5ede3d94 100644 --- a/lib/mito/discretization/blocks/public.h +++ b/lib/mito/discretization/blocks/public.h @@ -20,6 +20,7 @@ #include "AssemblyBlock.h" #include "GradGradBlock.h" #include "SourceTermBlock.h" +#include "L2NormBlock.h" // factories implementation #include "factories.h" From 8798d008e3b5bc3055163432be29fc279517230b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 26 Jul 2025 18:00:50 +0200 Subject: [PATCH 138/273] discretization: add an item {TOFIX} --- lib/mito/discretization/blocks/SourceTermBlock.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/mito/discretization/blocks/SourceTermBlock.h b/lib/mito/discretization/blocks/SourceTermBlock.h index 4375b2b90..f1b19cb9a 100644 --- a/lib/mito/discretization/blocks/SourceTermBlock.h +++ b/lib/mito/discretization/blocks/SourceTermBlock.h @@ -9,6 +9,8 @@ namespace mito::discretization::blocks { + // TOFIX: the source does not need to be necessarily a scalar field, it can be some other field + // see if we can use {field_c} instead of {scalar_field_c} template class SourceTermBlock : public AssemblyBlock> { From da304dd719fb6e39bd7f34579592603c44fb155c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 12:38:57 +0200 Subject: [PATCH 139/273] discretization: implement factory function to build a nodal field out of a continuous field --- lib/mito/discretization/DiscreteField.h | 4 ++-- lib/mito/discretization/api.h | 6 ++++++ lib/mito/discretization/factories.h | 21 +++++++++++++++++++++ tests/mito.lib/discretization/poisson.cc | 23 ++++++----------------- 4 files changed, 35 insertions(+), 19 deletions(-) diff --git a/lib/mito/discretization/DiscreteField.h b/lib/mito/discretization/DiscreteField.h index 19286d27c..ffa3d24a8 100644 --- a/lib/mito/discretization/DiscreteField.h +++ b/lib/mito/discretization/DiscreteField.h @@ -42,8 +42,8 @@ namespace mito::discretization { // delete copy constructor DiscreteField(const DiscreteField &) = delete; - // delete move copy constructor - DiscreteField(DiscreteField &&) = delete; + // default move constructor + DiscreteField(DiscreteField &&) = default; // delete copy assignment auto operator=(const DiscreteField &) -> DiscreteField & = delete; diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index e362593d0..8192e113c 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -29,6 +29,12 @@ namespace mito::discretization { template constexpr auto nodal_field(const mesh::mesh_c auto & mesh, std::string name); + // nodal field factory from a continuous field + template + constexpr auto nodal_field( + const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, + const fieldT & field, std::string name); + // point field factory template constexpr auto point_field(const cloudT & cloud, std::string name); diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index c3214b9f3..d06711bd2 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -34,6 +34,27 @@ namespace mito::discretization { return nodal_field_t(nodes, name); } + // nodal field factory from a continuous field + template + constexpr auto nodal_field( + const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, + const fieldT & field, std::string name) + { + // create a nodal field on the mesh + auto n_field = nodal_field(mesh, name); + + // populate the nodal field with the values of the continuous field + for (auto & [node, value] : n_field) { + // get the position of {node} + auto coord = coord_system.coordinates(node->point()); + // evaluate the continuousfield at {coord} + value = field(coord); + } + + // return the nodal field + return n_field; + } + // point field factory template constexpr auto point_field(const cloudT & cloud, std::string name) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 735a18d8b..7c29ccfa1 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -172,26 +172,15 @@ TEST(Fem, PoissonSquare) } // the forcing term nodal field on the mesh - auto forcing = mito::discretization::nodal_field(mesh, "forcing term"); - // fill information in nodal field - for (auto & [node, value] : forcing) { - // get the position of {node} - auto coord = coord_system.coordinates(node->point()); - // evaluate the forcing at {coord} - value = f(coord); - } + auto forcing = mito::discretization::nodal_field(mesh, coord_system, f, "forcing term"); - // the exact solution nodal field on the mesh - auto exact_solution = mito::discretization::nodal_field(mesh, "exact solution"); + // the exact solution field auto u_ex = mito::fields::field( mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y)); - // fill information in nodal field - for (auto & [node, value] : exact_solution) { - // get the position of {node} - auto coord = coord_system.coordinates(node->point()); - // evaluate the forcing at {coord} - value = u_ex(coord); - } + + // the exact solution nodal field on the mesh + auto exact_solution = + mito::discretization::nodal_field(mesh, coord_system, u_ex, "exact solution"); #ifdef WITH_VTK // write mesh to vtk file From d8ab53c3cacd612eca609c069c54b258511205a6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 12:46:37 +0200 Subject: [PATCH 140/273] discretization: readability improvement Nodal fields {forcing} and {exact_solution} are only used for visualization purposes, so only instantiate them if vtk files are written. --- tests/mito.lib/discretization/poisson.cc | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 7c29ccfa1..f08e0410d 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -171,18 +171,16 @@ TEST(Fem, PoissonSquare) } } - // the forcing term nodal field on the mesh - auto forcing = mito::discretization::nodal_field(mesh, coord_system, f, "forcing term"); - // the exact solution field auto u_ex = mito::fields::field( mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y)); - // the exact solution nodal field on the mesh +#ifdef WITH_VTK + // the forcing term nodal field on the mesh (for visualization) + auto forcing = mito::discretization::nodal_field(mesh, coord_system, f, "forcing term"); + // the exact solution nodal field on the mesh (for visualization) auto exact_solution = mito::discretization::nodal_field(mesh, coord_system, u_ex, "exact solution"); - -#ifdef WITH_VTK // write mesh to vtk file auto writer = mito::io::vtk::field_writer("poisson_square", mesh, coord_system); // sign {forcing} up with the writer From f0befcc34707bb970a6cfc3cd22211e602f77604 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 13:00:21 +0200 Subject: [PATCH 141/273] discretization: default empty default constructor of class {AssemblyBlock} --- lib/mito/discretization/blocks/AssemblyBlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/discretization/blocks/AssemblyBlock.h b/lib/mito/discretization/blocks/AssemblyBlock.h index 3a852a02e..637c4ff4f 100644 --- a/lib/mito/discretization/blocks/AssemblyBlock.h +++ b/lib/mito/discretization/blocks/AssemblyBlock.h @@ -22,7 +22,7 @@ namespace mito::discretization::blocks { public: // the constructor - constexpr AssemblyBlock() {} + constexpr AssemblyBlock() = default; // destructor constexpr ~AssemblyBlock() = default; From 152989a8b6a1f3b6e897c02af33638feb2881424 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 13:28:11 +0200 Subject: [PATCH 142/273] discretization: accessors of classes {IsoparametricTriangleP} now return {mito::functions::function} instances to element parametrization and shape functions. --- .../fem/tri1/IsoparametricTriangleP1.h | 44 ++++++++++--------- .../fem/tri2/IsoparametricTriangleP2.h | 44 ++++++++++--------- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h index 3501a961d..818968fbf 100644 --- a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h @@ -76,10 +76,11 @@ namespace mito::discretization { inline auto parametrization() const { // assemble the physical coordinates from the barycentric coordinates - auto x_cell = [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { - // compute the gradient of the isoparametric mapping - return _x_cell()({ xi[0], xi[1] }); - }; + auto x_cell = functions::function( + [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { + // compute the gradient of the isoparametric mapping + return _x_cell()({ xi[0], xi[1] }); + }); // and return it return x_cell; @@ -92,10 +93,11 @@ namespace mito::discretization { { // assemble the shape function associated with local node {a} as a function of // barycentric coordinates - auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { - // return the a-th shape function evaluated at {xi} - return shape_functions.shape()({ xi[0], xi[1] }); - }; + auto shape_function = functions::function( + [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { + // return the a-th shape function evaluated at {xi} + return shape_functions.shape()({ xi[0], xi[1] }); + }); // and return it return shape_function; @@ -105,11 +107,11 @@ namespace mito::discretization { inline auto jacobian() const { // assemble the jacobian as a function of barycentric coordinates - auto jacobian_function = + auto jacobian_function = functions::function( [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { - // compute the gradient of the isoparametric mapping - return fields::gradient(_x_cell())({ xi[0], xi[1] }); - }; + // compute the gradient of the isoparametric mapping + return fields::gradient(_x_cell())({ xi[0], xi[1] }); + }); // and return it return jacobian_function; @@ -121,16 +123,16 @@ namespace mito::discretization { inline auto gradient() const { // assemble the gradient as a function of barycentric coordinates - auto gradient_function = + auto gradient_function = functions::function( [&](const barycentric_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 barycentric coordinates - auto J_inv = tensor::inverse(J); - // return the spatial gradients of the shape functions evaluated at {xi} - return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; - }; + // 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 barycentric coordinates + auto J_inv = tensor::inverse(J); + // return the spatial gradients of the shape functions evaluated at {xi} + return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; + }); // and return it return gradient_function; } diff --git a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h index d78ab44fb..3881b9b92 100644 --- a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h @@ -83,10 +83,11 @@ namespace mito::discretization { inline auto parametrization() const { // assemble the physical coordinates from the barycentric coordinates - auto x_cell = [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { - // compute the gradient of the isoparametric mapping - return _x_cell()({ xi[0], xi[1] }); - }; + auto x_cell = functions::function( + [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { + // compute the gradient of the isoparametric mapping + return _x_cell()({ xi[0], xi[1] }); + }); // and return it return x_cell; @@ -99,10 +100,11 @@ namespace mito::discretization { { // assemble the shape function associated with local node {a} as a function of // barycentric coordinates - auto shape_function = [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { - // return the a-th shape function evaluated at {xi} - return shape_functions.shape()({ xi[0], xi[1] }); - }; + auto shape_function = functions::function( + [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { + // return the a-th shape function evaluated at {xi} + return shape_functions.shape()({ xi[0], xi[1] }); + }); // and return it return shape_function; @@ -112,11 +114,11 @@ namespace mito::discretization { inline auto jacobian() const { // assemble the jacobian as a function of barycentric coordinates - auto jacobian_function = + auto jacobian_function = functions::function( [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { - // compute the gradient of the isoparametric mapping - return fields::gradient(_x_cell())({ xi[0], xi[1] }); - }; + // compute the gradient of the isoparametric mapping + return fields::gradient(_x_cell())({ xi[0], xi[1] }); + }); // and return it return jacobian_function; @@ -128,16 +130,16 @@ namespace mito::discretization { inline auto gradient() const { // assemble the gradient as a function of barycentric coordinates - auto gradient_function = + auto gradient_function = functions::function( [&](const barycentric_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 barycentric coordinates - auto J_inv = tensor::inverse(J); - // return the spatial gradients of the shape functions evaluated at {xi} - return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; - }; + // 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 barycentric coordinates + auto J_inv = tensor::inverse(J); + // return the spatial gradients of the shape functions evaluated at {xi} + return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; + }); // and return it return gradient_function; } From 477d90f6e63a3ebb184b07acd2313f885902aa52 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 13:30:22 +0200 Subject: [PATCH 143/273] discretization: readability improvement in test {poisson} In the error calculation, localize the exact solution by composing it with the element parametrization. --- tests/mito.lib/discretization/poisson.cc | 23 +++++++++++------------ 1 file changed, 11 insertions(+), 12 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index f08e0410d..8cc93a931 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -208,11 +208,9 @@ TEST(Fem, PoissonSquare) mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); - // the coordinates of the quadrature point - auto coord = element.parametrization()(xi); - // get the exact solution at {coord} - auto u_exact = u_ex(coord); - // assemble the numerical solution at {coord} + // composition of the exact solution with the parametrization of the element + auto u_ex_local = u_ex.function()(element.parametrization()); + // assemble the numerical solution at {xi} auto u_numerical = 0.0; // loop on all the shape functions mito::tensor::constexpr_for_1([&]() { @@ -223,12 +221,12 @@ TEST(Fem, PoissonSquare) // get the equation number of {node_a} int eq = equation_map.at(node_a); if (eq != -1) { - // get the numerical solution at {coord} + // get the numerical solution at {xi} u_numerical += u[eq] * phi_a; } }); // get the error - error_L2 += (u_exact - u_numerical) * (u_exact - u_numerical) + error_L2 += (u_ex_local(xi) - u_numerical) * (u_ex_local(xi) - u_numerical) * quadrature_rule.weight(q) * volume; }); } @@ -253,9 +251,10 @@ TEST(Fem, PoissonSquare) auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point auto coord = element.parametrization()(xi); - // exact solution gradient at {coord} - auto grad_u_exact = mito::fields::gradient(u_ex)(coord); - // assemble the numerical solution gradient at {coord} + // composition of the exact solution gradient with the parametrization of the element + auto grad_u_ex_local = + mito::fields::gradient(u_ex).function()(element.parametrization()); + // assemble the numerical solution gradient at {xi} auto grad_u_numerical = mito::tensor::vector_t<2>{ 0.0, 0.0 }; // loop on all the shape functions mito::tensor::constexpr_for_1([&]() { @@ -266,12 +265,12 @@ TEST(Fem, PoissonSquare) // get the equation number of {node_a} int eq = equation_map.at(node_a); if (eq != -1) { - // get the numerical solution gradient at {coord} + // get the numerical solution gradient at {xi} grad_u_numerical += u[eq] * dphi_a; } }); // get the error - auto diff = grad_u_exact - grad_u_numerical; + auto diff = grad_u_ex_local(xi) - grad_u_numerical; error_H1 += mito::tensor::dot(diff, diff) * quadrature_rule.weight(q) * volume; }); } From ec2e3f66efe03198ff38ef43c9c215162b57380a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 13:46:46 +0200 Subject: [PATCH 144/273] discretization: consistency fix in {poisson} test driver --- tests/mito.lib/discretization/poisson.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 8cc93a931..e5c4d104f 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -61,7 +61,7 @@ TEST(Fem, PoissonSquare) // the function space (linear elements on the manifold) // TOFIX: function space should be template with respect to the finite element type - auto function_space = mito::discretization::function_space<2>(manifold, constraints); + auto function_space = mito::discretization::function_space(manifold, constraints); // the discrete system auto discrete_system = mito::discretization::discrete_system(function_space); From 2649239c825b3ac804277c6acdc10c8c31f70006 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 13:55:57 +0200 Subject: [PATCH 145/273] discretization: use element jacobian instead of cell volume in error calculations in {poisson} test driver --- tests/mito.lib/discretization/poisson.cc | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index e5c4d104f..90262128a 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -200,14 +200,12 @@ TEST(Fem, PoissonSquare) auto error_L2 = 0.0; // loop on all the cells of the mesh for (const auto & element : function_space.elements()) { - // get the corresponding cell - const auto & cell = element.geometric_simplex(); - // volume of the cell - auto volume = manifold.volume(cell); // loop on the quadrature points mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); + // jacobian of the element at {xi} + auto jacobian = mito::tensor::determinant(element.jacobian()(xi)); // composition of the exact solution with the parametrization of the element auto u_ex_local = u_ex.function()(element.parametrization()); // assemble the numerical solution at {xi} @@ -227,7 +225,7 @@ TEST(Fem, PoissonSquare) }); // get the error error_L2 += (u_ex_local(xi) - u_numerical) * (u_ex_local(xi) - u_numerical) - * quadrature_rule.weight(q) * volume; + * quadrature_rule.weight(q) * jacobian; }); } error_L2 = std::sqrt(error_L2); @@ -242,15 +240,12 @@ TEST(Fem, PoissonSquare) auto error_H1 = 0.0; // loop on all the cells of the mesh for (const auto & element : function_space.elements()) { - // get the corresponding cell - const auto & cell = element.geometric_simplex(); - // volume of the cell - auto volume = manifold.volume(cell); mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point auto xi = quadrature_rule.point(q); - // the coordinates of the quadrature point - auto coord = element.parametrization()(xi); + // jacobian of the element at {xi} + + auto jacobian = mito::tensor::determinant(element.jacobian()(xi)); // composition of the exact solution gradient with the parametrization of the element auto grad_u_ex_local = mito::fields::gradient(u_ex).function()(element.parametrization()); @@ -271,7 +266,7 @@ TEST(Fem, PoissonSquare) }); // get the error auto diff = grad_u_ex_local(xi) - grad_u_numerical; - error_H1 += mito::tensor::dot(diff, diff) * quadrature_rule.weight(q) * volume; + error_H1 += mito::tensor::dot(diff, diff) * quadrature_rule.weight(q) * jacobian; }); } error_H1 = std::sqrt(error_H1); From 25823cdadac8ae6fbd15f13e7a08106d31313ae0 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 14:06:54 +0200 Subject: [PATCH 146/273] discretization: minor readability improvement in class {SourceTermBlock} --- lib/mito/discretization/blocks/SourceTermBlock.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/discretization/blocks/SourceTermBlock.h b/lib/mito/discretization/blocks/SourceTermBlock.h index f1b19cb9a..7e214b900 100644 --- a/lib/mito/discretization/blocks/SourceTermBlock.h +++ b/lib/mito/discretization/blocks/SourceTermBlock.h @@ -53,7 +53,7 @@ namespace mito::discretization::blocks { constexpr auto xi = quadrature_rule.point(q); // the coordinates of the quadrature point - auto coord = element.parametrization()(quadrature_rule.point(q)); + auto coord = element.parametrization()(xi); // precompute the common factor auto factor = From 9ee7412fc8d7bfd0ed56212562259601bf0f3bb8 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 14:47:07 +0200 Subject: [PATCH 147/273] discretization/blocks: {L2NormBlock} now uses a function of the barycentric coordinates, not a function of physical coordinates --- lib/mito/discretization/blocks/L2NormBlock.h | 22 ++++++++------------ lib/mito/discretization/blocks/api.h | 8 +++---- lib/mito/discretization/blocks/factories.h | 6 +++--- lib/mito/discretization/blocks/forward.h | 8 ++++--- 4 files changed, 21 insertions(+), 23 deletions(-) diff --git a/lib/mito/discretization/blocks/L2NormBlock.h b/lib/mito/discretization/blocks/L2NormBlock.h index 5fc0dc58c..ac12ed588 100644 --- a/lib/mito/discretization/blocks/L2NormBlock.h +++ b/lib/mito/discretization/blocks/L2NormBlock.h @@ -9,8 +9,10 @@ namespace mito::discretization::blocks { - // TOFIX: the source does not need to be necessarily a scalar field, it can be some other field - template + template + // require that {functionT} is a function in barycentric coordinates + requires(std::is_same_v< + typename functionT::input_type, typename quadratureRuleT::quadrature_point_type>) class L2NormBlock : public AssemblyBlock { public: @@ -23,7 +25,7 @@ namespace mito::discretization::blocks { using quadrature_rule_type = quadratureRuleT; // the type of the function to compute the L2 norm of - using field_type = fieldT; + using function_type = functionT; public: // instantiate the quadrature rule @@ -31,15 +33,12 @@ namespace mito::discretization::blocks { public: // constructor - L2NormBlock(const field_type & field) : _field(field) {} + L2NormBlock(const function_type & function) : _function(function) {} public: // compute the elementary contribution of this block auto compute(const element_type & element) const -> elementary_block_type override { - // the number of nodes per element - constexpr int n_nodes = element_type::n_nodes; - // the number of quadrature points per element constexpr int n_quads = quadrature_rule_type::npoints; @@ -51,13 +50,10 @@ namespace mito::discretization::blocks { // the barycentric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); - // the coordinates of the quadrature point - auto coord = element.parametrization()(xi); - // populate the elementary contribution to the matrix elementary_contribution += quadrature_rule.weight(q) * tensor::determinant(element.jacobian()(xi)) - * _field(coord); + * _function(xi) * _function(xi); }); // all done @@ -65,8 +61,8 @@ namespace mito::discretization::blocks { } private: - // the field to compute the L2 norm of - const field_type & _field; + // the function to compute the L2 norm of + const function_type & _function; }; } // namespace mito diff --git a/lib/mito/discretization/blocks/api.h b/lib/mito/discretization/blocks/api.h index d004530b9..370396443 100644 --- a/lib/mito/discretization/blocks/api.h +++ b/lib/mito/discretization/blocks/api.h @@ -30,12 +30,12 @@ namespace mito::discretization::blocks { constexpr auto source_term_block(const sourceFieldT & f); // L2 norm block - template - using l2_norm_block_t = L2NormBlock; + template + using l2_norm_block_t = L2NormBlock; // L2 norm block factory - template - constexpr auto l2_norm_block(const fieldT & f); + template + constexpr auto l2_norm_block(const functionT & f); } diff --git a/lib/mito/discretization/blocks/factories.h b/lib/mito/discretization/blocks/factories.h index 333a5115c..8a6d32533 100644 --- a/lib/mito/discretization/blocks/factories.h +++ b/lib/mito/discretization/blocks/factories.h @@ -26,11 +26,11 @@ namespace mito::discretization::blocks { } // L2 norm block factory - template - constexpr auto l2_norm_block(const fieldT & f) + template + constexpr auto l2_norm_block(const functionT & f) { // all done - return l2_norm_block_t(f); + return l2_norm_block_t(f); } } diff --git a/lib/mito/discretization/blocks/forward.h b/lib/mito/discretization/blocks/forward.h index fca708d3f..b58068b66 100644 --- a/lib/mito/discretization/blocks/forward.h +++ b/lib/mito/discretization/blocks/forward.h @@ -21,10 +21,12 @@ namespace mito::discretization::blocks { template class SourceTermBlock; - // L2 norm block - template + // L2 norm block for a function defined at quadrature points in barycentric coordinates + template + // require that {functionT} is a function in barycentric coordinates + requires(std::is_same_v< + typename functionT::input_type, typename quadratureRuleT::quadrature_point_type>) class L2NormBlock; - } From d72de9939515ed3dfe684f885a45b1b1d2cfcdbd Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 28 Jul 2025 15:26:02 +0200 Subject: [PATCH 148/273] solvers: rename {solvers} directory to {matrix_solvers} Clarify that it contains matrix solvers as opposed to higher-level finite element solvers. --- .cmake/mito_sources.cmake | 4 +-- lib/mito/{solvers.h => matrix_solvers.h} | 2 +- .../backend/petsc.h | 0 .../backend/petsc/PETScKrylovSolver.cc | 15 +++++----- .../backend/petsc/PETScKrylovSolver.h | 2 +- .../backend/petsc/PETScLinearSystem.cc | 28 +++++++++---------- .../backend/petsc/PETScLinearSystem.h | 2 +- .../backend/petsc/PETScLinearSystem.icc | 4 +-- .../backend/petsc/api.h | 2 +- .../backend/petsc/externals.h | 2 +- .../backend/petsc/factories.h | 2 +- .../backend/petsc/forward.h | 2 +- .../backend/petsc/public.h | 0 lib/mito/{solvers => matrix_solvers}/public.h | 0 lib/mito/public.h | 2 +- tests/mito.lib/discretization/poisson.cc | 8 +++--- .../solvers/petsc_initialize_finalize.cc | 4 +-- tests/mito.lib/solvers/petsc_ksp.cc | 8 +++--- 18 files changed, 44 insertions(+), 43 deletions(-) rename lib/mito/{solvers.h => matrix_solvers.h} (81%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc.h (100%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/PETScKrylovSolver.cc (85%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/PETScKrylovSolver.h (96%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/PETScLinearSystem.cc (76%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/PETScLinearSystem.h (98%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/PETScLinearSystem.icc (86%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/api.h (87%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/externals.h (94%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/factories.h (90%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/forward.h (87%) rename lib/mito/{solvers => matrix_solvers}/backend/petsc/public.h (100%) rename lib/mito/{solvers => matrix_solvers}/public.h (100%) diff --git a/.cmake/mito_sources.cmake b/.cmake/mito_sources.cmake index 63d092c89..6fa1c85f9 100644 --- a/.cmake/mito_sources.cmake +++ b/.cmake/mito_sources.cmake @@ -10,8 +10,8 @@ set(MITO_SOURCES ${CMAKE_CURRENT_BINARY_DIR}/lib/mito/version.cc) # the mito petsc backend if (WITH_PETSC) set(MITO_SOURCES ${MITO_SOURCES} -lib/mito/solvers/backend/petsc/PETScLinearSystem.cc -lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc +lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.cc +lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc ) endif() diff --git a/lib/mito/solvers.h b/lib/mito/matrix_solvers.h similarity index 81% rename from lib/mito/solvers.h rename to lib/mito/matrix_solvers.h index f36edb3aa..565e3939a 100644 --- a/lib/mito/solvers.h +++ b/lib/mito/matrix_solvers.h @@ -8,7 +8,7 @@ // publish the interface -#include "solvers/public.h" +#include "matrix_solvers/public.h" // end of file \ No newline at end of file diff --git a/lib/mito/solvers/backend/petsc.h b/lib/mito/matrix_solvers/backend/petsc.h similarity index 100% rename from lib/mito/solvers/backend/petsc.h rename to lib/mito/matrix_solvers/backend/petsc.h diff --git a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc similarity index 85% rename from lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc rename to lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc index 708d84d7f..928f18b79 100644 --- a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.cc +++ b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc @@ -11,17 +11,18 @@ // constructor -mito::solvers::petsc::PETScKrylovSolver::PETScKrylovSolver(linear_system_type & linear_system) : +mito::matrix_solvers::petsc::PETScKrylovSolver::PETScKrylovSolver( + linear_system_type & linear_system) : _linear_system(linear_system), _options_prefix(linear_system.label() + "_") {} // destructor -mito::solvers::petsc::PETScKrylovSolver::~PETScKrylovSolver() {} +mito::matrix_solvers::petsc::PETScKrylovSolver::~PETScKrylovSolver() {} // create the Krylov solver auto -mito::solvers::petsc::PETScKrylovSolver::create() -> void +mito::matrix_solvers::petsc::PETScKrylovSolver::create() -> void { // create the Krylov solver PetscCallVoid(KSPCreate(PETSC_COMM_WORLD, &_ksp)); @@ -34,7 +35,7 @@ mito::solvers::petsc::PETScKrylovSolver::create() -> void // destroy the Krylov solver auto -mito::solvers::petsc::PETScKrylovSolver::destroy() -> void +mito::matrix_solvers::petsc::PETScKrylovSolver::destroy() -> void { // destroy the Krylov solver PetscCallVoid(KSPDestroy(&_ksp)); @@ -83,7 +84,7 @@ namespace { // set petsc options auto -mito::solvers::petsc::PETScKrylovSolver::set_options(const options_type & options) -> void +mito::matrix_solvers::petsc::PETScKrylovSolver::set_options(const options_type & options) -> void { // prepend the prefix {_options_prefix} to each of the space-separated options in input auto prefixed_options = prepend_options_prefix(options, _options_prefix); @@ -103,7 +104,7 @@ mito::solvers::petsc::PETScKrylovSolver::set_options(const options_type & option // solve the linear system auto -mito::solvers::petsc::PETScKrylovSolver::solve() -> void +mito::matrix_solvers::petsc::PETScKrylovSolver::solve() -> void { // assemble the linear system _linear_system.assemble(); @@ -117,7 +118,7 @@ mito::solvers::petsc::PETScKrylovSolver::solve() -> void // print the linear system of equations of the petsc solver auto -mito::solvers::petsc::PETScKrylovSolver::print() const -> void +mito::matrix_solvers::petsc::PETScKrylovSolver::print() const -> void { // create a reporting channel journal::info_t channel("mito.solvers.petsc.PETScKrylovSolver"); diff --git a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h similarity index 96% rename from lib/mito/solvers/backend/petsc/PETScKrylovSolver.h rename to lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h index 539e76ecd..bce47ef3a 100644 --- a/lib/mito/solvers/backend/petsc/PETScKrylovSolver.h +++ b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::solvers::petsc { +namespace mito::matrix_solvers::petsc { class PETScKrylovSolver { private: diff --git a/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc b/lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.cc similarity index 76% rename from lib/mito/solvers/backend/petsc/PETScLinearSystem.cc rename to lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.cc index 11cfb9b4b..cb8adc373 100644 --- a/lib/mito/solvers/backend/petsc/PETScLinearSystem.cc +++ b/lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.cc @@ -10,17 +10,17 @@ // constructor -mito::solvers::petsc::PETScLinearSystem::PETScLinearSystem(const label_type & label) : +mito::matrix_solvers::petsc::PETScLinearSystem::PETScLinearSystem(const label_type & label) : _label(label), _n_equations(0) {} // destructor -mito::solvers::petsc::PETScLinearSystem::~PETScLinearSystem() {} +mito::matrix_solvers::petsc::PETScLinearSystem::~PETScLinearSystem() {} // allocate memory for the matrix, right-hand side, and solution auto -mito::solvers::petsc::PETScLinearSystem::create(index_type size) -> void +mito::matrix_solvers::petsc::PETScLinearSystem::create(index_type size) -> void { // take note of the number of equations _n_equations = size; @@ -47,7 +47,7 @@ mito::solvers::petsc::PETScLinearSystem::create(index_type size) -> void // free memory for the matrix, right-hand side, and solution auto -mito::solvers::petsc::PETScLinearSystem::destroy() -> void +mito::matrix_solvers::petsc::PETScLinearSystem::destroy() -> void { // destroy the matrix, right-hand side, solution PetscCallVoid(MatDestroy(&_matrix)); @@ -60,7 +60,7 @@ mito::solvers::petsc::PETScLinearSystem::destroy() -> void // get the label of the linear system auto -mito::solvers::petsc::PETScLinearSystem::label() const -> label_type +mito::matrix_solvers::petsc::PETScLinearSystem::label() const -> label_type { // easy enough return _label; @@ -68,7 +68,7 @@ mito::solvers::petsc::PETScLinearSystem::label() const -> label_type // assemble the linear system auto -mito::solvers::petsc::PETScLinearSystem::assemble() -> void +mito::matrix_solvers::petsc::PETScLinearSystem::assemble() -> void { // assemble matrix PetscCallVoid(MatAssemblyBegin(_matrix, MAT_FINAL_ASSEMBLY)); @@ -84,7 +84,7 @@ mito::solvers::petsc::PETScLinearSystem::assemble() -> void // set the matrix entry at ({row}, {col}) to {value} auto -mito::solvers::petsc::PETScLinearSystem::insert_matrix_value( +mito::matrix_solvers::petsc::PETScLinearSystem::insert_matrix_value( index_type row, index_type col, const scalar_type & value) -> void { // delegate to PETSc @@ -96,7 +96,7 @@ mito::solvers::petsc::PETScLinearSystem::insert_matrix_value( // add {value} to matrix entry at ({row}, {col}) auto -mito::solvers::petsc::PETScLinearSystem::add_matrix_value( +mito::matrix_solvers::petsc::PETScLinearSystem::add_matrix_value( index_type row, index_type col, const scalar_type & value) -> void { // delegate to PETSc @@ -108,8 +108,8 @@ mito::solvers::petsc::PETScLinearSystem::add_matrix_value( // set the right-hand side entry at {row} to {value} auto -mito::solvers::petsc::PETScLinearSystem::insert_rhs_value(index_type row, const scalar_type & value) - -> void +mito::matrix_solvers::petsc::PETScLinearSystem::insert_rhs_value( + index_type row, const scalar_type & value) -> void { // delegate to PETSc PetscCallVoid(VecSetValue(_rhs, row, value, INSERT_VALUES)); @@ -120,8 +120,8 @@ mito::solvers::petsc::PETScLinearSystem::insert_rhs_value(index_type row, const // add {value} to right-hand side entry at {row} auto -mito::solvers::petsc::PETScLinearSystem::add_rhs_value(index_type row, const scalar_type & value) - -> void +mito::matrix_solvers::petsc::PETScLinearSystem::add_rhs_value( + index_type row, const scalar_type & value) -> void { // delegate to PETSc PetscCallVoid(VecSetValue(_rhs, row, value, ADD_VALUES)); @@ -131,7 +131,7 @@ mito::solvers::petsc::PETScLinearSystem::add_rhs_value(index_type row, const sca } auto -mito::solvers::petsc::PETScLinearSystem::n_equations() const -> int +mito::matrix_solvers::petsc::PETScLinearSystem::n_equations() const -> int { return _n_equations; } @@ -139,7 +139,7 @@ mito::solvers::petsc::PETScLinearSystem::n_equations() const -> int // print the linear system of equations of the petsc solver auto -mito::solvers::petsc::PETScLinearSystem::print() const -> void +mito::matrix_solvers::petsc::PETScLinearSystem::print() const -> void { // create a reporting channel journal::info_t channel("mito.solvers.petsc.PETScLinearSystem"); diff --git a/lib/mito/solvers/backend/petsc/PETScLinearSystem.h b/lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.h similarity index 98% rename from lib/mito/solvers/backend/petsc/PETScLinearSystem.h rename to lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.h index 444f86cb1..fd1450967 100644 --- a/lib/mito/solvers/backend/petsc/PETScLinearSystem.h +++ b/lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::solvers::petsc { +namespace mito::matrix_solvers::petsc { class PETScLinearSystem { diff --git a/lib/mito/solvers/backend/petsc/PETScLinearSystem.icc b/lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.icc similarity index 86% rename from lib/mito/solvers/backend/petsc/PETScLinearSystem.icc rename to lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.icc index a6e17b461..147993bc6 100644 --- a/lib/mito/solvers/backend/petsc/PETScLinearSystem.icc +++ b/lib/mito/matrix_solvers/backend/petsc/PETScLinearSystem.icc @@ -5,14 +5,14 @@ #if !defined(mito_solvers_backend_petsc_PETScLinearSystem_icc) -#error This header file contains implementation details of class mito::solvers::petsc::PETScLinearSystem +#error This header file contains implementation details of class mito::matrix_solvers::petsc::PETScLinearSystem #else // get the solution at entry {row} template auto -mito::solvers::petsc::PETScLinearSystem::get_solution(solutionT & solution) const -> void +mito::matrix_solvers::petsc::PETScLinearSystem::get_solution(solutionT & solution) const -> void { // get a pointer to the beginning of {_solution} const scalar_type * u; diff --git a/lib/mito/solvers/backend/petsc/api.h b/lib/mito/matrix_solvers/backend/petsc/api.h similarity index 87% rename from lib/mito/solvers/backend/petsc/api.h rename to lib/mito/matrix_solvers/backend/petsc/api.h index 086262adf..c8c4ecafe 100644 --- a/lib/mito/solvers/backend/petsc/api.h +++ b/lib/mito/matrix_solvers/backend/petsc/api.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::solvers::petsc { +namespace mito::matrix_solvers::petsc { // petsc linear system using linear_system_t = PETScLinearSystem; diff --git a/lib/mito/solvers/backend/petsc/externals.h b/lib/mito/matrix_solvers/backend/petsc/externals.h similarity index 94% rename from lib/mito/solvers/backend/petsc/externals.h rename to lib/mito/matrix_solvers/backend/petsc/externals.h index 2d5cc5618..7d0bf8c63 100644 --- a/lib/mito/solvers/backend/petsc/externals.h +++ b/lib/mito/matrix_solvers/backend/petsc/externals.h @@ -19,7 +19,7 @@ #include -namespace mito::solvers::petsc { +namespace mito::petsc { // initialize petsc inline auto initialize() -> void diff --git a/lib/mito/solvers/backend/petsc/factories.h b/lib/mito/matrix_solvers/backend/petsc/factories.h similarity index 90% rename from lib/mito/solvers/backend/petsc/factories.h rename to lib/mito/matrix_solvers/backend/petsc/factories.h index fb5546078..1db34c218 100644 --- a/lib/mito/solvers/backend/petsc/factories.h +++ b/lib/mito/matrix_solvers/backend/petsc/factories.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::solvers::petsc { +namespace mito::matrix_solvers::petsc { // petsc linear system auto linear_system(const std::string & name) diff --git a/lib/mito/solvers/backend/petsc/forward.h b/lib/mito/matrix_solvers/backend/petsc/forward.h similarity index 87% rename from lib/mito/solvers/backend/petsc/forward.h rename to lib/mito/matrix_solvers/backend/petsc/forward.h index c3c876e5e..278b45cf2 100644 --- a/lib/mito/solvers/backend/petsc/forward.h +++ b/lib/mito/matrix_solvers/backend/petsc/forward.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::solvers::petsc { +namespace mito::matrix_solvers::petsc { // class for PETSc linear system class PETScLinearSystem; diff --git a/lib/mito/solvers/backend/petsc/public.h b/lib/mito/matrix_solvers/backend/petsc/public.h similarity index 100% rename from lib/mito/solvers/backend/petsc/public.h rename to lib/mito/matrix_solvers/backend/petsc/public.h diff --git a/lib/mito/solvers/public.h b/lib/mito/matrix_solvers/public.h similarity index 100% rename from lib/mito/solvers/public.h rename to lib/mito/matrix_solvers/public.h diff --git a/lib/mito/public.h b/lib/mito/public.h index f051122a9..5a2ac7f59 100644 --- a/lib/mito/public.h +++ b/lib/mito/public.h @@ -25,7 +25,7 @@ #include "simulation.h" #include "topology.h" #include "utilities.h" -#include "solvers.h" +#include "matrix_solvers.h" // end of file diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 90262128a..da05d5827 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -72,12 +72,12 @@ TEST(Fem, PoissonSquare) // should be handled by the system // initialize PETSc - mito::solvers::petsc::initialize(); + mito::petsc::initialize(); // create a PETSc linear system of equations and a Krylov solver - auto linear_system = mito::solvers::petsc::linear_system("mysystem"); + auto linear_system = mito::matrix_solvers::petsc::linear_system("mysystem"); linear_system.create(N_equations); - auto solver = mito::solvers::petsc::ksp(linear_system); + auto solver = mito::matrix_solvers::petsc::ksp(linear_system); solver.create(); solver.set_options("-ksp_type preonly -pc_type cholesky"); @@ -282,7 +282,7 @@ TEST(Fem, PoissonSquare) // TOFIX: move this to the class owning the petsc instance // finalize PETSc - mito::solvers::petsc::finalize(); + mito::petsc::finalize(); } // end of file diff --git a/tests/mito.lib/solvers/petsc_initialize_finalize.cc b/tests/mito.lib/solvers/petsc_initialize_finalize.cc index 2f9cdfc09..e11b518c4 100644 --- a/tests/mito.lib/solvers/petsc_initialize_finalize.cc +++ b/tests/mito.lib/solvers/petsc_initialize_finalize.cc @@ -11,10 +11,10 @@ TEST(Solvers, PETScInitializeFinalize) { // initialize PETSc - mito::solvers::petsc::initialize(); + mito::petsc::initialize(); // finalize PETSc - mito::solvers::petsc::finalize(); + mito::petsc::finalize(); } diff --git a/tests/mito.lib/solvers/petsc_ksp.cc b/tests/mito.lib/solvers/petsc_ksp.cc index 0eebcd866..272a05f52 100644 --- a/tests/mito.lib/solvers/petsc_ksp.cc +++ b/tests/mito.lib/solvers/petsc_ksp.cc @@ -14,11 +14,11 @@ TEST(Solvers, PETScKSPSolver) int N = 10; // instantiate a PETSc linear system of size {N} - auto linear_system = mito::solvers::petsc::linear_system("mysystem"); + auto linear_system = mito::matrix_solvers::petsc::linear_system("mysystem"); linear_system.create(N); // instantiate a PETSc Krylov solver for the linear system - auto solver = mito::solvers::petsc::ksp(linear_system); + auto solver = mito::matrix_solvers::petsc::ksp(linear_system); solver.create(); solver.set_options("-ksp_monitor"); @@ -68,13 +68,13 @@ int main(int argc, char ** argv) { // initialize PETSc - mito::solvers::petsc::initialize(); + mito::petsc::initialize(); ::testing::InitGoogleTest(&argc, argv); auto result = RUN_ALL_TESTS(); // finalize PETSc - mito::solvers::petsc::finalize(); + mito::petsc::finalize(); // all done return result; From cd1859c3e382c37cf3616aa3ed78d49541d74317 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Jul 2025 11:35:20 +0200 Subject: [PATCH 149/273] discretization: move {DiscretizationNode} alias and factory out of {fem} subdirectory --- lib/mito/discretization/api.h | 3 +++ lib/mito/discretization/fem/api.h | 3 --- lib/mito/discretization/fem/forward.h | 3 --- lib/mito/discretization/forward.h | 3 +++ 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 8192e113c..ab6f127ba 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -9,6 +9,9 @@ namespace mito::discretization { + // discretization node alias + using discretization_node_t = utilities::std_shared_ptr; + // nodal field template using nodal_field_t = DiscreteField, Y>; diff --git a/lib/mito/discretization/fem/api.h b/lib/mito/discretization/fem/api.h index 8ff7c7e34..ecc2e5157 100644 --- a/lib/mito/discretization/fem/api.h +++ b/lib/mito/discretization/fem/api.h @@ -9,9 +9,6 @@ namespace mito::discretization { - // discretization node alias - using discretization_node_t = utilities::std_shared_ptr; - // function space alias template using function_space_t = FunctionSpace; diff --git a/lib/mito/discretization/fem/forward.h b/lib/mito/discretization/fem/forward.h index be5d69b4a..baf244a2d 100644 --- a/lib/mito/discretization/fem/forward.h +++ b/lib/mito/discretization/fem/forward.h @@ -9,9 +9,6 @@ namespace mito::discretization { - // class discretization node - class DiscretizationNode; - // class function space template class FunctionSpace; diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index ad6d05f61..da013596d 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -9,6 +9,9 @@ namespace mito::discretization { + // class discretization node + class DiscretizationNode; + // class discrete field template class DiscreteField; From 747c0eb03e3e0c9ddbf5d8632472db1eff42d0cf Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Jul 2025 11:46:02 +0200 Subject: [PATCH 150/273] discretization: rename nodal fields to mesh fields Spare the name "nodal field" for fields defined on discretization nodes. --- .cmake/mito_tests_mito_lib.cmake | 2 +- lib/mito/discretization/api.h | 12 +++++----- lib/mito/discretization/factories.h | 24 +++++++++---------- lib/mito/io/vtk/FieldVTKWriter.h | 2 +- .../{nodal_field.cc => mesh_field.cc} | 12 +++++----- tests/mito.lib/discretization/poisson.cc | 14 +++++------ .../io/parallel_vtk_mesh_field_writer.cc | 12 +++++----- tests/mito.lib/io/summit_to_summit_mesh_2D.cc | 8 +++---- 8 files changed, 43 insertions(+), 43 deletions(-) rename tests/mito.lib/discretization/{nodal_field.cc => mesh_field.cc} (83%) diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 2f80f4d7a..fb5c98a42 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -40,7 +40,7 @@ mito_test_driver(tests/mito.lib/constraints/dirichlet.cc) # discretization mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) -mito_test_driver(tests/mito.lib/discretization/nodal_field.cc) +mito_test_driver(tests/mito.lib/discretization/mesh_field.cc) mito_test_driver(tests/mito.lib/discretization/poisson.cc) mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p1.cc) mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p2.cc) diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index ab6f127ba..72dbde1c4 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -12,9 +12,9 @@ namespace mito::discretization { // discretization node alias using discretization_node_t = utilities::std_shared_ptr; - // nodal field + // mesh field template - using nodal_field_t = DiscreteField, Y>; + using mesh_field_t = DiscreteField, Y>; // point field template @@ -28,13 +28,13 @@ namespace mito::discretization { template constexpr auto quadrature_field(const meshT & mesh, std::string name); - // nodal field factory + // mesh field factory template - constexpr auto nodal_field(const mesh::mesh_c auto & mesh, std::string name); + constexpr auto mesh_field(const mesh::mesh_c auto & mesh, std::string name); - // nodal field factory from a continuous field + // mesh field factory from a continuous field template - constexpr auto nodal_field( + constexpr auto mesh_field( const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, const fieldT & field, std::string name); diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index d06711bd2..29d15766e 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -19,9 +19,9 @@ namespace mito::discretization { mesh.cells(), name); } - // nodal field factory + // mesh field factory template - constexpr auto nodal_field(const meshT & mesh, std::string name) + constexpr auto mesh_field(const meshT & mesh, std::string name) { // assemble the node type using node_type = geometry::node_t; @@ -30,29 +30,29 @@ namespace mito::discretization { std::unordered_set> nodes; mesh::get_nodes(mesh, nodes); - // build a nodal field on the nodes collected from the mesh - return nodal_field_t(nodes, name); + // build a mesh field on the nodes collected from the mesh + return mesh_field_t(nodes, name); } - // nodal field factory from a continuous field + // mesh field factory from a continuous field template - constexpr auto nodal_field( + constexpr auto mesh_field( const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, const fieldT & field, std::string name) { - // create a nodal field on the mesh - auto n_field = nodal_field(mesh, name); + // create a mesh field on the mesh + auto m_field = mesh_field(mesh, name); - // populate the nodal field with the values of the continuous field - for (auto & [node, value] : n_field) { + // populate the mesh field with the values of the continuous field + for (auto & [node, value] : m_field) { // get the position of {node} auto coord = coord_system.coordinates(node->point()); // evaluate the continuousfield at {coord} value = field(coord); } - // return the nodal field - return n_field; + // return the mesh field + return m_field; } // point field factory diff --git a/lib/mito/io/vtk/FieldVTKWriter.h b/lib/mito/io/vtk/FieldVTKWriter.h index fdd3f6ed2..a356a2cb2 100644 --- a/lib/mito/io/vtk/FieldVTKWriter.h +++ b/lib/mito/io/vtk/FieldVTKWriter.h @@ -18,7 +18,7 @@ namespace mito::io::vtk { template struct field_type { template - using type = discretization::nodal_field_t; + using type = discretization::mesh_field_t; }; // specialization to {point_cloud_c} case diff --git a/tests/mito.lib/discretization/nodal_field.cc b/tests/mito.lib/discretization/mesh_field.cc similarity index 83% rename from tests/mito.lib/discretization/nodal_field.cc rename to tests/mito.lib/discretization/mesh_field.cc index 2e58c5aae..38d0a50b4 100644 --- a/tests/mito.lib/discretization/nodal_field.cc +++ b/tests/mito.lib/discretization/mesh_field.cc @@ -22,8 +22,8 @@ TEST(Discretization, NodalFieldSphere) std::ifstream fileStream("sphere.summit"); auto mesh = mito::io::summit::reader>(fileStream, coord_system); - // a nodal field on the mesh - auto nodal_field = mito::discretization::nodal_field>(mesh, "normal"); + // a mesh field on the mesh + auto mesh_field = mito::discretization::mesh_field>(mesh, "normal"); // the normal field to the submanifold constexpr auto normal_field = mito::fields::field([](const coordinates_t & x) -> auto { @@ -34,8 +34,8 @@ TEST(Discretization, NodalFieldSphere) + std::cos(theta) * mito::tensor::e_2<3>; }); - // fill information in nodal field - for (auto & [node, value] : nodal_field) { + // fill information in mesh field + for (auto & [node, value] : mesh_field) { // get the coordinates of the node auto & coordinates = coord_system.coordinates(node->point()); // compute the value of the normal field at those coordinates @@ -45,8 +45,8 @@ TEST(Discretization, NodalFieldSphere) #ifdef WITH_VTK // write mesh to vtk file auto writer = mito::io::vtk::field_writer("sphere_mesh_field", mesh, coord_system); - // sign {nodal_field} up with the writer - writer.record(nodal_field); + // sign {mesh_field} up with the writer + writer.record(mesh_field); // write output file writer.write(); #endif diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index da05d5827..0ce7c885e 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -156,11 +156,11 @@ TEST(Fem, PoissonSquare) // TOFIX: the solution should be assembled by the function space, which is aware of the // constraints and can populate the constrained nodes appropriately - // the numerical solution nodal field on the mesh - auto solution = mito::discretization::nodal_field(mesh, "numerical solution"); + // the numerical solution mesh field on the mesh + auto solution = mito::discretization::mesh_field(mesh, "numerical solution"); // get the node map from the function space auto node_map = function_space.node_map(); - // fill information in nodal field + // fill information in mesh field for (auto & [node, value] : solution) { auto discretization_node = node_map.at(node); // get the equation number of {node} @@ -176,11 +176,11 @@ TEST(Fem, PoissonSquare) mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y)); #ifdef WITH_VTK - // the forcing term nodal field on the mesh (for visualization) - auto forcing = mito::discretization::nodal_field(mesh, coord_system, f, "forcing term"); - // the exact solution nodal field on the mesh (for visualization) + // the forcing term mesh field on the mesh (for visualization) + auto forcing = mito::discretization::mesh_field(mesh, coord_system, f, "forcing term"); + // the exact solution mesh field on the mesh (for visualization) auto exact_solution = - mito::discretization::nodal_field(mesh, coord_system, u_ex, "exact solution"); + mito::discretization::mesh_field(mesh, coord_system, u_ex, "exact solution"); // write mesh to vtk file auto writer = mito::io::vtk::field_writer("poisson_square", mesh, coord_system); // sign {forcing} up with the writer diff --git a/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc b/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc index a33115c7f..5fa6e6b1c 100644 --- a/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc +++ b/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc @@ -38,8 +38,8 @@ TEST(ParallelVtkWriter, MeshField) std::ifstream fileStream(mesh_file); auto mesh = mito::io::summit::reader>(fileStream, coord_system); - // a nodal field on the mesh - auto nodal_field = mito::discretization::nodal_field>(mesh, "normal"); + // a mesh field on the mesh + auto mesh_field = mito::discretization::mesh_field>(mesh, "normal"); // the normal field to the ball constexpr auto normal_field = mito::fields::field([](const coordinates_t & x) -> auto { @@ -50,8 +50,8 @@ TEST(ParallelVtkWriter, MeshField) + std::cos(theta) * mito::tensor::e_2<3>; }); - // fill information in nodal field - for (auto & [node, value] : nodal_field) { + // fill information in mesh field + for (auto & [node, value] : mesh_field) { // get the coordinates of the node auto & coordinates = coord_system.coordinates(node->point()); // compute the value of the normal field at those coordinates @@ -60,8 +60,8 @@ TEST(ParallelVtkWriter, MeshField) // write mesh to vtk file auto writer = mito::io::vtk::parallel_field_writer("sphere_mesh_field", mesh, coord_system); - // sign {nodal_field} up with the writer - writer.record(nodal_field); + // sign {mesh_field} up with the writer + writer.record(mesh_field); // write output file writer.write(); diff --git a/tests/mito.lib/io/summit_to_summit_mesh_2D.cc b/tests/mito.lib/io/summit_to_summit_mesh_2D.cc index 5de5bce28..71772d843 100644 --- a/tests/mito.lib/io/summit_to_summit_mesh_2D.cc +++ b/tests/mito.lib/io/summit_to_summit_mesh_2D.cc @@ -33,9 +33,9 @@ test() // get the original number of mesh cells original_mesh_cells = mesh.nCells(); - // get the original number of mesh nodes by counting the nodes of a nodal field built on it + // get the original number of mesh nodes by counting the nodes of a mesh field built on it original_mesh_nodes = - mito::discretization::nodal_field(mesh, "field").size(); + mito::discretization::mesh_field(mesh, "field").size(); // write summit mesh mito::io::summit::writer("rectangle_copy", mesh, coord_system); @@ -52,9 +52,9 @@ test() // get the reread number of mesh cells reread_mesh_cells = mesh.nCells(); - // get the reread number of mesh nodes by counting the nodes of a nodal field built on it + // get the reread number of mesh nodes by counting the nodes of a mesh field built on it reread_mesh_nodes = - mito::discretization::nodal_field(mesh, "field").size(); + mito::discretization::mesh_field(mesh, "field").size(); #ifdef WITH_VTK // write mesh to vtk file From aac430d689b0dae771363006df4380f43a1b012a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Jul 2025 11:58:10 +0200 Subject: [PATCH 151/273] discretization: move class {FunctionSpace} out of {fem} subdirectory This class should be on the same level of the {DiscreteSystem} class. --- .../discretization/{fem => }/FunctionSpace.h | 0 lib/mito/discretization/api.h | 8 +++++++ lib/mito/discretization/factories.h | 23 +++++++++++++++++++ lib/mito/discretization/fem/api.h | 8 ------- lib/mito/discretization/fem/factories.h | 22 ------------------ lib/mito/discretization/fem/forward.h | 3 --- lib/mito/discretization/fem/public.h | 1 - lib/mito/discretization/forward.h | 4 ++++ lib/mito/discretization/public.h | 1 + 9 files changed, 36 insertions(+), 34 deletions(-) rename lib/mito/discretization/{fem => }/FunctionSpace.h (100%) diff --git a/lib/mito/discretization/fem/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h similarity index 100% rename from lib/mito/discretization/fem/FunctionSpace.h rename to lib/mito/discretization/FunctionSpace.h diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 72dbde1c4..bcc392aff 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -42,6 +42,14 @@ namespace mito::discretization { template constexpr auto point_field(const cloudT & cloud, std::string name); + // function space alias + template + using function_space_t = FunctionSpace; + + // function space factory + template + constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); + // discrete system alias template using discrete_system_t = DiscreteSystem; diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 29d15766e..37805dadb 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -63,6 +63,29 @@ namespace mito::discretization { return point_field_t(cloud.points(), name); } + // TOFIX: create a constructor that takes no constraints + + // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a + // single constraint + // function space factory + template + constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) + { + // the manifold type + using manifold_type = manifoldT; + // the mesh type + using mesh_type = typename manifold_type::mesh_type; + // the cell type + using cell_type = typename mesh_type::cell_type; + // the degree of the finite element + constexpr int degree = p; + // typedef for a finite element + using element_type = typename isoparametric_simplex::type; + + // build a function space on the manifold and return it + return function_space_t(manifold, constraints); + } + // discrete system factory template constexpr auto discrete_system(const functionSpaceT & function_space) diff --git a/lib/mito/discretization/fem/api.h b/lib/mito/discretization/fem/api.h index ecc2e5157..264ce9af9 100644 --- a/lib/mito/discretization/fem/api.h +++ b/lib/mito/discretization/fem/api.h @@ -9,14 +9,6 @@ namespace mito::discretization { - // function space alias - template - using function_space_t = FunctionSpace; - - // function space factory - template - constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); - } diff --git a/lib/mito/discretization/fem/factories.h b/lib/mito/discretization/fem/factories.h index c2950d35e..d5414b6fc 100644 --- a/lib/mito/discretization/fem/factories.h +++ b/lib/mito/discretization/fem/factories.h @@ -9,28 +9,6 @@ namespace mito::discretization { - // TOFIX: create a constructor that takes no constraints - - // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a - // single constraint - // function space factory - template - constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) - { - // the manifold type - using manifold_type = manifoldT; - // the mesh type - using mesh_type = typename manifold_type::mesh_type; - // the cell type - using cell_type = typename mesh_type::cell_type; - // the degree of the finite element - constexpr int degree = p; - // typedef for a finite element - using element_type = typename isoparametric_simplex::type; - - // build a function space on the manifold and return it - return function_space_t(manifold, constraints); - } } diff --git a/lib/mito/discretization/fem/forward.h b/lib/mito/discretization/fem/forward.h index baf244a2d..264ce9af9 100644 --- a/lib/mito/discretization/fem/forward.h +++ b/lib/mito/discretization/fem/forward.h @@ -9,9 +9,6 @@ namespace mito::discretization { - // class function space - template - class FunctionSpace; } diff --git a/lib/mito/discretization/fem/public.h b/lib/mito/discretization/fem/public.h index 5d0aa83a0..bcf3626ea 100644 --- a/lib/mito/discretization/fem/public.h +++ b/lib/mito/discretization/fem/public.h @@ -20,7 +20,6 @@ #include "ReferenceTriangle.h" #include "IsoparametricTriangle.h" #include "isoparametric_simplex_library.h" -#include "FunctionSpace.h" // factories implementation #include "factories.h" diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index da013596d..d0ba5c0fe 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -16,6 +16,10 @@ namespace mito::discretization { template class DiscreteField; + // class function space + template + class FunctionSpace; + // class discrete system template class DiscreteSystem; diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index f1f25148a..05a9b3ba2 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -19,6 +19,7 @@ // classes implementation #include "DiscreteField.h" #include "DiscretizationNode.h" +#include "FunctionSpace.h" #include "DiscreteSystem.h" // finite elements implementation From a2b34319a2946a717837f2eddf40034386a810d6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Jul 2025 12:00:50 +0200 Subject: [PATCH 152/273] discretization: add concept of a {FunctionSpace} --- lib/mito/discretization/DiscreteSystem.h | 2 +- lib/mito/discretization/api.h | 4 ++-- lib/mito/discretization/factories.h | 2 +- lib/mito/discretization/fem/utilities.h | 2 +- lib/mito/discretization/forward.h | 11 ++++++++++- 5 files changed, 15 insertions(+), 6 deletions(-) diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 9e441eaed..568819ecf 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -9,7 +9,7 @@ namespace mito::discretization { - template + template class DiscreteSystem { private: diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index bcc392aff..e561296b3 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -51,11 +51,11 @@ namespace mito::discretization { constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); // discrete system alias - template + template using discrete_system_t = DiscreteSystem; // discrete system factory - template + template constexpr auto discrete_system(const functionSpaceT & function_space); } diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 37805dadb..1c8e636de 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -87,7 +87,7 @@ namespace mito::discretization { } // discrete system factory - template + template constexpr auto discrete_system(const functionSpaceT & function_space) { return discrete_system_t(function_space); diff --git a/lib/mito/discretization/fem/utilities.h b/lib/mito/discretization/fem/utilities.h index acf30cc79..6725a334b 100644 --- a/lib/mito/discretization/fem/utilities.h +++ b/lib/mito/discretization/fem/utilities.h @@ -10,7 +10,7 @@ namespace mito::discretization { // populate a container with a collection of all nodes in a function space - template + template inline auto get_discretization_nodes( const functionSpaceT & function_space, nodesCollectionT & nodes) -> void { diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index d0ba5c0fe..146c6b1e2 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -20,8 +20,17 @@ namespace mito::discretization { template class FunctionSpace; + // concept of a function space + template + concept function_space_c = requires(F c) { + // require that F only binds to {FunctionSpace} specializations + []( + const FunctionSpace &) { + }(c); + }; + // class discrete system - template + template class DiscreteSystem; } From d3d4bc674fa77f5566b93bc2da537c29e126cbfb Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Jul 2025 16:57:08 +0200 Subject: [PATCH 153/273] discretization: draft implementation {nodal_field_t} as a {DiscreteField} on discretization nodes For now the nodal field only represents the field at the only discretization nodes that are also mesh nodes, regardless of the subconnectivities coming with higher order elements. This should be fixed later. --- lib/mito/discretization/api.h | 8 ++++++++ lib/mito/discretization/factories.h | 15 +++++++++++++++ lib/mito/discretization/fem/utilities.h | 15 +++++++++++++++ 3 files changed, 38 insertions(+) diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index e561296b3..f510c36e4 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -20,6 +20,10 @@ namespace mito::discretization { template using point_field_t = DiscreteField, Y>; + // nodal field + template + using nodal_field_t = DiscreteField; + // quadrature field alias template using quadrature_field_t = DiscreteField>; @@ -42,6 +46,10 @@ namespace mito::discretization { template constexpr auto point_field(const cloudT & cloud, std::string name); + // nodal field factory + template + constexpr auto nodal_field(const functionSpaceT & function_space, std::string name); + // function space alias template using function_space_t = FunctionSpace; diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 1c8e636de..b59c04d68 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -63,6 +63,21 @@ namespace mito::discretization { return point_field_t(cloud.points(), name); } + // nodal field factory + template + constexpr auto nodal_field(const functionSpaceT & function_space, std::string name) + { + // assemble the node type + using node_type = functionSpaceT::discretization_node_type; + + // get the nodes in the mesh + std::unordered_set> nodes; + get_mesh_discretization_nodes(function_space, nodes); + + // build a nodal field on the discretization nodes collected from the function space + return nodal_field_t(nodes, name); + } + // TOFIX: create a constructor that takes no constraints // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a diff --git a/lib/mito/discretization/fem/utilities.h b/lib/mito/discretization/fem/utilities.h index 6725a334b..27615c53a 100644 --- a/lib/mito/discretization/fem/utilities.h +++ b/lib/mito/discretization/fem/utilities.h @@ -24,6 +24,21 @@ namespace mito::discretization { return; } + // populate a container with a collection of all first order nodes in a function space (include + // only the mesh nodes, exclude the nodes of the subconnectivities) + template + inline auto get_mesh_discretization_nodes( + const functionSpaceT & function_space, nodesCollectionT & nodes) -> void + { + for (const auto & element : function_space.elements()) { + for (const auto & node : element.geometric_simplex().nodes()) { + nodes.insert(function_space.node_map().at(node)); + } + } + + // all done + return; + } } From 206d77023ad6cbe92bfd39dc22893ccb2d3674d9 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 29 Jul 2025 16:58:39 +0200 Subject: [PATCH 154/273] vtk: implement writers for nodal fields --- lib/mito/io/vtk/FieldVTKWriter.h | 9 +- lib/mito/io/vtk/NodeVTKWriter.h | 125 +++++++++++++++++++++++ lib/mito/io/vtk/api.h | 47 +++++++++ lib/mito/io/vtk/factories.h | 44 +++++++- lib/mito/io/vtk/forward.h | 9 ++ lib/mito/io/vtk/public.h | 1 + tests/mito.lib/discretization/poisson.cc | 20 ++-- 7 files changed, 246 insertions(+), 9 deletions(-) create mode 100644 lib/mito/io/vtk/NodeVTKWriter.h diff --git a/lib/mito/io/vtk/FieldVTKWriter.h b/lib/mito/io/vtk/FieldVTKWriter.h index a356a2cb2..311837adb 100644 --- a/lib/mito/io/vtk/FieldVTKWriter.h +++ b/lib/mito/io/vtk/FieldVTKWriter.h @@ -28,6 +28,13 @@ namespace mito::io::vtk { using type = discretization::point_field_t; }; + // specialization to {function_space_c} case + template + struct field_type { + template + using type = discretization::nodal_field_t; + }; + // utility function to get the data pointer template constexpr auto dim() -> int @@ -93,7 +100,7 @@ namespace mito::io::vtk { vtkArray->SetNumberOfTuples(field_size); // populate the array - if constexpr (mesh::mesh_c) { + if constexpr (mesh::mesh_c or discretization::function_space_c) { // get the nodes in the grid const auto & nodes = _grid_writer.nodes(); diff --git a/lib/mito/io/vtk/NodeVTKWriter.h b/lib/mito/io/vtk/NodeVTKWriter.h new file mode 100644 index 000000000..89df530ae --- /dev/null +++ b/lib/mito/io/vtk/NodeVTKWriter.h @@ -0,0 +1,125 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::io::vtk { + + // TOFIX: this writer works for now on discretization nodes that are also mesh nodes, but + // should be generalized to write on any discretization node type, including nodes of higher + // order elements + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT, + class vtkGridWriterT> + requires( + utilities::same_dim_c + && utilities::same_dim_c) + class NodeVTKWriter : public vtkGridWriterT { + public: + // the grid type + using grid_type = functionSpaceT; + // the grid writer type + using grid_writer_type = vtkGridWriterT; + + private: + // the element type + using element_type = typename grid_type::element_type; + // the coordinate system type + using coord_system_type = coordSystemT; + // the dimension of the physical space + static constexpr int D = grid_type::dim; + // the type of node + using node_type = typename functionSpaceT::discretization_node_type; + // the type of a collection of nodes (nodes are mapped to the index of the vtk points; + // points that are shared among multiple elements have the same index) + using nodes_type = std::unordered_map>; + + private: + auto _create_vtk_grid( + const grid_type & function_space, const coord_system_type & coordinate_system) + { + // vtk points and cells + auto pointsVtk = vtkSmartPointer::New(); + + // global index assigned to each vtk point + auto indexPointVtk = 0; + + // loop over the elements + for (const auto & element : function_space.elements()) { + // get the cell associated with the element + const auto & cell = element.geometric_simplex(); + // loop over the nodes of the cell + for (const auto & node : cell.nodes()) { + // try to insert the point in the map + auto [_, inserted] = + _nodes.insert({ function_space.node_map().at(node), indexPointVtk }); + // if the point was inserted the map (i.e. not a duplicate) + if (inserted) { + // insert the new vtk point + insert_vtk_point(coordinate_system.coordinates(node->point()), pointsVtk); + // update global index for the vtk point + ++indexPointVtk; + } + } + } + + // loop over the elements + for (const auto & element : function_space.elements()) { + // get the cell associated with the element + const auto & cell = element.geometric_simplex(); + + // create vtk cell + auto cellVtk = + vtkCellPointer(); + + // local index for the points of the cell + auto indexLocalPointVtk = 0; + + // loop over the nodes of the cell + for (const auto & node : cell.nodes()) { + // assert that the node is present in the collection of nodes + assert(_nodes.contains(function_space.node_map().at(node))); + // get the index of the node + auto index = _nodes.at(function_space.node_map().at(node)); + // set the id of the point + cellVtk->GetPointIds()->SetId(indexLocalPointVtk, index); + // update local index for the points in the cell + ++indexLocalPointVtk; + } + + // insert the new cell + this->_grid->InsertNextCell(cellVtk->GetCellType(), cellVtk->GetPointIds()); + } + + // set the grid points + this->_grid->SetPoints(pointsVtk); + + // all done + return; + } + + public: + NodeVTKWriter( + std::string filename, const grid_type & function_space, + const coord_system_type & coord_system) : + grid_writer_type(filename) + { + _create_vtk_grid(function_space, coord_system); + } + + // accessor for the nodes + auto nodes() const -> const nodes_type & { return _nodes; } + + private: + // a collection of nodes in the grid + nodes_type _nodes; + }; + +} // namespace mito::io::vtk + + +// end of file diff --git a/lib/mito/io/vtk/api.h b/lib/mito/io/vtk/api.h index a5bd91967..8e1092c06 100644 --- a/lib/mito/io/vtk/api.h +++ b/lib/mito/io/vtk/api.h @@ -19,6 +19,13 @@ namespace mito::io::vtk { requires(utilities::same_dim_c) using cloud_writer_t = PointCloudVTKWriter>; + // node writer alias + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + using node_writer_t = + NodeVTKWriter>; + // field writer alias template using field_writer_t = FieldVTKWriter; @@ -33,6 +40,14 @@ namespace mito::io::vtk { requires(utilities::same_dim_c) auto grid_writer(std::string filename, const cloudT & cloud, const coordSystemT & coord_system); + // node writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto grid_writer( + std::string filename, const functionSpaceT & function_space, + const coordSystemT & coord_system); + // vtk mesh field writer factory template requires(utilities::same_dim_c) @@ -44,6 +59,14 @@ namespace mito::io::vtk { auto field_writer( std::string filename, const cloudT & cloud, const coordSystemT & coord_system); + // node field writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto field_writer( + std::string filename, const functionSpaceT & function_space, + const coordSystemT & coord_system); + #ifdef WITH_PARALLEL_VTK // parallel mesh writer alias template @@ -57,6 +80,13 @@ namespace mito::io::vtk { using parallel_cloud_writer_t = PointCloudVTKWriter>; + // parallel node writer alias + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + using parallel_node_writer_t = + NodeVTKWriter>; + // parallel vtk mesh writer factory template requires(utilities::same_dim_c) @@ -69,6 +99,14 @@ namespace mito::io::vtk { auto parallel_grid_writer( std::string filename, const cloudT & cloud, const coordSystemT & coord_system); + // parallel node writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto parallel_node_writer( + std::string filename, const functionSpaceT & function_space, + const coordSystemT & coord_system); + // parallel vtk mesh field writer factory template requires(utilities::same_dim_c) @@ -80,6 +118,15 @@ namespace mito::io::vtk { requires(utilities::same_dim_c) auto parallel_field_writer( std::string filename, const cloudT & cloud, const coordSystemT & coord_system); + + // parallel node field writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto parallel_field_writer( + std::string filename, const functionSpaceT & function_space, + const coordSystemT & coord_system); + #endif // WITH_PARALLEL_VTK } diff --git a/lib/mito/io/vtk/factories.h b/lib/mito/io/vtk/factories.h index a705ee288..59a131bca 100644 --- a/lib/mito/io/vtk/factories.h +++ b/lib/mito/io/vtk/factories.h @@ -25,6 +25,16 @@ namespace mito::io::vtk { return cloud_writer_t(filename, cloud, coord_system); } + // vtk node writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto grid_writer( + std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) + { + return node_writer_t(filename, node, coord_system); + } + // vtk mesh field writer factory template requires(utilities::same_dim_c) @@ -43,6 +53,17 @@ namespace mito::io::vtk { filename, cloud, coord_system); } + // vtk node field writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto field_writer( + std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) + { + return field_writer_t, coordSystemT>( + filename, node, coord_system); + } + #ifdef WITH_PARALLEL_VTK // parallel vtk mesh writer factory template @@ -62,6 +83,16 @@ namespace mito::io::vtk { return parallel_cloud_writer_t(filename, cloud, coord_system); } + // parallel vtk node writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto parallel_grid_writer( + std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) + { + return parallel_node_writer_t(filename, node, coord_system); + } + // parallel vtk mesh field writer factory template requires(utilities::same_dim_c) @@ -81,8 +112,19 @@ namespace mito::io::vtk { return field_writer_t, coordSystemT>( filename, cloud, coord_system); } -#endif // WITH_PARALLEL_VTK + // parallel vtk node field writer factory + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + requires(utilities::same_dim_c) + auto parallel_field_writer( + std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) + { + return field_writer_t, coordSystemT>( + filename, node, coord_system); + } + +#endif // WITH_PARALLEL_VTK } diff --git a/lib/mito/io/vtk/forward.h b/lib/mito/io/vtk/forward.h index e770c469f..c2b984fcc 100644 --- a/lib/mito/io/vtk/forward.h +++ b/lib/mito/io/vtk/forward.h @@ -28,6 +28,15 @@ namespace mito::io::vtk { && utilities::same_dim_c) class PointCloudVTKWriter; + // class node writer + template < + discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT, + class vtkGridWriterT> + requires( + utilities::same_dim_c + && utilities::same_dim_c) + class NodeVTKWriter; + // class field writer template class FieldVTKWriter; diff --git a/lib/mito/io/vtk/public.h b/lib/mito/io/vtk/public.h index 4f1eab1cf..d4756da54 100644 --- a/lib/mito/io/vtk/public.h +++ b/lib/mito/io/vtk/public.h @@ -24,6 +24,7 @@ #include "GridVTKWriter.h" #include "MeshVTKWriter.h" #include "PointCloudVTKWriter.h" +#include "NodeVTKWriter.h" #include "FieldVTKWriter.h" #ifdef WITH_PARALLEL_VTK #include "ParallelGridVTKWriter.h" diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 0ce7c885e..844e70865 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -157,14 +157,14 @@ TEST(Fem, PoissonSquare) // TOFIX: the solution should be assembled by the function space, which is aware of the // constraints and can populate the constrained nodes appropriately // the numerical solution mesh field on the mesh - auto solution = mito::discretization::mesh_field(mesh, "numerical solution"); + auto solution = + mito::discretization::nodal_field(function_space, "numerical solution"); // get the node map from the function space auto node_map = function_space.node_map(); - // fill information in mesh field + // fill information in nodal field for (auto & [node, value] : solution) { - auto discretization_node = node_map.at(node); // get the equation number of {node} - int eq = equation_map.at(discretization_node); + int eq = equation_map.at(node); if (eq != -1) { // read the solution at {eq} value = u[eq]; @@ -182,15 +182,21 @@ TEST(Fem, PoissonSquare) auto exact_solution = mito::discretization::mesh_field(mesh, coord_system, u_ex, "exact solution"); // write mesh to vtk file - auto writer = mito::io::vtk::field_writer("poisson_square", mesh, coord_system); + auto writer = mito::io::vtk::field_writer("poisson_square_data", mesh, coord_system); // sign {forcing} up with the writer writer.record(forcing); - // sign {solution} up with the writer - writer.record(solution); // sign {exact_solution} up with the writer writer.record(exact_solution); // write output file writer.write(); + + // write mesh to vtk file + auto writer_solution = + mito::io::vtk::field_writer("poisson_square_solution", function_space, coord_system); + // sign {solution} up with the writer + writer_solution.record(solution); + // write output file + writer_solution.write(); #endif // instantiate the quadrature rule From 02094301215b68aa1ac7c7cde3ebe2e19b0f0000 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 11:16:18 +0200 Subject: [PATCH 155/273] vtk: remove assumption that the number of points in the grid match the number of nodes in the discrete field attached to the grid MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Allow nodal fields to contain more nodes than those printed in the grid. This is the case, for example, for higher order discrete fields. Recall that for now the vtk writer writer only writes discretization nodes that are also mesh nodes. Later, we will implement higher order vtk writers with subconnectivities. --- lib/mito/io/vtk/FieldVTKWriter.h | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/lib/mito/io/vtk/FieldVTKWriter.h b/lib/mito/io/vtk/FieldVTKWriter.h index 311837adb..939d3f613 100644 --- a/lib/mito/io/vtk/FieldVTKWriter.h +++ b/lib/mito/io/vtk/FieldVTKWriter.h @@ -84,20 +84,17 @@ namespace mito::io::vtk { template auto _attach_field(const field_type & field, std::string fieldname) -> void { - // get the number of entries in the field - auto field_size = field.size(); - // get the grid auto & grid = _grid_writer.grid(); - // check the number of entries in the field equals the number of points in the grid - assert(field_size == grid->GetNumberOfPoints()); + // get the number of points in the grid + auto n_points = grid->GetNumberOfPoints(); // initialize a vtk array auto vtkArray = vtkSmartPointer::New(); vtkArray->SetName(fieldname.data()); vtkArray->SetNumberOfComponents(dim()); - vtkArray->SetNumberOfTuples(field_size); + vtkArray->SetNumberOfTuples(n_points); // populate the array if constexpr (mesh::mesh_c or discretization::function_space_c) { From 46ed6d47b11756e051da11d1f56f971bbd9064bf Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 11:17:43 +0200 Subject: [PATCH 156/273] discretization: nodal fields are now defined on all discretization nodes, not only on those that are also mesh nodes However, the vtk writer is, for now, able to only output the value of the field at those discretization nodes that are also mesh nodes. --- lib/mito/discretization/factories.h | 2 +- lib/mito/discretization/fem/utilities.h | 15 --------------- 2 files changed, 1 insertion(+), 16 deletions(-) diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index b59c04d68..28ed64b10 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -72,7 +72,7 @@ namespace mito::discretization { // get the nodes in the mesh std::unordered_set> nodes; - get_mesh_discretization_nodes(function_space, nodes); + get_discretization_nodes(function_space, nodes); // build a nodal field on the discretization nodes collected from the function space return nodal_field_t(nodes, name); diff --git a/lib/mito/discretization/fem/utilities.h b/lib/mito/discretization/fem/utilities.h index 27615c53a..6725a334b 100644 --- a/lib/mito/discretization/fem/utilities.h +++ b/lib/mito/discretization/fem/utilities.h @@ -24,21 +24,6 @@ namespace mito::discretization { return; } - // populate a container with a collection of all first order nodes in a function space (include - // only the mesh nodes, exclude the nodes of the subconnectivities) - template - inline auto get_mesh_discretization_nodes( - const functionSpaceT & function_space, nodesCollectionT & nodes) -> void - { - for (const auto & element : function_space.elements()) { - for (const auto & node : element.geometric_simplex().nodes()) { - nodes.insert(function_space.node_map().at(node)); - } - } - - // all done - return; - } } From d02e478eea0222de1cf4504b295a2a6aeaf680b2 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 12:29:59 +0200 Subject: [PATCH 157/273] discretization: major redesign of the components discrete system / linear system / solver / matrix solver In the new design, the linear system of equations is owned by the {DiscreteSystem} class and the matrix solver is owned by the {LinearSolver} class. Classes {DiscreteSystem} and {LinearSolver} are unaware of implementation details such as the representation of the matrix system of equations and of the matrix solver (petsc vs. alternatives). After chosing a (compatible) pair of matrix representation and matrix solver (e.g. {petsc::linear_system_t} and {petsc::ksp_t}), the user instantiates the {DiscreteSystem} first and then a {LinearSolver} on top of that {DiscreteSystem}. When the {LinearSolver} solves the linear system of equations (e.g. {PETScLinearSystem}) through a matrix solver (e.g. {PETScKrylovSolver}), it has the {DiscreteSystem} read the solution from the {PETScLinearSystem}. After the {solve} call, the {LinearSolver} can be safely destroyed as the solution lies with the {DiscreteSystem}. --- lib/mito/discretization/DiscreteSystem.h | 296 ++++++++++++++++-- lib/mito/discretization/api.h | 9 +- lib/mito/discretization/factories.h | 6 +- lib/mito/discretization/forward.h | 2 +- lib/mito/discretization/public.h | 6 +- .../backend/petsc/PETScKrylovSolver.cc | 8 +- .../backend/petsc/PETScKrylovSolver.h | 2 +- lib/mito/public.h | 1 + lib/mito/solvers/LinearSolver.h | 75 +++++ lib/mito/solvers/api.h | 22 ++ lib/mito/solvers/externals.h | 15 + lib/mito/solvers/factories.h | 22 ++ lib/mito/solvers/forward.h | 18 ++ lib/mito/solvers/public.h | 26 ++ tests/mito.lib/discretization/poisson.cc | 228 ++++---------- 15 files changed, 530 insertions(+), 206 deletions(-) create mode 100644 lib/mito/solvers/LinearSolver.h create mode 100644 lib/mito/solvers/api.h create mode 100644 lib/mito/solvers/externals.h create mode 100644 lib/mito/solvers/factories.h create mode 100644 lib/mito/solvers/forward.h create mode 100644 lib/mito/solvers/public.h diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 568819ecf..e151aeabd 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -9,26 +9,71 @@ namespace mito::discretization { - template + // TOFIX: for now the discrete system is one per function space. We should figure out a way to + // extend the design to the case that there are multiple finite element discretizations that + // end up on the same linear system. + + template class DiscreteSystem { private: // the function space type using function_space_type = functionSpaceT; + // the element type + using element_type = typename function_space_type::element_type; + // the linear system type + using linear_system_type = linearSystemT; + // the label type + using label_type = std::string; // the type of node using node_type = typename function_space_type::discretization_node_type; // QUESTION: is std::map the best choice for {equation_map_type}? // the equation map type (map associating an equation number to each node degree of freedom) using equation_map_type = std::map; + // TOFIX: what if the solution is not a scalar field? Generalize to different types of + // solutions + // the solution field type + using solution_field_type = tensor::scalar_t; + // the nodal field type + using nodal_field_type = nodal_field_t; + // TOFIX: rename to {n_element_nodes} + // the number of nodes per element + static constexpr int n_nodes = element_type::n_nodes; + // the elementary matrix type + using elementary_matrix_type = tensor::matrix_t; + // the elementary vector type + using elementary_vector_type = tensor::vector_t; + // the type of the lhs assembly block + using lhs_assembly_block_type = + blocks::assembly_block_t; + // a collection of lhs assembly blocks + using lhs_assembly_blocks_type = std::vector; + // the type of the rhs assembly block + using rhs_assembly_block_type = + blocks::assembly_block_t; + // a collection of rhs assembly blocks + using rhs_assembly_blocks_type = std::vector; public: // the default constructor - constexpr DiscreteSystem(const function_space_type & function_space) : + constexpr DiscreteSystem( + const function_space_type & function_space, const label_type & label) : _function_space(function_space), _equation_map(), - _n_equations(0) + _solution_field(nodal_field(function_space, label + ".solution")), + _linear_system(label) { - _build_equation_map(); + // make a channel + journal::info_t channel("discretization.discrete_system"); + + // build the equations map and get the number of equations + _n_equations = _build_equation_map(); + + // print the number of equations + channel << "Number of equations: " << _n_equations << journal::endl; + + // all done + return; } // destructor @@ -47,8 +92,8 @@ namespace mito::discretization { constexpr DiscreteSystem & operator=(DiscreteSystem &&) noexcept = delete; private: - // build the equation map - void _build_equation_map() + // build the equation map and return the number of equations + auto _build_equation_map() -> int { // make a channel journal::info_t channel("discretization.discrete_system"); @@ -95,36 +140,247 @@ namespace mito::discretization { } } - // the number of equations - _n_equations = equation; - - // print the number of equations - channel << "Number of equations: " << _n_equations << journal::endl; + // return the number of equations + return equation; } public: - // accessor to the equation map - constexpr auto equation_map() const noexcept -> const equation_map_type & + // accessor to the linear system + constexpr auto linear_system() noexcept -> linear_system_type & { return _linear_system; } + + // add a left hand side assembly block + constexpr auto add_lhs_block(const lhs_assembly_block_type & block) -> void + { + // add the block to the collection + _lhs_assembly_blocks.push_back(&block); + + // all done + return; + } + + // add a right hand side assembly block + constexpr auto add_rhs_block(const rhs_assembly_block_type & block) -> void + { + // add the block to the collection + _rhs_assembly_blocks.push_back(&block); + + // all done + return; + } + + // assemble the discrete system + constexpr auto assemble() -> void + { + // get the number of equations + int N_equations = _linear_system.n_equations(); + + // QUESTION: can we flip the element and block loops? What is the expected layout in + // memory? + // + // loop on all the cells of the mesh + for (const auto & element : _function_space.elements()) { + // instantiate the elementary matrix + auto elementary_matrix = elementary_matrix_type(); + // loop on the left hand side assembly blocks + for (const auto & block : _lhs_assembly_blocks) { + // compute the elementary contribution of the block + auto matrix_block = block->compute(element); + // add the elementary contribution to the elementary matrix + elementary_matrix += matrix_block; + } + + // instantiate the elementary vector + auto elementary_vector = elementary_vector_type(); + // loop on the right hand side assembly blocks + for (const auto & block : _rhs_assembly_blocks) { + // compute the elementary contribution of the block + auto vector_block = block->compute(element); + // add the elementary contribution to the elementary vector + elementary_vector += vector_block; + } + + // assemble the elementary blocks into the linear system of equations + mito::tensor::constexpr_for_1([&]() { + // get the a-th discretization node of the element + const auto & node_a = element.connectivity()[a]; + // get the equation number of {node_a} + int eq_a = _equation_map.at(node_a); + assert(eq_a < N_equations); + // non boundary nodes + if (eq_a != -1) { + // assemble the value in the right hand side + _linear_system.add_rhs_value(eq_a, elementary_vector[{ a }]); + // loop on the b-th discretization node of the element + mito::tensor::constexpr_for_1([&]() { + // get the b-th discretization node of the element + const auto & node_b = element.connectivity()[b]; + // get the equation number of {node_b} + int eq_b = _equation_map.at(node_b); + assert(eq_b < N_equations); + // non boundary nodes + if (eq_b != -1) { + // assemble the value in the stiffness matrix + _linear_system.add_matrix_value( + eq_a, eq_b, elementary_matrix[{ a, b }]); + } + }); + } + }); + } + } + + // read the solution nodal field + constexpr void read_solution() { - return _equation_map; + // get the number of equations + int N_equations = _linear_system.n_equations(); + + // read the solution + auto u = std::vector(N_equations); + _linear_system.get_solution(u); + + // TODO: ask the function space to populate the constrained nodes appropriately + + // get the node map from the function space + auto node_map = _function_space.node_map(); + // fill information in nodal field + for (auto & [node, value] : _solution_field) { + // get the equation number of {node} + int eq = _equation_map.at(node); + if (eq != -1) { + // read the solution at {eq} + value = u[eq]; + } + } + + // all done + return; + } + + // accessor to the solution nodal field + constexpr auto solution() const noexcept -> const nodal_field_type & + { + return _solution_field; } // accessor to the number of equations constexpr auto n_equations() const noexcept -> int { return _n_equations; } + // compute the L2 norm of the solution + template + constexpr auto compute_l2_error(const fields::field_c auto & u_exact) const + -> mito::tensor::scalar_t + { + // initialize the norm + auto norm = mito::tensor::scalar_t(0.0); + + // helper lambda to assemble the solution on a given element + constexpr auto _assemble_element_solution = []( + const auto & element, + const auto & _solution_field, + mito::tensor::integer_sequence) { + // assemble the solution field from the shape functions + return ( + (element.template shape() * _solution_field(element.connectivity()[a])) + + ...); + }; + + // loop on all the cells of the mesh + for (const auto & element : _function_space.elements()) { + // assemble the solution field on this element + auto u_numerical = _assemble_element_solution( + element, _solution_field, mito::tensor::make_integer_sequence()); + // assemble the elementary error field as a function of the barycentric coordinates + auto u_error = u_numerical - u_exact.function()(element.parametrization()); + + // compute the elementary contribution to the L2 norm + norm += + blocks::l2_norm_block(u_error).compute(element); + } + + return std::sqrt(norm); + } + + // compute the H1 norm of the solution + template + constexpr auto compute_h1_error(const fields::field_c auto & u_exact) const + -> mito::tensor::scalar_t + { + // initialize the norm + auto norm = mito::tensor::scalar_t(0.0); + + // QUESTION: is there a proper place to put this method? Perhaps this belongs to the + // isoparametric element class? + // helper lambda to assemble the solution on a given element + constexpr auto _assemble_element_solution = []( + const auto & element, + const auto & _solution_field, + mito::tensor::integer_sequence) { + // assemble the solution field from the shape functions + return ( + (element.template shape() * _solution_field(element.connectivity()[a])) + + ...); + }; + + // TOFIX: we should deduce this from {_assemble_element_solution} + // helper lambda to assemble the solution on a given element + constexpr auto _assemble_element_solution_gradient = + []( + const auto & element, const auto & _solution_field, + mito::tensor::integer_sequence) { + // assemble the solution field from the shape functions + return ( + (element.template gradient() + * _solution_field(element.connectivity()[a])) + + ...); + }; + + // loop on all the cells of the mesh + for (const auto & element : _function_space.elements()) { + // assemble the solution field on this element + auto u_numerical = _assemble_element_solution( + element, _solution_field, mito::tensor::make_integer_sequence()); + // assemble the elementary error field as a function of the barycentric coordinates + auto u_error = u_numerical - u_exact.function()(element.parametrization()); + // + auto u_numerical_gradient = _assemble_element_solution_gradient( + element, _solution_field, mito::tensor::make_integer_sequence()); + // assemble the elementary error gradient as a function of the barycentric + // coordinates + auto u_error_gradient = + u_numerical_gradient + - fields::gradient(u_exact).function()(element.parametrization()); + // compute the elementary contributions to the H1 norm + norm += + blocks::l2_norm_block(u_error).compute(element) + + blocks::l2_norm_block(u_error_gradient) + .compute(element); + } + + return std::sqrt(norm); + } + private: - // QUESTION: do we need the function space to be an attribute or do we only need it in the - // constructor? Also, for sure we should have an attribute that is aware of the 'bricks' to - // be assembled in the system. Either these bricks should be aware of the function space, or - // the function space should know how to discretize the bricks with its own shape functions // a const reference to the function space const function_space_type & _function_space; // the equation map equation_map_type _equation_map; - // the number of equations - int _n_equations; + // the solution nodal field + nodal_field_type _solution_field; + + // the linear system of equations + linear_system_type _linear_system; + + // the number of equations in the linear system + int _n_equations = 0; + + // the collection of left hand side assembly blocks + lhs_assembly_blocks_type _lhs_assembly_blocks; + + // the collection of right hand side assembly blocks + rhs_assembly_blocks_type _rhs_assembly_blocks; }; } // namespace mito diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index f510c36e4..742f4a1f9 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -59,12 +59,13 @@ namespace mito::discretization { constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); // discrete system alias - template - using discrete_system_t = DiscreteSystem; + template + using discrete_system_t = DiscreteSystem; // discrete system factory - template - constexpr auto discrete_system(const functionSpaceT & function_space); + template + constexpr auto discrete_system( + const functionSpaceT & function_space, const std::string & label); } diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 28ed64b10..284744a01 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -102,10 +102,10 @@ namespace mito::discretization { } // discrete system factory - template - constexpr auto discrete_system(const functionSpaceT & function_space) + template + constexpr auto discrete_system(const functionSpaceT & function_space, const std::string & label) { - return discrete_system_t(function_space); + return discrete_system_t(function_space, label); } } diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index 146c6b1e2..a2c8f3cc1 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -30,7 +30,7 @@ namespace mito::discretization { }; // class discrete system - template + template class DiscreteSystem; } diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 05a9b3ba2..6bf453d21 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -16,6 +16,9 @@ // published types factories; this is the file you are looking for... #include "api.h" +// blocks implementation +#include "blocks.h" + // classes implementation #include "DiscreteField.h" #include "DiscretizationNode.h" @@ -25,9 +28,6 @@ // finite elements implementation #include "fem.h" -// blocks implementation -#include "blocks.h" - // factories implementation #include "factories.h" diff --git a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc index 928f18b79..11af9e009 100644 --- a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc +++ b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc @@ -22,8 +22,11 @@ mito::matrix_solvers::petsc::PETScKrylovSolver::~PETScKrylovSolver() {} // create the Krylov solver auto -mito::matrix_solvers::petsc::PETScKrylovSolver::create() -> void +mito::matrix_solvers::petsc::PETScKrylovSolver::create(int n_equations) -> void { + // create the linear system and allocate the memory + _linear_system.create(n_equations); + // create the Krylov solver PetscCallVoid(KSPCreate(PETSC_COMM_WORLD, &_ksp)); PetscCallVoid(KSPSetOperators(_ksp, _linear_system._matrix, _linear_system._matrix)); @@ -37,6 +40,9 @@ mito::matrix_solvers::petsc::PETScKrylovSolver::create() -> void auto mito::matrix_solvers::petsc::PETScKrylovSolver::destroy() -> void { + // free the memory of the linear system + _linear_system.destroy(); + // destroy the Krylov solver PetscCallVoid(KSPDestroy(&_ksp)); diff --git a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h index bce47ef3a..c7c05d75c 100644 --- a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h +++ b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h @@ -29,7 +29,7 @@ namespace mito::matrix_solvers::petsc { public: // create the Krylov solver - auto create() -> void; + auto create(int) -> void; // destroy the Krylov solver auto destroy() -> void; diff --git a/lib/mito/public.h b/lib/mito/public.h index 5a2ac7f59..34afa4d55 100644 --- a/lib/mito/public.h +++ b/lib/mito/public.h @@ -26,6 +26,7 @@ #include "topology.h" #include "utilities.h" #include "matrix_solvers.h" +#include "solvers.h" // end of file diff --git a/lib/mito/solvers/LinearSolver.h b/lib/mito/solvers/LinearSolver.h new file mode 100644 index 000000000..610b1947f --- /dev/null +++ b/lib/mito/solvers/LinearSolver.h @@ -0,0 +1,75 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::solvers { + + template + // TODO: require that the {matrixSolverT} is compatible with the linear system in + // {discreteSystemT} + class LinearSolver { + + private: + // the discrete system type + using discrete_system_type = discreteSystemT; + // the matrix solver type + using matrix_solver_type = matrixSolverT; + // the options type + using options_type = std::string; + + public: + // the default constructor + constexpr LinearSolver(discrete_system_type & discrete_system) : + _discrete_system(discrete_system), + _matrix_solver(_discrete_system.linear_system()) + {} + + // TOFIX: the need to explicitly call {create} just holds for petsc matrix solvers... + // create the matrix solver + auto create() -> void { return _matrix_solver.create(_discrete_system.n_equations()); } + + // destroy the matrix solver + auto destroy() -> void { return _matrix_solver.destroy(); } + + // set matrix solver options + auto set_options(const options_type & options) -> void + { + return _matrix_solver.set_options(options); + } + + // solve the matrix system + auto solve() -> void + { + // assemble the discrete system + _discrete_system.assemble(); + + // solve the linear system + _matrix_solver.solve(); + + // have the discrete system read the solution + _discrete_system.read_solution(); + + // all done + return; + } + + // print the matrix system + auto print() const -> void { return _matrix_solver.print(); } + + private: + // the discrete system + discrete_system_type & _discrete_system; + // the underlying matrix solver implementation + matrix_solver_type _matrix_solver; + }; + + +} // namespace mito::discretization + + +// end of file diff --git a/lib/mito/solvers/api.h b/lib/mito/solvers/api.h new file mode 100644 index 000000000..24c38dfd2 --- /dev/null +++ b/lib/mito/solvers/api.h @@ -0,0 +1,22 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::solvers { + + // linear solver alias + template + using linear_solver_t = LinearSolver; + + // linear solver factory + template + constexpr auto linear_solver(discreteSystemT & discrete_system); +} + + +// end of file diff --git a/lib/mito/solvers/externals.h b/lib/mito/solvers/externals.h new file mode 100644 index 000000000..8d07d985d --- /dev/null +++ b/lib/mito/solvers/externals.h @@ -0,0 +1,15 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// support +#include "../discretization.h" +#include "../journal.h" + + +// end of file diff --git a/lib/mito/solvers/factories.h b/lib/mito/solvers/factories.h new file mode 100644 index 000000000..048cac48f --- /dev/null +++ b/lib/mito/solvers/factories.h @@ -0,0 +1,22 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::solvers { + + // linear factory + template + constexpr auto linear_solver(discreteSystemT & discrete_system) + { + return linear_solver_t(discrete_system); + } + +} + + +// end of file diff --git a/lib/mito/solvers/forward.h b/lib/mito/solvers/forward.h new file mode 100644 index 000000000..9841e391d --- /dev/null +++ b/lib/mito/solvers/forward.h @@ -0,0 +1,18 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::solvers { + + template + class LinearSolver; + +} + + +// end of file diff --git a/lib/mito/solvers/public.h b/lib/mito/solvers/public.h new file mode 100644 index 000000000..4022c87af --- /dev/null +++ b/lib/mito/solvers/public.h @@ -0,0 +1,26 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// external packages +#include "externals.h" + +// get the forward declarations +#include "forward.h" + +// published type factories; this is the file you are looking for... +#include "api.h" + +// classes implementation +#include "LinearSolver.h" + +// factories implementation +#include "factories.h" + + +// end of file diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 844e70865..248cba3c1 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -24,14 +24,25 @@ constexpr int degree = 2; // typedef for a finite element using finite_element_t = mito::discretization::isoparametric_simplex_t; +// typedef for a linear system of equations +using linear_system_t = mito::matrix_solvers::petsc::linear_system_t; +// typedef for a matrix solver +using matrix_solver_t = mito::matrix_solvers::petsc::ksp_t; + +// NOTE: component -> projection // the function extracting the x component of a 2D vector constexpr auto x = mito::functions::component; // the function extracting the y component of a 2D vector constexpr auto y = mito::functions::component; +// TODO: add unit tests for blocks individually + TEST(Fem, PoissonSquare) { + // initialize PETSc + mito::petsc::initialize(); + // make a channel journal::info_t channel("tests.poisson_square"); @@ -63,22 +74,20 @@ TEST(Fem, PoissonSquare) // TOFIX: function space should be template with respect to the finite element type auto function_space = mito::discretization::function_space(manifold, constraints); + // TODO: all top level instances have names. Name should be the first argument. Then we can use + // names in the configuration file and in the hdf5 file. Check libuuid vs. leading namestring. + // // the discrete system - auto discrete_system = mito::discretization::discrete_system(function_space); - const auto & equation_map = discrete_system.equation_map(); - int N_equations = discrete_system.n_equations(); - - // TODO: blocks should be signed up with the discrete system. Then the loop on the elements - // should be handled by the system + auto discrete_system = + mito::discretization::discrete_system(function_space, "mysystem"); - // initialize PETSc - mito::petsc::initialize(); - - // create a PETSc linear system of equations and a Krylov solver - auto linear_system = mito::matrix_solvers::petsc::linear_system("mysystem"); - linear_system.create(N_equations); - auto solver = mito::matrix_solvers::petsc::ksp(linear_system); + // TODO: {linear_system} is only needed in the solver, so we can skip this step + auto solver = mito::solvers::linear_solver(discrete_system); solver.create(); + + // QUESTION: do we need a method to set the options for the solver? Can this go in the + // constructor or in the create method? + // in the python layer, this will go in the configuration file solver.set_options("-ksp_type preonly -pc_type cholesky"); // a grad-grad matrix block @@ -95,86 +104,45 @@ TEST(Fem, PoissonSquare) auto fem_rhs_block = mito::discretization::blocks::source_term_block(f); - // the number of nodes per element - constexpr int n_nodes = - mito::utilities::base_type::element_type::n_nodes; - - // loop on all the cells of the mesh - for (const auto & element : function_space.elements()) { - - // assemble the elementary stiffness matrix - auto elementary_stiffness_matrix = fem_lhs_block.compute(element); - - // populate the linear system of equations - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // get the equation number of {node_a} - int eq_a = equation_map.at(node_a); - assert(eq_a < N_equations); - if (eq_a != -1) { - mito::tensor::constexpr_for_1([&]() { - // get the b-th discretization node of the element - const auto & node_b = element.connectivity()[b]; - // get the equation number of {node_b} - int eq_b = equation_map.at(node_b); - assert(eq_b < N_equations); - // non boundary nodes - if (eq_b != -1) { - // assemble the value in the stiffness matrix - linear_system.add_matrix_value( - eq_a, eq_b, elementary_stiffness_matrix[{ a, b }]); - } - }); - } - }); - - // assemble the elementary right hand side - auto elementary_rhs = fem_rhs_block.compute(element); - - // populate the right hand side - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // get the equation number of {node_a} - int eq_a = equation_map.at(node_a); - assert(eq_a < N_equations); - // non boundary nodes - if (eq_a != -1) { - // assemble the value in the right hand side - linear_system.add_rhs_value(eq_a, elementary_rhs[{ a }]); - } - }); - } + // TODO: + // // monolithic discretization matrix = [A, B; C, D] + // auto weakform_lhs = fem_lhs_block; + // auto weakform_rhs = fem_rhs_block; + // auto weakform = weakform(weakform_lhs, weakform_rhs); + // discrete_system.set_weak_form(weakform); + + // add the blocks to the discrete system + discrete_system.add_lhs_block(fem_lhs_block); + discrete_system.add_rhs_block(fem_rhs_block); + // solve the linear system solver.solve(); - solver.destroy(); - // read the solution - auto u = std::vector(N_equations); - linear_system.get_solution(u); - - // TOFIX: the solution should be assembled by the function space, which is aware of the - // constraints and can populate the constrained nodes appropriately - // the numerical solution mesh field on the mesh - auto solution = - mito::discretization::nodal_field(function_space, "numerical solution"); - // get the node map from the function space - auto node_map = function_space.node_map(); - // fill information in nodal field - for (auto & [node, value] : solution) { - // get the equation number of {node} - int eq = equation_map.at(node); - if (eq != -1) { - // read the solution at {eq} - value = u[eq]; - } - } + // free the solver + solver.destroy(); // the exact solution field auto u_ex = mito::fields::field( mito::functions::sin(std::numbers::pi * x) * mito::functions::sin(std::numbers::pi * y)); + // compute the L2 error + auto error_L2 = discrete_system.compute_l2_error(u_ex); + + // report + channel << "L2 error: " << error_L2 << journal::endl; + + // check that the l2 error is reasonable + EXPECT_TRUE(error_L2 < 0.02); + + // compute the H1 error + auto error_H1 = discrete_system.compute_h1_error(u_ex); + + // report + channel << "H1 error: " << error_H1 << journal::endl; + + // check that the h1 error is reasonable + EXPECT_TRUE(error_H1 < 0.02); + #ifdef WITH_VTK // the forcing term mesh field on the mesh (for visualization) auto forcing = mito::discretization::mesh_field(mesh, coord_system, f, "forcing term"); @@ -190,6 +158,8 @@ TEST(Fem, PoissonSquare) // write output file writer.write(); + // get the solution field + const auto & solution = discrete_system.solution(); // write mesh to vtk file auto writer_solution = mito::io::vtk::field_writer("poisson_square_solution", function_space, coord_system); @@ -199,94 +169,6 @@ TEST(Fem, PoissonSquare) writer_solution.write(); #endif - // instantiate the quadrature rule - auto quadrature_rule = quadrature_rule_t(); - - // compute the L2 error - auto error_L2 = 0.0; - // loop on all the cells of the mesh - for (const auto & element : function_space.elements()) { - // loop on the quadrature points - mito::tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point - constexpr auto xi = quadrature_rule.point(q); - // jacobian of the element at {xi} - auto jacobian = mito::tensor::determinant(element.jacobian()(xi)); - // composition of the exact solution with the parametrization of the element - auto u_ex_local = u_ex.function()(element.parametrization()); - // assemble the numerical solution at {xi} - auto u_numerical = 0.0; - // loop on all the shape functions - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // evaluate the a-th shape function at {xi} - auto phi_a = element.shape()(xi); - // get the equation number of {node_a} - int eq = equation_map.at(node_a); - if (eq != -1) { - // get the numerical solution at {xi} - u_numerical += u[eq] * phi_a; - } - }); - // get the error - error_L2 += (u_ex_local(xi) - u_numerical) * (u_ex_local(xi) - u_numerical) - * quadrature_rule.weight(q) * jacobian; - }); - } - error_L2 = std::sqrt(error_L2); - - // report - channel << "L2 error: " << error_L2 << journal::endl; - - // check that the l2 error is reasonable - EXPECT_TRUE(error_L2 < 0.02); - - // compute the H1 error - auto error_H1 = 0.0; - // loop on all the cells of the mesh - for (const auto & element : function_space.elements()) { - mito::tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point - auto xi = quadrature_rule.point(q); - // jacobian of the element at {xi} - - auto jacobian = mito::tensor::determinant(element.jacobian()(xi)); - // composition of the exact solution gradient with the parametrization of the element - auto grad_u_ex_local = - mito::fields::gradient(u_ex).function()(element.parametrization()); - // assemble the numerical solution gradient at {xi} - auto grad_u_numerical = mito::tensor::vector_t<2>{ 0.0, 0.0 }; - // loop on all the shape functions - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // evaluate the a-th shape function gradient at {xi} - auto dphi_a = element.gradient()(xi); - // get the equation number of {node_a} - int eq = equation_map.at(node_a); - if (eq != -1) { - // get the numerical solution gradient at {xi} - grad_u_numerical += u[eq] * dphi_a; - } - }); - // get the error - auto diff = grad_u_ex_local(xi) - grad_u_numerical; - error_H1 += mito::tensor::dot(diff, diff) * quadrature_rule.weight(q) * jacobian; - }); - } - error_H1 = std::sqrt(error_H1); - - // report - channel << "H1 error: " << error_H1 << journal::endl; - - // check that the h1 error is reasonable - EXPECT_TRUE(error_H1 < 0.02); - - // destroy the linear system - linear_system.destroy(); - - // TOFIX: move this to the class owning the petsc instance // finalize PETSc mito::petsc::finalize(); } From 844b3a6da1a4c7510fa66b01e9b249b0c97aaa4c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 12:32:39 +0200 Subject: [PATCH 158/273] vtk: have {FieldVTKWriter} give a runtime error if method {_attach_field} does not know how to populate the VTK array representing the field to be written --- lib/mito/io/vtk/FieldVTKWriter.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/mito/io/vtk/FieldVTKWriter.h b/lib/mito/io/vtk/FieldVTKWriter.h index 939d3f613..9ca3cb3c9 100644 --- a/lib/mito/io/vtk/FieldVTKWriter.h +++ b/lib/mito/io/vtk/FieldVTKWriter.h @@ -116,10 +116,17 @@ namespace mito::io::vtk { // get the index corresponding to the current point vtkArray->SetTuple(index++, begin(field(point))); } + } else { + // something went wrong: make a channel and report an error + journal::error_t channel("mito.field_vtk_writer.attach_field"); + channel << "unkown {grid_type}" << journal::endl; } // insert array into output grid grid->GetPointData()->AddArray(vtkArray); + + // all done + return; } public: From 428a2493815f4eecefba69582e083007481e01cd Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 12:47:34 +0200 Subject: [PATCH 159/273] solvers: consistency fix Adjusted test to changes to the petsc solvers coming from rev. d02e478e. --- tests/mito.lib/solvers/petsc_ksp.cc | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/tests/mito.lib/solvers/petsc_ksp.cc b/tests/mito.lib/solvers/petsc_ksp.cc index 272a05f52..440c011fd 100644 --- a/tests/mito.lib/solvers/petsc_ksp.cc +++ b/tests/mito.lib/solvers/petsc_ksp.cc @@ -15,11 +15,10 @@ TEST(Solvers, PETScKSPSolver) // instantiate a PETSc linear system of size {N} auto linear_system = mito::matrix_solvers::petsc::linear_system("mysystem"); - linear_system.create(N); // instantiate a PETSc Krylov solver for the linear system auto solver = mito::matrix_solvers::petsc::ksp(linear_system); - solver.create(); + solver.create(N); solver.set_options("-ksp_monitor"); // set matrix and right-hand side entries @@ -53,9 +52,6 @@ TEST(Solvers, PETScKSPSolver) EXPECT_DOUBLE_EQ(x[8], 9.0); EXPECT_DOUBLE_EQ(x[9], 5.0); - // destroy the system - linear_system.destroy(); - // destroy the solver solver.destroy(); From 7bf64213ca46ea3e22a630905ad8509d9ed663e7 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 12:48:25 +0200 Subject: [PATCH 160/273] solvers: consistency fix Adjusted test to changes to the petsc solvers coming from rev. d72de993. --- .cmake/mito_tests_mito_lib.cmake | 4 ++-- .../{solvers => matrix_solvers}/petsc_initialize_finalize.cc | 0 tests/mito.lib/{solvers => matrix_solvers}/petsc_ksp.cc | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/mito.lib/{solvers => matrix_solvers}/petsc_initialize_finalize.cc (100%) rename tests/mito.lib/{solvers => matrix_solvers}/petsc_ksp.cc (100%) diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index fb5c98a42..8b77ba19a 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -71,8 +71,8 @@ endif() # solvers if(WITH_PETSC) - mito_test_driver(tests/mito.lib/solvers/petsc_initialize_finalize.cc) - mito_test_driver(tests/mito.lib/solvers/petsc_ksp.cc) + mito_test_driver(tests/mito.lib/matrix_solvers/petsc_initialize_finalize.cc) + mito_test_driver(tests/mito.lib/matrix_solvers/petsc_ksp.cc) endif() # tensor diff --git a/tests/mito.lib/solvers/petsc_initialize_finalize.cc b/tests/mito.lib/matrix_solvers/petsc_initialize_finalize.cc similarity index 100% rename from tests/mito.lib/solvers/petsc_initialize_finalize.cc rename to tests/mito.lib/matrix_solvers/petsc_initialize_finalize.cc diff --git a/tests/mito.lib/solvers/petsc_ksp.cc b/tests/mito.lib/matrix_solvers/petsc_ksp.cc similarity index 100% rename from tests/mito.lib/solvers/petsc_ksp.cc rename to tests/mito.lib/matrix_solvers/petsc_ksp.cc From 9fc55ef9bfd809ea857946d1d5aeea821e8b4155 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 13:31:04 +0200 Subject: [PATCH 161/273] discretization: clean up old {TODO} --- tests/mito.lib/discretization/poisson.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 248cba3c1..d812d1d55 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -81,7 +81,7 @@ TEST(Fem, PoissonSquare) auto discrete_system = mito::discretization::discrete_system(function_space, "mysystem"); - // TODO: {linear_system} is only needed in the solver, so we can skip this step + // instantiate a linear solver for the discrete system auto solver = mito::solvers::linear_solver(discrete_system); solver.create(); From 55baeddd7b2b7a17b6c530ff20e82df17d7afcc9 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 13:50:05 +0200 Subject: [PATCH 162/273] discretization: formatting edits --- tests/mito.lib/discretization/poisson.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index d812d1d55..cc14f5b92 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -127,19 +127,15 @@ TEST(Fem, PoissonSquare) // compute the L2 error auto error_L2 = discrete_system.compute_l2_error(u_ex); - // report channel << "L2 error: " << error_L2 << journal::endl; - // check that the l2 error is reasonable EXPECT_TRUE(error_L2 < 0.02); // compute the H1 error auto error_H1 = discrete_system.compute_h1_error(u_ex); - // report channel << "H1 error: " << error_H1 << journal::endl; - // check that the h1 error is reasonable EXPECT_TRUE(error_H1 < 0.02); From 3f4990940375ed2cc78179ae976ab8551399096a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 14:20:52 +0200 Subject: [PATCH 163/273] discretization/blocks: bugfix Make sure elementary contributions are correctly initialized to zero in relase mode too. --- lib/mito/discretization/blocks/L2NormBlock.h | 2 +- lib/mito/discretization/blocks/SourceTermBlock.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/blocks/L2NormBlock.h b/lib/mito/discretization/blocks/L2NormBlock.h index ac12ed588..d2e724ee4 100644 --- a/lib/mito/discretization/blocks/L2NormBlock.h +++ b/lib/mito/discretization/blocks/L2NormBlock.h @@ -43,7 +43,7 @@ namespace mito::discretization::blocks { constexpr int n_quads = quadrature_rule_type::npoints; // the elementary contribution to the L2 norm - elementary_block_type elementary_contribution; + auto elementary_contribution = elementary_block_type{}; // loop on the quadrature points tensor::constexpr_for_1([&]() { diff --git a/lib/mito/discretization/blocks/SourceTermBlock.h b/lib/mito/discretization/blocks/SourceTermBlock.h index 7e214b900..77d1cd16b 100644 --- a/lib/mito/discretization/blocks/SourceTermBlock.h +++ b/lib/mito/discretization/blocks/SourceTermBlock.h @@ -45,7 +45,7 @@ namespace mito::discretization::blocks { constexpr int n_quads = quadrature_rule_type::npoints; // the elementary rhs - elementary_block_type elementary_rhs; + elementary_block_type elementary_rhs{}; // loop on the quadrature points tensor::constexpr_for_1([&]() { From e988805fb17d32a02e5f1b9cbf8f51df5d824a3b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 14:24:26 +0200 Subject: [PATCH 164/273] consistency edits Initialize all tensor objects with brace initialization instead of parentheses. --- .../mito.lib/integration/integration.cc | 2 +- lib/mito/discretization/DiscreteSystem.h | 4 +- lib/mito/materials/MaterialConsistencyTest.h | 2 +- lib/mito/quadrature/Integrator.h | 2 +- .../discretization/isoparametric_triangle.cc | 38 ++++++++++--------- tests/mito.lib/functions/algebra.cc | 2 +- 6 files changed, 26 insertions(+), 24 deletions(-) diff --git a/benchmarks/mito.lib/integration/integration.cc b/benchmarks/mito.lib/integration/integration.cc index 06f3e0e5f..f21c564a4 100644 --- a/benchmarks/mito.lib/integration/integration.cc +++ b/benchmarks/mito.lib/integration/integration.cc @@ -76,7 +76,7 @@ main() auto integrator = mito::quadrature::integrator(manifold); auto result = integrator.integrate(f); - auto exact = mito::tensor::scalar_t(0.9460830607878437); + auto exact = mito::tensor::scalar_t{ 0.9460830607878437 }; channel << "Integration of cos(x*y): Result = " << result << ", Error = " << std::fabs(result - exact) << journal::endl; diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index e151aeabd..47d9a31fc 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -272,7 +272,7 @@ namespace mito::discretization { -> mito::tensor::scalar_t { // initialize the norm - auto norm = mito::tensor::scalar_t(0.0); + auto norm = mito::tensor::scalar_t{ 0.0 }; // helper lambda to assemble the solution on a given element constexpr auto _assemble_element_solution = []( @@ -307,7 +307,7 @@ namespace mito::discretization { -> mito::tensor::scalar_t { // initialize the norm - auto norm = mito::tensor::scalar_t(0.0); + auto norm = mito::tensor::scalar_t{ 0.0 }; // QUESTION: is there a proper place to put this method? Perhaps this belongs to the // isoparametric element class? diff --git a/lib/mito/materials/MaterialConsistencyTest.h b/lib/mito/materials/MaterialConsistencyTest.h index f9662eb95..461765dc2 100644 --- a/lib/mito/materials/MaterialConsistencyTest.h +++ b/lib/mito/materials/MaterialConsistencyTest.h @@ -32,7 +32,7 @@ class mito::materials::MaterialConsistencyTest { auto F_perturbed = F; // initialize the energy increment tensor - auto energy_increment = mito::tensor::matrix_t<3>(); + auto energy_increment = mito::tensor::matrix_t<3>{}; // for each component of the deformation gradient for (int i = 0; i < 3; i++) { diff --git a/lib/mito/quadrature/Integrator.h b/lib/mito/quadrature/Integrator.h index dc1b0da1e..27af46a46 100644 --- a/lib/mito/quadrature/Integrator.h +++ b/lib/mito/quadrature/Integrator.h @@ -58,7 +58,7 @@ namespace mito::quadrature { auto integrate(const fields::scalar_field_c auto & f) const -> tensor::scalar_t { - auto result = tensor::scalar_t(0.0); + auto result = tensor::scalar_t{ 0.0 }; // assemble elementary contributions for (const auto & cell : _manifold.elements()) { for (auto q = 0; q < Q; ++q) { diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index e1e956878..30c2b3ccb 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -97,7 +97,7 @@ test_stiffness_matrix( constexpr int n_nodes = elementT::n_nodes; // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix - auto elementary_stiffness_matrix = mito::tensor::matrix_t(); + auto elementary_stiffness_matrix = mito::tensor::matrix_t{}; // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -156,7 +156,7 @@ test_mass_matrix( constexpr int n_nodes = elementT::n_nodes; // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix - auto elementary_mass_matrix = mito::tensor::matrix_t(); + auto elementary_mass_matrix = mito::tensor::matrix_t{}; // loop on the quadrature points for (int q = 0; q < quadrature_rule_t::npoints; ++q) { @@ -243,14 +243,14 @@ TEST(Fem, IsoparametricTriangle) // the analytical elementary stiffness matrix auto analytical_stiffness_matrix = 1.0 / 2.0 - * mito::tensor::matrix_t<3>({ 2.0, -1.0, -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0 }); + * mito::tensor::matrix_t<3>{ 2.0, -1.0, -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0 }; // check that the elementary stiffness matrix is computed correctly test_stiffness_matrix(element_p1, equation_map, analytical_stiffness_matrix); // the analytical elementary mass matrix auto analytical_mass_matrix = - 1.0 / 24.0 * mito::tensor::matrix_t<3>({ 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0 }); + 1.0 / 24.0 * mito::tensor::matrix_t<3>{ 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0 }; test_mass_matrix(element_p1, equation_map, analytical_mass_matrix); } @@ -291,25 +291,27 @@ TEST(Fem, IsoparametricTriangle) equation_map[discretization_node_5] = 5; // the analytical elementary stiffness matrix - auto analytical_stiffness_matrix = mito::tensor::matrix_t<6>( - { 1.0, 1.0 / 6.0, 1.0 / 6.0, -2.0 / 3.0, 0.0, -2.0 / 3.0, - 1.0 / 6.0, 1.0 / 2.0, 0.0, -2.0 / 3.0, 0.0, 0.0, - 1.0 / 6.0, 0.0, 1.0 / 2.0, 0.0, 0.0, -2.0 / 3.0, - -2.0 / 3.0, -2.0 / 3.0, 0.0, 8.0 / 3.0, -4.0 / 3.0, 0.0, - 0.0, 0.0, 0.0, -4.0 / 3.0, 8.0 / 3.0, -4.0 / 3.0, - -2.0 / 3.0, 0.0, -2.0 / 3.0, 0.0, -4.0 / 3.0, 8.0 / 3.0 }); + auto analytical_stiffness_matrix = mito::tensor::matrix_t<6>{ + 1.0, 1.0 / 6.0, 1.0 / 6.0, -2.0 / 3.0, 0.0, -2.0 / 3.0, + 1.0 / 6.0, 1.0 / 2.0, 0.0, -2.0 / 3.0, 0.0, 0.0, + 1.0 / 6.0, 0.0, 1.0 / 2.0, 0.0, 0.0, -2.0 / 3.0, + -2.0 / 3.0, -2.0 / 3.0, 0.0, 8.0 / 3.0, -4.0 / 3.0, 0.0, + 0.0, 0.0, 0.0, -4.0 / 3.0, 8.0 / 3.0, -4.0 / 3.0, + -2.0 / 3.0, 0.0, -2.0 / 3.0, 0.0, -4.0 / 3.0, 8.0 / 3.0 + }; // check that the elementary stiffness matrix is computed correctly test_stiffness_matrix(element_p2, equation_map, analytical_stiffness_matrix); // the analytical elementary mass matrix - auto analytical_mass_matrix = mito::tensor::matrix_t<6>( - { 1.0 / 60.0, -1.0 / 360.0, -1.0 / 360.0, 0.0, -1.0 / 90.0, 0.0, - -1.0 / 360.0, 1.0 / 60.0, -1.0 / 360.0, 0.0, 0.0, -1.0 / 90.0, - -1.0 / 360.0, -1.0 / 360.0, 1.0 / 60.0, -1.0 / 90.0, 0.0, 0.0, - 0.0, 0.0, -1.0 / 90.0, 4.0 / 45.0, 2.0 / 45.0, 2.0 / 45.0, - -1.0 / 90.0, 0.0, 0.0, 2.0 / 45.0, 4.0 / 45.0, 2.0 / 45.0, - 0.0, -1.0 / 90.0, 0.0, 2.0 / 45.0, 2.0 / 45.0, 4.0 / 45.0 }); + auto analytical_mass_matrix = mito::tensor::matrix_t<6>{ + 1.0 / 60.0, -1.0 / 360.0, -1.0 / 360.0, 0.0, -1.0 / 90.0, 0.0, + -1.0 / 360.0, 1.0 / 60.0, -1.0 / 360.0, 0.0, 0.0, -1.0 / 90.0, + -1.0 / 360.0, -1.0 / 360.0, 1.0 / 60.0, -1.0 / 90.0, 0.0, 0.0, + 0.0, 0.0, -1.0 / 90.0, 4.0 / 45.0, 2.0 / 45.0, 2.0 / 45.0, + -1.0 / 90.0, 0.0, 0.0, 2.0 / 45.0, 4.0 / 45.0, 2.0 / 45.0, + 0.0, -1.0 / 90.0, 0.0, 2.0 / 45.0, 2.0 / 45.0, 4.0 / 45.0 + }; test_mass_matrix(element_p2, equation_map, analytical_mass_matrix); } diff --git a/tests/mito.lib/functions/algebra.cc b/tests/mito.lib/functions/algebra.cc index d00763ff8..8416a0ae1 100644 --- a/tests/mito.lib/functions/algebra.cc +++ b/tests/mito.lib/functions/algebra.cc @@ -69,7 +69,7 @@ TEST(Algebra, ScalarValuedFunctions) constexpr auto function16 = function1 * e0 + function1 * e1 + function1 * e2; // vector times scalar multiplication - constexpr auto alpha = mito::tensor::scalar_t(10); + constexpr auto alpha = mito::tensor::scalar_t{ 10 }; constexpr auto function17 = alpha * function16; static_assert(function17(x) == alpha * function16(x)); From e43b77f9916b83b4abb524708a1340752e7b07d6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 30 Jul 2025 14:31:35 +0200 Subject: [PATCH 165/273] discretization: remove redundant namespace specifications --- lib/mito/discretization/DiscreteSystem.h | 24 +++++++++---------- .../discretization/blocks/SourceTermBlock.h | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 47d9a31fc..16a25180a 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -200,7 +200,7 @@ namespace mito::discretization { } // assemble the elementary blocks into the linear system of equations - mito::tensor::constexpr_for_1([&]() { + tensor::constexpr_for_1([&]() { // get the a-th discretization node of the element const auto & node_a = element.connectivity()[a]; // get the equation number of {node_a} @@ -211,7 +211,7 @@ namespace mito::discretization { // assemble the value in the right hand side _linear_system.add_rhs_value(eq_a, elementary_vector[{ a }]); // loop on the b-th discretization node of the element - mito::tensor::constexpr_for_1([&]() { + tensor::constexpr_for_1([&]() { // get the b-th discretization node of the element const auto & node_b = element.connectivity()[b]; // get the equation number of {node_b} @@ -269,16 +269,16 @@ namespace mito::discretization { // compute the L2 norm of the solution template constexpr auto compute_l2_error(const fields::field_c auto & u_exact) const - -> mito::tensor::scalar_t + -> tensor::scalar_t { // initialize the norm - auto norm = mito::tensor::scalar_t{ 0.0 }; + auto norm = tensor::scalar_t{ 0.0 }; // helper lambda to assemble the solution on a given element constexpr auto _assemble_element_solution = []( const auto & element, const auto & _solution_field, - mito::tensor::integer_sequence) { + tensor::integer_sequence) { // assemble the solution field from the shape functions return ( (element.template shape() * _solution_field(element.connectivity()[a])) @@ -289,7 +289,7 @@ namespace mito::discretization { for (const auto & element : _function_space.elements()) { // assemble the solution field on this element auto u_numerical = _assemble_element_solution( - element, _solution_field, mito::tensor::make_integer_sequence()); + element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error field as a function of the barycentric coordinates auto u_error = u_numerical - u_exact.function()(element.parametrization()); @@ -304,10 +304,10 @@ namespace mito::discretization { // compute the H1 norm of the solution template constexpr auto compute_h1_error(const fields::field_c auto & u_exact) const - -> mito::tensor::scalar_t + -> tensor::scalar_t { // initialize the norm - auto norm = mito::tensor::scalar_t{ 0.0 }; + auto norm = tensor::scalar_t{ 0.0 }; // QUESTION: is there a proper place to put this method? Perhaps this belongs to the // isoparametric element class? @@ -315,7 +315,7 @@ namespace mito::discretization { constexpr auto _assemble_element_solution = []( const auto & element, const auto & _solution_field, - mito::tensor::integer_sequence) { + tensor::integer_sequence) { // assemble the solution field from the shape functions return ( (element.template shape() * _solution_field(element.connectivity()[a])) @@ -327,7 +327,7 @@ namespace mito::discretization { constexpr auto _assemble_element_solution_gradient = []( const auto & element, const auto & _solution_field, - mito::tensor::integer_sequence) { + tensor::integer_sequence) { // assemble the solution field from the shape functions return ( (element.template gradient() @@ -339,12 +339,12 @@ namespace mito::discretization { for (const auto & element : _function_space.elements()) { // assemble the solution field on this element auto u_numerical = _assemble_element_solution( - element, _solution_field, mito::tensor::make_integer_sequence()); + element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error field as a function of the barycentric coordinates auto u_error = u_numerical - u_exact.function()(element.parametrization()); // auto u_numerical_gradient = _assemble_element_solution_gradient( - element, _solution_field, mito::tensor::make_integer_sequence()); + element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error gradient as a function of the barycentric // coordinates auto u_error_gradient = diff --git a/lib/mito/discretization/blocks/SourceTermBlock.h b/lib/mito/discretization/blocks/SourceTermBlock.h index 77d1cd16b..b0b669a9a 100644 --- a/lib/mito/discretization/blocks/SourceTermBlock.h +++ b/lib/mito/discretization/blocks/SourceTermBlock.h @@ -57,7 +57,7 @@ namespace mito::discretization::blocks { // precompute the common factor auto factor = - quadrature_rule.weight(q) * mito::tensor::determinant(element.jacobian()(xi)); + quadrature_rule.weight(q) * tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { From 928cea13077aa6cc167af5b0aad48330af7c842b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 31 Jul 2025 10:19:50 +0200 Subject: [PATCH 166/273] utilities: proof of concept implementation of {NamedClass} --- .cmake/mito_tests_mito_lib.cmake | 1 + lib/mito/utilities/NamedClass.h | 73 +++++++++++++++++++++++++ lib/mito/utilities/public.h | 1 + tests/mito.lib/utilities/named_class.cc | 47 ++++++++++++++++ 4 files changed, 122 insertions(+) create mode 100644 lib/mito/utilities/NamedClass.h create mode 100644 tests/mito.lib/utilities/named_class.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 8b77ba19a..e847730ba 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -161,6 +161,7 @@ mito_test_driver(tests/mito.lib/utilities/segmented_vector_iterator.cc) mito_test_driver(tests/mito.lib/utilities/segmented_vector_subscript.cc) mito_test_driver(tests/mito.lib/utilities/segmented_vector_print.cc) mito_test_driver(tests/mito.lib/utilities/shared_pointer.cc) +mito_test_driver(tests/mito.lib/utilities/named_class.cc) # quadrature mito_test_driver(tests/mito.lib/quadrature/quadrature_parametric_segment.cc) diff --git a/lib/mito/utilities/NamedClass.h b/lib/mito/utilities/NamedClass.h new file mode 100644 index 000000000..a7667c628 --- /dev/null +++ b/lib/mito/utilities/NamedClass.h @@ -0,0 +1,73 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + + +// code guard +#pragma once + + +namespace mito::utilities { + + // TODO: interface with {libuuid} to generate unique identifiers instead of "unnamed" + // + // Class {NamedClass} is meant to attach a string name identifier to a given class + // {classToName}. After implementing class {classToName}, you can define the alias + // {class_to_name_t} as follows: + // using class_to_name_t = NamedClass + // You can then create named instances of the class by using any of the {classToName} + // constructors (in which case, a default name will be used for the class) or by prepending the + // chosen instance name before the other constructor input arguments. + // + template + class NamedClass : public classToNameT { + // types + public: + // my template parameter + using class_to_name_type = classToNameT; + // me + using named_class_type = NamedClass; + // string identifier type + using name_type = std::string; + + // meta methods + public: + // default constructor + template + requires std::constructible_from + constexpr NamedClass(Args &&... args) : + class_to_name_type(std::forward(args)...), + _name("unnamed") + {} + + // named constructor + template + requires std::constructible_from + constexpr NamedClass(const name_type & name, Args &&... args) : + class_to_name_type(std::forward(args)...), + _name(name) + {} + + // destructor + constexpr ~NamedClass() = default; + + // copy constructor + constexpr NamedClass(const named_class_type &) = delete; + + // move constructor + constexpr NamedClass(named_class_type &&) = delete; + + public: + // accessor to name + constexpr auto name() const -> name_type { return _name; } + + private: + // string identifier + name_type _name; + }; + +} + + +// end of file diff --git a/lib/mito/utilities/public.h b/lib/mito/utilities/public.h index af95c6dcc..9992a7fbf 100644 --- a/lib/mito/utilities/public.h +++ b/lib/mito/utilities/public.h @@ -27,6 +27,7 @@ #include "SegmentedVector.h" #include "Repository.h" #include "SegmentedContainerIterator.h" +#include "NamedClass.h" // factories implementation #include "factories.h" diff --git a/tests/mito.lib/utilities/named_class.cc b/tests/mito.lib/utilities/named_class.cc new file mode 100644 index 000000000..d24c6c855 --- /dev/null +++ b/tests/mito.lib/utilities/named_class.cc @@ -0,0 +1,47 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +using namespace mito::utilities; + + +// a simple class to test NamedClass +class Foo { + public: + // my type + using foo_type = Foo; + + public: + // constructor + Foo(int foo) : _foo(foo) {} + + // accessor + int foo() const { return _foo; } + + private: + // an attribute + int _foo; +}; + + +// the resource type +using foo_t = NamedClass; + + +TEST(Utilities, NamedClass) +{ + // instantiate a named class + auto foo = foo_t(42); + + // assert that the name is "unnamed" + EXPECT_EQ(foo.name(), "unnamed"); + + // instantiate a named class with a name + auto bar = foo_t("bar", 43); + EXPECT_EQ(bar.name(), "bar"); +} From 162ffc352ec487cfa0147bdc47836dafbdba16fe Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 1 Aug 2025 16:05:55 +0000 Subject: [PATCH 167/273] .devcontainer: add Dockerfile and configuration for development environment --- .devcontainer/Dockerfile | 80 +++++++++++++++++++++++++++++++++ .devcontainer/devcontainer.json | 14 ++++++ .devcontainer/gitconfig | 2 + 3 files changed, 96 insertions(+) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 .devcontainer/gitconfig diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 000000000..a3a91fb03 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,80 @@ +# global args +ARG user=user +ARG homedir=/home/${user} +ARG nprocs=4 + +FROM ubuntu:latest + +# to avoid user interaction with tzdata asking for timezone +ARG DEBIAN_FRONTEND=noninteractive + +# +ARG user +ARG homedir +ARG nprocs + +# environment +# colorize the terminal +ENV TERM=xterm-256color +# openmpi +ENV OMPI_ALLOW_RUN_AS_ROOT=1 +ENV OMPI_ALLOW_RUN_AS_ROOT_CONFIRM=1 +ENV OMPI_MCA_rmaps_base_oversubscribe=1 + +# get the latest +RUN apt dist-upgrade -y + +# update the package repository +RUN apt update -y + +# install multipurpose packages +RUN apt install -y cmake-curses-gui +RUN apt install -y git +RUN apt install -y git-core +RUN apt install -y bash-completion +RUN apt install -y make +RUN apt install -y vim +RUN apt install -y sudo + +# install mito dependencies +RUN apt install -y libgtest-dev +RUN apt install -y libbenchmark-dev +RUN apt install -y libopenmpi-dev +RUN apt install -y libmetis-dev +RUN apt install -y libvtk9-dev +RUN apt install -y petsc-dev +RUN apt install -y valgrind +RUN apt install -y libpython3-dev +RUN apt install -y python3-pytest + +# install pyre dependencies +RUN apt install -y pybind11-dev + +# install pyre +WORKDIR ${homedir} +RUN git clone https://github.com/pyre/pyre \ + && cd pyre \ + && git checkout tensor \ + && mkdir build \ + && cd build \ + && cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=/usr/local/pyre .. \ + && make -j ${nprocs} \ + && make install \ + && cd .. \ + && rm -rf build + +# setup {user} user +ENV USER=${user} +ENV HOME=${homedir} +RUN useradd -s /bin/bash --create-home --home-dir $HOME $USER \ + && usermod -aG sudo $USER \ + && chown -R $USER:$USER $HOME +RUN echo "$USER:password" | chpasswd + +# default user and work directory when running the container +USER ${user} +WORKDIR ${homedir} +# remove annoying message on how to run a sudo command +RUN touch ~/.sudo_as_admin_successful + +# end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..9664cd309 --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,14 @@ +// .devcontainer/devcontainer.json +{ + "name": "mito", + "build": { + "dockerfile": "Dockerfile" + }, + "mounts": [ + "source=${localWorkspaceFolder},target=/home/user/mito,type=bind" + ], + "extensions": [ + "ms-vscode.cpptools-extension-pack" + ], + "remoteUser": "user" +} \ No newline at end of file diff --git a/.devcontainer/gitconfig b/.devcontainer/gitconfig new file mode 100644 index 000000000..37ad1fabb --- /dev/null +++ b/.devcontainer/gitconfig @@ -0,0 +1,2 @@ +[core] + editor = code -w \ No newline at end of file From bb606edda6c6d2287810f40fbd43cae5a71fbb5d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 1 Aug 2025 16:08:46 +0000 Subject: [PATCH 168/273] discretization: fix pedantic compiler error --- lib/mito/discretization/FunctionSpace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/discretization/FunctionSpace.h index 6e376e36e..e77ffe1df 100644 --- a/lib/mito/discretization/FunctionSpace.h +++ b/lib/mito/discretization/FunctionSpace.h @@ -169,7 +169,7 @@ namespace mito::discretization { // all done return; - }; + } // destructor constexpr ~FunctionSpace() = default; From f9e8e5d70e9fc098a5b9d2087d063f74b4d86a8f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 2 Aug 2025 18:12:18 +0200 Subject: [PATCH 169/273] discretization: {constexpr} shape functions calculation whenever possible --- .../fem/tri1/IsoparametricTriangleP1.h | 28 +++--- .../discretization/fem/tri1/ShapeTriangleP1.h | 4 +- .../fem/tri2/IsoparametricTriangleP2.h | 36 +++---- .../discretization/fem/tri2/ShapeTriangleP2.h | 4 +- .../discretization/isoparametric_triangle.cc | 66 +++++++------ .../shape_functions_triangle_p1.cc | 32 +++--- .../shape_functions_triangle_p2.cc | 99 +++++++++---------- 7 files changed, 138 insertions(+), 131 deletions(-) diff --git a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h index 818968fbf..4e0cdb438 100644 --- a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h @@ -41,25 +41,25 @@ namespace mito::discretization { inline ~IsoparametricTriangleP1() = default; // delete move constructor - inline IsoparametricTriangleP1(IsoparametricTriangleP1 &&) noexcept = delete; + constexpr IsoparametricTriangleP1(IsoparametricTriangleP1 &&) noexcept = delete; // delete copy constructor - inline IsoparametricTriangleP1(const IsoparametricTriangleP1 &) = delete; + constexpr IsoparametricTriangleP1(const IsoparametricTriangleP1 &) = delete; // delete assignment operator - inline IsoparametricTriangleP1 & operator=(const IsoparametricTriangleP1 &) = delete; + constexpr IsoparametricTriangleP1 & operator=(const IsoparametricTriangleP1 &) = delete; // delete move assignment operator - inline IsoparametricTriangleP1 & operator=(IsoparametricTriangleP1 &&) noexcept = delete; + constexpr IsoparametricTriangleP1 & operator=(IsoparametricTriangleP1 &&) noexcept = delete; private: // the isoparametric mapping from barycentric coordinates to physical coordinates - inline auto _x_cell() const + constexpr auto _x_cell() const { // get the shape functions - auto phi_0 = shape_functions.shape<0>(); - auto phi_1 = shape_functions.shape<1>(); - auto phi_2 = shape_functions.shape<2>(); + constexpr auto phi_0 = shape_functions.shape<0>(); + constexpr auto phi_1 = shape_functions.shape<1>(); + constexpr auto phi_2 = shape_functions.shape<2>(); // return the isoparametric mapping from barycentric to physical coordinates return _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; @@ -67,13 +67,13 @@ namespace mito::discretization { public: // get the discretization nodes - inline auto connectivity() const noexcept -> const connectivity_type & + constexpr auto connectivity() const noexcept -> const connectivity_type & { return _connectivity; } // get the isoparametric mapping from barycentric coordinates to physical coordinates - inline auto parametrization() const + constexpr auto parametrization() const { // assemble the physical coordinates from the barycentric coordinates auto x_cell = functions::function( @@ -89,11 +89,11 @@ namespace mito::discretization { // get the shape function associated with local node {a} template requires(a >= 0 && a < n_nodes) - inline auto shape() const + constexpr auto shape() const { // assemble the shape function associated with local node {a} as a function of // barycentric coordinates - auto shape_function = functions::function( + constexpr auto shape_function = functions::function( [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { // return the a-th shape function evaluated at {xi} return shape_functions.shape()({ xi[0], xi[1] }); @@ -104,7 +104,7 @@ namespace mito::discretization { } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - inline auto jacobian() const + constexpr auto jacobian() const { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = functions::function( @@ -120,7 +120,7 @@ namespace mito::discretization { // get the gradient of the a-th shape function as a function of barycentric coordinates template requires(a >= 0 && a < n_nodes) - inline auto gradient() const + constexpr auto gradient() const { // assemble the gradient as a function of barycentric coordinates auto gradient_function = functions::function( diff --git a/lib/mito/discretization/fem/tri1/ShapeTriangleP1.h b/lib/mito/discretization/fem/tri1/ShapeTriangleP1.h index c46c96c59..dcc893e73 100644 --- a/lib/mito/discretization/fem/tri1/ShapeTriangleP1.h +++ b/lib/mito/discretization/fem/tri1/ShapeTriangleP1.h @@ -39,7 +39,7 @@ namespace mito::discretization { // get the a-th shape function template requires(a >= 0 && a < N) - inline auto shape() const + constexpr auto shape() const { // return the a-th shape function return std::get(phi); @@ -48,7 +48,7 @@ namespace mito::discretization { // get the a-th shape function's gradient template requires(a >= 0 && a < N) - inline auto dshape() const + constexpr auto dshape() const { // return the a-th shape function's gradient return std::get(dphi); diff --git a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h index 3881b9b92..110a8310b 100644 --- a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h @@ -38,35 +38,35 @@ namespace mito::discretization { {} // destructor - inline ~IsoparametricTriangleP2() = default; + ~IsoparametricTriangleP2() = default; // delete move constructor - inline IsoparametricTriangleP2(IsoparametricTriangleP2 &&) noexcept = delete; + constexpr IsoparametricTriangleP2(IsoparametricTriangleP2 &&) noexcept = delete; // delete copy constructor - inline IsoparametricTriangleP2(const IsoparametricTriangleP2 &) = delete; + constexpr IsoparametricTriangleP2(const IsoparametricTriangleP2 &) = delete; // delete assignment operator - inline IsoparametricTriangleP2 & operator=(const IsoparametricTriangleP2 &) = delete; + constexpr IsoparametricTriangleP2 & operator=(const IsoparametricTriangleP2 &) = delete; // delete move assignment operator - inline IsoparametricTriangleP2 & operator=(IsoparametricTriangleP2 &&) noexcept = delete; + constexpr IsoparametricTriangleP2 & operator=(IsoparametricTriangleP2 &&) noexcept = delete; private: // the isoparametric mapping from barycentric coordinates to physical coordinates - inline auto _x_cell() const + constexpr auto _x_cell() const { auto x3 = 0.5 * (_x0 + _x1); auto x4 = 0.5 * (_x1 + _x2); auto x5 = 0.5 * (_x2 + _x0); // get the shape functions - auto phi_0 = shape_functions.shape<0>(); - auto phi_1 = shape_functions.shape<1>(); - auto phi_2 = shape_functions.shape<2>(); - auto phi_3 = shape_functions.shape<3>(); - auto phi_4 = shape_functions.shape<4>(); - auto phi_5 = shape_functions.shape<5>(); + constexpr auto phi_0 = shape_functions.shape<0>(); + constexpr auto phi_1 = shape_functions.shape<1>(); + constexpr auto phi_2 = shape_functions.shape<2>(); + constexpr auto phi_3 = shape_functions.shape<3>(); + constexpr auto phi_4 = shape_functions.shape<4>(); + constexpr auto phi_5 = shape_functions.shape<5>(); // return the isoparametric mapping from barycentric to physical coordinates return _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; @@ -74,13 +74,13 @@ namespace mito::discretization { public: // get the discretization nodes - inline auto connectivity() const noexcept -> const connectivity_type & + constexpr auto connectivity() const noexcept -> const connectivity_type & { return _connectivity; } // get the isoparametric mapping from barycentric coordinates to physical coordinates - inline auto parametrization() const + constexpr auto parametrization() const { // assemble the physical coordinates from the barycentric coordinates auto x_cell = functions::function( @@ -96,11 +96,11 @@ namespace mito::discretization { // get the shape function associated with local node {a} template requires(a >= 0 && a < n_nodes) - inline auto shape() const + constexpr auto shape() const { // assemble the shape function associated with local node {a} as a function of // barycentric coordinates - auto shape_function = functions::function( + constexpr auto shape_function = functions::function( [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { // return the a-th shape function evaluated at {xi} return shape_functions.shape()({ xi[0], xi[1] }); @@ -111,7 +111,7 @@ namespace mito::discretization { } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates - inline auto jacobian() const + constexpr auto jacobian() const { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = functions::function( @@ -127,7 +127,7 @@ namespace mito::discretization { // get the gradient of the a-th shape function as a function of barycentric coordinates template requires(a >= 0 && a < n_nodes) - inline auto gradient() const + constexpr auto gradient() const { // assemble the gradient as a function of barycentric coordinates auto gradient_function = functions::function( diff --git a/lib/mito/discretization/fem/tri2/ShapeTriangleP2.h b/lib/mito/discretization/fem/tri2/ShapeTriangleP2.h index 9d6ed7ffb..4971369bd 100644 --- a/lib/mito/discretization/fem/tri2/ShapeTriangleP2.h +++ b/lib/mito/discretization/fem/tri2/ShapeTriangleP2.h @@ -43,7 +43,7 @@ namespace mito::discretization { // get the a-th shape function template requires(a >= 0 && a < N) - inline auto shape() const + constexpr auto shape() const { // return the a-th shape function return std::get(phi); @@ -52,7 +52,7 @@ namespace mito::discretization { // get the a-th shape function's gradient template requires(a >= 0 && a < N) - inline auto dshape() const + constexpr auto dshape() const { // return the a-th shape function's gradient return std::get(dphi); diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 30c2b3ccb..ea9383a86 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -30,25 +30,27 @@ constexpr auto quadrature_rule = quadrature_rule_t(); auto test_partition_of_unity(const auto & element) { + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_t::npoints; + // the number of nodes per element constexpr int n_nodes = mito::utilities::base_type::n_nodes; // loop on the quadrature points - for (int q = 0; q < quadrature_rule_t::npoints; ++q) { - + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - auto xi = quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); - // the sum of the shape functions - auto sum = 0.0; - - // add together all the shape functions at {xi} - mito::tensor::constexpr_for_1( - [&]() { sum += element.template shape()(xi); }); + // compute the sum of the shape functions at {xi} for all nodes + constexpr auto sum = + ([]( + const auto & element, const auto & xi, mito::tensor::integer_sequence) { + return ((element.template shape()(xi)) + ...); + })(element, xi, mito::tensor::make_integer_sequence{}); // check the sum of the shape functions - EXPECT_DOUBLE_EQ(1.0, sum); - } + static_assert(1.0 == sum); + }); // all done return; @@ -58,26 +60,28 @@ test_partition_of_unity(const auto & element) auto test_gradient_consistency(const auto & element) { + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_t::npoints; + // the number of nodes per element constexpr int n_nodes = mito::utilities::base_type::n_nodes; // loop on the quadrature points - for (int q = 0; q < quadrature_rule_t::npoints; ++q) { - + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - auto xi = quadrature_rule.point(q); - - // the sum of the shape functions - auto sum = mito::tensor::vector_t<2>{ 0.0, 0.0 }; + constexpr auto xi = quadrature_rule.point(q); - // add together all the shape functions gradients at {xi} - mito::tensor::constexpr_for_1( - [&]() { sum += element.template gradient()(xi); }); + // compute the sum of the shape functions at {xi} for all nodes + auto sum = + ([]( + const auto & element, const auto & xi, mito::tensor::integer_sequence) { + return ((element.template gradient()(xi)) + ...); + })(element, xi, mito::tensor::make_integer_sequence{}); // check the sum of the shape functions gradients EXPECT_NEAR(0.0, sum[0], 3.0e-16); EXPECT_NEAR(0.0, sum[1], 3.0e-16); - } + }); // all done return; @@ -93,6 +97,9 @@ test_stiffness_matrix( // create reporting channel journal::info_t channel("test_stiffness_matrix"); + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_t::npoints; + // the number of nodes per element constexpr int n_nodes = elementT::n_nodes; @@ -100,10 +107,9 @@ test_stiffness_matrix( auto elementary_stiffness_matrix = mito::tensor::matrix_t{}; // loop on the quadrature points - for (int q = 0; q < quadrature_rule_t::npoints; ++q) { - + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - auto xi = quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); // area of the cell auto area = 0.5 * mito::tensor::determinant(element.jacobian()(xi)); @@ -130,7 +136,7 @@ test_stiffness_matrix( elementary_stiffness_matrix[{ i, j }] += factor * dphi_a * dphi_b; }); }); - } + }); // compute the error auto error = mito::tensor::norm(elementary_stiffness_matrix - analytical_stiffness_matrix); @@ -152,6 +158,9 @@ test_mass_matrix( // create reporting channel journal::info_t channel("test_mass_matrix"); + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_t::npoints; + // the number of nodes per element constexpr int n_nodes = elementT::n_nodes; @@ -159,10 +168,9 @@ test_mass_matrix( auto elementary_mass_matrix = mito::tensor::matrix_t{}; // loop on the quadrature points - for (int q = 0; q < quadrature_rule_t::npoints; ++q) { - + mito::tensor::constexpr_for_1([&]() { // the barycentric coordinates of the quadrature point - auto xi = quadrature_rule.point(q); + constexpr auto xi = quadrature_rule.point(q); // area of the cell auto factor = @@ -187,7 +195,7 @@ test_mass_matrix( elementary_mass_matrix[{ i, j }] += factor * phi_a * phi_b; }); }); - } + }); // compute the error auto error = mito::tensor::norm(elementary_mass_matrix - analytical_mass_matrix); diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc index e8aaedfe9..688dc23d6 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc @@ -16,41 +16,41 @@ using parametric_coordinates_t = shape_t::reference_element_type::parametric_coo TEST(Fem, ShapeTriangleP1) { // first order shape functions - auto element = shape_t(); + constexpr auto element = shape_t(); // node 0 in parametric coordinates - auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; + constexpr auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; // node 1 in parametric coordinates - auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; + constexpr auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; // node 2 in parametric coordinates - auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; + constexpr auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; // the shape function associated with local node {0} - auto phi_0 = element.shape<0>(); + constexpr auto phi_0 = element.shape<0>(); // check that the shape function at node 0 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_0(n0)); + static_assert(1.0 == phi_0(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n1)); + static_assert(0.0 == phi_0(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n2)); + static_assert(0.0 == phi_0(n2)); // the shape functions at node 1 - auto phi_1 = element.shape<1>(); + constexpr auto phi_1 = element.shape<1>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n0)); + static_assert(0.0 == phi_1(n0)); // check that the shape function at node 1 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_1(n1)); + static_assert(1.0 == phi_1(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n2)); + static_assert(0.0 == phi_1(n2)); // the shape functions at node 2 - auto phi_2 = element.shape<2>(); + constexpr auto phi_2 = element.shape<2>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n0)); + static_assert(0.0 == phi_2(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n1)); + static_assert(0.0 == phi_2(n1)); // check that the shape function at node 2 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_2(n2)); + static_assert(1.0 == phi_2(n2)); // all done return; diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p2.cc b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc index 70449a85d..1e3bb1612 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_p2.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc @@ -15,112 +15,111 @@ using parametric_coordinates_t = shape_t::reference_element_type::parametric_coo TEST(Fem, ShapeTriangleP2) { - // second order shape functions - auto element = shape_t(); + constexpr auto element = shape_t(); // node 0 in parametric coordinates - auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; + constexpr auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; // node 1 in parametric coordinates - auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; + constexpr auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; // node 2 in parametric coordinates - auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; + constexpr auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; // node 3 in parametric coordinates - auto n3 = parametric_coordinates_t{ 0.5, 0.5 }; + constexpr auto n3 = parametric_coordinates_t{ 0.5, 0.5 }; // node 4 in parametric coordinates - auto n4 = parametric_coordinates_t{ 0.0, 0.5 }; + constexpr auto n4 = parametric_coordinates_t{ 0.0, 0.5 }; // node 5 in parametric coordinates - auto n5 = parametric_coordinates_t{ 0.5, 0.0 }; + constexpr auto n5 = parametric_coordinates_t{ 0.5, 0.0 }; // the shape functions at node 0 - auto phi_0 = element.shape<0>(); + constexpr auto phi_0 = element.shape<0>(); // check that the shape function at node 0 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_0(n0)); + static_assert(1.0 == phi_0(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n1)); + static_assert(0.0 == phi_0(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n2)); + static_assert(0.0 == phi_0(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n3)); + static_assert(0.0 == phi_0(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n4)); + static_assert(0.0 == phi_0(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_0(n5)); + static_assert(0.0 == phi_0(n5)); // the shape functions at node 1 - auto phi_1 = element.shape<1>(); + constexpr auto phi_1 = element.shape<1>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n0)); + static_assert(0.0 == phi_1(n0)); // check that the shape function at node 1 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_1(n1)); + static_assert(1.0 == phi_1(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n2)); + static_assert(0.0 == phi_1(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n3)); + static_assert(0.0 == phi_1(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n4)); + static_assert(0.0 == phi_1(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_1(n5)); + static_assert(0.0 == phi_1(n5)); // the shape functions at node 2 - auto phi_2 = element.shape<2>(); + constexpr auto phi_2 = element.shape<2>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n0)); + static_assert(0.0 == phi_2(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n1)); + static_assert(0.0 == phi_2(n1)); // check that the shape function at node 2 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_2(n2)); + static_assert(1.0 == phi_2(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n3)); + static_assert(0.0 == phi_2(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n4)); + static_assert(0.0 == phi_2(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_2(n5)); + static_assert(0.0 == phi_2(n5)); // the shape functions at node 3 - auto phi_3 = element.shape<3>(); + constexpr auto phi_3 = element.shape<3>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3(n0)); + static_assert(0.0 == phi_3(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3(n1)); + static_assert(0.0 == phi_3(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3(n2)); + static_assert(0.0 == phi_3(n2)); // check that the shape function at node 3 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_3(n3)); + static_assert(1.0 == phi_3(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3(n4)); + static_assert(0.0 == phi_3(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_3(n5)); + static_assert(0.0 == phi_3(n5)); // the shape functions at node 4 - auto phi_4 = element.shape<4>(); + constexpr auto phi_4 = element.shape<4>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4(n0)); + static_assert(0.0 == phi_4(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4(n1)); + static_assert(0.0 == phi_4(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4(n2)); + static_assert(0.0 == phi_4(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4(n3)); + static_assert(0.0 == phi_4(n3)); // check that the shape function at node 4 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_4(n4)); + static_assert(1.0 == phi_4(n4)); // check that the shape function at node 5 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_4(n5)); + static_assert(0.0 == phi_4(n5)); // the shape functions at node 5 - auto phi_5 = element.shape<5>(); + constexpr auto phi_5 = element.shape<5>(); // check that the shape function at node 0 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5(n0)); + static_assert(0.0 == phi_5(n0)); // check that the shape function at node 1 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5(n1)); + static_assert(0.0 == phi_5(n1)); // check that the shape function at node 2 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5(n2)); + static_assert(0.0 == phi_5(n2)); // check that the shape function at node 3 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5(n3)); + static_assert(0.0 == phi_5(n3)); // check that the shape function at node 4 is 0.0 - EXPECT_DOUBLE_EQ(0.0, phi_5(n4)); + static_assert(0.0 == phi_5(n4)); // check that the shape function at node 5 is 1.0 - EXPECT_DOUBLE_EQ(1.0, phi_5(n5)); + static_assert(1.0 == phi_5(n5)); // all done return; From 740be19d824f488dfa0870376f5481353851317b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 2 Aug 2025 19:28:02 +0200 Subject: [PATCH 170/273] discretization/fem: fix major inefficiency in calculation of the jacobian matrices --- .../fem/tri1/IsoparametricTriangleP1.h | 10 +++++++++- .../fem/tri2/IsoparametricTriangleP2.h | 20 ++++++++++++++++++- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h index 4e0cdb438..72c431fa3 100644 --- a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h @@ -109,8 +109,16 @@ namespace mito::discretization { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = functions::function( [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { + // get the shape functions derivatives + constexpr auto dphi_0 = shape_functions.dshape<0>(); + constexpr auto dphi_1 = shape_functions.dshape<1>(); + constexpr auto dphi_2 = shape_functions.dshape<2>(); + // compute the gradient of the isoparametric mapping - return fields::gradient(_x_cell())({ xi[0], xi[1] }); + return ( + tensor::dyadic(_x0, dphi_0({ xi[0], xi[1] })) + + tensor::dyadic(_x1, dphi_1({ xi[0], xi[1] })) + + tensor::dyadic(_x2, dphi_2({ xi[0], xi[1] }))); }); // and return it diff --git a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h index 110a8310b..20dfc1c8f 100644 --- a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h @@ -116,8 +116,26 @@ namespace mito::discretization { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = functions::function( [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { + auto x3 = 0.5 * (_x0 + _x1); + auto x4 = 0.5 * (_x1 + _x2); + auto x5 = 0.5 * (_x2 + _x0); + + // get the shape functions derivatives + constexpr auto dphi_0 = shape_functions.dshape<0>(); + constexpr auto dphi_1 = shape_functions.dshape<1>(); + constexpr auto dphi_2 = shape_functions.dshape<2>(); + constexpr auto dphi_3 = shape_functions.dshape<3>(); + constexpr auto dphi_4 = shape_functions.dshape<4>(); + constexpr auto dphi_5 = shape_functions.dshape<5>(); + // compute the gradient of the isoparametric mapping - return fields::gradient(_x_cell())({ xi[0], xi[1] }); + return ( + tensor::dyadic(_x0, dphi_0({ xi[0], xi[1] })) + + tensor::dyadic(_x1, dphi_1({ xi[0], xi[1] })) + + tensor::dyadic(_x2, dphi_2({ xi[0], xi[1] })) + + tensor::dyadic(x3, dphi_3({ xi[0], xi[1] })) + + tensor::dyadic(x4, dphi_4({ xi[0], xi[1] })) + + tensor::dyadic(x5, dphi_5({ xi[0], xi[1] }))); }); // and return it From 8ff30b7a8b3e8062b19cf9bb0ac7034794d0467c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 17 Aug 2025 10:52:38 +0200 Subject: [PATCH 171/273] devcontainer: enable bash completions --- .devcontainer/Dockerfile | 2 ++ .devcontainer/bashrc | 6 ++++++ 2 files changed, 8 insertions(+) create mode 100644 .devcontainer/bashrc diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index a3a91fb03..acc50d35e 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -70,6 +70,8 @@ RUN useradd -s /bin/bash --create-home --home-dir $HOME $USER \ && usermod -aG sudo $USER \ && chown -R $USER:$USER $HOME RUN echo "$USER:password" | chpasswd +# copy the bashrc +COPY --chown=${user}:${user} bashrc .bashrc # default user and work directory when running the container USER ${user} diff --git a/.devcontainer/bashrc b/.devcontainer/bashrc new file mode 100644 index 000000000..d18cd4fc4 --- /dev/null +++ b/.devcontainer/bashrc @@ -0,0 +1,6 @@ +# enable bash completion +if [ -f /etc/bash_completion ]; then + . /etc/bash_completion +elif [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion +fi \ No newline at end of file From d0fc0949e35b73392da3a3495c3f3a3cb41f71e2 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 17 Aug 2025 10:52:52 +0200 Subject: [PATCH 172/273] devcontainer: add {gitlens} extension --- .devcontainer/devcontainer.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 9664cd309..7fd6769cc 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -8,7 +8,8 @@ "source=${localWorkspaceFolder},target=/home/user/mito,type=bind" ], "extensions": [ - "ms-vscode.cpptools-extension-pack" + "ms-vscode.cpptools-extension-pack", + "eamodio.gitlens", ], "remoteUser": "user" } \ No newline at end of file From 1ab9bf5d9bffbcdeedd0ec814e22c0757a8c31d7 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 17 Aug 2025 10:53:27 +0200 Subject: [PATCH 173/273] devcontainer: configure pull fastforward {git} behavior --- .devcontainer/Dockerfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index acc50d35e..11038a7e9 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -78,5 +78,7 @@ USER ${user} WORKDIR ${homedir} # remove annoying message on how to run a sudo command RUN touch ~/.sudo_as_admin_successful +# configure git +RUN git config --global pull.ff only # end of file From a83382b0846d4feb3ba347c13004928bd551fbc1 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 17 Aug 2025 10:53:50 +0200 Subject: [PATCH 174/273] devcontainer: remove unused and unnecessary {gitconfig} --- .devcontainer/gitconfig | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 .devcontainer/gitconfig diff --git a/.devcontainer/gitconfig b/.devcontainer/gitconfig deleted file mode 100644 index 37ad1fabb..000000000 --- a/.devcontainer/gitconfig +++ /dev/null @@ -1,2 +0,0 @@ -[core] - editor = code -w \ No newline at end of file From 5917c60fa6dff7ffa805e423085513e34b71e444 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 17 Aug 2025 11:26:19 +0200 Subject: [PATCH 175/273] discretization: add check that the number of equations in the discrete system and the linear system match --- lib/mito/discretization/DiscreteSystem.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 16a25180a..4df70040e 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -171,8 +171,8 @@ namespace mito::discretization { // assemble the discrete system constexpr auto assemble() -> void { - // get the number of equations - int N_equations = _linear_system.n_equations(); + // check that the number of equations matches that of the linear system + assert(_n_equations == _linear_system.n_equations()); // QUESTION: can we flip the element and block loops? What is the expected layout in // memory? @@ -205,7 +205,7 @@ namespace mito::discretization { const auto & node_a = element.connectivity()[a]; // get the equation number of {node_a} int eq_a = _equation_map.at(node_a); - assert(eq_a < N_equations); + assert(eq_a < _n_equations); // non boundary nodes if (eq_a != -1) { // assemble the value in the right hand side @@ -216,7 +216,7 @@ namespace mito::discretization { const auto & node_b = element.connectivity()[b]; // get the equation number of {node_b} int eq_b = _equation_map.at(node_b); - assert(eq_b < N_equations); + assert(eq_b < _n_equations); // non boundary nodes if (eq_b != -1) { // assemble the value in the stiffness matrix @@ -232,11 +232,11 @@ namespace mito::discretization { // read the solution nodal field constexpr void read_solution() { - // get the number of equations - int N_equations = _linear_system.n_equations(); + // check that the number of equations matches that of the linear system + assert(_n_equations == _linear_system.n_equations()); // read the solution - auto u = std::vector(N_equations); + auto u = std::vector(_n_equations); _linear_system.get_solution(u); // TODO: ask the function space to populate the constrained nodes appropriately From 9a1c07448fa9c561574da0b7cda50c0958e149fe Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 17 Aug 2025 11:26:43 +0200 Subject: [PATCH 176/273] devcontainer: add {gitgraph} extension --- .devcontainer/devcontainer.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 7fd6769cc..484c24ac3 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -10,6 +10,7 @@ "extensions": [ "ms-vscode.cpptools-extension-pack", "eamodio.gitlens", + "med-h.git-graph-revamped", ], "remoteUser": "user" } \ No newline at end of file From cd69b0a43e2f494c52e259ed1506df55cbf59877 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 21 Aug 2025 12:04:30 +0200 Subject: [PATCH 177/273] fields: generalize concept {compatible_fields_c} to an arbitrary number of fields --- lib/mito/fields/forward.h | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/mito/fields/forward.h b/lib/mito/fields/forward.h index 735e20721..09749055d 100644 --- a/lib/mito/fields/forward.h +++ b/lib/mito/fields/forward.h @@ -60,10 +60,13 @@ namespace mito::fields { concept p_form_field_c = field_c and tensor::p_form_c; // concept of two fields being compatible with each other (i.e. defined on the same coordinates) - template - // a scalar field is a field returning a scalar + template concept compatible_fields_c = - std::is_same_v; + (sizeof...(FIELDS) <= 1) || // trivially true for 0 or 1 + (std::same_as< + typename std::tuple_element_t<0, std::tuple>::coordinates_type, + typename FIELDS::coordinates_type> + && ...); } From 94f9ec2a17c7574df113f9c8c5324379fc2cb0d5 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 21 Aug 2025 16:58:13 +0200 Subject: [PATCH 178/273] functions: add helper functions {product_result_t} and {sum_result_t} in type traits --- lib/mito/functions/traits.h | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/lib/mito/functions/traits.h b/lib/mito/functions/traits.h index 236c3feac..41c9be5d7 100644 --- a/lib/mito/functions/traits.h +++ b/lib/mito/functions/traits.h @@ -9,6 +9,30 @@ namespace mito::functions { + // the type of the product of {C} and {X} + template + using product_result_t = std::invoke_result_t, C, X>; + + // helper: fold "plus" over a pack of types + template + struct sum_result; + + // helper: base case + template + struct sum_result { + using type = T; + }; + + // helper: recursion + template + struct sum_result { + using type = std::invoke_result_t, T1, typename sum_result::type>; + }; + + // the type of the sum of {Ts...} + template + using sum_result_t = typename sum_result::type; + // the type of the sum of two functions... template // ... which take the same input type {input_type}... @@ -17,9 +41,7 @@ namespace mito::functions { // ... is the function that takes {input_type} in input and returns the type of the sum of // the output types using type = Function< - typename F::input_type, - typename std::invoke_result< - std::plus<>, typename F::output_type, typename G::output_type>::type>; + typename F::input_type, sum_result_t>; }; // the type of the product of two functions... @@ -31,8 +53,7 @@ namespace mito::functions { // of the output types using type = Function< typename F::input_type, - typename std::invoke_result< - std::multiplies<>, typename F::output_type, typename G::output_type>::type>; + product_result_t>; }; // the type of the composition of two functions (F external, G internal)... From 9fb80837619ec0bc9ee02a23eeb24cb517a69c60 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 21 Aug 2025 17:01:36 +0200 Subject: [PATCH 179/273] functions: a {function_c} should not satisfy the concept of a {functor_c} The risk is otherwise to have ambiguous overloads of functions implemented for functions and functors. --- lib/mito/functions/forward.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mito/functions/forward.h b/lib/mito/functions/forward.h index 83b68bd8f..1f87a1aea 100644 --- a/lib/mito/functions/forward.h +++ b/lib/mito/functions/forward.h @@ -9,10 +9,6 @@ namespace mito::functions { - // the functor concept - template - concept functor_c = requires { &F::operator(); }; - // class {Function} template class Function; @@ -25,6 +21,10 @@ namespace mito::functions { }(c); }; + // the functor concept + template + concept functor_c = requires { &F::operator(); } and not function_c; + // concept of a scalar-valued function template concept scalar_function_c = function_c and tensor::scalar_c; From 7e77c8b021f584b3ccaeac5f8d65ae890ab0d46c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 21 Aug 2025 17:24:13 +0200 Subject: [PATCH 180/273] functions: add concept of functions with same input --- lib/mito/functions/forward.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/mito/functions/forward.h b/lib/mito/functions/forward.h index 1f87a1aea..0fa26a3c0 100644 --- a/lib/mito/functions/forward.h +++ b/lib/mito/functions/forward.h @@ -29,6 +29,14 @@ namespace mito::functions { template concept scalar_function_c = function_c and tensor::scalar_c; + // concept of functions taking the same input type + template + concept same_input_c = (sizeof...(Funcs) <= 1) || // trivially true for 0 or 1 + (std::same_as< + typename std::tuple_element_t<0, std::tuple>::input_type, + typename Funcs::input_type> + && ...); + // function composition template class Composition; From a8500c339046c681a882f1770461b8413adb3d4d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 21 Aug 2025 18:14:26 +0200 Subject: [PATCH 181/273] functions and fields: implement linear combinations of functions and fields --- lib/mito/fields/fields_arithmetic.h | 8 ++++ lib/mito/functions/api.h | 3 ++ lib/mito/functions/derivation_rules.h | 9 ++++ lib/mito/functions/factories.h | 7 +++ lib/mito/functions/function.h | 51 ++++++++++++++++++++++ lib/mito/functions/traits.h | 15 +++++++ tests/mito.lib/functions/derivative_sum.cc | 22 ++++++++++ 7 files changed, 115 insertions(+) diff --git a/lib/mito/fields/fields_arithmetic.h b/lib/mito/fields/fields_arithmetic.h index 73a2c5216..01a73d102 100644 --- a/lib/mito/fields/fields_arithmetic.h +++ b/lib/mito/fields/fields_arithmetic.h @@ -10,6 +10,14 @@ // Arithmetic operations on Fields namespace mito::fields { + // addition of N fields fa + ... + fn + template + constexpr auto linear_combination(std::array coeffs, const Fs &... fs) + requires(compatible_fields_c) + { + return field(functions::linear_combination(coeffs, fs.function()...)); + } + // addition of fields fa + fb template constexpr auto operator+(const F1 & fA, const F2 & fB) diff --git a/lib/mito/functions/api.h b/lib/mito/functions/api.h index b19052eed..cd0bdcb16 100644 --- a/lib/mito/functions/api.h +++ b/lib/mito/functions/api.h @@ -71,6 +71,9 @@ namespace mito::functions { template [[maybe_unused]] constexpr auto x = component, N>; + // the linear combination + template + constexpr auto linear_combination(std::array coeffs, Funcs... funcs); } diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index 514b03abe..bb62b6af3 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -68,6 +68,15 @@ namespace mito::functions { // the derivative of the transpose is the transpose of the derivative return functions::transpose(derivative(f.f())); } + + // the {I...}-th first partial derivative of a linear combination + template + constexpr auto derivative(const LinearCombination & f) + { + // the derivative of a linear combination is the linear combination of the derivatives + return linear_combination( + f.coefficients(), derivative(std::get(f.functions()))...); + } } diff --git a/lib/mito/functions/factories.h b/lib/mito/functions/factories.h index d60b332d7..7eca0ce0f 100644 --- a/lib/mito/functions/factories.h +++ b/lib/mito/functions/factories.h @@ -22,6 +22,13 @@ namespace mito::functions { { return FunctionFromFunctor(std::forward(f)); } + + // returns the linear combination + template + constexpr auto linear_combination(std::array coeffs, Funcs... funcs) + { + return LinearCombination(coeffs, std::forward(funcs)...); + } } diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index e238da09c..4c88d7347 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -123,6 +123,57 @@ namespace mito::functions { const G _g; }; + // the linear combination of functions {Funcs} with coefficients of type {T}... + template + class LinearCombination : public function_linear_combination::type { + public: + // the type of the function (what I derive from) + using function_type = function_linear_combination::type; + // the input type + using input_type = function_type::input_type; + // the output type + using output_type = function_type::output_type; + + private: + // the number of functions in the linear combination + static constexpr std::size_t N = sizeof...(Funcs); + // the type of coefficients + using coefficients_type = std::array; + // the type of functions + using functions_type = std::tuple; + + public: + // constructor + constexpr LinearCombination(const coefficients_type & coeffs, Funcs... funcs) : + _coeffs(coeffs), + _funcs(funcs...) + {} + + // call operator + constexpr auto operator()(const input_type & x) const -> output_type + { + // helper function to assemble the linear combination + auto eval = [&](const input_type & x, std::index_sequence) { + return ((_coeffs[Is] * std::get(_funcs)(x)) + ...); + }; + + // return the result of the linear combination + return eval(x, std::make_index_sequence{}); + } + + public: + // accessor for the coefficients + constexpr auto coefficients() const -> const coefficients_type & { return _coeffs; } + + // accessor for the functions + constexpr auto functions() const -> const functions_type & { return _funcs; } + + private: + // the coefficients in the linear combination + coefficients_type _coeffs; + // the functions in the linear combination + functions_type _funcs; + }; // the sum of a function with a constant template diff --git a/lib/mito/functions/traits.h b/lib/mito/functions/traits.h index 41c9be5d7..11f99920a 100644 --- a/lib/mito/functions/traits.h +++ b/lib/mito/functions/traits.h @@ -99,6 +99,21 @@ namespace mito::functions { std::remove_cvref_t::input_type>, typename functor_traits::output_type>; }; + + // the type of the linear combination of functions {Funcs} with coefficients of type {T}... + template + // require that all the functions to combine take the same input type + requires(same_input_c) + struct function_linear_combination { + // the input type (which is the same for all functions) + using input_type = typename std::tuple_element<0, std::tuple>::type::input_type; + // the output of the linear combination + using output_type = sum_result_t...>; + + // ... is the function that takes {input_type} in input and returns the type of the sum of + // the output types multiplied by the coefficients + using type = Function; + }; } diff --git a/tests/mito.lib/functions/derivative_sum.cc b/tests/mito.lib/functions/derivative_sum.cc index ac223d6d7..b2fbd9b3e 100644 --- a/tests/mito.lib/functions/derivative_sum.cc +++ b/tests/mito.lib/functions/derivative_sum.cc @@ -106,4 +106,26 @@ TEST(Derivatives, VectorSum) } +TEST(Derivatives, LinearCombination) +{ + // pi sixths + constexpr auto pi_sixth = pi / 6.0; + + // a sine function + constexpr auto sin = mito::functions::sin; + // a cosine function + constexpr auto cos = mito::functions::cos; + // the functions linear combination + constexpr auto combination = + mito::functions::linear_combination(std::array{ 2.0, -1.0 }, sin, cos); + // check that it is equal to {2.0 * sin + -1.0 * cos} + static_assert(2.0 * sin(pi_sixth) - cos(pi_sixth) == combination(pi_sixth)); + + // the derivative of the linear combination + constexpr auto combination_1 = mito::functions::derivative(combination); + // check that it is equal to {2.0 * cos + 1.0 * sin} + static_assert(2.0 * cos(pi_sixth) + sin(pi_sixth) == combination_1(pi_sixth)); +} + + // end of file From 9a974b5d512dd45e788686d803fd19a63a3d3aa5 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 23 Aug 2025 18:14:27 +0200 Subject: [PATCH 182/273] functions: bugfix chain rule for vector valued functions The scalar version of the chain rule was silently applied for composition of vector valued functions. --- lib/mito/functions/derivation_rules.h | 21 ++++++++- lib/mito/functions/forward.h | 4 ++ .../functions/derivative_chain_rule.cc | 45 ++++++++++++++++++- 3 files changed, 68 insertions(+), 2 deletions(-) diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index bb62b6af3..4ec5dede5 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -54,13 +54,32 @@ namespace mito::functions { return -1.0 * derivative(f.f()) / (f.f() * f.f()); } - // the chain rule for the {I...}-th first partial derivative + // the chain rule for the {I...}-th first partial derivative (f1(f2(x)) with f2 scalar valued) template + requires(scalar_function_c) constexpr auto derivative(const Composition & f) { return derivative(f.f1())(f.f2()) * derivative(f.f2()); } + // the chain rule for the {I...}-th first partial derivative (f1(f2(x)) with f2 vector valued) + template + requires(vector_function_c) + constexpr auto derivative(const Composition & f) + { + // the number of components of the vector (output of F2) + constexpr int N = F2::output_type::size; + + // helper function to compute the N partial derivatives + constexpr auto _derivative = [](const auto & f, std::index_sequence) { + // the vector of the partial derivatives + return ( + (derivative(f.f1())(f.f2()) * derivative(f.f2() * tensor::e)) + ...); + }; + + return _derivative(f, std::make_index_sequence{}); + } + // the derivative of the transpose of a function template constexpr auto derivative(const Transpose & f) diff --git a/lib/mito/functions/forward.h b/lib/mito/functions/forward.h index 0fa26a3c0..83beddb91 100644 --- a/lib/mito/functions/forward.h +++ b/lib/mito/functions/forward.h @@ -29,6 +29,10 @@ namespace mito::functions { template concept scalar_function_c = function_c and tensor::scalar_c; + // concept of a vector-valued function + template + concept vector_function_c = function_c and tensor::vector_c; + // concept of functions taking the same input type template concept same_input_c = (sizeof...(Funcs) <= 1) || // trivially true for 0 or 1 diff --git a/tests/mito.lib/functions/derivative_chain_rule.cc b/tests/mito.lib/functions/derivative_chain_rule.cc index bae6cdbea..09c6cd9e3 100644 --- a/tests/mito.lib/functions/derivative_chain_rule.cc +++ b/tests/mito.lib/functions/derivative_chain_rule.cc @@ -13,7 +13,7 @@ using std::numbers::pi; using mito::tensor::scalar_t; -TEST(Derivatives, Composition) +TEST(Derivatives, Scalar) { // pi sixths constexpr auto pi_sixth = pi / 6.0; @@ -49,4 +49,47 @@ TEST(Derivatives, Composition) } +// the coordinates type +using coordinates_type_2D = mito::tensor::vector_t<2>; +using coordinates_type_3D = mito::tensor::vector_t<3>; + + +TEST(Derivatives, Vector) +{ + // components 2D + constexpr auto a = mito::functions::component; + constexpr auto b = mito::functions::component; + + // a vector function R^2 -> R^3 (internal in the composition) + constexpr auto g = a * b * mito::tensor::e<1, 3> + (a + b) * mito::tensor::e<2, 3>; + + // components 3D + constexpr auto x = mito::functions::component; + constexpr auto y = mito::functions::component; + constexpr auto z = mito::functions::component; + + // a vector function R^3 -> R^3 (external in the composition) + constexpr auto f = + x * mito::tensor::e<0, 3> + y * mito::tensor::e<1, 3> + z * mito::tensor::e<2, 3>; + + // the composition of f and g (R^2 -> R^3) + constexpr auto h = f(g); + + // pick a point + constexpr auto p = coordinates_type_2D{ 1.0, 2.0 }; + + // f(g) = a * b * mito::tensor::e<1, 3> + (a + b) * mito::tensor::e<2, 3> + static_assert( + h(p) == p[0] * p[1] * mito::tensor::e<1, 3> + (p[0] + p[1]) * mito::tensor::e<2, 3>); + + // the derivative of h + constexpr auto h_0 = mito::functions::derivative<0>(h); + constexpr auto h_1 = mito::functions::derivative<1>(h); + + // check the result + static_assert(h_0(p) == p[1] * mito::tensor::e<1, 3> + mito::tensor::e<2, 3>); + static_assert(h_1(p) == p[0] * mito::tensor::e<1, 3> + mito::tensor::e<2, 3>); +} + + // end of file From d02edd0a383420732e0e0205605c399e8c11bc44 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 25 Aug 2025 13:12:26 +0200 Subject: [PATCH 183/273] functions: bugfix in {operator*} {operator*} is not commutative on generic tensors. --- lib/mito/functions/algebra.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mito/functions/algebra.h b/lib/mito/functions/algebra.h index 29a063f4d..a3aebf3d8 100644 --- a/lib/mito/functions/algebra.h +++ b/lib/mito/functions/algebra.h @@ -33,13 +33,13 @@ namespace mito::functions { // a * f constexpr auto operator*(const tensor::tensor_or_scalar_c auto & a, const function_c auto & f) { - return FunctionTimesConstant(f, a); + return ConstantTimesFunction(a, f); } // f * a constexpr auto operator*(const function_c auto & f, const tensor::tensor_or_scalar_c auto & a) { - return a * f; + return FunctionTimesConstant(f, a); } // f / a From 0c4ec2a39380cf09c91c015497d9461902a532be Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 25 Aug 2025 13:13:43 +0200 Subject: [PATCH 184/273] functions: implement {inverse} for square matrix functions --- lib/mito/functions/algebra.h | 6 ++++++ lib/mito/functions/function.h | 37 +++++++++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/lib/mito/functions/algebra.h b/lib/mito/functions/algebra.h index a3aebf3d8..cebbb9b1e 100644 --- a/lib/mito/functions/algebra.h +++ b/lib/mito/functions/algebra.h @@ -96,6 +96,12 @@ namespace mito::functions { { return Transpose(f); } + + // f inverse + constexpr auto inverse(const function_c auto & f) + { + return Inverse(f); + } } diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 4c88d7347..0b83c2c69 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -444,6 +444,43 @@ namespace mito::functions { private: const F _f; }; + + // function computing the inverse of a second order tensor + template + requires(tensor::square_matrix_c) + class Inverse : public Function { + + public: + // the inverse function type + using inverse_type = Function; + // the input type + using input_type = inverse_type::input_type; + // the output type + using output_type = inverse_type::output_type; + + public: + // constructor + constexpr Inverse(const F & f) : _f(f) {} + + // call operator for function composition + template + constexpr auto operator()(const H & f) const + { + return Composition(*this, f); + } + + // call operator + constexpr auto operator()(const input_type & x) const -> output_type + { + return tensor::inverse(_f(x)); + } + + // the matrix function to invert + constexpr auto f() const -> const F & { return _f; } + + private: + const F _f; + }; } From 6f9d01bf00e769c4d1fd35d75597dc1cc243fdd3 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 25 Aug 2025 13:14:17 +0200 Subject: [PATCH 185/273] functions: implement composition operator for class {LinearCombination} --- lib/mito/functions/function.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 0b83c2c69..3e0cf3b40 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -149,6 +149,13 @@ namespace mito::functions { _funcs(funcs...) {} + // call operator for function composition + template + constexpr auto operator()(const H & f) const + { + return Composition(*this, f); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { From 70dd74e54a714147596ca5bbb1d6896c0f21f76d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 25 Aug 2025 13:18:42 +0200 Subject: [PATCH 186/273] functions: add test on derivative of scalar product --- .../mito.lib/functions/derivative_product.cc | 41 +++++++++++++++++-- 1 file changed, 37 insertions(+), 4 deletions(-) diff --git a/tests/mito.lib/functions/derivative_product.cc b/tests/mito.lib/functions/derivative_product.cc index f6625b535..2fb7fc60c 100644 --- a/tests/mito.lib/functions/derivative_product.cc +++ b/tests/mito.lib/functions/derivative_product.cc @@ -108,10 +108,10 @@ TEST(Derivatives, ScalarProduct) constexpr auto a = mito::tensor::vector_t<2>{ -1.0, 1.0 }; // the function returning the constant e0 unit vector in 2D - constexpr auto e0 = mito::functions::constant>(mito::tensor::e_0<2>); + constexpr auto e0 = mito::tensor::e_0<2>; // the function returning the constant e1 unit vector in 2D - constexpr auto e1 = mito::functions::constant>(mito::tensor::e_1<2>); + constexpr auto e1 = mito::tensor::e_1<2>; // the function extracting the x_0 component of a 2D vector constexpr auto x0 = mito::functions::x<0, 2>; @@ -127,8 +127,41 @@ TEST(Derivatives, ScalarProduct) constexpr auto f_1 = mito::functions::derivative<1>(f); // check result - static_assert(a * e0(x) == f_0(x)); - static_assert(a * e1(x) == f_1(x)); + static_assert(a * e0 == f_0(x)); + static_assert(a * e1 == f_1(x)); +} + + +TEST(Derivatives, ScalarProductConstant) +{ + // a 2D vector + constexpr auto x = mito::tensor::vector_t<2>{ 0.1, 1.0 }; + + // a 2D vector + constexpr auto a = mito::tensor::vector_t<2>{ -1.0, 1.0 }; + + // the constant e0 unit vector in 2D + constexpr auto e0 = mito::tensor::e_0<2>; + + // the constant e1 unit vector in 2D + constexpr auto e1 = mito::tensor::e_1<2>; + + // the function extracting the x_0 component of a 2D vector + constexpr auto x0 = mito::functions::x<0, 2>; + + // the function extracting the x_1 component of a 2D vector + constexpr auto x1 = mito::functions::x<1, 2>; + + // a function {f} + constexpr auto f = a * (x0 * e0 + x1 * e1); + + // the derivative of f with respect to x0 + constexpr auto f_0 = mito::functions::derivative<0>(f); + constexpr auto f_1 = mito::functions::derivative<1>(f); + + // check result + static_assert(a * e0 == f_0(x)); + static_assert(a * e1 == f_1(x)); } From 1d7ef25ac772c3c4d70c949ec91833e117441cfd Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 25 Aug 2025 14:50:26 +0200 Subject: [PATCH 187/273] discretization: add test on construction of shape functions and derivatives in barycentric coordinates --- .cmake/mito_tests_mito_lib.cmake | 1 + .../shape_functions_triangle_construction.cc | 136 ++++++++++++++++++ 2 files changed, 137 insertions(+) create mode 100644 tests/mito.lib/discretization/shape_functions_triangle_construction.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index e847730ba..09afc3894 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -42,6 +42,7 @@ mito_test_driver(tests/mito.lib/constraints/dirichlet.cc) mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) mito_test_driver(tests/mito.lib/discretization/mesh_field.cc) mito_test_driver(tests/mito.lib/discretization/poisson.cc) +mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_construction.cc) mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p1.cc) mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p2.cc) mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle.cc) diff --git a/tests/mito.lib/discretization/shape_functions_triangle_construction.cc b/tests/mito.lib/discretization/shape_functions_triangle_construction.cc new file mode 100644 index 000000000..e66b32ae6 --- /dev/null +++ b/tests/mito.lib/discretization/shape_functions_triangle_construction.cc @@ -0,0 +1,136 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the parametric coordinates +using parametric_coordinates_type = mito::tensor::vector_t<2>; +constexpr auto xi_0 = mito::functions::component; +constexpr auto xi_1 = mito::functions::component; + +// the barycentric coordinates type +using barycentric_coordinates_type = mito::tensor::vector_t<3>; +constexpr auto eta_0 = mito::functions::component; +constexpr auto eta_1 = mito::functions::component; +constexpr auto eta_2 = mito::functions::component; + +// the conversion from parametric to barycentric coordinates +constexpr auto parametric_to_barycentric = xi_0 * mito::tensor::e_0<3> + xi_1 * mito::tensor::e_1<3> + + (1.0 - xi_0 - xi_1) * mito::tensor::e_2<3>; + +// the conversion from barycentric to parametric coordinates +constexpr auto barycentric_to_parametric = + eta_0 * mito::tensor::e_0<2> + eta_1 * mito::tensor::e_1<2>; + + +// assemble the gradient of f +constexpr auto +gradient(const auto & f) +{ + return mito::tensor::e_0<2> * mito::functions::derivative<0>(f) + + mito::tensor::e_1<2> * mito::functions::derivative<1>(f); +} + + +TEST(Fem, ShapeTriangleConstuctionP1) +{ + // create a channel + journal::info_t channel("tests.shape_triangle_construction_p1"); + + // linear shape functions on the reference triangle in barycentric coordinates + constexpr auto phi_0 = eta_0; + constexpr auto phi_1 = eta_1; + constexpr auto phi_2 = eta_2; + constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); + + // hard-coded derivatives of shape functions with respect to parametric coordinates + constexpr auto dphi_0 = + mito::functions::constant(mito::tensor::e_0<2>); + constexpr auto dphi_1 = + mito::functions::constant(mito::tensor::e_1<2>); + constexpr auto dphi_2 = mito::functions::constant( + -mito::tensor::e_0<2> - mito::tensor::e_1<2>); + constexpr auto dphi = std::make_tuple(dphi_0, dphi_1, dphi_2); + + // assemble the shape functions gradients as the partial derivatives of the shape functions with + // respect to the parametric coordinates, seen as functions of barycentric coordinates + constexpr auto dN0 = + gradient(std::get<0>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN1 = + gradient(std::get<1>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN2 = + gradient(std::get<2>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + + // barycenter in barycentric coordinates + constexpr auto barycenter = barycentric_coordinates_type{ 1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0 }; + + // check result + static_assert(dN0(barycenter) == std::get<0>(dphi)(barycenter)); + static_assert(dN1(barycenter) == std::get<1>(dphi)(barycenter)); + static_assert(dN2(barycenter) == std::get<2>(dphi)(barycenter)); + + // all done + return; +} + + +TEST(Fem, ShapeTriangleConstuctionP2) +{ + // create a channel + journal::info_t channel("tests.shape_triangle_construction_p2"); + + // quadratic shape functions on the reference triangle in barycentric coordinates + constexpr auto phi_3 = 4.0 * eta_0 * eta_1; + constexpr auto phi_4 = 4.0 * eta_1 * eta_2; + constexpr auto phi_5 = 4.0 * eta_0 * eta_2; + constexpr auto phi_0 = eta_0 - 0.5 * phi_5 - 0.5 * phi_3; + constexpr auto phi_1 = eta_1 - 0.5 * phi_3 - 0.5 * phi_4; + constexpr auto phi_2 = eta_2 - 0.5 * phi_5 - 0.5 * phi_4; + constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); + + // hard-coded derivatives of shape functions with respect to parametric coordinates + constexpr auto dphi_0 = mito::tensor::e_0<2> * (1.0 - 2.0 * eta_1 - 2.0 * eta_2 + 2.0 * eta_0); + constexpr auto dphi_1 = mito::tensor::e_1<2> * (1.0 - 2.0 * eta_0 - 2.0 * eta_2 + 2.0 * eta_1); + constexpr auto dphi_2 = (mito::tensor::e_0<2> + mito::tensor::e_1<2>) *( + -1.0 - 2.0 * eta_2 + 2.0 * eta_0 + 2.0 * eta_1); + constexpr auto dphi_3 = + mito::tensor::e_0<2> * (4.0 * eta_1) + mito::tensor::e_1<2> * (4.0 * eta_0); + constexpr auto dphi_4 = + mito::tensor::e_0<2> * (-4.0 * eta_1) + mito::tensor::e_1<2> * (4.0 * eta_2 - 4.0 * eta_1); + constexpr auto dphi_5 = + mito::tensor::e_0<2> * (4.0 * eta_2 - 4.0 * eta_0) + mito::tensor::e_1<2> * (-4.0 * eta_0); + constexpr auto dphi = std::make_tuple(dphi_0, dphi_1, dphi_2, dphi_3, dphi_4, dphi_5); + + // assemble the shape functions gradients as the partial derivatives of the shape functions with + // respect to the parametric coordinates, seen as functions of barycentric coordinates + constexpr auto dN0 = + gradient(std::get<0>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN1 = + gradient(std::get<1>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN2 = + gradient(std::get<2>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN3 = + gradient(std::get<3>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN4 = + gradient(std::get<4>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN5 = + gradient(std::get<5>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + + // barycenter in barycentric coordinates + constexpr auto barycenter = barycentric_coordinates_type{ 1.0, 0.0, 0.0 }; + + // check result + static_assert(dN0(barycenter) == std::get<0>(dphi)(barycenter)); + static_assert(dN1(barycenter) == std::get<1>(dphi)(barycenter)); + static_assert(dN2(barycenter) == std::get<2>(dphi)(barycenter)); + static_assert(dN3(barycenter) == std::get<3>(dphi)(barycenter)); + static_assert(dN4(barycenter) == std::get<4>(dphi)(barycenter)); + static_assert(dN5(barycenter) == std::get<5>(dphi)(barycenter)); + + // all done + return; +} \ No newline at end of file From 6d85434742a0522e6409c69219b4ec11851c73ca Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 25 Aug 2025 19:26:18 +0200 Subject: [PATCH 188/273] functions: uniformly rename type of function alias --- lib/mito/functions/function.h | 64 ++++++++++++++++++----------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 3e0cf3b40..b8e1a2b50 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -56,10 +56,12 @@ namespace mito::functions { template class Constant : public Function { public: + // the type of function (what I derive from) + using function_type = Function; // the input type - using input_type = Function::input_type; + using input_type = function_type::input_type; // the output type - using output_type = Function::output_type; + using output_type = function_type::output_type; public: // constructor @@ -89,11 +91,11 @@ namespace mito::functions { class Sum : public function_sum::type { public: // the type of sum function (what I derive from) - using sum_type = function_sum::type; + using function_type = function_sum::type; // the input type of the sum - using input_type = sum_type::input_type; + using input_type = function_type::input_type; // the output type of the sum - using output_type = sum_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -188,11 +190,11 @@ namespace mito::functions { public: // the type of function (what I derive from) - using my_function_type = function_type; + using function_type = functions::function_type; // the input type of the sum - using input_type = my_function_type::input_type; + using input_type = function_type::input_type; // the output type of the sum - using output_type = my_function_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -227,11 +229,11 @@ namespace mito::functions { class Product : public function_product::type { public: // the type of product function (what I derive from) - using product_type = function_product::type; + using function_type = function_product::type; // the input type of the sum - using input_type = product_type::input_type; + using input_type = function_type::input_type; // the output type of the sum - using output_type = product_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -269,11 +271,11 @@ namespace mito::functions { public: // the type of function (what I derive from) - using my_function_type = function_product>::type; + using function_type = function_product>::type; // the input type of the sum - using input_type = my_function_type::input_type; + using input_type = function_type::input_type; // the output type of the sum - using output_type = my_function_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -310,11 +312,11 @@ namespace mito::functions { public: // the type of function (what I derive from) - using my_function_type = function_product, F>::type; + using function_type = function_product, F>::type; // the input type of the sum - using input_type = my_function_type::input_type; + using input_type = function_type::input_type; // the output type of the sum - using output_type = my_function_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -350,11 +352,11 @@ namespace mito::functions { public: // the type of function (what I derive from) - using my_function_type = function_type; + using function_type = functions::function_type; // the input type of the sum - using input_type = my_function_type::input_type; + using input_type = function_type::input_type; // the output type of the sum - using output_type = my_function_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -384,11 +386,11 @@ namespace mito::functions { public: // the type of composition function (what I derive from) - using composition_type = function_composition::type; + using function_type = function_composition::type; // the input type of the composition - using input_type = composition_type::input_type; + using input_type = function_type::input_type; // the output type of the composition - using output_type = composition_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -421,12 +423,12 @@ namespace mito::functions { class Transpose : public function_transpose::type { public: - // the transpose function type - using transpose_type = function_transpose::type; + // the type of the function (what I derive from) + using function_type = function_transpose::type; // the input type - using input_type = transpose_type::input_type; + using input_type = function_type::input_type; // the output type - using output_type = transpose_type::output_type; + using output_type = function_type::output_type; public: // constructor @@ -458,12 +460,12 @@ namespace mito::functions { class Inverse : public Function { public: - // the inverse function type - using inverse_type = Function; + // the type of the function (what I derive from) + using function_type = Function; // the input type - using input_type = inverse_type::input_type; + using input_type = function_type::input_type; // the output type - using output_type = inverse_type::output_type; + using output_type = function_type::output_type; public: // constructor From ad0304ed87e9790df51f07fd9e0113b8643546f9 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 26 Aug 2025 12:01:08 +0200 Subject: [PATCH 189/273] functions: add concept of a tensor function --- lib/mito/functions/forward.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/mito/functions/forward.h b/lib/mito/functions/forward.h index 83beddb91..3940eca7c 100644 --- a/lib/mito/functions/forward.h +++ b/lib/mito/functions/forward.h @@ -33,6 +33,10 @@ namespace mito::functions { template concept vector_function_c = function_c and tensor::vector_c; + // concept of a tensor-valued function + template + concept tensor_function_c = function_c and tensor::tensor_c; + // concept of functions taking the same input type template concept same_input_c = (sizeof...(Funcs) <= 1) || // trivially true for 0 or 1 From d8d6f4b99df4c1eada85e31e4e7fc4c6516d9a77 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 26 Aug 2025 12:02:18 +0200 Subject: [PATCH 190/273] functions: add subscript function operator and its derivative --- .cmake/mito_tests_mito_lib.cmake | 1 + lib/mito/functions/derivation_rules.h | 8 ++ lib/mito/functions/forward.h | 13 ++ lib/mito/functions/function.h | 117 ++++++++++++++++++ lib/mito/functions/traits.h | 7 ++ .../functions/derivative_subscript.cc | 27 ++++ 6 files changed, 173 insertions(+) create mode 100644 tests/mito.lib/functions/derivative_subscript.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 09afc3894..9f8a2d84e 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -10,6 +10,7 @@ mito_test_driver(tests/mito.lib/functions/derivative_constants.cc) mito_test_driver(tests/mito.lib/functions/derivative_chain_rule.cc) mito_test_driver(tests/mito.lib/functions/derivative_higher_order.cc) mito_test_driver(tests/mito.lib/functions/derivative_sum.cc) +mito_test_driver(tests/mito.lib/functions/derivative_subscript.cc) mito_test_driver(tests/mito.lib/functions/derivative_product.cc) mito_test_driver(tests/mito.lib/functions/derivative_inverse.cc) mito_test_driver(tests/mito.lib/functions/partial_derivatives.cc) diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index 4ec5dede5..954fda8de 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -88,6 +88,14 @@ namespace mito::functions { return functions::transpose(derivative(f.f())); } + // the {I...}-th first partial derivative of the {Subscript} function + template + constexpr auto derivative(const Subscript & f) + { + // the derivative of the subscript is the subscript of the derivative + return Subscript(derivative(f.f()), f.index()); + } + // the {I...}-th first partial derivative of a linear combination template constexpr auto derivative(const LinearCombination & f) diff --git a/lib/mito/functions/forward.h b/lib/mito/functions/forward.h index 3940eca7c..b338d5cd5 100644 --- a/lib/mito/functions/forward.h +++ b/lib/mito/functions/forward.h @@ -37,6 +37,16 @@ namespace mito::functions { template concept tensor_function_c = function_c and tensor::tensor_c; + // concept of a subscriptable type + template + concept subscriptable_c = requires(F f, int i) { + { f[i] }; + }; + + // concept of a subscriptable function + template + concept subscriptable_function_c = function_c and subscriptable_c; + // concept of functions taking the same input type template concept same_input_c = (sizeof...(Funcs) <= 1) || // trivially true for 0 or 1 @@ -49,6 +59,9 @@ namespace mito::functions { template class Composition; + // function subscript + template + class Subscript; } diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index b8e1a2b50..bc2720733 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -43,6 +43,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(x); } @@ -77,6 +84,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type &) const -> output_type { return _c; } @@ -108,6 +122,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -158,6 +179,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -210,6 +238,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(x) + _a; } @@ -246,6 +281,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -291,6 +333,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(x) * _a; } @@ -332,6 +381,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _a * _f(x); } @@ -403,6 +459,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(_g(x)); } @@ -417,6 +480,46 @@ namespace mito::functions { const G _g; }; + + template + class Subscript : public function_subscript::type { + + public: + // the type of the function (what I derive from) + using function_type = function_subscript::type; + // the input type + using input_type = function_type::input_type; + // the output type + using output_type = function_type::output_type; + // the type of index + using index_type = int; + + public: + // constructor + constexpr Subscript(const F & f, const int i) : _f(f), _i(i) {} + + // call operator for function composition + template + constexpr auto operator()(const H & f) const + { + return Composition(*this, f); + } + + // call operator + constexpr auto operator()(const input_type & x) const -> output_type { return _f(x)[_i]; } + + // the function to subscript + constexpr auto f() const -> const F & { return _f; } + + // the index + constexpr auto index() const -> int { return _i; } + + private: + const F _f; + const int _i; + }; + + // function transposing a function of a second order tensor template requires(tensor::matrix_c) @@ -441,6 +544,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -478,6 +588,13 @@ namespace mito::functions { return Composition(*this, f); } + // subscript operator: only available if {output_type} is a tensor + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { diff --git a/lib/mito/functions/traits.h b/lib/mito/functions/traits.h index 11f99920a..d78d81137 100644 --- a/lib/mito/functions/traits.h +++ b/lib/mito/functions/traits.h @@ -66,6 +66,13 @@ namespace mito::functions { using type = Function; }; + // the type of the subscript of a tensor function... + template + struct function_subscript { + // ... is the function that takes the {input_type} of F and returns the scalar type  + using type = Function; + }; + // the type of the transpose of a function... template // with matrix values... diff --git a/tests/mito.lib/functions/derivative_subscript.cc b/tests/mito.lib/functions/derivative_subscript.cc new file mode 100644 index 000000000..1f238821e --- /dev/null +++ b/tests/mito.lib/functions/derivative_subscript.cc @@ -0,0 +1,27 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// pi +using std::numbers::pi; + + +TEST(Derivatives, Subscript) +{ + // a matrix + constexpr auto x = pi / 4.0; + + // a vector function R -> R^2x3 + constexpr auto f = mito::functions::sin * mito::tensor::e_12<2, 3>; + + // check that the derivative of the subscript is the subscript of the derivative + static_assert(mito::functions::derivative(f[5])(x) == mito::functions::derivative(f)(x)[5]); +} + + +// end of file From daf2cf05c7012021dd8cf74287a1b94d11f39055 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 26 Aug 2025 14:47:32 +0200 Subject: [PATCH 191/273] functions: clarify concepts of scalar (vector) functions and scalar- (vector-) valued functions --- lib/mito/fields/fields_functions_arithmetic.h | 2 +- lib/mito/functions/algebra.h | 4 +-- lib/mito/functions/derivation_rules.h | 4 +-- lib/mito/functions/forward.h | 30 +++++++++++++++++-- lib/mito/functions/function.h | 2 +- 5 files changed, 33 insertions(+), 9 deletions(-) diff --git a/lib/mito/fields/fields_functions_arithmetic.h b/lib/mito/fields/fields_functions_arithmetic.h index 50b7e6dea..bb479e484 100644 --- a/lib/mito/fields/fields_functions_arithmetic.h +++ b/lib/mito/fields/fields_functions_arithmetic.h @@ -51,7 +51,7 @@ namespace mito::fields { } // field1 / field2 - template + template constexpr auto operator/(const F1 & f1, const F2 & f2) { return field(f1.function() / f2); diff --git a/lib/mito/functions/algebra.h b/lib/mito/functions/algebra.h index cebbb9b1e..b464aa3be 100644 --- a/lib/mito/functions/algebra.h +++ b/lib/mito/functions/algebra.h @@ -80,13 +80,13 @@ namespace mito::functions { // a / f constexpr auto operator/( - const tensor::tensor_or_scalar_c auto & a, const scalar_function_c auto & f) + const tensor::tensor_or_scalar_c auto & a, const scalar_valued_function_c auto & f) { return a * Reciprocal(f); } // f1 / f2 - constexpr auto operator/(const function_c auto & f1, const scalar_function_c auto & f2) + constexpr auto operator/(const function_c auto & f1, const scalar_valued_function_c auto & f2) { return f1 * Reciprocal(f2); } diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index 954fda8de..1ff521624 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -56,7 +56,7 @@ namespace mito::functions { // the chain rule for the {I...}-th first partial derivative (f1(f2(x)) with f2 scalar valued) template - requires(scalar_function_c) + requires(scalar_valued_function_c) constexpr auto derivative(const Composition & f) { return derivative(f.f1())(f.f2()) * derivative(f.f2()); @@ -64,7 +64,7 @@ namespace mito::functions { // the chain rule for the {I...}-th first partial derivative (f1(f2(x)) with f2 vector valued) template - requires(vector_function_c) + requires(vector_valued_function_c) constexpr auto derivative(const Composition & f) { // the number of components of the vector (output of F2) diff --git a/lib/mito/functions/forward.h b/lib/mito/functions/forward.h index b338d5cd5..33dd4e15b 100644 --- a/lib/mito/functions/forward.h +++ b/lib/mito/functions/forward.h @@ -25,17 +25,41 @@ namespace mito::functions { template concept functor_c = requires { &F::operator(); } and not function_c; + // concept of a function defined on scalars + template + concept scalar_domain_function_c = function_c and tensor::scalar_c; + // concept of a scalar-valued function template - concept scalar_function_c = function_c and tensor::scalar_c; + concept scalar_valued_function_c = function_c and tensor::scalar_c; + + // concept of a scalar-valued function of scalars + template + concept scalar_function_c = scalar_domain_function_c and scalar_valued_function_c; + + // concept of a function defined on vectors + template + concept vector_domain_function_c = function_c and tensor::vector_c; // concept of a vector-valued function template - concept vector_function_c = function_c and tensor::vector_c; + concept vector_valued_function_c = function_c and tensor::vector_c; + + // concept of a vector-valued function of vectors + template + concept vector_function_c = vector_domain_function_c and vector_valued_function_c; + + // concept of a function defined on tensors + template + concept tensor_domain_function_c = function_c and tensor::tensor_c; // concept of a tensor-valued function template - concept tensor_function_c = function_c and tensor::tensor_c; + concept tensor_valued_function_c = function_c and tensor::tensor_c; + + // concept of a tensor-valued function of tensors + template + concept tensor_function_c = tensor_domain_function_c and tensor_valued_function_c; // concept of a subscriptable type template diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index bc2720733..5475fb263 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -403,7 +403,7 @@ namespace mito::functions { // the reciprocal of a scalar function - template + template class Reciprocal : public function_type { public: From dfb0f80b052f2e1c853950e180895d343ceb7483 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 26 Aug 2025 16:51:09 +0200 Subject: [PATCH 192/273] functions: redesign partial derivatives of tensor functions Partial derivatives of tensor-valued functions of tensors are now represented as matrices of functions: rows correspond to output components, columns to input components. This redesign replaces the previous multi-index parameter-pack interface with a single integer template argument indicating the input component being differentiated. --- lib/mito/functions/derivation_rules.h | 64 ++++++++-------- lib/mito/functions/library_derivatives.h | 60 +++++++-------- lib/mito/functions/library_functions.h | 6 +- lib/mito/functions/partial_derivatives.h | 94 ++++++++++++++++++++++++ lib/mito/functions/public.h | 2 + 5 files changed, 161 insertions(+), 65 deletions(-) create mode 100644 lib/mito/functions/partial_derivatives.h diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index 1ff521624..a2bea57de 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -12,58 +12,58 @@ namespace mito::functions { - // the {I...}-th first partial derivative of a function sum - template + // the I-th first partial derivative of a function sum + template constexpr auto derivative(const Sum & f) { - return derivative(f.f1()) + derivative(f.f2()); + return derivative(f.f1()) + derivative(f.f2()); } - // the {I...}-th first partial derivative of a constant plus a function - template + // the I-th first partial derivative of a constant plus a function + template constexpr auto derivative(const FunctionPlusConstant & f) { - return derivative(f.f()); + return derivative(f.f()); } - // the {I...}-th first partial derivative of a function times a constant - template + // the I-th first partial derivative of a function times a constant + template constexpr auto derivative(const FunctionTimesConstant & f) { - return derivative(f.f()) * f.constant(); + return derivative(f.f()) * f.constant(); } - // the {I...}-th first partial derivative of a constant times a function - template + // the I-th first partial derivative of a constant times a function + template constexpr auto derivative(const ConstantTimesFunction & f) { - return f.constant() * derivative(f.f()); + return f.constant() * derivative(f.f()); } - // the {I...}-th first partial derivative of a product of functions - template + // the I-th first partial derivative of a product of functions + template constexpr auto derivative(const Product & f) { - return f.f1() * derivative(f.f2()) + derivative(f.f1()) * f.f2(); + return f.f1() * derivative(f.f2()) + derivative(f.f1()) * f.f2(); } - // the {I...}-th first partial derivative of a product of the reciprocal function - template + // the I-th first partial derivative of a product of the reciprocal function + template constexpr auto derivative(const Reciprocal & f) { - return -1.0 * derivative(f.f()) / (f.f() * f.f()); + return -1.0 * derivative(f.f()) / (f.f() * f.f()); } - // the chain rule for the {I...}-th first partial derivative (f1(f2(x)) with f2 scalar valued) - template + // the chain rule for the I-th first partial derivative (f1(f2(x)) with f2 scalar valued) + template requires(scalar_valued_function_c) constexpr auto derivative(const Composition & f) { - return derivative(f.f1())(f.f2()) * derivative(f.f2()); + return derivative(f.f1())(f.f2()) * derivative(f.f2()); } - // the chain rule for the {I...}-th first partial derivative (f1(f2(x)) with f2 vector valued) - template + // the chain rule for the I-th first partial derivative (f1(f2(x)) with f2 vector valued) + template requires(vector_valued_function_c) constexpr auto derivative(const Composition & f) { @@ -74,35 +74,35 @@ namespace mito::functions { constexpr auto _derivative = [](const auto & f, std::index_sequence) { // the vector of the partial derivatives return ( - (derivative(f.f1())(f.f2()) * derivative(f.f2() * tensor::e)) + ...); + (derivative(f.f1())(f.f2()) * derivative(f.f2() * tensor::e)) + ...); }; return _derivative(f, std::make_index_sequence{}); } // the derivative of the transpose of a function - template + template constexpr auto derivative(const Transpose & f) { // the derivative of the transpose is the transpose of the derivative - return functions::transpose(derivative(f.f())); + return functions::transpose(derivative(f.f())); } - // the {I...}-th first partial derivative of the {Subscript} function - template + // the I-th first partial derivative of the {Subscript} function + template constexpr auto derivative(const Subscript & f) { // the derivative of the subscript is the subscript of the derivative - return Subscript(derivative(f.f()), f.index()); + return Subscript(derivative(f.f()), f.index()); } - // the {I...}-th first partial derivative of a linear combination - template + // the I-th first partial derivative of a linear combination + template constexpr auto derivative(const LinearCombination & f) { // the derivative of a linear combination is the linear combination of the derivatives return linear_combination( - f.coefficients(), derivative(std::get(f.functions()))...); + f.coefficients(), derivative(std::get(f.functions()))...); } } diff --git a/lib/mito/functions/library_derivatives.h b/lib/mito/functions/library_derivatives.h index 83265077a..f25066e8f 100644 --- a/lib/mito/functions/library_derivatives.h +++ b/lib/mito/functions/library_derivatives.h @@ -9,104 +9,104 @@ namespace mito::functions { - // the {I...}-th first partial derivative of the {Constant} function - template + // the I-th first partial derivative of the {Constant} function + template constexpr auto derivative(const Constant &) { // the zero constant return Constant({}); } - // the {I...}-th first partial derivative of the {Power} function - template + // the I-th first partial derivative of the {Power} function + template constexpr auto derivative(const Power &) { return N * pow; } - // the {I...}-th first partial derivative of the {Power<1>} function - template + // the I-th first partial derivative of the {Power<1>} function + template constexpr auto derivative(const Power<1> &) { return one; } - // the {I...}-th first partial derivative of the {Sin} function - template + // the I-th first partial derivative of the {Sin} function + template constexpr auto derivative(const Sin &) { return cos; } - // the {I...}-th first partial derivative of the {Cos} function - template + // the I-th first partial derivative of the {Cos} function + template constexpr auto derivative(const Cos &) { return -sin; } - // the {I...}-th first partial derivative of the {Tan} function - template + // the I-th first partial derivative of the {Tan} function + template constexpr auto derivative(const Tan &) { return 1.0 / pow<2>(cos); } - // the {I...}-th first partial derivative of the {ArcCos} function - template + // the I-th first partial derivative of the {ArcCos} function + template constexpr auto derivative(const ArcCos &) { return -1.0 / sqrt(1.0 - pow<2>); } - // the {I...}-th first partial derivative of the {ArcSin} function - template + // the I-th first partial derivative of the {ArcSin} function + template constexpr auto derivative(const ArcSin &) { return 1.0 / sqrt(1.0 - pow<2>); } - // the {I...}-th first partial derivative of the {ArcTan} function - template + // the I-th first partial derivative of the {ArcTan} function + template constexpr auto derivative(const ArcTan &) { return 1.0 / (1.0 + pow<2>); } - // the {I...}-th first partial derivative of the {Exp} function - template + // the I-th first partial derivative of the {Exp} function + template constexpr auto derivative(const Exp &) { return exp; } - // the {I...}-th first partial derivative of the {Log} function - template + // the I-th first partial derivative of the {Log} function + template constexpr auto derivative(const Log &) { return 1.0 / pow<1>; } - // the {I...}-th first partial derivative of the {Sqrt} function - template + // the I-th first partial derivative of the {Sqrt} function + template constexpr auto derivative(const Sqrt &) { return 0.5 / sqrt; } - // the {I...}-th first partial derivative of the {Cbrt} function - template + // the I-th first partial derivative of the {Cbrt} function + template constexpr auto derivative(const Cbrt &) { return (1.0 / 3.0) / pow<2>(cbrt); } - // the {I...}-th first partial derivative of the {Component} function - template - constexpr auto derivative(const Component &) + // the I-th first partial derivative of the {Component} function + template + constexpr auto derivative(const Component &) { // the dirac delta - if constexpr (std::make_tuple(I...) == std::make_tuple(N...)) + if constexpr (I == N) return one; else return zero; diff --git a/lib/mito/functions/library_functions.h b/lib/mito/functions/library_functions.h index 9622e8be3..bd92f4a2a 100644 --- a/lib/mito/functions/library_functions.h +++ b/lib/mito/functions/library_functions.h @@ -12,8 +12,8 @@ namespace mito::functions { - // function extracting the {I...} component of a tensor - template + // function extracting the I-th component of a tensor + template class Component : public Function { public: @@ -31,7 +31,7 @@ namespace mito::functions { } // call operator - constexpr auto operator()(const input_type & x) const -> output_type { return x[{ I... }]; } + constexpr auto operator()(const input_type & x) const -> output_type { return x[I]; } }; diff --git a/lib/mito/functions/partial_derivatives.h b/lib/mito/functions/partial_derivatives.h new file mode 100644 index 000000000..c935a3444 --- /dev/null +++ b/lib/mito/functions/partial_derivatives.h @@ -0,0 +1,94 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// Partial derivatives + + +namespace mito::functions { + + template + constexpr auto derivative(const F & f) + { + return derivative<0>(f); + } + + namespace { + // implementation of the assembly of the matrix of partial derivatives + // (row: output index; column: input index) + template + constexpr auto derivative_impl(const F & f) + { + // the output matrix type + using output_matrix = tensor::matrix_t; + + // helper function to compute the derivative + constexpr auto _derivative = [](const F & f, std::index_sequence) { + constexpr auto _derivative_with_respect_to = + [](const F & f, std::index_sequence) { + // the matrix of the partial derivatives + // (\partial field_I / \partial x_K ) * e_IK, I = 0, ..., N-1, K = 0, ..., + // D-1 + if constexpr (N == 1) { + return ((derivative(f) * tensor::unit) +...); + } else { + return ((derivative(f[I]) * tensor::unit) +...); + } + }; + + return ( + (_derivative_with_respect_to.template operator()( + f, std::make_index_sequence{})) + + ...); + }; + + return _derivative(f, std::make_index_sequence{}); + } + } + + // the derivative of a tensor-valued function of tensors + template + constexpr auto derivative(const F & f) + { + // the number of components of the input vector of F + constexpr int D = F::input_type::size; + // the number of components of the output vector of F + constexpr int N = F::output_type::size; + // call the implementation + return derivative_impl(f); + } + + // the derivative of a scalar-valued function of tensors + template + requires(tensor_domain_function_c and scalar_valued_function_c) + constexpr auto derivative(const F & f) + { + // the number of components of the input vector of F + constexpr int D = F::input_type::size; + // the number of components of the output vector of F + constexpr int N = 1; + // call the implementation + return derivative_impl(f); + } + + // the derivative of a tensor-valued function of scalars + template + requires(scalar_domain_function_c and tensor_valued_function_c) + constexpr auto derivative(const F & f) + { + // the number of components of the input vector of F + constexpr int D = 1; + // the number of components of the output vector of F + constexpr int N = F::output_type::size; + // call the implementation + return derivative_impl(f); + } +} + + +// end of file diff --git a/lib/mito/functions/public.h b/lib/mito/functions/public.h index 681fc99b0..0ff689b6f 100644 --- a/lib/mito/functions/public.h +++ b/lib/mito/functions/public.h @@ -33,6 +33,8 @@ #include "library_derivatives.h" // the derivation rules #include "derivation_rules.h" +// compact notation for partial derivatives +#include "partial_derivatives.h" // end of file From 35b36f441178a6e6ea9a9c438d413b4ca772a4dc Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 26 Aug 2025 16:53:21 +0200 Subject: [PATCH 193/273] tests/discretization: mark end of file --- .../discretization/shape_functions_triangle_construction.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/mito.lib/discretization/shape_functions_triangle_construction.cc b/tests/mito.lib/discretization/shape_functions_triangle_construction.cc index e66b32ae6..bef93c1e5 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_construction.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_construction.cc @@ -133,4 +133,6 @@ TEST(Fem, ShapeTriangleConstuctionP2) // all done return; -} \ No newline at end of file +} + +// end of file \ No newline at end of file From 73328ebfd932d5b191adce7fd1c477e5fffddca9 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 26 Aug 2025 16:56:46 +0200 Subject: [PATCH 194/273] tests/discretization: rewrite test of construction of shape functions with new partial derivatives notation --- .../shape_functions_triangle_construction.cc | 63 ++++++++----------- 1 file changed, 27 insertions(+), 36 deletions(-) diff --git a/tests/mito.lib/discretization/shape_functions_triangle_construction.cc b/tests/mito.lib/discretization/shape_functions_triangle_construction.cc index bef93c1e5..1b8a619a6 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_construction.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_construction.cc @@ -27,15 +27,6 @@ constexpr auto barycentric_to_parametric = eta_0 * mito::tensor::e_0<2> + eta_1 * mito::tensor::e_1<2>; -// assemble the gradient of f -constexpr auto -gradient(const auto & f) -{ - return mito::tensor::e_0<2> * mito::functions::derivative<0>(f) - + mito::tensor::e_1<2> * mito::functions::derivative<1>(f); -} - - TEST(Fem, ShapeTriangleConstuctionP1) { // create a channel @@ -58,20 +49,20 @@ TEST(Fem, ShapeTriangleConstuctionP1) // assemble the shape functions gradients as the partial derivatives of the shape functions with // respect to the parametric coordinates, seen as functions of barycentric coordinates - constexpr auto dN0 = - gradient(std::get<0>(phi)(parametric_to_barycentric))(barycentric_to_parametric); - constexpr auto dN1 = - gradient(std::get<1>(phi)(parametric_to_barycentric))(barycentric_to_parametric); - constexpr auto dN2 = - gradient(std::get<2>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN0 = mito::functions::derivative(std::get<0>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); + constexpr auto dN1 = mito::functions::derivative(std::get<1>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); + constexpr auto dN2 = mito::functions::derivative(std::get<2>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); // barycenter in barycentric coordinates constexpr auto barycenter = barycentric_coordinates_type{ 1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0 }; // check result - static_assert(dN0(barycenter) == std::get<0>(dphi)(barycenter)); - static_assert(dN1(barycenter) == std::get<1>(dphi)(barycenter)); - static_assert(dN2(barycenter) == std::get<2>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN0(barycenter)) == std::get<0>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN1(barycenter)) == std::get<1>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN2(barycenter)) == std::get<2>(dphi)(barycenter)); // all done return; @@ -107,29 +98,29 @@ TEST(Fem, ShapeTriangleConstuctionP2) // assemble the shape functions gradients as the partial derivatives of the shape functions with // respect to the parametric coordinates, seen as functions of barycentric coordinates - constexpr auto dN0 = - gradient(std::get<0>(phi)(parametric_to_barycentric))(barycentric_to_parametric); - constexpr auto dN1 = - gradient(std::get<1>(phi)(parametric_to_barycentric))(barycentric_to_parametric); - constexpr auto dN2 = - gradient(std::get<2>(phi)(parametric_to_barycentric))(barycentric_to_parametric); - constexpr auto dN3 = - gradient(std::get<3>(phi)(parametric_to_barycentric))(barycentric_to_parametric); - constexpr auto dN4 = - gradient(std::get<4>(phi)(parametric_to_barycentric))(barycentric_to_parametric); - constexpr auto dN5 = - gradient(std::get<5>(phi)(parametric_to_barycentric))(barycentric_to_parametric); + constexpr auto dN0 = mito::functions::derivative(std::get<0>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); + constexpr auto dN1 = mito::functions::derivative(std::get<1>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); + constexpr auto dN2 = mito::functions::derivative(std::get<2>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); + constexpr auto dN3 = mito::functions::derivative(std::get<3>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); + constexpr auto dN4 = mito::functions::derivative(std::get<4>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); + constexpr auto dN5 = mito::functions::derivative(std::get<5>(phi)(parametric_to_barycentric))( + barycentric_to_parametric); // barycenter in barycentric coordinates constexpr auto barycenter = barycentric_coordinates_type{ 1.0, 0.0, 0.0 }; // check result - static_assert(dN0(barycenter) == std::get<0>(dphi)(barycenter)); - static_assert(dN1(barycenter) == std::get<1>(dphi)(barycenter)); - static_assert(dN2(barycenter) == std::get<2>(dphi)(barycenter)); - static_assert(dN3(barycenter) == std::get<3>(dphi)(barycenter)); - static_assert(dN4(barycenter) == std::get<4>(dphi)(barycenter)); - static_assert(dN5(barycenter) == std::get<5>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN0(barycenter)) == std::get<0>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN1(barycenter)) == std::get<1>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN2(barycenter)) == std::get<2>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN3(barycenter)) == std::get<3>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN4(barycenter)) == std::get<4>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN5(barycenter)) == std::get<5>(dphi)(barycenter)); // all done return; From ace004c9564f5a351c79d502303ed729bdf75d78 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 30 Aug 2025 18:31:19 +0200 Subject: [PATCH 195/273] tests/functions: add test with derivatives of tensor functions The test include all 9 combinations of scalar/vector/matrix functions of scalar/vector/matrix. --- .cmake/mito_tests_mito_lib.cmake | 1 + .../mito.lib/functions/tensor_derivatives.cc | 208 ++++++++++++++++++ 2 files changed, 209 insertions(+) create mode 100644 tests/mito.lib/functions/tensor_derivatives.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 9f8a2d84e..b0212937b 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -14,6 +14,7 @@ mito_test_driver(tests/mito.lib/functions/derivative_subscript.cc) mito_test_driver(tests/mito.lib/functions/derivative_product.cc) mito_test_driver(tests/mito.lib/functions/derivative_inverse.cc) mito_test_driver(tests/mito.lib/functions/partial_derivatives.cc) +mito_test_driver(tests/mito.lib/functions/tensor_derivatives.cc) #  geometry mito_test_driver(tests/mito.lib/geometry/coordinates.cc) diff --git a/tests/mito.lib/functions/tensor_derivatives.cc b/tests/mito.lib/functions/tensor_derivatives.cc new file mode 100644 index 000000000..0ce8991c2 --- /dev/null +++ b/tests/mito.lib/functions/tensor_derivatives.cc @@ -0,0 +1,208 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the coordinates functions in 2D space +static constexpr auto x0 = mito::functions::x<0, 2>; +static constexpr auto x1 = mito::functions::x<1, 2>; + +// unit vectors in 3D +static constexpr auto e0 = mito::tensor::e_0<3>; +static constexpr auto e1 = mito::tensor::e_1<3>; +static constexpr auto e2 = mito::tensor::e_2<3>; + +// unit matrices in 2D +static constexpr auto e00 = mito::tensor::e_00<2>; +static constexpr auto e01 = mito::tensor::e_01<2>; +static constexpr auto e10 = mito::tensor::e_10<2>; +static constexpr auto e11 = mito::tensor::e_11<2>; + + +TEST(Derivatives, ScalarOfScalar) +{ + // a scalar function of scalar + constexpr auto f = mito::functions::sin; + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a scalar input + constexpr auto x = mito::tensor::scalar_t{ 2.0 }; + // check that the derivative is correct + static_assert(df(x) == mito::functions::cos(x)); +} + + +TEST(Derivatives, ScalarOfVector) +{ + // a scalar function of a 2D vector + constexpr auto f = mito::functions::sin(x0 * x1); + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a 2D vector input + constexpr auto x = mito::tensor::vector_t<2>{ 0.1, 1.0 }; + // check the derivatives + static_assert(df(x)[0] == (mito::functions::cos(x0 * x1) * x1)(x)); + static_assert(df(x)[1] == (mito::functions::cos(x0 * x1) * x0)(x)); +} + + +TEST(Derivatives, ScalarOfMatrix) +{ + // a scalar function of a 2D matrix (trace) + constexpr auto f = mito::functions::component, 0> + + mito::functions::component, 3>; + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a 2D matrix input + constexpr auto A = mito::tensor::matrix_t<2, 2>{ 1.0, 2.0, 3.0, 4.0 }; + // check the derivatives + static_assert(df(A)[0] == 1.0); + static_assert(df(A)[1] == 0.0); + static_assert(df(A)[2] == 0.0); + static_assert(df(A)[3] == 1.0); +} + + +TEST(Derivatives, VectorOfScalar) +{ + // a 3D vector function of a scalar + constexpr auto f = + mito::functions::sin * e0 + mito::functions::cos * e1 + mito::functions::exp * e2; + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a scalar input + constexpr auto x = mito::tensor::scalar_t{ 0.5 }; + // check the derivatives + static_assert(df(x)[{ 0, 0 }] == mito::functions::cos(x)); // d/dx sin = cos + static_assert(df(x)[{ 1, 0 }] == -mito::functions::sin(x)); // d/dx cos = -sin + static_assert(df(x)[{ 2, 0 }] == mito::functions::exp(x)); // d/dx exp = exp +} + + +TEST(Derivatives, VectorOfVector) +{ + // a 3D vector function of a 2D vector + constexpr auto f = x0 * e0 + x1 * e1 + x0 * x1 * e2; + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a 2D vector input + constexpr auto x = mito::tensor::vector_t<2>{ 0.1, 0.2 }; + // check the derivatives + static_assert(df(x)[{ 0, 0 }] == 1.0); + static_assert(df(x)[{ 0, 1 }] == 0.0); + static_assert(df(x)[{ 1, 0 }] == 0.0); + static_assert(df(x)[{ 1, 1 }] == 1.0); + static_assert(df(x)[{ 2, 0 }] == x1(x)); + static_assert(df(x)[{ 2, 1 }] == x0(x)); +} + + +TEST(Derivatives, VectorOfMatrix) +{ + // component function to extract A_ij from a matrix A + constexpr auto A_00 = mito::functions::component, 0>; + constexpr auto A_01 = mito::functions::component, 1>; + constexpr auto A_10 = mito::functions::component, 2>; + constexpr auto A_11 = mito::functions::component, 3>; + + // a 3D vector function of a 2D matrix + constexpr auto f = A_00 * e0 + A_01 * e1 + (A_10 - A_11) * e2; + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a 2D matrix input + constexpr auto A = mito::tensor::matrix_t<2, 2>{ 1.0, 2.0, 3.0, 4.0 }; + // check the derivatives (first component of the output vector) + static_assert(df(A)[{ 0, 0 }] == 1.0); // d/dA_00 A_00 = 1 + static_assert(df(A)[{ 0, 1 }] == 0.0); // d/dA_01 A_00 = 0 + static_assert(df(A)[{ 0, 2 }] == 0.0); // d/dA_10 A_00 = 0 + static_assert(df(A)[{ 0, 3 }] == 0.0); // d/dA_11 A_00 = 0 + // check the derivatives (second component of the output vector) + static_assert(df(A)[{ 1, 0 }] == 0.0); // d/dA_00 A_01 = 0 + static_assert(df(A)[{ 1, 1 }] == 1.0); // d/dA_01 A_01 = 1 + static_assert(df(A)[{ 1, 2 }] == 0.0); // d/dA_10 A_01 = 0 + static_assert(df(A)[{ 1, 3 }] == 0.0); // d/dA_11 A_01 = 0 + // check the derivatives (third component of the output vector) + static_assert(df(A)[{ 2, 0 }] == 0.0); // d/dA_00 (A_10 - A_11) = 0 + static_assert(df(A)[{ 2, 1 }] == 0.0); // d/dA_01 (A_10 - A_11) = 0 + static_assert(df(A)[{ 2, 2 }] == 1.0); // d/dA_10 (A_10 - A_11) = 1 + static_assert(df(A)[{ 2, 3 }] == -1.0); // d/dA_11 (A_10 - A_11) = -1 +} + + +TEST(Derivatives, MatrixOfScalar) +{ + // a 2D matrix function of a scalar + constexpr auto f = + mito::functions::sin * e00 + mito::functions::cos * e01 + mito::functions::exp * e10; + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a scalar input + constexpr auto x = mito::tensor::scalar_t{ 1.0 }; + // check the derivatives + static_assert(df(x)[{ 0, 0 }] == mito::functions::cos(x)); + static_assert(df(x)[{ 1, 0 }] == -mito::functions::sin(x)); + static_assert(df(x)[{ 2, 0 }] == mito::functions::exp(x)); + static_assert(df(x)[{ 3, 0 }] == 0.0); +} + + +TEST(Derivatives, MatrixOfVector) +{ + // a 2D matrix function of a 2D vector + constexpr auto f = mito::functions::sin(x0) * e00 + mito::functions::cos(x1) * e01 + + mito::functions::exp(x0 * x1) * e11; + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a 2D vector input + constexpr auto x = mito::tensor::vector_t<2>{ 1.0, -1.0 }; + // check the derivatives + static_assert(df(x)[{ 0, 0 }] == mito::functions::cos(x0)(x)); // d/dx0 (sin(x0)) = cos(x0) + static_assert(df(x)[{ 0, 1 }] == 0.0); // d/dx1 (sin(x0)) = 0 + static_assert(df(x)[{ 1, 0 }] == 0.0); // d/dx0 (cos(x1)) = 0 + static_assert(df(x)[{ 1, 1 }] == -mito::functions::sin(x1)(x)); // d/dx1 (cos(x1)) = -sin(x1) + static_assert(df(x)[{ 2, 0 }] == 0.0); // d/dx0 (0) = 0 + static_assert(df(x)[{ 2, 1 }] == 0.0); // d/dx1 (0) = 0 + static_assert( + df(x)[{ 3, 0 }] + == (mito::functions::exp(x0 * x1) * x1)(x)); // d/dx0 (exp(x0 * x1)) = exp(x0 * x1) * x1 + static_assert( + df(x)[{ 3, 1 }] + == (mito::functions::exp(x0 * x1) * x0)(x)); // d/dx1 (exp(x0 * x1)) = exp(x0 * x1) * x0 +} + + +TEST(Derivatives, MatrixOfMatrix) +{ + // a 2D matrix function of a 2D matrix + constexpr auto f = + (mito::functions::component, 0> + + mito::functions::component, 3>) *(e00 + e10); + // its derivative + constexpr auto df = mito::functions::derivative(f); + // a 2D matrix input + constexpr auto A = mito::tensor::matrix_t<2, 2>{ 1.0, 2.0, 3.0, 4.0 }; + // check the derivatives + static_assert(df(A)[{ 0, 0 }] == 1.0); + static_assert(df(A)[{ 0, 1 }] == 0.0); + static_assert(df(A)[{ 0, 2 }] == 0.0); + static_assert(df(A)[{ 0, 3 }] == 1.0); + static_assert(df(A)[{ 1, 0 }] == 0.0); + static_assert(df(A)[{ 1, 1 }] == 0.0); + static_assert(df(A)[{ 1, 2 }] == 0.0); + static_assert(df(A)[{ 1, 3 }] == 0.0); + static_assert(df(A)[{ 2, 0 }] == 1.0); + static_assert(df(A)[{ 2, 1 }] == 0.0); + static_assert(df(A)[{ 2, 2 }] == 0.0); + static_assert(df(A)[{ 2, 3 }] == 1.0); + static_assert(df(A)[{ 3, 0 }] == 0.0); + static_assert(df(A)[{ 3, 1 }] == 0.0); + static_assert(df(A)[{ 3, 2 }] == 0.0); + static_assert(df(A)[{ 3, 3 }] == 0.0); +} + + +// end of file From 8b9847a2d7079c6c3d4dcf3febef61b2710833ed Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 30 Aug 2025 18:35:28 +0200 Subject: [PATCH 196/273] tests/functions: simplify test thanks to redesign of rev. dfb0f80 --- .../mito.lib/functions/partial_derivatives.cc | 52 ++++++++----------- 1 file changed, 22 insertions(+), 30 deletions(-) diff --git a/tests/mito.lib/functions/partial_derivatives.cc b/tests/mito.lib/functions/partial_derivatives.cc index afe82d3ee..2fe7fa353 100644 --- a/tests/mito.lib/functions/partial_derivatives.cc +++ b/tests/mito.lib/functions/partial_derivatives.cc @@ -23,40 +23,34 @@ TEST(VectorFunctions, Components) static_assert(1.0 == x1(x)); // the partial derivatives of x0 - constexpr auto x0_0 = mito::functions::derivative<0>(x0); - constexpr auto x0_1 = mito::functions::derivative<1>(x0); + constexpr auto dx0 = mito::functions::derivative(x0); + // check result - static_assert(1.0 == x0_0(x)); - static_assert(0.0 == x0_1(x)); + static_assert(1.0 == dx0(x)[0]); + static_assert(0.0 == dx0(x)[1]); // the partial derivatives of x1 - constexpr auto x1_0 = mito::functions::derivative<0>(x1); - constexpr auto x1_1 = mito::functions::derivative<1>(x1); + constexpr auto dx1 = mito::functions::derivative(x1); // check result - static_assert(0.0 == x1_0(x)); - static_assert(1.0 == x1_1(x)); + static_assert(0.0 == dx1(x)[0]); + static_assert(1.0 == dx1(x)[1]); // the second partial derivatives of x0 - constexpr auto x0_00 = mito::functions::derivative<0>(x0_0); - constexpr auto x0_01 = mito::functions::derivative<1>(x0_0); - constexpr auto x0_10 = mito::functions::derivative<0>(x0_1); - constexpr auto x0_11 = mito::functions::derivative<1>(x0_1); + constexpr auto ddx0 = mito::functions::derivative(dx0); + // check result - static_assert(0.0 == x0_00(x)); - static_assert(0.0 == x0_01(x)); - static_assert(0.0 == x0_10(x)); - static_assert(0.0 == x0_11(x)); + static_assert(0.0 == ddx0(x)[{ 0, 0 }]); + static_assert(0.0 == ddx0(x)[{ 0, 1 }]); + static_assert(0.0 == ddx0(x)[{ 1, 0 }]); + static_assert(0.0 == ddx0(x)[{ 1, 1 }]); // the second partial derivatives of x1 - constexpr auto x1_00 = mito::functions::derivative<0>(x1_0); - constexpr auto x1_01 = mito::functions::derivative<1>(x1_0); - constexpr auto x1_10 = mito::functions::derivative<0>(x1_1); - constexpr auto x1_11 = mito::functions::derivative<1>(x1_1); + constexpr auto ddx1 = mito::functions::derivative(dx1); // check result - static_assert(0.0 == x1_00(x)); - static_assert(0.0 == x1_01(x)); - static_assert(0.0 == x1_10(x)); - static_assert(0.0 == x1_11(x)); + static_assert(0.0 == ddx1(x)[{ 0, 0 }]); + static_assert(0.0 == ddx1(x)[{ 0, 1 }]); + static_assert(0.0 == ddx1(x)[{ 1, 0 }]); + static_assert(0.0 == ddx1(x)[{ 1, 1 }]); } @@ -73,17 +67,15 @@ TEST(Derivatives, PartialDerivatives) // sin(x0 * x1) constexpr auto sin = mito::functions::sin(x0 * x1); - // the partial derivative of sin(x0 * x1) wrt to x0 - constexpr auto sin_0 = mito::functions::derivative<0>(sin); - // the partial derivative of sin(x0 * x1) wrt to x1 - constexpr auto sin_1 = mito::functions::derivative<1>(sin); + // the partial derivatives of sin(x0 * x1) wrt to x0 and x1 + constexpr auto dsin = mito::functions::derivative(sin); // cos(x0 * x1) constexpr auto cos = mito::functions::cos(x0 * x1); // check result - static_assert((cos * x1)(x) == sin_0(x)); - static_assert((cos * x0)(x) == sin_1(x)); + static_assert((cos * x1)(x) == dsin[0](x)); + static_assert((cos * x0)(x) == dsin[1](x)); } From 9d3e1e5d090c5d91a1aa1970d372b72577893388 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 30 Aug 2025 18:47:56 +0200 Subject: [PATCH 197/273] tests/functions: add check that evaluating commutes with subscripting --- tests/mito.lib/functions/derivative_subscript.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mito.lib/functions/derivative_subscript.cc b/tests/mito.lib/functions/derivative_subscript.cc index 1f238821e..494f53afb 100644 --- a/tests/mito.lib/functions/derivative_subscript.cc +++ b/tests/mito.lib/functions/derivative_subscript.cc @@ -19,6 +19,9 @@ TEST(Derivatives, Subscript) // a vector function R -> R^2x3 constexpr auto f = mito::functions::sin * mito::tensor::e_12<2, 3>; + // check that evaluating and subscripting is the same than subscripting and evaluating + static_assert(f(x)[5] == f[5](x)); + // check that the derivative of the subscript is the subscript of the derivative static_assert(mito::functions::derivative(f[5])(x) == mito::functions::derivative(f)(x)[5]); } From 0a15481bd34440b474194682d3f1a250d80a44bb Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 30 Aug 2025 18:49:44 +0200 Subject: [PATCH 198/273] functions: fix typos in comments --- lib/mito/functions/function.h | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 5475fb263..941fe1f23 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -43,7 +43,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -84,7 +84,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -122,7 +122,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -179,7 +179,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -238,7 +238,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -281,7 +281,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -333,7 +333,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -381,7 +381,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -459,7 +459,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -544,7 +544,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { @@ -588,7 +588,7 @@ namespace mito::functions { return Composition(*this, f); } - // subscript operator: only available if {output_type} is a tensor + // subscript operator: only available if {output_type} is subscriptable constexpr auto operator[](int i) const requires subscriptable_c { From 1fb55c05ca580b0a506dd09d2359fb4a9b577b4b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 31 Aug 2025 19:14:55 +0200 Subject: [PATCH 199/273] functions: class {Subscript} is now template wrt the index type --- lib/mito/functions/derivation_rules.h | 4 ++-- lib/mito/functions/forward.h | 2 +- lib/mito/functions/function.h | 10 +++++----- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index a2bea57de..a5260a800 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -89,8 +89,8 @@ namespace mito::functions { } // the I-th first partial derivative of the {Subscript} function - template - constexpr auto derivative(const Subscript & f) + template + constexpr auto derivative(const Subscript & f) { // the derivative of the subscript is the subscript of the derivative return Subscript(derivative(f.f()), f.index()); diff --git a/lib/mito/functions/forward.h b/lib/mito/functions/forward.h index 33dd4e15b..8a47519d2 100644 --- a/lib/mito/functions/forward.h +++ b/lib/mito/functions/forward.h @@ -84,7 +84,7 @@ namespace mito::functions { class Composition; // function subscript - template + template class Subscript; } diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 941fe1f23..74a0bb2b0 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -481,7 +481,7 @@ namespace mito::functions { }; - template + template class Subscript : public function_subscript::type { public: @@ -492,11 +492,11 @@ namespace mito::functions { // the output type using output_type = function_type::output_type; // the type of index - using index_type = int; + using index_type = indexT; public: // constructor - constexpr Subscript(const F & f, const int i) : _f(f), _i(i) {} + constexpr Subscript(const F & f, const index_type i) : _f(f), _i(i) {} // call operator for function composition template @@ -512,11 +512,11 @@ namespace mito::functions { constexpr auto f() const -> const F & { return _f; } // the index - constexpr auto index() const -> int { return _i; } + constexpr auto index() const -> index_type { return _i; } private: const F _f; - const int _i; + const index_type _i; }; From 7f44faba6040748812e80a1490df10fc05a42aac Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 31 Aug 2025 19:24:08 +0200 Subject: [PATCH 200/273] functions: add derivative of a (constant) tensor --- lib/mito/functions/derivation_rules.h | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index a5260a800..5bf970a6e 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -12,6 +12,13 @@ namespace mito::functions { + // the I-th first partial derivative of a constant + template + constexpr auto derivative(const T &) + { + return tensor::zero; + } + // the I-th first partial derivative of a function sum template constexpr auto derivative(const Sum & f) From 602d3b691fffd8b11775d3c310583284cc385ac0 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 31 Aug 2025 19:25:10 +0200 Subject: [PATCH 201/273] functions: add multi-index version of operator[] for tensor valued functions --- lib/mito/functions/function.h | 77 +++++++++++++++++++ .../functions/derivative_subscript.cc | 21 ++++- 2 files changed, 96 insertions(+), 2 deletions(-) diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 74a0bb2b0..eaaf5652c 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -50,6 +50,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(x); } @@ -91,6 +98,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type &) const -> output_type { return _c; } @@ -129,6 +143,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -186,6 +207,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -245,6 +273,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(x) + _a; } @@ -288,6 +323,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -340,6 +382,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(x) * _a; } @@ -388,6 +437,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _a * _f(x); } @@ -466,6 +522,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { return _f(_g(x)); } @@ -551,6 +614,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { @@ -595,6 +665,13 @@ namespace mito::functions { return Subscript(*this, i); } + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + // call operator constexpr auto operator()(const input_type & x) const -> output_type { diff --git a/tests/mito.lib/functions/derivative_subscript.cc b/tests/mito.lib/functions/derivative_subscript.cc index 494f53afb..67ffd532e 100644 --- a/tests/mito.lib/functions/derivative_subscript.cc +++ b/tests/mito.lib/functions/derivative_subscript.cc @@ -19,11 +19,28 @@ TEST(Derivatives, Subscript) // a vector function R -> R^2x3 constexpr auto f = mito::functions::sin * mito::tensor::e_12<2, 3>; + // get the output type of the function {f}, in this case a 2x3 tensor + using output_type = decltype(f)::output_type; + + // get the offset corresponding to the multi-index {1, 2} in a 2x3 tensor + // multi-index {1, 2} is where {f} has the only nontrivial value + constexpr int offset = output_type::getOffset<1, 2>(); + + // check that evaluating and subscripting is the same than subscripting and evaluating + static_assert(f(x)[offset] == f[offset](x)); + // check that evaluating and subscripting is the same than subscripting and evaluating - static_assert(f(x)[5] == f[5](x)); + static_assert(f(x)[{ 1, 2 }] == f[{ 1, 2 }](x)); // check that the derivative of the subscript is the subscript of the derivative - static_assert(mito::functions::derivative(f[5])(x) == mito::functions::derivative(f)(x)[5]); + static_assert( + mito::functions::derivative(f[offset])(x) == mito::functions::derivative(f)(x)[offset]); + + // check that the derivative of the scalar function which extracts the {1, 2} component is equal + // to the {{1, 2}, 0} component of the total derivative + static_assert( + mito::functions::derivative(f[{ 1, 2 }])(x) + == mito::functions::derivative(f)(x)[{ offset, 0 }]); } From eb84656faf6ee70e5f060518864a8e11970beffe Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 31 Aug 2025 19:25:20 +0200 Subject: [PATCH 202/273] functions: fix typo in comment --- tests/mito.lib/functions/derivative_subscript.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/mito.lib/functions/derivative_subscript.cc b/tests/mito.lib/functions/derivative_subscript.cc index 67ffd532e..b4c90169b 100644 --- a/tests/mito.lib/functions/derivative_subscript.cc +++ b/tests/mito.lib/functions/derivative_subscript.cc @@ -13,7 +13,7 @@ using std::numbers::pi; TEST(Derivatives, Subscript) { - // a matrix + // a scalar constexpr auto x = pi / 4.0; // a vector function R -> R^2x3 From 91e3ae172e1dae4742495b3b2436c6a66b0ef448 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 31 Aug 2025 19:32:37 +0200 Subject: [PATCH 203/273] functions: generalize {derivative} of composition to composite tensor functions --- lib/mito/functions/derivation_rules.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index 5bf970a6e..fa76cae65 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -69,9 +69,9 @@ namespace mito::functions { return derivative(f.f1())(f.f2()) * derivative(f.f2()); } - // the chain rule for the I-th first partial derivative (f1(f2(x)) with f2 vector valued) + // the chain rule for the I-th first partial derivative (f1(f2(x)) with f2 tensor function) template - requires(vector_valued_function_c) + requires(tensor_function_c) constexpr auto derivative(const Composition & f) { // the number of components of the vector (output of F2) @@ -80,8 +80,7 @@ namespace mito::functions { // helper function to compute the N partial derivatives constexpr auto _derivative = [](const auto & f, std::index_sequence) { // the vector of the partial derivatives - return ( - (derivative(f.f1())(f.f2()) * derivative(f.f2() * tensor::e)) + ...); + return ((derivative(f.f1())(f.f2()) * derivative(f.f2()[J])) + ...); }; return _derivative(f, std::make_index_sequence{}); From 01eedd2f123650608b5966f5c22ed7a3053d4905 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 31 Aug 2025 19:50:53 +0200 Subject: [PATCH 204/273] functions: fix redundant test, mistakenly introduced in rev. 70dd74e --- tests/mito.lib/functions/derivative_product.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/mito.lib/functions/derivative_product.cc b/tests/mito.lib/functions/derivative_product.cc index 2fb7fc60c..643879e8e 100644 --- a/tests/mito.lib/functions/derivative_product.cc +++ b/tests/mito.lib/functions/derivative_product.cc @@ -108,10 +108,10 @@ TEST(Derivatives, ScalarProduct) constexpr auto a = mito::tensor::vector_t<2>{ -1.0, 1.0 }; // the function returning the constant e0 unit vector in 2D - constexpr auto e0 = mito::tensor::e_0<2>; + constexpr auto e0 = mito::functions::constant>(mito::tensor::e_0<2>); // the function returning the constant e1 unit vector in 2D - constexpr auto e1 = mito::tensor::e_1<2>; + constexpr auto e1 = mito::functions::constant>(mito::tensor::e_1<2>); // the function extracting the x_0 component of a 2D vector constexpr auto x0 = mito::functions::x<0, 2>; @@ -127,8 +127,8 @@ TEST(Derivatives, ScalarProduct) constexpr auto f_1 = mito::functions::derivative<1>(f); // check result - static_assert(a * e0 == f_0(x)); - static_assert(a * e1 == f_1(x)); + static_assert(a * e0(x) == f_0(x)); + static_assert(a * e1(x) == f_1(x)); } From 6505c555ae36c7890f587d164df729691454d81f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 4 Sep 2025 19:50:08 +0200 Subject: [PATCH 205/273] manifolds/geometry/quadrature: remove cell-level {parametrization} method from class {Manifold} This method has been moved to {GeometricSimplex}. This way class {Manifold} doesn't need knowledge of lower level type definitions, such as the type of barycentric coordinates. Also, this method in class {Manifold} was problematic in that it implied (without checking) that the cell passed in input to the method did belong to the manifold. --- lib/mito/geometry/GeometricSimplex.h | 24 ++++++++++++++++++++++++ lib/mito/manifolds/Manifold.h | 23 ----------------------- lib/mito/quadrature/Integrator.h | 3 ++- 3 files changed, 26 insertions(+), 24 deletions(-) diff --git a/lib/mito/geometry/GeometricSimplex.h b/lib/mito/geometry/GeometricSimplex.h index 78e626f54..42e73c0d3 100644 --- a/lib/mito/geometry/GeometricSimplex.h +++ b/lib/mito/geometry/GeometricSimplex.h @@ -132,6 +132,30 @@ namespace mito::geometry { // return the composition of this simplex in terms of its vertices constexpr auto nodes() const -> const nodes_type & { return _nodes; } + template + constexpr auto parametrization( + const barycentric_coordinates_type & point, + const coordinateSystemT & coordinate_system) const + -> coordinateSystemT::coordinates_type + { + // get the coordinates of the first node + auto coord_0 = coordinate_system.coordinates(_nodes[0]->point()); + + // the vector going from {coord_0} to the position of the parametric point (initialize + // with the zero vector) + auto result = coord_0 - coord_0; + + // loop on the element nodes + int v = 0; + for (const auto & node : _nodes) { + result += (coordinate_system.coordinates(node->point()) - coord_0) * point[v]; + ++v; + } + + // return the coordinates of the parametric point + return coord_0 + result; + } + private: // the simplex nodes nodes_type _nodes; diff --git a/lib/mito/manifolds/Manifold.h b/lib/mito/manifolds/Manifold.h index 80f29aac7..6e2de11f7 100644 --- a/lib/mito/manifolds/Manifold.h +++ b/lib/mito/manifolds/Manifold.h @@ -34,8 +34,6 @@ namespace mito::manifolds { using coordinates_type = coordsT; // typedef for a coordinates system using coordinate_system_type = geometry::coordinate_system_t; - // typedef for a point in parametric coordinates - using parametric_point_type = typename cell_type::barycentric_coordinates_type; public: constexpr Manifold( @@ -85,27 +83,6 @@ namespace mito::manifolds { return _coordinate_system.coordinates(v->point()); } - constexpr auto parametrization( - const cell_type & cell, const parametric_point_type & point) const -> coordinates_type - { - // get the coordinates of the first node - auto coord_0 = coordinates(cell.nodes()[0]); - - // the vector going from {coord_0} to the position of the parametric point (initialize - // with the zero vector) - auto result = coord_0 - coord_0; - - // loop on the element nodes - int v = 0; - for (const auto & node : cell.nodes()) { - result += (coordinates(node) - coord_0) * point[v]; - ++v; - } - - // return the coordinates of the parametric point - return coord_0 + result; - } - constexpr auto print() const -> void { // make a channel diff --git a/lib/mito/quadrature/Integrator.h b/lib/mito/quadrature/Integrator.h index 27af46a46..0e3972cca 100644 --- a/lib/mito/quadrature/Integrator.h +++ b/lib/mito/quadrature/Integrator.h @@ -41,7 +41,8 @@ namespace mito::quadrature { // the canonical element to the coordinate of the quadrature point _coordinates.insert( element.simplex(), - { _manifold.parametrization(element, _quadratureRule.point(q))... }); + { element.parametrization( + _quadratureRule.point(q), _manifold.coordinate_system())... }); } // all done From bf426c5a66cea00225340f4ba309a91b0d8ddc8f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 07:46:33 +0200 Subject: [PATCH 206/273] discretization: move non-fem related discretization classes to new directory and namespace {discrete} This includes, for example, discrete fields, which are not specific to finite elements and may be used in other discretization approaches. --- .cmake/mito_tests_mito_lib.cmake | 6 +- lib/mito/discrete.h | 15 ++++ .../DiscreteField.h | 2 +- .../DiscretizationNode.h | 2 +- lib/mito/discrete/api.h | 52 ++++++++++++++ lib/mito/discrete/externals.h | 17 +++++ lib/mito/discrete/factories.h | 69 +++++++++++++++++++ lib/mito/discrete/forward.h | 21 ++++++ lib/mito/discrete/public.h | 26 +++++++ lib/mito/discretization/DiscreteSystem.h | 2 +- lib/mito/discretization/api.h | 37 ---------- lib/mito/discretization/externals.h | 1 + lib/mito/discretization/factories.h | 56 +-------------- .../fem/IsoparametricTriangle.h | 2 +- lib/mito/discretization/forward.h | 7 -- lib/mito/discretization/public.h | 2 - lib/mito/io/vtk/FieldVTKWriter.h | 6 +- lib/mito/io/vtk/externals.h | 3 + lib/mito/public.h | 1 + lib/mito/quadrature/Integrator.h | 3 +- .../mesh_field.cc | 4 +- .../quadrature_field.cc | 4 +- .../discretization/isoparametric_triangle.cc | 2 +- tests/mito.lib/discretization/poisson.cc | 5 +- .../io/parallel_vtk_cloud_field_writer.cc | 3 +- .../io/parallel_vtk_mesh_field_writer.cc | 4 +- tests/mito.lib/io/parallel_vtk_mesh_writer.cc | 2 +- tests/mito.lib/io/summit_to_summit_mesh_2D.cc | 4 +- 28 files changed, 231 insertions(+), 127 deletions(-) create mode 100644 lib/mito/discrete.h rename lib/mito/{discretization => discrete}/DiscreteField.h (98%) rename lib/mito/{discretization => discrete}/DiscretizationNode.h (96%) create mode 100644 lib/mito/discrete/api.h create mode 100644 lib/mito/discrete/externals.h create mode 100644 lib/mito/discrete/factories.h create mode 100644 lib/mito/discrete/forward.h create mode 100644 lib/mito/discrete/public.h rename tests/mito.lib/{discretization => discrete}/mesh_field.cc (92%) rename tests/mito.lib/{discretization => discrete}/quadrature_field.cc (92%) diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index b0212937b..c27aea621 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -40,9 +40,11 @@ mito_test_driver(tests/mito.lib/geometry/spherical_metric_space.cc) # constraints mito_test_driver(tests/mito.lib/constraints/dirichlet.cc) +# discrete +mito_test_driver(tests/mito.lib/discrete/quadrature_field.cc) +mito_test_driver(tests/mito.lib/discrete/mesh_field.cc) + # discretization -mito_test_driver(tests/mito.lib/discretization/quadrature_field.cc) -mito_test_driver(tests/mito.lib/discretization/mesh_field.cc) mito_test_driver(tests/mito.lib/discretization/poisson.cc) mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_construction.cc) mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p1.cc) diff --git a/lib/mito/discrete.h b/lib/mito/discrete.h new file mode 100644 index 000000000..d9bb76532 --- /dev/null +++ b/lib/mito/discrete.h @@ -0,0 +1,15 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// publish the interface +// the api is in "discrete/api.h" +#include "discrete/public.h" + + +// end of file diff --git a/lib/mito/discretization/DiscreteField.h b/lib/mito/discrete/DiscreteField.h similarity index 98% rename from lib/mito/discretization/DiscreteField.h rename to lib/mito/discrete/DiscreteField.h index ffa3d24a8..5ebebb933 100644 --- a/lib/mito/discretization/DiscreteField.h +++ b/lib/mito/discrete/DiscreteField.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::discrete { template class DiscreteField { diff --git a/lib/mito/discretization/DiscretizationNode.h b/lib/mito/discrete/DiscretizationNode.h similarity index 96% rename from lib/mito/discretization/DiscretizationNode.h rename to lib/mito/discrete/DiscretizationNode.h index 1ab3a80c0..404678a11 100644 --- a/lib/mito/discretization/DiscretizationNode.h +++ b/lib/mito/discrete/DiscretizationNode.h @@ -12,7 +12,7 @@ * */ -namespace mito::discretization { +namespace mito::discrete { class DiscretizationNode : public utilities::Invalidatable { diff --git a/lib/mito/discrete/api.h b/lib/mito/discrete/api.h new file mode 100644 index 000000000..85c04260b --- /dev/null +++ b/lib/mito/discrete/api.h @@ -0,0 +1,52 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discrete { + + // discretization node alias + using discretization_node_t = utilities::std_shared_ptr; + + // mesh field + template + using mesh_field_t = DiscreteField, Y>; + + // point field + template + using point_field_t = DiscreteField, Y>; + + // nodal field + template + using nodal_field_t = DiscreteField; + + // quadrature field alias + template + using quadrature_field_t = DiscreteField>; + + // quadrature field factory + template + constexpr auto quadrature_field(const meshT & mesh, std::string name); + + // mesh field factory + template + constexpr auto mesh_field(const mesh::mesh_c auto & mesh, std::string name); + + // mesh field factory from a continuous field + template + constexpr auto mesh_field( + const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, + const fieldT & field, std::string name); + + // point field factory + template + constexpr auto point_field(const cloudT & cloud, std::string name); + +} + + +// end of file diff --git a/lib/mito/discrete/externals.h b/lib/mito/discrete/externals.h new file mode 100644 index 000000000..3f27eafc0 --- /dev/null +++ b/lib/mito/discrete/externals.h @@ -0,0 +1,17 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// externals +#include + +// support +#include "../mesh.h" +#include "../utilities.h" + +// end of file diff --git a/lib/mito/discrete/factories.h b/lib/mito/discrete/factories.h new file mode 100644 index 000000000..23a910a8a --- /dev/null +++ b/lib/mito/discrete/factories.h @@ -0,0 +1,69 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discrete { + + // quadrature field factory + template + constexpr auto quadrature_field(const meshT & mesh, std::string name) + { + // build a quadrature field on the cells collected from the mesh + // ({Q} quad points per cell) + return quadrature_field_t( + mesh.cells(), name); + } + + // mesh field factory + template + constexpr auto mesh_field(const meshT & mesh, std::string name) + { + // assemble the node type + using node_type = geometry::node_t; + + // get the nodes in the mesh + std::unordered_set> nodes; + mesh::get_nodes(mesh, nodes); + + // build a mesh field on the nodes collected from the mesh + return mesh_field_t(nodes, name); + } + + // mesh field factory from a continuous field + template + constexpr auto mesh_field( + const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, + const fieldT & field, std::string name) + { + // create a mesh field on the mesh + auto m_field = mesh_field(mesh, name); + + // populate the mesh field with the values of the continuous field + for (auto & [node, value] : m_field) { + // get the position of {node} + auto coord = coord_system.coordinates(node->point()); + // evaluate the continuousfield at {coord} + value = field(coord); + } + + // return the mesh field + return m_field; + } + + // point field factory + template + constexpr auto point_field(const cloudT & cloud, std::string name) + { + // build a point field on the points collected from the cloud + return point_field_t(cloud.points(), name); + } + +} + + +// end of file diff --git a/lib/mito/discrete/forward.h b/lib/mito/discrete/forward.h new file mode 100644 index 000000000..ea0878b43 --- /dev/null +++ b/lib/mito/discrete/forward.h @@ -0,0 +1,21 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::discrete { + + // class discretization node + class DiscretizationNode; + + // class discrete field + template + class DiscreteField; +} + + +// end of file diff --git a/lib/mito/discrete/public.h b/lib/mito/discrete/public.h new file mode 100644 index 000000000..e78183a77 --- /dev/null +++ b/lib/mito/discrete/public.h @@ -0,0 +1,26 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// external packages +#include "externals.h" + +// get the forward declarations +#include "forward.h" + +// published types factories; this is the file you are looking for... +#include "api.h" + +// classes implementation +#include "DiscreteField.h" +#include "DiscretizationNode.h" + +// factories implementation +#include "factories.h" + +// end of file diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/discretization/DiscreteSystem.h index 4df70040e..14b67891b 100644 --- a/lib/mito/discretization/DiscreteSystem.h +++ b/lib/mito/discretization/DiscreteSystem.h @@ -35,7 +35,7 @@ namespace mito::discretization { // the solution field type using solution_field_type = tensor::scalar_t; // the nodal field type - using nodal_field_type = nodal_field_t; + using nodal_field_type = discrete::nodal_field_t; // TOFIX: rename to {n_element_nodes} // the number of nodes per element static constexpr int n_nodes = element_type::n_nodes; diff --git a/lib/mito/discretization/api.h b/lib/mito/discretization/api.h index 742f4a1f9..0a8ec8380 100644 --- a/lib/mito/discretization/api.h +++ b/lib/mito/discretization/api.h @@ -9,43 +9,6 @@ namespace mito::discretization { - // discretization node alias - using discretization_node_t = utilities::std_shared_ptr; - - // mesh field - template - using mesh_field_t = DiscreteField, Y>; - - // point field - template - using point_field_t = DiscreteField, Y>; - - // nodal field - template - using nodal_field_t = DiscreteField; - - // quadrature field alias - template - using quadrature_field_t = DiscreteField>; - - // quadrature field factory - template - constexpr auto quadrature_field(const meshT & mesh, std::string name); - - // mesh field factory - template - constexpr auto mesh_field(const mesh::mesh_c auto & mesh, std::string name); - - // mesh field factory from a continuous field - template - constexpr auto mesh_field( - const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, - const fieldT & field, std::string name); - - // point field factory - template - constexpr auto point_field(const cloudT & cloud, std::string name); - // nodal field factory template constexpr auto nodal_field(const functionSpaceT & function_space, std::string name); diff --git a/lib/mito/discretization/externals.h b/lib/mito/discretization/externals.h index 6ba9ad0c5..cda32c32c 100644 --- a/lib/mito/discretization/externals.h +++ b/lib/mito/discretization/externals.h @@ -14,6 +14,7 @@ #include "../journal.h" #include "../manifolds.h" #include "../constraints.h" +#include "../discrete.h" #include "../utilities.h" diff --git a/lib/mito/discretization/factories.h b/lib/mito/discretization/factories.h index 284744a01..b4df289ae 100644 --- a/lib/mito/discretization/factories.h +++ b/lib/mito/discretization/factories.h @@ -9,60 +9,6 @@ namespace mito::discretization { - // quadrature field factory - template - constexpr auto quadrature_field(const meshT & mesh, std::string name) - { - // build a quadrature field on the cells collected from the mesh - // ({Q} quad points per cell) - return quadrature_field_t( - mesh.cells(), name); - } - - // mesh field factory - template - constexpr auto mesh_field(const meshT & mesh, std::string name) - { - // assemble the node type - using node_type = geometry::node_t; - - // get the nodes in the mesh - std::unordered_set> nodes; - mesh::get_nodes(mesh, nodes); - - // build a mesh field on the nodes collected from the mesh - return mesh_field_t(nodes, name); - } - - // mesh field factory from a continuous field - template - constexpr auto mesh_field( - const mesh::mesh_c auto & mesh, const geometry::coordinate_system_c auto & coord_system, - const fieldT & field, std::string name) - { - // create a mesh field on the mesh - auto m_field = mesh_field(mesh, name); - - // populate the mesh field with the values of the continuous field - for (auto & [node, value] : m_field) { - // get the position of {node} - auto coord = coord_system.coordinates(node->point()); - // evaluate the continuousfield at {coord} - value = field(coord); - } - - // return the mesh field - return m_field; - } - - // point field factory - template - constexpr auto point_field(const cloudT & cloud, std::string name) - { - // build a point field on the points collected from the cloud - return point_field_t(cloud.points(), name); - } - // nodal field factory template constexpr auto nodal_field(const functionSpaceT & function_space, std::string name) @@ -75,7 +21,7 @@ namespace mito::discretization { get_discretization_nodes(function_space, nodes); // build a nodal field on the discretization nodes collected from the function space - return nodal_field_t(nodes, name); + return discrete::nodal_field_t(nodes, name); } // TOFIX: create a constructor that takes no constraints diff --git a/lib/mito/discretization/fem/IsoparametricTriangle.h b/lib/mito/discretization/fem/IsoparametricTriangle.h index 727333ed2..ecfd1a131 100644 --- a/lib/mito/discretization/fem/IsoparametricTriangle.h +++ b/lib/mito/discretization/fem/IsoparametricTriangle.h @@ -18,7 +18,7 @@ namespace mito::discretization { // the dimension of the physical space static constexpr int dim = 2; // the discretization node type - using discretization_node_type = discretization_node_t; + using discretization_node_type = discrete::discretization_node_t; // the geometric simplex type using geometric_simplex_type = geometry::triangle_t; // type of a point in barycentric coordinates diff --git a/lib/mito/discretization/forward.h b/lib/mito/discretization/forward.h index a2c8f3cc1..2312a6477 100644 --- a/lib/mito/discretization/forward.h +++ b/lib/mito/discretization/forward.h @@ -9,13 +9,6 @@ namespace mito::discretization { - // class discretization node - class DiscretizationNode; - - // class discrete field - template - class DiscreteField; - // class function space template class FunctionSpace; diff --git a/lib/mito/discretization/public.h b/lib/mito/discretization/public.h index 6bf453d21..52e4f4377 100644 --- a/lib/mito/discretization/public.h +++ b/lib/mito/discretization/public.h @@ -20,8 +20,6 @@ #include "blocks.h" // classes implementation -#include "DiscreteField.h" -#include "DiscretizationNode.h" #include "FunctionSpace.h" #include "DiscreteSystem.h" diff --git a/lib/mito/io/vtk/FieldVTKWriter.h b/lib/mito/io/vtk/FieldVTKWriter.h index 9ca3cb3c9..d29e0a765 100644 --- a/lib/mito/io/vtk/FieldVTKWriter.h +++ b/lib/mito/io/vtk/FieldVTKWriter.h @@ -18,21 +18,21 @@ namespace mito::io::vtk { template struct field_type { template - using type = discretization::mesh_field_t; + using type = discrete::mesh_field_t; }; // specialization to {point_cloud_c} case template struct field_type { template - using type = discretization::point_field_t; + using type = discrete::point_field_t; }; // specialization to {function_space_c} case template struct field_type { template - using type = discretization::nodal_field_t; + using type = discrete::nodal_field_t; }; // utility function to get the data pointer diff --git a/lib/mito/io/vtk/externals.h b/lib/mito/io/vtk/externals.h index 2b783e4ce..c4eaa8b6a 100644 --- a/lib/mito/io/vtk/externals.h +++ b/lib/mito/io/vtk/externals.h @@ -22,4 +22,7 @@ #include #endif // WITH_PARALLEL_VTK +// support +#include "../../discrete.h" + // end of file diff --git a/lib/mito/public.h b/lib/mito/public.h index 34afa4d55..f1f58b3cc 100644 --- a/lib/mito/public.h +++ b/lib/mito/public.h @@ -11,6 +11,7 @@ #include "journal.h" #include "tensor.h" #include "functions.h" +#include "discrete.h" #include "discretization.h" #include "constraints.h" #include "coordinates.h" diff --git a/lib/mito/quadrature/Integrator.h b/lib/mito/quadrature/Integrator.h index 0e3972cca..519eb126b 100644 --- a/lib/mito/quadrature/Integrator.h +++ b/lib/mito/quadrature/Integrator.h @@ -28,8 +28,7 @@ namespace mito::quadrature { // the number of quadrature points static constexpr int Q = quadrature_rule_type::npoints; // the quadrature field type to store the coordinates of the quadrature points - using quadrature_field_type = - discretization::quadrature_field_t; + using quadrature_field_type = discrete::quadrature_field_t; private: template diff --git a/tests/mito.lib/discretization/mesh_field.cc b/tests/mito.lib/discrete/mesh_field.cc similarity index 92% rename from tests/mito.lib/discretization/mesh_field.cc rename to tests/mito.lib/discrete/mesh_field.cc index 38d0a50b4..5eee2910d 100644 --- a/tests/mito.lib/discretization/mesh_field.cc +++ b/tests/mito.lib/discrete/mesh_field.cc @@ -4,7 +4,7 @@ // #include -#include +#include #include #include @@ -23,7 +23,7 @@ TEST(Discretization, NodalFieldSphere) auto mesh = mito::io::summit::reader>(fileStream, coord_system); // a mesh field on the mesh - auto mesh_field = mito::discretization::mesh_field>(mesh, "normal"); + auto mesh_field = mito::discrete::mesh_field>(mesh, "normal"); // the normal field to the submanifold constexpr auto normal_field = mito::fields::field([](const coordinates_t & x) -> auto { diff --git a/tests/mito.lib/discretization/quadrature_field.cc b/tests/mito.lib/discrete/quadrature_field.cc similarity index 92% rename from tests/mito.lib/discretization/quadrature_field.cc rename to tests/mito.lib/discrete/quadrature_field.cc index 696292f80..d76880dc7 100644 --- a/tests/mito.lib/discretization/quadrature_field.cc +++ b/tests/mito.lib/discrete/quadrature_field.cc @@ -4,7 +4,7 @@ // #include -#include +#include // pick a cell type @@ -14,7 +14,7 @@ constexpr int Q = 1; // a type for the field using vector_type = mito::tensor::vector_t<2>; // assemble the quadrature field -using quadrature_field_type = mito::discretization::quadrature_field_t; +using quadrature_field_type = mito::discrete::quadrature_field_t; // an empty topology auto & topology = mito::topology::topology(); diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index ea9383a86..91be35cf9 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -12,7 +12,7 @@ using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN // the type of coordinate system using coord_system_t = mito::geometry::coordinate_system_t; // the type of discretization node -using discretization_node_t = mito::discretization::discretization_node_t; +using discretization_node_t = mito::discrete::discretization_node_t; // the type of cell using cell_t = mito::geometry::triangle_t<2>; // Gauss quadrature on triangles with degree of exactness 4 diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index cc14f5b92..ecb2f7f76 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -141,10 +141,9 @@ TEST(Fem, PoissonSquare) #ifdef WITH_VTK // the forcing term mesh field on the mesh (for visualization) - auto forcing = mito::discretization::mesh_field(mesh, coord_system, f, "forcing term"); + auto forcing = mito::discrete::mesh_field(mesh, coord_system, f, "forcing term"); // the exact solution mesh field on the mesh (for visualization) - auto exact_solution = - mito::discretization::mesh_field(mesh, coord_system, u_ex, "exact solution"); + auto exact_solution = mito::discrete::mesh_field(mesh, coord_system, u_ex, "exact solution"); // write mesh to vtk file auto writer = mito::io::vtk::field_writer("poisson_square_data", mesh, coord_system); // sign {forcing} up with the writer diff --git a/tests/mito.lib/io/parallel_vtk_cloud_field_writer.cc b/tests/mito.lib/io/parallel_vtk_cloud_field_writer.cc index 1330474c8..342a167c1 100644 --- a/tests/mito.lib/io/parallel_vtk_cloud_field_writer.cc +++ b/tests/mito.lib/io/parallel_vtk_cloud_field_writer.cc @@ -56,8 +56,7 @@ TEST(ParallelVtkWriter, CloudField) } // a point field on the cloud - auto point_field = - mito::discretization::point_field>(cloud, "normal"); + auto point_field = mito::discrete::point_field>(cloud, "normal"); // the normal field to the submanifold constexpr auto normal_field = mito::fields::field([](const coordinates_t & x) -> auto { diff --git a/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc b/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc index 5fa6e6b1c..bc2ee42af 100644 --- a/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc +++ b/tests/mito.lib/io/parallel_vtk_mesh_field_writer.cc @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include @@ -39,7 +39,7 @@ TEST(ParallelVtkWriter, MeshField) auto mesh = mito::io::summit::reader>(fileStream, coord_system); // a mesh field on the mesh - auto mesh_field = mito::discretization::mesh_field>(mesh, "normal"); + auto mesh_field = mito::discrete::mesh_field>(mesh, "normal"); // the normal field to the ball constexpr auto normal_field = mito::fields::field([](const coordinates_t & x) -> auto { diff --git a/tests/mito.lib/io/parallel_vtk_mesh_writer.cc b/tests/mito.lib/io/parallel_vtk_mesh_writer.cc index 2998f611f..6908aa24e 100644 --- a/tests/mito.lib/io/parallel_vtk_mesh_writer.cc +++ b/tests/mito.lib/io/parallel_vtk_mesh_writer.cc @@ -6,7 +6,7 @@ #include #include -#include +#include #include #include diff --git a/tests/mito.lib/io/summit_to_summit_mesh_2D.cc b/tests/mito.lib/io/summit_to_summit_mesh_2D.cc index 71772d843..cc79599fc 100644 --- a/tests/mito.lib/io/summit_to_summit_mesh_2D.cc +++ b/tests/mito.lib/io/summit_to_summit_mesh_2D.cc @@ -35,7 +35,7 @@ test() // get the original number of mesh nodes by counting the nodes of a mesh field built on it original_mesh_nodes = - mito::discretization::mesh_field(mesh, "field").size(); + mito::discrete::mesh_field(mesh, "field").size(); // write summit mesh mito::io::summit::writer("rectangle_copy", mesh, coord_system); @@ -54,7 +54,7 @@ test() // get the reread number of mesh nodes by counting the nodes of a mesh field built on it reread_mesh_nodes = - mito::discretization::mesh_field(mesh, "field").size(); + mito::discrete::mesh_field(mesh, "field").size(); #ifdef WITH_VTK // write mesh to vtk file From 97e11f4d628dc9c1e6278951be2f354fa2169ae4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 07:47:30 +0200 Subject: [PATCH 207/273] solvers: add forgotten header {solvers.h} --- lib/mito/solvers.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 lib/mito/solvers.h diff --git a/lib/mito/solvers.h b/lib/mito/solvers.h new file mode 100644 index 000000000..f36edb3aa --- /dev/null +++ b/lib/mito/solvers.h @@ -0,0 +1,14 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +// publish the interface +#include "solvers/public.h" + + +// end of file \ No newline at end of file From 1e09bed5207111c3fa4313f84ebfd1cf22b1b9bc Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 07:54:48 +0200 Subject: [PATCH 208/273] solvers: remove unnecessary {include} statement --- lib/mito/solvers/externals.h | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/mito/solvers/externals.h b/lib/mito/solvers/externals.h index 8d07d985d..3b1a7812d 100644 --- a/lib/mito/solvers/externals.h +++ b/lib/mito/solvers/externals.h @@ -8,7 +8,6 @@ // support -#include "../discretization.h" #include "../journal.h" From 0b7b4105d046f807cbac7b865cf14187986f7a30 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 07:57:47 +0200 Subject: [PATCH 209/273] fem: rename {discretization} directory to {fem} --- lib/mito/{discretization.h => fem.h} | 4 ++-- lib/mito/{discretization => fem}/DiscreteSystem.h | 0 lib/mito/{discretization => fem}/FunctionSpace.h | 0 lib/mito/{discretization => fem}/api.h | 0 lib/mito/{discretization => fem}/blocks.h | 0 lib/mito/{discretization => fem}/blocks/AssemblyBlock.h | 0 lib/mito/{discretization => fem}/blocks/GradGradBlock.h | 0 lib/mito/{discretization => fem}/blocks/L2NormBlock.h | 0 lib/mito/{discretization => fem}/blocks/SourceTermBlock.h | 0 lib/mito/{discretization => fem}/blocks/api.h | 0 lib/mito/{discretization => fem}/blocks/externals.h | 0 lib/mito/{discretization => fem}/blocks/factories.h | 0 lib/mito/{discretization => fem}/blocks/forward.h | 0 lib/mito/{discretization => fem}/blocks/public.h | 0 lib/mito/{discretization => fem}/externals.h | 0 lib/mito/{discretization => fem}/factories.h | 0 lib/mito/{discretization => fem}/fem.h | 0 lib/mito/{discretization => fem}/fem/IsoparametricTriangle.h | 0 lib/mito/{discretization => fem}/fem/ReferenceTriangle.h | 0 lib/mito/{discretization => fem}/fem/api.h | 0 lib/mito/{discretization => fem}/fem/externals.h | 0 lib/mito/{discretization => fem}/fem/factories.h | 0 lib/mito/{discretization => fem}/fem/forward.h | 0 .../fem/isoparametric_simplex_library.h | 0 lib/mito/{discretization => fem}/fem/public.h | 0 .../fem/tri1/IsoparametricTriangleP1.h | 0 lib/mito/{discretization => fem}/fem/tri1/ShapeTriangleP1.h | 0 lib/mito/{discretization => fem}/fem/tri1/public.h | 0 .../fem/tri2/IsoparametricTriangleP2.h | 0 lib/mito/{discretization => fem}/fem/tri2/ShapeTriangleP2.h | 0 lib/mito/{discretization => fem}/fem/tri2/public.h | 0 lib/mito/{discretization => fem}/fem/utilities.h | 0 lib/mito/{discretization => fem}/forward.h | 0 lib/mito/{discretization => fem}/public.h | 0 lib/mito/io/externals.h | 2 +- lib/mito/public.h | 2 +- lib/mito/quadrature/externals.h | 2 +- 37 files changed, 5 insertions(+), 5 deletions(-) rename lib/mito/{discretization.h => fem.h} (67%) rename lib/mito/{discretization => fem}/DiscreteSystem.h (100%) rename lib/mito/{discretization => fem}/FunctionSpace.h (100%) rename lib/mito/{discretization => fem}/api.h (100%) rename lib/mito/{discretization => fem}/blocks.h (100%) rename lib/mito/{discretization => fem}/blocks/AssemblyBlock.h (100%) rename lib/mito/{discretization => fem}/blocks/GradGradBlock.h (100%) rename lib/mito/{discretization => fem}/blocks/L2NormBlock.h (100%) rename lib/mito/{discretization => fem}/blocks/SourceTermBlock.h (100%) rename lib/mito/{discretization => fem}/blocks/api.h (100%) rename lib/mito/{discretization => fem}/blocks/externals.h (100%) rename lib/mito/{discretization => fem}/blocks/factories.h (100%) rename lib/mito/{discretization => fem}/blocks/forward.h (100%) rename lib/mito/{discretization => fem}/blocks/public.h (100%) rename lib/mito/{discretization => fem}/externals.h (100%) rename lib/mito/{discretization => fem}/factories.h (100%) rename lib/mito/{discretization => fem}/fem.h (100%) rename lib/mito/{discretization => fem}/fem/IsoparametricTriangle.h (100%) rename lib/mito/{discretization => fem}/fem/ReferenceTriangle.h (100%) rename lib/mito/{discretization => fem}/fem/api.h (100%) rename lib/mito/{discretization => fem}/fem/externals.h (100%) rename lib/mito/{discretization => fem}/fem/factories.h (100%) rename lib/mito/{discretization => fem}/fem/forward.h (100%) rename lib/mito/{discretization => fem}/fem/isoparametric_simplex_library.h (100%) rename lib/mito/{discretization => fem}/fem/public.h (100%) rename lib/mito/{discretization => fem}/fem/tri1/IsoparametricTriangleP1.h (100%) rename lib/mito/{discretization => fem}/fem/tri1/ShapeTriangleP1.h (100%) rename lib/mito/{discretization => fem}/fem/tri1/public.h (100%) rename lib/mito/{discretization => fem}/fem/tri2/IsoparametricTriangleP2.h (100%) rename lib/mito/{discretization => fem}/fem/tri2/ShapeTriangleP2.h (100%) rename lib/mito/{discretization => fem}/fem/tri2/public.h (100%) rename lib/mito/{discretization => fem}/fem/utilities.h (100%) rename lib/mito/{discretization => fem}/forward.h (100%) rename lib/mito/{discretization => fem}/public.h (100%) diff --git a/lib/mito/discretization.h b/lib/mito/fem.h similarity index 67% rename from lib/mito/discretization.h rename to lib/mito/fem.h index 6288e2e37..1a2a834fb 100644 --- a/lib/mito/discretization.h +++ b/lib/mito/fem.h @@ -8,8 +8,8 @@ // publish the interface -// the api is in "discretization/api.h" -#include "discretization/public.h" +// the api is in "fem/api.h" +#include "fem/public.h" // end of file diff --git a/lib/mito/discretization/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h similarity index 100% rename from lib/mito/discretization/DiscreteSystem.h rename to lib/mito/fem/DiscreteSystem.h diff --git a/lib/mito/discretization/FunctionSpace.h b/lib/mito/fem/FunctionSpace.h similarity index 100% rename from lib/mito/discretization/FunctionSpace.h rename to lib/mito/fem/FunctionSpace.h diff --git a/lib/mito/discretization/api.h b/lib/mito/fem/api.h similarity index 100% rename from lib/mito/discretization/api.h rename to lib/mito/fem/api.h diff --git a/lib/mito/discretization/blocks.h b/lib/mito/fem/blocks.h similarity index 100% rename from lib/mito/discretization/blocks.h rename to lib/mito/fem/blocks.h diff --git a/lib/mito/discretization/blocks/AssemblyBlock.h b/lib/mito/fem/blocks/AssemblyBlock.h similarity index 100% rename from lib/mito/discretization/blocks/AssemblyBlock.h rename to lib/mito/fem/blocks/AssemblyBlock.h diff --git a/lib/mito/discretization/blocks/GradGradBlock.h b/lib/mito/fem/blocks/GradGradBlock.h similarity index 100% rename from lib/mito/discretization/blocks/GradGradBlock.h rename to lib/mito/fem/blocks/GradGradBlock.h diff --git a/lib/mito/discretization/blocks/L2NormBlock.h b/lib/mito/fem/blocks/L2NormBlock.h similarity index 100% rename from lib/mito/discretization/blocks/L2NormBlock.h rename to lib/mito/fem/blocks/L2NormBlock.h diff --git a/lib/mito/discretization/blocks/SourceTermBlock.h b/lib/mito/fem/blocks/SourceTermBlock.h similarity index 100% rename from lib/mito/discretization/blocks/SourceTermBlock.h rename to lib/mito/fem/blocks/SourceTermBlock.h diff --git a/lib/mito/discretization/blocks/api.h b/lib/mito/fem/blocks/api.h similarity index 100% rename from lib/mito/discretization/blocks/api.h rename to lib/mito/fem/blocks/api.h diff --git a/lib/mito/discretization/blocks/externals.h b/lib/mito/fem/blocks/externals.h similarity index 100% rename from lib/mito/discretization/blocks/externals.h rename to lib/mito/fem/blocks/externals.h diff --git a/lib/mito/discretization/blocks/factories.h b/lib/mito/fem/blocks/factories.h similarity index 100% rename from lib/mito/discretization/blocks/factories.h rename to lib/mito/fem/blocks/factories.h diff --git a/lib/mito/discretization/blocks/forward.h b/lib/mito/fem/blocks/forward.h similarity index 100% rename from lib/mito/discretization/blocks/forward.h rename to lib/mito/fem/blocks/forward.h diff --git a/lib/mito/discretization/blocks/public.h b/lib/mito/fem/blocks/public.h similarity index 100% rename from lib/mito/discretization/blocks/public.h rename to lib/mito/fem/blocks/public.h diff --git a/lib/mito/discretization/externals.h b/lib/mito/fem/externals.h similarity index 100% rename from lib/mito/discretization/externals.h rename to lib/mito/fem/externals.h diff --git a/lib/mito/discretization/factories.h b/lib/mito/fem/factories.h similarity index 100% rename from lib/mito/discretization/factories.h rename to lib/mito/fem/factories.h diff --git a/lib/mito/discretization/fem.h b/lib/mito/fem/fem.h similarity index 100% rename from lib/mito/discretization/fem.h rename to lib/mito/fem/fem.h diff --git a/lib/mito/discretization/fem/IsoparametricTriangle.h b/lib/mito/fem/fem/IsoparametricTriangle.h similarity index 100% rename from lib/mito/discretization/fem/IsoparametricTriangle.h rename to lib/mito/fem/fem/IsoparametricTriangle.h diff --git a/lib/mito/discretization/fem/ReferenceTriangle.h b/lib/mito/fem/fem/ReferenceTriangle.h similarity index 100% rename from lib/mito/discretization/fem/ReferenceTriangle.h rename to lib/mito/fem/fem/ReferenceTriangle.h diff --git a/lib/mito/discretization/fem/api.h b/lib/mito/fem/fem/api.h similarity index 100% rename from lib/mito/discretization/fem/api.h rename to lib/mito/fem/fem/api.h diff --git a/lib/mito/discretization/fem/externals.h b/lib/mito/fem/fem/externals.h similarity index 100% rename from lib/mito/discretization/fem/externals.h rename to lib/mito/fem/fem/externals.h diff --git a/lib/mito/discretization/fem/factories.h b/lib/mito/fem/fem/factories.h similarity index 100% rename from lib/mito/discretization/fem/factories.h rename to lib/mito/fem/fem/factories.h diff --git a/lib/mito/discretization/fem/forward.h b/lib/mito/fem/fem/forward.h similarity index 100% rename from lib/mito/discretization/fem/forward.h rename to lib/mito/fem/fem/forward.h diff --git a/lib/mito/discretization/fem/isoparametric_simplex_library.h b/lib/mito/fem/fem/isoparametric_simplex_library.h similarity index 100% rename from lib/mito/discretization/fem/isoparametric_simplex_library.h rename to lib/mito/fem/fem/isoparametric_simplex_library.h diff --git a/lib/mito/discretization/fem/public.h b/lib/mito/fem/fem/public.h similarity index 100% rename from lib/mito/discretization/fem/public.h rename to lib/mito/fem/fem/public.h diff --git a/lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h similarity index 100% rename from lib/mito/discretization/fem/tri1/IsoparametricTriangleP1.h rename to lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h diff --git a/lib/mito/discretization/fem/tri1/ShapeTriangleP1.h b/lib/mito/fem/fem/tri1/ShapeTriangleP1.h similarity index 100% rename from lib/mito/discretization/fem/tri1/ShapeTriangleP1.h rename to lib/mito/fem/fem/tri1/ShapeTriangleP1.h diff --git a/lib/mito/discretization/fem/tri1/public.h b/lib/mito/fem/fem/tri1/public.h similarity index 100% rename from lib/mito/discretization/fem/tri1/public.h rename to lib/mito/fem/fem/tri1/public.h diff --git a/lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h similarity index 100% rename from lib/mito/discretization/fem/tri2/IsoparametricTriangleP2.h rename to lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h diff --git a/lib/mito/discretization/fem/tri2/ShapeTriangleP2.h b/lib/mito/fem/fem/tri2/ShapeTriangleP2.h similarity index 100% rename from lib/mito/discretization/fem/tri2/ShapeTriangleP2.h rename to lib/mito/fem/fem/tri2/ShapeTriangleP2.h diff --git a/lib/mito/discretization/fem/tri2/public.h b/lib/mito/fem/fem/tri2/public.h similarity index 100% rename from lib/mito/discretization/fem/tri2/public.h rename to lib/mito/fem/fem/tri2/public.h diff --git a/lib/mito/discretization/fem/utilities.h b/lib/mito/fem/fem/utilities.h similarity index 100% rename from lib/mito/discretization/fem/utilities.h rename to lib/mito/fem/fem/utilities.h diff --git a/lib/mito/discretization/forward.h b/lib/mito/fem/forward.h similarity index 100% rename from lib/mito/discretization/forward.h rename to lib/mito/fem/forward.h diff --git a/lib/mito/discretization/public.h b/lib/mito/fem/public.h similarity index 100% rename from lib/mito/discretization/public.h rename to lib/mito/fem/public.h diff --git a/lib/mito/io/externals.h b/lib/mito/io/externals.h index 29d77e1b3..deb1c8864 100644 --- a/lib/mito/io/externals.h +++ b/lib/mito/io/externals.h @@ -14,7 +14,7 @@ #include "../journal.h" #include "../geometry.h" #include "../mesh.h" -#include "../discretization.h" +#include "../fem.h" // end of file diff --git a/lib/mito/public.h b/lib/mito/public.h index f1f58b3cc..7b5c879ae 100644 --- a/lib/mito/public.h +++ b/lib/mito/public.h @@ -12,7 +12,7 @@ #include "tensor.h" #include "functions.h" #include "discrete.h" -#include "discretization.h" +#include "fem.h" #include "constraints.h" #include "coordinates.h" #include "geometry.h" diff --git a/lib/mito/quadrature/externals.h b/lib/mito/quadrature/externals.h index bbebce90e..9ff5cfce4 100644 --- a/lib/mito/quadrature/externals.h +++ b/lib/mito/quadrature/externals.h @@ -13,7 +13,7 @@ #include "../journal.h" #include "../manifolds.h" #include "../math.h" -#include "../discretization.h" +#include "../fem.h" // end of file From 320be08c07355cb7974c873a85c514cf83311692 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 07:59:33 +0200 Subject: [PATCH 210/273] fem: rename {discretization} namespace to {fem} --- lib/mito/fem/DiscreteSystem.h | 2 +- lib/mito/fem/FunctionSpace.h | 2 +- lib/mito/fem/api.h | 2 +- lib/mito/fem/blocks/AssemblyBlock.h | 2 +- lib/mito/fem/blocks/GradGradBlock.h | 2 +- lib/mito/fem/blocks/L2NormBlock.h | 2 +- lib/mito/fem/blocks/SourceTermBlock.h | 2 +- lib/mito/fem/blocks/api.h | 2 +- lib/mito/fem/blocks/factories.h | 2 +- lib/mito/fem/blocks/forward.h | 2 +- lib/mito/fem/factories.h | 2 +- lib/mito/fem/fem/IsoparametricTriangle.h | 2 +- lib/mito/fem/fem/ReferenceTriangle.h | 2 +- lib/mito/fem/fem/api.h | 2 +- lib/mito/fem/fem/factories.h | 2 +- lib/mito/fem/fem/forward.h | 2 +- .../fem/fem/isoparametric_simplex_library.h | 2 +- .../fem/fem/tri1/IsoparametricTriangleP1.h | 2 +- lib/mito/fem/fem/tri1/ShapeTriangleP1.h | 2 +- .../fem/fem/tri2/IsoparametricTriangleP2.h | 2 +- lib/mito/fem/fem/tri2/ShapeTriangleP2.h | 2 +- lib/mito/fem/fem/utilities.h | 2 +- lib/mito/fem/forward.h | 2 +- lib/mito/io/vtk/FieldVTKWriter.h | 4 ++-- lib/mito/io/vtk/NodeVTKWriter.h | 2 +- lib/mito/io/vtk/api.h | 18 ++++++------------ lib/mito/io/vtk/factories.h | 12 ++++-------- lib/mito/io/vtk/forward.h | 2 +- lib/mito/solvers/LinearSolver.h | 2 +- .../discretization/isoparametric_triangle.cc | 4 ++-- tests/mito.lib/discretization/poisson.cc | 12 +++++------- .../shape_functions_triangle_p1.cc | 2 +- .../shape_functions_triangle_p2.cc | 2 +- 33 files changed, 47 insertions(+), 59 deletions(-) diff --git a/lib/mito/fem/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h index 14b67891b..8d66d5fd8 100644 --- a/lib/mito/fem/DiscreteSystem.h +++ b/lib/mito/fem/DiscreteSystem.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { // TOFIX: for now the discrete system is one per function space. We should figure out a way to // extend the design to the case that there are multiple finite element discretizations that diff --git a/lib/mito/fem/FunctionSpace.h b/lib/mito/fem/FunctionSpace.h index e77ffe1df..2c192a596 100644 --- a/lib/mito/fem/FunctionSpace.h +++ b/lib/mito/fem/FunctionSpace.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { // Class {FunctionSpace} represents a collection of finite elements of order {p} defined on a // manifold and subjected to a set of constraints. diff --git a/lib/mito/fem/api.h b/lib/mito/fem/api.h index 0a8ec8380..6fbeadd51 100644 --- a/lib/mito/fem/api.h +++ b/lib/mito/fem/api.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { // nodal field factory template diff --git a/lib/mito/fem/blocks/AssemblyBlock.h b/lib/mito/fem/blocks/AssemblyBlock.h index 637c4ff4f..4d44ec69b 100644 --- a/lib/mito/fem/blocks/AssemblyBlock.h +++ b/lib/mito/fem/blocks/AssemblyBlock.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization::blocks { +namespace mito::fem::blocks { // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in // the same elementary type) diff --git a/lib/mito/fem/blocks/GradGradBlock.h b/lib/mito/fem/blocks/GradGradBlock.h index 533b2624a..a830fb082 100644 --- a/lib/mito/fem/blocks/GradGradBlock.h +++ b/lib/mito/fem/blocks/GradGradBlock.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization::blocks { +namespace mito::fem::blocks { // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in // the same elementary type) diff --git a/lib/mito/fem/blocks/L2NormBlock.h b/lib/mito/fem/blocks/L2NormBlock.h index d2e724ee4..eff2ebddd 100644 --- a/lib/mito/fem/blocks/L2NormBlock.h +++ b/lib/mito/fem/blocks/L2NormBlock.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization::blocks { +namespace mito::fem::blocks { template // require that {functionT} is a function in barycentric coordinates diff --git a/lib/mito/fem/blocks/SourceTermBlock.h b/lib/mito/fem/blocks/SourceTermBlock.h index b0b669a9a..0a3a74b13 100644 --- a/lib/mito/fem/blocks/SourceTermBlock.h +++ b/lib/mito/fem/blocks/SourceTermBlock.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization::blocks { +namespace mito::fem::blocks { // TOFIX: the source does not need to be necessarily a scalar field, it can be some other field // see if we can use {field_c} instead of {scalar_field_c} diff --git a/lib/mito/fem/blocks/api.h b/lib/mito/fem/blocks/api.h index 370396443..2bbbb7a4d 100644 --- a/lib/mito/fem/blocks/api.h +++ b/lib/mito/fem/blocks/api.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization::blocks { +namespace mito::fem::blocks { // assembly block template diff --git a/lib/mito/fem/blocks/factories.h b/lib/mito/fem/blocks/factories.h index 8a6d32533..dd906a0f6 100644 --- a/lib/mito/fem/blocks/factories.h +++ b/lib/mito/fem/blocks/factories.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization::blocks { +namespace mito::fem::blocks { // matrix block factory template diff --git a/lib/mito/fem/blocks/forward.h b/lib/mito/fem/blocks/forward.h index b58068b66..adbf4e276 100644 --- a/lib/mito/fem/blocks/forward.h +++ b/lib/mito/fem/blocks/forward.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization::blocks { +namespace mito::fem::blocks { // assembly block template diff --git a/lib/mito/fem/factories.h b/lib/mito/fem/factories.h index b4df289ae..ebb2b5a32 100644 --- a/lib/mito/fem/factories.h +++ b/lib/mito/fem/factories.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { // nodal field factory template diff --git a/lib/mito/fem/fem/IsoparametricTriangle.h b/lib/mito/fem/fem/IsoparametricTriangle.h index ecfd1a131..8f71ca9c9 100644 --- a/lib/mito/fem/fem/IsoparametricTriangle.h +++ b/lib/mito/fem/fem/IsoparametricTriangle.h @@ -11,7 +11,7 @@ // Class {IsoparametricTriangle} represents a second order simplex equipped barycentric coordinates. -namespace mito::discretization { +namespace mito::fem { class IsoparametricTriangle : public utilities::Invalidatable { public: diff --git a/lib/mito/fem/fem/ReferenceTriangle.h b/lib/mito/fem/fem/ReferenceTriangle.h index ae3dbe18b..74c54747e 100644 --- a/lib/mito/fem/fem/ReferenceTriangle.h +++ b/lib/mito/fem/fem/ReferenceTriangle.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { class ReferenceTriangle { diff --git a/lib/mito/fem/fem/api.h b/lib/mito/fem/fem/api.h index 264ce9af9..3dc17eb77 100644 --- a/lib/mito/fem/fem/api.h +++ b/lib/mito/fem/fem/api.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { } diff --git a/lib/mito/fem/fem/factories.h b/lib/mito/fem/fem/factories.h index d5414b6fc..3abada991 100644 --- a/lib/mito/fem/fem/factories.h +++ b/lib/mito/fem/fem/factories.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { } diff --git a/lib/mito/fem/fem/forward.h b/lib/mito/fem/fem/forward.h index 264ce9af9..3dc17eb77 100644 --- a/lib/mito/fem/fem/forward.h +++ b/lib/mito/fem/fem/forward.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { } diff --git a/lib/mito/fem/fem/isoparametric_simplex_library.h b/lib/mito/fem/fem/isoparametric_simplex_library.h index ba89ef900..3669cf4d7 100644 --- a/lib/mito/fem/fem/isoparametric_simplex_library.h +++ b/lib/mito/fem/fem/isoparametric_simplex_library.h @@ -11,7 +11,7 @@ #include "tri2/public.h" -namespace mito::discretization { +namespace mito::fem { // struct storing the type of an isoparametric simplex of polynomial degree {degree} on a // geometric simplex of type {geometricSimplexT} diff --git a/lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h index 72c431fa3..157000d0e 100644 --- a/lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h @@ -12,7 +12,7 @@ // equipped with linear shape functions defined in the parametric space. -namespace mito::discretization { +namespace mito::fem { class IsoparametricTriangleP1 : public IsoparametricTriangle { diff --git a/lib/mito/fem/fem/tri1/ShapeTriangleP1.h b/lib/mito/fem/fem/tri1/ShapeTriangleP1.h index dcc893e73..9753a4374 100644 --- a/lib/mito/fem/fem/tri1/ShapeTriangleP1.h +++ b/lib/mito/fem/fem/tri1/ShapeTriangleP1.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { class ShapeTriangleP1 { diff --git a/lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h index 20dfc1c8f..8cd54dcb5 100644 --- a/lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h @@ -12,7 +12,7 @@ // equipped with quadratic shape functions defined in the parametric space. -namespace mito::discretization { +namespace mito::fem { class IsoparametricTriangleP2 : public IsoparametricTriangle { diff --git a/lib/mito/fem/fem/tri2/ShapeTriangleP2.h b/lib/mito/fem/fem/tri2/ShapeTriangleP2.h index 4971369bd..563181684 100644 --- a/lib/mito/fem/fem/tri2/ShapeTriangleP2.h +++ b/lib/mito/fem/fem/tri2/ShapeTriangleP2.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { class ShapeTriangleP2 { diff --git a/lib/mito/fem/fem/utilities.h b/lib/mito/fem/fem/utilities.h index 6725a334b..5812d04ed 100644 --- a/lib/mito/fem/fem/utilities.h +++ b/lib/mito/fem/fem/utilities.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { // populate a container with a collection of all nodes in a function space template diff --git a/lib/mito/fem/forward.h b/lib/mito/fem/forward.h index 2312a6477..caa8a4bcf 100644 --- a/lib/mito/fem/forward.h +++ b/lib/mito/fem/forward.h @@ -7,7 +7,7 @@ #pragma once -namespace mito::discretization { +namespace mito::fem { // class function space template diff --git a/lib/mito/io/vtk/FieldVTKWriter.h b/lib/mito/io/vtk/FieldVTKWriter.h index d29e0a765..93eab2364 100644 --- a/lib/mito/io/vtk/FieldVTKWriter.h +++ b/lib/mito/io/vtk/FieldVTKWriter.h @@ -29,7 +29,7 @@ namespace mito::io::vtk { }; // specialization to {function_space_c} case - template + template struct field_type { template using type = discrete::nodal_field_t; @@ -97,7 +97,7 @@ namespace mito::io::vtk { vtkArray->SetNumberOfTuples(n_points); // populate the array - if constexpr (mesh::mesh_c or discretization::function_space_c) { + if constexpr (mesh::mesh_c or fem::function_space_c) { // get the nodes in the grid const auto & nodes = _grid_writer.nodes(); diff --git a/lib/mito/io/vtk/NodeVTKWriter.h b/lib/mito/io/vtk/NodeVTKWriter.h index 89df530ae..9c01ca3e4 100644 --- a/lib/mito/io/vtk/NodeVTKWriter.h +++ b/lib/mito/io/vtk/NodeVTKWriter.h @@ -13,7 +13,7 @@ namespace mito::io::vtk { // should be generalized to write on any discretization node type, including nodes of higher // order elements template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT, + fem::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT, class vtkGridWriterT> requires( utilities::same_dim_c diff --git a/lib/mito/io/vtk/api.h b/lib/mito/io/vtk/api.h index 8e1092c06..b8e9440b9 100644 --- a/lib/mito/io/vtk/api.h +++ b/lib/mito/io/vtk/api.h @@ -20,8 +20,7 @@ namespace mito::io::vtk { using cloud_writer_t = PointCloudVTKWriter>; // node writer alias - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) using node_writer_t = NodeVTKWriter>; @@ -41,8 +40,7 @@ namespace mito::io::vtk { auto grid_writer(std::string filename, const cloudT & cloud, const coordSystemT & coord_system); // node writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto grid_writer( std::string filename, const functionSpaceT & function_space, @@ -60,8 +58,7 @@ namespace mito::io::vtk { std::string filename, const cloudT & cloud, const coordSystemT & coord_system); // node field writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto field_writer( std::string filename, const functionSpaceT & function_space, @@ -81,8 +78,7 @@ namespace mito::io::vtk { PointCloudVTKWriter>; // parallel node writer alias - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) using parallel_node_writer_t = NodeVTKWriter>; @@ -100,8 +96,7 @@ namespace mito::io::vtk { std::string filename, const cloudT & cloud, const coordSystemT & coord_system); // parallel node writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto parallel_node_writer( std::string filename, const functionSpaceT & function_space, @@ -120,8 +115,7 @@ namespace mito::io::vtk { std::string filename, const cloudT & cloud, const coordSystemT & coord_system); // parallel node field writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto parallel_field_writer( std::string filename, const functionSpaceT & function_space, diff --git a/lib/mito/io/vtk/factories.h b/lib/mito/io/vtk/factories.h index 59a131bca..94c11601d 100644 --- a/lib/mito/io/vtk/factories.h +++ b/lib/mito/io/vtk/factories.h @@ -26,8 +26,7 @@ namespace mito::io::vtk { } // vtk node writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto grid_writer( std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) @@ -54,8 +53,7 @@ namespace mito::io::vtk { } // vtk node field writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto field_writer( std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) @@ -84,8 +82,7 @@ namespace mito::io::vtk { } // parallel vtk node writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto parallel_grid_writer( std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) @@ -114,8 +111,7 @@ namespace mito::io::vtk { } // parallel vtk node field writer factory - template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT> + template requires(utilities::same_dim_c) auto parallel_field_writer( std::string filename, const functionSpaceT & node, const coordSystemT & coord_system) diff --git a/lib/mito/io/vtk/forward.h b/lib/mito/io/vtk/forward.h index c2b984fcc..7615837e6 100644 --- a/lib/mito/io/vtk/forward.h +++ b/lib/mito/io/vtk/forward.h @@ -30,7 +30,7 @@ namespace mito::io::vtk { // class node writer template < - discretization::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT, + fem::function_space_c functionSpaceT, geometry::coordinate_system_c coordSystemT, class vtkGridWriterT> requires( utilities::same_dim_c diff --git a/lib/mito/solvers/LinearSolver.h b/lib/mito/solvers/LinearSolver.h index 610b1947f..e1ccb2154 100644 --- a/lib/mito/solvers/LinearSolver.h +++ b/lib/mito/solvers/LinearSolver.h @@ -69,7 +69,7 @@ namespace mito::solvers { }; -} // namespace mito::discretization +} // namespace mito::fem // end of file diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index 91be35cf9..d41826221 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -222,7 +222,7 @@ TEST(Fem, IsoparametricTriangle) { // first order isoparametric triangle - using element_p1_t = mito::discretization::isoparametric_simplex<1, cell_t>::type; + using element_p1_t = mito::fem::isoparametric_simplex<1, cell_t>::type; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); @@ -265,7 +265,7 @@ TEST(Fem, IsoparametricTriangle) { // second order isoparametric triangle - using element_p2_t = mito::discretization::isoparametric_simplex<2, cell_t>::type; + using element_p2_t = mito::fem::isoparametric_simplex<2, cell_t>::type; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index ecb2f7f76..8c16856a4 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -22,7 +22,7 @@ using quadrature_rule_t = // the degree of the finite element constexpr int degree = 2; // typedef for a finite element -using finite_element_t = mito::discretization::isoparametric_simplex_t; +using finite_element_t = mito::fem::isoparametric_simplex_t; // typedef for a linear system of equations using linear_system_t = mito::matrix_solvers::petsc::linear_system_t; @@ -72,14 +72,13 @@ TEST(Fem, PoissonSquare) // the function space (linear elements on the manifold) // TOFIX: function space should be template with respect to the finite element type - auto function_space = mito::discretization::function_space(manifold, constraints); + auto function_space = mito::fem::function_space(manifold, constraints); // TODO: all top level instances have names. Name should be the first argument. Then we can use // names in the configuration file and in the hdf5 file. Check libuuid vs. leading namestring. // // the discrete system - auto discrete_system = - mito::discretization::discrete_system(function_space, "mysystem"); + auto discrete_system = mito::fem::discrete_system(function_space, "mysystem"); // instantiate a linear solver for the discrete system auto solver = mito::solvers::linear_solver(discrete_system); @@ -91,8 +90,7 @@ TEST(Fem, PoissonSquare) solver.set_options("-ksp_type preonly -pc_type cholesky"); // a grad-grad matrix block - auto fem_lhs_block = - mito::discretization::blocks::grad_grad_block(); + auto fem_lhs_block = mito::fem::blocks::grad_grad_block(); // the right hand side auto f = mito::fields::field( @@ -102,7 +100,7 @@ TEST(Fem, PoissonSquare) // a source term block auto fem_rhs_block = - mito::discretization::blocks::source_term_block(f); + mito::fem::blocks::source_term_block(f); // TODO: // // monolithic discretization matrix = [A, B; C, D] diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc index 688dc23d6..de338cb6e 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_p1.cc @@ -8,7 +8,7 @@ // first order shape functions type -using shape_t = mito::discretization::ShapeTriangleP1; +using shape_t = mito::fem::ShapeTriangleP1; // the parametric coordinates type using parametric_coordinates_t = shape_t::reference_element_type::parametric_coordinates_type; diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p2.cc b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc index 1e3bb1612..913fbb092 100644 --- a/tests/mito.lib/discretization/shape_functions_triangle_p2.cc +++ b/tests/mito.lib/discretization/shape_functions_triangle_p2.cc @@ -8,7 +8,7 @@ // second order shape functions type -using shape_t = mito::discretization::ShapeTriangleP2; +using shape_t = mito::fem::ShapeTriangleP2; // the parametric coordinates type using parametric_coordinates_t = shape_t::reference_element_type::parametric_coordinates_type; From 5dcdf3b6f4021d006f7d158eea23315d4d01b35e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 08:01:16 +0200 Subject: [PATCH 211/273] fem: rename {fem} subdirectory to {elements} --- lib/mito/fem/{fem.h => elements.h} | 2 +- lib/mito/fem/{fem => elements}/IsoparametricTriangle.h | 0 lib/mito/fem/{fem => elements}/ReferenceTriangle.h | 0 lib/mito/fem/{fem => elements}/api.h | 0 lib/mito/fem/{fem => elements}/externals.h | 0 lib/mito/fem/{fem => elements}/factories.h | 0 lib/mito/fem/{fem => elements}/forward.h | 0 lib/mito/fem/{fem => elements}/isoparametric_simplex_library.h | 0 lib/mito/fem/{fem => elements}/public.h | 0 lib/mito/fem/{fem => elements}/tri1/IsoparametricTriangleP1.h | 0 lib/mito/fem/{fem => elements}/tri1/ShapeTriangleP1.h | 0 lib/mito/fem/{fem => elements}/tri1/public.h | 0 lib/mito/fem/{fem => elements}/tri2/IsoparametricTriangleP2.h | 0 lib/mito/fem/{fem => elements}/tri2/ShapeTriangleP2.h | 0 lib/mito/fem/{fem => elements}/tri2/public.h | 0 lib/mito/fem/{fem => elements}/utilities.h | 0 lib/mito/fem/public.h | 2 +- 17 files changed, 2 insertions(+), 2 deletions(-) rename lib/mito/fem/{fem.h => elements.h} (84%) rename lib/mito/fem/{fem => elements}/IsoparametricTriangle.h (100%) rename lib/mito/fem/{fem => elements}/ReferenceTriangle.h (100%) rename lib/mito/fem/{fem => elements}/api.h (100%) rename lib/mito/fem/{fem => elements}/externals.h (100%) rename lib/mito/fem/{fem => elements}/factories.h (100%) rename lib/mito/fem/{fem => elements}/forward.h (100%) rename lib/mito/fem/{fem => elements}/isoparametric_simplex_library.h (100%) rename lib/mito/fem/{fem => elements}/public.h (100%) rename lib/mito/fem/{fem => elements}/tri1/IsoparametricTriangleP1.h (100%) rename lib/mito/fem/{fem => elements}/tri1/ShapeTriangleP1.h (100%) rename lib/mito/fem/{fem => elements}/tri1/public.h (100%) rename lib/mito/fem/{fem => elements}/tri2/IsoparametricTriangleP2.h (100%) rename lib/mito/fem/{fem => elements}/tri2/ShapeTriangleP2.h (100%) rename lib/mito/fem/{fem => elements}/tri2/public.h (100%) rename lib/mito/fem/{fem => elements}/utilities.h (100%) diff --git a/lib/mito/fem/fem.h b/lib/mito/fem/elements.h similarity index 84% rename from lib/mito/fem/fem.h rename to lib/mito/fem/elements.h index 3da96c16a..2992dad3d 100644 --- a/lib/mito/fem/fem.h +++ b/lib/mito/fem/elements.h @@ -8,7 +8,7 @@ // publish the interface -#include "fem/public.h" +#include "elements/public.h" // end of file diff --git a/lib/mito/fem/fem/IsoparametricTriangle.h b/lib/mito/fem/elements/IsoparametricTriangle.h similarity index 100% rename from lib/mito/fem/fem/IsoparametricTriangle.h rename to lib/mito/fem/elements/IsoparametricTriangle.h diff --git a/lib/mito/fem/fem/ReferenceTriangle.h b/lib/mito/fem/elements/ReferenceTriangle.h similarity index 100% rename from lib/mito/fem/fem/ReferenceTriangle.h rename to lib/mito/fem/elements/ReferenceTriangle.h diff --git a/lib/mito/fem/fem/api.h b/lib/mito/fem/elements/api.h similarity index 100% rename from lib/mito/fem/fem/api.h rename to lib/mito/fem/elements/api.h diff --git a/lib/mito/fem/fem/externals.h b/lib/mito/fem/elements/externals.h similarity index 100% rename from lib/mito/fem/fem/externals.h rename to lib/mito/fem/elements/externals.h diff --git a/lib/mito/fem/fem/factories.h b/lib/mito/fem/elements/factories.h similarity index 100% rename from lib/mito/fem/fem/factories.h rename to lib/mito/fem/elements/factories.h diff --git a/lib/mito/fem/fem/forward.h b/lib/mito/fem/elements/forward.h similarity index 100% rename from lib/mito/fem/fem/forward.h rename to lib/mito/fem/elements/forward.h diff --git a/lib/mito/fem/fem/isoparametric_simplex_library.h b/lib/mito/fem/elements/isoparametric_simplex_library.h similarity index 100% rename from lib/mito/fem/fem/isoparametric_simplex_library.h rename to lib/mito/fem/elements/isoparametric_simplex_library.h diff --git a/lib/mito/fem/fem/public.h b/lib/mito/fem/elements/public.h similarity index 100% rename from lib/mito/fem/fem/public.h rename to lib/mito/fem/elements/public.h diff --git a/lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h similarity index 100% rename from lib/mito/fem/fem/tri1/IsoparametricTriangleP1.h rename to lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h diff --git a/lib/mito/fem/fem/tri1/ShapeTriangleP1.h b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h similarity index 100% rename from lib/mito/fem/fem/tri1/ShapeTriangleP1.h rename to lib/mito/fem/elements/tri1/ShapeTriangleP1.h diff --git a/lib/mito/fem/fem/tri1/public.h b/lib/mito/fem/elements/tri1/public.h similarity index 100% rename from lib/mito/fem/fem/tri1/public.h rename to lib/mito/fem/elements/tri1/public.h diff --git a/lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h similarity index 100% rename from lib/mito/fem/fem/tri2/IsoparametricTriangleP2.h rename to lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h diff --git a/lib/mito/fem/fem/tri2/ShapeTriangleP2.h b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h similarity index 100% rename from lib/mito/fem/fem/tri2/ShapeTriangleP2.h rename to lib/mito/fem/elements/tri2/ShapeTriangleP2.h diff --git a/lib/mito/fem/fem/tri2/public.h b/lib/mito/fem/elements/tri2/public.h similarity index 100% rename from lib/mito/fem/fem/tri2/public.h rename to lib/mito/fem/elements/tri2/public.h diff --git a/lib/mito/fem/fem/utilities.h b/lib/mito/fem/elements/utilities.h similarity index 100% rename from lib/mito/fem/fem/utilities.h rename to lib/mito/fem/elements/utilities.h diff --git a/lib/mito/fem/public.h b/lib/mito/fem/public.h index 52e4f4377..56a94bbaa 100644 --- a/lib/mito/fem/public.h +++ b/lib/mito/fem/public.h @@ -24,7 +24,7 @@ #include "DiscreteSystem.h" // finite elements implementation -#include "fem.h" +#include "elements.h" // factories implementation #include "factories.h" From 0a8fd276e777a7273b90a221b0b10169ac1d50e3 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 08:11:08 +0200 Subject: [PATCH 212/273] geometry: add class {ReferenceSimplex} This class will eventually replace class {ReferenceTriangle} in the {fem} directory. --- lib/mito/geometry/ReferenceSimplex.h | 28 ++++++++++++++++++++++++++++ lib/mito/geometry/api.h | 13 +++++++++++++ lib/mito/geometry/forward.h | 4 ++++ lib/mito/geometry/public.h | 1 + 4 files changed, 46 insertions(+) create mode 100644 lib/mito/geometry/ReferenceSimplex.h diff --git a/lib/mito/geometry/ReferenceSimplex.h b/lib/mito/geometry/ReferenceSimplex.h new file mode 100644 index 000000000..be93cfa21 --- /dev/null +++ b/lib/mito/geometry/ReferenceSimplex.h @@ -0,0 +1,28 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::geometry { + + template + class ReferenceSimplex { + + public: + // the barycentric coordinates type + using barycentric_coordinates_type = geometry::coordinates_t; + + // the function extracting the I component of a parametric point + template + static constexpr auto xi = + fields::field(functions::component); + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/geometry/api.h b/lib/mito/geometry/api.h index f98027129..8bdbb8ec8 100644 --- a/lib/mito/geometry/api.h +++ b/lib/mito/geometry/api.h @@ -17,6 +17,10 @@ namespace mito::geometry { template using point_t = utilities::shared_ptr>; + // reference simplex alias + template + using reference_simplex_t = ReferenceSimplex; + // geometric simplex alias template using geometric_simplex_t = GeometricSimplex; @@ -25,6 +29,15 @@ namespace mito::geometry { template using node_t = utilities::std_shared_ptr>; + // reference segment alias + using reference_segment_t = reference_simplex_t<1>; + + // reference triangle alias + using reference_triangle_t = reference_simplex_t<2>; + + // reference tetrahedron alias + using reference_tetrahedron_t = reference_simplex_t<3>; + // segment alias template requires(D > 0) diff --git a/lib/mito/geometry/forward.h b/lib/mito/geometry/forward.h index be6ef700d..9b0bfdb5b 100644 --- a/lib/mito/geometry/forward.h +++ b/lib/mito/geometry/forward.h @@ -29,6 +29,10 @@ namespace mito::geometry { template class Point; + // reference simplex + template + class ReferenceSimplex; + // class geometric simplex template requires((N >= 0) && (N <= D) && (D > 0)) diff --git a/lib/mito/geometry/public.h b/lib/mito/geometry/public.h index d72d534b8..ea5f547bd 100644 --- a/lib/mito/geometry/public.h +++ b/lib/mito/geometry/public.h @@ -33,6 +33,7 @@ // classes implementation #include "CoordinateSystem.h" #include "Point.h" +#include "ReferenceSimplex.h" #include "GeometricSimplex.h" #include "PointCloud.h" From 8741cb83936aac1d432f5323a7a059429ba6c552 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 17:49:36 +0200 Subject: [PATCH 213/273] quadrature: quadrature rules are now defined on the {ReferenceSimplex} as opposed to topological simplices --- lib/mito/geometry/GeometricSimplex.h | 6 ++++-- lib/mito/geometry/ReferenceSimplex.h | 2 +- lib/mito/quadrature/Integrator.h | 3 ++- lib/mito/quadrature/QuadratureTable.h | 5 ++--- lib/mito/quadrature/externals.h | 3 ++- .../quadrature/quadrature_tables_segments.icc | 8 ++++---- .../quadrature/quadrature_tables_tetrahedra.icc | 8 ++++---- .../quadrature/quadrature_tables_triangles.icc | 16 ++++++++-------- .../discretization/isoparametric_triangle.cc | 4 +++- tests/mito.lib/discretization/poisson.cc | 6 +++--- .../quadrature/quadrature_parametric_segment.cc | 11 ++++++++--- .../quadrature_parametric_tetrahedron.cc | 14 ++++++++++---- .../quadrature/quadrature_parametric_triangle.cc | 14 ++++++++++---- 13 files changed, 61 insertions(+), 39 deletions(-) diff --git a/lib/mito/geometry/GeometricSimplex.h b/lib/mito/geometry/GeometricSimplex.h index 42e73c0d3..feaa64803 100644 --- a/lib/mito/geometry/GeometricSimplex.h +++ b/lib/mito/geometry/GeometricSimplex.h @@ -54,9 +54,11 @@ namespace mito::geometry { template using cell_topological_family_type = typename topology::cell_family; + // the reference simplex type + using reference_simplex_type = reference_simplex_t; + // type of a point in barycentric coordinates - using barycentric_coordinates_type = - typename simplex_type::resource_type::barycentric_coordinates_type; + using barycentric_coordinates_type = reference_simplex_type::barycentric_coordinates_type; private: constexpr auto _sanity_check() const -> bool diff --git a/lib/mito/geometry/ReferenceSimplex.h b/lib/mito/geometry/ReferenceSimplex.h index be93cfa21..8c6d368da 100644 --- a/lib/mito/geometry/ReferenceSimplex.h +++ b/lib/mito/geometry/ReferenceSimplex.h @@ -14,7 +14,7 @@ namespace mito::geometry { public: // the barycentric coordinates type - using barycentric_coordinates_type = geometry::coordinates_t; + using barycentric_coordinates_type = geometry::coordinates_t; // the function extracting the I component of a parametric point template diff --git a/lib/mito/quadrature/Integrator.h b/lib/mito/quadrature/Integrator.h index 519eb126b..750184c1b 100644 --- a/lib/mito/quadrature/Integrator.h +++ b/lib/mito/quadrature/Integrator.h @@ -18,11 +18,12 @@ namespace mito::quadrature { // publish my template parameters using manifold_type = manifoldT; using cell_type = typename manifold_type::cell_type::simplex_type; + using reference_cell_type = typename manifold_type::cell_type::reference_simplex_type; using coordinates_type = typename manifold_type::coordinates_type; private: // quadrature_type, cell_type, and r identify a specific quadrature rule - using quadrature_rule_type = quadrature_rule_t; + using quadrature_rule_type = quadrature_rule_t; // the quadrature rule static constexpr auto _quadratureRule = quadrature_rule_type(); // the number of quadrature points diff --git a/lib/mito/quadrature/QuadratureTable.h b/lib/mito/quadrature/QuadratureTable.h index aca86bd0b..3ea02934b 100644 --- a/lib/mito/quadrature/QuadratureTable.h +++ b/lib/mito/quadrature/QuadratureTable.h @@ -14,9 +14,8 @@ namespace mito::quadrature { class Table { public: - // the type of quadrature points' parametric coordinates - using quadrature_point_type = - typename elementT::resource_type::barycentric_coordinates_type; + // the type of quadrature points' barycentric coordinates + using quadrature_point_type = typename elementT::barycentric_coordinates_type; // the type of quadrature weights using quadrature_weight_type = double; // the type of quadrature point-weight pairing diff --git a/lib/mito/quadrature/externals.h b/lib/mito/quadrature/externals.h index 9ff5cfce4..04b3f0f1c 100644 --- a/lib/mito/quadrature/externals.h +++ b/lib/mito/quadrature/externals.h @@ -13,7 +13,8 @@ #include "../journal.h" #include "../manifolds.h" #include "../math.h" -#include "../fem.h" +#include "../discrete.h" +#include "../geometry.h" // end of file diff --git a/lib/mito/quadrature/quadrature_tables_segments.icc b/lib/mito/quadrature/quadrature_tables_segments.icc index 399beb44d..5f088ad07 100644 --- a/lib/mito/quadrature/quadrature_tables_segments.icc +++ b/lib/mito/quadrature/quadrature_tables_segments.icc @@ -10,10 +10,10 @@ namespace mito::quadrature { template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 1; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; return table_type({ /*{point}, weight*/ @@ -21,10 +21,10 @@ namespace mito::quadrature { } template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 2; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; constexpr auto a = 0.788675134594813; diff --git a/lib/mito/quadrature/quadrature_tables_tetrahedra.icc b/lib/mito/quadrature/quadrature_tables_tetrahedra.icc index 6e12b2f18..a68fed80d 100644 --- a/lib/mito/quadrature/quadrature_tables_tetrahedra.icc +++ b/lib/mito/quadrature/quadrature_tables_tetrahedra.icc @@ -10,10 +10,10 @@ namespace mito::quadrature { template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 1; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; /*Hammer rule*/ @@ -23,10 +23,10 @@ namespace mito::quadrature { } template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 4; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; constexpr auto a = 0.5854101966249685; diff --git a/lib/mito/quadrature/quadrature_tables_triangles.icc b/lib/mito/quadrature/quadrature_tables_triangles.icc index 9272be380..19aab255e 100644 --- a/lib/mito/quadrature/quadrature_tables_triangles.icc +++ b/lib/mito/quadrature/quadrature_tables_triangles.icc @@ -10,10 +10,10 @@ namespace mito::quadrature { template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 1; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; return table_type({ /*{point}, weight*/ @@ -21,10 +21,10 @@ namespace mito::quadrature { } template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 3; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; return table_type( @@ -35,10 +35,10 @@ namespace mito::quadrature { } template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 6; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; constexpr auto a = 0.16288285039589191090016180418490635; @@ -57,10 +57,10 @@ namespace mito::quadrature { // Dunavant's Rule #4, Hammer–Stroud-type rule template <> - constexpr auto QuadratureTable() -> auto + constexpr auto QuadratureTable() -> auto { constexpr int Q = 6; - using table_type = Table; + using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; constexpr auto a = 0.816847572980458513080857; diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/discretization/isoparametric_triangle.cc index d41826221..7b9cf7dc5 100644 --- a/tests/mito.lib/discretization/isoparametric_triangle.cc +++ b/tests/mito.lib/discretization/isoparametric_triangle.cc @@ -15,9 +15,11 @@ using coord_system_t = mito::geometry::coordinate_system_t; using discretization_node_t = mito::discrete::discretization_node_t; // the type of cell using cell_t = mito::geometry::triangle_t<2>; +// the reference simplex +using reference_simplex_t = mito::geometry::reference_triangle_t; // Gauss quadrature on triangles with degree of exactness 4 using quadrature_rule_t = - mito::quadrature::quadrature_rule_t; + mito::quadrature::quadrature_rule_t; // the equation map type (map associating an equation number to each node degree of freedom) using equation_map_type = std::map; diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/discretization/poisson.cc index 8c16856a4..021fce5db 100644 --- a/tests/mito.lib/discretization/poisson.cc +++ b/tests/mito.lib/discretization/poisson.cc @@ -13,11 +13,11 @@ using scalar_t = mito::tensor::scalar_t; using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; // the type of cell using cell_t = mito::geometry::triangle_t<2>; -// the type of simplex -using simplex_t = cell_t::simplex_type; +// the reference simplex +using reference_simplex_t = mito::geometry::reference_triangle_t; // Gauss quadrature on triangles with degree of exactness 2 using quadrature_rule_t = - mito::quadrature::quadrature_rule_t; + mito::quadrature::quadrature_rule_t; // the degree of the finite element constexpr int degree = 2; diff --git a/tests/mito.lib/quadrature/quadrature_parametric_segment.cc b/tests/mito.lib/quadrature/quadrature_parametric_segment.cc index dd14ca2fe..50b468953 100644 --- a/tests/mito.lib/quadrature/quadrature_parametric_segment.cc +++ b/tests/mito.lib/quadrature/quadrature_parametric_segment.cc @@ -4,15 +4,20 @@ // #include -#include #include +// the type of quadrature +using mito::quadrature::GAUSS; +// the reference segment type +using reference_segment_t = mito::geometry::reference_segment_t; + + TEST(ParametricSegment, Order1) { // a Gauss quadrature rule on segments with degree of exactness 1 constexpr auto quadrature_rule = - mito::quadrature::quadrature_rule(); + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; @@ -36,7 +41,7 @@ TEST(ParametricSegment, Order2) { // a Gauss quadrature rule on segments with degree of exactness 2 constexpr auto quadrature_rule = - mito::quadrature::quadrature_rule(); + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; diff --git a/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc b/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc index 99420a13e..c91dd2a32 100644 --- a/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc +++ b/tests/mito.lib/quadrature/quadrature_parametric_tetrahedron.cc @@ -8,11 +8,17 @@ #include +// the type of quadrature +using mito::quadrature::GAUSS; +// the reference tetrahedron type +using reference_tetrahedron_t = mito::geometry::reference_tetrahedron_t; + + TEST(ParametricTetrahedron, Order1) { // a Gauss quadrature rule on tetrahedrons with degree of exactness 1 - constexpr auto quadrature_rule = mito::quadrature::quadrature_rule< - mito::quadrature::GAUSS, mito::topology::tetrahedron_t, 1>(); + constexpr auto quadrature_rule = + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; @@ -38,8 +44,8 @@ TEST(ParametricTetrahedron, Order1) TEST(ParametricTetrahedron, Order2) { // a Gauss quadrature rule on tetrahedrons with degree of exactness 2 - constexpr auto quadrature_rule = mito::quadrature::quadrature_rule< - mito::quadrature::GAUSS, mito::topology::tetrahedron_t, 2>(); + constexpr auto quadrature_rule = + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; diff --git a/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc b/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc index 3d7d76e59..ce2f9e0a7 100644 --- a/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc +++ b/tests/mito.lib/quadrature/quadrature_parametric_triangle.cc @@ -8,11 +8,17 @@ #include +// the type of quadrature +using mito::quadrature::GAUSS; +// the reference triangle type +using reference_triangle_t = mito::geometry::reference_triangle_t; + + TEST(ParametricTriangle, Order1) { // a Gauss quadrature rule on triangles with degree of exactness 1 constexpr auto quadrature_rule = - mito::quadrature::quadrature_rule(); + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; @@ -39,7 +45,7 @@ TEST(ParametricTriangle, Order2) { // a Gauss quadrature rule on triangles with degree of exactness 2 constexpr auto quadrature_rule = - mito::quadrature::quadrature_rule(); + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; @@ -69,7 +75,7 @@ TEST(ParametricTriangle, Order3) { // a Gauss quadrature rule on triangles with degree of exactness 3 constexpr auto quadrature_rule = - mito::quadrature::quadrature_rule(); + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; @@ -102,7 +108,7 @@ TEST(ParametricTriangle, Order4) { // a Gauss quadrature rule on triangles with degree of exactness 4 constexpr auto quadrature_rule = - mito::quadrature::quadrature_rule(); + mito::quadrature::quadrature_rule(); // the parametric point type using point_t = decltype(quadrature_rule)::quadrature_point_type; From 5c8c95df685b984cdc9171dedc76a3772059c64f Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 6 Sep 2025 18:05:10 +0200 Subject: [PATCH 214/273] tests: rename {discretization} test directory to {fem} Consistently with rev. 0b7b410. --- .cmake/mito_tests_mito_lib.cmake | 12 ++++++------ .../isoparametric_triangle.cc | 0 tests/mito.lib/{discretization => fem}/poisson.cc | 0 .../shape_functions_triangle_construction.cc | 0 .../shape_functions_triangle_p1.cc | 0 .../shape_functions_triangle_p2.cc | 0 .../{discretization => fem}/verification_p1.py | 0 .../{discretization => fem}/verification_p2.py | 0 8 files changed, 6 insertions(+), 6 deletions(-) rename tests/mito.lib/{discretization => fem}/isoparametric_triangle.cc (100%) rename tests/mito.lib/{discretization => fem}/poisson.cc (100%) rename tests/mito.lib/{discretization => fem}/shape_functions_triangle_construction.cc (100%) rename tests/mito.lib/{discretization => fem}/shape_functions_triangle_p1.cc (100%) rename tests/mito.lib/{discretization => fem}/shape_functions_triangle_p2.cc (100%) rename tests/mito.lib/{discretization => fem}/verification_p1.py (100%) rename tests/mito.lib/{discretization => fem}/verification_p2.py (100%) diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index c27aea621..3ae452d90 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -44,12 +44,12 @@ mito_test_driver(tests/mito.lib/constraints/dirichlet.cc) mito_test_driver(tests/mito.lib/discrete/quadrature_field.cc) mito_test_driver(tests/mito.lib/discrete/mesh_field.cc) -# discretization -mito_test_driver(tests/mito.lib/discretization/poisson.cc) -mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_construction.cc) -mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p1.cc) -mito_test_driver(tests/mito.lib/discretization/shape_functions_triangle_p2.cc) -mito_test_driver(tests/mito.lib/discretization/isoparametric_triangle.cc) +# fem +mito_test_driver(tests/mito.lib/fem/poisson.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) # io mito_test_driver(tests/mito.lib/io/summit_mesh_reader_2D.cc) diff --git a/tests/mito.lib/discretization/isoparametric_triangle.cc b/tests/mito.lib/fem/isoparametric_triangle.cc similarity index 100% rename from tests/mito.lib/discretization/isoparametric_triangle.cc rename to tests/mito.lib/fem/isoparametric_triangle.cc diff --git a/tests/mito.lib/discretization/poisson.cc b/tests/mito.lib/fem/poisson.cc similarity index 100% rename from tests/mito.lib/discretization/poisson.cc rename to tests/mito.lib/fem/poisson.cc diff --git a/tests/mito.lib/discretization/shape_functions_triangle_construction.cc b/tests/mito.lib/fem/shape_functions_triangle_construction.cc similarity index 100% rename from tests/mito.lib/discretization/shape_functions_triangle_construction.cc rename to tests/mito.lib/fem/shape_functions_triangle_construction.cc diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p1.cc b/tests/mito.lib/fem/shape_functions_triangle_p1.cc similarity index 100% rename from tests/mito.lib/discretization/shape_functions_triangle_p1.cc rename to tests/mito.lib/fem/shape_functions_triangle_p1.cc diff --git a/tests/mito.lib/discretization/shape_functions_triangle_p2.cc b/tests/mito.lib/fem/shape_functions_triangle_p2.cc similarity index 100% rename from tests/mito.lib/discretization/shape_functions_triangle_p2.cc rename to tests/mito.lib/fem/shape_functions_triangle_p2.cc diff --git a/tests/mito.lib/discretization/verification_p1.py b/tests/mito.lib/fem/verification_p1.py similarity index 100% rename from tests/mito.lib/discretization/verification_p1.py rename to tests/mito.lib/fem/verification_p1.py diff --git a/tests/mito.lib/discretization/verification_p2.py b/tests/mito.lib/fem/verification_p2.py similarity index 100% rename from tests/mito.lib/discretization/verification_p2.py rename to tests/mito.lib/fem/verification_p2.py From 55b67179f3d42b6366b83748e17c6d491544497e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 7 Sep 2025 19:56:17 +0200 Subject: [PATCH 215/273] functions: generalize class {Sum} to the sum of an arbitrary number of functions --- lib/mito/functions/algebra.h | 2 +- lib/mito/functions/api.h | 4 ++++ lib/mito/functions/derivation_rules.h | 7 ++++--- lib/mito/functions/factories.h | 7 +++++++ lib/mito/functions/function.h | 26 ++++++++++++++------------ lib/mito/functions/traits.h | 15 +++++++++------ 6 files changed, 39 insertions(+), 22 deletions(-) diff --git a/lib/mito/functions/algebra.h b/lib/mito/functions/algebra.h index b464aa3be..05945b11b 100644 --- a/lib/mito/functions/algebra.h +++ b/lib/mito/functions/algebra.h @@ -15,7 +15,7 @@ namespace mito::functions { // f1 + f2 constexpr auto operator+(const function_c auto & f1, const function_c auto & f2) { - return Sum(f1, f2); + return Summation(f1, f2); } // a + f diff --git a/lib/mito/functions/api.h b/lib/mito/functions/api.h index cd0bdcb16..bb0162b8d 100644 --- a/lib/mito/functions/api.h +++ b/lib/mito/functions/api.h @@ -74,6 +74,10 @@ namespace mito::functions { // the linear combination template constexpr auto linear_combination(std::array coeffs, Funcs... funcs); + + // returns the summation of functions + template + constexpr auto summation(Funcs... funcs); } diff --git a/lib/mito/functions/derivation_rules.h b/lib/mito/functions/derivation_rules.h index fa76cae65..eee2e8025 100644 --- a/lib/mito/functions/derivation_rules.h +++ b/lib/mito/functions/derivation_rules.h @@ -20,10 +20,11 @@ namespace mito::functions { } // the I-th first partial derivative of a function sum - template - constexpr auto derivative(const Sum & f) + template + constexpr auto derivative(const Summation & f) { - return derivative(f.f1()) + derivative(f.f2()); + return std::apply( + [&](const auto &... funcs) { return (derivative(funcs) + ...); }, f.functions()); } // the I-th first partial derivative of a constant plus a function diff --git a/lib/mito/functions/factories.h b/lib/mito/functions/factories.h index 7eca0ce0f..c17c358f7 100644 --- a/lib/mito/functions/factories.h +++ b/lib/mito/functions/factories.h @@ -23,6 +23,13 @@ namespace mito::functions { return FunctionFromFunctor(std::forward(f)); } + // returns the summation of functions + template + constexpr auto summation(Funcs... funcs) + { + return Summation(std::forward(funcs)...); + } + // returns the linear combination template constexpr auto linear_combination(std::array coeffs, Funcs... funcs) diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index eaaf5652c..ebfe6bfe7 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -115,19 +115,23 @@ namespace mito::functions { // the sum of two functions - template - class Sum : public function_sum::type { + template + class Summation : public function_sum::type { public: // the type of sum function (what I derive from) - using function_type = function_sum::type; + using function_type = function_sum::type; // the input type of the sum using input_type = function_type::input_type; // the output type of the sum using output_type = function_type::output_type; + private: + // the type of functions + using functions_type = std::tuple; + public: // constructor - constexpr Sum(const F & f, const G & g) : _f(f), _g(g) {} + constexpr Summation(Funcs... funcs) : _funcs(funcs...) {} // call operator for function composition template @@ -153,18 +157,16 @@ namespace mito::functions { // call operator constexpr auto operator()(const input_type & x) const -> output_type { - return _f(x) + _g(x); + // the sum of all functions + return std::apply([&](const auto &... funcs) { return (funcs(x) + ...); }, _funcs); } - // the first in the sum - constexpr auto f1() const -> const F & { return _f; } - - // the second in the sum - constexpr auto f2() const -> const G & { return _g; } + // accessor for the functions in the summation + constexpr auto functions() const -> const functions_type & { return _funcs; } private: - const F _f; - const G _g; + // the functions in the summation + functions_type _funcs; }; // the linear combination of functions {Funcs} with coefficients of type {T}... diff --git a/lib/mito/functions/traits.h b/lib/mito/functions/traits.h index d78d81137..b8a88121c 100644 --- a/lib/mito/functions/traits.h +++ b/lib/mito/functions/traits.h @@ -34,14 +34,17 @@ namespace mito::functions { using sum_result_t = typename sum_result::type; // the type of the sum of two functions... - template + template // ... which take the same input type {input_type}... - requires(std::is_same_v) + requires(same_input_c) struct function_sum { - // ... is the function that takes {input_type} in input and returns the type of the sum of - // the output types - using type = Function< - typename F::input_type, sum_result_t>; + // the common input type + using input_type = typename std::tuple_element<0, std::tuple>::type::input_type; + // the type of the sum of the outputs + using output_type = sum_result_t; + // ... is the function that takes {input_type} in input and + // returns the type of the sum of the output types + using type = Function; }; // the type of the product of two functions... From 81304f1973848b79a0a9f4ebb6530ec9debb7856 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 7 Sep 2025 20:17:47 +0200 Subject: [PATCH 216/273] functions: add class {DyadicProduct} --- lib/mito/functions/algebra.h | 7 ++++ lib/mito/functions/function.h | 54 +++++++++++++++++++++++++++++ lib/mito/functions/traits.h | 25 +++++++++++++ tests/mito.lib/functions/algebra.cc | 15 ++++++++ 4 files changed, 101 insertions(+) diff --git a/lib/mito/functions/algebra.h b/lib/mito/functions/algebra.h index 05945b11b..2bc6c72ab 100644 --- a/lib/mito/functions/algebra.h +++ b/lib/mito/functions/algebra.h @@ -102,6 +102,13 @@ namespace mito::functions { { return Inverse(f); } + + // dyadic product of vector-valued functions f and g + constexpr auto dyadic( + const vector_valued_function_c auto & f, const vector_valued_function_c auto & g) + { + return DyadicProduct(f, g); + } } diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index ebfe6bfe7..5a566087b 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -686,6 +686,60 @@ namespace mito::functions { private: const F _f; }; + + // function computing the dyadic of two vector valued functions + template + class DyadicProduct : public function_dyadic_product::type { + + public: + // the type of the function (what I derive from) + using function_type = function_dyadic_product::type; + // the input type + using input_type = function_type::input_type; + // the output type + using output_type = function_type::output_type; + + public: + // constructor + constexpr DyadicProduct(const F1 & f1, const F2 & f2) : _f1(f1), _f2(f2) {} + + // call operator for function composition + template + constexpr auto operator()(const H & f) const + { + return Composition(*this, f); + } + + // subscript operator: only available if {output_type} is subscriptable + constexpr auto operator[](int i) const + requires subscriptable_c + { + return Subscript(*this, i); + } + + // subscript operator with multi-index: only available if {output_type} is a tensor + template + constexpr auto operator[](const typename outputT::index_t & i) const + { + return Subscript(*this, i); + } + + // call operator + constexpr auto operator()(const input_type & x) const -> output_type + { + return tensor::dyadic(_f1(x), _f2(x)); + } + + // the first function in the dyadic product + constexpr auto f1() const -> const F1 & { return _f1; } + + // the second function in the dyadic product + constexpr auto f2() const -> const F2 & { return _f2; } + + private: + const F1 _f1; + const F2 _f2; + }; } diff --git a/lib/mito/functions/traits.h b/lib/mito/functions/traits.h index b8a88121c..4629f7e4a 100644 --- a/lib/mito/functions/traits.h +++ b/lib/mito/functions/traits.h @@ -124,6 +124,31 @@ namespace mito::functions { // the output types multiplied by the coefficients using type = Function; }; + + // the type of the dyadic product of two vector-valued functions... + template + requires( + // ... which take the same input type {input_type}... + std::is_same_v + // ... and return vectors of same size ... + && F::output_type::size == G::output_type::size) + struct function_dyadic_product { + // the common input type + using input_type = typename F::input_type; + // the scalar type of the output of the first function + using scalar_type_1 = typename F::output_type::scalar_type; + // the scalar type of the output of the second function + using scalar_type_2 = typename G::output_type::scalar_type; + // the dimension of the two vectors in output + static constexpr int output_dimension = F::output_type::size; + // the type of the sum of the outputs + using output_type = tensor::matrix_t< + F::output_type::size, F::output_type::size, + product_result_t>; + // ... is the function that takes {input_type} in input and returns the type of the dyadic + // product of the output types + using type = Function; + }; } diff --git a/tests/mito.lib/functions/algebra.cc b/tests/mito.lib/functions/algebra.cc index 8416a0ae1..07f75a95a 100644 --- a/tests/mito.lib/functions/algebra.cc +++ b/tests/mito.lib/functions/algebra.cc @@ -138,4 +138,19 @@ TEST(Algebra, ScalarProduct) // check result static_assert(0.1 == (x0 * x1)(x)); +} + + +TEST(Algebra, DyadicProduct) +{ + // a 2D vector + constexpr auto x = mito::tensor::vector_t<2>{ 0.1, 1.0 }; + + // the function returning the constant e0 unit vector in 2D + constexpr auto e0 = mito::functions::constant>(mito::tensor::e_0<2>); + + // check result + static_assert( + mito::tensor::dyadic(mito::tensor::e_0<2>, mito::tensor::e_0<2>) + == mito::functions::dyadic(e0, e0)(x)); } \ No newline at end of file From 7967076d4bb3ea1a352337bd7b84ed6eb6bf48ae Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 8 Sep 2025 13:42:18 +0200 Subject: [PATCH 217/273] fem: shape functions are now defined on the same reference simplex as quadrature rules This implies that shape functions are now functions of barycentric coordinates. No 'wrapping' at the level of isoparametric simplices is needed any longer to 'map' shape functions from parametric to barycentric coordinates. --- lib/mito/fem/elements/ReferenceTriangle.h | 31 --------- lib/mito/fem/elements/public.h | 1 - .../elements/tri1/IsoparametricTriangleP1.h | 63 +++++-------------- lib/mito/fem/elements/tri1/ShapeTriangleP1.h | 21 ++++--- .../elements/tri2/IsoparametricTriangleP2.h | 63 +++++-------------- lib/mito/fem/elements/tri2/ShapeTriangleP2.h | 20 +++--- lib/mito/geometry/ReferenceSimplex.h | 5 +- .../fem/shape_functions_triangle_p1.cc | 10 +-- .../fem/shape_functions_triangle_p2.cc | 28 ++++----- 9 files changed, 77 insertions(+), 165 deletions(-) delete mode 100644 lib/mito/fem/elements/ReferenceTriangle.h diff --git a/lib/mito/fem/elements/ReferenceTriangle.h b/lib/mito/fem/elements/ReferenceTriangle.h deleted file mode 100644 index 74c54747e..000000000 --- a/lib/mito/fem/elements/ReferenceTriangle.h +++ /dev/null @@ -1,31 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - -// code guard -#pragma once - - -namespace mito::fem { - - class ReferenceTriangle { - - public: - // the parametric coordinates type - using parametric_coordinates_type = geometry::coordinates_t<2, geometry::CARTESIAN>; - - // the function extracting the 0 component of a parametric point - static constexpr auto xi_0 = - fields::field(functions::component); - // the function extracting the 1 component of a parametric point - static constexpr auto xi_1 = - fields::field(functions::component); - // the function extracting the 2 component of a parametric point - static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; - }; - -} // namespace mito - - -// end of file diff --git a/lib/mito/fem/elements/public.h b/lib/mito/fem/elements/public.h index bcf3626ea..4de40cab4 100644 --- a/lib/mito/fem/elements/public.h +++ b/lib/mito/fem/elements/public.h @@ -17,7 +17,6 @@ #include "api.h" // classes implementation -#include "ReferenceTriangle.h" #include "IsoparametricTriangle.h" #include "isoparametric_simplex_library.h" diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index 157000d0e..8b8b837a2 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -21,6 +21,9 @@ namespace mito::fem { static constexpr int degree = 1; // the type of shape functions using shape_functions_type = ShapeTriangleP1; + // the barycentric coordinates type + using barycentric_coordinates_type = + typename shape_functions_type::barycentric_coordinates_type; // the linear shape functions static constexpr auto shape_functions = shape_functions_type(); // the number of discretization discretization nodes @@ -52,19 +55,6 @@ namespace mito::fem { // delete move assignment operator constexpr IsoparametricTriangleP1 & operator=(IsoparametricTriangleP1 &&) noexcept = delete; - private: - // the isoparametric mapping from barycentric coordinates to physical coordinates - constexpr auto _x_cell() const - { - // get the shape functions - constexpr auto phi_0 = shape_functions.shape<0>(); - constexpr auto phi_1 = shape_functions.shape<1>(); - constexpr auto phi_2 = shape_functions.shape<2>(); - - // return the isoparametric mapping from barycentric to physical coordinates - return _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2; - } - public: // get the discretization nodes constexpr auto connectivity() const noexcept -> const connectivity_type & @@ -75,15 +65,14 @@ namespace mito::fem { // get the isoparametric mapping from barycentric coordinates to physical coordinates constexpr auto parametrization() const { - // assemble the physical coordinates from the barycentric coordinates - auto x_cell = functions::function( - [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { - // compute the gradient of the isoparametric mapping - return _x_cell()({ xi[0], xi[1] }); - }); + // get the shape functions + constexpr auto phi_0 = shape_functions.shape<0>(); + constexpr auto phi_1 = shape_functions.shape<1>(); + constexpr auto phi_2 = shape_functions.shape<2>(); - // and return it - return x_cell; + // return the isoparametric mapping from parametric to physical coordinates + return mito::functions::linear_combination( + std::array{ _x0, _x1, _x2 }, phi_0, phi_1, phi_2); } // get the shape function associated with local node {a} @@ -91,16 +80,8 @@ namespace mito::fem { requires(a >= 0 && a < n_nodes) constexpr auto shape() const { - // assemble the shape function associated with local node {a} as a function of - // barycentric coordinates - constexpr auto shape_function = functions::function( - [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { - // return the a-th shape function evaluated at {xi} - return shape_functions.shape()({ xi[0], xi[1] }); - }); - - // and return it - return shape_function; + // return the shape functions + return shape_functions.shape(); } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -116,9 +97,8 @@ namespace mito::fem { // compute the gradient of the isoparametric mapping return ( - tensor::dyadic(_x0, dphi_0({ xi[0], xi[1] })) - + tensor::dyadic(_x1, dphi_1({ xi[0], xi[1] })) - + tensor::dyadic(_x2, dphi_2({ xi[0], xi[1] }))); + tensor::dyadic(_x0, dphi_0(xi)) + tensor::dyadic(_x1, dphi_1(xi)) + + tensor::dyadic(_x2, dphi_2(xi))); }); // and return it @@ -130,19 +110,8 @@ namespace mito::fem { requires(a >= 0 && a < n_nodes) constexpr auto gradient() const { - // assemble the gradient as a function of barycentric coordinates - auto gradient_function = functions::function( - [&](const barycentric_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 barycentric coordinates - auto J_inv = tensor::inverse(J); - // return the spatial gradients of the shape functions evaluated at {xi} - return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; - }); - // and return it - return gradient_function; + // return the (physical) gradient of the a-th shape function + return shape_functions.dshape() * functions::inverse(jacobian()); } private: diff --git a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h index 9753a4374..4b98fa978 100644 --- a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h +++ b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h @@ -13,15 +13,18 @@ namespace mito::fem { public: // the reference element - using reference_element_type = ReferenceTriangle; + using reference_element_type = geometry::reference_triangle_t; + // the barycentric coordinates type + using barycentric_coordinates_type = + typename reference_element_type::barycentric_coordinates_type; // the number of shape functions static constexpr int N = 3; private: - // get the parametric coordinates from the reference element - static constexpr auto xi_0 = reference_element_type::xi_0; - static constexpr auto xi_1 = reference_element_type::xi_1; - static constexpr auto xi_2 = reference_element_type::xi_2; + // linear shape functions on the reference triangle in barycentric coordinates + static constexpr auto xi_0 = reference_element_type::xi<0>; + static constexpr auto xi_1 = reference_element_type::xi<1>; + static constexpr auto xi_2 = reference_element_type::xi<2>; // linear shape functions on the triangle static constexpr auto phi_0 = xi_0; @@ -33,10 +36,12 @@ namespace mito::fem { // the gradients of the shape functions static constexpr auto dphi = std::make_tuple( - fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2)); + functions::constant(tensor::e_0<2>), + functions::constant(tensor::e_1<2>), + functions::constant(-tensor::e_0<2> - tensor::e_1<2>)); public: - // get the a-th shape function + // get the a-th shape function as a function of barycentric coordinates template requires(a >= 0 && a < N) constexpr auto shape() const @@ -45,7 +50,7 @@ namespace mito::fem { return std::get(phi); } - // get the a-th shape function's gradient + // get the a-th shape function's derivative as a function of barycentric coordinates template requires(a >= 0 && a < N) constexpr auto dshape() const diff --git a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h index 8cd54dcb5..59040d696 100644 --- a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h @@ -21,6 +21,9 @@ namespace mito::fem { static constexpr int degree = 2; // the type of shape functions using shape_functions_type = ShapeTriangleP2; + // type of a point in barycentric coordinates + using barycentric_coordinates_type = + typename shape_functions_type::reference_element_type::barycentric_coordinates_type; // the linear shape functions static constexpr auto shape_functions = shape_functions_type(); // the number of discretization nodes @@ -52,9 +55,9 @@ namespace mito::fem { // delete move assignment operator constexpr IsoparametricTriangleP2 & operator=(IsoparametricTriangleP2 &&) noexcept = delete; - private: - // the isoparametric mapping from barycentric coordinates to physical coordinates - constexpr auto _x_cell() const + public: + // get the isoparametric mapping from barycentric coordinates to physical coordinates + constexpr auto parametrization() const { auto x3 = 0.5 * (_x0 + _x1); auto x4 = 0.5 * (_x1 + _x2); @@ -69,45 +72,23 @@ namespace mito::fem { constexpr auto phi_5 = shape_functions.shape<5>(); // return the isoparametric mapping from barycentric to physical coordinates - return _x0 * phi_0 + _x1 * phi_1 + _x2 * phi_2 + x3 * phi_3 + x4 * phi_4 + x5 * phi_5; + return mito::functions::linear_combination( + std::array{ _x0, _x1, _x2, x3, x4, x5 }, phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); } - public: // get the discretization nodes constexpr auto connectivity() const noexcept -> const connectivity_type & { return _connectivity; } - // get the isoparametric mapping from barycentric coordinates to physical coordinates - constexpr auto parametrization() const - { - // assemble the physical coordinates from the barycentric coordinates - auto x_cell = functions::function( - [&](const barycentric_coordinates_type & xi) -> tensor::vector_t<2> { - // compute the gradient of the isoparametric mapping - return _x_cell()({ xi[0], xi[1] }); - }); - - // and return it - return x_cell; - } - // get the shape function associated with local node {a} template requires(a >= 0 && a < n_nodes) constexpr auto shape() const { - // assemble the shape function associated with local node {a} as a function of - // barycentric coordinates - constexpr auto shape_function = functions::function( - [](const barycentric_coordinates_type & xi) -> tensor::scalar_t { - // return the a-th shape function evaluated at {xi} - return shape_functions.shape()({ xi[0], xi[1] }); - }); - - // and return it - return shape_function; + // return the shape functions + return shape_functions.shape(); } // get the jacobian of the isoparametric mapping from barycentric to actual coordinates @@ -130,12 +111,9 @@ namespace mito::fem { // compute the gradient of the isoparametric mapping return ( - tensor::dyadic(_x0, dphi_0({ xi[0], xi[1] })) - + tensor::dyadic(_x1, dphi_1({ xi[0], xi[1] })) - + tensor::dyadic(_x2, dphi_2({ xi[0], xi[1] })) - + tensor::dyadic(x3, dphi_3({ xi[0], xi[1] })) - + tensor::dyadic(x4, dphi_4({ xi[0], xi[1] })) - + tensor::dyadic(x5, dphi_5({ xi[0], xi[1] }))); + tensor::dyadic(_x0, dphi_0(xi)) + tensor::dyadic(_x1, dphi_1(xi)) + + tensor::dyadic(_x2, dphi_2(xi)) + tensor::dyadic(x3, dphi_3(xi)) + + tensor::dyadic(x4, dphi_4(xi)) + tensor::dyadic(x5, dphi_5(xi))); }); // and return it @@ -147,19 +125,8 @@ namespace mito::fem { requires(a >= 0 && a < n_nodes) constexpr auto gradient() const { - // assemble the gradient as a function of barycentric coordinates - auto gradient_function = functions::function( - [&](const barycentric_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 barycentric coordinates - auto J_inv = tensor::inverse(J); - // return the spatial gradients of the shape functions evaluated at {xi} - return shape_functions.dshape()({ xi[0], xi[1] }) * J_inv; - }); - // and return it - return gradient_function; + // return the (physical) gradient of the a-th shape function + return shape_functions.dshape() * functions::inverse(jacobian()); } private: diff --git a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h index 563181684..546f82832 100644 --- a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h +++ b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h @@ -13,15 +13,15 @@ namespace mito::fem { public: // the reference element - using reference_element_type = ReferenceTriangle; + using reference_element_type = geometry::reference_triangle_t; // the number of shape functions static constexpr int N = 6; private: // get the parametric coordinates from the reference element - static constexpr auto xi_0 = reference_element_type::xi_0; - static constexpr auto xi_1 = reference_element_type::xi_1; - static constexpr auto xi_2 = reference_element_type::xi_2; + static constexpr auto xi_0 = reference_element_type::xi<0>; + static constexpr auto xi_1 = reference_element_type::xi<1>; + static constexpr auto xi_2 = reference_element_type::xi<2>; // quadratic shape functions on the triangle static constexpr auto phi_3 = 4.0 * xi_0 * xi_1; @@ -36,11 +36,15 @@ namespace mito::fem { // the gradients of the shape functions static constexpr auto dphi = std::make_tuple( - fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2), - fields::gradient(phi_3), fields::gradient(phi_4), fields::gradient(phi_5)); + tensor::e_0<2> * (1.0 - 2.0 * xi_1 - 2.0 * xi_2 + 2.0 * xi_0), + tensor::e_1<2> * (1.0 - 2.0 * xi_0 - 2.0 * xi_2 + 2.0 * xi_1), + (tensor::e_0<2> + tensor::e_1<2>) *(-1.0 - 2.0 * xi_2 + 2.0 * xi_0 + 2.0 * xi_1), + tensor::e_0<2> * (4.0 * xi_1) + tensor::e_1<2> * (4.0 * xi_0), + tensor::e_0<2> * (-4.0 * xi_1) + tensor::e_1<2> * (4.0 * xi_2 - 4.0 * xi_1), + tensor::e_0<2> * (4.0 * xi_2 - 4.0 * xi_0) + tensor::e_1<2> * (-4.0 * xi_0)); public: - // get the a-th shape function + // get the a-th shape function as a function of barycentric coordinates template requires(a >= 0 && a < N) constexpr auto shape() const @@ -49,7 +53,7 @@ namespace mito::fem { return std::get(phi); } - // get the a-th shape function's gradient + // get the a-th shape function's gradient as a function of barycentric coordinates template requires(a >= 0 && a < N) constexpr auto dshape() const diff --git a/lib/mito/geometry/ReferenceSimplex.h b/lib/mito/geometry/ReferenceSimplex.h index 8c6d368da..ac2d43dc5 100644 --- a/lib/mito/geometry/ReferenceSimplex.h +++ b/lib/mito/geometry/ReferenceSimplex.h @@ -14,12 +14,11 @@ namespace mito::geometry { public: // the barycentric coordinates type - using barycentric_coordinates_type = geometry::coordinates_t; + using barycentric_coordinates_type = tensor::vector_t; // the function extracting the I component of a parametric point template - static constexpr auto xi = - fields::field(functions::component); + static constexpr auto xi = functions::component; }; } // namespace mito diff --git a/tests/mito.lib/fem/shape_functions_triangle_p1.cc b/tests/mito.lib/fem/shape_functions_triangle_p1.cc index de338cb6e..82e3fa83b 100644 --- a/tests/mito.lib/fem/shape_functions_triangle_p1.cc +++ b/tests/mito.lib/fem/shape_functions_triangle_p1.cc @@ -9,8 +9,8 @@ // first order shape functions type using shape_t = mito::fem::ShapeTriangleP1; -// the parametric coordinates type -using parametric_coordinates_t = shape_t::reference_element_type::parametric_coordinates_type; +// the barycentric coordinates type +using barycentric_coordinates_type = shape_t::reference_element_type::barycentric_coordinates_type; TEST(Fem, ShapeTriangleP1) @@ -19,11 +19,11 @@ TEST(Fem, ShapeTriangleP1) constexpr auto element = shape_t(); // node 0 in parametric coordinates - constexpr auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; + constexpr auto n0 = barycentric_coordinates_type{ 1.0, 0.0, 0.0 }; // node 1 in parametric coordinates - constexpr auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; + constexpr auto n1 = barycentric_coordinates_type{ 0.0, 1.0, 0.0 }; // node 2 in parametric coordinates - constexpr auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; + constexpr auto n2 = barycentric_coordinates_type{ 0.0, 0.0, 1.0 }; // the shape function associated with local node {0} constexpr auto phi_0 = element.shape<0>(); diff --git a/tests/mito.lib/fem/shape_functions_triangle_p2.cc b/tests/mito.lib/fem/shape_functions_triangle_p2.cc index 913fbb092..5a6d4610c 100644 --- a/tests/mito.lib/fem/shape_functions_triangle_p2.cc +++ b/tests/mito.lib/fem/shape_functions_triangle_p2.cc @@ -9,8 +9,8 @@ // second order shape functions type using shape_t = mito::fem::ShapeTriangleP2; -// the parametric coordinates type -using parametric_coordinates_t = shape_t::reference_element_type::parametric_coordinates_type; +// the barycentric coordinates type +using barycentric_coordinates_t = shape_t::reference_element_type::barycentric_coordinates_type; TEST(Fem, ShapeTriangleP2) @@ -18,18 +18,18 @@ TEST(Fem, ShapeTriangleP2) // second order shape functions constexpr auto element = shape_t(); - // node 0 in parametric coordinates - constexpr auto n0 = parametric_coordinates_t{ 1.0, 0.0 }; - // node 1 in parametric coordinates - constexpr auto n1 = parametric_coordinates_t{ 0.0, 1.0 }; - // node 2 in parametric coordinates - constexpr auto n2 = parametric_coordinates_t{ 0.0, 0.0 }; - // node 3 in parametric coordinates - constexpr auto n3 = parametric_coordinates_t{ 0.5, 0.5 }; - // node 4 in parametric coordinates - constexpr auto n4 = parametric_coordinates_t{ 0.0, 0.5 }; - // node 5 in parametric coordinates - constexpr auto n5 = parametric_coordinates_t{ 0.5, 0.0 }; + // node 0 in barycentric coordinates + constexpr auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + // node 1 in barycentric coordinates + constexpr auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + // node 2 in barycentric coordinates + constexpr auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + // node 3 in barycentric coordinates + constexpr auto n3 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; + // node 4 in barycentric coordinates + constexpr auto n4 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; + // node 5 in barycentric coordinates + constexpr auto n5 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; // the shape functions at node 0 constexpr auto phi_0 = element.shape<0>(); From 11c9cff64d56952a937f43eae090b21a5d0bcb75 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 8 Sep 2025 19:30:18 +0200 Subject: [PATCH 218/273] .cmake: switch to {c++23} --- .cmake/mito-config.cmake.in | 4 ++-- .cmake/mito_init.cmake | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.cmake/mito-config.cmake.in b/.cmake/mito-config.cmake.in index 124606f58..427eebac1 100644 --- a/.cmake/mito-config.cmake.in +++ b/.cmake/mito-config.cmake.in @@ -7,8 +7,8 @@ include(${CMAKE_CURRENT_LIST_DIR}/mito-targets.cmake) check_required_components(mito) -# request c++20 -set(CMAKE_CXX_STANDARD 20) +# request c++23 +set(CMAKE_CXX_STANDARD 23) # adjust the include path list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}) diff --git a/.cmake/mito_init.cmake b/.cmake/mito_init.cmake index e75e725eb..4dd6251bd 100644 --- a/.cmake/mito_init.cmake +++ b/.cmake/mito_init.cmake @@ -30,8 +30,8 @@ function(mito_cxxInit) # set C++ standard include(CheckCXXCompilerFlag) - # request c++20 - set(CMAKE_CXX_STANDARD 20 PARENT_SCOPE) + # request c++23 + set(CMAKE_CXX_STANDARD 23 PARENT_SCOPE) set(CMAKE_CXX_STANDARD_REQUIRED True PARENT_SCOPE) # additional compilation flags From 4be59c4114a0b0f71a87736a10b7d224f945a86a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 8 Sep 2025 19:31:33 +0200 Subject: [PATCH 219/273] tests/fem: improve readability of shape functions construction test --- .../shape_functions_triangle_construction.cc | 40 +++++++++---------- 1 file changed, 18 insertions(+), 22 deletions(-) diff --git a/tests/mito.lib/fem/shape_functions_triangle_construction.cc b/tests/mito.lib/fem/shape_functions_triangle_construction.cc index 1b8a619a6..4054f0277 100644 --- a/tests/mito.lib/fem/shape_functions_triangle_construction.cc +++ b/tests/mito.lib/fem/shape_functions_triangle_construction.cc @@ -36,7 +36,6 @@ TEST(Fem, ShapeTriangleConstuctionP1) constexpr auto phi_0 = eta_0; constexpr auto phi_1 = eta_1; constexpr auto phi_2 = eta_2; - constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2); // hard-coded derivatives of shape functions with respect to parametric coordinates constexpr auto dphi_0 = @@ -45,24 +44,23 @@ TEST(Fem, ShapeTriangleConstuctionP1) mito::functions::constant(mito::tensor::e_1<2>); constexpr auto dphi_2 = mito::functions::constant( -mito::tensor::e_0<2> - mito::tensor::e_1<2>); - constexpr auto dphi = std::make_tuple(dphi_0, dphi_1, dphi_2); // assemble the shape functions gradients as the partial derivatives of the shape functions with // respect to the parametric coordinates, seen as functions of barycentric coordinates - constexpr auto dN0 = mito::functions::derivative(std::get<0>(phi)(parametric_to_barycentric))( + constexpr auto dN0 = mito::functions::derivative(phi_0(parametric_to_barycentric))( barycentric_to_parametric); - constexpr auto dN1 = mito::functions::derivative(std::get<1>(phi)(parametric_to_barycentric))( + constexpr auto dN1 = mito::functions::derivative(phi_1(parametric_to_barycentric))( barycentric_to_parametric); - constexpr auto dN2 = mito::functions::derivative(std::get<2>(phi)(parametric_to_barycentric))( + constexpr auto dN2 = mito::functions::derivative(phi_2(parametric_to_barycentric))( barycentric_to_parametric); // barycenter in barycentric coordinates constexpr auto barycenter = barycentric_coordinates_type{ 1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0 }; // check result - static_assert(mito::tensor::row<0>(dN0(barycenter)) == std::get<0>(dphi)(barycenter)); - static_assert(mito::tensor::row<0>(dN1(barycenter)) == std::get<1>(dphi)(barycenter)); - static_assert(mito::tensor::row<0>(dN2(barycenter)) == std::get<2>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN0(barycenter)) == dphi_0(barycenter)); + static_assert(mito::tensor::row<0>(dN1(barycenter)) == dphi_1(barycenter)); + static_assert(mito::tensor::row<0>(dN2(barycenter)) == dphi_2(barycenter)); // all done return; @@ -81,7 +79,6 @@ TEST(Fem, ShapeTriangleConstuctionP2) constexpr auto phi_0 = eta_0 - 0.5 * phi_5 - 0.5 * phi_3; constexpr auto phi_1 = eta_1 - 0.5 * phi_3 - 0.5 * phi_4; constexpr auto phi_2 = eta_2 - 0.5 * phi_5 - 0.5 * phi_4; - constexpr auto phi = std::make_tuple(phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); // hard-coded derivatives of shape functions with respect to parametric coordinates constexpr auto dphi_0 = mito::tensor::e_0<2> * (1.0 - 2.0 * eta_1 - 2.0 * eta_2 + 2.0 * eta_0); @@ -94,33 +91,32 @@ TEST(Fem, ShapeTriangleConstuctionP2) mito::tensor::e_0<2> * (-4.0 * eta_1) + mito::tensor::e_1<2> * (4.0 * eta_2 - 4.0 * eta_1); constexpr auto dphi_5 = mito::tensor::e_0<2> * (4.0 * eta_2 - 4.0 * eta_0) + mito::tensor::e_1<2> * (-4.0 * eta_0); - constexpr auto dphi = std::make_tuple(dphi_0, dphi_1, dphi_2, dphi_3, dphi_4, dphi_5); // assemble the shape functions gradients as the partial derivatives of the shape functions with // respect to the parametric coordinates, seen as functions of barycentric coordinates - constexpr auto dN0 = mito::functions::derivative(std::get<0>(phi)(parametric_to_barycentric))( + constexpr auto dN0 = mito::functions::derivative(phi_0(parametric_to_barycentric))( barycentric_to_parametric); - constexpr auto dN1 = mito::functions::derivative(std::get<1>(phi)(parametric_to_barycentric))( + constexpr auto dN1 = mito::functions::derivative(phi_1(parametric_to_barycentric))( barycentric_to_parametric); - constexpr auto dN2 = mito::functions::derivative(std::get<2>(phi)(parametric_to_barycentric))( + constexpr auto dN2 = mito::functions::derivative(phi_2(parametric_to_barycentric))( barycentric_to_parametric); - constexpr auto dN3 = mito::functions::derivative(std::get<3>(phi)(parametric_to_barycentric))( + constexpr auto dN3 = mito::functions::derivative(phi_3(parametric_to_barycentric))( barycentric_to_parametric); - constexpr auto dN4 = mito::functions::derivative(std::get<4>(phi)(parametric_to_barycentric))( + constexpr auto dN4 = mito::functions::derivative(phi_4(parametric_to_barycentric))( barycentric_to_parametric); - constexpr auto dN5 = mito::functions::derivative(std::get<5>(phi)(parametric_to_barycentric))( + constexpr auto dN5 = mito::functions::derivative(phi_5(parametric_to_barycentric))( barycentric_to_parametric); // barycenter in barycentric coordinates constexpr auto barycenter = barycentric_coordinates_type{ 1.0, 0.0, 0.0 }; // check result - static_assert(mito::tensor::row<0>(dN0(barycenter)) == std::get<0>(dphi)(barycenter)); - static_assert(mito::tensor::row<0>(dN1(barycenter)) == std::get<1>(dphi)(barycenter)); - static_assert(mito::tensor::row<0>(dN2(barycenter)) == std::get<2>(dphi)(barycenter)); - static_assert(mito::tensor::row<0>(dN3(barycenter)) == std::get<3>(dphi)(barycenter)); - static_assert(mito::tensor::row<0>(dN4(barycenter)) == std::get<4>(dphi)(barycenter)); - static_assert(mito::tensor::row<0>(dN5(barycenter)) == std::get<5>(dphi)(barycenter)); + static_assert(mito::tensor::row<0>(dN0(barycenter)) == dphi_0(barycenter)); + static_assert(mito::tensor::row<0>(dN1(barycenter)) == dphi_1(barycenter)); + static_assert(mito::tensor::row<0>(dN2(barycenter)) == dphi_2(barycenter)); + static_assert(mito::tensor::row<0>(dN3(barycenter)) == dphi_3(barycenter)); + static_assert(mito::tensor::row<0>(dN4(barycenter)) == dphi_4(barycenter)); + static_assert(mito::tensor::row<0>(dN5(barycenter)) == dphi_5(barycenter)); // all done return; From f48e03796d519fb16691fcdb5a479c7d3caba75d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 8 Sep 2025 19:37:14 +0200 Subject: [PATCH 220/273] functions: classes {LinearCombination} and {Summation} now take the input functions by const reference --- lib/mito/functions/function.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/mito/functions/function.h b/lib/mito/functions/function.h index 5a566087b..0f7e58c86 100644 --- a/lib/mito/functions/function.h +++ b/lib/mito/functions/function.h @@ -131,7 +131,7 @@ namespace mito::functions { public: // constructor - constexpr Summation(Funcs... funcs) : _funcs(funcs...) {} + constexpr Summation(const Funcs &... funcs) : _funcs(funcs...) {} // call operator for function composition template @@ -190,7 +190,7 @@ namespace mito::functions { public: // constructor - constexpr LinearCombination(const coefficients_type & coeffs, Funcs... funcs) : + constexpr LinearCombination(const coefficients_type & coeffs, const Funcs &... funcs) : _coeffs(coeffs), _funcs(funcs...) {} From b57dd1c8b94252b5cf6e948f97706ec6fe0e3e1b Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 8 Sep 2025 20:09:42 +0200 Subject: [PATCH 221/273] fem/elements: remove unused type alias --- lib/mito/fem/elements/IsoparametricTriangle.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/mito/fem/elements/IsoparametricTriangle.h b/lib/mito/fem/elements/IsoparametricTriangle.h index 8f71ca9c9..177a7dc90 100644 --- a/lib/mito/fem/elements/IsoparametricTriangle.h +++ b/lib/mito/fem/elements/IsoparametricTriangle.h @@ -21,9 +21,6 @@ namespace mito::fem { using discretization_node_type = discrete::discretization_node_t; // the geometric simplex type using geometric_simplex_type = geometry::triangle_t; - // type of a point in barycentric coordinates - using barycentric_coordinates_type = - typename geometric_simplex_type::barycentric_coordinates_type; protected: // cartesian coordinates in 2D From dee7c3ef3500de14be975fc6fa75a5b4a2ca544a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 9 Sep 2025 19:45:00 +0200 Subject: [PATCH 222/273] topology: remove unused type alias {barycentric_coordinates_type} in class {OrientedSimplex} --- lib/mito/topology/OrientedSimplex.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/mito/topology/OrientedSimplex.h b/lib/mito/topology/OrientedSimplex.h index 71d90ca02..5896c9e6d 100644 --- a/lib/mito/topology/OrientedSimplex.h +++ b/lib/mito/topology/OrientedSimplex.h @@ -34,9 +34,6 @@ namespace mito::topology { template using cell_family_type = simplex_t; - // type of a point in barycentric coordinates - using barycentric_coordinates_type = std::array; - // private constructors: only the OrientedSimplexFactory has the right to instantiate // oriented simplices private: From f04677b828a5141b96ad302d19d6776ff5591bc4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 9 Sep 2025 19:49:19 +0200 Subject: [PATCH 223/273] quadrature: narrative edits --- lib/mito/quadrature/Integrator.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/mito/quadrature/Integrator.h b/lib/mito/quadrature/Integrator.h index 750184c1b..4490763cc 100644 --- a/lib/mito/quadrature/Integrator.h +++ b/lib/mito/quadrature/Integrator.h @@ -37,8 +37,9 @@ namespace mito::quadrature { { // loop on elements for (const auto & element : _manifold.elements()) { - // use manifold parametrization to map the position of quadrature points in - // the canonical element to the coordinate of the quadrature point + // use element parametrization and manifold's coordinate systemto map the position + // of quadrature points in the canonical element to the coordinate of the quadrature + // point _coordinates.insert( element.simplex(), { element.parametrization( From a9e3bfc8a0b14f8e398b7712844b5053432f636e Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Tue, 9 Sep 2025 19:52:46 +0200 Subject: [PATCH 224/273] geometry, quadrature and fem: replace barycentric coordinates with parametric coordinates on the canonical element --- .../elements/tri1/IsoparametricTriangleP1.h | 6 ++-- lib/mito/fem/elements/tri1/ShapeTriangleP1.h | 12 +++---- .../elements/tri2/IsoparametricTriangleP2.h | 6 ++-- lib/mito/fem/elements/tri2/ShapeTriangleP2.h | 2 +- lib/mito/geometry/GeometricSimplex.h | 28 ++++++++++----- lib/mito/geometry/ReferenceSimplex.h | 6 ++-- lib/mito/quadrature/QuadratureTable.h | 2 +- .../quadrature/quadrature_tables_segments.icc | 4 +-- .../quadrature_tables_tetrahedra.icc | 13 ++++--- .../quadrature_tables_triangles.icc | 35 +++++++++---------- .../fem/shape_functions_triangle_p1.cc | 8 ++--- .../fem/shape_functions_triangle_p2.cc | 14 ++++---- 12 files changed, 71 insertions(+), 65 deletions(-) diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index 8b8b837a2..947498721 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -22,8 +22,8 @@ namespace mito::fem { // the type of shape functions using shape_functions_type = ShapeTriangleP1; // the barycentric coordinates type - using barycentric_coordinates_type = - typename shape_functions_type::barycentric_coordinates_type; + using parametric_coordinates_type = + typename shape_functions_type::parametric_coordinates_type; // the linear shape functions static constexpr auto shape_functions = shape_functions_type(); // the number of discretization discretization nodes @@ -89,7 +89,7 @@ namespace mito::fem { { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = functions::function( - [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { + [&](const parametric_coordinates_type & xi) -> tensor::matrix_t<2> { // get the shape functions derivatives constexpr auto dphi_0 = shape_functions.dshape<0>(); constexpr auto dphi_1 = shape_functions.dshape<1>(); diff --git a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h index 4b98fa978..3523c79cc 100644 --- a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h +++ b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h @@ -15,8 +15,8 @@ namespace mito::fem { // the reference element using reference_element_type = geometry::reference_triangle_t; // the barycentric coordinates type - using barycentric_coordinates_type = - typename reference_element_type::barycentric_coordinates_type; + using parametric_coordinates_type = + typename reference_element_type::parametric_coordinates_type; // the number of shape functions static constexpr int N = 3; @@ -24,7 +24,7 @@ namespace mito::fem { // linear shape functions on the reference triangle in barycentric coordinates static constexpr auto xi_0 = reference_element_type::xi<0>; static constexpr auto xi_1 = reference_element_type::xi<1>; - static constexpr auto xi_2 = reference_element_type::xi<2>; + static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; // linear shape functions on the triangle static constexpr auto phi_0 = xi_0; @@ -36,9 +36,9 @@ namespace mito::fem { // the gradients of the shape functions static constexpr auto dphi = std::make_tuple( - functions::constant(tensor::e_0<2>), - functions::constant(tensor::e_1<2>), - functions::constant(-tensor::e_0<2> - tensor::e_1<2>)); + functions::constant(tensor::e_0<2>), + functions::constant(tensor::e_1<2>), + functions::constant(-tensor::e_0<2> - tensor::e_1<2>)); public: // get the a-th shape function as a function of barycentric coordinates diff --git a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h index 59040d696..99541f995 100644 --- a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h @@ -22,8 +22,8 @@ namespace mito::fem { // the type of shape functions using shape_functions_type = ShapeTriangleP2; // type of a point in barycentric coordinates - using barycentric_coordinates_type = - typename shape_functions_type::reference_element_type::barycentric_coordinates_type; + using parametric_coordinates_type = + typename shape_functions_type::reference_element_type::parametric_coordinates_type; // the linear shape functions static constexpr auto shape_functions = shape_functions_type(); // the number of discretization nodes @@ -96,7 +96,7 @@ namespace mito::fem { { // assemble the jacobian as a function of barycentric coordinates auto jacobian_function = functions::function( - [&](const barycentric_coordinates_type & xi) -> tensor::matrix_t<2> { + [&](const parametric_coordinates_type & xi) -> tensor::matrix_t<2> { auto x3 = 0.5 * (_x0 + _x1); auto x4 = 0.5 * (_x1 + _x2); auto x5 = 0.5 * (_x2 + _x0); diff --git a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h index 546f82832..dbb7d89e3 100644 --- a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h +++ b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h @@ -21,7 +21,7 @@ namespace mito::fem { // get the parametric coordinates from the reference element static constexpr auto xi_0 = reference_element_type::xi<0>; static constexpr auto xi_1 = reference_element_type::xi<1>; - static constexpr auto xi_2 = reference_element_type::xi<2>; + static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; // quadratic shape functions on the triangle static constexpr auto phi_3 = 4.0 * xi_0 * xi_1; diff --git a/lib/mito/geometry/GeometricSimplex.h b/lib/mito/geometry/GeometricSimplex.h index feaa64803..5e6555e51 100644 --- a/lib/mito/geometry/GeometricSimplex.h +++ b/lib/mito/geometry/GeometricSimplex.h @@ -58,7 +58,7 @@ namespace mito::geometry { using reference_simplex_type = reference_simplex_t; // type of a point in barycentric coordinates - using barycentric_coordinates_type = reference_simplex_type::barycentric_coordinates_type; + using parametric_coordinates_type = reference_simplex_type::parametric_coordinates_type; private: constexpr auto _sanity_check() const -> bool @@ -134,9 +134,10 @@ namespace mito::geometry { // return the composition of this simplex in terms of its vertices constexpr auto nodes() const -> const nodes_type & { return _nodes; } + // get the coordinates of a parametric point in physical space template constexpr auto parametrization( - const barycentric_coordinates_type & point, + const parametric_coordinates_type & point, const coordinateSystemT & coordinate_system) const -> coordinateSystemT::coordinates_type { @@ -146,13 +147,22 @@ namespace mito::geometry { // the vector going from {coord_0} to the position of the parametric point (initialize // with the zero vector) auto result = coord_0 - coord_0; - - // loop on the element nodes - int v = 0; - for (const auto & node : _nodes) { - result += (coordinate_system.coordinates(node->point()) - coord_0) * point[v]; - ++v; - } + // the sum of the parametric coordinates (initialize with zero) + auto xi = 0.0; + // loop on the vertices of the element + tensor::constexpr_for_1([&]() { + // get the coordinates of the i-th vertex + const auto & coord_i = coordinate_system.coordinates(_nodes[i]->point()); + // assemble the contribution of the i-th vertex + result += (coord_i - coord_0) * point[i]; + // accumulate the parametric coordinate + xi += point[i]; + }); + // get the coordinates of the last vertex + const auto & coord_i = coordinate_system.coordinates(_nodes[n_vertices - 1]->point()); + // add the contribution of the last vertex + // (note that the last barycentric coordinate is 1 - sum of the others) + result += (coord_i - coord_0) * (1.0 - xi); // return the coordinates of the parametric point return coord_0 + result; diff --git a/lib/mito/geometry/ReferenceSimplex.h b/lib/mito/geometry/ReferenceSimplex.h index ac2d43dc5..7984674d0 100644 --- a/lib/mito/geometry/ReferenceSimplex.h +++ b/lib/mito/geometry/ReferenceSimplex.h @@ -13,12 +13,12 @@ namespace mito::geometry { class ReferenceSimplex { public: - // the barycentric coordinates type - using barycentric_coordinates_type = tensor::vector_t; + // the type of coordinates in the parametric space + using parametric_coordinates_type = tensor::vector_t; // the function extracting the I component of a parametric point template - static constexpr auto xi = functions::component; + static constexpr auto xi = functions::component; }; } // namespace mito diff --git a/lib/mito/quadrature/QuadratureTable.h b/lib/mito/quadrature/QuadratureTable.h index 3ea02934b..3646f491a 100644 --- a/lib/mito/quadrature/QuadratureTable.h +++ b/lib/mito/quadrature/QuadratureTable.h @@ -15,7 +15,7 @@ namespace mito::quadrature { public: // the type of quadrature points' barycentric coordinates - using quadrature_point_type = typename elementT::barycentric_coordinates_type; + using quadrature_point_type = typename elementT::parametric_coordinates_type; // the type of quadrature weights using quadrature_weight_type = double; // the type of quadrature point-weight pairing diff --git a/lib/mito/quadrature/quadrature_tables_segments.icc b/lib/mito/quadrature/quadrature_tables_segments.icc index 5f088ad07..f9f381291 100644 --- a/lib/mito/quadrature/quadrature_tables_segments.icc +++ b/lib/mito/quadrature/quadrature_tables_segments.icc @@ -17,7 +17,7 @@ namespace mito::quadrature { using point_weight_pair_type = table_type::point_weight_pair_type; return table_type({ /*{point}, weight*/ - point_weight_pair_type({ 0.5, 0.5 }, 1.0) }); + point_weight_pair_type({ 0.5 }, 1.0) }); } template <> @@ -32,7 +32,7 @@ namespace mito::quadrature { return table_type( { /*{point}, weight*/ - point_weight_pair_type({ a, b }, 0.5), point_weight_pair_type({ b, a }, 0.5) }); + point_weight_pair_type({ a }, 0.5), point_weight_pair_type({ b }, 0.5) }); } } // namespace mito diff --git a/lib/mito/quadrature/quadrature_tables_tetrahedra.icc b/lib/mito/quadrature/quadrature_tables_tetrahedra.icc index a68fed80d..a5c160810 100644 --- a/lib/mito/quadrature/quadrature_tables_tetrahedra.icc +++ b/lib/mito/quadrature/quadrature_tables_tetrahedra.icc @@ -17,9 +17,8 @@ namespace mito::quadrature { using point_weight_pair_type = table_type::point_weight_pair_type; /*Hammer rule*/ - return table_type( - { /*{point}, weight*/ - point_weight_pair_type({ 1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0 }, 1.0) }); + return table_type({ /*{point}, weight*/ + point_weight_pair_type({ 1.0 / 4.0, 1.0 / 4.0, 1.0 / 4.0 }, 1.0) }); } template <> @@ -34,10 +33,10 @@ namespace mito::quadrature { /*Hammer rule*/ return table_type({ /*{point}, weight*/ - point_weight_pair_type({ a, b, b, b }, 1.0 / 4.0), - point_weight_pair_type({ b, a, b, b }, 1.0 / 4.0), - point_weight_pair_type({ b, b, a, b }, 1.0 / 4.0), - point_weight_pair_type({ b, b, b, a }, 1.0 / 4.0) }); + point_weight_pair_type({ a, b, b }, 1.0 / 4.0), + point_weight_pair_type({ b, a, b }, 1.0 / 4.0), + point_weight_pair_type({ b, b, a }, 1.0 / 4.0), + point_weight_pair_type({ b, b, b }, 1.0 / 4.0) }); } } // namespace mito diff --git a/lib/mito/quadrature/quadrature_tables_triangles.icc b/lib/mito/quadrature/quadrature_tables_triangles.icc index 19aab255e..9ae97fa2c 100644 --- a/lib/mito/quadrature/quadrature_tables_triangles.icc +++ b/lib/mito/quadrature/quadrature_tables_triangles.icc @@ -17,7 +17,7 @@ namespace mito::quadrature { using point_weight_pair_type = table_type::point_weight_pair_type; return table_type({ /*{point}, weight*/ - point_weight_pair_type({ 1.0 / 3.0, 1.0 / 3.0, 1.0 / 3.0 }, 1.0) }); + point_weight_pair_type({ 1.0 / 3.0, 1.0 / 3.0 }, 1.0) }); } template <> @@ -27,11 +27,10 @@ namespace mito::quadrature { using table_type = Table; using point_weight_pair_type = table_type::point_weight_pair_type; - return table_type( - { /*{point}, weight*/ - point_weight_pair_type({ 2.0 / 3.0, 1.0 / 6.0, 1.0 / 6.0 }, 1.0 / 3.0), - point_weight_pair_type({ 1.0 / 6.0, 2.0 / 3.0, 1.0 / 6.0 }, 1.0 / 3.0), - point_weight_pair_type({ 1.0 / 6.0, 1.0 / 6.0, 2.0 / 3.0 }, 1.0 / 3.0) }); + return table_type({ /*{point}, weight*/ + point_weight_pair_type({ 2.0 / 3.0, 1.0 / 6.0 }, 1.0 / 3.0), + point_weight_pair_type({ 1.0 / 6.0, 2.0 / 3.0 }, 1.0 / 3.0), + point_weight_pair_type({ 1.0 / 6.0, 1.0 / 6.0 }, 1.0 / 3.0) }); } template <> @@ -47,12 +46,12 @@ namespace mito::quadrature { constexpr auto w2 = 0.05218353089235368507981901063125638; return table_type({ /*{point}, weight*/ - point_weight_pair_type({ 1.0 - 2.0 * a, a, a }, w1), - point_weight_pair_type({ a, 1.0 - 2.0 * a, a }, w1), - point_weight_pair_type({ a, a, 1.0 - 2.0 * a }, w1), - point_weight_pair_type({ 1.0 - 2.0 * b, b, b }, w2), - point_weight_pair_type({ b, 1.0 - 2.0 * b, b }, w2), - point_weight_pair_type({ b, b, 1.0 - 2.0 * b }, w2) }); + point_weight_pair_type({ 1.0 - 2.0 * a, a }, w1), + point_weight_pair_type({ a, 1.0 - 2.0 * a }, w1), + point_weight_pair_type({ a, a }, w1), + point_weight_pair_type({ 1.0 - 2.0 * b, b }, w2), + point_weight_pair_type({ b, 1.0 - 2.0 * b }, w2), + point_weight_pair_type({ b, b }, w2) }); } // Dunavant's Rule #4, Hammer–Stroud-type rule @@ -70,13 +69,11 @@ namespace mito::quadrature { constexpr auto w1 = 0.109951743655321867638326; constexpr auto w2 = 0.223381589678011465695007; - return table_type({ /*{point}, weight*/ - point_weight_pair_type({ a, b, 1.0 - a - b }, w1), - point_weight_pair_type({ b, a, 1.0 - a - b }, w1), - point_weight_pair_type({ b, b, 1.0 - 2.0 * b }, w1), - point_weight_pair_type({ c, d, 1.0 - c - d }, w2), - point_weight_pair_type({ d, c, 1.0 - c - d }, w2), - point_weight_pair_type({ d, d, 1.0 - 2.0 * d }, w2) }); + return table_type( + { /*{point}, weight*/ + point_weight_pair_type({ a, b }, w1), point_weight_pair_type({ b, a }, w1), + point_weight_pair_type({ b, b }, w1), point_weight_pair_type({ c, d }, w2), + point_weight_pair_type({ d, c }, w2), point_weight_pair_type({ d, d }, w2) }); } } // namespace mito diff --git a/tests/mito.lib/fem/shape_functions_triangle_p1.cc b/tests/mito.lib/fem/shape_functions_triangle_p1.cc index 82e3fa83b..3253908d0 100644 --- a/tests/mito.lib/fem/shape_functions_triangle_p1.cc +++ b/tests/mito.lib/fem/shape_functions_triangle_p1.cc @@ -10,7 +10,7 @@ // first order shape functions type using shape_t = mito::fem::ShapeTriangleP1; // the barycentric coordinates type -using barycentric_coordinates_type = shape_t::reference_element_type::barycentric_coordinates_type; +using parametric_coordinates_type = shape_t::reference_element_type::parametric_coordinates_type; TEST(Fem, ShapeTriangleP1) @@ -19,11 +19,11 @@ TEST(Fem, ShapeTriangleP1) constexpr auto element = shape_t(); // node 0 in parametric coordinates - constexpr auto n0 = barycentric_coordinates_type{ 1.0, 0.0, 0.0 }; + constexpr auto n0 = parametric_coordinates_type{ 1.0, 0.0 }; // node 1 in parametric coordinates - constexpr auto n1 = barycentric_coordinates_type{ 0.0, 1.0, 0.0 }; + constexpr auto n1 = parametric_coordinates_type{ 0.0, 1.0 }; // node 2 in parametric coordinates - constexpr auto n2 = barycentric_coordinates_type{ 0.0, 0.0, 1.0 }; + constexpr auto n2 = parametric_coordinates_type{ 0.0, 0.0 }; // the shape function associated with local node {0} constexpr auto phi_0 = element.shape<0>(); diff --git a/tests/mito.lib/fem/shape_functions_triangle_p2.cc b/tests/mito.lib/fem/shape_functions_triangle_p2.cc index 5a6d4610c..a318571f2 100644 --- a/tests/mito.lib/fem/shape_functions_triangle_p2.cc +++ b/tests/mito.lib/fem/shape_functions_triangle_p2.cc @@ -10,7 +10,7 @@ // second order shape functions type using shape_t = mito::fem::ShapeTriangleP2; // the barycentric coordinates type -using barycentric_coordinates_t = shape_t::reference_element_type::barycentric_coordinates_type; +using barycentric_coordinates_t = shape_t::reference_element_type::parametric_coordinates_type; TEST(Fem, ShapeTriangleP2) @@ -19,17 +19,17 @@ TEST(Fem, ShapeTriangleP2) constexpr auto element = shape_t(); // node 0 in barycentric coordinates - constexpr auto n0 = barycentric_coordinates_t{ 1.0, 0.0, 0.0 }; + constexpr auto n0 = barycentric_coordinates_t{ 1.0, 0.0 }; // node 1 in barycentric coordinates - constexpr auto n1 = barycentric_coordinates_t{ 0.0, 1.0, 0.0 }; + constexpr auto n1 = barycentric_coordinates_t{ 0.0, 1.0 }; // node 2 in barycentric coordinates - constexpr auto n2 = barycentric_coordinates_t{ 0.0, 0.0, 1.0 }; + constexpr auto n2 = barycentric_coordinates_t{ 0.0, 0.0 }; // node 3 in barycentric coordinates - constexpr auto n3 = barycentric_coordinates_t{ 0.5, 0.5, 0.0 }; + constexpr auto n3 = barycentric_coordinates_t{ 0.5, 0.5 }; // node 4 in barycentric coordinates - constexpr auto n4 = barycentric_coordinates_t{ 0.0, 0.5, 0.5 }; + constexpr auto n4 = barycentric_coordinates_t{ 0.0, 0.5 }; // node 5 in barycentric coordinates - constexpr auto n5 = barycentric_coordinates_t{ 0.5, 0.0, 0.5 }; + constexpr auto n5 = barycentric_coordinates_t{ 0.5, 0.0 }; // the shape functions at node 0 constexpr auto phi_0 = element.shape<0>(); From 6d64973e98285c112e14b34ee3c75340bcbd970c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 10 Sep 2025 20:12:41 +0200 Subject: [PATCH 225/273] fem: shape functions are now fields defined on parametric coordinates --- lib/mito/fem/DiscreteSystem.h | 21 +++++++++++-------- .../elements/tri1/IsoparametricTriangleP1.h | 2 +- lib/mito/fem/elements/tri1/ShapeTriangleP1.h | 4 +--- .../elements/tri2/IsoparametricTriangleP2.h | 2 +- lib/mito/fem/elements/tri2/ShapeTriangleP2.h | 8 ++----- lib/mito/geometry/ReferenceSimplex.h | 5 +++-- 6 files changed, 20 insertions(+), 22 deletions(-) diff --git a/lib/mito/fem/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h index 8d66d5fd8..4a5af056e 100644 --- a/lib/mito/fem/DiscreteSystem.h +++ b/lib/mito/fem/DiscreteSystem.h @@ -291,11 +291,12 @@ namespace mito::fem { auto u_numerical = _assemble_element_solution( element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error field as a function of the barycentric coordinates - auto u_error = u_numerical - u_exact.function()(element.parametrization()); + auto u_error = + u_numerical - u_exact.function()(element.parametrization().function()); // compute the elementary contribution to the L2 norm - norm += - blocks::l2_norm_block(u_error).compute(element); + norm += blocks::l2_norm_block(u_error.function()) + .compute(element); } return std::sqrt(norm); @@ -341,7 +342,8 @@ namespace mito::fem { auto u_numerical = _assemble_element_solution( element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error field as a function of the barycentric coordinates - auto u_error = u_numerical - u_exact.function()(element.parametrization()); + auto u_error = + u_numerical - u_exact.function()(element.parametrization().function()); // auto u_numerical_gradient = _assemble_element_solution_gradient( element, _solution_field, tensor::make_integer_sequence()); @@ -349,12 +351,13 @@ namespace mito::fem { // coordinates auto u_error_gradient = u_numerical_gradient - - fields::gradient(u_exact).function()(element.parametrization()); + - fields::gradient(u_exact).function()(element.parametrization().function()); // compute the elementary contributions to the H1 norm - norm += - blocks::l2_norm_block(u_error).compute(element) - + blocks::l2_norm_block(u_error_gradient) - .compute(element); + norm += blocks::l2_norm_block(u_error.function()) + .compute(element) + + blocks::l2_norm_block( + u_error_gradient.function()) + .compute(element); } return std::sqrt(norm); diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index 947498721..e71f15ff0 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -71,7 +71,7 @@ namespace mito::fem { constexpr auto phi_2 = shape_functions.shape<2>(); // return the isoparametric mapping from parametric to physical coordinates - return mito::functions::linear_combination( + return mito::fields::linear_combination( std::array{ _x0, _x1, _x2 }, phi_0, phi_1, phi_2); } diff --git a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h index 3523c79cc..f79746086 100644 --- a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h +++ b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h @@ -36,9 +36,7 @@ namespace mito::fem { // the gradients of the shape functions static constexpr auto dphi = std::make_tuple( - functions::constant(tensor::e_0<2>), - functions::constant(tensor::e_1<2>), - functions::constant(-tensor::e_0<2> - tensor::e_1<2>)); + fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2)); public: // get the a-th shape function as a function of barycentric coordinates diff --git a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h index 99541f995..09b4f719f 100644 --- a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h @@ -72,7 +72,7 @@ namespace mito::fem { constexpr auto phi_5 = shape_functions.shape<5>(); // return the isoparametric mapping from barycentric to physical coordinates - return mito::functions::linear_combination( + return mito::fields::linear_combination( std::array{ _x0, _x1, _x2, x3, x4, x5 }, phi_0, phi_1, phi_2, phi_3, phi_4, phi_5); } diff --git a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h index dbb7d89e3..47b869cf4 100644 --- a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h +++ b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h @@ -36,12 +36,8 @@ namespace mito::fem { // the gradients of the shape functions static constexpr auto dphi = std::make_tuple( - tensor::e_0<2> * (1.0 - 2.0 * xi_1 - 2.0 * xi_2 + 2.0 * xi_0), - tensor::e_1<2> * (1.0 - 2.0 * xi_0 - 2.0 * xi_2 + 2.0 * xi_1), - (tensor::e_0<2> + tensor::e_1<2>) *(-1.0 - 2.0 * xi_2 + 2.0 * xi_0 + 2.0 * xi_1), - tensor::e_0<2> * (4.0 * xi_1) + tensor::e_1<2> * (4.0 * xi_0), - tensor::e_0<2> * (-4.0 * xi_1) + tensor::e_1<2> * (4.0 * xi_2 - 4.0 * xi_1), - tensor::e_0<2> * (4.0 * xi_2 - 4.0 * xi_0) + tensor::e_1<2> * (-4.0 * xi_0)); + fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2), + fields::gradient(phi_3), fields::gradient(phi_4), fields::gradient(phi_5)); public: // get the a-th shape function as a function of barycentric coordinates diff --git a/lib/mito/geometry/ReferenceSimplex.h b/lib/mito/geometry/ReferenceSimplex.h index 7984674d0..d5d8fbe64 100644 --- a/lib/mito/geometry/ReferenceSimplex.h +++ b/lib/mito/geometry/ReferenceSimplex.h @@ -14,11 +14,12 @@ namespace mito::geometry { public: // the type of coordinates in the parametric space - using parametric_coordinates_type = tensor::vector_t; + using parametric_coordinates_type = coordinates_t; // the function extracting the I component of a parametric point template - static constexpr auto xi = functions::component; + static constexpr auto xi = + fields::field(functions::component); }; } // namespace mito From d38b7f5f6bb6c938a016e770afa146989a5f3804 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 13 Sep 2025 08:50:57 +0200 Subject: [PATCH 226/273] fem/elements: fix inefficiency in shape functions gradients evaluation --- .../fem/elements/tri1/IsoparametricTriangleP1.h | 15 +++++++++++++-- .../fem/elements/tri2/IsoparametricTriangleP2.h | 15 +++++++++++++-- 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index e71f15ff0..f143d1ee1 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -110,8 +110,19 @@ namespace mito::fem { requires(a >= 0 && a < n_nodes) constexpr auto gradient() const { - // return the (physical) gradient of the a-th shape function - return shape_functions.dshape() * functions::inverse(jacobian()); + // assemble the gradient as a function of barycentric coordinates + auto gradient_function = + fields::field([&](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 barycentric coordinates + auto J_inv = tensor::inverse(J); + // return the spatial gradients of the shape functions evaluated at {xi} + return shape_functions.dshape()(xi) * J_inv; + }); + // and return it + return gradient_function; } private: diff --git a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h index 09b4f719f..b59554d04 100644 --- a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h @@ -125,8 +125,19 @@ namespace mito::fem { requires(a >= 0 && a < n_nodes) constexpr auto gradient() const { - // return the (physical) gradient of the a-th shape function - return shape_functions.dshape() * functions::inverse(jacobian()); + // assemble the gradient as a function of barycentric coordinates + auto gradient_function = + fields::field([&](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 barycentric coordinates + auto J_inv = tensor::inverse(J); + // return the spatial gradients of the shape functions evaluated at {xi} + return shape_functions.dshape()(xi) * J_inv; + }); + // and return it + return gradient_function; } private: From c684b94757d4e04a781bcb7d62915169f64a7a78 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 28 Sep 2025 10:07:54 +0200 Subject: [PATCH 227/273] coordinates: fix typo --- lib/mito/coordinates/Coordinates.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/coordinates/Coordinates.h b/lib/mito/coordinates/Coordinates.h index 4a61069fb..28d33df3b 100644 --- a/lib/mito/coordinates/Coordinates.h +++ b/lib/mito/coordinates/Coordinates.h @@ -47,7 +47,7 @@ namespace mito::geometry { constexpr Coordinates(mito::tensor::scalar_t (&&coords)[D]) : _array(std::move(coords)) {} // constructor - constexpr Coordinates(const array_t coords) : _array(coords) {} + constexpr Coordinates(const array_t & coords) : _array(coords) {} // constructor from parameter pack template From 3582fb559d373cea5b8ce7bca597edab15952195 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 28 Sep 2025 10:19:14 +0200 Subject: [PATCH 228/273] mesh: fix typo --- lib/mito/mesh/tetra.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/mesh/tetra.h b/lib/mito/mesh/tetra.h index f58c77272..680696f43 100644 --- a/lib/mito/mesh/tetra.h +++ b/lib/mito/mesh/tetra.h @@ -188,7 +188,7 @@ namespace mito::mesh { for (const auto & cell : mesh.cells()) { // get the nodes of the cell in the order dictated by the orientation - auto nodes = cell.nodes(); + const auto & nodes = cell.nodes(); // helper function to expand array to parameter pack constexpr auto _subdivide = From 5aaf0e7595aa1491399f64856b769d4597b472d4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 28 Sep 2025 16:26:00 +0200 Subject: [PATCH 229/273] fem: in isoparametric classes, rename {geometric_simplex_type} to {cell_type} --- lib/mito/fem/FunctionSpace.h | 3 +-- lib/mito/fem/elements/IsoparametricTriangle.h | 25 +++++++------------ .../elements/tri1/IsoparametricTriangleP1.h | 4 +-- .../elements/tri2/IsoparametricTriangleP2.h | 4 +-- lib/mito/io/vtk/NodeVTKWriter.h | 7 +++--- 5 files changed, 17 insertions(+), 26 deletions(-) diff --git a/lib/mito/fem/FunctionSpace.h b/lib/mito/fem/FunctionSpace.h index 2c192a596..2b9abfdb6 100644 --- a/lib/mito/fem/FunctionSpace.h +++ b/lib/mito/fem/FunctionSpace.h @@ -46,8 +46,7 @@ namespace mito::fem { template // require compatibility between the manifold cell and the finite element cell requires(std::is_same_v< - typename manifoldT::mesh_type::cell_type, - typename element_type::geometric_simplex_type>) + typename manifoldT::mesh_type::cell_type, typename element_type::cell_type>) constexpr FunctionSpace(const manifoldT & manifold, const constraints_type & constraints) : _elements(100), _constraints(constraints), diff --git a/lib/mito/fem/elements/IsoparametricTriangle.h b/lib/mito/fem/elements/IsoparametricTriangle.h index 177a7dc90..7c8ed5bcb 100644 --- a/lib/mito/fem/elements/IsoparametricTriangle.h +++ b/lib/mito/fem/elements/IsoparametricTriangle.h @@ -19,8 +19,8 @@ namespace mito::fem { static constexpr int dim = 2; // the discretization node type using discretization_node_type = discrete::discretization_node_t; - // the geometric simplex type - using geometric_simplex_type = geometry::triangle_t; + // the underlying cell type + using cell_type = geometry::triangle_t; protected: // cartesian coordinates in 2D @@ -33,15 +33,11 @@ namespace mito::fem { public: // the default constructor constexpr IsoparametricTriangle( - const geometric_simplex_type & geometric_simplex, - const coordinate_system_type & coord_system) : - _geometric_simplex(geometric_simplex), - _x0{ coord_system.coordinates(geometric_simplex.nodes()[0]->point()) - - coordinates_type{} }, - _x1{ coord_system.coordinates(geometric_simplex.nodes()[1]->point()) - - coordinates_type{} }, - _x2{ coord_system.coordinates(geometric_simplex.nodes()[2]->point()) - - coordinates_type{} } + const cell_type & cell, const coordinate_system_type & coord_system) : + _cell(cell), + _x0{ coord_system.coordinates(cell.nodes()[0]->point()) - coordinates_type{} }, + _x1{ coord_system.coordinates(cell.nodes()[1]->point()) - coordinates_type{} }, + _x2{ coord_system.coordinates(cell.nodes()[2]->point()) - coordinates_type{} } {} // destructor @@ -61,15 +57,12 @@ namespace mito::fem { public: // get the geometric simplex - constexpr auto geometric_simplex() const noexcept -> const geometric_simplex_type & - { - return _geometric_simplex; - } + constexpr auto cell() const noexcept -> const cell_type & { return _cell; } protected: // QUESTION: do we need to maintain a reference to the geometric simplex? // a const reference to the geometric simplex - const geometric_simplex_type & _geometric_simplex; + const cell_type & _cell; // the coordinates of the discretization nodes of the triangle const vector_type _x0; diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index f143d1ee1..c4c74fbd9 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -34,8 +34,8 @@ namespace mito::fem { public: // the default constructor inline IsoparametricTriangleP1( - const geometric_simplex_type & geometric_simplex, - const coordinate_system_type & coord_system, const connectivity_type & connectivity) : + const cell_type & geometric_simplex, const coordinate_system_type & coord_system, + const connectivity_type & connectivity) : IsoparametricTriangle(geometric_simplex, coord_system), _connectivity(connectivity) {} diff --git a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h index b59554d04..665092729 100644 --- a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h @@ -34,8 +34,8 @@ namespace mito::fem { public: // the default constructor inline IsoparametricTriangleP2( - const geometric_simplex_type & geometric_simplex, - const coordinate_system_type & coord_system, const connectivity_type & connectivity) : + const cell_type & geometric_simplex, const coordinate_system_type & coord_system, + const connectivity_type & connectivity) : IsoparametricTriangle(geometric_simplex, coord_system), _connectivity(connectivity) {} diff --git a/lib/mito/io/vtk/NodeVTKWriter.h b/lib/mito/io/vtk/NodeVTKWriter.h index 9c01ca3e4..41f0dbf2c 100644 --- a/lib/mito/io/vtk/NodeVTKWriter.h +++ b/lib/mito/io/vtk/NodeVTKWriter.h @@ -51,7 +51,7 @@ namespace mito::io::vtk { // loop over the elements for (const auto & element : function_space.elements()) { // get the cell associated with the element - const auto & cell = element.geometric_simplex(); + const auto & cell = element.cell(); // loop over the nodes of the cell for (const auto & node : cell.nodes()) { // try to insert the point in the map @@ -70,11 +70,10 @@ namespace mito::io::vtk { // loop over the elements for (const auto & element : function_space.elements()) { // get the cell associated with the element - const auto & cell = element.geometric_simplex(); + const auto & cell = element.cell(); // create vtk cell - auto cellVtk = - vtkCellPointer(); + auto cellVtk = vtkCellPointer(); // local index for the points of the cell auto indexLocalPointVtk = 0; From fcba59db070193a1b3aec1e8f8977f2e8567ddda Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 28 Sep 2025 16:30:17 +0200 Subject: [PATCH 230/273] fem: function space is now template with respect to the finite element type --- lib/mito/fem/factories.h | 18 +++++------------- tests/mito.lib/fem/poisson.cc | 3 +-- 2 files changed, 6 insertions(+), 15 deletions(-) diff --git a/lib/mito/fem/factories.h b/lib/mito/fem/factories.h index ebb2b5a32..03e8e7247 100644 --- a/lib/mito/fem/factories.h +++ b/lib/mito/fem/factories.h @@ -29,22 +29,14 @@ namespace mito::fem { // TOFIX: {constraints} should be a collection of constraints as opposed to an instance of a // single constraint // function space factory - template + template < + class elementT, manifolds::manifold_c manifoldT, constraints::constraint_c constraintsT> + // require compatibility between the manifold cell and the finite element cell + requires(std::is_same_v) constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints) { - // the manifold type - using manifold_type = manifoldT; - // the mesh type - using mesh_type = typename manifold_type::mesh_type; - // the cell type - using cell_type = typename mesh_type::cell_type; - // the degree of the finite element - constexpr int degree = p; - // typedef for a finite element - using element_type = typename isoparametric_simplex::type; - // build a function space on the manifold and return it - return function_space_t(manifold, constraints); + return function_space_t(manifold, constraints); } // discrete system factory diff --git a/tests/mito.lib/fem/poisson.cc b/tests/mito.lib/fem/poisson.cc index 021fce5db..2e5a258e1 100644 --- a/tests/mito.lib/fem/poisson.cc +++ b/tests/mito.lib/fem/poisson.cc @@ -71,8 +71,7 @@ TEST(Fem, PoissonSquare) auto manifold = mito::manifolds::manifold(mesh, coord_system); // the function space (linear elements on the manifold) - // TOFIX: function space should be template with respect to the finite element type - auto function_space = mito::fem::function_space(manifold, constraints); + auto function_space = mito::fem::function_space(manifold, constraints); // TODO: all top level instances have names. Name should be the first argument. Then we can use // names in the configuration file and in the hdf5 file. Check libuuid vs. leading namestring. From debcf95603b8ad8750030f53289cccf37c06c329 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 5 Oct 2025 09:44:13 +0200 Subject: [PATCH 231/273] fem: pass label as first input argument in constructor of {DiscreteSystem} --- lib/mito/fem/DiscreteSystem.h | 2 +- lib/mito/fem/factories.h | 4 ++-- tests/mito.lib/fem/poisson.cc | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mito/fem/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h index 4a5af056e..548012d72 100644 --- a/lib/mito/fem/DiscreteSystem.h +++ b/lib/mito/fem/DiscreteSystem.h @@ -57,7 +57,7 @@ namespace mito::fem { public: // the default constructor constexpr DiscreteSystem( - const function_space_type & function_space, const label_type & label) : + const label_type & label, const function_space_type & function_space) : _function_space(function_space), _equation_map(), _solution_field(nodal_field(function_space, label + ".solution")), diff --git a/lib/mito/fem/factories.h b/lib/mito/fem/factories.h index 03e8e7247..be23f6e6f 100644 --- a/lib/mito/fem/factories.h +++ b/lib/mito/fem/factories.h @@ -41,9 +41,9 @@ namespace mito::fem { // discrete system factory template - constexpr auto discrete_system(const functionSpaceT & function_space, const std::string & label) + constexpr auto discrete_system(const std::string & label, const functionSpaceT & function_space) { - return discrete_system_t(function_space, label); + return discrete_system_t(label, function_space); } } diff --git a/tests/mito.lib/fem/poisson.cc b/tests/mito.lib/fem/poisson.cc index 2e5a258e1..98a406966 100644 --- a/tests/mito.lib/fem/poisson.cc +++ b/tests/mito.lib/fem/poisson.cc @@ -77,7 +77,7 @@ TEST(Fem, PoissonSquare) // names in the configuration file and in the hdf5 file. Check libuuid vs. leading namestring. // // the discrete system - auto discrete_system = mito::fem::discrete_system(function_space, "mysystem"); + auto discrete_system = mito::fem::discrete_system("mysystem", function_space); // instantiate a linear solver for the discrete system auto solver = mito::solvers::linear_solver(discrete_system); From b41eeb4f25699e0329ec089f147a67cff26e22e2 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 5 Oct 2025 09:52:05 +0200 Subject: [PATCH 232/273] fem: narrative edits --- lib/mito/fem/DiscreteSystem.h | 2 +- tests/mito.lib/fem/poisson.cc | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/mito/fem/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h index 548012d72..22511de3f 100644 --- a/lib/mito/fem/DiscreteSystem.h +++ b/lib/mito/fem/DiscreteSystem.h @@ -55,7 +55,7 @@ namespace mito::fem { using rhs_assembly_blocks_type = std::vector; public: - // the default constructor + // constructor constexpr DiscreteSystem( const label_type & label, const function_space_type & function_space) : _function_space(function_space), diff --git a/tests/mito.lib/fem/poisson.cc b/tests/mito.lib/fem/poisson.cc index 98a406966..2cb44770e 100644 --- a/tests/mito.lib/fem/poisson.cc +++ b/tests/mito.lib/fem/poisson.cc @@ -61,10 +61,10 @@ TEST(Fem, PoissonSquare) // the zero field auto zero = mito::fields::field(mito::functions::zero); - // get all the nodes on the mesh boundary + // get the boundary mesh auto boundary_mesh = mito::mesh::boundary(mesh); - // the Dirichlet boundary condition + // set homogeneous Dirichlet boundary condition auto constraints = mito::constraints::dirichlet_bc(boundary_mesh, zero); // create the body manifold @@ -112,7 +112,7 @@ TEST(Fem, PoissonSquare) discrete_system.add_lhs_block(fem_lhs_block); discrete_system.add_rhs_block(fem_rhs_block); - // solve the linear system + // solve the system solver.solve(); // free the solver From 136933fbca08395ea57b18cf71c30fe4bc926812 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 5 Oct 2025 10:11:41 +0200 Subject: [PATCH 233/273] fem/poisson.cc: remove addressed questions/todos --- tests/mito.lib/fem/poisson.cc | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/tests/mito.lib/fem/poisson.cc b/tests/mito.lib/fem/poisson.cc index 2cb44770e..63b490b44 100644 --- a/tests/mito.lib/fem/poisson.cc +++ b/tests/mito.lib/fem/poisson.cc @@ -73,9 +73,6 @@ TEST(Fem, PoissonSquare) // the function space (linear elements on the manifold) auto function_space = mito::fem::function_space(manifold, constraints); - // TODO: all top level instances have names. Name should be the first argument. Then we can use - // names in the configuration file and in the hdf5 file. Check libuuid vs. leading namestring. - // // the discrete system auto discrete_system = mito::fem::discrete_system("mysystem", function_space); @@ -83,9 +80,7 @@ TEST(Fem, PoissonSquare) auto solver = mito::solvers::linear_solver(discrete_system); solver.create(); - // QUESTION: do we need a method to set the options for the solver? Can this go in the - // constructor or in the create method? - // in the python layer, this will go in the configuration file + // set options for the matrix solver solver.set_options("-ksp_type preonly -pc_type cholesky"); // a grad-grad matrix block From ddde1fbcd6ea7181d58a7a9cc5e0b7393bf49002 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 5 Oct 2025 10:18:35 +0200 Subject: [PATCH 234/273] fem: implement class {Weakform} This class collects in one place all the blocks to be assembled in the {DiscreteSystem}. --- lib/mito/fem/DiscreteSystem.h | 70 +++------------------ lib/mito/fem/Weakform.h | 115 ++++++++++++++++++++++++++++++++++ lib/mito/fem/api.h | 8 +++ lib/mito/fem/factories.h | 15 ++++- lib/mito/fem/forward.h | 4 ++ lib/mito/fem/public.h | 1 + tests/mito.lib/fem/poisson.cc | 33 +++++----- 7 files changed, 164 insertions(+), 82 deletions(-) create mode 100644 lib/mito/fem/Weakform.h diff --git a/lib/mito/fem/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h index 22511de3f..4b94d35cf 100644 --- a/lib/mito/fem/DiscreteSystem.h +++ b/lib/mito/fem/DiscreteSystem.h @@ -21,6 +21,8 @@ namespace mito::fem { using function_space_type = functionSpaceT; // the element type using element_type = typename function_space_type::element_type; + // the weakform type + using weakform_type = weakform_t; // the linear system type using linear_system_type = linearSystemT; // the label type @@ -39,26 +41,14 @@ namespace mito::fem { // TOFIX: rename to {n_element_nodes} // the number of nodes per element static constexpr int n_nodes = element_type::n_nodes; - // the elementary matrix type - using elementary_matrix_type = tensor::matrix_t; - // the elementary vector type - using elementary_vector_type = tensor::vector_t; - // the type of the lhs assembly block - using lhs_assembly_block_type = - blocks::assembly_block_t; - // a collection of lhs assembly blocks - using lhs_assembly_blocks_type = std::vector; - // the type of the rhs assembly block - using rhs_assembly_block_type = - blocks::assembly_block_t; - // a collection of rhs assembly blocks - using rhs_assembly_blocks_type = std::vector; public: // constructor constexpr DiscreteSystem( - const label_type & label, const function_space_type & function_space) : + const label_type & label, const function_space_type & function_space, + const weakform_type & weakform) : _function_space(function_space), + _weakform(weakform), _equation_map(), _solution_field(nodal_field(function_space, label + ".solution")), _linear_system(label) @@ -148,26 +138,6 @@ namespace mito::fem { // accessor to the linear system constexpr auto linear_system() noexcept -> linear_system_type & { return _linear_system; } - // add a left hand side assembly block - constexpr auto add_lhs_block(const lhs_assembly_block_type & block) -> void - { - // add the block to the collection - _lhs_assembly_blocks.push_back(&block); - - // all done - return; - } - - // add a right hand side assembly block - constexpr auto add_rhs_block(const rhs_assembly_block_type & block) -> void - { - // add the block to the collection - _rhs_assembly_blocks.push_back(&block); - - // all done - return; - } - // assemble the discrete system constexpr auto assemble() -> void { @@ -179,25 +149,8 @@ namespace mito::fem { // // loop on all the cells of the mesh for (const auto & element : _function_space.elements()) { - // instantiate the elementary matrix - auto elementary_matrix = elementary_matrix_type(); - // loop on the left hand side assembly blocks - for (const auto & block : _lhs_assembly_blocks) { - // compute the elementary contribution of the block - auto matrix_block = block->compute(element); - // add the elementary contribution to the elementary matrix - elementary_matrix += matrix_block; - } - - // instantiate the elementary vector - auto elementary_vector = elementary_vector_type(); - // loop on the right hand side assembly blocks - for (const auto & block : _rhs_assembly_blocks) { - // compute the elementary contribution of the block - auto vector_block = block->compute(element); - // add the elementary contribution to the elementary vector - elementary_vector += vector_block; - } + // get the elementary contributions to matrix and right-hand side from the weakform + auto [elementary_matrix, elementary_vector] = _weakform.compute_blocks(element); // assemble the elementary blocks into the linear system of equations tensor::constexpr_for_1([&]() { @@ -367,6 +320,9 @@ namespace mito::fem { // a const reference to the function space const function_space_type & _function_space; + // the weakform + const weakform_type & _weakform; + // the equation map equation_map_type _equation_map; @@ -378,12 +334,6 @@ namespace mito::fem { // the number of equations in the linear system int _n_equations = 0; - - // the collection of left hand side assembly blocks - lhs_assembly_blocks_type _lhs_assembly_blocks; - - // the collection of right hand side assembly blocks - rhs_assembly_blocks_type _rhs_assembly_blocks; }; } // namespace mito diff --git a/lib/mito/fem/Weakform.h b/lib/mito/fem/Weakform.h new file mode 100644 index 000000000..c13961e73 --- /dev/null +++ b/lib/mito/fem/Weakform.h @@ -0,0 +1,115 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + // TODO: concept for element type + template + class Weakform { + + private: + // the element type + using element_type = elementT; + // the number of nodes per element + static constexpr int n_element_nodes = element_type::n_nodes; + // the elementary matrix type + using elementary_matrix_type = tensor::matrix_t; + // the elementary vector type + using elementary_vector_type = tensor::vector_t; + // the type of the lhs assembly block + using lhs_assembly_block_type = + blocks::assembly_block_t; + // a collection of lhs assembly blocks + using lhs_assembly_blocks_type = std::vector; + // the type of the rhs assembly block + using rhs_assembly_block_type = + blocks::assembly_block_t; + // a collection of rhs assembly blocks + using rhs_assembly_blocks_type = std::vector; + + public: + // default constructor + constexpr Weakform() = default; + + // destructor + constexpr ~Weakform() = default; + + // delete move constructor + constexpr Weakform(Weakform &&) noexcept = delete; + + // delete copy constructor + constexpr Weakform(const Weakform &) = delete; + + // delete assignment operator + constexpr Weakform & operator=(const Weakform &) = delete; + + // delete move assignment operator + constexpr Weakform & operator=(Weakform &&) noexcept = delete; + + public: + // add a left hand side assembly block + constexpr auto add_block(const lhs_assembly_block_type & block) -> void + { + // add the block to the collection + _lhs_assembly_blocks.push_back(&block); + + // all done + return; + } + + // add a right hand side assembly block + constexpr auto add_block(const rhs_assembly_block_type & block) -> void + { + // add the block to the collection + _rhs_assembly_blocks.push_back(&block); + + // all done + return; + } + + // compute the elementary contributions to matrix and right-hand side from the weakform + constexpr auto compute_blocks(const element_type & element) const + -> std::pair + { + // instantiate the elementary matrix + auto elementary_matrix = elementary_matrix_type(); + // loop on the left hand side assembly blocks + for (const auto & block : _lhs_assembly_blocks) { + // compute the elementary contribution of the block + auto matrix_block = block->compute(element); + // add the elementary contribution to the elementary matrix + elementary_matrix += matrix_block; + } + + // instantiate the elementary vector + auto elementary_vector = elementary_vector_type(); + // loop on the right hand side assembly blocks + for (const auto & block : _rhs_assembly_blocks) { + // compute the elementary contribution of the block + auto vector_block = block->compute(element); + // add the elementary contribution to the elementary vector + elementary_vector += vector_block; + } + + // return the elementary matrix and vector + return { elementary_matrix, elementary_vector }; + } + + private: + // the collection of left hand side assembly blocks + lhs_assembly_blocks_type _lhs_assembly_blocks; + + // the collection of right hand side assembly blocks + rhs_assembly_blocks_type _rhs_assembly_blocks; + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/fem/api.h b/lib/mito/fem/api.h index 6fbeadd51..435d876e2 100644 --- a/lib/mito/fem/api.h +++ b/lib/mito/fem/api.h @@ -21,6 +21,14 @@ namespace mito::fem { template constexpr auto function_space(const manifoldT & manifold, const constraintsT & constraints); + // weakform alias + template + using weakform_t = Weakform; + + // weakform factory + template + constexpr auto weakform(); + // discrete system alias template using discrete_system_t = DiscreteSystem; diff --git a/lib/mito/fem/factories.h b/lib/mito/fem/factories.h index be23f6e6f..6148588a8 100644 --- a/lib/mito/fem/factories.h +++ b/lib/mito/fem/factories.h @@ -39,11 +39,20 @@ namespace mito::fem { return function_space_t(manifold, constraints); } + // weakform factory + template + constexpr auto weakform() + { + return weakform_t(); + } + // discrete system factory - template - constexpr auto discrete_system(const std::string & label, const functionSpaceT & function_space) + template + constexpr auto discrete_system( + const std::string & label, const functionSpaceT & function_space, + const weakformT & weakform) { - return discrete_system_t(label, function_space); + return discrete_system_t(label, function_space, weakform); } } diff --git a/lib/mito/fem/forward.h b/lib/mito/fem/forward.h index caa8a4bcf..d212e8f4a 100644 --- a/lib/mito/fem/forward.h +++ b/lib/mito/fem/forward.h @@ -22,6 +22,10 @@ namespace mito::fem { }(c); }; + // weakform alias + template + class Weakform; + // class discrete system template class DiscreteSystem; diff --git a/lib/mito/fem/public.h b/lib/mito/fem/public.h index 56a94bbaa..1ce8000ab 100644 --- a/lib/mito/fem/public.h +++ b/lib/mito/fem/public.h @@ -22,6 +22,7 @@ // classes implementation #include "FunctionSpace.h" #include "DiscreteSystem.h" +#include "Weakform.h" // finite elements implementation #include "elements.h" diff --git a/tests/mito.lib/fem/poisson.cc b/tests/mito.lib/fem/poisson.cc index 63b490b44..b59aa14b5 100644 --- a/tests/mito.lib/fem/poisson.cc +++ b/tests/mito.lib/fem/poisson.cc @@ -73,16 +73,6 @@ TEST(Fem, PoissonSquare) // the function space (linear elements on the manifold) auto function_space = mito::fem::function_space(manifold, constraints); - // the discrete system - auto discrete_system = mito::fem::discrete_system("mysystem", function_space); - - // instantiate a linear solver for the discrete system - auto solver = mito::solvers::linear_solver(discrete_system); - solver.create(); - - // set options for the matrix solver - solver.set_options("-ksp_type preonly -pc_type cholesky"); - // a grad-grad matrix block auto fem_lhs_block = mito::fem::blocks::grad_grad_block(); @@ -96,16 +86,21 @@ TEST(Fem, PoissonSquare) auto fem_rhs_block = mito::fem::blocks::source_term_block(f); - // TODO: - // // monolithic discretization matrix = [A, B; C, D] - // auto weakform_lhs = fem_lhs_block; - // auto weakform_rhs = fem_rhs_block; - // auto weakform = weakform(weakform_lhs, weakform_rhs); - // discrete_system.set_weak_form(weakform); + // create the weak form and populate it with the blocks + auto weakform = mito::fem::weakform(); + weakform.add_block(fem_lhs_block); + weakform.add_block(fem_rhs_block); - // add the blocks to the discrete system - discrete_system.add_lhs_block(fem_lhs_block); - discrete_system.add_rhs_block(fem_rhs_block); + // the discrete system + auto discrete_system = + mito::fem::discrete_system("mysystem", function_space, weakform); + + // instantiate a linear solver for the discrete system + auto solver = mito::solvers::linear_solver(discrete_system); + solver.create(); + + // set options for the backend {petsc} matrix solver + solver.set_options("-ksp_type preonly -pc_type cholesky"); // solve the system solver.solve(); From 9460f3b570100e88a6a669715bdd80af738692fa Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 6 Oct 2025 15:01:16 +0200 Subject: [PATCH 235/273] matrix_solvers/petsc: remove call to linear system {create} in the solver {create} method Creating the solver does not require knowing the number of equations. Creating the system does. --- lib/mito/fem/DiscreteSystem.h | 3 +++ .../matrix_solvers/backend/petsc/PETScKrylovSolver.cc | 5 +---- .../matrix_solvers/backend/petsc/PETScKrylovSolver.h | 2 +- lib/mito/solvers/LinearSolver.h | 9 ++++----- tests/mito.lib/fem/poisson.cc | 1 - tests/mito.lib/matrix_solvers/petsc_ksp.cc | 3 ++- 6 files changed, 11 insertions(+), 12 deletions(-) diff --git a/lib/mito/fem/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h index 4b94d35cf..ef08550f3 100644 --- a/lib/mito/fem/DiscreteSystem.h +++ b/lib/mito/fem/DiscreteSystem.h @@ -62,6 +62,9 @@ namespace mito::fem { // print the number of equations channel << "Number of equations: " << _n_equations << journal::endl; + // create the linear system and allocate the memory + _linear_system.create(_n_equations); + // all done return; } diff --git a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc index 11af9e009..4ee548109 100644 --- a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc +++ b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.cc @@ -22,11 +22,8 @@ mito::matrix_solvers::petsc::PETScKrylovSolver::~PETScKrylovSolver() {} // create the Krylov solver auto -mito::matrix_solvers::petsc::PETScKrylovSolver::create(int n_equations) -> void +mito::matrix_solvers::petsc::PETScKrylovSolver::create() -> void { - // create the linear system and allocate the memory - _linear_system.create(n_equations); - // create the Krylov solver PetscCallVoid(KSPCreate(PETSC_COMM_WORLD, &_ksp)); PetscCallVoid(KSPSetOperators(_ksp, _linear_system._matrix, _linear_system._matrix)); diff --git a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h index c7c05d75c..bce47ef3a 100644 --- a/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h +++ b/lib/mito/matrix_solvers/backend/petsc/PETScKrylovSolver.h @@ -29,7 +29,7 @@ namespace mito::matrix_solvers::petsc { public: // create the Krylov solver - auto create(int) -> void; + auto create() -> void; // destroy the Krylov solver auto destroy() -> void; diff --git a/lib/mito/solvers/LinearSolver.h b/lib/mito/solvers/LinearSolver.h index e1ccb2154..397f55a5d 100644 --- a/lib/mito/solvers/LinearSolver.h +++ b/lib/mito/solvers/LinearSolver.h @@ -27,11 +27,10 @@ namespace mito::solvers { constexpr LinearSolver(discrete_system_type & discrete_system) : _discrete_system(discrete_system), _matrix_solver(_discrete_system.linear_system()) - {} - - // TOFIX: the need to explicitly call {create} just holds for petsc matrix solvers... - // create the matrix solver - auto create() -> void { return _matrix_solver.create(_discrete_system.n_equations()); } + { + // create the matrix solver + _matrix_solver.create(); + } // destroy the matrix solver auto destroy() -> void { return _matrix_solver.destroy(); } diff --git a/tests/mito.lib/fem/poisson.cc b/tests/mito.lib/fem/poisson.cc index b59aa14b5..87e5b5d9e 100644 --- a/tests/mito.lib/fem/poisson.cc +++ b/tests/mito.lib/fem/poisson.cc @@ -97,7 +97,6 @@ TEST(Fem, PoissonSquare) // instantiate a linear solver for the discrete system auto solver = mito::solvers::linear_solver(discrete_system); - solver.create(); // set options for the backend {petsc} matrix solver solver.set_options("-ksp_type preonly -pc_type cholesky"); diff --git a/tests/mito.lib/matrix_solvers/petsc_ksp.cc b/tests/mito.lib/matrix_solvers/petsc_ksp.cc index 440c011fd..7cd8294f8 100644 --- a/tests/mito.lib/matrix_solvers/petsc_ksp.cc +++ b/tests/mito.lib/matrix_solvers/petsc_ksp.cc @@ -15,10 +15,11 @@ TEST(Solvers, PETScKSPSolver) // instantiate a PETSc linear system of size {N} auto linear_system = mito::matrix_solvers::petsc::linear_system("mysystem"); + linear_system.create(N); // instantiate a PETSc Krylov solver for the linear system auto solver = mito::matrix_solvers::petsc::ksp(linear_system); - solver.create(N); + solver.create(); solver.set_options("-ksp_monitor"); // set matrix and right-hand side entries From e6ff277e332e6abf0bfed2d654f01fe50e763e9a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 6 Oct 2025 15:01:29 +0200 Subject: [PATCH 236/273] matrix_solvers/petsc: narrative edits --- tests/mito.lib/matrix_solvers/petsc_ksp.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/mito.lib/matrix_solvers/petsc_ksp.cc b/tests/mito.lib/matrix_solvers/petsc_ksp.cc index 7cd8294f8..96090eea5 100644 --- a/tests/mito.lib/matrix_solvers/petsc_ksp.cc +++ b/tests/mito.lib/matrix_solvers/petsc_ksp.cc @@ -15,11 +15,14 @@ TEST(Solvers, PETScKSPSolver) // instantiate a PETSc linear system of size {N} auto linear_system = mito::matrix_solvers::petsc::linear_system("mysystem"); + // create the linear system and allocate the memory linear_system.create(N); // instantiate a PETSc Krylov solver for the linear system auto solver = mito::matrix_solvers::petsc::ksp(linear_system); + // create the Krylov solver and allocate the memory solver.create(); + // set options for the petsc Krylov solver solver.set_options("-ksp_monitor"); // set matrix and right-hand side entries From ed849058323d61a1dd6b95c030b4f02f695819ca Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 12 Oct 2025 09:54:25 +0200 Subject: [PATCH 237/273] geometry: expose the order of reference simplices --- lib/mito/geometry/ReferenceSimplex.h | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/mito/geometry/ReferenceSimplex.h b/lib/mito/geometry/ReferenceSimplex.h index d5d8fbe64..9b1cbb60b 100644 --- a/lib/mito/geometry/ReferenceSimplex.h +++ b/lib/mito/geometry/ReferenceSimplex.h @@ -11,6 +11,9 @@ namespace mito::geometry { template class ReferenceSimplex { + public: + // the order of the reference simplex + constexpr static int order = N; public: // the type of coordinates in the parametric space From 22b8ba0d3d13e68d1f66926b4a7b549d9eae8b4a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 12 Oct 2025 10:06:49 +0200 Subject: [PATCH 238/273] topology: remove unused utility function --- lib/mito/topology/utilities.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/mito/topology/utilities.h b/lib/mito/topology/utilities.h index 8f8ddd8fb..7ba29abe5 100644 --- a/lib/mito/topology/utilities.h +++ b/lib/mito/topology/utilities.h @@ -8,12 +8,6 @@ namespace mito::topology { - // order of simplex - template - constexpr auto order() -> int - { - return cellT::resource_type::order; - } // number of vertices of simplex template From b88440c73d89bf9256c0bbd061b04337cd8eeb85 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 12 Oct 2025 10:25:01 +0200 Subject: [PATCH 239/273] fem: fix typos barycentric -> parametric --- lib/mito/fem/blocks/GradGradBlock.h | 2 +- lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h | 2 +- lib/mito/fem/elements/tri1/ShapeTriangleP1.h | 8 ++++---- lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h | 2 +- lib/mito/fem/elements/tri2/ShapeTriangleP2.h | 4 ++-- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/lib/mito/fem/blocks/GradGradBlock.h b/lib/mito/fem/blocks/GradGradBlock.h index a830fb082..46078bded 100644 --- a/lib/mito/fem/blocks/GradGradBlock.h +++ b/lib/mito/fem/blocks/GradGradBlock.h @@ -43,7 +43,7 @@ namespace mito::fem::blocks { // loop on the quadrature points tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point + // the parametric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); // precompute the common factor diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index c4c74fbd9..db9a45249 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -21,7 +21,7 @@ namespace mito::fem { static constexpr int degree = 1; // the type of shape functions using shape_functions_type = ShapeTriangleP1; - // the barycentric coordinates type + // the parametric coordinates type using parametric_coordinates_type = typename shape_functions_type::parametric_coordinates_type; // the linear shape functions diff --git a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h index f79746086..ddd4bb799 100644 --- a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h +++ b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h @@ -14,14 +14,14 @@ namespace mito::fem { public: // the reference element using reference_element_type = geometry::reference_triangle_t; - // the barycentric coordinates type + // the parametric coordinates type using parametric_coordinates_type = typename reference_element_type::parametric_coordinates_type; // the number of shape functions static constexpr int N = 3; private: - // linear shape functions on the reference triangle in barycentric coordinates + // linear shape functions on the reference triangle in parametric coordinates static constexpr auto xi_0 = reference_element_type::xi<0>; static constexpr auto xi_1 = reference_element_type::xi<1>; static constexpr auto xi_2 = 1.0 - xi_0 - xi_1; @@ -39,7 +39,7 @@ namespace mito::fem { fields::gradient(phi_0), fields::gradient(phi_1), fields::gradient(phi_2)); public: - // get the a-th shape function as a function of barycentric coordinates + // get the a-th shape function as a function of parametric coordinates template requires(a >= 0 && a < N) constexpr auto shape() const @@ -48,7 +48,7 @@ namespace mito::fem { return std::get(phi); } - // get the a-th shape function's derivative as a function of barycentric coordinates + // get the a-th shape function's derivative as a function of parametric coordinates template requires(a >= 0 && a < N) constexpr auto dshape() const diff --git a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h index 665092729..f76a91b7b 100644 --- a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h @@ -21,7 +21,7 @@ namespace mito::fem { static constexpr int degree = 2; // the type of shape functions using shape_functions_type = ShapeTriangleP2; - // type of a point in barycentric coordinates + // type of a point in parametric coordinates using parametric_coordinates_type = typename shape_functions_type::reference_element_type::parametric_coordinates_type; // the linear shape functions diff --git a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h index 47b869cf4..0640fb564 100644 --- a/lib/mito/fem/elements/tri2/ShapeTriangleP2.h +++ b/lib/mito/fem/elements/tri2/ShapeTriangleP2.h @@ -40,7 +40,7 @@ namespace mito::fem { fields::gradient(phi_3), fields::gradient(phi_4), fields::gradient(phi_5)); public: - // get the a-th shape function as a function of barycentric coordinates + // get the a-th shape function as a function of parametric coordinates template requires(a >= 0 && a < N) constexpr auto shape() const @@ -49,7 +49,7 @@ namespace mito::fem { return std::get(phi); } - // get the a-th shape function's gradient as a function of barycentric coordinates + // get the a-th shape function's gradient as a function of parametric coordinates template requires(a >= 0 && a < N) constexpr auto dshape() const From 2c6b556ca7b74bb6074a3612abdc9ee7814715b6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 12 Oct 2025 10:28:27 +0200 Subject: [PATCH 240/273] fem/elements: consistency edit --- lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h | 2 +- lib/mito/fem/elements/tri1/ShapeTriangleP1.h | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index db9a45249..387bff298 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -23,7 +23,7 @@ namespace mito::fem { using shape_functions_type = ShapeTriangleP1; // the parametric coordinates type using parametric_coordinates_type = - typename shape_functions_type::parametric_coordinates_type; + typename shape_functions_type::reference_element_type::parametric_coordinates_type; // the linear shape functions static constexpr auto shape_functions = shape_functions_type(); // the number of discretization discretization nodes diff --git a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h index ddd4bb799..f90867ba6 100644 --- a/lib/mito/fem/elements/tri1/ShapeTriangleP1.h +++ b/lib/mito/fem/elements/tri1/ShapeTriangleP1.h @@ -14,9 +14,6 @@ namespace mito::fem { public: // the reference element using reference_element_type = geometry::reference_triangle_t; - // the parametric coordinates type - using parametric_coordinates_type = - typename reference_element_type::parametric_coordinates_type; // the number of shape functions static constexpr int N = 3; From 92a5fdd7a99d42b21ba3a5b7fa1cc29eaee2eaf0 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 13 Oct 2025 15:19:03 +0200 Subject: [PATCH 241/273] fem/blocks: bugfix in blocks (grad-grad, source, L2) In the numerical integration, the quadrature weights should be multiplied by the area of the canonical elements. --- lib/mito/fem/blocks/GradGradBlock.h | 7 +++++-- lib/mito/fem/blocks/L2NormBlock.h | 11 ++++++++--- lib/mito/fem/blocks/SourceTermBlock.h | 7 +++++-- lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h | 4 +++- lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h | 4 +++- lib/mito/geometry/ReferenceSimplex.h | 3 +++ 6 files changed, 27 insertions(+), 9 deletions(-) diff --git a/lib/mito/fem/blocks/GradGradBlock.h b/lib/mito/fem/blocks/GradGradBlock.h index 46078bded..e511ea2f0 100644 --- a/lib/mito/fem/blocks/GradGradBlock.h +++ b/lib/mito/fem/blocks/GradGradBlock.h @@ -46,9 +46,12 @@ namespace mito::fem::blocks { // the parametric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); + // the quadrature weight at this point scaled with the area of the canonical simplex + constexpr auto w = + element_type::canonical_element_type::area * quadrature_rule.weight(q); + // precompute the common factor - auto factor = - quadrature_rule.weight(q) * tensor::determinant(element.jacobian()(xi)); + auto factor = w * tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { diff --git a/lib/mito/fem/blocks/L2NormBlock.h b/lib/mito/fem/blocks/L2NormBlock.h index eff2ebddd..c80dbbd7c 100644 --- a/lib/mito/fem/blocks/L2NormBlock.h +++ b/lib/mito/fem/blocks/L2NormBlock.h @@ -50,10 +50,15 @@ namespace mito::fem::blocks { // the barycentric coordinates of the quadrature point constexpr auto xi = quadrature_rule.point(q); + // the quadrature weight at this point scaled with the area of the canonical simplex + constexpr auto w = + element_type::canonical_element_type::area * quadrature_rule.weight(q); + + // precompute the common factor + auto factor = w * tensor::determinant(element.jacobian()(xi)); + // populate the elementary contribution to the matrix - elementary_contribution += quadrature_rule.weight(q) - * tensor::determinant(element.jacobian()(xi)) - * _function(xi) * _function(xi); + elementary_contribution += factor * _function(xi) * _function(xi); }); // all done diff --git a/lib/mito/fem/blocks/SourceTermBlock.h b/lib/mito/fem/blocks/SourceTermBlock.h index 0a3a74b13..021e3b493 100644 --- a/lib/mito/fem/blocks/SourceTermBlock.h +++ b/lib/mito/fem/blocks/SourceTermBlock.h @@ -55,9 +55,12 @@ namespace mito::fem::blocks { // the coordinates of the quadrature point auto coord = element.parametrization()(xi); + // the quadrature weight at this point scaled with the area of the canonical simplex + constexpr auto w = + element_type::canonical_element_type::area * quadrature_rule.weight(q); + // precompute the common factor - auto factor = - quadrature_rule.weight(q) * tensor::determinant(element.jacobian()(xi)); + auto factor = w * tensor::determinant(element.jacobian()(xi)); // loop on the nodes of the element tensor::constexpr_for_1([&]() { diff --git a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h index 387bff298..fcd527d92 100644 --- a/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h +++ b/lib/mito/fem/elements/tri1/IsoparametricTriangleP1.h @@ -21,9 +21,11 @@ namespace mito::fem { static constexpr int degree = 1; // the type of shape functions using shape_functions_type = ShapeTriangleP1; + // the canonical element type + using canonical_element_type = typename shape_functions_type::reference_element_type; // the parametric coordinates type using parametric_coordinates_type = - typename shape_functions_type::reference_element_type::parametric_coordinates_type; + typename canonical_element_type::parametric_coordinates_type; // the linear shape functions static constexpr auto shape_functions = shape_functions_type(); // the number of discretization discretization nodes diff --git a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h index f76a91b7b..8248875df 100644 --- a/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h +++ b/lib/mito/fem/elements/tri2/IsoparametricTriangleP2.h @@ -21,9 +21,11 @@ namespace mito::fem { static constexpr int degree = 2; // the type of shape functions using shape_functions_type = ShapeTriangleP2; + // the canonical element type + using canonical_element_type = typename shape_functions_type::reference_element_type; // type of a point in parametric coordinates using parametric_coordinates_type = - typename shape_functions_type::reference_element_type::parametric_coordinates_type; + typename canonical_element_type::parametric_coordinates_type; // the linear shape functions static constexpr auto shape_functions = shape_functions_type(); // the number of discretization nodes diff --git a/lib/mito/geometry/ReferenceSimplex.h b/lib/mito/geometry/ReferenceSimplex.h index 9b1cbb60b..6b94a0bd4 100644 --- a/lib/mito/geometry/ReferenceSimplex.h +++ b/lib/mito/geometry/ReferenceSimplex.h @@ -15,6 +15,9 @@ namespace mito::geometry { // the order of the reference simplex constexpr static int order = N; + // the area of the reference simplex + constexpr static double area = 1.0 / mito::tensor::factorial(); + public: // the type of coordinates in the parametric space using parametric_coordinates_type = coordinates_t; From 43dd2ca4ddcb128ceb3ffabc3756ce2716d6a662 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 13 Oct 2025 15:19:39 +0200 Subject: [PATCH 242/273] fem/blocks: add mass matrix block --- lib/mito/fem/blocks/MassBlock.h | 76 +++++++++++++++++++++++++++++++++ lib/mito/fem/blocks/api.h | 8 ++++ lib/mito/fem/blocks/factories.h | 8 ++++ lib/mito/fem/blocks/forward.h | 4 ++ lib/mito/fem/blocks/public.h | 1 + 5 files changed, 97 insertions(+) create mode 100644 lib/mito/fem/blocks/MassBlock.h diff --git a/lib/mito/fem/blocks/MassBlock.h b/lib/mito/fem/blocks/MassBlock.h new file mode 100644 index 000000000..ca4500a72 --- /dev/null +++ b/lib/mito/fem/blocks/MassBlock.h @@ -0,0 +1,76 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem::blocks { + + template + class MassBlock : public AssemblyBlock> { + + public: + // my parent class + using parent_type = AssemblyBlock>; + + // my template parameters + using element_type = typename parent_type::element_type; + using elementary_block_type = typename parent_type::elementary_block_type; + using quadrature_rule_type = quadratureRuleT; + + public: + // instantiate the quadrature rule + static constexpr auto quadrature_rule = quadrature_rule_type(); + + public: + // compute the elementary contribution of this block + auto compute(const element_type & element) const -> elementary_block_type override + { + // the number of nodes per element + constexpr int n_nodes = element_type::n_nodes; + + // the number of quadrature points per element + constexpr int n_quads = quadrature_rule_type::npoints; + + // the elementary matrix + elementary_block_type elementary_matrix; + + // loop on the quadrature points + tensor::constexpr_for_1([&]() { + // the parametric coordinates of the quadrature point + constexpr auto xi = quadrature_rule.point(q); + + // the quadrature weight at this point scaled with the area of the canonical simplex + constexpr auto w = + element_type::canonical_element_type::area * quadrature_rule.weight(q); + + // precompute the common factor + auto factor = w * tensor::determinant(element.jacobian()(xi)); + + // loop on the nodes of the element + tensor::constexpr_for_1([&]() { + // evaluate the spatial gradient of the element's a-th shape function at {xi} + auto phi_a = element.template shape()(xi); + // loop on the nodes of the element + tensor::constexpr_for_1([&]() { + // evaluate the spatial gradient of the element's b-th shape function at + // {xi} + auto phi_b = element.template shape()(xi); + // populate the elementary contribution to the matrix + elementary_matrix[{ a, b }] += factor * phi_a * phi_b; + }); + }); + }); + + // all done + return elementary_matrix; + } + }; + +} // namespace mito + + +// end of file diff --git a/lib/mito/fem/blocks/api.h b/lib/mito/fem/blocks/api.h index 2bbbb7a4d..e68a2584b 100644 --- a/lib/mito/fem/blocks/api.h +++ b/lib/mito/fem/blocks/api.h @@ -21,6 +21,14 @@ namespace mito::fem::blocks { template constexpr auto grad_grad_block(); + // mass block + template + using mass_block_t = MassBlock; + + // mass block factory + template + constexpr auto mass_block(); + // source term block template using source_term_block_t = SourceTermBlock; diff --git a/lib/mito/fem/blocks/factories.h b/lib/mito/fem/blocks/factories.h index dd906a0f6..014e0a95a 100644 --- a/lib/mito/fem/blocks/factories.h +++ b/lib/mito/fem/blocks/factories.h @@ -17,6 +17,14 @@ namespace mito::fem::blocks { return grad_grad_block_t(); } + // mass block factory + template + constexpr auto mass_block() + { + // all done + return mass_block_t(); + } + // source term block factory template constexpr auto source_term_block(const sourceFieldT & f) diff --git a/lib/mito/fem/blocks/forward.h b/lib/mito/fem/blocks/forward.h index adbf4e276..ec91f5397 100644 --- a/lib/mito/fem/blocks/forward.h +++ b/lib/mito/fem/blocks/forward.h @@ -17,6 +17,10 @@ namespace mito::fem::blocks { template class GradGradBlock; + // mass block + template + class MassBlock; + // source term block template class SourceTermBlock; diff --git a/lib/mito/fem/blocks/public.h b/lib/mito/fem/blocks/public.h index a5ede3d94..f212c0ad6 100644 --- a/lib/mito/fem/blocks/public.h +++ b/lib/mito/fem/blocks/public.h @@ -19,6 +19,7 @@ // classes implementation #include "AssemblyBlock.h" #include "GradGradBlock.h" +#include "MassBlock.h" #include "SourceTermBlock.h" #include "L2NormBlock.h" From 1cd55eb9392a57410ed29bcbf553446368fbb8e3 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 13 Oct 2025 15:21:28 +0200 Subject: [PATCH 243/273] fem/blocks: add unit tests for grad-grad and mass blocks --- .cmake/mito_tests_mito_lib.cmake | 2 + lib/mito/fem/blocks/GradGradBlock.h | 3 - tests/mito.lib/fem/block_grad_grad.cc | 117 ++++++++++++ tests/mito.lib/fem/block_mass.cc | 115 ++++++++++++ tests/mito.lib/fem/isoparametric_triangle.cc | 179 ------------------- 5 files changed, 234 insertions(+), 182 deletions(-) create mode 100644 tests/mito.lib/fem/block_grad_grad.cc create mode 100644 tests/mito.lib/fem/block_mass.cc diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 3ae452d90..682c70d71 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -46,6 +46,8 @@ mito_test_driver(tests/mito.lib/discrete/mesh_field.cc) # fem mito_test_driver(tests/mito.lib/fem/poisson.cc) +mito_test_driver(tests/mito.lib/fem/block_grad_grad.cc) +mito_test_driver(tests/mito.lib/fem/block_mass.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) diff --git a/lib/mito/fem/blocks/GradGradBlock.h b/lib/mito/fem/blocks/GradGradBlock.h index e511ea2f0..340e76403 100644 --- a/lib/mito/fem/blocks/GradGradBlock.h +++ b/lib/mito/fem/blocks/GradGradBlock.h @@ -9,9 +9,6 @@ namespace mito::fem::blocks { - // TODO: implement sum and subtraction operators for the blocks (only for blocks that result in - // the same elementary type) - template class GradGradBlock : public AssemblyBlock> { diff --git a/tests/mito.lib/fem/block_grad_grad.cc b/tests/mito.lib/fem/block_grad_grad.cc new file mode 100644 index 000000000..80354f3f3 --- /dev/null +++ b/tests/mito.lib/fem/block_grad_grad.cc @@ -0,0 +1,117 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; +// the type of coordinate system +using coord_system_t = mito::geometry::coordinate_system_t; +// the type of discretization node +using discretization_node_t = mito::discrete::discretization_node_t; +// the type of cell +using cell_t = mito::geometry::triangle_t<2>; +// the reference simplex +using reference_simplex_t = mito::geometry::reference_triangle_t; +// Gauss quadrature on triangles with degree of exactness 4 +using quadrature_rule_t = + mito::quadrature::quadrature_rule_t; + +// instantiate the quadrature rule +constexpr auto quadrature_rule = quadrature_rule_t(); + + +TEST(Fem, IsoparametricTriangle) +{ + // the coordinate system + auto coord_system = coord_system_t(); + + // build nodes + auto node_0 = mito::geometry::node(coord_system, { 0.0, 0.0 }); + auto node_1 = mito::geometry::node(coord_system, { 1.0, 0.0 }); + auto node_2 = mito::geometry::node(coord_system, { 0.0, 1.0 }); + + // make a geometric simplex + auto geometric_simplex = mito::geometry::triangle<2>({ node_0, node_1, node_2 }); + + { + // first order isoparametric triangle + using element_p1_t = mito::fem::isoparametric_simplex<1, cell_t>::type; + + // build the discretization nodes + auto discretization_node_0 = discretization_node_t(); + auto discretization_node_1 = discretization_node_t(); + auto discretization_node_2 = discretization_node_t(); + + // a finite element + auto element_p1 = element_p1_t( + geometric_simplex, coord_system, + { discretization_node_0, discretization_node_1, discretization_node_2 }); + + // a grad-grad matrix block + auto grad_grad_block = + mito::fem::blocks::grad_grad_block(); + + // the analytical elementary stiffness matrix + auto analytical_block = 1.0 / 2.0 * mito::tensor::matrix_t<3>{ 2.0, -1.0, -1.0, -1.0, 1.0, + 0.0, -1.0, 0.0, 1.0 }; + + // compute the elementary contribution of the block + auto computed_block = grad_grad_block.compute(element_p1); + + // compute the error + auto error = mito::tensor::norm(computed_block - analytical_block); + + // check the error is reasonable + EXPECT_NEAR(0.0, error, 1.e-14); + } + + { + // second order isoparametric triangle + using element_p2_t = mito::fem::isoparametric_simplex<2, cell_t>::type; + + // build the discretization nodes + auto discretization_node_0 = discretization_node_t(); + auto discretization_node_1 = discretization_node_t(); + auto discretization_node_2 = discretization_node_t(); + auto discretization_node_3 = discretization_node_t(); + auto discretization_node_4 = discretization_node_t(); + auto discretization_node_5 = discretization_node_t(); + + // a finite element + auto element_p2 = element_p2_t( + geometric_simplex, coord_system, + { discretization_node_0, discretization_node_1, discretization_node_2, + discretization_node_3, discretization_node_4, discretization_node_5 }); + + // a grad-grad matrix block + auto grad_grad_block = + mito::fem::blocks::grad_grad_block(); + + // the analytical elementary stiffness matrix + auto analytical_block = mito::tensor::matrix_t<6>{ + 1.0, 1.0 / 6.0, 1.0 / 6.0, -2.0 / 3.0, 0.0, -2.0 / 3.0, + 1.0 / 6.0, 1.0 / 2.0, 0.0, -2.0 / 3.0, 0.0, 0.0, + 1.0 / 6.0, 0.0, 1.0 / 2.0, 0.0, 0.0, -2.0 / 3.0, + -2.0 / 3.0, -2.0 / 3.0, 0.0, 8.0 / 3.0, -4.0 / 3.0, 0.0, + 0.0, 0.0, 0.0, -4.0 / 3.0, 8.0 / 3.0, -4.0 / 3.0, + -2.0 / 3.0, 0.0, -2.0 / 3.0, 0.0, -4.0 / 3.0, 8.0 / 3.0 + }; + + // compute the elementary contribution of the block + auto computed_block = grad_grad_block.compute(element_p2); + + // compute the error + auto error = mito::tensor::norm(computed_block - analytical_block); + + // check the error is reasonable + EXPECT_NEAR(0.0, error, 1.e-14); + } + + // all done + return; +} \ No newline at end of file diff --git a/tests/mito.lib/fem/block_mass.cc b/tests/mito.lib/fem/block_mass.cc new file mode 100644 index 000000000..b03d86822 --- /dev/null +++ b/tests/mito.lib/fem/block_mass.cc @@ -0,0 +1,115 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +#include +#include + + +// the type of coordinates +using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; +// the type of coordinate system +using coord_system_t = mito::geometry::coordinate_system_t; +// the type of discretization node +using discretization_node_t = mito::discrete::discretization_node_t; +// the type of cell +using cell_t = mito::geometry::triangle_t<2>; +// the reference simplex +using reference_simplex_t = mito::geometry::reference_triangle_t; +// Gauss quadrature on triangles with degree of exactness 4 +using quadrature_rule_t = + mito::quadrature::quadrature_rule_t; + +// instantiate the quadrature rule +constexpr auto quadrature_rule = quadrature_rule_t(); + + +TEST(Fem, IsoparametricTriangle) +{ + // the coordinate system + auto coord_system = coord_system_t(); + + // build nodes + auto node_0 = mito::geometry::node(coord_system, { 0.0, 0.0 }); + auto node_1 = mito::geometry::node(coord_system, { 1.0, 0.0 }); + auto node_2 = mito::geometry::node(coord_system, { 0.0, 1.0 }); + + // make a geometric simplex + auto geometric_simplex = mito::geometry::triangle<2>({ node_0, node_1, node_2 }); + + { + // first order isoparametric triangle + using element_p1_t = mito::fem::isoparametric_simplex<1, cell_t>::type; + + // build the discretization nodes + auto discretization_node_0 = discretization_node_t(); + auto discretization_node_1 = discretization_node_t(); + auto discretization_node_2 = discretization_node_t(); + + // a finite element + auto element_p1 = element_p1_t( + geometric_simplex, coord_system, + { discretization_node_0, discretization_node_1, discretization_node_2 }); + + // a mass matrix block + auto mass_block = mito::fem::blocks::mass_block(); + + // the analytical elementary mass matrix + auto analytical_block = + 1.0 / 24.0 * mito::tensor::matrix_t<3>{ 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0 }; + + // compute the elementary contribution of the block + auto computed_block = mass_block.compute(element_p1); + + // compute the error + auto error = mito::tensor::norm(computed_block - analytical_block); + + // check the error is reasonable + EXPECT_NEAR(0.0, error, 1.e-14); + } + + { + // second order isoparametric triangle + using element_p2_t = mito::fem::isoparametric_simplex<2, cell_t>::type; + + // build the discretization nodes + auto discretization_node_0 = discretization_node_t(); + auto discretization_node_1 = discretization_node_t(); + auto discretization_node_2 = discretization_node_t(); + auto discretization_node_3 = discretization_node_t(); + auto discretization_node_4 = discretization_node_t(); + auto discretization_node_5 = discretization_node_t(); + + // a finite element + auto element_p2 = element_p2_t( + geometric_simplex, coord_system, + { discretization_node_0, discretization_node_1, discretization_node_2, + discretization_node_3, discretization_node_4, discretization_node_5 }); + + // a mass matrix block + auto mass_block = mito::fem::blocks::mass_block(); + + // the analytical elementary mass matrix + auto analytical_block = mito::tensor::matrix_t<6>{ + 1.0 / 60.0, -1.0 / 360.0, -1.0 / 360.0, 0.0, -1.0 / 90.0, 0.0, + -1.0 / 360.0, 1.0 / 60.0, -1.0 / 360.0, 0.0, 0.0, -1.0 / 90.0, + -1.0 / 360.0, -1.0 / 360.0, 1.0 / 60.0, -1.0 / 90.0, 0.0, 0.0, + 0.0, 0.0, -1.0 / 90.0, 4.0 / 45.0, 2.0 / 45.0, 2.0 / 45.0, + -1.0 / 90.0, 0.0, 0.0, 2.0 / 45.0, 4.0 / 45.0, 2.0 / 45.0, + 0.0, -1.0 / 90.0, 0.0, 2.0 / 45.0, 2.0 / 45.0, 4.0 / 45.0 + }; + + // compute the elementary contribution of the block + auto computed_block = mass_block.compute(element_p2); + + // compute the error + auto error = mito::tensor::norm(computed_block - analytical_block); + + // check the error is reasonable + EXPECT_NEAR(0.0, error, 1.e-14); + } + + // all done + return; +} \ No newline at end of file diff --git a/tests/mito.lib/fem/isoparametric_triangle.cc b/tests/mito.lib/fem/isoparametric_triangle.cc index 7b9cf7dc5..82fa5d34e 100644 --- a/tests/mito.lib/fem/isoparametric_triangle.cc +++ b/tests/mito.lib/fem/isoparametric_triangle.cc @@ -20,8 +20,6 @@ using reference_simplex_t = mito::geometry::reference_triangle_t; // Gauss quadrature on triangles with degree of exactness 4 using quadrature_rule_t = mito::quadrature::quadrature_rule_t; -// the equation map type (map associating an equation number to each node degree of freedom) -using equation_map_type = std::map; // instantiate the quadrature rule @@ -89,125 +87,6 @@ test_gradient_consistency(const auto & element) return; } -// test that the elementary stiffness matrix is computed correctly -template -auto -test_stiffness_matrix( - const elementT & element, const equation_map_type & equation_map, - const mito::tensor::matrix_t & analytical_stiffness_matrix) -> void -{ - // create reporting channel - journal::info_t channel("test_stiffness_matrix"); - - // the number of quadrature points per element - constexpr int n_quads = quadrature_rule_t::npoints; - - // the number of nodes per element - constexpr int n_nodes = elementT::n_nodes; - - // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix - auto elementary_stiffness_matrix = mito::tensor::matrix_t{}; - - // loop on the quadrature points - mito::tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point - constexpr auto xi = quadrature_rule.point(q); - - // area of the cell - auto area = 0.5 * mito::tensor::determinant(element.jacobian()(xi)); - - // precompute the common factor for integration - auto factor = quadrature_rule.weight(q) * area; - - // populate the stiffness matrix - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // evaluate the spatial gradient of the element's a-th shape function at {xi} - auto dphi_a = element.template gradient()(xi); - // get the equation number of {node_a} - int i = equation_map.at(node_a); - mito::tensor::constexpr_for_1([&]() { - // get the b-th discretization node of the element - const auto & node_b = element.connectivity()[b]; - // evaluate the spatial gradient of the element's b-th shape function at {xi} - auto dphi_b = element.template gradient()(xi); - // get the equation number of {node_b} - int j = equation_map.at(node_b); - // assemble the {node_a, node_b} contribution to the mass matrix - elementary_stiffness_matrix[{ i, j }] += factor * dphi_a * dphi_b; - }); - }); - }); - - // compute the error - auto error = mito::tensor::norm(elementary_stiffness_matrix - analytical_stiffness_matrix); - - // check the error is reasonable - EXPECT_NEAR(0.0, error, 1.e-14); - - // all done - return; -} - -// test that the elementary mass matrix is computed correctly -template -auto -test_mass_matrix( - const elementT & element, const equation_map_type & equation_map, - const mito::tensor::matrix_t & analytical_mass_matrix) -> void -{ - // create reporting channel - journal::info_t channel("test_mass_matrix"); - - // the number of quadrature points per element - constexpr int n_quads = quadrature_rule_t::npoints; - - // the number of nodes per element - constexpr int n_nodes = elementT::n_nodes; - - // create a {n_nodes}x{n_nodes} matrix to store the elementary stiffness matrix - auto elementary_mass_matrix = mito::tensor::matrix_t{}; - - // loop on the quadrature points - mito::tensor::constexpr_for_1([&]() { - // the barycentric coordinates of the quadrature point - constexpr auto xi = quadrature_rule.point(q); - - // area of the cell - auto factor = - 0.5 * mito::tensor::determinant(element.jacobian()(xi)) * quadrature_rule.weight(q); - - // populate the mass matrix - mito::tensor::constexpr_for_1([&]() { - // get the a-th discretization node of the element - const auto & node_a = element.connectivity()[a]; - // evaluate element's a-th shape function at {xi} - auto phi_a = element.template shape()(xi); - // get the equation number of {node_a} - int i = equation_map.at(node_a); - mito::tensor::constexpr_for_1([&]() { - // get the b-th discretization node of the element - const auto & node_b = element.connectivity()[b]; - // evaluate element's b-th shape function at {xi} - auto phi_b = element.template shape()(xi); - // get the equation number of {node_b} - int j = equation_map.at(node_b); - // assemble the {node_a, node_b} contribution to the mass matrix - elementary_mass_matrix[{ i, j }] += factor * phi_a * phi_b; - }); - }); - }); - - // compute the error - auto error = mito::tensor::norm(elementary_mass_matrix - analytical_mass_matrix); - - // check the error is reasonable - EXPECT_NEAR(0.0, error, 1.e-14); - - // all done - return; -} TEST(Fem, IsoparametricTriangle) { @@ -241,28 +120,6 @@ TEST(Fem, IsoparametricTriangle) // check that the gradients of first order shape functions sum to 0.0 test_gradient_consistency(element_p1); - - // the map between the discretization nodes and the equation numbers - equation_map_type equation_map; - - // populate the equation map - equation_map[discretization_node_0] = 0; - equation_map[discretization_node_1] = 1; - equation_map[discretization_node_2] = 2; - - // the analytical elementary stiffness matrix - auto analytical_stiffness_matrix = - 1.0 / 2.0 - * mito::tensor::matrix_t<3>{ 2.0, -1.0, -1.0, -1.0, 1.0, 0.0, -1.0, 0.0, 1.0 }; - - // check that the elementary stiffness matrix is computed correctly - test_stiffness_matrix(element_p1, equation_map, analytical_stiffness_matrix); - - // the analytical elementary mass matrix - auto analytical_mass_matrix = - 1.0 / 24.0 * mito::tensor::matrix_t<3>{ 2.0, 1.0, 1.0, 1.0, 2.0, 1.0, 1.0, 1.0, 2.0 }; - - test_mass_matrix(element_p1, equation_map, analytical_mass_matrix); } { @@ -288,42 +145,6 @@ TEST(Fem, IsoparametricTriangle) // check that the gradients of second order shape functions sum to 0.0 test_gradient_consistency(element_p2); - - // the map between the discretization nodes and the equation numbers - equation_map_type equation_map; - - // populate the equation map - equation_map[discretization_node_0] = 0; - equation_map[discretization_node_1] = 1; - equation_map[discretization_node_2] = 2; - equation_map[discretization_node_3] = 3; - equation_map[discretization_node_4] = 4; - equation_map[discretization_node_5] = 5; - - // the analytical elementary stiffness matrix - auto analytical_stiffness_matrix = mito::tensor::matrix_t<6>{ - 1.0, 1.0 / 6.0, 1.0 / 6.0, -2.0 / 3.0, 0.0, -2.0 / 3.0, - 1.0 / 6.0, 1.0 / 2.0, 0.0, -2.0 / 3.0, 0.0, 0.0, - 1.0 / 6.0, 0.0, 1.0 / 2.0, 0.0, 0.0, -2.0 / 3.0, - -2.0 / 3.0, -2.0 / 3.0, 0.0, 8.0 / 3.0, -4.0 / 3.0, 0.0, - 0.0, 0.0, 0.0, -4.0 / 3.0, 8.0 / 3.0, -4.0 / 3.0, - -2.0 / 3.0, 0.0, -2.0 / 3.0, 0.0, -4.0 / 3.0, 8.0 / 3.0 - }; - - // check that the elementary stiffness matrix is computed correctly - test_stiffness_matrix(element_p2, equation_map, analytical_stiffness_matrix); - - // the analytical elementary mass matrix - auto analytical_mass_matrix = mito::tensor::matrix_t<6>{ - 1.0 / 60.0, -1.0 / 360.0, -1.0 / 360.0, 0.0, -1.0 / 90.0, 0.0, - -1.0 / 360.0, 1.0 / 60.0, -1.0 / 360.0, 0.0, 0.0, -1.0 / 90.0, - -1.0 / 360.0, -1.0 / 360.0, 1.0 / 60.0, -1.0 / 90.0, 0.0, 0.0, - 0.0, 0.0, -1.0 / 90.0, 4.0 / 45.0, 2.0 / 45.0, 2.0 / 45.0, - -1.0 / 90.0, 0.0, 0.0, 2.0 / 45.0, 4.0 / 45.0, 2.0 / 45.0, - 0.0, -1.0 / 90.0, 0.0, 2.0 / 45.0, 2.0 / 45.0, 4.0 / 45.0 - }; - - test_mass_matrix(element_p2, equation_map, analytical_mass_matrix); } // all done From 456f28f4b39ecee7e107cbbb685fc1c18c940e23 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 13 Oct 2025 19:57:20 +0200 Subject: [PATCH 244/273] fem/blocks: tighten tolerances on error checks --- tests/mito.lib/fem/block_grad_grad.cc | 6 +++--- tests/mito.lib/fem/block_mass.cc | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/tests/mito.lib/fem/block_grad_grad.cc b/tests/mito.lib/fem/block_grad_grad.cc index 80354f3f3..22e4816be 100644 --- a/tests/mito.lib/fem/block_grad_grad.cc +++ b/tests/mito.lib/fem/block_grad_grad.cc @@ -66,8 +66,8 @@ TEST(Fem, IsoparametricTriangle) // compute the error auto error = mito::tensor::norm(computed_block - analytical_block); - // check the error is reasonable - EXPECT_NEAR(0.0, error, 1.e-14); + // check the error is zero to machine precision + EXPECT_DOUBLE_EQ(0.0, error); } { @@ -109,7 +109,7 @@ TEST(Fem, IsoparametricTriangle) auto error = mito::tensor::norm(computed_block - analytical_block); // check the error is reasonable - EXPECT_NEAR(0.0, error, 1.e-14); + EXPECT_NEAR(0.0, error, 1.e-15); } // all done diff --git a/tests/mito.lib/fem/block_mass.cc b/tests/mito.lib/fem/block_mass.cc index b03d86822..e502547e9 100644 --- a/tests/mito.lib/fem/block_mass.cc +++ b/tests/mito.lib/fem/block_mass.cc @@ -66,7 +66,7 @@ TEST(Fem, IsoparametricTriangle) auto error = mito::tensor::norm(computed_block - analytical_block); // check the error is reasonable - EXPECT_NEAR(0.0, error, 1.e-14); + EXPECT_NEAR(0.0, error, 1.e-16); } { @@ -107,7 +107,7 @@ TEST(Fem, IsoparametricTriangle) auto error = mito::tensor::norm(computed_block - analytical_block); // check the error is reasonable - EXPECT_NEAR(0.0, error, 1.e-14); + EXPECT_NEAR(0.0, error, 1.e-16); } // all done From cd60182ca4794cc29c1835cb7e5156a302a3df63 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 13 Oct 2025 20:05:17 +0200 Subject: [PATCH 245/273] fem/blocks: minor readability improvements to blocks --- lib/mito/fem/blocks/GradGradBlock.h | 7 ++----- lib/mito/fem/blocks/L2NormBlock.h | 7 ++----- lib/mito/fem/blocks/MassBlock.h | 7 ++----- lib/mito/fem/blocks/SourceTermBlock.h | 7 ++----- 4 files changed, 8 insertions(+), 20 deletions(-) diff --git a/lib/mito/fem/blocks/GradGradBlock.h b/lib/mito/fem/blocks/GradGradBlock.h index 340e76403..68fd7d1b2 100644 --- a/lib/mito/fem/blocks/GradGradBlock.h +++ b/lib/mito/fem/blocks/GradGradBlock.h @@ -13,12 +13,9 @@ namespace mito::fem::blocks { class GradGradBlock : public AssemblyBlock> { public: - // my parent class - using parent_type = AssemblyBlock>; - // my template parameters - using element_type = typename parent_type::element_type; - using elementary_block_type = typename parent_type::elementary_block_type; + using element_type = elementT; + using elementary_block_type = tensor::matrix_t; using quadrature_rule_type = quadratureRuleT; public: diff --git a/lib/mito/fem/blocks/L2NormBlock.h b/lib/mito/fem/blocks/L2NormBlock.h index c80dbbd7c..ec34df694 100644 --- a/lib/mito/fem/blocks/L2NormBlock.h +++ b/lib/mito/fem/blocks/L2NormBlock.h @@ -16,12 +16,9 @@ namespace mito::fem::blocks { class L2NormBlock : public AssemblyBlock { public: - // my parent class - using parent_type = AssemblyBlock; - // my template parameters - using element_type = typename parent_type::element_type; - using elementary_block_type = typename parent_type::elementary_block_type; + using element_type = elementT; + using elementary_block_type = tensor::scalar_t; using quadrature_rule_type = quadratureRuleT; // the type of the function to compute the L2 norm of diff --git a/lib/mito/fem/blocks/MassBlock.h b/lib/mito/fem/blocks/MassBlock.h index ca4500a72..8d95eb710 100644 --- a/lib/mito/fem/blocks/MassBlock.h +++ b/lib/mito/fem/blocks/MassBlock.h @@ -13,12 +13,9 @@ namespace mito::fem::blocks { class MassBlock : public AssemblyBlock> { public: - // my parent class - using parent_type = AssemblyBlock>; - // my template parameters - using element_type = typename parent_type::element_type; - using elementary_block_type = typename parent_type::elementary_block_type; + using element_type = elementT; + using elementary_block_type = tensor::matrix_t; using quadrature_rule_type = quadratureRuleT; public: diff --git a/lib/mito/fem/blocks/SourceTermBlock.h b/lib/mito/fem/blocks/SourceTermBlock.h index 021e3b493..5dc123036 100644 --- a/lib/mito/fem/blocks/SourceTermBlock.h +++ b/lib/mito/fem/blocks/SourceTermBlock.h @@ -15,12 +15,9 @@ namespace mito::fem::blocks { class SourceTermBlock : public AssemblyBlock> { public: - // my parent class - using parent_type = AssemblyBlock>; - // my template parameters - using element_type = typename parent_type::element_type; - using elementary_block_type = typename parent_type::elementary_block_type; + using element_type = elementT; + using elementary_block_type = tensor::vector_t; using quadrature_rule_type = quadratureRuleT; // the type of the source term function From 786a2087e22f007d21f3e25e635b61377152d974 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 25 Oct 2025 08:49:22 +0200 Subject: [PATCH 246/273] fem: reaname {n_nodes} to {n_element_nodes} in class {DiscreteSystem} --- lib/mito/fem/DiscreteSystem.h | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/mito/fem/DiscreteSystem.h b/lib/mito/fem/DiscreteSystem.h index ef08550f3..de88210da 100644 --- a/lib/mito/fem/DiscreteSystem.h +++ b/lib/mito/fem/DiscreteSystem.h @@ -38,9 +38,8 @@ namespace mito::fem { using solution_field_type = tensor::scalar_t; // the nodal field type using nodal_field_type = discrete::nodal_field_t; - // TOFIX: rename to {n_element_nodes} // the number of nodes per element - static constexpr int n_nodes = element_type::n_nodes; + static constexpr int n_element_nodes = element_type::n_nodes; public: // constructor @@ -156,7 +155,7 @@ namespace mito::fem { auto [elementary_matrix, elementary_vector] = _weakform.compute_blocks(element); // assemble the elementary blocks into the linear system of equations - tensor::constexpr_for_1([&]() { + tensor::constexpr_for_1([&]() { // get the a-th discretization node of the element const auto & node_a = element.connectivity()[a]; // get the equation number of {node_a} @@ -167,7 +166,7 @@ namespace mito::fem { // assemble the value in the right hand side _linear_system.add_rhs_value(eq_a, elementary_vector[{ a }]); // loop on the b-th discretization node of the element - tensor::constexpr_for_1([&]() { + tensor::constexpr_for_1([&]() { // get the b-th discretization node of the element const auto & node_b = element.connectivity()[b]; // get the equation number of {node_b} @@ -245,7 +244,7 @@ namespace mito::fem { for (const auto & element : _function_space.elements()) { // assemble the solution field on this element auto u_numerical = _assemble_element_solution( - element, _solution_field, tensor::make_integer_sequence()); + element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error field as a function of the barycentric coordinates auto u_error = u_numerical - u_exact.function()(element.parametrization().function()); @@ -296,13 +295,13 @@ namespace mito::fem { for (const auto & element : _function_space.elements()) { // assemble the solution field on this element auto u_numerical = _assemble_element_solution( - element, _solution_field, tensor::make_integer_sequence()); + element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error field as a function of the barycentric coordinates auto u_error = u_numerical - u_exact.function()(element.parametrization().function()); // auto u_numerical_gradient = _assemble_element_solution_gradient( - element, _solution_field, tensor::make_integer_sequence()); + element, _solution_field, tensor::make_integer_sequence()); // assemble the elementary error gradient as a function of the barycentric // coordinates auto u_error_gradient = From 81b45fa00857987c38116a58b9eec70d9544be01 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 26 Oct 2025 08:26:38 +0100 Subject: [PATCH 247/273] fem: factor discretization implementation outside of class {FunctionSpace} --- lib/mito/fem/FunctionSpace.h | 123 ++---------------- .../elements/tri1/DiscretizeTriangleP1CG.h | 88 +++++++++++++ lib/mito/fem/elements/tri1/api.h | 23 ++++ lib/mito/fem/elements/tri1/public.h | 4 + .../elements/tri2/DiscretizeTriangleP2CG.h | 123 ++++++++++++++++++ lib/mito/fem/elements/tri2/api.h | 23 ++++ lib/mito/fem/elements/tri2/public.h | 5 + 7 files changed, 276 insertions(+), 113 deletions(-) create mode 100644 lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h create mode 100644 lib/mito/fem/elements/tri1/api.h create mode 100644 lib/mito/fem/elements/tri2/DiscretizeTriangleP2CG.h create mode 100644 lib/mito/fem/elements/tri2/api.h diff --git a/lib/mito/fem/FunctionSpace.h b/lib/mito/fem/FunctionSpace.h index 2b9abfdb6..6d4b25d64 100644 --- a/lib/mito/fem/FunctionSpace.h +++ b/lib/mito/fem/FunctionSpace.h @@ -30,12 +30,8 @@ namespace mito::fem { using mesh_node_type = geometry::node_t; // the discretization node type using discretization_node_type = typename element_type::discretization_node_type; - // the nodes type - using connectivity_type = typename element_type::connectivity_type; // the constrained nodes type using constrained_nodes_type = std::set; - - private: // the type of a map between the mesh nodes and discretization nodes using map_type = std::unordered_map< mesh_node_type, discretization_node_type, utilities::hash_function>; @@ -52,122 +48,23 @@ namespace mito::fem { _constraints(constraints), _node_map() { - // TOFIX: the following code is for a CG discretization, we should define this as a - // function some place else and just call it here - // first order discretization if constexpr (degree == 1) { - - // get the coordinate system of the manifold - const auto & coord_system = manifold.coordinate_system(); - - // loop on the cells of the mesh - for (const auto & cell : manifold.elements()) { - - // get the nodes of the cell - const auto & nodes = cell.nodes(); - - // add the nodes to the map (if the mesh node is already present in the map, - // then the present discretization node is used) - auto node_0 = - _node_map.insert({ nodes[0], discretization_node_type() }).first->second; - auto node_1 = - _node_map.insert({ nodes[1], discretization_node_type() }).first->second; - auto node_2 = - _node_map.insert({ nodes[2], discretization_node_type() }).first->second; - - // create a finite element for each cell and add it to the pile - _elements.emplace( - cell, coord_system, connectivity_type{ node_0, node_1, node_2 }); - } - - // populate the constrained nodes - for (const auto & cell : constraints.domain().cells()) { - for (const auto & node : cell.nodes()) { - // get the discretization node associated with the mesh node from the map - auto it = _node_map.find(node); - // add the node to the constrained nodes - _constrained_nodes.insert(it->second); - } - } + // discretize the manifold with first order continuous Galerkin + discretize_triangleP1_CG( + manifold, constraints, _elements, _node_map, _constrained_nodes); + // all done + return; } // second order discretization if constexpr (degree == 2) { - // id type of mesh nodes - using mesh_node_id_t = utilities::index_t; - - // the type of a map between the two vertices and the middle discretization nodes - using mid_nodes_map_type = - std::map, discretization_node_type>; - - // create a map to store the mid nodes - auto mid_nodes_map = mid_nodes_map_type(); - - // get the coordinate system of the manifold - const auto & coord_system = manifold.coordinate_system(); - - // loop on the cells of the mesh - for (const auto & cell : manifold.elements()) { - - // get the nodes of the cell - const auto & nodes = cell.nodes(); - - // add the nodes to the map (if the mesh node is already present in the map, - // then the present discretization node is used) - auto node_0 = - _node_map.insert({ nodes[0], discretization_node_type() }).first->second; - auto node_1 = - _node_map.insert({ nodes[1], discretization_node_type() }).first->second; - auto node_2 = - _node_map.insert({ nodes[2], discretization_node_type() }).first->second; - - auto ordered_nodes_3 = (node_0.id() < node_1.id()) ? - std::array{ node_0.id(), node_1.id() } : - std::array{ node_1.id(), node_0.id() }; - auto node_3 = - mid_nodes_map.insert({ ordered_nodes_3, discretization_node_type() }) - .first->second; - auto ordered_nodes_4 = (node_1.id() < node_2.id()) ? - std::array{ node_1.id(), node_2.id() } : - std::array{ node_2.id(), node_1.id() }; - auto node_4 = - mid_nodes_map.insert({ ordered_nodes_4, discretization_node_type() }) - .first->second; - auto ordered_nodes_5 = (node_2.id() < node_0.id()) ? - std::array{ node_2.id(), node_0.id() } : - std::array{ node_0.id(), node_2.id() }; - auto node_5 = - mid_nodes_map.insert({ ordered_nodes_5, discretization_node_type() }) - .first->second; - - // create a finite element for each cell and add it to the pile - _elements.emplace( - cell, coord_system, - connectivity_type{ node_0, node_1, node_2, node_3, node_4, node_5 }); - } - - // populate the constrained nodes - for (const auto & cell : constraints.domain().cells()) { - for (const auto & node : cell.nodes()) { - // get the discretization node associated with the mesh node from the map - auto it = _node_map.find(node); - // add the node to the constrained nodes - _constrained_nodes.insert(it->second); - } - auto node_0 = _node_map.at(cell.nodes()[0]); - auto node_1 = _node_map.at(cell.nodes()[1]); - auto ordered_nodes = (node_0.id() < node_1.id()) ? - std::array{ node_0.id(), node_1.id() } : - std::array{ node_1.id(), node_0.id() }; - auto node = mid_nodes_map.at(ordered_nodes); - // add the node to the constrained nodes - _constrained_nodes.insert(node); - } + // discretize the manifold with second order continuous Galerkin + discretize_triangleP2_CG( + manifold, constraints, _elements, _node_map, _constrained_nodes); + // all done + return; } - - // all done - return; } // destructor diff --git a/lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h b/lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h new file mode 100644 index 000000000..528775f54 --- /dev/null +++ b/lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h @@ -0,0 +1,88 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + template + class DiscretizeTriangleP1CG { + + private: + // the element type + using element_type = IsoparametricTriangleP1; + // the constraints type + using constraints_type = constraintsT; + // the function space type + using function_space_type = FunctionSpace; + // the mesh node type + using mesh_node_type = typename function_space_type::mesh_node_type; + // the discretization node type + using discretization_node_type = typename function_space_type::discretization_node_type; + // the elements type + using elements_type = typename function_space_type::elements_type; + // the nodes type + using connectivity_type = typename element_type::connectivity_type; + // the constrained nodes type + using constrained_nodes_type = typename function_space_type::constrained_nodes_type; + // the type of a map between the mesh nodes and discretization nodes + using map_type = typename function_space_type::map_type; + + public: + // discretize {manifold} with first order isoparametric triangles subject to {constraints} + // this method creates three data structures representing the discretization: a collection + // of discrete elements, a map between the nodes in a mesh and the discretization nodes, and + // a set of constrained nodes + template + // require compatibility between the manifold cell and the finite element cell + requires(std::is_same_v< + typename manifoldT::mesh_type::cell_type, typename element_type::cell_type>) + static void discretize( + const manifoldT & manifold, const constraints_type & constraints, + elements_type & elements, map_type & node_map, + constrained_nodes_type & constrained_nodes) + { + + // get the coordinate system of the manifold + const auto & coord_system = manifold.coordinate_system(); + + // loop on the cells of the mesh + for (const auto & cell : manifold.elements()) { + + // get the nodes of the cell + const auto & nodes = cell.nodes(); + + // add the nodes to the map (if the mesh node is already present in the map, + // then the present discretization node is used) + auto node_0 = + node_map.insert({ nodes[0], discretization_node_type() }).first->second; + auto node_1 = + node_map.insert({ nodes[1], discretization_node_type() }).first->second; + auto node_2 = + node_map.insert({ nodes[2], discretization_node_type() }).first->second; + + // create a finite element for each cell and add it to the pile + elements.emplace(cell, coord_system, connectivity_type{ node_0, node_1, node_2 }); + } + + // populate the constrained nodes + for (const auto & cell : constraints.domain().cells()) { + for (const auto & node : cell.nodes()) { + // get the discretization node associated with the mesh node from the map + auto it = node_map.find(node); + // add the node to the constrained nodes + constrained_nodes.insert(it->second); + } + } + + // all done + return; + } + }; +} + +// end of file diff --git a/lib/mito/fem/elements/tri1/api.h b/lib/mito/fem/elements/tri1/api.h new file mode 100644 index 000000000..1a2e7c57c --- /dev/null +++ b/lib/mito/fem/elements/tri1/api.h @@ -0,0 +1,23 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + template + auto discretize_triangleP1_CG( + const manifoldT & manifold, const constraintsT & constraints, auto & elements, + auto & node_map, auto & constrained_nodes) + { + return DiscretizeTriangleP1CG::template discretize( + manifold, constraints, elements, node_map, constrained_nodes); + } +} + + +// end of file diff --git a/lib/mito/fem/elements/tri1/public.h b/lib/mito/fem/elements/tri1/public.h index 5c7941d17..0c1ee7123 100644 --- a/lib/mito/fem/elements/tri1/public.h +++ b/lib/mito/fem/elements/tri1/public.h @@ -10,6 +10,10 @@ // classes implementation #include "ShapeTriangleP1.h" #include "IsoparametricTriangleP1.h" +#include "DiscretizeTriangleP1CG.h" +// published types and factories +#include "api.h" + // end of file diff --git a/lib/mito/fem/elements/tri2/DiscretizeTriangleP2CG.h b/lib/mito/fem/elements/tri2/DiscretizeTriangleP2CG.h new file mode 100644 index 000000000..145ceb1c2 --- /dev/null +++ b/lib/mito/fem/elements/tri2/DiscretizeTriangleP2CG.h @@ -0,0 +1,123 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + template + class DiscretizeTriangle2CG { + + private: + // the element type + using element_type = IsoparametricTriangleP2; + // the constraints type + using constraints_type = constraintsT; + // the function space type + using function_space_type = FunctionSpace; + // the mesh node type + using mesh_node_type = typename function_space_type::mesh_node_type; + // the discretization node type + using discretization_node_type = typename function_space_type::discretization_node_type; + // the elements type + using elements_type = typename function_space_type::elements_type; + // the nodes type + using connectivity_type = typename element_type::connectivity_type; + // the constrained nodes type + using constrained_nodes_type = typename function_space_type::constrained_nodes_type; + // the type of a map between the mesh nodes and discretization nodes + using map_type = typename function_space_type::map_type; + + public: + // discretize {manifold} with second order isoparametric triangles subject to {constraints} + // this method creates three data structures representing the discretization: a collection + // of discrete elements, a map between the nodes in a mesh and the discretization nodes, and + // a set of constrained nodes + template + // require compatibility between the manifold cell and the finite element cell + requires(std::is_same_v< + typename manifoldT::mesh_type::cell_type, typename element_type::cell_type>) + static void discretize( + const manifoldT & manifold, const constraints_type & constraints, + elements_type & elements, map_type & node_map, + constrained_nodes_type & constrained_nodes) + { + // id type of mesh nodes + using mesh_node_id_t = utilities::index_t; + + // the type of a map between the two vertices and the middle discretization nodes + using mid_nodes_map_type = + std::map, discretization_node_type>; + + // create a map to store the mid nodes + auto mid_nodes_map = mid_nodes_map_type(); + + // get the coordinate system of the manifold + const auto & coord_system = manifold.coordinate_system(); + + // loop on the cells of the mesh + for (const auto & cell : manifold.elements()) { + + // get the nodes of the cell + const auto & nodes = cell.nodes(); + + // add the nodes to the map (if the mesh node is already present in the map, + // then the present discretization node is used) + auto node_0 = + node_map.insert({ nodes[0], discretization_node_type() }).first->second; + auto node_1 = + node_map.insert({ nodes[1], discretization_node_type() }).first->second; + auto node_2 = + node_map.insert({ nodes[2], discretization_node_type() }).first->second; + + auto ordered_nodes_3 = (node_0.id() < node_1.id()) ? + std::array{ node_0.id(), node_1.id() } : + std::array{ node_1.id(), node_0.id() }; + auto node_3 = mid_nodes_map.insert({ ordered_nodes_3, discretization_node_type() }) + .first->second; + auto ordered_nodes_4 = (node_1.id() < node_2.id()) ? + std::array{ node_1.id(), node_2.id() } : + std::array{ node_2.id(), node_1.id() }; + auto node_4 = mid_nodes_map.insert({ ordered_nodes_4, discretization_node_type() }) + .first->second; + auto ordered_nodes_5 = (node_2.id() < node_0.id()) ? + std::array{ node_2.id(), node_0.id() } : + std::array{ node_0.id(), node_2.id() }; + auto node_5 = mid_nodes_map.insert({ ordered_nodes_5, discretization_node_type() }) + .first->second; + + // create a finite element for each cell and add it to the pile + elements.emplace( + cell, coord_system, + connectivity_type{ node_0, node_1, node_2, node_3, node_4, node_5 }); + } + + // populate the constrained nodes + for (const auto & cell : constraints.domain().cells()) { + for (const auto & node : cell.nodes()) { + // get the discretization node associated with the mesh node from the map + auto it = node_map.find(node); + // add the node to the constrained nodes + constrained_nodes.insert(it->second); + } + auto node_0 = node_map.at(cell.nodes()[0]); + auto node_1 = node_map.at(cell.nodes()[1]); + auto ordered_nodes = (node_0.id() < node_1.id()) ? + std::array{ node_0.id(), node_1.id() } : + std::array{ node_1.id(), node_0.id() }; + auto node = mid_nodes_map.at(ordered_nodes); + // add the node to the constrained nodes + constrained_nodes.insert(node); + } + + // all done + return; + } + }; +} + +// end of file diff --git a/lib/mito/fem/elements/tri2/api.h b/lib/mito/fem/elements/tri2/api.h new file mode 100644 index 000000000..2d225cfbb --- /dev/null +++ b/lib/mito/fem/elements/tri2/api.h @@ -0,0 +1,23 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + template + auto discretize_triangleP2_CG( + const manifoldT & manifold, const constraintsT & constraints, auto & elements, + auto & node_map, auto & constrained_nodes) + { + return DiscretizeTriangle2CG::template discretize( + manifold, constraints, elements, node_map, constrained_nodes); + } +} + + +// end of file diff --git a/lib/mito/fem/elements/tri2/public.h b/lib/mito/fem/elements/tri2/public.h index 5354259a8..ffdf3475b 100644 --- a/lib/mito/fem/elements/tri2/public.h +++ b/lib/mito/fem/elements/tri2/public.h @@ -10,6 +10,11 @@ // classes implementation #include "ShapeTriangleP2.h" #include "IsoparametricTriangleP2.h" +#include "DiscretizeTriangleP2CG.h" + + +// published types and factories +#include "api.h" // end of file From 2f8ac1924c6750d380c616539d3b1ae3d7a9d5b7 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 26 Oct 2025 08:37:11 +0100 Subject: [PATCH 248/273] fem: change length of segment for {elements_type} container to the number of elements in the manifold --- lib/mito/fem/FunctionSpace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/mito/fem/FunctionSpace.h b/lib/mito/fem/FunctionSpace.h index 6d4b25d64..3422f25b8 100644 --- a/lib/mito/fem/FunctionSpace.h +++ b/lib/mito/fem/FunctionSpace.h @@ -44,7 +44,7 @@ namespace mito::fem { requires(std::is_same_v< typename manifoldT::mesh_type::cell_type, typename element_type::cell_type>) constexpr FunctionSpace(const manifoldT & manifold, const constraints_type & constraints) : - _elements(100), + _elements(manifold.nElements()), _constraints(constraints), _node_map() { From 5e757729662772c8af5d2dbbd08279b42f917df1 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 26 Oct 2025 09:20:10 +0100 Subject: [PATCH 249/273] fem: redesign discretization logic Discretization is carried out via a class {Discretizer}, which admits specializations based on the finite element and the discretization type. --- lib/mito/fem/FunctionSpace.h | 24 ++--- lib/mito/fem/api.h | 3 + lib/mito/fem/elements/Discretizer.h | 34 +++++++ lib/mito/fem/elements/forward.h | 4 + lib/mito/fem/elements/public.h | 1 + .../elements/tri1/DiscretizeTriangleP1CG.h | 88 ------------------- lib/mito/fem/elements/tri1/DiscretizerCG.h | 68 ++++++++++++++ lib/mito/fem/elements/tri1/api.h | 23 ----- lib/mito/fem/elements/tri1/public.h | 5 +- ...scretizeTriangleP2CG.h => DiscretizerCG.h} | 58 +++++------- lib/mito/fem/elements/tri2/api.h | 23 ----- lib/mito/fem/elements/tri2/public.h | 6 +- 12 files changed, 140 insertions(+), 197 deletions(-) create mode 100644 lib/mito/fem/elements/Discretizer.h delete mode 100644 lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h create mode 100644 lib/mito/fem/elements/tri1/DiscretizerCG.h delete mode 100644 lib/mito/fem/elements/tri1/api.h rename lib/mito/fem/elements/tri2/{DiscretizeTriangleP2CG.h => DiscretizerCG.h} (66%) delete mode 100644 lib/mito/fem/elements/tri2/api.h diff --git a/lib/mito/fem/FunctionSpace.h b/lib/mito/fem/FunctionSpace.h index 3422f25b8..f4e7b8246 100644 --- a/lib/mito/fem/FunctionSpace.h +++ b/lib/mito/fem/FunctionSpace.h @@ -39,7 +39,9 @@ namespace mito::fem { public: // the constructor - template + template < + manifolds::manifold_c manifoldT, + discretization_t discretizationT = discretization_t::CG> // require compatibility between the manifold cell and the finite element cell requires(std::is_same_v< typename manifoldT::mesh_type::cell_type, typename element_type::cell_type>) @@ -48,23 +50,9 @@ namespace mito::fem { _constraints(constraints), _node_map() { - // first order discretization - if constexpr (degree == 1) { - // discretize the manifold with first order continuous Galerkin - discretize_triangleP1_CG( - manifold, constraints, _elements, _node_map, _constrained_nodes); - // all done - return; - } - - // second order discretization - if constexpr (degree == 2) { - // discretize the manifold with second order continuous Galerkin - discretize_triangleP2_CG( - manifold, constraints, _elements, _node_map, _constrained_nodes); - // all done - return; - } + // discretize the manifold subject to the constraints + discretize( + manifold, constraints, _elements, _node_map, _constrained_nodes); } // destructor diff --git a/lib/mito/fem/api.h b/lib/mito/fem/api.h index 435d876e2..b0222bb33 100644 --- a/lib/mito/fem/api.h +++ b/lib/mito/fem/api.h @@ -13,6 +13,9 @@ namespace mito::fem { template constexpr auto nodal_field(const functionSpaceT & function_space, std::string name); + // the possible discretization types: continuous Galerking (CG) vs. discontinuous Galerkin (DG) + enum class discretization_t { CG, DG }; + // function space alias template using function_space_t = FunctionSpace; diff --git a/lib/mito/fem/elements/Discretizer.h b/lib/mito/fem/elements/Discretizer.h new file mode 100644 index 000000000..23077a0cf --- /dev/null +++ b/lib/mito/fem/elements/Discretizer.h @@ -0,0 +1,34 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + template + struct Discretizer { + template < + typename manifoldT, typename constraintsT, typename elements_type, typename map_type, + typename constrained_nodes_type> + static void apply( + const manifoldT &, const constraintsT &, elements_type &, map_type &, + constrained_nodes_type &); + }; + + template + auto discretize( + const auto & manifold, const auto & constraints, auto & elements, auto & node_map, + auto & constrained_nodes) + { + Discretizer::apply( + manifold, constraints, elements, node_map, constrained_nodes); + } + +} + + +// end of file diff --git a/lib/mito/fem/elements/forward.h b/lib/mito/fem/elements/forward.h index 3dc17eb77..8255085d8 100644 --- a/lib/mito/fem/elements/forward.h +++ b/lib/mito/fem/elements/forward.h @@ -9,6 +9,10 @@ namespace mito::fem { + // the struct that implements the discretization strategy + template + struct Discretizer; + } diff --git a/lib/mito/fem/elements/public.h b/lib/mito/fem/elements/public.h index 4de40cab4..cce7f4b0d 100644 --- a/lib/mito/fem/elements/public.h +++ b/lib/mito/fem/elements/public.h @@ -19,6 +19,7 @@ // classes implementation #include "IsoparametricTriangle.h" #include "isoparametric_simplex_library.h" +#include "Discretizer.h" // factories implementation #include "factories.h" diff --git a/lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h b/lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h deleted file mode 100644 index 528775f54..000000000 --- a/lib/mito/fem/elements/tri1/DiscretizeTriangleP1CG.h +++ /dev/null @@ -1,88 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - -// code guard -#pragma once - - -namespace mito::fem { - - template - class DiscretizeTriangleP1CG { - - private: - // the element type - using element_type = IsoparametricTriangleP1; - // the constraints type - using constraints_type = constraintsT; - // the function space type - using function_space_type = FunctionSpace; - // the mesh node type - using mesh_node_type = typename function_space_type::mesh_node_type; - // the discretization node type - using discretization_node_type = typename function_space_type::discretization_node_type; - // the elements type - using elements_type = typename function_space_type::elements_type; - // the nodes type - using connectivity_type = typename element_type::connectivity_type; - // the constrained nodes type - using constrained_nodes_type = typename function_space_type::constrained_nodes_type; - // the type of a map between the mesh nodes and discretization nodes - using map_type = typename function_space_type::map_type; - - public: - // discretize {manifold} with first order isoparametric triangles subject to {constraints} - // this method creates three data structures representing the discretization: a collection - // of discrete elements, a map between the nodes in a mesh and the discretization nodes, and - // a set of constrained nodes - template - // require compatibility between the manifold cell and the finite element cell - requires(std::is_same_v< - typename manifoldT::mesh_type::cell_type, typename element_type::cell_type>) - static void discretize( - const manifoldT & manifold, const constraints_type & constraints, - elements_type & elements, map_type & node_map, - constrained_nodes_type & constrained_nodes) - { - - // get the coordinate system of the manifold - const auto & coord_system = manifold.coordinate_system(); - - // loop on the cells of the mesh - for (const auto & cell : manifold.elements()) { - - // get the nodes of the cell - const auto & nodes = cell.nodes(); - - // add the nodes to the map (if the mesh node is already present in the map, - // then the present discretization node is used) - auto node_0 = - node_map.insert({ nodes[0], discretization_node_type() }).first->second; - auto node_1 = - node_map.insert({ nodes[1], discretization_node_type() }).first->second; - auto node_2 = - node_map.insert({ nodes[2], discretization_node_type() }).first->second; - - // create a finite element for each cell and add it to the pile - elements.emplace(cell, coord_system, connectivity_type{ node_0, node_1, node_2 }); - } - - // populate the constrained nodes - for (const auto & cell : constraints.domain().cells()) { - for (const auto & node : cell.nodes()) { - // get the discretization node associated with the mesh node from the map - auto it = node_map.find(node); - // add the node to the constrained nodes - constrained_nodes.insert(it->second); - } - } - - // all done - return; - } - }; -} - -// end of file diff --git a/lib/mito/fem/elements/tri1/DiscretizerCG.h b/lib/mito/fem/elements/tri1/DiscretizerCG.h new file mode 100644 index 000000000..efeadf7af --- /dev/null +++ b/lib/mito/fem/elements/tri1/DiscretizerCG.h @@ -0,0 +1,68 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + // discretizer specialization for {IsoparametricTriangleP1} with continuous Galerkin + template <> + struct Discretizer { + template < + typename manifoldT, typename constraintsT, typename elements_type, typename map_type, + typename constrained_nodes_type> + static void apply( + const manifoldT & manifold, const constraintsT & constraints, elements_type & elements, + map_type & node_map, constrained_nodes_type & constrained_nodes) + { + + // the discretization node type + using discretization_node_type = + typename IsoparametricTriangleP1::discretization_node_type; + + // the connectivity type + using connectivity_type = typename IsoparametricTriangleP1::connectivity_type; + + // get the coordinate system of the manifold + const auto & coord_system = manifold.coordinate_system(); + + // loop on the cells of the mesh + for (const auto & cell : manifold.elements()) { + + // get the nodes of the cell + const auto & nodes = cell.nodes(); + + // add the nodes to the map (if the mesh node is already present in the map, + // then the present discretization node is used) + auto node_0 = + node_map.insert({ nodes[0], discretization_node_type() }).first->second; + auto node_1 = + node_map.insert({ nodes[1], discretization_node_type() }).first->second; + auto node_2 = + node_map.insert({ nodes[2], discretization_node_type() }).first->second; + + // create a finite element for each cell and add it to the pile + elements.emplace(cell, coord_system, connectivity_type{ node_0, node_1, node_2 }); + } + + // populate the constrained nodes + for (const auto & cell : constraints.domain().cells()) { + for (const auto & node : cell.nodes()) { + // get the discretization node associated with the mesh node from the map + auto it = node_map.find(node); + // add the node to the constrained nodes + constrained_nodes.insert(it->second); + } + } + + // all done + return; + } + }; +} + +// end of file diff --git a/lib/mito/fem/elements/tri1/api.h b/lib/mito/fem/elements/tri1/api.h deleted file mode 100644 index 1a2e7c57c..000000000 --- a/lib/mito/fem/elements/tri1/api.h +++ /dev/null @@ -1,23 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - -// code guard -#pragma once - - -namespace mito::fem { - - template - auto discretize_triangleP1_CG( - const manifoldT & manifold, const constraintsT & constraints, auto & elements, - auto & node_map, auto & constrained_nodes) - { - return DiscretizeTriangleP1CG::template discretize( - manifold, constraints, elements, node_map, constrained_nodes); - } -} - - -// end of file diff --git a/lib/mito/fem/elements/tri1/public.h b/lib/mito/fem/elements/tri1/public.h index 0c1ee7123..8d0457b02 100644 --- a/lib/mito/fem/elements/tri1/public.h +++ b/lib/mito/fem/elements/tri1/public.h @@ -10,10 +10,7 @@ // classes implementation #include "ShapeTriangleP1.h" #include "IsoparametricTriangleP1.h" -#include "DiscretizeTriangleP1CG.h" +#include "DiscretizerCG.h" -// published types and factories -#include "api.h" - // end of file diff --git a/lib/mito/fem/elements/tri2/DiscretizeTriangleP2CG.h b/lib/mito/fem/elements/tri2/DiscretizerCG.h similarity index 66% rename from lib/mito/fem/elements/tri2/DiscretizeTriangleP2CG.h rename to lib/mito/fem/elements/tri2/DiscretizerCG.h index 145ceb1c2..919f368a4 100644 --- a/lib/mito/fem/elements/tri2/DiscretizeTriangleP2CG.h +++ b/lib/mito/fem/elements/tri2/DiscretizerCG.h @@ -9,43 +9,29 @@ namespace mito::fem { - template - class DiscretizeTriangle2CG { - - private: - // the element type - using element_type = IsoparametricTriangleP2; - // the constraints type - using constraints_type = constraintsT; - // the function space type - using function_space_type = FunctionSpace; - // the mesh node type - using mesh_node_type = typename function_space_type::mesh_node_type; - // the discretization node type - using discretization_node_type = typename function_space_type::discretization_node_type; - // the elements type - using elements_type = typename function_space_type::elements_type; - // the nodes type - using connectivity_type = typename element_type::connectivity_type; - // the constrained nodes type - using constrained_nodes_type = typename function_space_type::constrained_nodes_type; - // the type of a map between the mesh nodes and discretization nodes - using map_type = typename function_space_type::map_type; - - public: - // discretize {manifold} with second order isoparametric triangles subject to {constraints} - // this method creates three data structures representing the discretization: a collection - // of discrete elements, a map between the nodes in a mesh and the discretization nodes, and - // a set of constrained nodes - template - // require compatibility between the manifold cell and the finite element cell - requires(std::is_same_v< - typename manifoldT::mesh_type::cell_type, typename element_type::cell_type>) - static void discretize( - const manifoldT & manifold, const constraints_type & constraints, - elements_type & elements, map_type & node_map, - constrained_nodes_type & constrained_nodes) + // discretizer specialization for {IsoparametricTriangleP2} with continuous Galerkin + template <> + struct Discretizer { + template < + typename manifoldT, typename constraintsT, typename elements_type, typename map_type, + typename constrained_nodes_type> + static void apply( + const manifoldT & manifold, const constraintsT & constraints, elements_type & elements, + map_type & node_map, constrained_nodes_type & constrained_nodes) { + // the dimension of the physical space + constexpr int dim = IsoparametricTriangleP2::dim; + + // assemble the mesh node type + using mesh_node_type = geometry::node_t; + + // the discretization node type + using discretization_node_type = + typename IsoparametricTriangleP2::discretization_node_type; + + // the connectivity type + using connectivity_type = typename IsoparametricTriangleP2::connectivity_type; + // id type of mesh nodes using mesh_node_id_t = utilities::index_t; diff --git a/lib/mito/fem/elements/tri2/api.h b/lib/mito/fem/elements/tri2/api.h deleted file mode 100644 index 2d225cfbb..000000000 --- a/lib/mito/fem/elements/tri2/api.h +++ /dev/null @@ -1,23 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - -// code guard -#pragma once - - -namespace mito::fem { - - template - auto discretize_triangleP2_CG( - const manifoldT & manifold, const constraintsT & constraints, auto & elements, - auto & node_map, auto & constrained_nodes) - { - return DiscretizeTriangle2CG::template discretize( - manifold, constraints, elements, node_map, constrained_nodes); - } -} - - -// end of file diff --git a/lib/mito/fem/elements/tri2/public.h b/lib/mito/fem/elements/tri2/public.h index ffdf3475b..b72615e43 100644 --- a/lib/mito/fem/elements/tri2/public.h +++ b/lib/mito/fem/elements/tri2/public.h @@ -10,11 +10,7 @@ // classes implementation #include "ShapeTriangleP2.h" #include "IsoparametricTriangleP2.h" -#include "DiscretizeTriangleP2CG.h" - - -// published types and factories -#include "api.h" +#include "DiscretizerCG.h" // end of file From afa02d63bafe92fa2e44e74440bee4caf42803d9 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 26 Oct 2025 10:45:07 +0100 Subject: [PATCH 250/273] fem: reorganize elements library The specialization of {isoparametric_simplex} struct is now within each element-specific subdirectory. --- lib/mito/fem/elements/api.h | 4 ++ lib/mito/fem/elements/elements_library.h | 14 +++++++ lib/mito/fem/elements/forward.h | 5 +++ .../elements/isoparametric_simplex_library.h | 39 ------------------- lib/mito/fem/elements/public.h | 4 +- lib/mito/fem/elements/tri1/api.h | 21 ++++++++++ lib/mito/fem/elements/tri1/public.h | 3 ++ lib/mito/fem/elements/tri2/api.h | 21 ++++++++++ lib/mito/fem/elements/tri2/public.h | 3 ++ 9 files changed, 74 insertions(+), 40 deletions(-) create mode 100644 lib/mito/fem/elements/elements_library.h delete mode 100644 lib/mito/fem/elements/isoparametric_simplex_library.h create mode 100644 lib/mito/fem/elements/tri1/api.h create mode 100644 lib/mito/fem/elements/tri2/api.h diff --git a/lib/mito/fem/elements/api.h b/lib/mito/fem/elements/api.h index 3dc17eb77..d37901314 100644 --- a/lib/mito/fem/elements/api.h +++ b/lib/mito/fem/elements/api.h @@ -9,6 +9,10 @@ namespace mito::fem { + // type alias for convenient access to the isoparametric simplex type + template + using isoparametric_simplex_t = typename isoparametric_simplex::type; + } diff --git a/lib/mito/fem/elements/elements_library.h b/lib/mito/fem/elements/elements_library.h new file mode 100644 index 000000000..d52cfc68d --- /dev/null +++ b/lib/mito/fem/elements/elements_library.h @@ -0,0 +1,14 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +#include "tri1/public.h" +#include "tri2/public.h" + + +// end of file diff --git a/lib/mito/fem/elements/forward.h b/lib/mito/fem/elements/forward.h index 8255085d8..f8c9f3078 100644 --- a/lib/mito/fem/elements/forward.h +++ b/lib/mito/fem/elements/forward.h @@ -13,6 +13,11 @@ namespace mito::fem { template struct Discretizer; + // struct storing the type of an isoparametric simplex of polynomial degree {degree} on a + // geometric simplex of type {geometricSimplexT} + template + struct isoparametric_simplex; + } diff --git a/lib/mito/fem/elements/isoparametric_simplex_library.h b/lib/mito/fem/elements/isoparametric_simplex_library.h deleted file mode 100644 index 3669cf4d7..000000000 --- a/lib/mito/fem/elements/isoparametric_simplex_library.h +++ /dev/null @@ -1,39 +0,0 @@ -// -*- c++ -*- -// -// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved -// - -// code guard -#pragma once - - -#include "tri1/public.h" -#include "tri2/public.h" - - -namespace mito::fem { - - // struct storing the type of an isoparametric simplex of polynomial degree {degree} on a - // geometric simplex of type {geometricSimplexT} - template - struct isoparametric_simplex {}; - - // specialization for linear shape functions on triangles in 2D - template <> - struct isoparametric_simplex<1, geometry::triangle_t<2>> { - using type = IsoparametricTriangleP1; - }; - - // specialization for quadratic shape functions on triangles in 2D - template <> - struct isoparametric_simplex<2, geometry::triangle_t<2>> { - using type = IsoparametricTriangleP2; - }; - - // type alias for convenient access to the isoparametric simplex type - template - using isoparametric_simplex_t = typename isoparametric_simplex::type; -} - - -// end of file diff --git a/lib/mito/fem/elements/public.h b/lib/mito/fem/elements/public.h index cce7f4b0d..40f144579 100644 --- a/lib/mito/fem/elements/public.h +++ b/lib/mito/fem/elements/public.h @@ -18,9 +18,11 @@ // classes implementation #include "IsoparametricTriangle.h" -#include "isoparametric_simplex_library.h" #include "Discretizer.h" +// library of finite elements +#include "elements_library.h" + // factories implementation #include "factories.h" diff --git a/lib/mito/fem/elements/tri1/api.h b/lib/mito/fem/elements/tri1/api.h new file mode 100644 index 000000000..937d35638 --- /dev/null +++ b/lib/mito/fem/elements/tri1/api.h @@ -0,0 +1,21 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + // specialization for linear shape functions on triangles in 2D + template <> + struct isoparametric_simplex<1, geometry::triangle_t<2>> { + using type = IsoparametricTriangleP1; + }; + +} + + +// end of file diff --git a/lib/mito/fem/elements/tri1/public.h b/lib/mito/fem/elements/tri1/public.h index 8d0457b02..01bfcf009 100644 --- a/lib/mito/fem/elements/tri1/public.h +++ b/lib/mito/fem/elements/tri1/public.h @@ -12,5 +12,8 @@ #include "IsoparametricTriangleP1.h" #include "DiscretizerCG.h" +// published types and factories +#include "api.h" + // end of file diff --git a/lib/mito/fem/elements/tri2/api.h b/lib/mito/fem/elements/tri2/api.h new file mode 100644 index 000000000..4edff71ce --- /dev/null +++ b/lib/mito/fem/elements/tri2/api.h @@ -0,0 +1,21 @@ +// -*- c++ -*- +// +// Copyright (c) 2020-2024, the MiTo Authors, all rights reserved +// + +// code guard +#pragma once + + +namespace mito::fem { + + // specialization for quadratic shape functions on triangles in 2D + template <> + struct isoparametric_simplex<2, geometry::triangle_t<2>> { + using type = IsoparametricTriangleP2; + }; + +} + + +// end of file diff --git a/lib/mito/fem/elements/tri2/public.h b/lib/mito/fem/elements/tri2/public.h index b72615e43..f0d81b37d 100644 --- a/lib/mito/fem/elements/tri2/public.h +++ b/lib/mito/fem/elements/tri2/public.h @@ -12,5 +12,8 @@ #include "IsoparametricTriangleP2.h" #include "DiscretizerCG.h" +// published types and factories +#include "api.h" + // end of file From 8215da4042dfbfdb251d5008435d52105f60df8c Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 26 Oct 2025 10:47:07 +0100 Subject: [PATCH 251/273] fem: tests now use api typedef {isoparametric_simplex_t} --- tests/mito.lib/fem/block_grad_grad.cc | 4 ++-- tests/mito.lib/fem/block_mass.cc | 4 ++-- tests/mito.lib/fem/isoparametric_triangle.cc | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/mito.lib/fem/block_grad_grad.cc b/tests/mito.lib/fem/block_grad_grad.cc index 22e4816be..210e9b5db 100644 --- a/tests/mito.lib/fem/block_grad_grad.cc +++ b/tests/mito.lib/fem/block_grad_grad.cc @@ -40,7 +40,7 @@ TEST(Fem, IsoparametricTriangle) { // first order isoparametric triangle - using element_p1_t = mito::fem::isoparametric_simplex<1, cell_t>::type; + using element_p1_t = mito::fem::isoparametric_simplex_t<1, cell_t>; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); @@ -72,7 +72,7 @@ TEST(Fem, IsoparametricTriangle) { // second order isoparametric triangle - using element_p2_t = mito::fem::isoparametric_simplex<2, cell_t>::type; + using element_p2_t = mito::fem::isoparametric_simplex_t<2, cell_t>; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); diff --git a/tests/mito.lib/fem/block_mass.cc b/tests/mito.lib/fem/block_mass.cc index e502547e9..a0577cc89 100644 --- a/tests/mito.lib/fem/block_mass.cc +++ b/tests/mito.lib/fem/block_mass.cc @@ -40,7 +40,7 @@ TEST(Fem, IsoparametricTriangle) { // first order isoparametric triangle - using element_p1_t = mito::fem::isoparametric_simplex<1, cell_t>::type; + using element_p1_t = mito::fem::isoparametric_simplex_t<1, cell_t>; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); @@ -71,7 +71,7 @@ TEST(Fem, IsoparametricTriangle) { // second order isoparametric triangle - using element_p2_t = mito::fem::isoparametric_simplex<2, cell_t>::type; + using element_p2_t = mito::fem::isoparametric_simplex_t<2, cell_t>; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); diff --git a/tests/mito.lib/fem/isoparametric_triangle.cc b/tests/mito.lib/fem/isoparametric_triangle.cc index 82fa5d34e..8baba4991 100644 --- a/tests/mito.lib/fem/isoparametric_triangle.cc +++ b/tests/mito.lib/fem/isoparametric_triangle.cc @@ -103,7 +103,7 @@ TEST(Fem, IsoparametricTriangle) { // first order isoparametric triangle - using element_p1_t = mito::fem::isoparametric_simplex<1, cell_t>::type; + using element_p1_t = mito::fem::isoparametric_simplex_t<1, cell_t>; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); @@ -124,7 +124,7 @@ TEST(Fem, IsoparametricTriangle) { // second order isoparametric triangle - using element_p2_t = mito::fem::isoparametric_simplex<2, cell_t>::type; + using element_p2_t = mito::fem::isoparametric_simplex_t<2, cell_t>; // build the discretization nodes auto discretization_node_0 = discretization_node_t(); From f82ca5cbef3bee5a4ad259824e14680b59ab0d34 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 1 Nov 2025 07:59:53 +0100 Subject: [PATCH 252/273] .github/workflows: skip upgrade step for {ubuntu} --- .github/workflows/cmake-ubuntu.yaml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/cmake-ubuntu.yaml b/.github/workflows/cmake-ubuntu.yaml index 7e0512f42..a0d7b8048 100644 --- a/.github/workflows/cmake-ubuntu.yaml +++ b/.github/workflows/cmake-ubuntu.yaml @@ -38,10 +38,6 @@ jobs: run: | echo " -- update the package cache" sudo apt update - echo " -- upgradables" - sudo apt list --upgradable - echo " -- upgrade" - sudo apt dist-upgrade echo " -- install our dependencies" sudo apt install -y make cmake libgtest-dev libbenchmark-dev libvtk9-dev libopenmpi-dev libmetis-dev valgrind petsc-dev From a3a84608899917e290b5ef4c4c07f031f5d767a2 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 1 Nov 2025 08:06:43 +0100 Subject: [PATCH 253/273] .github/workflows: install default {vtk} version Not sure if we still need to ensure that {vtk@9.1.0} is used. --- .github/workflows/cmake-macos.yaml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 203ef90ea..2a09d70f9 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -37,11 +37,9 @@ jobs: - name: ${{matrix.os}} refresh run: | echo " -- install our dependencies" - brew install make cmake metis open-mpi + brew install make cmake metis open-mpi vtk # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-12 google-benchmark - curl https://raw.githubusercontent.com/Homebrew/homebrew-core/67b277e6d1faee20d2aa4fc8b2dc229a241fa807/Formula/vtk.rb > vtk.rb - HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1 brew install vtk.rb - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 From 314fe673d662fb33a6074bf8052f87a3dfbbc403 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 5 Nov 2025 19:47:27 +0100 Subject: [PATCH 254/273] .github/workflows: checkout {pyre} {tensor} branch instead of {main} --- .github/workflows/cmake-macos.yaml | 2 +- .github/workflows/cmake-ubuntu.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 2a09d70f9..10f490523 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -82,7 +82,7 @@ jobs: repository: pyre/pyre fetch-depth: 0 path: ${{github.workspace}}/pyre - ref: main + ref: tensor - name: retrieve pyre commit SHA id: pyre-sha diff --git a/.github/workflows/cmake-ubuntu.yaml b/.github/workflows/cmake-ubuntu.yaml index a0d7b8048..240962dfa 100644 --- a/.github/workflows/cmake-ubuntu.yaml +++ b/.github/workflows/cmake-ubuntu.yaml @@ -57,7 +57,7 @@ jobs: repository: pyre/pyre fetch-depth: 0 path: ${{github.workspace}}/pyre - ref: main + ref: tensor - name: retrieve pyre commit SHA id: pyre-sha From f803b73e53b8c3fe08a6ce217769913df9e289be Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 5 Nov 2025 19:53:23 +0100 Subject: [PATCH 255/273] .cmake: conditionally add {poisson} test only if {petsc} is supported --- .cmake/mito_tests_mito_lib.cmake | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index 682c70d71..cb210695c 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -45,7 +45,9 @@ mito_test_driver(tests/mito.lib/discrete/quadrature_field.cc) mito_test_driver(tests/mito.lib/discrete/mesh_field.cc) # fem -mito_test_driver(tests/mito.lib/fem/poisson.cc) +if(WITH_PETSC) + mito_test_driver(tests/mito.lib/fem/poisson.cc) +endif() mito_test_driver(tests/mito.lib/fem/block_grad_grad.cc) mito_test_driver(tests/mito.lib/fem/block_mass.cc) mito_test_driver(tests/mito.lib/fem/shape_functions_triangle_construction.cc) From 03518b372981b0a3031f1df4bade17fcd8859ab5 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Wed, 5 Nov 2025 20:09:50 +0100 Subject: [PATCH 256/273] benchmarks: promote {poisson} driver to benchmarks --- .cmake/mito_benchmarks_mito_lib.cmake | 4 ++++ .cmake/mito_tests_mito_lib.cmake | 3 --- .../mito.lib/fem => benchmarks/mito.lib/pdes}/poisson.cc | 9 ++------- 3 files changed, 6 insertions(+), 10 deletions(-) rename {tests/mito.lib/fem => benchmarks/mito.lib/pdes}/poisson.cc (96%) diff --git a/.cmake/mito_benchmarks_mito_lib.cmake b/.cmake/mito_benchmarks_mito_lib.cmake index 54372f4d6..033a672ae 100644 --- a/.cmake/mito_benchmarks_mito_lib.cmake +++ b/.cmake/mito_benchmarks_mito_lib.cmake @@ -20,5 +20,9 @@ mito_benchmark_driver(benchmarks/mito.lib/integration/integration.cc) # fields mito_benchmark_driver(benchmarks/mito.lib/fields/laplacian.cc) +if(WITH_PETSC) + # poisson boundary value problem + mito_benchmark_driver(benchmarks/mito.lib/pdes/poisson.cc) +endif() # end of file diff --git a/.cmake/mito_tests_mito_lib.cmake b/.cmake/mito_tests_mito_lib.cmake index cb210695c..88ab480e6 100644 --- a/.cmake/mito_tests_mito_lib.cmake +++ b/.cmake/mito_tests_mito_lib.cmake @@ -45,9 +45,6 @@ mito_test_driver(tests/mito.lib/discrete/quadrature_field.cc) mito_test_driver(tests/mito.lib/discrete/mesh_field.cc) # fem -if(WITH_PETSC) - mito_test_driver(tests/mito.lib/fem/poisson.cc) -endif() mito_test_driver(tests/mito.lib/fem/block_grad_grad.cc) mito_test_driver(tests/mito.lib/fem/block_mass.cc) mito_test_driver(tests/mito.lib/fem/shape_functions_triangle_construction.cc) diff --git a/tests/mito.lib/fem/poisson.cc b/benchmarks/mito.lib/pdes/poisson.cc similarity index 96% rename from tests/mito.lib/fem/poisson.cc rename to benchmarks/mito.lib/pdes/poisson.cc index 87e5b5d9e..fd2907714 100644 --- a/tests/mito.lib/fem/poisson.cc +++ b/benchmarks/mito.lib/pdes/poisson.cc @@ -3,7 +3,6 @@ // Copyright (c) 2020-2024, the MiTo Authors, all rights reserved // -#include #include @@ -37,8 +36,8 @@ constexpr auto y = mito::functions::component; // TODO: add unit tests for blocks individually - -TEST(Fem, PoissonSquare) +int +main() { // initialize PETSc mito::petsc::initialize(); @@ -115,15 +114,11 @@ TEST(Fem, PoissonSquare) auto error_L2 = discrete_system.compute_l2_error(u_ex); // report channel << "L2 error: " << error_L2 << journal::endl; - // check that the l2 error is reasonable - EXPECT_TRUE(error_L2 < 0.02); // compute the H1 error auto error_H1 = discrete_system.compute_h1_error(u_ex); // report channel << "H1 error: " << error_H1 << journal::endl; - // check that the h1 error is reasonable - EXPECT_TRUE(error_H1 < 0.02); #ifdef WITH_VTK // the forcing term mesh field on the mesh (for visualization) From f066d3b6977538922a989267c8b55f76acd026e4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Thu, 6 Nov 2025 18:50:35 +0100 Subject: [PATCH 257/273] .github/workflows: update to {gcc14} --- .github/workflows/cmake-macos.yaml | 2 +- .github/workflows/cmake-ubuntu.yaml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 10f490523..a46da2fa4 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -27,7 +27,7 @@ jobs: target: [Debug, Release] python: ["3.11"] suite: [gcc] - suiteVersion: ["12"] + suiteVersion: ["14"] include: - suite: gcc cc: gcc diff --git a/.github/workflows/cmake-ubuntu.yaml b/.github/workflows/cmake-ubuntu.yaml index 240962dfa..27bbb4c89 100644 --- a/.github/workflows/cmake-ubuntu.yaml +++ b/.github/workflows/cmake-ubuntu.yaml @@ -27,7 +27,7 @@ jobs: target: [Debug, Release] python: ["3.11"] suite: [gcc] - suiteVersion: ["12"] + suiteVersion: ["14"] include: - suite: gcc cc: gcc From 232712786e1c6fdd161b6e2edc018b6dd9153c10 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Nov 2025 18:29:47 +0100 Subject: [PATCH 258/273] .github/workflows: build {google-benchmark} with {gcc-14} --- .github/workflows/cmake-macos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index b7f20d6ca..1420e440f 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -39,7 +39,7 @@ jobs: echo " -- install our dependencies" brew install make cmake metis open-mpi vtk # install {google-benchmark} from source to make sure it is built with the same compiler - brew install --build-from-source --cc=gcc-12 google-benchmark + brew install --build-from-source --cc=gcc-14 google-benchmark - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 From 910cd394f0c01cf8160ce3599f9470ffb1b2aa83 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Nov 2025 18:34:43 +0100 Subject: [PATCH 259/273] .github/workflows: use {vtk@9.5.1} --- .github/workflows/cmake-macos.yaml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 1420e440f..614f45e65 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -37,9 +37,10 @@ jobs: - name: ${{matrix.os}} refresh run: | echo " -- install our dependencies" - brew install make cmake metis open-mpi vtk + brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark + brew tap-new mito/vtk && brew extract --version=9.5.1 vtk mito/vtk && brew install mito/vtk/vtk@9.5.1 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 From 126ddcf1aeadc6fa1be08ef712a81b5417e75c69 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Nov 2025 20:34:50 +0100 Subject: [PATCH 260/273] .github/workflows: use {vtk@9.1.0} --- .github/workflows/cmake-macos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 614f45e65..c207737c6 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -40,7 +40,7 @@ jobs: brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark - brew tap-new mito/vtk && brew extract --version=9.5.1 vtk mito/vtk && brew install mito/vtk/vtk@9.5.1 + brew tap-new mito/vtk && brew extract --version=9.1.0 vtk mito/vtk && brew install mito/vtk/vtk@9.1.0 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 From 990decca68835b8770ac0dcf87379f8650939bdf Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Nov 2025 20:50:56 +0100 Subject: [PATCH 261/273] .github/workflows: use {vtk@9.1.0} --- .github/workflows/cmake-macos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index c207737c6..3a317bf0a 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -50,7 +50,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk + pip3 install distro 'numpy<2.0' pybind11 pytest vtk=9.1.0 - name: checkout gtest uses: actions/checkout@v3 From 5ae7a15767b1719c836ed5d7155c49f9a9c95a84 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Fri, 7 Nov 2025 20:51:17 +0100 Subject: [PATCH 262/273] .github/workflows: show available {vtk} formulae --- .github/workflows/cmake-macos.yaml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 3a317bf0a..cf2c7e07e 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -40,6 +40,7 @@ jobs: brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark + brew log --formula vtk brew tap-new mito/vtk && brew extract --version=9.1.0 vtk mito/vtk && brew install mito/vtk/vtk@9.1.0 - name: python ${{matrix.python}} setup From b88fe13f0e9d7103a8543f6631fe6ca2241786a2 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 8 Nov 2025 09:14:51 +0100 Subject: [PATCH 263/273] .github/workflows: use {vtk@9.5.1} both for {brew} and {pip} --- .github/workflows/cmake-macos.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index cf2c7e07e..e9bfe988d 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -41,7 +41,7 @@ jobs: # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark brew log --formula vtk - brew tap-new mito/vtk && brew extract --version=9.1.0 vtk mito/vtk && brew install mito/vtk/vtk@9.1.0 + brew tap-new mito/vtk && brew extract --version=9.5.1 vtk mito/vtk && brew install mito/vtk/vtk@9.5.1 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 @@ -51,7 +51,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk=9.1.0 + pip3 install distro 'numpy<2.0' pybind11 pytest vtk=9.5.1 - name: checkout gtest uses: actions/checkout@v3 From 6b6423168f8f9fd364d88f9d364b6c350c742987 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sat, 8 Nov 2025 12:17:37 +0100 Subject: [PATCH 264/273] .github/workflows: fix typo --- .github/workflows/cmake-macos.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index e9bfe988d..a32b08cd7 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -51,7 +51,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk=9.5.1 + pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.5.1 - name: checkout gtest uses: actions/checkout@v3 From f71a45316961b80409f01a3d3d34d26d6974b4ce Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Nov 2025 08:47:29 +0100 Subject: [PATCH 265/273] .github/workflows: use {vtk@9.0.2} both for {brew} and {pip} --- .github/workflows/cmake-macos.yaml | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index a32b08cd7..160f0422f 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -40,8 +40,7 @@ jobs: brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark - brew log --formula vtk - brew tap-new mito/vtk && brew extract --version=9.5.1 vtk mito/vtk && brew install mito/vtk/vtk@9.5.1 + brew tap-new mito/vtk && brew extract --version=9.0.2 vtk mito/vtk && brew install mito/vtk/vtk@9.0.2 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 @@ -51,7 +50,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.5.1 + pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.0.2 - name: checkout gtest uses: actions/checkout@v3 From 3495371f1b43b5bebfb7a6cdd0c44d7af15859f6 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Nov 2025 08:58:07 +0100 Subject: [PATCH 266/273] .github/workflows: use {vtk@9.2.6} both for {brew} and {pip} --- .github/workflows/cmake-macos.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 160f0422f..ec4a099ee 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -40,7 +40,7 @@ jobs: brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark - brew tap-new mito/vtk && brew extract --version=9.0.2 vtk mito/vtk && brew install mito/vtk/vtk@9.0.2 + brew tap-new mito/vtk && brew extract --version=9.2.6 vtk mito/vtk && brew install mito/vtk/vtk@9.2.6 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 @@ -50,7 +50,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.0.2 + pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.2.6 - name: checkout gtest uses: actions/checkout@v3 From c387b183fbd881aa7c51e6bf4afa1c8bcb39114a Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Nov 2025 09:48:49 +0100 Subject: [PATCH 267/273] .github/workflows: use {vtk@9.3.1} both for {brew} and {pip} --- .github/workflows/cmake-macos.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index ec4a099ee..1906c3a06 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -40,7 +40,7 @@ jobs: brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark - brew tap-new mito/vtk && brew extract --version=9.2.6 vtk mito/vtk && brew install mito/vtk/vtk@9.2.6 + brew tap-new mito/vtk && brew extract --version=9.3.1 vtk mito/vtk && brew install mito/vtk/vtk@9.3.1 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 @@ -50,7 +50,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.2.6 + pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.3.1 - name: checkout gtest uses: actions/checkout@v3 From 321ec720af70db398fddd706e749a5803c65d095 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Nov 2025 09:58:12 +0100 Subject: [PATCH 268/273] .github/workflows: use {vtk@9.4.0} both for {brew} and {pip} --- .github/workflows/cmake-macos.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 1906c3a06..c01f271e2 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -40,7 +40,7 @@ jobs: brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark - brew tap-new mito/vtk && brew extract --version=9.3.1 vtk mito/vtk && brew install mito/vtk/vtk@9.3.1 + brew tap-new mito/vtk && brew extract --version=9.4.0 vtk mito/vtk && brew install mito/vtk/vtk@9.4.0 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 @@ -50,7 +50,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.3.1 + pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.4.0 - name: checkout gtest uses: actions/checkout@v3 From 7072f609c23825ef8660a7eea721864db0d9b490 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Nov 2025 12:39:28 +0100 Subject: [PATCH 269/273] .github/workflows: let's see if {macos-14} makes things better --- .github/workflows/cmake-macos.yaml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index c01f271e2..06a6029ca 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -23,7 +23,7 @@ jobs: strategy: fail-fast: false matrix: - os: [macos-13] + os: [macos-14] target: [Debug, Release] python: ["3.12"] suite: [gcc] @@ -37,10 +37,9 @@ jobs: - name: ${{matrix.os}} refresh run: | echo " -- install our dependencies" - brew install make cmake metis open-mpi + brew install make cmake metis open-mpi vtk # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark - brew tap-new mito/vtk && brew extract --version=9.4.0 vtk mito/vtk && brew install mito/vtk/vtk@9.4.0 - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 @@ -50,7 +49,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk==9.4.0 + pip3 install distro 'numpy<2.0' pybind11 pytest vtk - name: checkout gtest uses: actions/checkout@v3 From 7981441f63ec57d7b951093709b6a9594213cae4 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Sun, 9 Nov 2025 16:50:32 +0100 Subject: [PATCH 270/273] .github/workflows: build {vtk} from source with {gcc-14} --- .github/workflows/cmake-macos.yaml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 06a6029ca..ba034da81 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -37,9 +37,11 @@ jobs: - name: ${{matrix.os}} refresh run: | echo " -- install our dependencies" - brew install make cmake metis open-mpi vtk + brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark + # build {vtk} from source with {gcc-14} + brew install --build-from-source --cc=gcc-14 vtk - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 From e6a1b3aab98a999a23a6e6271794163feb4d3d3d Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 10 Nov 2025 10:21:47 +0100 Subject: [PATCH 271/273] poisson: improvements to narrative --- benchmarks/mito.lib/pdes/poisson.cc | 37 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/benchmarks/mito.lib/pdes/poisson.cc b/benchmarks/mito.lib/pdes/poisson.cc index fd2907714..f7e30148e 100644 --- a/benchmarks/mito.lib/pdes/poisson.cc +++ b/benchmarks/mito.lib/pdes/poisson.cc @@ -6,35 +6,34 @@ #include -// the scalar type -using scalar_t = mito::tensor::scalar_t; -// the type of coordinates +// cartesian coordinates in 2D using coordinates_t = mito::geometry::coordinates_t<2, mito::geometry::CARTESIAN>; -// the type of cell + +// simplicial cells in 2D using cell_t = mito::geometry::triangle_t<2>; +// second degree finite elements +constexpr int degree = 2; +// assemble the finite element type +using finite_element_t = mito::fem::isoparametric_simplex_t; + // the reference simplex using reference_simplex_t = mito::geometry::reference_triangle_t; +// degree of exactness for the quadrature rule +constexpr int doe = 2; // Gauss quadrature on triangles with degree of exactness 2 using quadrature_rule_t = - mito::quadrature::quadrature_rule_t; - -// the degree of the finite element -constexpr int degree = 2; -// typedef for a finite element -using finite_element_t = mito::fem::isoparametric_simplex_t; + mito::quadrature::quadrature_rule_t; // typedef for a linear system of equations using linear_system_t = mito::matrix_solvers::petsc::linear_system_t; // typedef for a matrix solver using matrix_solver_t = mito::matrix_solvers::petsc::ksp_t; -// NOTE: component -> projection -// the function extracting the x component of a 2D vector +// the x scalar field in 2D constexpr auto x = mito::functions::component; -// the function extracting the y component of a 2D vector +// the y scalar field in 2D constexpr auto y = mito::functions::component; -// TODO: add unit tests for blocks individually int main() @@ -57,18 +56,18 @@ main() // const auto subdivisions = 1; // auto mesh = mito::mesh::tetra(original_mesh, coord_system, subdivisions); - // the zero field - auto zero = mito::fields::field(mito::functions::zero); + // create the body manifold + auto manifold = mito::manifolds::manifold(mesh, coord_system); // get the boundary mesh auto boundary_mesh = mito::mesh::boundary(mesh); + // the zero field + auto zero = mito::fields::field(mito::functions::zero); + // set homogeneous Dirichlet boundary condition auto constraints = mito::constraints::dirichlet_bc(boundary_mesh, zero); - // create the body manifold - auto manifold = mito::manifolds::manifold(mesh, coord_system); - // the function space (linear elements on the manifold) auto function_space = mito::fem::function_space(manifold, constraints); From 3c0e67cf03371d390ca5d6f5df20caefccca6ed5 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 10 Nov 2025 10:28:18 +0100 Subject: [PATCH 272/273] .github/workflows: disable {vtk} in {macos} actions --- .github/workflows/cmake-macos.yaml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index ba034da81..5eb52380e 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -40,8 +40,6 @@ jobs: brew install make cmake metis open-mpi # install {google-benchmark} from source to make sure it is built with the same compiler brew install --build-from-source --cc=gcc-14 google-benchmark - # build {vtk} from source with {gcc-14} - brew install --build-from-source --cc=gcc-14 vtk - name: python ${{matrix.python}} setup uses: actions/setup-python@v4 @@ -51,7 +49,7 @@ jobs: - name: install dependencies run: | python3 -m pip install --upgrade pip - pip3 install distro 'numpy<2.0' pybind11 pytest vtk + pip3 install distro 'numpy<2.0' pybind11 pytest - name: checkout gtest uses: actions/checkout@v3 @@ -172,7 +170,7 @@ jobs: mkdir build cd build echo " -- configuring the build" - cmake -DCMAKE_INSTALL_PREFIX=${prefix} -DCMAKE_BUILD_TYPE=${target} -DCMAKE_CXX_COMPILER=${cxx} -DPython_EXECUTABLE=${pythonLocation}/bin/python${pythonVersion} -Dpybind11_DIR=${pythonLocation}/lib/python${pythonVersion}/site-packages/pybind11/share/cmake/pybind11 -DMITO_BUILD_TESTING=ON -DMITO_BUILD_BENCHMARKS=ON -Dpyre_DIR=${{runner.temp}}/pyre_install/share/cmake/pyre -DGTest_DIR=${{runner.temp}}/gtest_install/lib/cmake/GTest -DWITH_VTK=ON -DWITH_METIS=ON ${{github.workspace}}/mito + cmake -DCMAKE_INSTALL_PREFIX=${prefix} -DCMAKE_BUILD_TYPE=${target} -DCMAKE_CXX_COMPILER=${cxx} -DPython_EXECUTABLE=${pythonLocation}/bin/python${pythonVersion} -Dpybind11_DIR=${pythonLocation}/lib/python${pythonVersion}/site-packages/pybind11/share/cmake/pybind11 -DMITO_BUILD_TESTING=ON -DMITO_BUILD_BENCHMARKS=ON -Dpyre_DIR=${{runner.temp}}/pyre_install/share/cmake/pyre -DGTest_DIR=${{runner.temp}}/gtest_install/lib/cmake/GTest -DWITH_VTK=OFF -DWITH_METIS=ON ${{github.workspace}}/mito echo " -- building mito" make -j 2 install env: From 0ba0aae2b57556dcfe896965f70664051b1b65b1 Mon Sep 17 00:00:00 2001 From: Bianca Giovanardi Date: Mon, 10 Nov 2025 11:05:29 +0100 Subject: [PATCH 273/273] .github/workflows: forgot to disable {pip} show of {vtk} in {macos} actions --- .github/workflows/cmake-macos.yaml | 2 -- 1 file changed, 2 deletions(-) diff --git a/.github/workflows/cmake-macos.yaml b/.github/workflows/cmake-macos.yaml index 5eb52380e..7369bb870 100644 --- a/.github/workflows/cmake-macos.yaml +++ b/.github/workflows/cmake-macos.yaml @@ -153,8 +153,6 @@ jobs: find ${pythonLocation}/lib/python${pythonVersion}/site-packages/pybind11 echo " -- pytest" pip3 show pytest - echo " -- vtk" - pip3 show vtk env: pythonVersion: ${{matrix.python}}