feat(field-support): added field support system, mid migration

currently the barotope and the pressure force operator are migrated to the new support system
This commit is contained in:
2026-08-23 10:13:53 -04:00
parent dc912fd15e
commit 0f3ca8050b
137 changed files with 29975 additions and 16389 deletions

View File

@@ -17,21 +17,14 @@ TEST_CASE(
constexpr double jacobian_tolerance = 1.0e-8;
constexpr double zero_tolerance = 1.0e-14;
constexpr int velocity_block =
solver::block_index(solver::FieldBlock::velocity);
constexpr int density_block =
solver::block_index(solver::FieldBlock::density);
constexpr int gravity_gradient_block =
solver::block_index(solver::FieldBlock::gravity_gradient);
constexpr int gravity_potential_block =
solver::block_index(solver::FieldBlock::gravity_potential);
constexpr int displacement_block =
solver::block_index(solver::FieldBlock::displacement);
constexpr int block_count = solver::field_block_count;
constexpr int velocity_block = solver::block_index(solver::FieldBlock::velocity);
constexpr int density_block = solver::block_index(solver::FieldBlock::density);
constexpr int gravity_gradient_block = solver::block_index(solver::FieldBlock::gravity_gradient);
constexpr int gravity_potential_block = solver::block_index(solver::FieldBlock::gravity_potential);
constexpr int displacement_block = solver::block_index(solver::FieldBlock::displacement);
constexpr int block_count = solver::field_block_count;
mfem::Mesh mesh = mfem::Mesh::MakeCartesian3D(
1, 1, 1, mfem::Element::HEXAHEDRON, 1.0, 1.0, 1.0
);
mfem::Mesh mesh = mfem::Mesh::MakeCartesian3D(1, 1, 1, mfem::Element::HEXAHEDRON, 1.0, 1.0, 1.0);
mfem::H1_FECollection velocity_fec(2, dim);
mfem::L2_FECollection density_fec(1, dim);
@@ -39,54 +32,35 @@ TEST_CASE(
mfem::L2_FECollection gravity_potential_fec(1, dim);
mfem::H1_FECollection displacement_fec(2, dim);
mfem::FiniteElementSpace velocity_fes(
&mesh, &velocity_fec, dim, mfem::Ordering::byVDIM
);
mfem::FiniteElementSpace velocity_fes(&mesh, &velocity_fec, dim, mfem::Ordering::byVDIM);
mfem::FiniteElementSpace density_fes(&mesh, &density_fec);
mfem::FiniteElementSpace gravity_gradient_fes(&mesh, &gravity_gradient_fec);
mfem::FiniteElementSpace gravity_potential_fes(
&mesh, &gravity_potential_fec
);
mfem::FiniteElementSpace displacement_fes(
&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM
);
mfem::FiniteElementSpace gravity_potential_fes(&mesh, &gravity_potential_fec);
mfem::FiniteElementSpace displacement_fes(&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM);
mfem::GridFunction displacement(&displacement_fes);
displacement = 0.0;
mapping::DomainMapper domain_mapper(displacement, 1.0, 2.0);
INFO(
std::format(
"Domain mapping is has displacement field: {}",
domain_mapper.HasDisplacementField()
)
);
INFO(
std::format(
"Domain mapping is identity: {}", domain_mapper.CalcIsIdentity()
)
);
INFO(std::format("Domain mapping is has displacement field: {}", domain_mapper.HasDisplacementField()));
INFO(std::format("Domain mapping is identity: {}", domain_mapper.CalcIsIdentity()));
REQUIRE(domain_mapper.CalcIsIdentity());
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
const mfem::FiniteElement *gravity_gradient_element =
gravity_gradient_fes.GetFE(0);
const mfem::FiniteElement *gravity_potential_element =
gravity_potential_fes.GetFE(0);
const mfem::FiniteElement *displacement_element = displacement_fes.GetFE(0);
mfem::ElementTransformation *transformation =
mesh.GetElementTransformation(0);
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
const mfem::FiniteElement *gravity_gradient_element = gravity_gradient_fes.GetFE(0);
const mfem::FiniteElement *gravity_potential_element = gravity_potential_fes.GetFE(0);
const mfem::FiniteElement *displacement_element = displacement_fes.GetFE(0);
mfem::ElementTransformation *transformation = mesh.GetElementTransformation(0);
const int velocity_dofs_count = velocity_element->GetDof();
const int density_dofs_count = density_element->GetDof();
const int gravity_gradient_dofs_count = gravity_gradient_element->GetDof();
const int gravity_potential_dofs_count =
gravity_potential_element->GetDof();
const int displacement_dofs_count = displacement_element->GetDof();
const int velocity_size = dim * velocity_dofs_count;
const int displacement_size = dim * displacement_dofs_count;
const int velocity_dofs_count = velocity_element->GetDof();
const int density_dofs_count = density_element->GetDof();
const int gravity_gradient_dofs_count = gravity_gradient_element->GetDof();
const int gravity_potential_dofs_count = gravity_potential_element->GetDof();
const int displacement_dofs_count = displacement_element->GetDof();
const int velocity_size = dim * velocity_dofs_count;
const int displacement_size = dim * displacement_dofs_count;
mfem::Vector velocity_dofs(velocity_size);
mfem::Vector density_dofs(density_dofs_count);
@@ -116,9 +90,8 @@ TEST_CASE(
}
for (int i = 0; i < gravity_gradient_dofs_count; ++i) {
const double sign = i % 3 == 0 ? -1.0 : 1.0;
gravity_gradient_direction(i) =
sign * (0.03 + 0.005 * static_cast<double>(i));
const double sign = i % 3 == 0 ? -1.0 : 1.0;
gravity_gradient_direction(i) = sign * (0.03 + 0.005 * static_cast<double>(i));
}
for (int i = 0; i < velocity_size; ++i) {
@@ -161,14 +134,10 @@ TEST_CASE(
);
const int maximum_order = std::max(
velocity_element->GetOrder(),
std::max(
density_element->GetOrder(), gravity_gradient_element->GetOrder()
)
);
const mfem::IntegrationRule &integration_rule = mfem::IntRules.Get(
velocity_element->GetGeomType(), 2 * maximum_order + 8
velocity_element->GetOrder(), std::max(density_element->GetOrder(), gravity_gradient_element->GetOrder())
);
const mfem::IntegrationRule &integration_rule =
mfem::IntRules.Get(velocity_element->GetGeomType(), 2 * maximum_order + 8);
integrator.SetIntegrationRule(integration_rule);
mfem::DenseMatrix dv_dv(velocity_size, velocity_size);
@@ -180,9 +149,7 @@ TEST_CASE(
dv_dgrad_phi = 1.0;
dv_ddisplacement = 1.0;
mfem::Array2D<mfem::DenseMatrix *> element_matrices(
block_count, block_count
);
mfem::Array2D<mfem::DenseMatrix *> element_matrices(block_count, block_count);
for (int row = 0; row < block_count; ++row) {
for (int column = 0; column < block_count; ++column) {
@@ -193,25 +160,19 @@ TEST_CASE(
element_matrices(velocity_block, velocity_block) = &dv_dv;
element_matrices(velocity_block, density_block) = &dv_drho;
element_matrices(velocity_block, gravity_gradient_block) = &dv_dgrad_phi;
element_matrices(velocity_block, displacement_block) = &dv_ddisplacement;
element_matrices(velocity_block, displacement_block) = &dv_ddisplacement;
integrator.AssembleElementGrad(
elements, *transformation, element_state, element_matrices
);
integrator.AssembleElementGrad(elements, *transformation, element_state, element_matrices);
auto assemble_velocity_residual =
[&](const mfem::Vector &density_state,
const mfem::Vector &gravity_gradient_state) {
element_state[density_block] = &density_state;
element_state[gravity_gradient_block] = &gravity_gradient_state;
integrator.AssembleElementVector(
elements, *transformation, element_state, element_residual
);
return mfem::Vector(velocity_residual);
};
auto assemble_velocity_residual = [&](const mfem::Vector &density_state,
const mfem::Vector &gravity_gradient_state) {
element_state[density_block] = &density_state;
element_state[gravity_gradient_block] = &gravity_gradient_state;
integrator.AssembleElementVector(elements, *transformation, element_state, element_residual);
return mfem::Vector(velocity_residual);
};
auto relative_error = [](mfem::Vector computed,
const mfem::Vector &reference) {
auto relative_error = [](mfem::Vector computed, const mfem::Vector &reference) {
computed -= reference;
return computed.Norml2() / std::max(reference.Norml2(), 1.0e-30);
};
@@ -221,10 +182,8 @@ TEST_CASE(
density_plus.Add(finite_difference_step, density_direction);
density_minus.Add(-finite_difference_step, density_direction);
mfem::Vector density_residual_plus =
assemble_velocity_residual(density_plus, gravity_gradient_dofs);
mfem::Vector density_residual_minus =
assemble_velocity_residual(density_minus, gravity_gradient_dofs);
mfem::Vector density_residual_plus = assemble_velocity_residual(density_plus, gravity_gradient_dofs);
mfem::Vector density_residual_minus = assemble_velocity_residual(density_minus, gravity_gradient_dofs);
mfem::Vector density_finite_difference(density_residual_plus);
density_finite_difference -= density_residual_minus;
density_finite_difference *= 0.5 / finite_difference_step;
@@ -234,17 +193,11 @@ TEST_CASE(
mfem::Vector gravity_gradient_plus(gravity_gradient_dofs);
mfem::Vector gravity_gradient_minus(gravity_gradient_dofs);
gravity_gradient_plus.Add(
finite_difference_step, gravity_gradient_direction
);
gravity_gradient_minus.Add(
-finite_difference_step, gravity_gradient_direction
);
gravity_gradient_plus.Add(finite_difference_step, gravity_gradient_direction);
gravity_gradient_minus.Add(-finite_difference_step, gravity_gradient_direction);
mfem::Vector gravity_residual_plus =
assemble_velocity_residual(density_dofs, gravity_gradient_plus);
mfem::Vector gravity_residual_minus =
assemble_velocity_residual(density_dofs, gravity_gradient_minus);
mfem::Vector gravity_residual_plus = assemble_velocity_residual(density_dofs, gravity_gradient_plus);
mfem::Vector gravity_residual_minus = assemble_velocity_residual(density_dofs, gravity_gradient_minus);
mfem::Vector gravity_finite_difference(gravity_residual_plus);
gravity_finite_difference -= gravity_residual_minus;
gravity_finite_difference *= 0.5 / finite_difference_step;
@@ -258,19 +211,11 @@ TEST_CASE(
mfem::Vector combined_gravity_minus(gravity_gradient_dofs);
combined_density_plus.Add(finite_difference_step, density_direction);
combined_density_minus.Add(-finite_difference_step, density_direction);
combined_gravity_plus.Add(
finite_difference_step, gravity_gradient_direction
);
combined_gravity_minus.Add(
-finite_difference_step, gravity_gradient_direction
);
combined_gravity_plus.Add(finite_difference_step, gravity_gradient_direction);
combined_gravity_minus.Add(-finite_difference_step, gravity_gradient_direction);
mfem::Vector combined_residual_plus = assemble_velocity_residual(
combined_density_plus, combined_gravity_plus
);
mfem::Vector combined_residual_minus = assemble_velocity_residual(
combined_density_minus, combined_gravity_minus
);
mfem::Vector combined_residual_plus = assemble_velocity_residual(combined_density_plus, combined_gravity_plus);
mfem::Vector combined_residual_minus = assemble_velocity_residual(combined_density_minus, combined_gravity_minus);
mfem::Vector combined_finite_difference(combined_residual_plus);
combined_finite_difference -= combined_residual_minus;
combined_finite_difference *= 0.5 / finite_difference_step;
@@ -283,39 +228,19 @@ TEST_CASE(
dv_dv.Mult(velocity_direction, inactive_velocity_action);
dv_ddisplacement.Mult(displacement_direction, inactive_displacement_action);
const double density_relative_error =
relative_error(density_finite_difference, density_jacobian_action);
const double gravity_relative_error =
relative_error(gravity_finite_difference, gravity_jacobian_action);
const double combined_relative_error =
relative_error(combined_finite_difference, combined_jacobian_action);
const double density_relative_error = relative_error(density_finite_difference, density_jacobian_action);
const double gravity_relative_error = relative_error(gravity_finite_difference, gravity_jacobian_action);
const double combined_relative_error = relative_error(combined_finite_difference, combined_jacobian_action);
INFO("Density Jacobian relative error = " << density_relative_error);
INFO(
"Gravity-gradient Jacobian relative error = " << gravity_relative_error
);
INFO("Gravity-gradient Jacobian relative error = " << gravity_relative_error);
INFO("Combined Jacobian relative error = " << combined_relative_error);
CHECK_THAT(
density_relative_error,
Catch::Matchers::WithinAbs(0.0, jacobian_tolerance)
);
CHECK_THAT(
gravity_relative_error,
Catch::Matchers::WithinAbs(0.0, jacobian_tolerance)
);
CHECK_THAT(
combined_relative_error,
Catch::Matchers::WithinAbs(0.0, jacobian_tolerance)
);
CHECK_THAT(
inactive_velocity_action.Norml2(),
Catch::Matchers::WithinAbs(0.0, zero_tolerance)
);
CHECK_THAT(
inactive_displacement_action.Norml2(),
Catch::Matchers::WithinAbs(0.0, zero_tolerance)
);
CHECK_THAT(density_relative_error, Catch::Matchers::WithinAbs(0.0, jacobian_tolerance));
CHECK_THAT(gravity_relative_error, Catch::Matchers::WithinAbs(0.0, jacobian_tolerance));
CHECK_THAT(combined_relative_error, Catch::Matchers::WithinAbs(0.0, jacobian_tolerance));
CHECK_THAT(inactive_velocity_action.Norml2(), Catch::Matchers::WithinAbs(0.0, zero_tolerance));
CHECK_THAT(inactive_displacement_action.Norml2(), Catch::Matchers::WithinAbs(0.0, zero_tolerance));
mfem::Vector field_coupled_density_action(density_jacobian_action);
@@ -326,68 +251,46 @@ TEST_CASE(
dv_ddisplacement = 1.0;
element_state[density_block] = &density_dofs;
element_state[gravity_gradient_block] = &gravity_gradient_dofs;
integrator.AssembleElementGrad(
elements, *transformation, element_state, element_matrices
);
integrator.AssembleElementGrad(elements, *transformation, element_state, element_matrices);
mfem::Vector minimal_density_action(velocity_size);
mfem::Vector minimal_gravity_action(velocity_size);
dv_drho.Mult(density_direction, minimal_density_action);
dv_dgrad_phi.Mult(gravity_gradient_direction, minimal_gravity_action);
const double minimal_density_difference =
relative_error(minimal_density_action, field_coupled_density_action);
const double minimal_density_difference = relative_error(minimal_density_action, field_coupled_density_action);
INFO(
"Minimal-mode density-block difference = " << minimal_density_difference
);
INFO("Minimal-mode density-block difference = " << minimal_density_difference);
CHECK_THAT(
minimal_density_difference,
Catch::Matchers::WithinAbs(0.0, zero_tolerance)
);
CHECK_THAT(
minimal_gravity_action.Norml2(),
Catch::Matchers::WithinAbs(0.0, zero_tolerance)
);
CHECK_THAT(minimal_density_difference, Catch::Matchers::WithinAbs(0.0, zero_tolerance));
CHECK_THAT(minimal_gravity_action.Norml2(), Catch::Matchers::WithinAbs(0.0, zero_tolerance));
}
TEST_CASE(
"Gravity Force Integrator Matches Manufactured Cartesian Load",
tags::unit &tags::solver &tags::integrator &tags::gravity
) {
constexpr int dim = 3;
constexpr double tolerance = 1.0e-12;
constexpr int dim = 3;
constexpr double tolerance = 1.0e-12;
constexpr int velocity_block =
solver::block_index(solver::FieldBlock::velocity);
constexpr int density_block =
solver::block_index(solver::FieldBlock::density);
constexpr int gravity_gradient_block =
solver::block_index(solver::FieldBlock::gravity_gradient);
constexpr int gravity_potential_block =
solver::block_index(solver::FieldBlock::gravity_potential);
constexpr int displacement_block =
solver::block_index(solver::FieldBlock::displacement);
constexpr int block_count = solver::field_block_count;
constexpr int velocity_block = solver::block_index(solver::FieldBlock::velocity);
constexpr int density_block = solver::block_index(solver::FieldBlock::density);
constexpr int gravity_gradient_block = solver::block_index(solver::FieldBlock::gravity_gradient);
constexpr int gravity_potential_block = solver::block_index(solver::FieldBlock::gravity_potential);
constexpr int displacement_block = solver::block_index(solver::FieldBlock::displacement);
constexpr int block_count = solver::field_block_count;
mfem::Mesh mesh = mfem::Mesh::MakeCartesian3D(
1, 1, 1, mfem::Element::HEXAHEDRON, 1.0, 1.0, 1.0
);
mfem::Mesh mesh = mfem::Mesh::MakeCartesian3D(1, 1, 1, mfem::Element::HEXAHEDRON, 1.0, 1.0, 1.0);
mfem::H1_FECollection velocity_fec(1, dim);
mfem::L2_FECollection density_fec(1, dim);
mfem::RT_FECollection gravity_gradient_fec(0, dim);
mfem::H1_FECollection displacement_fec(1, dim);
mfem::FiniteElementSpace velocity_fes(
&mesh, &velocity_fec, dim, mfem::Ordering::byVDIM
);
mfem::FiniteElementSpace velocity_fes(&mesh, &velocity_fec, dim, mfem::Ordering::byVDIM);
mfem::FiniteElementSpace density_fes(&mesh, &density_fec);
mfem::FiniteElementSpace gravity_gradient_fes(&mesh, &gravity_gradient_fec);
mfem::FiniteElementSpace displacement_fes(
&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM
);
mfem::FiniteElementSpace displacement_fes(&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM);
mfem::GridFunction displacement(&displacement_fes);
displacement = 0.0;
@@ -396,10 +299,9 @@ TEST_CASE(
REQUIRE(domain_mapper.CalcIsIdentity());
auto reference_density = [](const mfem::Vector &x) { return 1.0 + x(0); };
auto reference_density = [](const mfem::Vector &x) { return 1.0 + x(0); };
auto reference_gravity_gradient = [](const mfem::Vector &x,
mfem::Vector &gradient) {
auto reference_gravity_gradient = [](const mfem::Vector &x, mfem::Vector &gradient) {
gradient.SetSize(3);
gradient(0) = 2.0 * x(0);
gradient(1) = 3.0 * x(1);
@@ -407,29 +309,25 @@ TEST_CASE(
};
mfem::FunctionCoefficient density_coefficient(reference_density);
mfem::VectorFunctionCoefficient gravity_gradient_coefficient(
dim, reference_gravity_gradient
);
mfem::VectorFunctionCoefficient gravity_gradient_coefficient(dim, reference_gravity_gradient);
mfem::GridFunction density(&density_fes);
mfem::GridFunction gravity_gradient(&gravity_gradient_fes);
density.ProjectCoefficient(density_coefficient);
gravity_gradient.ProjectCoefficient(gravity_gradient_coefficient);
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
const mfem::FiniteElement *gravity_gradient_element =
gravity_gradient_fes.GetFE(0);
const mfem::FiniteElement *displacement_element = displacement_fes.GetFE(0);
mfem::ElementTransformation *transformation =
mesh.GetElementTransformation(0);
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
const mfem::FiniteElement *gravity_gradient_element = gravity_gradient_fes.GetFE(0);
const mfem::FiniteElement *displacement_element = displacement_fes.GetFE(0);
mfem::ElementTransformation *transformation = mesh.GetElementTransformation(0);
const int velocity_dofs_count = velocity_element->GetDof();
const int density_dofs_count = density_element->GetDof();
const int gravity_gradient_dofs_count = gravity_gradient_element->GetDof();
const int displacement_dofs_count = displacement_element->GetDof();
const int velocity_size = dim * velocity_dofs_count;
const int displacement_size = dim * displacement_dofs_count;
const int velocity_dofs_count = velocity_element->GetDof();
const int density_dofs_count = density_element->GetDof();
const int gravity_gradient_dofs_count = gravity_gradient_element->GetDof();
const int displacement_dofs_count = displacement_element->GetDof();
const int velocity_size = dim * velocity_dofs_count;
const int displacement_size = dim * displacement_dofs_count;
mfem::Array<int> density_dof_indices;
mfem::Array<int> gravity_gradient_dof_indices;
@@ -438,9 +336,7 @@ TEST_CASE(
density_fes.GetElementDofs(0, density_dof_indices);
gravity_gradient_fes.GetElementVDofs(0, gravity_gradient_dof_indices);
density.GetSubVector(density_dof_indices, density_dofs);
gravity_gradient.GetSubVector(
gravity_gradient_dof_indices, gravity_gradient_dofs
);
gravity_gradient.GetSubVector(gravity_gradient_dof_indices, gravity_gradient_dofs);
REQUIRE(density_dofs.Size() == density_dofs_count);
REQUIRE(gravity_gradient_dofs.Size() == gravity_gradient_dofs_count);
@@ -483,23 +379,18 @@ TEST_CASE(
domain_mapper, integrators::GravityForceJacobianMode::field_coupled
);
const mfem::IntegrationRule &integration_rule =
mfem::IntRules.Get(velocity_element->GetGeomType(), 8);
const mfem::IntegrationRule &integration_rule = mfem::IntRules.Get(velocity_element->GetGeomType(), 8);
integrator.SetIntegrationRule(integration_rule);
integrator.AssembleElementVector(
elements, *transformation, element_state, element_residual
);
integrator.AssembleElementVector(elements, *transformation, element_state, element_residual);
mfem::Vector reference_velocity_residual(velocity_residual);
auto residual_action = [&](const int component,
const int coordinate_weight) {
auto residual_action = [&](const int component, const int coordinate_weight) {
mfem::Vector test_dofs(velocity_size);
mfem::Vector x_physical(dim);
test_dofs = 0.0;
test_dofs = 0.0;
const mfem::IntegrationRule &velocity_nodes =
velocity_element->GetNodes();
const mfem::IntegrationRule &velocity_nodes = velocity_element->GetNodes();
for (int i = 0; i < velocity_dofs_count; ++i) {
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
@@ -512,106 +403,62 @@ TEST_CASE(
return test_dofs * velocity_residual;
};
CHECK_THAT(
residual_action(0, -1), Catch::Matchers::WithinAbs(5.0 / 3.0, tolerance)
);
CHECK_THAT(
residual_action(1, -1), Catch::Matchers::WithinAbs(9.0 / 4.0, tolerance)
);
CHECK_THAT(
residual_action(2, -1), Catch::Matchers::WithinAbs(3.0, tolerance)
);
CHECK_THAT(
residual_action(0, 0), Catch::Matchers::WithinAbs(7.0 / 6.0, tolerance)
);
CHECK_THAT(
residual_action(1, 1), Catch::Matchers::WithinAbs(3.0 / 2.0, tolerance)
);
CHECK_THAT(
residual_action(2, 2), Catch::Matchers::WithinAbs(2.0, tolerance)
);
CHECK_THAT(
residual_action(1, 0), Catch::Matchers::WithinAbs(5.0 / 4.0, tolerance)
);
CHECK_THAT(residual_action(0, -1), Catch::Matchers::WithinAbs(5.0 / 3.0, tolerance));
CHECK_THAT(residual_action(1, -1), Catch::Matchers::WithinAbs(9.0 / 4.0, tolerance));
CHECK_THAT(residual_action(2, -1), Catch::Matchers::WithinAbs(3.0, tolerance));
CHECK_THAT(residual_action(0, 0), Catch::Matchers::WithinAbs(7.0 / 6.0, tolerance));
CHECK_THAT(residual_action(1, 1), Catch::Matchers::WithinAbs(3.0 / 2.0, tolerance));
CHECK_THAT(residual_action(2, 2), Catch::Matchers::WithinAbs(2.0, tolerance));
CHECK_THAT(residual_action(1, 0), Catch::Matchers::WithinAbs(5.0 / 4.0, tolerance));
CHECK_THAT(
density_residual.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
gravity_gradient_residual.Norml2(),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
gravity_potential_residual.Norml2(),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
displacement_residual.Norml2(),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(density_residual.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(gravity_gradient_residual.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(gravity_potential_residual.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(displacement_residual.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
integrator.SetJacobianMode(integrators::GravityForceJacobianMode::minimal);
integrator.AssembleElementVector(
elements, *transformation, element_state, element_residual
);
integrator.AssembleElementVector(elements, *transformation, element_state, element_residual);
mfem::Vector minimal_difference(velocity_residual);
minimal_difference -= reference_velocity_residual;
integrator.SetJacobianMode(integrators::GravityForceJacobianMode::exact);
integrator.AssembleElementVector(
elements, *transformation, element_state, element_residual
);
integrator.AssembleElementVector(elements, *transformation, element_state, element_residual);
mfem::Vector exact_difference(velocity_residual);
exact_difference -= reference_velocity_residual;
CHECK_THAT(
minimal_difference.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
exact_difference.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(minimal_difference.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(exact_difference.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
}
TEST_CASE(
"Gravity Force Integrator Preserves Gravity Identities",
tags::unit &tags::solver &tags::integrator &tags::gravity
) {
constexpr int dim = 3;
constexpr double density_value = 1.7;
constexpr double gravity_scale = 2.4;
constexpr double density_scale = 0.6;
constexpr double tolerance = 1.0e-12;
constexpr int dim = 3;
constexpr double density_value = 1.7;
constexpr double gravity_scale = 2.4;
constexpr double density_scale = 0.6;
constexpr double tolerance = 1.0e-12;
constexpr int velocity_block =
solver::block_index(solver::FieldBlock::velocity);
constexpr int density_block =
solver::block_index(solver::FieldBlock::density);
constexpr int gravity_gradient_block =
solver::block_index(solver::FieldBlock::gravity_gradient);
constexpr int gravity_potential_block =
solver::block_index(solver::FieldBlock::gravity_potential);
constexpr int displacement_block =
solver::block_index(solver::FieldBlock::displacement);
constexpr int block_count = solver::field_block_count;
constexpr int velocity_block = solver::block_index(solver::FieldBlock::velocity);
constexpr int density_block = solver::block_index(solver::FieldBlock::density);
constexpr int gravity_gradient_block = solver::block_index(solver::FieldBlock::gravity_gradient);
constexpr int gravity_potential_block = solver::block_index(solver::FieldBlock::gravity_potential);
constexpr int displacement_block = solver::block_index(solver::FieldBlock::displacement);
constexpr int block_count = solver::field_block_count;
mfem::Mesh mesh = mfem::Mesh::MakeCartesian3D(
1, 1, 1, mfem::Element::HEXAHEDRON, 1.0, 1.0, 1.0
);
mfem::Mesh mesh = mfem::Mesh::MakeCartesian3D(1, 1, 1, mfem::Element::HEXAHEDRON, 1.0, 1.0, 1.0);
mfem::H1_FECollection velocity_fec(1, dim);
mfem::L2_FECollection density_fec(0, dim);
mfem::RT_FECollection gravity_gradient_fec(0, dim);
mfem::H1_FECollection displacement_fec(1, dim);
mfem::FiniteElementSpace velocity_fes(
&mesh, &velocity_fec, dim, mfem::Ordering::byVDIM
);
mfem::FiniteElementSpace velocity_fes(&mesh, &velocity_fec, dim, mfem::Ordering::byVDIM);
mfem::FiniteElementSpace density_fes(&mesh, &density_fec);
mfem::FiniteElementSpace gravity_gradient_fes(&mesh, &gravity_gradient_fec);
mfem::FiniteElementSpace displacement_fes(
&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM
);
mfem::FiniteElementSpace displacement_fes(&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM);
mfem::GridFunction displacement(&displacement_fes);
displacement = 0.0;
@@ -635,20 +482,18 @@ TEST_CASE(
density.ProjectCoefficient(density_coefficient);
gravity_gradient.ProjectCoefficient(gravity_coefficient);
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
const mfem::FiniteElement *gravity_gradient_element =
gravity_gradient_fes.GetFE(0);
const mfem::FiniteElement *displacement_element = displacement_fes.GetFE(0);
mfem::ElementTransformation *transformation =
mesh.GetElementTransformation(0);
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
const mfem::FiniteElement *gravity_gradient_element = gravity_gradient_fes.GetFE(0);
const mfem::FiniteElement *displacement_element = displacement_fes.GetFE(0);
mfem::ElementTransformation *transformation = mesh.GetElementTransformation(0);
const int velocity_dofs_count = velocity_element->GetDof();
const int density_dofs_count = density_element->GetDof();
const int gravity_gradient_dofs_count = gravity_gradient_element->GetDof();
const int displacement_dofs_count = displacement_element->GetDof();
const int velocity_size = dim * velocity_dofs_count;
const int displacement_size = dim * displacement_dofs_count;
const int velocity_dofs_count = velocity_element->GetDof();
const int density_dofs_count = density_element->GetDof();
const int gravity_gradient_dofs_count = gravity_gradient_element->GetDof();
const int displacement_dofs_count = displacement_element->GetDof();
const int velocity_size = dim * velocity_dofs_count;
const int displacement_size = dim * displacement_dofs_count;
mfem::Array<int> density_dof_indices;
mfem::Array<int> gravity_gradient_dof_indices;
@@ -657,9 +502,7 @@ TEST_CASE(
density_fes.GetElementDofs(0, density_dof_indices);
gravity_gradient_fes.GetElementVDofs(0, gravity_gradient_dof_indices);
density.GetSubVector(density_dof_indices, density_dofs);
gravity_gradient.GetSubVector(
gravity_gradient_dof_indices, gravity_gradient_dofs
);
gravity_gradient.GetSubVector(gravity_gradient_dof_indices, gravity_gradient_dofs);
mfem::Vector zero_density(density_dofs_count);
mfem::Vector zero_gravity(gravity_gradient_dofs_count);
@@ -703,76 +546,54 @@ TEST_CASE(
domain_mapper, integrators::GravityForceJacobianMode::field_coupled
);
const mfem::IntegrationRule &integration_rule =
mfem::IntRules.Get(velocity_element->GetGeomType(), 8);
const mfem::IntegrationRule &integration_rule = mfem::IntRules.Get(velocity_element->GetGeomType(), 8);
integrator.SetIntegrationRule(integration_rule);
auto assemble_velocity_residual = [&](const mfem::Vector &density_state,
const mfem::Vector &gravity_state) {
auto assemble_velocity_residual = [&](const mfem::Vector &density_state, const mfem::Vector &gravity_state) {
element_state[density_block] = &density_state;
element_state[gravity_gradient_block] = &gravity_state;
integrator.AssembleElementVector(
elements, *transformation, element_state, element_residual
);
integrator.AssembleElementVector(elements, *transformation, element_state, element_residual);
return mfem::Vector(velocity_residual);
};
auto scaled_difference_norm = [](mfem::Vector computed,
const mfem::Vector &reference,
const double scale) {
auto scaled_difference_norm = [](mfem::Vector computed, const mfem::Vector &reference, const double scale) {
computed.Add(-scale, reference);
return computed.Norml2();
};
const mfem::Vector base_residual =
assemble_velocity_residual(density_dofs, gravity_gradient_dofs);
const mfem::Vector base_residual = assemble_velocity_residual(density_dofs, gravity_gradient_dofs);
REQUIRE(base_residual.Norml2() > tolerance);
const mfem::Vector zero_field_residual =
assemble_velocity_residual(density_dofs, zero_gravity);
const mfem::Vector zero_field_residual = assemble_velocity_residual(density_dofs, zero_gravity);
mfem::Vector reversed_gravity(gravity_gradient_dofs);
reversed_gravity *= -1.0;
const mfem::Vector reversed_residual =
assemble_velocity_residual(density_dofs, reversed_gravity);
const mfem::Vector reversed_residual = assemble_velocity_residual(density_dofs, reversed_gravity);
mfem::Vector scaled_gravity(gravity_gradient_dofs);
scaled_gravity *= gravity_scale;
const mfem::Vector gravity_scaled_residual =
assemble_velocity_residual(density_dofs, scaled_gravity);
const mfem::Vector gravity_scaled_residual = assemble_velocity_residual(density_dofs, scaled_gravity);
mfem::Vector scaled_density(density_dofs);
scaled_density *= density_scale;
const mfem::Vector density_scaled_residual =
assemble_velocity_residual(scaled_density, gravity_gradient_dofs);
const mfem::Vector jointly_scaled_residual =
assemble_velocity_residual(scaled_density, scaled_gravity);
const mfem::Vector density_scaled_residual = assemble_velocity_residual(scaled_density, gravity_gradient_dofs);
const mfem::Vector jointly_scaled_residual = assemble_velocity_residual(scaled_density, scaled_gravity);
CHECK_THAT(zero_field_residual.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(
zero_field_residual.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance)
scaled_difference_norm(reversed_residual, base_residual, -1.0), Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
scaled_difference_norm(reversed_residual, base_residual, -1.0),
scaled_difference_norm(gravity_scaled_residual, base_residual, gravity_scale),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
scaled_difference_norm(
gravity_scaled_residual, base_residual, gravity_scale
),
scaled_difference_norm(density_scaled_residual, base_residual, density_scale),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
scaled_difference_norm(
density_scaled_residual, base_residual, density_scale
),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
scaled_difference_norm(
jointly_scaled_residual, base_residual,
density_scale * gravity_scale
),
scaled_difference_norm(jointly_scaled_residual, base_residual, density_scale * gravity_scale),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
@@ -781,10 +602,9 @@ TEST_CASE(
mfem::Vector x_physical(dim);
mfem::Vector centered_position(dim);
mfem::Vector test_value(dim);
test_dofs = 0.0;
test_dofs = 0.0;
const mfem::IntegrationRule &velocity_nodes =
velocity_element->GetNodes();
const mfem::IntegrationRule &velocity_nodes = velocity_element->GetNodes();
for (int i = 0; i < velocity_dofs_count; ++i) {
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
@@ -798,87 +618,63 @@ TEST_CASE(
test_function(centered_position, test_value);
for (int component = 0; component < dim; ++component) {
test_dofs(i + component * velocity_dofs_count) =
test_value(component);
test_dofs(i + component * velocity_dofs_count) = test_value(component);
}
}
return test_dofs;
};
const mfem::Vector force_x_test =
make_test_dofs([](const mfem::Vector &, mfem::Vector &value) {
value.SetSize(3);
value = 0.0;
value(0) = 1.0;
});
const mfem::Vector force_x_test = make_test_dofs([](const mfem::Vector &, mfem::Vector &value) {
value.SetSize(3);
value = 0.0;
value(0) = 1.0;
});
const mfem::Vector force_y_test =
make_test_dofs([](const mfem::Vector &, mfem::Vector &value) {
value.SetSize(3);
value = 0.0;
value(1) = 1.0;
});
const mfem::Vector force_y_test = make_test_dofs([](const mfem::Vector &, mfem::Vector &value) {
value.SetSize(3);
value = 0.0;
value(1) = 1.0;
});
const mfem::Vector force_z_test =
make_test_dofs([](const mfem::Vector &, mfem::Vector &value) {
value.SetSize(3);
value = 0.0;
value(2) = 1.0;
});
const mfem::Vector force_z_test = make_test_dofs([](const mfem::Vector &, mfem::Vector &value) {
value.SetSize(3);
value = 0.0;
value(2) = 1.0;
});
const mfem::Vector torque_x_test =
make_test_dofs([](const mfem::Vector &position, mfem::Vector &value) {
value.SetSize(3);
value(0) = 0.0;
value(1) = -position(2);
value(2) = position(1);
});
const mfem::Vector torque_x_test = make_test_dofs([](const mfem::Vector &position, mfem::Vector &value) {
value.SetSize(3);
value(0) = 0.0;
value(1) = -position(2);
value(2) = position(1);
});
const mfem::Vector torque_y_test =
make_test_dofs([](const mfem::Vector &position, mfem::Vector &value) {
value.SetSize(3);
value(0) = position(2);
value(1) = 0.0;
value(2) = -position(0);
});
const mfem::Vector torque_y_test = make_test_dofs([](const mfem::Vector &position, mfem::Vector &value) {
value.SetSize(3);
value(0) = position(2);
value(1) = 0.0;
value(2) = -position(0);
});
const mfem::Vector torque_z_test =
make_test_dofs([](const mfem::Vector &position, mfem::Vector &value) {
value.SetSize(3);
value(0) = -position(1);
value(1) = position(0);
value(2) = 0.0;
});
const mfem::Vector torque_z_test = make_test_dofs([](const mfem::Vector &position, mfem::Vector &value) {
value.SetSize(3);
value(0) = -position(1);
value(1) = position(0);
value(2) = 0.0;
});
CHECK_THAT(
force_x_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
force_y_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
force_z_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
torque_x_test * base_residual,
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
torque_y_test * base_residual,
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
torque_z_test * base_residual,
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(force_x_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(force_y_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(force_z_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(torque_x_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(torque_y_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(torque_z_test * base_residual, Catch::Matchers::WithinAbs(0.0, tolerance));
mfem::DenseMatrix dv_drho(velocity_size, density_dofs_count);
mfem::DenseMatrix dv_dgrad_phi(velocity_size, gravity_gradient_dofs_count);
mfem::Array2D<mfem::DenseMatrix *> element_matrices(
block_count, block_count
);
mfem::Array2D<mfem::DenseMatrix *> element_matrices(block_count, block_count);
for (int row = 0; row < block_count; ++row) {
for (int column = 0; column < block_count; ++column) {
@@ -891,19 +687,14 @@ TEST_CASE(
element_state[density_block] = &density_dofs;
element_state[gravity_gradient_block] = &zero_gravity;
integrator.AssembleElementGrad(
elements, *transformation, element_state, element_matrices
);
integrator.AssembleElementGrad(elements, *transformation, element_state, element_matrices);
mfem::Vector zero_gravity_density_action(velocity_size);
mfem::Vector zero_gravity_field_action(velocity_size);
dv_drho.Mult(density_dofs, zero_gravity_density_action);
dv_dgrad_phi.Mult(gravity_gradient_dofs, zero_gravity_field_action);
CHECK_THAT(
zero_gravity_density_action.Norml2(),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(zero_gravity_density_action.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
CHECK_THAT(
scaled_difference_norm(zero_gravity_field_action, base_residual, 1.0),
Catch::Matchers::WithinAbs(0.0, tolerance)
@@ -911,9 +702,7 @@ TEST_CASE(
element_state[density_block] = &zero_density;
element_state[gravity_gradient_block] = &gravity_gradient_dofs;
integrator.AssembleElementGrad(
elements, *transformation, element_state, element_matrices
);
integrator.AssembleElementGrad(elements, *transformation, element_state, element_matrices);
mfem::Vector zero_density_density_action(velocity_size);
mfem::Vector zero_density_field_action(velocity_size);
@@ -924,8 +713,5 @@ TEST_CASE(
scaled_difference_norm(zero_density_density_action, base_residual, 1.0),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(
zero_density_field_action.Norml2(),
Catch::Matchers::WithinAbs(0.0, tolerance)
);
CHECK_THAT(zero_density_field_action.Norml2(), Catch::Matchers::WithinAbs(0.0, tolerance));
}