feat(FieldDofMap): Completed FieldDofMap migration
also removed legacy BarotropicPolytrope implementation
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include <cmath>
|
||||
#include <cstddef>
|
||||
#include <mfem.hpp>
|
||||
#include <mpi.h>
|
||||
@@ -79,6 +80,11 @@ namespace field_dof_map_test_utils {
|
||||
concept CanMakeFieldDofMap =
|
||||
requires(const mfem::ParFiniteElementSpace &space) { field::make_field_dof_map<FieldT, Schema>(space); };
|
||||
|
||||
template <typename FieldT>
|
||||
concept CanMakeFieldDofGridFunctionAdapter = requires(const mfem::ParFiniteElementSpace &space) {
|
||||
field::make_field_dof_grid_function_adapter<FieldT, Schema>(space);
|
||||
};
|
||||
|
||||
using AlternateSchema = domain::DomainSchema<
|
||||
domain::MaterialList<
|
||||
domain::Material<domain::Core, 11>,
|
||||
@@ -90,7 +96,7 @@ namespace field_dof_map_test_utils {
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Preserves Canonical Bidirectional Indexing",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -166,7 +172,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Rejects Invalid Canonical Mappings",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -191,7 +197,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Rejects Out Of Range Index Queries",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -212,7 +218,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Gather Selects Exactly The Active True DOFs",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -247,7 +253,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Scatter Produces The Canonical Supported Projection",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -281,7 +287,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Gather Scatter Projects A Full Vector Onto Field Support",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -310,7 +316,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Scatter Into Preserves Unsupported True DOFs",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -337,7 +343,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Scatter Add Accumulates Only Onto Active True DOFs",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -364,7 +370,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Operations Support MFEM Vector Views Without Resizing",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -406,7 +412,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Operations Reject Incompatible Vector Sizes",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -433,7 +439,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Identity Mapping Is An Exact Vector Identity",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -463,7 +469,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Validates Field DOF Support Consistency",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -495,7 +501,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Factory Is Available Only For Spatial Registered Fields",
|
||||
tags::unit &tags::field
|
||||
tags::field_dof_unit
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -509,12 +515,24 @@ TEST_CASE(
|
||||
|
||||
STATIC_REQUIRE_FALSE(field_dof_map_test_utils::CanMakeFieldDofMap<field::BarotropicConstant>);
|
||||
|
||||
STATIC_REQUIRE(field_dof_map_test_utils::CanMakeFieldDofGridFunctionAdapter<field::Density>);
|
||||
|
||||
STATIC_REQUIRE(field_dof_map_test_utils::CanMakeFieldDofGridFunctionAdapter<field::Enthalpy>);
|
||||
|
||||
STATIC_REQUIRE(field_dof_map_test_utils::CanMakeFieldDofGridFunctionAdapter<field::Gravity>);
|
||||
|
||||
STATIC_REQUIRE(field_dof_map_test_utils::CanMakeFieldDofGridFunctionAdapter<field::Displacement>);
|
||||
|
||||
STATIC_REQUIRE_FALSE(
|
||||
field_dof_map_test_utils::CanMakeFieldDofGridFunctionAdapter<field::BarotropicConstant>
|
||||
);
|
||||
|
||||
CHECK(true);
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Factory Exactly Preserves Density Support",
|
||||
tags::integration &tags::field
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -567,7 +585,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Factory Exactly Preserves H1 Enthalpy Support",
|
||||
tags::integration &tags::field
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -614,7 +632,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Factory Produces Identity Maps For All Supported Fields",
|
||||
tags::integration &tags::field
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -648,7 +666,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Factory Uses Schema Material Bindings Rather Than Numeric Conventions",
|
||||
tags::integration &tags::field
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -681,7 +699,7 @@ TEST_CASE(
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Map Reduced Vectors Round Trip Through Real Field Support",
|
||||
tags::integration &tags::field
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
@@ -721,4 +739,246 @@ TEST_CASE(
|
||||
CHECK(full(trueDof) == 0.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Grid Function Adapter Gathers Exactly The Supported True DOFs",
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
mfem::Mesh serialMesh = field_dof_map_test_utils::make_split_mesh();
|
||||
mfem::ParMesh mesh(MPI_COMM_WORLD, serialMesh);
|
||||
|
||||
auto fec = field::Field<field::Density>::make_fec<field::Density::Scalar>(2);
|
||||
auto finiteElementSpace =
|
||||
field::Field<field::Density>::make_fespace<field::Density::Scalar>(mesh, *fec);
|
||||
|
||||
REQUIRE(finiteElementSpace != nullptr);
|
||||
|
||||
const field::FieldDofGridFunctionAdapter adapter =
|
||||
field::make_field_dof_grid_function_adapter<field::Density, field_dof_map_test_utils::Schema>(
|
||||
*finiteElementSpace
|
||||
);
|
||||
|
||||
mfem::Vector full(adapter.dof_map().full_size());
|
||||
for (int trueDof = 0; trueDof < full.Size(); ++trueDof) {
|
||||
full(trueDof) = 1.25 + 0.375 * static_cast<double>(trueDof + 1);
|
||||
}
|
||||
|
||||
mfem::ParGridFunction gridFunction(finiteElementSpace.get());
|
||||
gridFunction.SetFromTrueDofs(full);
|
||||
|
||||
const mfem::Vector expected = adapter.dof_map().gather(full);
|
||||
const mfem::Vector actual = adapter.gather(gridFunction);
|
||||
|
||||
REQUIRE(actual.Size() == expected.Size());
|
||||
for (int reducedDof = 0; reducedDof < actual.Size(); ++reducedDof) {
|
||||
CAPTURE(reducedDof);
|
||||
CHECK(actual(reducedDof) == expected(reducedDof));
|
||||
}
|
||||
|
||||
mfem::Vector output(adapter.dof_map().reduced_size());
|
||||
adapter.gather(gridFunction, output);
|
||||
|
||||
for (int reducedDof = 0; reducedDof < output.Size(); ++reducedDof) {
|
||||
CAPTURE(reducedDof);
|
||||
CHECK(output(reducedDof) == expected(reducedDof));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Grid Function Adapter Scatter Projects And Round Trips Reduced Fields",
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
mfem::Mesh serialMesh = field_dof_map_test_utils::make_split_mesh();
|
||||
mfem::ParMesh mesh(MPI_COMM_WORLD, serialMesh);
|
||||
|
||||
auto fec = field::Field<field::Enthalpy>::make_fec<field::Enthalpy::Scalar>(2);
|
||||
auto finiteElementSpace =
|
||||
field::Field<field::Enthalpy>::make_fespace<field::Enthalpy::Scalar>(mesh, *fec);
|
||||
|
||||
REQUIRE(finiteElementSpace != nullptr);
|
||||
|
||||
const field::FieldDofGridFunctionAdapter adapter =
|
||||
field::make_field_dof_grid_function_adapter<field::Enthalpy, field_dof_map_test_utils::Schema>(
|
||||
*finiteElementSpace
|
||||
);
|
||||
|
||||
mfem::Vector reduced(adapter.dof_map().reduced_size());
|
||||
for (int reducedDof = 0; reducedDof < reduced.Size(); ++reducedDof) {
|
||||
reduced(reducedDof) = -0.75 + 0.0625 * static_cast<double>(reducedDof + 1);
|
||||
}
|
||||
|
||||
mfem::ParGridFunction gridFunction(finiteElementSpace.get());
|
||||
gridFunction = 91.0;
|
||||
adapter.scatter(reduced, gridFunction);
|
||||
|
||||
mfem::Vector actualFull;
|
||||
gridFunction.GetTrueDofs(actualFull);
|
||||
|
||||
const mfem::Vector expectedFull = adapter.dof_map().scatter(reduced);
|
||||
|
||||
REQUIRE(actualFull.Size() == expectedFull.Size());
|
||||
for (int trueDof = 0; trueDof < actualFull.Size(); ++trueDof) {
|
||||
CAPTURE(trueDof);
|
||||
CHECK(actualFull(trueDof) == expectedFull(trueDof));
|
||||
|
||||
if (!adapter.dof_map().contains_true_dof(trueDof)) {
|
||||
CHECK(actualFull(trueDof) == 0.0);
|
||||
}
|
||||
}
|
||||
|
||||
const mfem::Vector recovered = adapter.gather(gridFunction);
|
||||
REQUIRE(recovered.Size() == reduced.Size());
|
||||
|
||||
for (int reducedDof = 0; reducedDof < reduced.Size(); ++reducedDof) {
|
||||
CAPTURE(reducedDof);
|
||||
CHECK(recovered(reducedDof) == reduced(reducedDof));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Grid Function Adapter Scatter Into Preserves Unsupported True DOFs",
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
mfem::Mesh serialMesh = field_dof_map_test_utils::make_split_mesh();
|
||||
mfem::ParMesh mesh(MPI_COMM_WORLD, serialMesh);
|
||||
|
||||
auto fec = field::Field<field::Density>::make_fec<field::Density::Scalar>(2);
|
||||
auto finiteElementSpace =
|
||||
field::Field<field::Density>::make_fespace<field::Density::Scalar>(mesh, *fec);
|
||||
|
||||
REQUIRE(finiteElementSpace != nullptr);
|
||||
|
||||
const field::FieldDofGridFunctionAdapter adapter =
|
||||
field::make_field_dof_grid_function_adapter<field::Density, field_dof_map_test_utils::Schema>(
|
||||
*finiteElementSpace
|
||||
);
|
||||
|
||||
mfem::Vector initialFull(adapter.dof_map().full_size());
|
||||
for (int trueDof = 0; trueDof < initialFull.Size(); ++trueDof) {
|
||||
initialFull(trueDof) = 40.0 + static_cast<double>(trueDof);
|
||||
}
|
||||
|
||||
mfem::Vector reduced(adapter.dof_map().reduced_size());
|
||||
for (int reducedDof = 0; reducedDof < reduced.Size(); ++reducedDof) {
|
||||
reduced(reducedDof) = -10.0 - static_cast<double>(reducedDof);
|
||||
}
|
||||
|
||||
mfem::ParGridFunction gridFunction(finiteElementSpace.get());
|
||||
gridFunction.SetFromTrueDofs(initialFull);
|
||||
adapter.scatter_into(reduced, gridFunction);
|
||||
|
||||
mfem::Vector actualFull;
|
||||
gridFunction.GetTrueDofs(actualFull);
|
||||
|
||||
mfem::Vector expectedFull(initialFull);
|
||||
adapter.dof_map().scatter_into(reduced, expectedFull);
|
||||
|
||||
REQUIRE(actualFull.Size() == expectedFull.Size());
|
||||
for (int trueDof = 0; trueDof < actualFull.Size(); ++trueDof) {
|
||||
CAPTURE(trueDof);
|
||||
CHECK(actualFull(trueDof) == expectedFull(trueDof));
|
||||
|
||||
if (!adapter.dof_map().contains_true_dof(trueDof)) {
|
||||
CHECK(actualFull(trueDof) == initialFull(trueDof));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Grid Function Adapter Is Exact For Identity Vector Field Maps",
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
mfem::Mesh serialMesh = field_dof_map_test_utils::make_split_mesh();
|
||||
mfem::ParMesh mesh(MPI_COMM_WORLD, serialMesh);
|
||||
|
||||
auto fec = field::Field<field::Displacement>::make_fec<field::Displacement::Vector>(2);
|
||||
auto finiteElementSpace =
|
||||
field::Field<field::Displacement>::make_fespace<field::Displacement::Vector>(mesh, *fec);
|
||||
|
||||
REQUIRE(finiteElementSpace != nullptr);
|
||||
|
||||
const field::FieldDofGridFunctionAdapter adapter =
|
||||
field::make_field_dof_grid_function_adapter<field::Displacement, field_dof_map_test_utils::Schema>(
|
||||
*finiteElementSpace
|
||||
);
|
||||
|
||||
REQUIRE(adapter.dof_map().is_identity());
|
||||
|
||||
mfem::Vector reduced(adapter.dof_map().reduced_size());
|
||||
for (int dof = 0; dof < reduced.Size(); ++dof) {
|
||||
reduced(dof) = std::sin(0.23 * static_cast<double>(dof + 1));
|
||||
}
|
||||
|
||||
mfem::ParGridFunction gridFunction(finiteElementSpace.get());
|
||||
adapter.scatter(reduced, gridFunction);
|
||||
|
||||
const mfem::Vector recovered = adapter.gather(gridFunction);
|
||||
|
||||
REQUIRE(recovered.Size() == reduced.Size());
|
||||
for (int dof = 0; dof < reduced.Size(); ++dof) {
|
||||
CAPTURE(dof);
|
||||
CHECK(recovered(dof) == reduced(dof));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE(
|
||||
"Field DOF Grid Function Adapter Rejects Incompatible Maps Spaces And Vectors",
|
||||
tags::field_dof_integration
|
||||
) {
|
||||
namespace field = mean_field::field;
|
||||
|
||||
mfem::Mesh serialMesh = field_dof_map_test_utils::make_split_mesh();
|
||||
mfem::ParMesh mesh(MPI_COMM_WORLD, serialMesh);
|
||||
|
||||
auto fec = field::Field<field::Density>::make_fec<field::Density::Scalar>(2);
|
||||
auto finiteElementSpace =
|
||||
field::Field<field::Density>::make_fespace<field::Density::Scalar>(mesh, *fec);
|
||||
|
||||
auto otherFec = field::Field<field::Density>::make_fec<field::Density::Scalar>(2);
|
||||
auto otherFiniteElementSpace =
|
||||
field::Field<field::Density>::make_fespace<field::Density::Scalar>(mesh, *otherFec);
|
||||
|
||||
REQUIRE(finiteElementSpace != nullptr);
|
||||
REQUIRE(otherFiniteElementSpace != nullptr);
|
||||
REQUIRE(finiteElementSpace->GetTrueVSize() == otherFiniteElementSpace->GetTrueVSize());
|
||||
|
||||
const field::FieldDofGridFunctionAdapter adapter =
|
||||
field::make_field_dof_grid_function_adapter<field::Density, field_dof_map_test_utils::Schema>(
|
||||
*finiteElementSpace
|
||||
);
|
||||
|
||||
const mfem::Array<int> empty;
|
||||
CHECK_THROWS_AS(
|
||||
(field::FieldDofGridFunctionAdapter(
|
||||
field::FieldDofMap(finiteElementSpace->GetTrueVSize() + 1, empty),
|
||||
*finiteElementSpace
|
||||
)),
|
||||
std::invalid_argument
|
||||
);
|
||||
|
||||
mfem::ParGridFunction gridFunction(finiteElementSpace.get());
|
||||
mfem::ParGridFunction otherGridFunction(otherFiniteElementSpace.get());
|
||||
|
||||
mfem::Vector reduced(adapter.dof_map().reduced_size());
|
||||
reduced = 1.0;
|
||||
|
||||
mfem::Vector wrongReduced(adapter.dof_map().reduced_size() + 1);
|
||||
mfem::Vector wrongOutput(adapter.dof_map().reduced_size() + 1);
|
||||
|
||||
CHECK_THROWS_AS(adapter.gather(otherGridFunction), std::invalid_argument);
|
||||
CHECK_THROWS_AS(adapter.scatter(reduced, otherGridFunction), std::invalid_argument);
|
||||
CHECK_THROWS_AS(adapter.scatter_into(reduced, otherGridFunction), std::invalid_argument);
|
||||
|
||||
CHECK_THROWS_AS(adapter.gather(gridFunction, wrongOutput), std::invalid_argument);
|
||||
CHECK_THROWS_AS(adapter.scatter(wrongReduced, gridFunction), std::invalid_argument);
|
||||
CHECK_THROWS_AS(adapter.scatter_into(wrongReduced, gridFunction), std::invalid_argument);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user