diff --git a/src/reduced_lung/tests/4C_reduced_lung_boundary_conditions_test.cpp b/src/reduced_lung/tests/4C_reduced_lung_boundary_conditions_test.cpp index f4a079d004..3f8bdc2ece 100644 --- a/src/reduced_lung/tests/4C_reduced_lung_boundary_conditions_test.cpp +++ b/src/reduced_lung/tests/4C_reduced_lung_boundary_conditions_test.cpp @@ -13,7 +13,7 @@ #include "4C_linalg_map.hpp" #include "4C_linalg_sparsematrix.hpp" #include "4C_linalg_vector.hpp" -#include "4C_red_airways_elementbase.hpp" +#include "4C_reduced_lung_test_utils_test.hpp" #include "4C_unittest_utils_assertions_test.hpp" #include "4C_utils_exceptions.hpp" #include "4C_utils_function_manager.hpp" @@ -36,29 +36,6 @@ namespace using namespace FourC::ReducedLung; using namespace FourC::ReducedLung::BoundaryConditions; - std::unique_ptr make_airway_discretization( - const std::vector& node_ids, const std::vector>& element_nodes) - { - auto dis = - std::make_unique("boundary_conditions_test", MPI_COMM_WORLD, 3); - - for (int node_id : node_ids) - { - std::array coords{static_cast(node_id), 0.0, 0.0}; - dis->add_node(coords, node_id, nullptr); - } - - for (size_t i = 0; i < element_nodes.size(); ++i) - { - auto ele = std::make_shared(static_cast(i), 0); - ele->set_node_ids(2, element_nodes[i].data()); - dis->add_element(ele); - } - - dis->fill_complete(Core::FE::OptionsFillComplete::none()); - return dis; - } - using InputBc = ReducedLungParameters::BoundaryConditions; //! Boundary condition input together with the constrained nodes of the mesh it refers to. @@ -199,7 +176,8 @@ namespace BoundaryConditionFixture make_fixture() { BoundaryConditionFixture fixture; - fixture.discretization = make_airway_discretization({0, 1, 2}, {{0, 1}, {1, 2}}); + fixture.discretization = + ReducedLung::TestUtils::make_chain_discretization("boundary_conditions_test", 2); fixture.set_bc_input(make_constant_parameters()); fixture.ele_ids_per_node = {{0, {0}}, {1, {0, 1}}, {2, {1}}}; fixture.global_dof_per_ele = {{0, 3}, {1, 3}}; diff --git a/src/reduced_lung/tests/4C_reduced_lung_helpers_test.cpp b/src/reduced_lung/tests/4C_reduced_lung_helpers_test.cpp index 35fc86fcfc..65e5bf6465 100644 --- a/src/reduced_lung/tests/4C_reduced_lung_helpers_test.cpp +++ b/src/reduced_lung/tests/4C_reduced_lung_helpers_test.cpp @@ -13,6 +13,7 @@ #include "4C_io_input_field.hpp" #include "4C_linalg_map.hpp" #include "4C_rebalance.hpp" +#include "4C_reduced_lung_test_utils_test.hpp" #include @@ -127,45 +128,6 @@ namespace return params; } - std::unique_ptr make_discretization( - const std::vector>& node_coordinates, - const std::vector>& element_nodes, const char* name) - { - auto discretization = std::make_unique(name, MPI_COMM_WORLD, 3); - Core::Rebalance::RebalanceParameters rebalance_parameters; - build_discretization_from_nodes_and_elements( - *discretization, node_coordinates, element_nodes, rebalance_parameters); - discretization->fill_complete(Core::FE::OptionsFillComplete{ - .assign_degrees_of_freedom = true, - .init_elements = true, - .do_boundary_conditions = false, - }); - return discretization; - } - - //! A straight chain of @p num_elements line2 elements with unit length along the x-axis. - std::unique_ptr make_chain_discretization( - const int num_elements, const char* name) - { - std::vector> node_coordinates; - std::vector> element_nodes; - for (int node_id = 0; node_id <= num_elements; ++node_id) - { - node_coordinates.push_back({static_cast(node_id), 0.0, 0.0}); - if (node_id > 0) element_nodes.push_back({node_id - 1, node_id}); - } - return make_discretization(node_coordinates, element_nodes, name); - } - - //! A single element splitting into two elements at its outlet node. - std::unique_ptr make_bifurcation_discretization(const char* name) - { - const std::vector> node_coordinates{ - {0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {2.0, 1.0, 0.0}, {2.0, -1.0, 0.0}}; - const std::vector> element_nodes{{0, 1}, {1, 2}, {1, 3}}; - return make_discretization(node_coordinates, element_nodes, name); - } - TEST(ReducedLungHelpersTests, CreateGlobalDofMapsBuildsOffsetsInElementOrder) { const std::map local_dof_per_ele{{7, 3}, {1, 4}, {5, 2}}; @@ -308,7 +270,8 @@ namespace TEST(ReducedLungHelpersTests, CreateLocalElementModelsBuildsModelContainers) { const auto params = make_setup_model_parameters(); - auto discretization = make_chain_discretization(3, "local_element_models_test"); + auto discretization = + ReducedLung::TestUtils::make_chain_discretization("local_element_models_test", 3); Airways::AirwayContainer airways; TerminalUnits::TerminalUnitContainer terminal_units; @@ -355,7 +318,8 @@ namespace TEST(ReducedLungHelpersTests, CreateLocalElementModelsUsesSelectedModelStateCount) { const auto params = make_revisited_airway_model_parameters(); - auto discretization = make_chain_discretization(4, "revisited_airway_model_test"); + auto discretization = + ReducedLung::TestUtils::make_chain_discretization("revisited_airway_model_test", 4); Airways::AirwayContainer airways; TerminalUnits::TerminalUnitContainer terminal_units; @@ -377,7 +341,8 @@ namespace TEST(ReducedLungHelpersTests, CreateGlobalEleIdsPerNodeCollectsAdjacency) { - auto discretization = make_bifurcation_discretization("global_ele_ids_test"); + auto discretization = + ReducedLung::TestUtils::make_bifurcation_discretization("global_ele_ids_test"); auto global_ele_ids_per_node = create_global_ele_ids_per_node(*discretization, MPI_COMM_WORLD); ASSERT_EQ(global_ele_ids_per_node.size(), 4u); diff --git a/src/reduced_lung/tests/4C_reduced_lung_junctions_test.cpp b/src/reduced_lung/tests/4C_reduced_lung_junctions_test.cpp index d0df966011..4ce0802254 100644 --- a/src/reduced_lung/tests/4C_reduced_lung_junctions_test.cpp +++ b/src/reduced_lung/tests/4C_reduced_lung_junctions_test.cpp @@ -13,7 +13,7 @@ #include "4C_linalg_map.hpp" #include "4C_linalg_sparsematrix.hpp" #include "4C_linalg_vector.hpp" -#include "4C_red_airways_elementbase.hpp" +#include "4C_reduced_lung_test_utils_test.hpp" #include "4C_unittest_utils_assertions_test.hpp" #include "4C_utils_exceptions.hpp" @@ -55,28 +55,6 @@ namespace } } - std::unique_ptr make_airway_discretization( - const std::vector& node_ids, const std::vector>& element_nodes) - { - auto dis = std::make_unique("junctions_test", MPI_COMM_WORLD, 3); - - for (int node_id : node_ids) - { - std::array coords{static_cast(node_id), 0.0, 0.0}; - dis->add_node(coords, node_id, nullptr); - } - - for (size_t i = 0; i < element_nodes.size(); ++i) - { - auto ele = std::make_shared(static_cast(i), 0); - ele->set_node_ids(2, element_nodes[i].data()); - dis->add_element(ele); - } - - dis->fill_complete(Core::FE::OptionsFillComplete::none()); - return dis; - } - TEST(JunctionsTests, ConnectionResidualAssembly) { ConnectionData connections; @@ -226,9 +204,9 @@ namespace GTEST_SKIP() << "Junction creation tests require a serial communicator."; } - auto dis = make_airway_discretization({1, 2, 3}, {{1, 2}, {2, 3}}); + auto dis = ReducedLung::TestUtils::make_chain_discretization("junctions_test", 2); - std::map> ele_ids_per_node{{1, {0}}, {2, {0, 1}}, {3, {1}}}; + std::map> ele_ids_per_node{{0, {0}}, {1, {0, 1}}, {2, {1}}}; std::map global_dof_per_ele{{0, 3}, {1, 3}}; std::map first_global_dof_of_ele{{0, 0}, {1, 3}}; @@ -256,9 +234,9 @@ namespace GTEST_SKIP() << "Junction creation tests require a serial communicator."; } - auto dis = make_airway_discretization({1, 2, 3, 4}, {{1, 2}, {2, 3}, {2, 4}}); + auto dis = ReducedLung::TestUtils::make_bifurcation_discretization("junctions_test"); - std::map> ele_ids_per_node{{1, {0}}, {2, {0, 1, 2}}, {3, {1}}, {4, {2}}}; + std::map> ele_ids_per_node{{0, {0}}, {1, {0, 1, 2}}, {2, {1}}, {3, {2}}}; std::map global_dof_per_ele{{0, 3}, {1, 3}, {2, 3}}; std::map first_global_dof_of_ele{{0, 0}, {1, 3}, {2, 6}}; @@ -287,9 +265,9 @@ namespace GTEST_SKIP() << "Junction creation tests require a serial communicator."; } - auto dis = make_airway_discretization({1, 2, 3}, {{1, 2}, {2, 3}}); + auto dis = ReducedLung::TestUtils::make_chain_discretization("junctions_test", 2); - std::map> ele_ids_per_node{{1, {0}}, {3, {1}}}; + std::map> ele_ids_per_node{{0, {0}}, {2, {1}}}; std::map global_dof_per_ele{{0, 3}, {1, 3}}; std::map first_global_dof_of_ele{{0, 0}, {1, 3}}; @@ -310,9 +288,10 @@ namespace GTEST_SKIP() << "Junction creation tests require a serial communicator."; } - auto dis = make_airway_discretization({1, 2, 3}, {{1, 2}, {3, 2}}); + auto dis = ReducedLung::TestUtils::make_line2_discretization( + "junctions_test", {{0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {2.0, 0.0, 0.0}}, {{0, 1}, {2, 1}}); - std::map> ele_ids_per_node{{1, {0}}, {2, {0, 1}}, {3, {1}}}; + std::map> ele_ids_per_node{{0, {0}}, {1, {0, 1}}, {2, {1}}}; std::map global_dof_per_ele{{0, 3}, {1, 3}}; std::map first_global_dof_of_ele{{0, 0}, {1, 3}}; @@ -333,9 +312,9 @@ namespace GTEST_SKIP() << "Junction creation tests require a serial communicator."; } - auto dis = make_airway_discretization({1, 2, 3}, {{1, 2}, {2, 3}}); + auto dis = ReducedLung::TestUtils::make_chain_discretization("junctions_test", 2); - std::map> ele_ids_per_node{{1, {0}}, {2, {0, 1, 2, 3}}, {3, {1}}}; + std::map> ele_ids_per_node{{0, {0}}, {1, {0, 1, 2, 3}}, {2, {1}}}; std::map global_dof_per_ele{{0, 3}, {1, 3}}; std::map first_global_dof_of_ele{{0, 0}, {1, 3}}; diff --git a/src/reduced_lung/tests/4C_reduced_lung_test_utils_test.hpp b/src/reduced_lung/tests/4C_reduced_lung_test_utils_test.hpp index f5262b181a..8904a07b36 100644 --- a/src/reduced_lung/tests/4C_reduced_lung_test_utils_test.hpp +++ b/src/reduced_lung/tests/4C_reduced_lung_test_utils_test.hpp @@ -13,12 +13,19 @@ #include "4C_config.hpp" +#include "4C_fem_discretization.hpp" #include "4C_linalg_map.hpp" #include "4C_linalg_sparsematrix.hpp" #include "4C_linalg_vector.hpp" +#include "4C_rebalance.hpp" #include "4C_reduced_lung_airways.hpp" +#include "4C_reduced_lung_helpers.hpp" #include "4C_reduced_lung_terminal_unit.hpp" +#include + +#include +#include #include #include @@ -26,6 +33,56 @@ FOUR_C_NAMESPACE_OPEN namespace ReducedLung::TestUtils { + /** + * Build a line2 discretization from nodal coordinates and connectivity, using the same routine + * as the production code. Nodes and elements get 0-based ids in the order they are passed; + * @p element_nodes is the connectivity [node_in, node_out] referring to those node ids. + */ + inline std::unique_ptr make_line2_discretization( + const std::string& name, const std::vector>& node_coordinates, + const std::vector>& element_nodes) + { + auto discretization = std::make_unique(name, MPI_COMM_WORLD, 3); + const Core::Rebalance::RebalanceParameters rebalance_parameters{}; + build_discretization_from_nodes_and_elements( + *discretization, node_coordinates, element_nodes, rebalance_parameters); + discretization->fill_complete(Core::FE::OptionsFillComplete{ + .assign_degrees_of_freedom = true, + .init_elements = true, + .do_boundary_conditions = false, + }); + + return discretization; + } + + /** + * Build a straight line discretization along the x-axis with 0-based node ids. + * The discretization is bifurcation-free consisting of @p num_elements line2 elements of unit + * length. + */ + inline std::unique_ptr make_chain_discretization( + const std::string& name, const int num_elements) + { + std::vector> node_coordinates; + std::vector> element_nodes; + for (int node_id = 0; node_id <= num_elements; ++node_id) + { + node_coordinates.push_back({static_cast(node_id), 0.0, 0.0}); + if (node_id > 0) element_nodes.push_back({node_id - 1, node_id}); + } + return make_line2_discretization(name, node_coordinates, element_nodes); + } + + //! A single element splitting into two elements at its outlet node. + inline std::unique_ptr make_bifurcation_discretization( + const std::string& name) + { + const std::vector> node_coordinates{ + {0.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {2.0, 1.0, 0.0}, {2.0, -1.0, 0.0}}; + const std::vector> element_nodes{{0, 1}, {1, 2}, {1, 3}}; + return make_line2_discretization(name, node_coordinates, element_nodes); + } + // Generalized helper to check a Jacobian column against a central finite-difference // approximation of the residual. Works for both TerminalUnitModel and AirwayModel as long // as the model exposes `data`, `residual_evaluator` and the data structure