feat(FieldDofMap): Completed FieldDofMap migration
also removed legacy BarotropicPolytrope implementation
This commit is contained in:
@@ -44,7 +44,6 @@ target_sources(mean_field
|
|||||||
libmeanfield/impl/analysis/integral.cpp
|
libmeanfield/impl/analysis/integral.cpp
|
||||||
libmeanfield/impl/fem.cpp
|
libmeanfield/impl/fem.cpp
|
||||||
libmeanfield/impl/mapping/coefficients.cpp
|
libmeanfield/impl/mapping/coefficients.cpp
|
||||||
libmeanfield/impl/mapping/domain_mapper.cpp
|
|
||||||
libmeanfield/impl/mapping/compactification/kelvin.cpp
|
libmeanfield/impl/mapping/compactification/kelvin.cpp
|
||||||
libmeanfield/impl/physics/gravity.cpp
|
libmeanfield/impl/physics/gravity.cpp
|
||||||
libmeanfield/impl/physics/solid.cpp
|
libmeanfield/impl/physics/solid.cpp
|
||||||
@@ -56,7 +55,7 @@ target_sources(mean_field
|
|||||||
libmeanfield/impl/integrators/gravity.cpp
|
libmeanfield/impl/integrators/gravity.cpp
|
||||||
libmeanfield/impl/integrators/mass_continuity.cpp
|
libmeanfield/impl/integrators/mass_continuity.cpp
|
||||||
libmeanfield/impl/integrators/viscosity.cpp
|
libmeanfield/impl/integrators/viscosity.cpp
|
||||||
libmeanfield/impl/mapping/domain_mapper_new.cpp
|
libmeanfield/impl/mapping/domain_mapper.cpp
|
||||||
libmeanfield/impl/mapping/transformations.cpp
|
libmeanfield/impl/mapping/transformations.cpp
|
||||||
libmeanfield/impl/operators/gravity_field.cpp
|
libmeanfield/impl/operators/gravity_field.cpp
|
||||||
libmeanfield/impl/operators/gravity_field_jacobian.cpp
|
libmeanfield/impl/operators/gravity_field_jacobian.cpp
|
||||||
@@ -98,7 +97,6 @@ target_sources(mean_field
|
|||||||
libmeanfield/interface/mapping/compactification/compactification.cppm
|
libmeanfield/interface/mapping/compactification/compactification.cppm
|
||||||
libmeanfield/interface/mapping/compactification/kelvin.cppm
|
libmeanfield/interface/mapping/compactification/kelvin.cppm
|
||||||
libmeanfield/interface/mapping/compactification/options.cppm
|
libmeanfield/interface/mapping/compactification/options.cppm
|
||||||
libmeanfield/interface/physics/context.cppm
|
|
||||||
libmeanfield/interface/physics/gravity.cppm
|
libmeanfield/interface/physics/gravity.cppm
|
||||||
libmeanfield/interface/physics/solid.cppm
|
libmeanfield/interface/physics/solid.cppm
|
||||||
libmeanfield/interface/utils/domain.cppm
|
libmeanfield/interface/utils/domain.cppm
|
||||||
@@ -126,7 +124,6 @@ target_sources(mean_field
|
|||||||
libmeanfield/interface/field/field_base.cppm
|
libmeanfield/interface/field/field_base.cppm
|
||||||
libmeanfield/interface/field/field_registry.cppm
|
libmeanfield/interface/field/field_registry.cppm
|
||||||
libmeanfield/interface/field/field_mfem.cppm
|
libmeanfield/interface/field/field_mfem.cppm
|
||||||
libmeanfield/interface/physics/barotrope.cppm
|
|
||||||
libmeanfield/interface/operators/prepared_barotropic_closure_operator.cppm
|
libmeanfield/interface/operators/prepared_barotropic_closure_operator.cppm
|
||||||
libmeanfield/interface/operators/contexts/barotropic_closure_linearization_context.cppm
|
libmeanfield/interface/operators/contexts/barotropic_closure_linearization_context.cppm
|
||||||
libmeanfield/interface/physics/rigid_rotation.cppm
|
libmeanfield/interface/physics/rigid_rotation.cppm
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
#include <mfem.hpp>
|
#include <mfem.hpp>
|
||||||
#include <mpi.h>
|
#include <mpi.h>
|
||||||
|
|
||||||
|
|
||||||
import mean_field;
|
import mean_field;
|
||||||
import test_helpers;
|
import test_helpers;
|
||||||
import experiment;
|
import experiment;
|
||||||
@@ -38,47 +37,66 @@ struct AccuracyBudgetMetrics {
|
|||||||
static double global_norm(const mfem::Vector &vector, MPI_Comm communicator) {
|
static double global_norm(const mfem::Vector &vector, MPI_Comm communicator) {
|
||||||
const double local_norm_squared = vector * vector;
|
const double local_norm_squared = vector * vector;
|
||||||
double global_norm_squared = 0.0;
|
double global_norm_squared = 0.0;
|
||||||
MPI_Allreduce(&local_norm_squared, &global_norm_squared, 1, MPI_DOUBLE, MPI_SUM, communicator);
|
MPI_Allreduce(&local_norm_squared, &global_norm_squared, 1, MPI_DOUBLE,
|
||||||
|
MPI_SUM, communicator);
|
||||||
return std::sqrt(global_norm_squared);
|
return std::sqrt(global_norm_squared);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double global_dot(const mfem::Vector& left, const mfem::Vector& right, MPI_Comm communicator) {
|
static double global_dot(const mfem::Vector &left, const mfem::Vector &right,
|
||||||
|
MPI_Comm communicator) {
|
||||||
const double local_dot = left * right;
|
const double local_dot = left * right;
|
||||||
double global_dot_product = 0.0;
|
double global_dot_product = 0.0;
|
||||||
MPI_Allreduce(&local_dot, &global_dot_product, 1, MPI_DOUBLE, MPI_SUM, communicator);
|
MPI_Allreduce(&local_dot, &global_dot_product, 1, MPI_DOUBLE, MPI_SUM,
|
||||||
|
communicator);
|
||||||
return global_dot_product;
|
return global_dot_product;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void zero_vacuum_density(const mean_field::fem::FEM& fem, mfem::GridFunction& density) {
|
static void zero_vacuum_density(const mean_field::fem::FEM &fem,
|
||||||
for (int index = 0; index < fem.vacuum_tdof_rho.Size(); ++index) {
|
mfem::GridFunction &density) {
|
||||||
density(fem.vacuum_tdof_rho[index]) = 0.0;
|
using DomainSchema =
|
||||||
}
|
mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
|
const mean_field::field::FieldDofMap density_map =
|
||||||
|
mean_field::field::make_field_dof_map<mean_field::field::Density,
|
||||||
|
DomainSchema>(*fem.densityFes);
|
||||||
|
|
||||||
|
mfem::Vector density_true;
|
||||||
|
density.GetTrueDofs(density_true);
|
||||||
|
|
||||||
|
const mfem::Vector supported_density = density_map.gather(density_true);
|
||||||
|
density_map.scatter(supported_density, density_true);
|
||||||
|
density.SetFromTrueDofs(density_true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int diagnostic_quadrature_order(const mean_field::fem::FEM &fem) {
|
static int diagnostic_quadrature_order(const mean_field::fem::FEM &fem) {
|
||||||
return 2 * std::max(fem.L2_fes->GetMaxElementOrder(), fem.RT_fes->GetMaxElementOrder()) + 8;
|
return 2 * std::max(fem.gravityPotentialFes->GetMaxElementOrder(),
|
||||||
|
fem.gravityFluxFes->GetMaxElementOrder()) +
|
||||||
|
8;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mfem::Vector assemble_monopole_projection_rhs(
|
static mfem::Vector assemble_monopole_projection_rhs(
|
||||||
mean_field::fem::FEM& fem,
|
mean_field::fem::FEM &fem, const mfem::GridFunction &displacement,
|
||||||
const mfem::GridFunction& displacement,
|
const double mass, const double stellar_radius) {
|
||||||
const double mass,
|
*fem.displacement = displacement;
|
||||||
const double stellar_radius
|
|
||||||
) {
|
|
||||||
static_cast<void>(displacement);
|
|
||||||
|
|
||||||
mfem::Vector local_rhs(fem.RT_fes->GetVSize());
|
mfem::Vector local_rhs(fem.gravityFluxFes->GetVSize());
|
||||||
local_rhs = 0.0;
|
local_rhs = 0.0;
|
||||||
|
|
||||||
const int vacuum_attribute = fem.domain_mapper_stateless->GetVacuumElementAttribute();
|
const int vacuum_attribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
const int quadrature_order = diagnostic_quadrature_order(fem);
|
const int quadrature_order = diagnostic_quadrature_order(fem);
|
||||||
|
mean_field::mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate);
|
||||||
|
|
||||||
for (int element_id = 0; element_id < fem.mesh->GetNE(); ++element_id) {
|
for (int element_id = 0; element_id < fem.mesh->GetNE(); ++element_id) {
|
||||||
const mfem::FiniteElement& gravity_element = *fem.RT_fes->GetFE(element_id);
|
const mfem::FiniteElement &gravity_element =
|
||||||
mfem::ElementTransformation* transformation = fem.mesh->GetElementTransformation(element_id);
|
*fem.gravityFluxFes->GetFE(element_id);
|
||||||
|
mfem::ElementTransformation *transformation =
|
||||||
|
fem.mesh->GetElementTransformation(element_id);
|
||||||
|
|
||||||
mfem::Array<int> gravity_dofs;
|
mfem::Array<int> gravity_dofs;
|
||||||
mfem::DofTransformation* gravity_transform = fem.RT_fes->GetElementVDofs(element_id, gravity_dofs);
|
mfem::DofTransformation *gravity_transform =
|
||||||
|
fem.gravityFluxFes->GetElementVDofs(element_id, gravity_dofs);
|
||||||
|
|
||||||
const int dof_count = gravity_element.GetDof();
|
const int dof_count = gravity_element.GetDof();
|
||||||
const int dimension = transformation->GetSpaceDim();
|
const int dimension = transformation->GetSpaceDim();
|
||||||
@@ -86,32 +104,38 @@ static mfem::Vector assemble_monopole_projection_rhs(
|
|||||||
mfem::Vector physical_position(dimension);
|
mfem::Vector physical_position(dimension);
|
||||||
mfem::Vector analytic_field(dimension);
|
mfem::Vector analytic_field(dimension);
|
||||||
mfem::Vector pulled_field(dimension);
|
mfem::Vector pulled_field(dimension);
|
||||||
mfem::DenseMatrix mapping_jacobian(dimension);
|
|
||||||
mfem::DenseMatrix vector_shape(dof_count, dimension);
|
mfem::DenseMatrix vector_shape(dof_count, dimension);
|
||||||
element_rhs = 0.0;
|
element_rhs = 0.0;
|
||||||
|
|
||||||
const mfem::IntegrationRule& rule = mfem::IntRules.Get(
|
const mfem::IntegrationRule &rule =
|
||||||
transformation->GetGeometryType(),
|
mfem::IntRules.Get(transformation->GetGeometryType(), quadrature_order);
|
||||||
quadrature_order
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int quadrature_point_id = 0; quadrature_point_id < rule.GetNPoints(); ++quadrature_point_id) {
|
for (int quadrature_point_id = 0; quadrature_point_id < rule.GetNPoints();
|
||||||
|
++quadrature_point_id) {
|
||||||
const mfem::IntegrationPoint &point = rule.IntPoint(quadrature_point_id);
|
const mfem::IntegrationPoint &point = rule.IntPoint(quadrature_point_id);
|
||||||
fem.mapping->GetPhysicalPoint(*transformation, point, physical_position);
|
mean_field::mapping::MappingPointContext mapping_context;
|
||||||
|
MFEM_VERIFY(
|
||||||
|
mapping_evaluator.EvaluatePoint(*transformation, point,
|
||||||
|
mapping_context) ==
|
||||||
|
mean_field::mapping::MappingStatus::valid,
|
||||||
|
"Invalid mapping in monopole projection RHS.");
|
||||||
|
physical_position = mapping_context.physical_position;
|
||||||
|
|
||||||
const double radius = physical_position.Norml2();
|
const double radius = physical_position.Norml2();
|
||||||
MFEM_VERIFY(std::isfinite(radius) && radius > 0.0, "Invalid radius in monopole projection RHS.");
|
MFEM_VERIFY(std::isfinite(radius) && radius > 0.0,
|
||||||
|
"Invalid radius in monopole projection RHS.");
|
||||||
|
|
||||||
analytic_field = physical_position;
|
analytic_field = physical_position;
|
||||||
if (transformation->Attribute == vacuum_attribute) {
|
if (transformation->Attribute == vacuum_attribute) {
|
||||||
analytic_field *= mean_field::utils::G * mass / (radius * radius * radius);
|
analytic_field *=
|
||||||
|
mean_field::utils::G * mass / (radius * radius * radius);
|
||||||
} else {
|
} else {
|
||||||
analytic_field *= mean_field::utils::G * mass /
|
analytic_field *= mean_field::utils::G * mass /
|
||||||
(stellar_radius * stellar_radius * stellar_radius);
|
(stellar_radius * stellar_radius * stellar_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
fem.mapping->ComputeJacobian(*transformation, mapping_jacobian);
|
mapping_context.mapping_jacobian.MultTranspose(analytic_field,
|
||||||
mapping_jacobian.MultTranspose(analytic_field, pulled_field);
|
pulled_field);
|
||||||
|
|
||||||
transformation->SetIntPoint(&point);
|
transformation->SetIntPoint(&point);
|
||||||
gravity_element.CalcVShape(*transformation, vector_shape);
|
gravity_element.CalcVShape(*transformation, vector_shape);
|
||||||
@@ -119,7 +143,8 @@ static mfem::Vector assemble_monopole_projection_rhs(
|
|||||||
|
|
||||||
for (int dof = 0; dof < dof_count; ++dof) {
|
for (int dof = 0; dof < dof_count; ++dof) {
|
||||||
for (int component = 0; component < dimension; ++component) {
|
for (int component = 0; component < dimension; ++component) {
|
||||||
element_rhs(dof) += reference_weight * vector_shape(dof, component) * pulled_field(component);
|
element_rhs(dof) += reference_weight * vector_shape(dof, component) *
|
||||||
|
pulled_field(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -130,9 +155,10 @@ static mfem::Vector assemble_monopole_projection_rhs(
|
|||||||
local_rhs.AddElementVector(gravity_dofs, element_rhs);
|
local_rhs.AddElementVector(gravity_dofs, element_rhs);
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector true_rhs(fem.RT_fes->GetTrueVSize());
|
mfem::Vector true_rhs(fem.gravityFluxFes->GetTrueVSize());
|
||||||
true_rhs = 0.0;
|
true_rhs = 0.0;
|
||||||
const mfem::Operator* prolongation = fem.RT_fes->GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
fem.gravityFluxFes->GetProlongationMatrix();
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->MultTranspose(local_rhs, true_rhs);
|
prolongation->MultTranspose(local_rhs, true_rhs);
|
||||||
} else {
|
} else {
|
||||||
@@ -142,120 +168,134 @@ static mfem::Vector assemble_monopole_projection_rhs(
|
|||||||
return true_rhs;
|
return true_rhs;
|
||||||
}
|
}
|
||||||
|
|
||||||
static mfem::Vector project_monopole_gradient(
|
static mfem::Vector
|
||||||
mean_field::fem::FEM& fem,
|
project_monopole_gradient(mean_field::fem::FEM &fem,
|
||||||
const mfem::GridFunction &displacement,
|
const mfem::GridFunction &displacement,
|
||||||
const double mass,
|
const double mass, const double stellar_radius) {
|
||||||
const double stellar_radius
|
|
||||||
) {
|
|
||||||
mfem::Vector displacement_true;
|
mfem::Vector displacement_true;
|
||||||
displacement.GetTrueDofs(displacement_true);
|
displacement.GetTrueDofs(displacement_true);
|
||||||
|
|
||||||
const mfem::Vector projection_rhs = assemble_monopole_projection_rhs(
|
const mfem::Vector projection_rhs_true =
|
||||||
fem,
|
assemble_monopole_projection_rhs(fem, displacement, mass, stellar_radius);
|
||||||
displacement,
|
|
||||||
mass,
|
|
||||||
stellar_radius
|
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::PreparedMappedHDivMassOperator mass_operator(
|
mean_field::operators::PreparedMappedHDivMassOperator mass_operator(
|
||||||
fem,
|
fem, *fem.domainMapperStateless);
|
||||||
*fem.domain_mapper_stateless
|
mass_operator.Prepare(
|
||||||
);
|
mass_operator.GetDisplacementMap().gather(displacement_true));
|
||||||
mass_operator.Prepare(displacement_true);
|
|
||||||
|
|
||||||
mfem::CGSolver solver(fem.RT_fes->GetComm());
|
const mfem::Vector projection_rhs =
|
||||||
|
mass_operator.GetFluxMap().gather(projection_rhs_true);
|
||||||
|
|
||||||
|
mfem::CGSolver solver(fem.gravityFluxFes->GetComm());
|
||||||
solver.SetOperator(mass_operator);
|
solver.SetOperator(mass_operator);
|
||||||
solver.SetRelTol(1.0e-11);
|
solver.SetRelTol(1.0e-11);
|
||||||
solver.SetAbsTol(1.0e-13);
|
solver.SetAbsTol(1.0e-13);
|
||||||
solver.SetMaxIter(4000);
|
solver.SetMaxIter(4000);
|
||||||
solver.SetPrintLevel(0);
|
solver.SetPrintLevel(0);
|
||||||
|
|
||||||
mfem::Vector projected_gradient(fem.RT_fes->GetTrueVSize());
|
mfem::Vector projected_gradient_reduced(
|
||||||
projected_gradient = 0.0;
|
mass_operator.GetFluxMap().reduced_size());
|
||||||
solver.Mult(projection_rhs, projected_gradient);
|
projected_gradient_reduced = 0.0;
|
||||||
|
solver.Mult(projection_rhs, projected_gradient_reduced);
|
||||||
|
|
||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
mass_operator.Mult(projected_gradient, residual);
|
mass_operator.Mult(projected_gradient_reduced, residual);
|
||||||
residual -= projection_rhs;
|
residual -= projection_rhs;
|
||||||
|
|
||||||
const double relative_residual = global_norm(residual, fem.RT_fes->GetComm()) /
|
const double relative_residual =
|
||||||
std::max(global_norm(projection_rhs, fem.RT_fes->GetComm()), std::numeric_limits<double>::epsilon());
|
global_norm(residual, fem.gravityFluxFes->GetComm()) /
|
||||||
|
std::max(global_norm(projection_rhs, fem.gravityFluxFes->GetComm()),
|
||||||
|
std::numeric_limits<double>::epsilon());
|
||||||
|
|
||||||
REQUIRE(std::isfinite(relative_residual));
|
REQUIRE(std::isfinite(relative_residual));
|
||||||
REQUIRE(relative_residual < 1.0e-8);
|
REQUIRE(relative_residual < 1.0e-8);
|
||||||
return projected_gradient;
|
return mass_operator.GetFluxMap().scatter(projected_gradient_reduced);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double mapped_hdiv_relative_gap(
|
static double mapped_hdiv_relative_gap(mean_field::fem::FEM &fem,
|
||||||
mean_field::fem::FEM& fem,
|
|
||||||
const mfem::GridFunction &displacement,
|
const mfem::GridFunction &displacement,
|
||||||
const mfem::Vector &calculated,
|
const mfem::Vector &calculated,
|
||||||
const mfem::Vector& reference
|
const mfem::Vector &reference) {
|
||||||
) {
|
|
||||||
mfem::Vector displacement_true;
|
mfem::Vector displacement_true;
|
||||||
displacement.GetTrueDofs(displacement_true);
|
displacement.GetTrueDofs(displacement_true);
|
||||||
|
|
||||||
mean_field::operators::PreparedMappedHDivMassOperator mass_operator(
|
mean_field::operators::PreparedMappedHDivMassOperator mass_operator(
|
||||||
fem,
|
fem, *fem.domainMapperStateless);
|
||||||
*fem.domain_mapper_stateless
|
mass_operator.Prepare(
|
||||||
);
|
mass_operator.GetDisplacementMap().gather(displacement_true));
|
||||||
mass_operator.Prepare(displacement_true);
|
|
||||||
|
|
||||||
mfem::Vector difference(calculated);
|
mfem::Vector difference(calculated);
|
||||||
difference -= reference;
|
difference -= reference;
|
||||||
mfem::Vector difference_action;
|
mfem::Vector difference_action;
|
||||||
mfem::Vector reference_action;
|
mfem::Vector reference_action;
|
||||||
mass_operator.Mult(difference, difference_action);
|
const mfem::Vector reduced_difference =
|
||||||
mass_operator.Mult(reference, reference_action);
|
mass_operator.GetFluxMap().gather(difference);
|
||||||
|
const mfem::Vector reduced_reference =
|
||||||
|
mass_operator.GetFluxMap().gather(reference);
|
||||||
|
mass_operator.Mult(reduced_difference, difference_action);
|
||||||
|
mass_operator.Mult(reduced_reference, reference_action);
|
||||||
|
|
||||||
const double difference_energy = global_dot(difference, difference_action, fem.RT_fes->GetComm());
|
const double difference_energy = global_dot(
|
||||||
const double reference_energy = global_dot(reference, reference_action, fem.RT_fes->GetComm());
|
reduced_difference, difference_action, fem.gravityFluxFes->GetComm());
|
||||||
MFEM_VERIFY(reference_energy > 0.0, "Projected monopole field has zero mapped H(div) norm.");
|
const double reference_energy = global_dot(
|
||||||
|
reduced_reference, reference_action, fem.gravityFluxFes->GetComm());
|
||||||
|
MFEM_VERIFY(reference_energy > 0.0,
|
||||||
|
"Projected monopole field has zero mapped H(div) norm.");
|
||||||
|
|
||||||
return std::sqrt(std::max(0.0, difference_energy) / reference_energy);
|
return std::sqrt(std::max(0.0, difference_energy) / reference_energy);
|
||||||
}
|
}
|
||||||
|
|
||||||
static AccuracyBudgetEnergies measure_stellar_energies(
|
static AccuracyBudgetEnergies
|
||||||
mean_field::fem::FEM& fem,
|
measure_stellar_energies(mean_field::fem::FEM &fem,
|
||||||
const mfem::GridFunction &density,
|
const mfem::GridFunction &density,
|
||||||
const mean_field::physics::GravitySolution& solution
|
const mean_field::physics::GravitySolution &solution) {
|
||||||
) {
|
const int vacuum_attribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
const int vacuum_attribute = fem.domain_mapper_stateless->GetVacuumElementAttribute();
|
|
||||||
const int quadrature_order = diagnostic_quadrature_order(fem);
|
const int quadrature_order = diagnostic_quadrature_order(fem);
|
||||||
|
mean_field::mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate);
|
||||||
double local_binding = 0.0;
|
double local_binding = 0.0;
|
||||||
double local_virial = 0.0;
|
double local_virial = 0.0;
|
||||||
|
|
||||||
mfem::Vector physical_position(3);
|
mfem::Vector physical_position(3);
|
||||||
mfem::Vector reference_field(3);
|
mfem::Vector reference_field(3);
|
||||||
mfem::Vector physical_field(3);
|
mfem::Vector physical_field(3);
|
||||||
mfem::DenseMatrix mapping_jacobian(3);
|
|
||||||
|
|
||||||
for (int element_id = 0; element_id < fem.mesh->GetNE(); ++element_id) {
|
for (int element_id = 0; element_id < fem.mesh->GetNE(); ++element_id) {
|
||||||
mfem::ElementTransformation* transformation = fem.mesh->GetElementTransformation(element_id);
|
mfem::ElementTransformation *transformation =
|
||||||
|
fem.mesh->GetElementTransformation(element_id);
|
||||||
if (transformation->Attribute == vacuum_attribute) {
|
if (transformation->Attribute == vacuum_attribute) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::IntegrationRule& rule = mfem::IntRules.Get(
|
const mfem::IntegrationRule &rule =
|
||||||
transformation->GetGeometryType(),
|
mfem::IntRules.Get(transformation->GetGeometryType(), quadrature_order);
|
||||||
quadrature_order
|
|
||||||
);
|
|
||||||
|
|
||||||
for (int quadrature_point_id = 0; quadrature_point_id < rule.GetNPoints(); ++quadrature_point_id) {
|
for (int quadrature_point_id = 0; quadrature_point_id < rule.GetNPoints();
|
||||||
|
++quadrature_point_id) {
|
||||||
const mfem::IntegrationPoint &point = rule.IntPoint(quadrature_point_id);
|
const mfem::IntegrationPoint &point = rule.IntPoint(quadrature_point_id);
|
||||||
transformation->SetIntPoint(&point);
|
transformation->SetIntPoint(&point);
|
||||||
|
|
||||||
fem.mapping->GetPhysicalPoint(*transformation, point, physical_position);
|
mean_field::mapping::MappingPointContext mapping_context;
|
||||||
fem.mapping->ComputeJacobian(*transformation, mapping_jacobian);
|
MFEM_VERIFY(
|
||||||
const double mapping_determinant = mapping_jacobian.Det();
|
mapping_evaluator.EvaluatePoint(*transformation, point,
|
||||||
MFEM_VERIFY(mapping_determinant > 0.0, "Non-positive mapping determinant in energy diagnostic.");
|
mapping_context) ==
|
||||||
|
mean_field::mapping::MappingStatus::valid,
|
||||||
|
"Invalid mapping in energy diagnostic.");
|
||||||
|
physical_position = mapping_context.physical_position;
|
||||||
|
const mfem::DenseMatrix &mapping_jacobian =
|
||||||
|
mapping_context.mapping_jacobian;
|
||||||
|
const double mapping_determinant =
|
||||||
|
mapping_context.mapping_determinant;
|
||||||
|
MFEM_VERIFY(mapping_determinant > 0.0,
|
||||||
|
"Non-positive mapping determinant in energy diagnostic.");
|
||||||
|
|
||||||
solution.gradPhi.GetVectorValue(element_id, point, reference_field);
|
solution.gradPhi.GetVectorValue(element_id, point, reference_field);
|
||||||
mapping_jacobian.Mult(reference_field, physical_field);
|
mapping_jacobian.Mult(reference_field, physical_field);
|
||||||
physical_field /= mapping_determinant;
|
physical_field /= mapping_determinant;
|
||||||
|
|
||||||
const double weight = point.weight * transformation->Weight() * mapping_determinant;
|
const double weight =
|
||||||
|
point.weight * transformation->Weight() * mapping_determinant;
|
||||||
const double rho = density.GetValue(element_id, point);
|
const double rho = density.GetValue(element_id, point);
|
||||||
const double phi = solution.phi.GetValue(element_id, point);
|
const double phi = solution.phi.GetValue(element_id, point);
|
||||||
local_binding += 0.5 * rho * phi * weight;
|
local_binding += 0.5 * rho * phi * weight;
|
||||||
@@ -264,34 +304,49 @@ static AccuracyBudgetEnergies measure_stellar_energies(
|
|||||||
}
|
}
|
||||||
|
|
||||||
AccuracyBudgetEnergies energies;
|
AccuracyBudgetEnergies energies;
|
||||||
MPI_Allreduce(&local_binding, &energies.binding, 1, MPI_DOUBLE, MPI_SUM, fem.L2_fes->GetComm());
|
MPI_Allreduce(&local_binding, &energies.binding, 1, MPI_DOUBLE, MPI_SUM,
|
||||||
MPI_Allreduce(&local_virial, &energies.virial, 1, MPI_DOUBLE, MPI_SUM, fem.L2_fes->GetComm());
|
fem.densityFes->GetComm());
|
||||||
|
MPI_Allreduce(&local_virial, &energies.virial, 1, MPI_DOUBLE, MPI_SUM,
|
||||||
|
fem.densityFes->GetComm());
|
||||||
return energies;
|
return energies;
|
||||||
}
|
}
|
||||||
|
|
||||||
static double reduced_gravity_relative_residual(
|
static double reduced_gravity_relative_residual(
|
||||||
mean_field::fem::FEM& fem,
|
mean_field::fem::FEM &fem, const mfem::GridFunction &density,
|
||||||
const mfem::GridFunction& density,
|
|
||||||
const mfem::GridFunction &displacement,
|
const mfem::GridFunction &displacement,
|
||||||
const mean_field::physics::GravitySolution& solution
|
const mean_field::physics::GravitySolution &solution) {
|
||||||
) {
|
|
||||||
using GravityFieldForm = mean_field::utils::blocks::gravity_field_form;
|
using GravityFieldForm = mean_field::utils::blocks::gravity_field_form;
|
||||||
|
|
||||||
constexpr auto gradient_block = mean_field::utils::blocks::get_residual_block<GravityFieldForm>(
|
constexpr auto gradient_block =
|
||||||
mean_field::utils::blocks::gravity_field.gradient_term
|
mean_field::utils::blocks::get_residual_block<GravityFieldForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.gradient_term);
|
||||||
constexpr auto poisson_block = mean_field::utils::blocks::get_residual_block<GravityFieldForm>(
|
constexpr auto poisson_block =
|
||||||
mean_field::utils::blocks::gravity_field.poisson_term
|
mean_field::utils::blocks::get_residual_block<GravityFieldForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
|
using DomainSchema =
|
||||||
|
mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
const mean_field::field::FieldDofMap density_map =
|
||||||
|
mean_field::field::make_field_dof_map<mean_field::field::Density,
|
||||||
|
DomainSchema>(*fem.densityFes);
|
||||||
|
const mean_field::field::FieldDofMap displacement_map =
|
||||||
|
mean_field::field::make_field_dof_map<mean_field::field::Displacement,
|
||||||
|
DomainSchema>(*fem.displacementFes);
|
||||||
|
const mean_field::field::FieldDofMap gravity_flux_map =
|
||||||
|
mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
|
DomainSchema>(*fem.gravityFluxFes);
|
||||||
|
const mean_field::field::FieldDofMap gravity_potential_map =
|
||||||
|
mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
|
DomainSchema>(
|
||||||
|
*fem.gravityPotentialFes);
|
||||||
|
|
||||||
const std::array<int, GravityFieldForm::value_block_count> value_sizes{
|
const std::array<int, GravityFieldForm::value_block_count> value_sizes{
|
||||||
fem.L2_fes->GetTrueVSize(), fem.Vec_H1_fes->GetTrueVSize(),
|
density_map.reduced_size(), displacement_map.reduced_size(),
|
||||||
fem.RT_fes->GetTrueVSize(), fem.L2_fes->GetTrueVSize()
|
gravity_flux_map.reduced_size(), gravity_potential_map.reduced_size()};
|
||||||
};
|
|
||||||
const std::array<int, GravityFieldForm::residual_block_count> residual_sizes{
|
const std::array<int, GravityFieldForm::residual_block_count> residual_sizes{
|
||||||
fem.RT_fes->GetTrueVSize(), fem.L2_fes->GetTrueVSize()
|
gravity_flux_map.reduced_size(), gravity_potential_map.reduced_size()};
|
||||||
};
|
const mean_field::utils::blocks::form_layout<GravityFieldForm> layout(
|
||||||
const mean_field::utils::blocks::form_layout<GravityFieldForm> layout(value_sizes, residual_sizes);
|
value_sizes, residual_sizes);
|
||||||
|
|
||||||
mfem::Vector density_true;
|
mfem::Vector density_true;
|
||||||
mfem::Vector displacement_true;
|
mfem::Vector displacement_true;
|
||||||
@@ -302,60 +357,47 @@ static double reduced_gravity_relative_residual(
|
|||||||
solution.gradPhi.GetTrueDofs(gradient_true);
|
solution.gradPhi.GetTrueDofs(gradient_true);
|
||||||
solution.phi.GetTrueDofs(potential_true);
|
solution.phi.GetTrueDofs(potential_true);
|
||||||
|
|
||||||
mean_field::operators::context::gravity_field::GravityFieldLinearizationContext linearization_context(
|
mean_field::operators::context::gravity_field::
|
||||||
fem,
|
GravityFieldLinearizationContext linearization_context(
|
||||||
*fem.domain_mapper_stateless
|
fem, *fem.domainMapperStateless);
|
||||||
);
|
|
||||||
mean_field::operators::GravityFieldJacobianOperator jacobian(
|
mean_field::operators::GravityFieldJacobianOperator jacobian(
|
||||||
fem,
|
fem, *fem.domainMapperStateless, linearization_context,
|
||||||
*fem.domain_mapper_stateless,
|
layout.value_offsets(), layout.residual_offsets());
|
||||||
linearization_context,
|
|
||||||
layout.value_offsets(),
|
|
||||||
layout.residual_offsets()
|
|
||||||
);
|
|
||||||
mean_field::operators::GravityFieldOperator field_operator(
|
mean_field::operators::GravityFieldOperator field_operator(
|
||||||
fem,
|
fem, *fem.domainMapperStateless, linearization_context,
|
||||||
*fem.domain_mapper_stateless,
|
layout.value_offsets(), jacobian);
|
||||||
linearization_context,
|
mean_field::operators::context::gravity_field::GravityFieldGeometryContext
|
||||||
layout.value_offsets(),
|
geometry_context(fem, *fem.domainMapperStateless);
|
||||||
jacobian
|
|
||||||
);
|
|
||||||
mean_field::operators::context::gravity_field::GravityFieldGeometryContext geometry_context(
|
|
||||||
fem,
|
|
||||||
*fem.domain_mapper_stateless
|
|
||||||
);
|
|
||||||
mean_field::operators::ReducedGravityFieldOperator reduced_operator(
|
mean_field::operators::ReducedGravityFieldOperator reduced_operator(
|
||||||
field_operator,
|
field_operator, geometry_context,
|
||||||
geometry_context,
|
displacement_map.gather(displacement_true));
|
||||||
displacement_true
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector right_hand_side;
|
mfem::Vector right_hand_side;
|
||||||
reduced_operator.BuildRightHandSide(density_true, right_hand_side);
|
reduced_operator.BuildRightHandSide(density_map.gather(density_true),
|
||||||
|
right_hand_side);
|
||||||
|
|
||||||
mfem::BlockVector state(layout.residual_offsets());
|
mfem::BlockVector state(layout.residual_offsets());
|
||||||
state = 0.0;
|
state = 0.0;
|
||||||
state.GetBlock(gradient_block) = gradient_true;
|
state.GetBlock(gradient_block) = gravity_flux_map.gather(gradient_true);
|
||||||
state.GetBlock(poisson_block) = potential_true;
|
state.GetBlock(poisson_block) = gravity_potential_map.gather(potential_true);
|
||||||
|
|
||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
reduced_operator.Mult(state, residual);
|
reduced_operator.Mult(state, residual);
|
||||||
residual -= right_hand_side;
|
residual -= right_hand_side;
|
||||||
|
|
||||||
return global_norm(residual, fem.L2_fes->GetComm()) /
|
return global_norm(residual, fem.mesh->GetComm()) /
|
||||||
std::max(global_norm(right_hand_side, fem.L2_fes->GetComm()), std::numeric_limits<double>::epsilon());
|
std::max(global_norm(right_hand_side, fem.mesh->GetComm()),
|
||||||
|
std::numeric_limits<double>::epsilon());
|
||||||
}
|
}
|
||||||
|
|
||||||
static AccuracyBudgetMetrics measure_monopole_accuracy(
|
static AccuracyBudgetMetrics
|
||||||
mean_field::fem::FEM& fem,
|
measure_monopole_accuracy(mean_field::fem::FEM &fem,
|
||||||
const mfem::GridFunction &density,
|
const mfem::GridFunction &density,
|
||||||
const mfem::GridFunction &displacement,
|
const mfem::GridFunction &displacement,
|
||||||
const mean_field::physics::GravitySolution &solution,
|
const mean_field::physics::GravitySolution &solution,
|
||||||
const mfem::ParGridFunction &projected_potential,
|
const mfem::ParGridFunction &projected_potential,
|
||||||
const mfem::Vector &projected_gradient,
|
const mfem::Vector &projected_gradient,
|
||||||
const double mass,
|
const double mass, const double stellar_radius) {
|
||||||
const double stellar_radius
|
|
||||||
) {
|
|
||||||
mfem::Vector solution_gradient;
|
mfem::Vector solution_gradient;
|
||||||
solution.gradPhi.GetTrueDofs(solution_gradient);
|
solution.gradPhi.GetTrueDofs(solution_gradient);
|
||||||
|
|
||||||
@@ -364,7 +406,8 @@ static AccuracyBudgetMetrics measure_monopole_accuracy(
|
|||||||
solution.phi.GetTrueDofs(solution_potential);
|
solution.phi.GetTrueDofs(solution_potential);
|
||||||
projected_potential.GetTrueDofs(projection_potential);
|
projected_potential.GetTrueDofs(projection_potential);
|
||||||
|
|
||||||
mfem::ParGridFunction projected_gradient_grid_function(fem.RT_fes.get());
|
mfem::ParGridFunction projected_gradient_grid_function(
|
||||||
|
fem.gravityFluxFes.get());
|
||||||
projected_gradient_grid_function.SetFromTrueDofs(projected_gradient);
|
projected_gradient_grid_function.SetFromTrueDofs(projected_gradient);
|
||||||
|
|
||||||
double local_solution_gradient_error = 0.0;
|
double local_solution_gradient_error = 0.0;
|
||||||
@@ -374,146 +417,185 @@ static AccuracyBudgetMetrics measure_monopole_accuracy(
|
|||||||
double local_projection_potential_error = 0.0;
|
double local_projection_potential_error = 0.0;
|
||||||
double local_potential_norm = 0.0;
|
double local_potential_norm = 0.0;
|
||||||
|
|
||||||
const int vacuum_attribute = fem.domain_mapper_stateless->GetVacuumElementAttribute();
|
const int vacuum_attribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
const int quadrature_order = diagnostic_quadrature_order(fem);
|
const int quadrature_order = diagnostic_quadrature_order(fem);
|
||||||
|
mean_field::mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate);
|
||||||
mfem::Vector physical_position(3);
|
mfem::Vector physical_position(3);
|
||||||
mfem::Vector analytic_gradient(3);
|
mfem::Vector analytic_gradient(3);
|
||||||
mfem::Vector solution_reference_gradient(3);
|
mfem::Vector solution_reference_gradient(3);
|
||||||
mfem::Vector projection_reference_gradient(3);
|
mfem::Vector projection_reference_gradient(3);
|
||||||
mfem::Vector solution_physical_gradient(3);
|
mfem::Vector solution_physical_gradient(3);
|
||||||
mfem::Vector projection_physical_gradient(3);
|
mfem::Vector projection_physical_gradient(3);
|
||||||
mfem::DenseMatrix mapping_jacobian(3);
|
|
||||||
|
|
||||||
for (int element_id = 0; element_id < fem.mesh->GetNE(); ++element_id) {
|
for (int element_id = 0; element_id < fem.mesh->GetNE(); ++element_id) {
|
||||||
mfem::ElementTransformation* transformation = fem.mesh->GetElementTransformation(element_id);
|
mfem::ElementTransformation *transformation =
|
||||||
const mfem::IntegrationRule& rule = mfem::IntRules.Get(
|
fem.mesh->GetElementTransformation(element_id);
|
||||||
transformation->GetGeometryType(),
|
const mfem::IntegrationRule &rule =
|
||||||
quadrature_order
|
mfem::IntRules.Get(transformation->GetGeometryType(), quadrature_order);
|
||||||
);
|
|
||||||
|
|
||||||
for (int quadrature_point_id = 0; quadrature_point_id < rule.GetNPoints(); ++quadrature_point_id) {
|
for (int quadrature_point_id = 0; quadrature_point_id < rule.GetNPoints();
|
||||||
|
++quadrature_point_id) {
|
||||||
const mfem::IntegrationPoint &point = rule.IntPoint(quadrature_point_id);
|
const mfem::IntegrationPoint &point = rule.IntPoint(quadrature_point_id);
|
||||||
transformation->SetIntPoint(&point);
|
transformation->SetIntPoint(&point);
|
||||||
fem.mapping->GetPhysicalPoint(*transformation, point, physical_position);
|
mean_field::mapping::MappingPointContext mapping_context;
|
||||||
fem.mapping->ComputeJacobian(*transformation, mapping_jacobian);
|
MFEM_VERIFY(
|
||||||
const double mapping_determinant = mapping_jacobian.Det();
|
mapping_evaluator.EvaluatePoint(*transformation, point,
|
||||||
MFEM_VERIFY(mapping_determinant > 0.0, "Non-positive mapping determinant in accuracy diagnostic.");
|
mapping_context) ==
|
||||||
|
mean_field::mapping::MappingStatus::valid,
|
||||||
|
"Invalid mapping in accuracy diagnostic.");
|
||||||
|
physical_position = mapping_context.physical_position;
|
||||||
|
const mfem::DenseMatrix &mapping_jacobian =
|
||||||
|
mapping_context.mapping_jacobian;
|
||||||
|
const double mapping_determinant =
|
||||||
|
mapping_context.mapping_determinant;
|
||||||
|
MFEM_VERIFY(mapping_determinant > 0.0,
|
||||||
|
"Non-positive mapping determinant in accuracy diagnostic.");
|
||||||
|
|
||||||
const double radius = physical_position.Norml2();
|
const double radius = physical_position.Norml2();
|
||||||
MFEM_VERIFY(std::isfinite(radius) && radius > 0.0, "Invalid radius in monopole diagnostic.");
|
MFEM_VERIFY(std::isfinite(radius) && radius > 0.0,
|
||||||
|
"Invalid radius in monopole diagnostic.");
|
||||||
|
|
||||||
analytic_gradient = physical_position;
|
analytic_gradient = physical_position;
|
||||||
double analytic_potential = 0.0;
|
double analytic_potential = 0.0;
|
||||||
if (transformation->Attribute == vacuum_attribute) {
|
if (transformation->Attribute == vacuum_attribute) {
|
||||||
analytic_gradient *= mean_field::utils::G * mass / (radius * radius * radius);
|
analytic_gradient *=
|
||||||
|
mean_field::utils::G * mass / (radius * radius * radius);
|
||||||
analytic_potential = -mean_field::utils::G * mass / radius;
|
analytic_potential = -mean_field::utils::G * mass / radius;
|
||||||
} else {
|
} else {
|
||||||
analytic_gradient *= mean_field::utils::G * mass /
|
analytic_gradient *= mean_field::utils::G * mass /
|
||||||
(stellar_radius * stellar_radius * stellar_radius);
|
(stellar_radius * stellar_radius * stellar_radius);
|
||||||
analytic_potential = -mean_field::utils::G * mass *
|
analytic_potential =
|
||||||
|
-mean_field::utils::G * mass *
|
||||||
(3.0 * stellar_radius * stellar_radius - radius * radius) /
|
(3.0 * stellar_radius * stellar_radius - radius * radius) /
|
||||||
(2.0 * stellar_radius * stellar_radius * stellar_radius);
|
(2.0 * stellar_radius * stellar_radius * stellar_radius);
|
||||||
}
|
}
|
||||||
|
|
||||||
solution.gradPhi.GetVectorValue(element_id, point, solution_reference_gradient);
|
solution.gradPhi.GetVectorValue(element_id, point,
|
||||||
mapping_jacobian.Mult(solution_reference_gradient, solution_physical_gradient);
|
solution_reference_gradient);
|
||||||
|
mapping_jacobian.Mult(solution_reference_gradient,
|
||||||
|
solution_physical_gradient);
|
||||||
solution_physical_gradient /= mapping_determinant;
|
solution_physical_gradient /= mapping_determinant;
|
||||||
|
|
||||||
projected_gradient_grid_function.GetVectorValue(element_id, point, projection_reference_gradient);
|
projected_gradient_grid_function.GetVectorValue(
|
||||||
mapping_jacobian.Mult(projection_reference_gradient, projection_physical_gradient);
|
element_id, point, projection_reference_gradient);
|
||||||
|
mapping_jacobian.Mult(projection_reference_gradient,
|
||||||
|
projection_physical_gradient);
|
||||||
projection_physical_gradient /= mapping_determinant;
|
projection_physical_gradient /= mapping_determinant;
|
||||||
|
|
||||||
const double solution_potential_value = solution.phi.GetValue(element_id, point);
|
const double solution_potential_value =
|
||||||
const double projection_potential_value = projected_potential.GetValue(element_id, point);
|
solution.phi.GetValue(element_id, point);
|
||||||
const double weight = point.weight * transformation->Weight() * mapping_determinant;
|
const double projection_potential_value =
|
||||||
|
projected_potential.GetValue(element_id, point);
|
||||||
|
const double weight =
|
||||||
|
point.weight * transformation->Weight() * mapping_determinant;
|
||||||
|
|
||||||
solution_physical_gradient -= analytic_gradient;
|
solution_physical_gradient -= analytic_gradient;
|
||||||
projection_physical_gradient -= analytic_gradient;
|
projection_physical_gradient -= analytic_gradient;
|
||||||
local_solution_gradient_error += weight * (solution_physical_gradient * solution_physical_gradient);
|
local_solution_gradient_error +=
|
||||||
local_projection_gradient_error += weight * (projection_physical_gradient * projection_physical_gradient);
|
weight * (solution_physical_gradient * solution_physical_gradient);
|
||||||
|
local_projection_gradient_error +=
|
||||||
|
weight *
|
||||||
|
(projection_physical_gradient * projection_physical_gradient);
|
||||||
local_gradient_norm += weight * (analytic_gradient * analytic_gradient);
|
local_gradient_norm += weight * (analytic_gradient * analytic_gradient);
|
||||||
local_solution_potential_error += weight *
|
local_solution_potential_error +=
|
||||||
(solution_potential_value - analytic_potential) * (solution_potential_value - analytic_potential);
|
weight * (solution_potential_value - analytic_potential) *
|
||||||
local_projection_potential_error += weight *
|
(solution_potential_value - analytic_potential);
|
||||||
(projection_potential_value - analytic_potential) * (projection_potential_value - analytic_potential);
|
local_projection_potential_error +=
|
||||||
|
weight * (projection_potential_value - analytic_potential) *
|
||||||
|
(projection_potential_value - analytic_potential);
|
||||||
local_potential_norm += weight * analytic_potential * analytic_potential;
|
local_potential_norm += weight * analytic_potential * analytic_potential;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::array<double, 6> local_values{
|
const std::array<double, 6> local_values{local_solution_gradient_error,
|
||||||
local_solution_gradient_error, local_projection_gradient_error, local_gradient_norm,
|
local_projection_gradient_error,
|
||||||
local_solution_potential_error, local_projection_potential_error, local_potential_norm
|
local_gradient_norm,
|
||||||
};
|
local_solution_potential_error,
|
||||||
|
local_projection_potential_error,
|
||||||
|
local_potential_norm};
|
||||||
std::array<double, 6> global_values{};
|
std::array<double, 6> global_values{};
|
||||||
MPI_Allreduce(
|
MPI_Allreduce(local_values.data(), global_values.data(),
|
||||||
local_values.data(), global_values.data(), static_cast<int>(local_values.size()),
|
static_cast<int>(local_values.size()), MPI_DOUBLE, MPI_SUM,
|
||||||
MPI_DOUBLE, MPI_SUM, fem.L2_fes->GetComm()
|
fem.mesh->GetComm());
|
||||||
);
|
|
||||||
|
|
||||||
const AccuracyBudgetEnergies energies = measure_stellar_energies(fem, density, solution);
|
const AccuracyBudgetEnergies energies =
|
||||||
const double analytic_energy = -3.0 * mean_field::utils::G * mass * mass / (5.0 * stellar_radius);
|
measure_stellar_energies(fem, density, solution);
|
||||||
|
const double analytic_energy =
|
||||||
|
-3.0 * mean_field::utils::G * mass * mass / (5.0 * stellar_radius);
|
||||||
|
|
||||||
REQUIRE(global_values[2] > 0.0);
|
REQUIRE(global_values[2] > 0.0);
|
||||||
REQUIRE(global_values[5] > 0.0);
|
REQUIRE(global_values[5] > 0.0);
|
||||||
|
|
||||||
AccuracyBudgetMetrics metrics;
|
AccuracyBudgetMetrics metrics;
|
||||||
metrics.direct_relative_residual = reduced_gravity_relative_residual(fem, density, displacement, solution);
|
metrics.direct_relative_residual =
|
||||||
metrics.gradient_relative_error = std::sqrt(global_values[0] / global_values[2]);
|
reduced_gravity_relative_residual(fem, density, displacement, solution);
|
||||||
metrics.gradient_projection_relative_error = std::sqrt(global_values[1] / global_values[2]);
|
metrics.gradient_relative_error =
|
||||||
|
std::sqrt(global_values[0] / global_values[2]);
|
||||||
|
metrics.gradient_projection_relative_error =
|
||||||
|
std::sqrt(global_values[1] / global_values[2]);
|
||||||
metrics.gradient_solution_projection_gap = mapped_hdiv_relative_gap(
|
metrics.gradient_solution_projection_gap = mapped_hdiv_relative_gap(
|
||||||
fem, displacement, solution_gradient, projected_gradient
|
fem, displacement, solution_gradient, projected_gradient);
|
||||||
);
|
metrics.potential_relative_error =
|
||||||
metrics.potential_relative_error = std::sqrt(global_values[3] / global_values[5]);
|
std::sqrt(global_values[3] / global_values[5]);
|
||||||
metrics.potential_projection_relative_error = std::sqrt(global_values[4] / global_values[5]);
|
metrics.potential_projection_relative_error =
|
||||||
|
std::sqrt(global_values[4] / global_values[5]);
|
||||||
mfem::Vector potential_difference(solution_potential);
|
mfem::Vector potential_difference(solution_potential);
|
||||||
potential_difference -= projection_potential;
|
potential_difference -= projection_potential;
|
||||||
const double projection_potential_norm = global_norm(projection_potential, fem.L2_fes->GetComm());
|
const double projection_potential_norm =
|
||||||
|
global_norm(projection_potential, fem.gravityPotentialFes->GetComm());
|
||||||
REQUIRE(projection_potential_norm > 0.0);
|
REQUIRE(projection_potential_norm > 0.0);
|
||||||
metrics.potential_solution_projection_gap = global_norm(potential_difference, fem.L2_fes->GetComm()) /
|
metrics.potential_solution_projection_gap =
|
||||||
|
global_norm(potential_difference, fem.gravityPotentialFes->GetComm()) /
|
||||||
projection_potential_norm;
|
projection_potential_norm;
|
||||||
metrics.binding_relative_error = std::abs(energies.binding - analytic_energy) / std::abs(analytic_energy);
|
metrics.binding_relative_error =
|
||||||
metrics.virial_relative_error = std::abs(energies.virial - analytic_energy) / std::abs(analytic_energy);
|
std::abs(energies.binding - analytic_energy) / std::abs(analytic_energy);
|
||||||
metrics.virial_consistency_error = std::abs(energies.binding - energies.virial) /
|
metrics.virial_relative_error =
|
||||||
std::max(std::abs(energies.binding), std::numeric_limits<double>::epsilon());
|
std::abs(energies.virial - analytic_energy) / std::abs(analytic_energy);
|
||||||
|
metrics.virial_consistency_error =
|
||||||
|
std::abs(energies.binding - energies.virial) /
|
||||||
|
std::max(std::abs(energies.binding),
|
||||||
|
std::numeric_limits<double>::epsilon());
|
||||||
return metrics;
|
return metrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void run_monopole_case(
|
static void run_monopole_case(const std::string &sweep_name,
|
||||||
const std::string& sweep_name,
|
|
||||||
const std::string &case_name,
|
const std::string &case_name,
|
||||||
mean_field::utils::Args args,
|
mean_field::utils::Args args,
|
||||||
const double solver_tolerance,
|
const double solver_tolerance,
|
||||||
const int quadrature_boost
|
const int quadrature_boost) {
|
||||||
) {
|
|
||||||
args.p.rtol = solver_tolerance;
|
args.p.rtol = solver_tolerance;
|
||||||
args.p.atol = std::min(args.p.atol, solver_tolerance * 1.0e-2);
|
args.p.atol = std::min(args.p.atol, solver_tolerance * 1.0e-2);
|
||||||
args.p.max_iters = std::max(args.p.max_iters, 2000);
|
args.p.max_iters = std::max(args.p.max_iters, 2000);
|
||||||
args.quadrature.global_boost = quadrature_boost;
|
args.quadrature.global_boost = quadrature_boost;
|
||||||
|
|
||||||
mean_field::fem::FEM fem = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM fem =
|
||||||
REQUIRE(fem.mapping != nullptr);
|
mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
REQUIRE(fem.domain_mapper_stateless != nullptr);
|
REQUIRE(fem.domainMapperStateless != nullptr);
|
||||||
|
|
||||||
const double stellar_radius = mean_field::utils::RADIUS;
|
const double stellar_radius = mean_field::utils::RADIUS;
|
||||||
const double mass = mean_field::utils::MASS;
|
const double mass = mean_field::utils::MASS;
|
||||||
const double density_value = mass / ((4.0 / 3.0) * M_PI * stellar_radius * stellar_radius * stellar_radius);
|
const double density_value = mass / ((4.0 / 3.0) * M_PI * stellar_radius *
|
||||||
|
stellar_radius * stellar_radius);
|
||||||
|
|
||||||
mfem::ParGridFunction displacement(fem.Vec_H1_fes.get());
|
mfem::ParGridFunction displacement(fem.displacementFes.get());
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
fem.mapping->ResetDisplacement();
|
*fem.displacement = 0.0;
|
||||||
mean_field::physics::update_stiffness_matrix(fem);
|
mfem::GridFunction density(fem.densityFes.get());
|
||||||
|
|
||||||
mfem::GridFunction density(fem.L2_fes.get());
|
|
||||||
density = density_value;
|
density = density_value;
|
||||||
zero_vacuum_density(fem, density);
|
zero_vacuum_density(fem, density);
|
||||||
mean_field::analysis::conserve_mass(fem, density, mass);
|
mean_field::analysis::conserve_mass(fem, density, mass);
|
||||||
fem.com = mean_field::analysis::get_com(fem, density);
|
fem.com = mean_field::analysis::get_com(fem, density);
|
||||||
fem.Q = mean_field::physics::compute_quadrupole_moment_tensor(fem, density, fem.com);
|
fem.Q = mean_field::physics::compute_quadrupole_moment_tensor(fem, density,
|
||||||
|
fem.com);
|
||||||
|
|
||||||
const mean_field::physics::GravitySolution solution =
|
const mean_field::physics::GravitySolution solution =
|
||||||
mean_field::physics::grav_potential_new(fem, args, density, displacement);
|
mean_field::physics::solve_gravity_field(fem, args, density,
|
||||||
|
displacement);
|
||||||
|
|
||||||
auto analytic_potential = [mass, stellar_radius](const mfem::Vector& position) {
|
auto analytic_potential = [mass,
|
||||||
|
stellar_radius](const mfem::Vector &position) {
|
||||||
const double radius = position.Norml2();
|
const double radius = position.Norml2();
|
||||||
if (radius >= stellar_radius) {
|
if (radius >= stellar_radius) {
|
||||||
return -mean_field::utils::G * mass / radius;
|
return -mean_field::utils::G * mass / radius;
|
||||||
@@ -522,30 +604,19 @@ static void run_monopole_case(
|
|||||||
(3.0 * stellar_radius * stellar_radius - radius * radius) /
|
(3.0 * stellar_radius * stellar_radius - radius * radius) /
|
||||||
(2.0 * stellar_radius * stellar_radius * stellar_radius);
|
(2.0 * stellar_radius * stellar_radius * stellar_radius);
|
||||||
};
|
};
|
||||||
mean_field::mapping::PhysicalPositionFunctionCoefficient potential_coefficient(
|
mean_field::mapping::PhysicalPositionFunctionCoefficient
|
||||||
*fem.mapping,
|
potential_coefficient(*fem.domainMapperStateless, *fem.displacement,
|
||||||
analytic_potential
|
*fem.compactificationCoordinate,
|
||||||
);
|
analytic_potential);
|
||||||
mfem::ParGridFunction projected_potential(fem.L2_fes.get());
|
mfem::ParGridFunction projected_potential(fem.gravityPotentialFes.get());
|
||||||
projected_potential.ProjectCoefficient(potential_coefficient);
|
projected_potential.ProjectCoefficient(potential_coefficient);
|
||||||
|
|
||||||
const mfem::Vector projected_gradient = project_monopole_gradient(
|
const mfem::Vector projected_gradient =
|
||||||
fem,
|
project_monopole_gradient(fem, displacement, mass, stellar_radius);
|
||||||
displacement,
|
|
||||||
mass,
|
|
||||||
stellar_radius
|
|
||||||
);
|
|
||||||
|
|
||||||
const AccuracyBudgetMetrics metrics = measure_monopole_accuracy(
|
const AccuracyBudgetMetrics metrics = measure_monopole_accuracy(
|
||||||
fem,
|
fem, density, displacement, solution, projected_potential,
|
||||||
density,
|
projected_gradient, mass, stellar_radius);
|
||||||
displacement,
|
|
||||||
solution,
|
|
||||||
projected_potential,
|
|
||||||
projected_gradient,
|
|
||||||
mass,
|
|
||||||
stellar_radius
|
|
||||||
);
|
|
||||||
|
|
||||||
REQUIRE(std::isfinite(metrics.direct_relative_residual));
|
REQUIRE(std::isfinite(metrics.direct_relative_residual));
|
||||||
REQUIRE(std::isfinite(metrics.gradient_relative_error));
|
REQUIRE(std::isfinite(metrics.gradient_relative_error));
|
||||||
@@ -553,64 +624,51 @@ static void run_monopole_case(
|
|||||||
REQUIRE(std::isfinite(metrics.virial_consistency_error));
|
REQUIRE(std::isfinite(metrics.virial_consistency_error));
|
||||||
|
|
||||||
record_experiment_result(
|
record_experiment_result(
|
||||||
sweep_name,
|
sweep_name, case_name,
|
||||||
case_name,
|
{{"solver_rtol", std::to_string(solver_tolerance)},
|
||||||
{
|
|
||||||
{"solver_rtol", std::to_string(solver_tolerance)},
|
|
||||||
{"quadrature_global_boost", std::to_string(quadrature_boost)},
|
{"quadrature_global_boost", std::to_string(quadrature_boost)},
|
||||||
{"mesh_file", args.mesh_file}
|
{"mesh_file", args.mesh_file}},
|
||||||
},
|
{{"direct_relative_residual", metrics.direct_relative_residual},
|
||||||
{
|
|
||||||
{"direct_relative_residual", metrics.direct_relative_residual},
|
|
||||||
{"gradient_relative_error", metrics.gradient_relative_error},
|
{"gradient_relative_error", metrics.gradient_relative_error},
|
||||||
{"gradient_projection_relative_error", metrics.gradient_projection_relative_error},
|
{"gradient_projection_relative_error",
|
||||||
{"gradient_solution_projection_gap", metrics.gradient_solution_projection_gap},
|
metrics.gradient_projection_relative_error},
|
||||||
|
{"gradient_solution_projection_gap",
|
||||||
|
metrics.gradient_solution_projection_gap},
|
||||||
{"potential_relative_error", metrics.potential_relative_error},
|
{"potential_relative_error", metrics.potential_relative_error},
|
||||||
{"potential_projection_relative_error", metrics.potential_projection_relative_error},
|
{"potential_projection_relative_error",
|
||||||
{"potential_solution_projection_gap", metrics.potential_solution_projection_gap},
|
metrics.potential_projection_relative_error},
|
||||||
|
{"potential_solution_projection_gap",
|
||||||
|
metrics.potential_solution_projection_gap},
|
||||||
{"binding_relative_error", metrics.binding_relative_error},
|
{"binding_relative_error", metrics.binding_relative_error},
|
||||||
{"virial_relative_error", metrics.virial_relative_error},
|
{"virial_relative_error", metrics.virial_relative_error},
|
||||||
{"virial_consistency_error", metrics.virial_consistency_error}
|
{"virial_consistency_error", metrics.virial_consistency_error}});
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Uniform Monopole Accuracy Budget: Solver Tolerance", tags::gravity & tags::accuracy & tags::integration) {
|
TEST_CASE("Uniform Monopole Accuracy Budget: Solver Tolerance",
|
||||||
|
tags::gravity_analytic_accuracy) {
|
||||||
const mean_field::utils::Args args = test_utils::setup_args();
|
const mean_field::utils::Args args = test_utils::setup_args();
|
||||||
constexpr std::array<double, 4> solver_tolerances{1.0e-8, 1.0e-10, 1.0e-12, 1.0e-14};
|
constexpr std::array<double, 4> solver_tolerances{1.0e-8, 1.0e-10, 1.0e-12,
|
||||||
|
1.0e-14};
|
||||||
|
|
||||||
for (const double solver_tolerance : solver_tolerances) {
|
for (const double solver_tolerance : solver_tolerances) {
|
||||||
run_monopole_case(
|
run_monopole_case("solver_tolerance", "uniform_monopole", args,
|
||||||
"solver_tolerance",
|
solver_tolerance, 0);
|
||||||
"uniform_monopole",
|
|
||||||
args,
|
|
||||||
solver_tolerance,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Uniform Monopole Accuracy Budget: Quadrature", tags::gravity & tags::accuracy & tags::integration) {
|
TEST_CASE("Uniform Monopole Accuracy Budget: Quadrature",
|
||||||
|
tags::gravity_analytic_accuracy) {
|
||||||
const mean_field::utils::Args args = test_utils::setup_args();
|
const mean_field::utils::Args args = test_utils::setup_args();
|
||||||
constexpr std::array<int, 3> quadrature_boosts{0, 4, 8};
|
constexpr std::array<int, 3> quadrature_boosts{0, 4, 8};
|
||||||
|
|
||||||
for (const int quadrature_boost : quadrature_boosts) {
|
for (const int quadrature_boost : quadrature_boosts) {
|
||||||
run_monopole_case(
|
run_monopole_case("quadrature", "uniform_monopole", args, 1.0e-13,
|
||||||
"quadrature",
|
quadrature_boost);
|
||||||
"uniform_monopole",
|
|
||||||
args,
|
|
||||||
1.0e-13,
|
|
||||||
quadrature_boost
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("Uniform Monopole Accuracy Budget: Projection Decomposition", tags::gravity & tags::accuracy & tags::integration) {
|
TEST_CASE("Uniform Monopole Accuracy Budget: Projection Decomposition",
|
||||||
run_monopole_case(
|
tags::gravity_analytic_accuracy) {
|
||||||
"projection_decomposition",
|
run_monopole_case("projection_decomposition", "uniform_monopole",
|
||||||
"uniform_monopole",
|
test_utils::setup_args(), 1.0e-13, 0);
|
||||||
test_utils::setup_args(),
|
|
||||||
1.0e-13,
|
|
||||||
0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,32 @@ module mean_field;
|
|||||||
import :mapping.coefficients;
|
import :mapping.coefficients;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
|
mfem::Array<int> make_domain_marker(
|
||||||
|
const mfem::Mesh &mesh,
|
||||||
|
const mean_field::utils::DOMAINS domain
|
||||||
|
) {
|
||||||
|
switch (domain) {
|
||||||
|
case mean_field::utils::DOMAINS::CORE:
|
||||||
|
return mean_field::utils::domain::make_attribute_marker<
|
||||||
|
mean_field::utils::domain::Core, DomainSchema>(mesh);
|
||||||
|
case mean_field::utils::DOMAINS::ENVELOPE:
|
||||||
|
return mean_field::utils::domain::make_attribute_marker<
|
||||||
|
mean_field::utils::domain::Envelope, DomainSchema>(mesh);
|
||||||
|
case mean_field::utils::DOMAINS::ALL:
|
||||||
|
return mean_field::utils::domain::make_attribute_marker<
|
||||||
|
mean_field::utils::domain::All, DomainSchema>(mesh);
|
||||||
|
case mean_field::utils::DOMAINS::STELLAR:
|
||||||
|
return mean_field::utils::domain::make_attribute_marker<
|
||||||
|
mean_field::utils::domain::Stellar, DomainSchema>(mesh);
|
||||||
|
case mean_field::utils::DOMAINS::VACUUM:
|
||||||
|
return mean_field::utils::domain::make_attribute_marker<
|
||||||
|
mean_field::utils::domain::Vacuum, DomainSchema>(mesh);
|
||||||
|
}
|
||||||
|
MFEM_ABORT("Unsupported integration domain.");
|
||||||
|
}
|
||||||
|
|
||||||
template <typename FormT>
|
template <typename FormT>
|
||||||
const mfem::IntegrationRule &get_density_rule(
|
const mfem::IntegrationRule &get_density_rule(
|
||||||
const mean_field::fem::FEM &fem,
|
const mean_field::fem::FEM &fem,
|
||||||
@@ -36,14 +62,16 @@ namespace mean_field::analysis {
|
|||||||
mfem::LinearForm lf(fem.densityFes.get());
|
mfem::LinearForm lf(fem.densityFes.get());
|
||||||
mfem::GridFunctionCoefficient gf_c(&gf);
|
mfem::GridFunctionCoefficient gf_c(&gf);
|
||||||
double local_integral;
|
double local_integral;
|
||||||
mfem::Array<int> elem_markers;
|
mfem::Array<int> elem_markers = make_domain_marker(*fem.mesh, domain);
|
||||||
populate_element_mask(fem.mesh.get(), domain, elem_markers);
|
|
||||||
const mfem::ElementTransformation &representative_transformation = *fem.mesh->GetElementTransformation(0);
|
const mfem::ElementTransformation &representative_transformation = *fem.mesh->GetElementTransformation(0);
|
||||||
const mfem::IntegrationRule &integration_rule =
|
const mfem::IntegrationRule &integration_rule =
|
||||||
get_density_rule<field::Density::Form::MassConservation>(fem, representative_transformation, {}, domain);
|
get_density_rule<field::Density::Form::MassConservation>(fem, representative_transformation, {}, domain);
|
||||||
|
|
||||||
if (fem.has_mapping() && coord_space == mapping::COORDINATE_SPACE::PHYSICAL) {
|
if (fem.has_mapping() && coord_space == mapping::COORDINATE_SPACE::PHYSICAL) {
|
||||||
mapping::MappedScalarCoefficient mapped_gf_c(*fem.mapping, gf_c);
|
mapping::MappedScalarCoefficient mapped_gf_c(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate, gf_c
|
||||||
|
);
|
||||||
|
|
||||||
// ReSharper disable once CppDFAMemoryLeak // Disabled because MFEM
|
// ReSharper disable once CppDFAMemoryLeak // Disabled because MFEM
|
||||||
// takes ownership so memory is not leaked
|
// takes ownership so memory is not leaked
|
||||||
@@ -78,12 +106,17 @@ namespace mean_field::analysis {
|
|||||||
const mfem::GridFunction &rho
|
const mfem::GridFunction &rho
|
||||||
) {
|
) {
|
||||||
const int dim = fem.mesh->Dimension();
|
const int dim = fem.mesh->Dimension();
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate
|
||||||
|
);
|
||||||
mfem::Vector local_com(dim);
|
mfem::Vector local_com(dim);
|
||||||
local_com = 0.0;
|
local_com = 0.0;
|
||||||
double local_mass = 0.0;
|
double local_mass = 0.0;
|
||||||
|
|
||||||
for (int i = 0; i < fem.mesh->GetNE(); ++i) {
|
for (int i = 0; i < fem.mesh->GetNE(); ++i) {
|
||||||
if (fem.mesh->GetAttribute(i) == 3)
|
if (!DomainSchema::template attribute_belongs_to<utils::domain::Stellar>(
|
||||||
|
fem.mesh->GetAttribute(i)))
|
||||||
continue;
|
continue;
|
||||||
mfem::ElementTransformation *trans = fem.mesh->GetElementTransformation(i);
|
mfem::ElementTransformation *trans = fem.mesh->GetElementTransformation(i);
|
||||||
const mfem::IntegrationRule &ir = get_density_rule<field::Density::Form::CenterOfMass>(
|
const mfem::IntegrationRule &ir = get_density_rule<field::Density::Form::CenterOfMass>(
|
||||||
@@ -94,18 +127,16 @@ namespace mean_field::analysis {
|
|||||||
const mfem::IntegrationPoint &ip = ir.IntPoint(j);
|
const mfem::IntegrationPoint &ip = ir.IntPoint(j);
|
||||||
trans->SetIntPoint(&ip);
|
trans->SetIntPoint(&ip);
|
||||||
|
|
||||||
double weight = trans->Weight() * ip.weight;
|
mapping::VolumeMappingContext mapping_context;
|
||||||
if (fem.has_mapping()) {
|
MFEM_VERIFY(
|
||||||
weight *= fem.mapping->ComputeDetJ(*trans, ip);
|
mapping_evaluator.EvaluateVolume(*trans, ip, mapping_context) ==
|
||||||
}
|
mapping::MappingStatus::valid,
|
||||||
|
"Center-of-mass integration encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
const double weight = mapping_context.quadrature.weight;
|
||||||
double rho_val = rho.GetValue(i, ip);
|
double rho_val = rho.GetValue(i, ip);
|
||||||
|
|
||||||
mfem::Vector phys_point(dim);
|
const mfem::Vector &phys_point = mapping_context.mapping.physical_position;
|
||||||
if (fem.has_mapping()) {
|
|
||||||
fem.mapping->GetPhysicalPoint(*trans, ip, phys_point);
|
|
||||||
} else {
|
|
||||||
trans->Transform(ip, phys_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
const double mass_term = rho_val * weight;
|
const double mass_term = rho_val * weight;
|
||||||
local_mass += mass_term;
|
local_mass += mass_term;
|
||||||
@@ -151,7 +182,10 @@ namespace mean_field::analysis {
|
|||||||
|
|
||||||
std::unique_ptr<mfem::Coefficient> s2_coeff;
|
std::unique_ptr<mfem::Coefficient> s2_coeff;
|
||||||
if (fem.has_mapping()) {
|
if (fem.has_mapping()) {
|
||||||
s2_coeff = std::make_unique<mapping::PhysicalPositionFunctionCoefficient>(*fem.mapping, s2_func);
|
s2_coeff = std::make_unique<mapping::PhysicalPositionFunctionCoefficient>(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate, s2_func
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
s2_coeff = std::make_unique<mfem::FunctionCoefficient>(s2_func);
|
s2_coeff = std::make_unique<mfem::FunctionCoefficient>(s2_func);
|
||||||
}
|
}
|
||||||
@@ -164,12 +198,15 @@ namespace mean_field::analysis {
|
|||||||
const mfem::IntegrationRule &integration_rule = get_density_rule<field::Density::Form::Quadrupole>(
|
const mfem::IntegrationRule &integration_rule = get_density_rule<field::Density::Form::Quadrupole>(
|
||||||
fem, representative_transformation, std::array<int, 1>{2}, utils::DOMAINS::STELLAR
|
fem, representative_transformation, std::array<int, 1>{2}, utils::DOMAINS::STELLAR
|
||||||
);
|
);
|
||||||
mfem::Array<int> stellar_markers;
|
mfem::Array<int> stellar_markers =
|
||||||
populate_element_mask(fem.mesh.get(), utils::DOMAINS::STELLAR, stellar_markers);
|
utils::domain::make_attribute_marker<utils::domain::Stellar, DomainSchema>(*fem.mesh);
|
||||||
|
|
||||||
double local_I = 0.0;
|
double local_I = 0.0;
|
||||||
if (fem.has_mapping()) {
|
if (fem.has_mapping()) {
|
||||||
mapping::MappedScalarCoefficient mapped_integrand(*fem.mapping, I_integrand);
|
mapping::MappedScalarCoefficient mapped_integrand(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate, I_integrand
|
||||||
|
);
|
||||||
auto *integrator = new mfem::DomainLFIntegrator(mapped_integrand);
|
auto *integrator = new mfem::DomainLFIntegrator(mapped_integrand);
|
||||||
integrator->SetIntRule(&integration_rule);
|
integrator->SetIntRule(&integration_rule);
|
||||||
I_lf.AddDomainIntegrator(integrator, stellar_markers);
|
I_lf.AddDomainIntegrator(integrator, stellar_markers);
|
||||||
@@ -201,23 +238,21 @@ namespace mean_field::analysis {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double local_volume = 0.0;
|
double local_volume = 0.0;
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate
|
||||||
|
);
|
||||||
|
|
||||||
for (int e = 0; e < mesh.GetNE(); ++e) {
|
for (int e = 0; e < mesh.GetNE(); ++e) {
|
||||||
const int attr = mesh.GetAttribute(e);
|
const int attr = mesh.GetAttribute(e);
|
||||||
switch (domain) {
|
const bool selected =
|
||||||
case utils::DOMAINS::ALL:
|
domain == utils::DOMAINS::ALL ||
|
||||||
break;
|
(domain == utils::DOMAINS::STELLAR &&
|
||||||
case utils::DOMAINS::STELLAR:
|
DomainSchema::template attribute_belongs_to<utils::domain::Stellar>(attr)) ||
|
||||||
if (attr == 3)
|
(domain == utils::DOMAINS::VACUUM &&
|
||||||
|
DomainSchema::template attribute_belongs_to<utils::domain::Vacuum>(attr));
|
||||||
|
if (!selected)
|
||||||
continue;
|
continue;
|
||||||
break;
|
|
||||||
case utils::DOMAINS::VACUUM:
|
|
||||||
if (attr != 3)
|
|
||||||
continue;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MFEM_ABORT("Unsupported domain type for volume computation.");
|
|
||||||
}
|
|
||||||
mfem::ElementTransformation *T = mesh.GetElementTransformation(e);
|
mfem::ElementTransformation *T = mesh.GetElementTransformation(e);
|
||||||
const mfem::IntegrationRule &ir =
|
const mfem::IntegrationRule &ir =
|
||||||
get_density_rule<field::Density::Form::MassConservation>(fem, *T, {}, domain);
|
get_density_rule<field::Density::Form::MassConservation>(fem, *T, {}, domain);
|
||||||
@@ -229,7 +264,13 @@ namespace mean_field::analysis {
|
|||||||
double dV = ip.weight * T->Weight();
|
double dV = ip.weight * T->Weight();
|
||||||
|
|
||||||
if (physical) {
|
if (physical) {
|
||||||
dV *= std::fabs(fem.mapping->ComputeDetJ(*T, ip));
|
mapping::VolumeMappingContext context;
|
||||||
|
MFEM_VERIFY(
|
||||||
|
mapping_evaluator.EvaluateVolume(*T, ip, context) ==
|
||||||
|
mapping::MappingStatus::valid,
|
||||||
|
"Mesh-volume integration encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
dV = context.quadrature.weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
local_volume += dV;
|
local_volume += dV;
|
||||||
|
|||||||
@@ -21,11 +21,8 @@ import :utils.misc;
|
|||||||
import :utils.user;
|
import :utils.user;
|
||||||
|
|
||||||
namespace mean_field::fem {
|
namespace mean_field::fem {
|
||||||
FEM setup_fem(
|
FEM setup_fem(const std::string &filename, const utils::Args &args,
|
||||||
const std::string &filename,
|
const int extraRefine) {
|
||||||
const utils::Args &args,
|
|
||||||
const int extraRefine
|
|
||||||
) {
|
|
||||||
FEM fem;
|
FEM fem;
|
||||||
|
|
||||||
using GravityPotential = field::Gravity::Potential;
|
using GravityPotential = field::Gravity::Potential;
|
||||||
@@ -33,6 +30,7 @@ namespace mean_field::fem {
|
|||||||
using DisplacementVector = field::Displacement::Vector;
|
using DisplacementVector = field::Displacement::Vector;
|
||||||
using DensityScalar = field::Density::Scalar;
|
using DensityScalar = field::Density::Scalar;
|
||||||
using EnthalpyScalar = field::Enthalpy::Scalar;
|
using EnthalpyScalar = field::Enthalpy::Scalar;
|
||||||
|
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Section 1: Mesh construction
|
// Section 1: Mesh construction
|
||||||
@@ -47,9 +45,11 @@ namespace mean_field::fem {
|
|||||||
int mpiSize = 1;
|
int mpiSize = 1;
|
||||||
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
MPI_Comm_size(MPI_COMM_WORLD, &mpiSize);
|
||||||
|
|
||||||
const std::unique_ptr<int[]> meshPartitioning(fem.smesh.mesh->GeneratePartitioning(mpiSize, 1));
|
const std::unique_ptr<int[]> meshPartitioning(
|
||||||
|
fem.smesh.mesh->GeneratePartitioning(mpiSize, 1));
|
||||||
|
|
||||||
fem.mesh = std::make_unique<mfem::ParMesh>(MPI_COMM_WORLD, *fem.smesh.mesh, meshPartitioning.get(), 1);
|
fem.mesh = std::make_unique<mfem::ParMesh>(MPI_COMM_WORLD, *fem.smesh.mesh,
|
||||||
|
meshPartitioning.get(), 1);
|
||||||
|
|
||||||
fem.mesh->EnsureNodes();
|
fem.mesh->EnsureNodes();
|
||||||
|
|
||||||
@@ -69,22 +69,22 @@ namespace mean_field::fem {
|
|||||||
throw std::runtime_error("Values for exterior coordinate not set.");
|
throw std::runtime_error("Values for exterior coordinate not set.");
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElementSpace &serialCoordinateSpace = *fem.smesh.exterior_coordinate->space;
|
const mfem::FiniteElementSpace &serialCoordinateSpace =
|
||||||
|
*fem.smesh.exterior_coordinate->space;
|
||||||
|
|
||||||
const mfem::GridFunction &serialCoordinate = *fem.smesh.exterior_coordinate->values;
|
const mfem::GridFunction &serialCoordinate =
|
||||||
|
*fem.smesh.exterior_coordinate->values;
|
||||||
|
|
||||||
if (serialCoordinate.FESpace() != &serialCoordinateSpace) {
|
if (serialCoordinate.FESpace() != &serialCoordinateSpace) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Exterior coordinate values are not associated with the "
|
"Exterior coordinate values are not associated with the "
|
||||||
"supplied finite-element space."
|
"supplied finite-element space.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serialCoordinateSpace.GetMesh() != fem.smesh.mesh.get()) {
|
if (serialCoordinateSpace.GetMesh() != fem.smesh.mesh.get()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Exterior coordinate space is not associated with the "
|
"Exterior coordinate space is not associated with the "
|
||||||
"loaded STROID mesh."
|
"loaded STROID mesh.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (serialCoordinateSpace.GetVDim() != 1) {
|
if (serialCoordinateSpace.GetVDim() != 1) {
|
||||||
@@ -94,29 +94,30 @@ namespace mean_field::fem {
|
|||||||
if (serialCoordinate.Size() != serialCoordinateSpace.GetVSize()) {
|
if (serialCoordinate.Size() != serialCoordinateSpace.GetVSize()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Exterior coordinate value count does not match its "
|
"Exterior coordinate value count does not match its "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int compactificationOrder = serialCoordinateSpace.GetMaxElementOrder();
|
const int compactificationOrder = serialCoordinateSpace.GetMaxElementOrder();
|
||||||
|
|
||||||
const int dimension = fem.mesh->Dimension();
|
const int dimension = fem.mesh->Dimension();
|
||||||
|
|
||||||
fem.compactificationFec = std::make_unique<mfem::H1_FECollection>(compactificationOrder, dimension);
|
fem.compactificationFec =
|
||||||
|
std::make_unique<mfem::H1_FECollection>(compactificationOrder, dimension);
|
||||||
|
|
||||||
fem.compactificationFes =
|
fem.compactificationFes = std::make_unique<mfem::ParFiniteElementSpace>(
|
||||||
std::make_unique<mfem::ParFiniteElementSpace>(fem.mesh.get(), fem.compactificationFec.get());
|
fem.mesh.get(), fem.compactificationFec.get());
|
||||||
|
|
||||||
mfem::ParGridFunction distributedCoordinate(fem.mesh.get(), &serialCoordinate, meshPartitioning.get());
|
mfem::ParGridFunction distributedCoordinate(fem.mesh.get(), &serialCoordinate,
|
||||||
|
meshPartitioning.get());
|
||||||
|
|
||||||
if (distributedCoordinate.Size() != fem.compactificationFes->GetVSize()) {
|
if (distributedCoordinate.Size() != fem.compactificationFes->GetVSize()) {
|
||||||
throw std::runtime_error(
|
throw std::runtime_error(
|
||||||
"Distributed exterior coordinate does not match the "
|
"Distributed exterior coordinate does not match the "
|
||||||
"constructed parallel finite-element space."
|
"constructed parallel finite-element space.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fem.compactificationCoordinate = std::make_unique<mfem::ParGridFunction>(fem.compactificationFes.get());
|
fem.compactificationCoordinate =
|
||||||
|
std::make_unique<mfem::ParGridFunction>(fem.compactificationFes.get());
|
||||||
|
|
||||||
*fem.compactificationCoordinate = distributedCoordinate;
|
*fem.compactificationCoordinate = distributedCoordinate;
|
||||||
|
|
||||||
@@ -128,7 +129,8 @@ namespace mean_field::fem {
|
|||||||
const double value = (*fem.compactificationCoordinate)(index);
|
const double value = (*fem.compactificationCoordinate)(index);
|
||||||
|
|
||||||
if (!std::isfinite(value)) {
|
if (!std::isfinite(value)) {
|
||||||
throw std::runtime_error("Exterior coordinate contains a non-finite value.");
|
throw std::runtime_error(
|
||||||
|
"Exterior coordinate contains a non-finite value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
localMinimum = std::min(localMinimum, value);
|
localMinimum = std::min(localMinimum, value);
|
||||||
@@ -139,17 +141,18 @@ namespace mean_field::fem {
|
|||||||
double globalMinimum = 0.0;
|
double globalMinimum = 0.0;
|
||||||
double globalMaximum = 0.0;
|
double globalMaximum = 0.0;
|
||||||
|
|
||||||
MPI_Allreduce(&localMinimum, &globalMinimum, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD);
|
MPI_Allreduce(&localMinimum, &globalMinimum, 1, MPI_DOUBLE, MPI_MIN,
|
||||||
|
MPI_COMM_WORLD);
|
||||||
|
|
||||||
MPI_Allreduce(&localMaximum, &globalMaximum, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD);
|
MPI_Allreduce(&localMaximum, &globalMaximum, 1, MPI_DOUBLE, MPI_MAX,
|
||||||
|
MPI_COMM_WORLD);
|
||||||
|
|
||||||
constexpr double coordinateTolerance = 1.0e-12;
|
constexpr double coordinateTolerance = 1.0e-12;
|
||||||
|
|
||||||
if (globalMinimum < -coordinateTolerance || globalMaximum > 1.0 + coordinateTolerance) {
|
if (globalMinimum < -coordinateTolerance ||
|
||||||
throw std::runtime_error(
|
globalMaximum > 1.0 + coordinateTolerance) {
|
||||||
"Exterior coordinate lies outside the expected "
|
throw std::runtime_error("Exterior coordinate lies outside the expected "
|
||||||
"interval [0, 1]."
|
"interval [0, 1].");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
@@ -162,7 +165,8 @@ namespace mean_field::fem {
|
|||||||
|
|
||||||
fem.gravityPotentialFec = GravityField::make_fec<GravityPotential>(dimension);
|
fem.gravityPotentialFec = GravityField::make_fec<GravityPotential>(dimension);
|
||||||
|
|
||||||
fem.gravityPotentialFes = GravityField::make_fespace<GravityPotential>(*fem.mesh, *fem.gravityPotentialFec);
|
fem.gravityPotentialFes = GravityField::make_fespace<GravityPotential>(
|
||||||
|
*fem.mesh, *fem.gravityPotentialFec);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Gravity flux: H(div)/RT. Basis choices are encoded by field.mfem.
|
// Gravity flux: H(div)/RT. Basis choices are encoded by field.mfem.
|
||||||
@@ -170,17 +174,21 @@ namespace mean_field::fem {
|
|||||||
|
|
||||||
fem.gravityFluxFec = GravityField::make_fec<GravityFlux>(dimension);
|
fem.gravityFluxFec = GravityField::make_fec<GravityFlux>(dimension);
|
||||||
|
|
||||||
fem.gravityFluxFes = GravityField::make_fespace<GravityFlux>(*fem.mesh, *fem.gravityFluxFec);
|
fem.gravityFluxFes =
|
||||||
|
GravityField::make_fespace<GravityFlux>(*fem.mesh, *fem.gravityFluxFec);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Displacement: vector H1. Ordering is encoded by field.mfem.
|
// Displacement: vector H1. Ordering is encoded by field.mfem.
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
fem.displacementFec = DisplacementField::make_fec<DisplacementVector>(dimension);
|
fem.displacementFec =
|
||||||
|
DisplacementField::make_fec<DisplacementVector>(dimension);
|
||||||
|
|
||||||
fem.displacementFes = DisplacementField::make_fespace<DisplacementVector>(*fem.mesh, *fem.displacementFec);
|
fem.displacementFes = DisplacementField::make_fespace<DisplacementVector>(
|
||||||
|
*fem.mesh, *fem.displacementFec);
|
||||||
|
|
||||||
fem.displacement = std::make_unique<mfem::ParGridFunction>(fem.displacementFes.get());
|
fem.displacement =
|
||||||
|
std::make_unique<mfem::ParGridFunction>(fem.displacementFes.get());
|
||||||
|
|
||||||
*fem.displacement = 0.0;
|
*fem.displacement = 0.0;
|
||||||
|
|
||||||
@@ -190,7 +198,8 @@ namespace mean_field::fem {
|
|||||||
|
|
||||||
fem.densityFec = DensityField::make_fec<DensityScalar>(dimension);
|
fem.densityFec = DensityField::make_fec<DensityScalar>(dimension);
|
||||||
|
|
||||||
fem.densityFes = DensityField::make_fespace<DensityScalar>(*fem.mesh, *fem.densityFec);
|
fem.densityFes =
|
||||||
|
DensityField::make_fespace<DensityScalar>(*fem.mesh, *fem.densityFec);
|
||||||
|
|
||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
// Specific enthalpy: scalar continuous H1
|
// Specific enthalpy: scalar continuous H1
|
||||||
@@ -198,50 +207,11 @@ namespace mean_field::fem {
|
|||||||
|
|
||||||
fem.enthalpyFec = EnthalpyField::make_fec<EnthalpyScalar>(dimension);
|
fem.enthalpyFec = EnthalpyField::make_fec<EnthalpyScalar>(dimension);
|
||||||
|
|
||||||
fem.enthalpyFes = EnthalpyField::make_fespace<EnthalpyScalar>(*fem.mesh, *fem.enthalpyFec);
|
fem.enthalpyFes =
|
||||||
|
EnthalpyField::make_fespace<EnthalpyScalar>(*fem.mesh, *fem.enthalpyFec);
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Section 4: Domain mapping
|
// Section 4: Multipole data
|
||||||
// =====================================================================
|
|
||||||
|
|
||||||
auto [stellarRadiusReference, infinityRadiusReference] =
|
|
||||||
utils::discover_bounds(fem.mesh.get(), 3)
|
|
||||||
.or_else([](const boundary::BoundsError &) -> std::expected<boundary::Bounds, boundary::BoundsError> {
|
|
||||||
throw std::runtime_error(
|
|
||||||
"Unable to determine vacuum-domain reference "
|
|
||||||
"boundaries."
|
|
||||||
);
|
|
||||||
})
|
|
||||||
.value();
|
|
||||||
|
|
||||||
fem.mapping =
|
|
||||||
std::make_unique<mapping::DomainMapper>(*fem.displacement, stellarRadiusReference, infinityRadiusReference);
|
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
// Section 5: Block offsets
|
|
||||||
//
|
|
||||||
// Legacy layouts only. New coupled operators use :utils.blocks forms.
|
|
||||||
//
|
|
||||||
// Main system: [Displacement | Density]
|
|
||||||
// Gravity system: [Flux | Potential]
|
|
||||||
// =====================================================================
|
|
||||||
|
|
||||||
fem.blockTrueOffsets.SetSize(3);
|
|
||||||
fem.blockTrueOffsets[0] = 0;
|
|
||||||
|
|
||||||
fem.blockTrueOffsets[1] = fem.displacementFes->GetTrueVSize();
|
|
||||||
|
|
||||||
fem.blockTrueOffsets[2] = fem.blockTrueOffsets[1] + fem.densityFes->GetTrueVSize();
|
|
||||||
|
|
||||||
fem.gravityBlockTrueOffsets.SetSize(3);
|
|
||||||
fem.gravityBlockTrueOffsets[0] = 0;
|
|
||||||
|
|
||||||
fem.gravityBlockTrueOffsets[1] = fem.gravityFluxFes->GetTrueVSize();
|
|
||||||
|
|
||||||
fem.gravityBlockTrueOffsets[2] = fem.gravityBlockTrueOffsets[1] + fem.gravityPotentialFes->GetTrueVSize();
|
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
// Section 6: Multipole data
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
fem.com.SetSize(dimension);
|
fem.com.SetSize(dimension);
|
||||||
@@ -251,13 +221,9 @@ namespace mean_field::fem {
|
|||||||
fem.Q = 0.0;
|
fem.Q = 0.0;
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Section 7: Essential boundaries and domain masks
|
// Section 5: Boundary markers
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
fem.essentialDisplacementTdofs.SetSize(0);
|
|
||||||
|
|
||||||
populate_element_mask(fem.mesh.get(), utils::DOMAINS::STELLAR, fem.gravityContext.stellar_mask);
|
|
||||||
|
|
||||||
const int boundaryAttributeCount = fem.mesh->bdr_attributes.Max();
|
const int boundaryAttributeCount = fem.mesh->bdr_attributes.Max();
|
||||||
|
|
||||||
fem.boundaryContext.inf_bounds.SetSize(boundaryAttributeCount);
|
fem.boundaryContext.inf_bounds.SetSize(boundaryAttributeCount);
|
||||||
@@ -267,76 +233,47 @@ namespace mean_field::fem {
|
|||||||
fem.boundaryContext.inf_bounds = 0;
|
fem.boundaryContext.inf_bounds = 0;
|
||||||
fem.boundaryContext.stellar_bounds = 0;
|
fem.boundaryContext.stellar_bounds = 0;
|
||||||
|
|
||||||
fem.boundaryContext.inf_bounds[static_cast<int>(boundary::Boundaries::INF_SURFACE) - 1] = 1;
|
fem.boundaryContext
|
||||||
|
.inf_bounds[static_cast<int>(boundary::Boundaries::INF_SURFACE) - 1] = 1;
|
||||||
|
|
||||||
fem.boundaryContext.stellar_bounds[static_cast<int>(boundary::Boundaries::STELLAR_SURFACE) - 1] = 1;
|
fem.boundaryContext
|
||||||
|
.stellar_bounds[static_cast<int>(boundary::Boundaries::STELLAR_SURFACE) -
|
||||||
|
1] = 1;
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Section 8: Gravity solver context
|
// Section 7: Quadrature policy
|
||||||
// =====================================================================
|
|
||||||
|
|
||||||
fem.gravityContext.minres = std::make_unique<mfem::MINRESSolver>(fem.mesh->GetComm());
|
|
||||||
|
|
||||||
fem.gravityContext.minres->SetRelTol(1.0e-12);
|
|
||||||
fem.gravityContext.minres->SetAbsTol(1.0e-12);
|
|
||||||
fem.gravityContext.minres->SetMaxIter(1000);
|
|
||||||
fem.gravityContext.minres->SetPrintLevel(0);
|
|
||||||
|
|
||||||
fem.gravityContext.prec_Phi = std::make_unique<mfem::HypreBoomerAMG>();
|
|
||||||
|
|
||||||
fem.gravityContext.prec_Phi->SetPrintLevel(0);
|
|
||||||
|
|
||||||
fem.gravityContext.block_prec =
|
|
||||||
std::make_unique<mfem::BlockDiagonalPreconditioner>(fem.gravityBlockTrueOffsets);
|
|
||||||
|
|
||||||
fem.gravityContext.minres->SetPreconditioner(*fem.gravityContext.block_prec);
|
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
// Section 9: Vacuum true-DOF masks
|
|
||||||
// =====================================================================
|
|
||||||
|
|
||||||
{
|
|
||||||
mfem::Array<int> vacuumMask;
|
|
||||||
|
|
||||||
utils::populate_element_mask(fem.mesh.get(), utils::DOMAINS::VACUUM, vacuumMask);
|
|
||||||
|
|
||||||
utils::populate_domain_tdofs(fem.displacementFes.get(), vacuumMask, fem.vacuumDisplacementTdofs);
|
|
||||||
|
|
||||||
utils::populate_domain_tdofs(fem.densityFes.get(), vacuumMask, fem.vacuumDensityTdofs);
|
|
||||||
|
|
||||||
utils::populate_domain_tdofs(fem.enthalpyFes.get(), vacuumMask, fem.vacuumEnthalpyTdofs);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
// Section 10: Quadrature policy
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
const quadrature::QuadratureOptions &quadratureOptions = args.quadrature;
|
const quadrature::QuadratureOptions &quadratureOptions = args.quadrature;
|
||||||
|
|
||||||
if (quadratureOptions.validation.reject_negative_boosts && quadratureOptions.global_boost < 0) {
|
if (quadratureOptions.validation.reject_negative_boosts &&
|
||||||
|
quadratureOptions.global_boost < 0) {
|
||||||
throw std::invalid_argument("Global quadrature boost cannot be negative.");
|
throw std::invalid_argument("Global quadrature boost cannot be negative.");
|
||||||
}
|
}
|
||||||
|
|
||||||
quadrature::RuleSet quadratureRuleSet =
|
quadrature::RuleSet quadratureRuleSet = quadrature::make_rule_set(
|
||||||
quadrature::make_rule_set(quadratureOptions.mode, quadratureOptions.global_boost);
|
quadratureOptions.mode, quadratureOptions.global_boost);
|
||||||
|
|
||||||
if (quadratureOptions.fallback_fixed_order.has_value()) {
|
if (quadratureOptions.fallback_fixed_order.has_value()) {
|
||||||
if (*quadratureOptions.fallback_fixed_order < 0) {
|
if (*quadratureOptions.fallback_fixed_order < 0) {
|
||||||
throw std::invalid_argument("Fallback quadrature order cannot be negative.");
|
throw std::invalid_argument(
|
||||||
|
"Fallback quadrature order cannot be negative.");
|
||||||
}
|
}
|
||||||
|
|
||||||
quadratureRuleSet.fallback.fixed_order = quadratureOptions.fallback_fixed_order;
|
quadratureRuleSet.fallback.fixed_order =
|
||||||
|
quadratureOptions.fallback_fixed_order;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto apply_quadrature_options = [&quadratureOptions](
|
auto apply_quadrature_options = [&quadratureOptions](
|
||||||
quadrature::RuleControl &ruleControl,
|
quadrature::RuleControl &ruleControl,
|
||||||
const quadrature::QuadratureTermOptions &termOptions
|
const quadrature::QuadratureTermOptions
|
||||||
) {
|
&termOptions) {
|
||||||
if (termOptions.fixed_order.has_value() && *termOptions.fixed_order < 0) {
|
if (termOptions.fixed_order.has_value() && *termOptions.fixed_order < 0) {
|
||||||
throw std::invalid_argument("Fixed quadrature order cannot be negative.");
|
throw std::invalid_argument("Fixed quadrature order cannot be negative.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quadratureOptions.validation.reject_negative_boosts && termOptions.additional_boost < 0) {
|
if (quadratureOptions.validation.reject_negative_boosts &&
|
||||||
|
termOptions.additional_boost < 0) {
|
||||||
throw std::invalid_argument("Term quadrature boost cannot be negative.");
|
throw std::invalid_argument("Term quadrature boost cannot be negative.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -347,66 +284,97 @@ namespace mean_field::fem {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.gravity_hdiv_mass, quadratureOptions.gravity_hdiv_mass);
|
apply_quadrature_options(quadratureRuleSet.gravity_hdiv_mass,
|
||||||
|
quadratureOptions.gravity_hdiv_mass);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.gravity_divergence, quadratureOptions.gravity_divergence);
|
apply_quadrature_options(quadratureRuleSet.gravity_divergence,
|
||||||
|
quadratureOptions.gravity_divergence);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.gravity_source, quadratureOptions.gravity_source);
|
apply_quadrature_options(quadratureRuleSet.gravity_source,
|
||||||
|
quadratureOptions.gravity_source);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.gravity_force, quadratureOptions.gravity_force);
|
apply_quadrature_options(quadratureRuleSet.gravity_force,
|
||||||
|
quadratureOptions.gravity_force);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.gravity_boundary, quadratureOptions.gravity_boundary);
|
apply_quadrature_options(quadratureRuleSet.gravity_boundary,
|
||||||
|
quadratureOptions.gravity_boundary);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.centrifugal, quadratureOptions.centrifugal);
|
apply_quadrature_options(quadratureRuleSet.centrifugal,
|
||||||
|
quadratureOptions.centrifugal);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.density_projection, quadratureOptions.density_projection);
|
apply_quadrature_options(quadratureRuleSet.density_projection,
|
||||||
|
quadratureOptions.density_projection);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.eos_closure, quadratureOptions.eos_closure);
|
apply_quadrature_options(quadratureRuleSet.eos_closure,
|
||||||
|
quadratureOptions.eos_closure);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.hydrostatic_equilibrium, quadratureOptions.hydrostatic_equilibrium);
|
apply_quadrature_options(quadratureRuleSet.hydrostatic_equilibrium,
|
||||||
|
quadratureOptions.hydrostatic_equilibrium);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.isobaric_surface, quadratureOptions.isobaric_surface);
|
apply_quadrature_options(quadratureRuleSet.isobaric_surface,
|
||||||
|
quadratureOptions.isobaric_surface);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.mesh_extension, quadratureOptions.mesh_extension);
|
apply_quadrature_options(quadratureRuleSet.mesh_extension,
|
||||||
|
quadratureOptions.mesh_extension);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.mass_conservation, quadratureOptions.mass_conservation);
|
apply_quadrature_options(quadratureRuleSet.mass_conservation,
|
||||||
|
quadratureOptions.mass_conservation);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.mass_normalization, quadratureOptions.mass_normalization);
|
apply_quadrature_options(quadratureRuleSet.mass_normalization,
|
||||||
|
quadratureOptions.mass_normalization);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.center_of_mass, quadratureOptions.center_of_mass);
|
apply_quadrature_options(quadratureRuleSet.center_of_mass,
|
||||||
|
quadratureOptions.center_of_mass);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.quadrupole, quadratureOptions.quadrupole);
|
apply_quadrature_options(quadratureRuleSet.quadrupole,
|
||||||
|
quadratureOptions.quadrupole);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.gravitational_energy, quadratureOptions.gravitational_energy);
|
apply_quadrature_options(quadratureRuleSet.gravitational_energy,
|
||||||
|
quadratureOptions.gravitational_energy);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.pressure_integral, quadratureOptions.pressure_integral);
|
apply_quadrature_options(quadratureRuleSet.pressure_integral,
|
||||||
|
quadratureOptions.pressure_integral);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.pressure_force, quadratureOptions.pressure_force);
|
apply_quadrature_options(quadratureRuleSet.pressure_force,
|
||||||
|
quadratureOptions.pressure_force);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.virial, quadratureOptions.virial);
|
apply_quadrature_options(quadratureRuleSet.virial, quadratureOptions.virial);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.error_norm, quadratureOptions.error_norm);
|
apply_quadrature_options(quadratureRuleSet.error_norm,
|
||||||
|
quadratureOptions.error_norm);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.roles.discretization, quadratureOptions.roles.discretization);
|
apply_quadrature_options(quadratureRuleSet.roles.discretization,
|
||||||
|
quadratureOptions.roles.discretization);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.roles.preconditioner, quadratureOptions.roles.preconditioner);
|
apply_quadrature_options(quadratureRuleSet.roles.preconditioner,
|
||||||
|
quadratureOptions.roles.preconditioner);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.roles.diagnostic, quadratureOptions.roles.diagnostic);
|
apply_quadrature_options(quadratureRuleSet.roles.diagnostic,
|
||||||
|
quadratureOptions.roles.diagnostic);
|
||||||
|
|
||||||
apply_quadrature_options(quadratureRuleSet.roles.projection, quadratureOptions.roles.projection);
|
apply_quadrature_options(quadratureRuleSet.roles.projection,
|
||||||
|
quadratureOptions.roles.projection);
|
||||||
|
|
||||||
fem.quadratureFactory =
|
fem.quadratureFactory = std::make_unique<quadrature::RuleFactory>(
|
||||||
std::make_unique<quadrature::RuleFactory>(quadrature::Policy(std::move(quadratureRuleSet)));
|
quadrature::Policy(std::move(quadratureRuleSet)));
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Section 11: Stateless domain mapper
|
// Section 11: Stateless domain mapper
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
auto exteriorDomain =
|
auto exteriorDomain =
|
||||||
std::make_unique<const mapping::compactification::KelvinCompactification>(args.kelvin_options);
|
std::make_unique<const mapping::compactification::KelvinCompactification>(
|
||||||
|
args.kelvin_options);
|
||||||
|
|
||||||
fem.domainMapperStateless =
|
MFEM_VERIFY(
|
||||||
std::make_unique<mapping::DomainMapperStateless>(args.domain_mapper_options, std::move(exteriorDomain));
|
args.domain_mapper_options.vacuum_element_attribute ==
|
||||||
|
DomainSchema::template material_attribute<utils::domain::Vacuum>(),
|
||||||
|
"The domain-mapper compactification attribute must match the vacuum "
|
||||||
|
"material registered by the "
|
||||||
|
"production domain schema.");
|
||||||
|
|
||||||
|
fem.domainMapperStateless = std::make_unique<mapping::DomainMapper>(
|
||||||
|
args.domain_mapper_options, std::move(exteriorDomain));
|
||||||
|
|
||||||
return fem;
|
return fem;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,12 @@ module;
|
|||||||
module mean_field;
|
module mean_field;
|
||||||
|
|
||||||
namespace mean_field::integrators {
|
namespace mean_field::integrators {
|
||||||
AdvectionIntegrator::AdvectionIntegrator(const mapping::DomainMapper &map) : m_map(map) {
|
AdvectionIntegrator::AdvectionIntegrator(
|
||||||
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate
|
||||||
|
)
|
||||||
|
: m_mapping(mapper, displacement, compactification_coordinate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void AdvectionIntegrator::AssembleElementVector(
|
void AdvectionIntegrator::AssembleElementVector(
|
||||||
@@ -13,6 +18,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvec
|
const mfem::Array<mfem::Vector *> &elvec
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elvec)) {
|
if (utils::is_vacuum(Tr, elvec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -44,7 +51,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||||
@@ -93,6 +100,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
const mfem::FiniteElement *fe_v = el[0];
|
const mfem::FiniteElement *fe_v = el[0];
|
||||||
const mfem::FiniteElement *fe_rho = el[1];
|
const mfem::FiniteElement *fe_rho = el[1];
|
||||||
|
|
||||||
@@ -120,7 +129,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||||
|
|||||||
@@ -4,10 +4,12 @@ module mean_field;
|
|||||||
|
|
||||||
namespace mean_field::integrators {
|
namespace mean_field::integrators {
|
||||||
CentrifugalForceIntegrator::CentrifugalForceIntegrator(
|
CentrifugalForceIntegrator::CentrifugalForceIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const mfem::Vector &omega
|
const mfem::Vector &omega
|
||||||
)
|
)
|
||||||
: m_map(map),
|
: m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_omega(3) {
|
m_omega(3) {
|
||||||
MFEM_ASSERT(omega.Size() == 3, "Omega vector must be 3D");
|
MFEM_ASSERT(omega.Size() == 3, "Omega vector must be 3D");
|
||||||
m_omega = omega;
|
m_omega = omega;
|
||||||
@@ -28,6 +30,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvec
|
const mfem::Array<mfem::Vector *> &elvec
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elvec)) {
|
if (utils::is_vacuum(Tr, elvec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -64,12 +68,12 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_rho->CalcShape(ip, shape_rho);
|
fe_rho->CalcShape(ip, shape_rho);
|
||||||
|
|
||||||
m_map.GetPhysicalPoint(Tr, ip, x_phys);
|
m_mapping.GetPhysicalPoint(Tr, ip, x_phys);
|
||||||
|
|
||||||
// ω x r
|
// ω x r
|
||||||
a(0) = m_omega(1) * x_phys(2) - m_omega(2) * x_phys(1);
|
a(0) = m_omega(1) * x_phys(2) - m_omega(2) * x_phys(1);
|
||||||
@@ -100,6 +104,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elmats)) {
|
if (utils::is_vacuum(Tr, elmats)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -134,12 +140,12 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_rho->CalcShape(ip, shape_rho);
|
fe_rho->CalcShape(ip, shape_rho);
|
||||||
|
|
||||||
m_map.GetPhysicalPoint(Tr, ip, x_phys);
|
m_mapping.GetPhysicalPoint(Tr, ip, x_phys);
|
||||||
|
|
||||||
// ω x r
|
// ω x r
|
||||||
a(0) = m_omega(1) * x_phys(2) - m_omega(2) * x_phys(1);
|
a(0) = m_omega(1) * x_phys(2) - m_omega(2) * x_phys(1);
|
||||||
|
|||||||
@@ -5,10 +5,12 @@ module mean_field;
|
|||||||
|
|
||||||
namespace mean_field::integrators {
|
namespace mean_field::integrators {
|
||||||
CoriolisIntegrator::CoriolisIntegrator(
|
CoriolisIntegrator::CoriolisIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const mfem::Vector &omega
|
const mfem::Vector &omega
|
||||||
)
|
)
|
||||||
: m_map(map),
|
: m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_omega(omega) {
|
m_omega(omega) {
|
||||||
m_omega_mat.SetSize(3, 3);
|
m_omega_mat.SetSize(3, 3);
|
||||||
m_omega_mat = 0.0;
|
m_omega_mat = 0.0;
|
||||||
@@ -26,6 +28,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvec
|
const mfem::Array<mfem::Vector *> &elvec
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elvec)) {
|
if (utils::is_vacuum(Tr, elvec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -55,7 +59,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_rho->CalcShape(ip, shape_rho);
|
fe_rho->CalcShape(ip, shape_rho);
|
||||||
@@ -89,6 +93,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
const mfem::FiniteElement *fe_v = el[0];
|
const mfem::FiniteElement *fe_v = el[0];
|
||||||
const mfem::FiniteElement *fe_rho = el[1];
|
const mfem::FiniteElement *fe_rho = el[1];
|
||||||
@@ -115,7 +120,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_rho->CalcShape(ip, shape_rho);
|
fe_rho->CalcShape(ip, shape_rho);
|
||||||
|
|||||||
@@ -14,10 +14,12 @@ namespace {
|
|||||||
|
|
||||||
namespace mean_field::integrators {
|
namespace mean_field::integrators {
|
||||||
GravityMomentumIntegrator::GravityMomentumIntegrator(
|
GravityMomentumIntegrator::GravityMomentumIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const GravityForceJacobianMode jacobian_mode
|
const GravityForceJacobianMode jacobian_mode
|
||||||
)
|
)
|
||||||
: m_map(map),
|
: m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_jacobian_mode(jacobian_mode) {
|
m_jacobian_mode(jacobian_mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,6 +41,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvec
|
const mfem::Array<mfem::Vector *> &elvec
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elvec)) {
|
if (utils::is_vacuum(Tr, elvec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -123,7 +127,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &integration_point = integration_rule.IntPoint(q);
|
const mfem::IntegrationPoint &integration_point = integration_rule.IntPoint(q);
|
||||||
Tr.SetIntPoint(&integration_point);
|
Tr.SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const mapping::VolumeQuadratureContext context = m_map.GetQuadratureContext(Tr, integration_point);
|
const mapping::VolumeQuadratureContext context = m_mapping.GetQuadratureContext(Tr, integration_point);
|
||||||
|
|
||||||
velocity_element->CalcShape(integration_point, velocity_shape);
|
velocity_element->CalcShape(integration_point, velocity_shape);
|
||||||
density_element->CalcShape(integration_point, density_shape);
|
density_element->CalcShape(integration_point, density_shape);
|
||||||
@@ -152,6 +156,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elmats)) {
|
if (utils::is_vacuum(Tr, elmats)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -189,8 +195,8 @@ namespace mean_field::integrators {
|
|||||||
MFEM_ABORT(
|
MFEM_ABORT(
|
||||||
"Exact GravityForceIntegrator geometry Jacobian is unavailable "
|
"Exact GravityForceIntegrator geometry Jacobian is unavailable "
|
||||||
"until "
|
"until "
|
||||||
"DomainMapper linearization is "
|
"the stateless mapping variation is wired into this legacy "
|
||||||
"implemented."
|
"integrator."
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -240,7 +246,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &integration_point = integration_rule.IntPoint(q);
|
const mfem::IntegrationPoint &integration_point = integration_rule.IntPoint(q);
|
||||||
Tr.SetIntPoint(&integration_point);
|
Tr.SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const mapping::VolumeQuadratureContext context = m_map.GetQuadratureContext(Tr, integration_point);
|
const mapping::VolumeQuadratureContext context = m_mapping.GetQuadratureContext(Tr, integration_point);
|
||||||
|
|
||||||
velocity_element->CalcShape(integration_point, velocity_shape);
|
velocity_element->CalcShape(integration_point, velocity_shape);
|
||||||
density_element->CalcShape(integration_point, density_shape);
|
density_element->CalcShape(integration_point, density_shape);
|
||||||
|
|||||||
@@ -4,7 +4,12 @@ module;
|
|||||||
module mean_field;
|
module mean_field;
|
||||||
|
|
||||||
namespace mean_field::integrators {
|
namespace mean_field::integrators {
|
||||||
ContinuityVolumeIntegrator::ContinuityVolumeIntegrator(const mapping::DomainMapper &map) : m_map(map) { };
|
ContinuityVolumeIntegrator::ContinuityVolumeIntegrator(
|
||||||
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate
|
||||||
|
)
|
||||||
|
: m_mapping(mapper, displacement, compactification_coordinate) { };
|
||||||
|
|
||||||
void ContinuityVolumeIntegrator::AssembleElementVector(
|
void ContinuityVolumeIntegrator::AssembleElementVector(
|
||||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||||
@@ -12,6 +17,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvec
|
const mfem::Array<mfem::Vector *> &elvec
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elvec)) {
|
if (utils::is_vacuum(Tr, elvec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -46,7 +53,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_rho->CalcShape(ip, shape_rho);
|
fe_rho->CalcShape(ip, shape_rho);
|
||||||
@@ -82,6 +89,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
const mfem::FiniteElement *fe_v = el[0];
|
const mfem::FiniteElement *fe_v = el[0];
|
||||||
const mfem::FiniteElement *fe_rho = el[1];
|
const mfem::FiniteElement *fe_rho = el[1];
|
||||||
@@ -115,7 +123,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcShape(ip, shape_v);
|
fe_v->CalcShape(ip, shape_v);
|
||||||
fe_rho->CalcShape(ip, shape_rho);
|
fe_rho->CalcShape(ip, shape_rho);
|
||||||
@@ -161,7 +169,12 @@ namespace mean_field::integrators {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ContinuityFaceIntegrator::ContinuityFaceIntegrator(const mapping::DomainMapper &map) : m_map(map) {
|
ContinuityFaceIntegrator::ContinuityFaceIntegrator(
|
||||||
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate
|
||||||
|
)
|
||||||
|
: m_mapping(mapper, displacement, compactification_coordinate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContinuityFaceIntegrator::AssembleFaceVector(
|
void ContinuityFaceIntegrator::AssembleFaceVector(
|
||||||
@@ -171,6 +184,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvect
|
const mfem::Array<mfem::Vector *> &elvect
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
const mfem::FiniteElement *fe_v_minus = el1[0];
|
const mfem::FiniteElement *fe_v_minus = el1[0];
|
||||||
const mfem::FiniteElement *fe_v_plus = el2[0];
|
const mfem::FiniteElement *fe_v_plus = el2[0];
|
||||||
|
|
||||||
@@ -195,9 +210,9 @@ namespace mean_field::integrators {
|
|||||||
|
|
||||||
const int attr_minus = Tr.Elem1->Attribute;
|
const int attr_minus = Tr.Elem1->Attribute;
|
||||||
const int attr_plus = (Tr.Elem2 != nullptr) ? Tr.Elem2->Attribute : -1;
|
const int attr_plus = (Tr.Elem2 != nullptr) ? Tr.Elem2->Attribute : -1;
|
||||||
constexpr int VACUUM_ATTR = 3;
|
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
if (DomainSchema::template attribute_belongs_to<utils::domain::Vacuum>(attr_minus) ||
|
||||||
if (attr_minus == VACUUM_ATTR || attr_plus == VACUUM_ATTR) {
|
DomainSchema::template attribute_belongs_to<utils::domain::Vacuum>(attr_plus)) {
|
||||||
return; // No flux contribution for vacuum faces
|
return; // No flux contribution for vacuum faces
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -228,7 +243,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip_minus = Tr.GetElement1IntPoint();
|
const mfem::IntegrationPoint &ip_minus = Tr.GetElement1IntPoint();
|
||||||
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
|
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
|
||||||
|
|
||||||
auto [n_unit, ds, v_dot_n_scale] = m_map.GetFaceQuadratureContext(Tr, face_ip);
|
auto [n_unit, ds, v_dot_n_scale] = m_mapping.GetFaceQuadratureContext(Tr, face_ip);
|
||||||
|
|
||||||
fe_v_minus->CalcShape(ip_minus, shape_v_minus);
|
fe_v_minus->CalcShape(ip_minus, shape_v_minus);
|
||||||
fe_rho_minus->CalcShape(ip_minus, shape_rho_minus);
|
fe_rho_minus->CalcShape(ip_minus, shape_rho_minus);
|
||||||
@@ -281,6 +296,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
const mfem::FiniteElement *fe_v_minus = el1[0];
|
const mfem::FiniteElement *fe_v_minus = el1[0];
|
||||||
const mfem::FiniteElement *fe_v_plus = el2[0];
|
const mfem::FiniteElement *fe_v_plus = el2[0];
|
||||||
const mfem::FiniteElement *fe_rho_minus = el1[1];
|
const mfem::FiniteElement *fe_rho_minus = el1[1];
|
||||||
@@ -330,7 +347,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip_minus = Tr.GetElement1IntPoint();
|
const mfem::IntegrationPoint &ip_minus = Tr.GetElement1IntPoint();
|
||||||
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
|
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
|
||||||
|
|
||||||
auto [n_unit, ds, v_dot_n_scale] = m_map.GetFaceQuadratureContext(Tr, face_ip);
|
auto [n_unit, ds, v_dot_n_scale] = m_mapping.GetFaceQuadratureContext(Tr, face_ip);
|
||||||
|
|
||||||
fe_v_minus->CalcShape(ip_minus, shape_v_minus);
|
fe_v_minus->CalcShape(ip_minus, shape_v_minus);
|
||||||
fe_rho_minus->CalcShape(ip_minus, shape_rho_minus);
|
fe_rho_minus->CalcShape(ip_minus, shape_rho_minus);
|
||||||
@@ -399,10 +416,11 @@ namespace mean_field::integrators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool ContinuityFaceIntegrator::skip_face(const mfem::FaceElementTransformations &Tr) {
|
bool ContinuityFaceIntegrator::skip_face(const mfem::FaceElementTransformations &Tr) {
|
||||||
constexpr int VACUUM_ATTR = 3;
|
|
||||||
const int attr_minus = Tr.Elem1->Attribute;
|
const int attr_minus = Tr.Elem1->Attribute;
|
||||||
const int attr_plus = (Tr.Elem2 != nullptr) ? Tr.Elem2->Attribute : -1;
|
const int attr_plus = (Tr.Elem2 != nullptr) ? Tr.Elem2->Attribute : -1;
|
||||||
if (attr_minus == VACUUM_ATTR || attr_plus == VACUUM_ATTR) {
|
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
if (DomainSchema::template attribute_belongs_to<utils::domain::Vacuum>(attr_minus) ||
|
||||||
|
DomainSchema::template attribute_belongs_to<utils::domain::Vacuum>(attr_plus)) {
|
||||||
return true; // No flux contribution for vacuum faces
|
return true; // No flux contribution for vacuum faces
|
||||||
}
|
}
|
||||||
if (Tr.Elem2 == nullptr) {
|
if (Tr.Elem2 == nullptr) {
|
||||||
|
|||||||
@@ -4,11 +4,13 @@ module mean_field;
|
|||||||
|
|
||||||
namespace mean_field::integrators {
|
namespace mean_field::integrators {
|
||||||
ViscosityIntegrator::ViscosityIntegrator(
|
ViscosityIntegrator::ViscosityIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const double mu,
|
const double mu,
|
||||||
const int quad_boost
|
const int quad_boost
|
||||||
)
|
)
|
||||||
: m_map(map),
|
: m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_mu(mu),
|
m_mu(mu),
|
||||||
m_quad_boost(quad_boost) {
|
m_quad_boost(quad_boost) {
|
||||||
}
|
}
|
||||||
@@ -23,6 +25,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvec
|
const mfem::Array<mfem::Vector *> &elvec
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elvec)) {
|
if (utils::is_vacuum(Tr, elvec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -56,7 +60,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||||
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
||||||
@@ -102,6 +106,8 @@ namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
const mfem::FiniteElement *fe_v = el[0];
|
const mfem::FiniteElement *fe_v = el[0];
|
||||||
const mfem::FiniteElement *fe_rho = el[1];
|
const mfem::FiniteElement *fe_rho = el[1];
|
||||||
|
|
||||||
@@ -130,7 +136,7 @@ namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||||
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
||||||
|
|||||||
@@ -9,11 +9,13 @@ namespace mean_field::mapping {
|
|||||||
/// MappedScalarCoefficient ///
|
/// MappedScalarCoefficient ///
|
||||||
//////////////////////////////
|
//////////////////////////////
|
||||||
MappedScalarCoefficient::MappedScalarCoefficient(
|
MappedScalarCoefficient::MappedScalarCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
Coefficient &coeff,
|
Coefficient &coeff,
|
||||||
const COORDINATE_SPACE coord_space
|
const COORDINATE_SPACE coord_space
|
||||||
)
|
)
|
||||||
: m_map(map),
|
: m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_coeff(coeff),
|
m_coeff(coeff),
|
||||||
m_coord_space(coord_space) { };
|
m_coord_space(coord_space) { };
|
||||||
|
|
||||||
@@ -27,8 +29,12 @@ namespace mean_field::mapping {
|
|||||||
switch (m_coord_space) {
|
switch (m_coord_space) {
|
||||||
case COORDINATE_SPACE::PHYSICAL: {
|
case COORDINATE_SPACE::PHYSICAL: {
|
||||||
f_val = eval_at_point(m_coeff, T, ip);
|
f_val = eval_at_point(m_coeff, T, ip);
|
||||||
const double detJ = m_map.ComputeDetJ(T, ip);
|
VolumeMappingContext context;
|
||||||
return f_val * fabs(detJ);
|
MFEM_VERIFY(
|
||||||
|
m_mapping.EvaluateVolume(T, ip, context) == MappingStatus::valid,
|
||||||
|
"Mapped scalar coefficient encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
return f_val * std::abs(context.mapping.mapping_determinant);
|
||||||
}
|
}
|
||||||
case COORDINATE_SPACE::REFERENCE: {
|
case COORDINATE_SPACE::REFERENCE: {
|
||||||
f_val = m_coeff.Eval(T, ip);
|
f_val = m_coeff.Eval(T, ip);
|
||||||
@@ -50,21 +56,25 @@ namespace mean_field::mapping {
|
|||||||
//////////////////////////////////
|
//////////////////////////////////
|
||||||
|
|
||||||
MappedDiffusionCoefficient::MappedDiffusionCoefficient(
|
MappedDiffusionCoefficient::MappedDiffusionCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
mfem::Coefficient &sigma,
|
mfem::Coefficient &sigma,
|
||||||
const int dim
|
const int dim
|
||||||
)
|
)
|
||||||
: MatrixCoefficient(dim),
|
: MatrixCoefficient(dim),
|
||||||
m_map(map),
|
m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_scalar(&sigma),
|
m_scalar(&sigma),
|
||||||
m_tensor(nullptr) { };
|
m_tensor(nullptr) { };
|
||||||
|
|
||||||
MappedDiffusionCoefficient::MappedDiffusionCoefficient(
|
MappedDiffusionCoefficient::MappedDiffusionCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
MatrixCoefficient &sigma
|
MatrixCoefficient &sigma
|
||||||
)
|
)
|
||||||
: MatrixCoefficient(sigma.GetHeight()),
|
: MatrixCoefficient(sigma.GetHeight()),
|
||||||
m_map(map),
|
m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_scalar(nullptr),
|
m_scalar(nullptr),
|
||||||
m_tensor(&sigma) { };
|
m_tensor(&sigma) { };
|
||||||
|
|
||||||
@@ -76,10 +86,13 @@ namespace mean_field::mapping {
|
|||||||
const int dim = height;
|
const int dim = height;
|
||||||
T.SetIntPoint(&ip);
|
T.SetIntPoint(&ip);
|
||||||
|
|
||||||
mfem::DenseMatrix J(dim, dim), JInv(dim, dim);
|
VolumeMappingContext context;
|
||||||
m_map.ComputeJacobian(T, J);
|
MFEM_VERIFY(
|
||||||
const double detJ = J.Det();
|
m_mapping.EvaluateVolume(T, ip, context) == MappingStatus::valid,
|
||||||
mfem::CalcInverse(J, JInv);
|
"Mapped diffusion coefficient encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
const mfem::DenseMatrix &JInv = context.mapping.inverse_mapping_jacobian;
|
||||||
|
const double detJ = context.mapping.mapping_determinant;
|
||||||
|
|
||||||
if (m_scalar) {
|
if (m_scalar) {
|
||||||
const double sig_val = m_scalar->Eval(T, ip);
|
const double sig_val = m_scalar->Eval(T, ip);
|
||||||
@@ -101,11 +114,13 @@ namespace mean_field::mapping {
|
|||||||
/// MappedVectorCoefficient ///
|
/// MappedVectorCoefficient ///
|
||||||
///////////////////////////////
|
///////////////////////////////
|
||||||
MappedVectorCoefficient::MappedVectorCoefficient(
|
MappedVectorCoefficient::MappedVectorCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
VectorCoefficient &coeff
|
VectorCoefficient &coeff
|
||||||
)
|
)
|
||||||
: VectorCoefficient(coeff.GetVDim()),
|
: VectorCoefficient(coeff.GetVDim()),
|
||||||
m_map(map),
|
m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_coeff(coeff) { };
|
m_coeff(coeff) { };
|
||||||
|
|
||||||
void MappedVectorCoefficient::Eval(
|
void MappedVectorCoefficient::Eval(
|
||||||
@@ -116,9 +131,13 @@ namespace mean_field::mapping {
|
|||||||
const int dim = vdim;
|
const int dim = vdim;
|
||||||
T.SetIntPoint(&ip);
|
T.SetIntPoint(&ip);
|
||||||
|
|
||||||
mfem::DenseMatrix JInv(dim, dim);
|
VolumeMappingContext context;
|
||||||
m_map.ComputeInverseJacobian(T, JInv);
|
MFEM_VERIFY(
|
||||||
double detJ = m_map.ComputeDetJ(T, ip);
|
m_mapping.EvaluateVolume(T, ip, context) == MappingStatus::valid,
|
||||||
|
"Mapped vector coefficient encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
const mfem::DenseMatrix &JInv = context.mapping.inverse_mapping_jacobian;
|
||||||
|
const double detJ = context.mapping.mapping_determinant;
|
||||||
|
|
||||||
mfem::Vector C_phys(dim);
|
mfem::Vector C_phys(dim);
|
||||||
m_coeff.Eval(C_phys, T, ip);
|
m_coeff.Eval(C_phys, T, ip);
|
||||||
@@ -132,28 +151,35 @@ namespace mean_field::mapping {
|
|||||||
/// PhysicalPositionFunctionCoefficient ///
|
/// PhysicalPositionFunctionCoefficient ///
|
||||||
///////////////////////////////////////////
|
///////////////////////////////////////////
|
||||||
PhysicalPositionFunctionCoefficient::PhysicalPositionFunctionCoefficient(
|
PhysicalPositionFunctionCoefficient::PhysicalPositionFunctionCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
Func f // std::function<double(const mfem::Vector&)>
|
Func f // std::function<double(const mfem::Vector&)>
|
||||||
)
|
)
|
||||||
: m_f(std::move(f)),
|
: m_f(std::move(f)),
|
||||||
m_map(map) { };
|
m_mapping(mapper, displacement, compactification_coordinate) { };
|
||||||
|
|
||||||
double PhysicalPositionFunctionCoefficient::Eval(
|
double PhysicalPositionFunctionCoefficient::Eval(
|
||||||
mfem::ElementTransformation &T,
|
mfem::ElementTransformation &T,
|
||||||
const mfem::IntegrationPoint &ip
|
const mfem::IntegrationPoint &ip
|
||||||
) {
|
) {
|
||||||
T.SetIntPoint(&ip);
|
T.SetIntPoint(&ip);
|
||||||
mfem::Vector x;
|
MappingPointContext context;
|
||||||
m_map.GetPhysicalPoint(T, ip, x);
|
MFEM_VERIFY(
|
||||||
return m_f(x);
|
m_mapping.EvaluatePoint(T, ip, context) == MappingStatus::valid,
|
||||||
|
"Physical-position coefficient encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
return m_f(context.physical_position);
|
||||||
}
|
}
|
||||||
|
|
||||||
MappedHDivMassCoefficient::MappedHDivMassCoefficient(
|
MappedHDivMassCoefficient::MappedHDivMassCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const int dim
|
const int dim
|
||||||
)
|
)
|
||||||
: MatrixCoefficient(dim),
|
: MatrixCoefficient(dim),
|
||||||
m_map(map) {
|
m_mapping(mapper, displacement, compactification_coordinate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappedHDivMassCoefficient::Eval(
|
void MappedHDivMassCoefficient::Eval(
|
||||||
@@ -163,10 +189,13 @@ namespace mean_field::mapping {
|
|||||||
) {
|
) {
|
||||||
transformation.SetIntPoint(&integration_point);
|
transformation.SetIntPoint(&integration_point);
|
||||||
|
|
||||||
mfem::DenseMatrix map_jacobian(height, height);
|
VolumeMappingContext context;
|
||||||
m_map.ComputeJacobian(transformation, map_jacobian);
|
MFEM_VERIFY(
|
||||||
|
m_mapping.EvaluateVolume(transformation, integration_point, context) == MappingStatus::valid,
|
||||||
const double map_determinant = map_jacobian.Det();
|
"Mapped H(div) coefficient encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
const mfem::DenseMatrix &map_jacobian = context.mapping.mapping_jacobian;
|
||||||
|
const double map_determinant = context.mapping.mapping_determinant;
|
||||||
|
|
||||||
MFEM_VERIFY(map_determinant > 0.0, "Domain mapping has a non-positive Jacobian determinant.");
|
MFEM_VERIFY(map_determinant > 0.0, "Domain mapping has a non-positive Jacobian determinant.");
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,770 +0,0 @@
|
|||||||
module;
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <memory>
|
|
||||||
#include <mfem.hpp>
|
|
||||||
#include <stdexcept>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
module mean_field;
|
|
||||||
import :mapping.types;
|
|
||||||
import :mapping.compactification;
|
|
||||||
import :utils.user;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
bool vector_is_finite(const mfem::Vector &vector) {
|
|
||||||
for (int i = 0; i < vector.Size(); ++i) {
|
|
||||||
if (!std::isfinite(vector(i)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool matrix_is_finite(const mfem::DenseMatrix &matrix) {
|
|
||||||
for (int i = 0; i < matrix.Height(); ++i) {
|
|
||||||
for (int j = 0; j < matrix.Width(); ++j) {
|
|
||||||
if (!std::isfinite(matrix(i, j)))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace mean_field::mapping {
|
|
||||||
ElementCompactificationData::ElementCompactificationData(
|
|
||||||
const mfem::FiniteElement &element,
|
|
||||||
const mfem::Vector &dofs
|
|
||||||
)
|
|
||||||
: m_element(&element),
|
|
||||||
m_dofs(dofs) {
|
|
||||||
if (element.GetRangeType() != mfem::FiniteElement::SCALAR) {
|
|
||||||
throw std::invalid_argument("Compactification coordinate requires a scalar finite element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.GetMapType() != mfem::FiniteElement::VALUE) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification coordinate requires a value-mapped scalar "
|
|
||||||
"finite "
|
|
||||||
"element."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.GetDerivType() != mfem::FiniteElement::GRAD) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification coordinate finite element must provide a "
|
|
||||||
"gradient."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element.GetDof() <= 0) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification coordinate finite element has no degrees of "
|
|
||||||
"freedom."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dofs.Size() != element.GetDof()) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification coordinate DOF count does not match its "
|
|
||||||
"finite "
|
|
||||||
"element."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mfem::FiniteElement &ElementCompactificationData::GetElement() const noexcept {
|
|
||||||
return *m_element;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mfem::Vector &ElementCompactificationData::GetDofs() const noexcept {
|
|
||||||
return m_dofs;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ElementCompactificationData::GetDofCount() const noexcept {
|
|
||||||
return m_dofs.Size();
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementDisplacementData::ElementDisplacementData(
|
|
||||||
const mfem::FiniteElement &element,
|
|
||||||
const mfem::Vector &displacement_dofs,
|
|
||||||
const mfem::Ordering::Type ordering
|
|
||||||
)
|
|
||||||
: m_element(&element),
|
|
||||||
m_dimension(0),
|
|
||||||
m_ordering(ordering) {
|
|
||||||
const int dof_count = element.GetDof();
|
|
||||||
if (dof_count <= 0)
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"The displacement element must have at least one degree of "
|
|
||||||
"freedom."
|
|
||||||
);
|
|
||||||
if (displacement_dofs.Size() <= 0 || displacement_dofs.Size() % dof_count != 0) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"The displacement vector size must be a positive multiple of "
|
|
||||||
"the "
|
|
||||||
"element degree-of-freedom count."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dimension = displacement_dofs.Size() / dof_count;
|
|
||||||
m_dof_matrix.SetSize(dof_count, m_dimension);
|
|
||||||
|
|
||||||
if (ordering == mfem::Ordering::byNODES) {
|
|
||||||
for (int component = 0; component < m_dimension; ++component) {
|
|
||||||
for (int i = 0; i < dof_count; ++i) {
|
|
||||||
m_dof_matrix(i, component) = displacement_dofs(i + component * dof_count);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if (ordering == mfem::Ordering::byVDIM) {
|
|
||||||
for (int i = 0; i < dof_count; ++i) {
|
|
||||||
for (int component = 0; component < m_dimension; ++component) {
|
|
||||||
m_dof_matrix(i, component) = displacement_dofs(component + i * m_dimension);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
throw std::invalid_argument("Unsupported MFEM displacement ordering.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const mfem::FiniteElement &ElementDisplacementData::GetElement() const noexcept {
|
|
||||||
return *m_element;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mfem::DenseMatrix &ElementDisplacementData::GetDofMatrix() const noexcept {
|
|
||||||
return m_dof_matrix;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ElementDisplacementData::GetDimension() const noexcept {
|
|
||||||
return m_dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
int ElementDisplacementData::GetDofCount() const noexcept {
|
|
||||||
return m_element->GetDof();
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::Ordering::Type ElementDisplacementData::GetOrdering() const noexcept {
|
|
||||||
return m_ordering;
|
|
||||||
}
|
|
||||||
|
|
||||||
ElementDisplacementData ElementDisplacementDataFromElementVDofs(
|
|
||||||
const mfem::FiniteElement &element,
|
|
||||||
const mfem::Vector &displacement_dofs
|
|
||||||
) {
|
|
||||||
return ElementDisplacementData(element, displacement_dofs, mfem::Ordering::byNODES);
|
|
||||||
}
|
|
||||||
|
|
||||||
DomainMapperStateless::Workspace::Workspace(const int dimension) {
|
|
||||||
SetDimension(dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
void DomainMapperStateless::Workspace::SetDimension(const int dimension) {
|
|
||||||
if (dimension <= 0) {
|
|
||||||
throw std::invalid_argument("Domain mapping workspace dimension must be positive.");
|
|
||||||
}
|
|
||||||
|
|
||||||
m_dimension = dimension;
|
|
||||||
|
|
||||||
m_field_value.SetSize(dimension);
|
|
||||||
m_field_jacobian.SetSize(dimension, dimension);
|
|
||||||
|
|
||||||
m_compactification_point.coordinate = 0.0;
|
|
||||||
m_compactification_point.coordinate_gradient.SetSize(dimension);
|
|
||||||
|
|
||||||
m_reference_normal.SetSize(dimension);
|
|
||||||
m_mapped_normal.SetSize(dimension);
|
|
||||||
m_full_element_jacobian.SetSize(dimension, dimension);
|
|
||||||
|
|
||||||
m_vector_temp.SetSize(dimension);
|
|
||||||
m_matrix_temp_1.SetSize(dimension, dimension);
|
|
||||||
m_matrix_temp_2.SetSize(dimension, dimension);
|
|
||||||
|
|
||||||
m_exterior_result.physical_position.SetSize(dimension);
|
|
||||||
m_exterior_result.mapping_jacobian.SetSize(dimension, dimension);
|
|
||||||
|
|
||||||
m_exterior_variation.physical_position_variation.SetSize(dimension);
|
|
||||||
m_exterior_variation.mapping_jacobian_variation.SetSize(dimension, dimension);
|
|
||||||
}
|
|
||||||
|
|
||||||
int DomainMapperStateless::Workspace::GetDimension() const noexcept {
|
|
||||||
return m_dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
DomainMapperStateless::DomainMapperStateless(
|
|
||||||
const utils::DomainMapperStatelessOptions options,
|
|
||||||
std::unique_ptr<const compactification::ExteriorDomainMap> exterior_map
|
|
||||||
)
|
|
||||||
: m_options(options),
|
|
||||||
m_exterior_map(std::move(exterior_map)) {
|
|
||||||
if (m_options.dimension <= 0)
|
|
||||||
throw std::invalid_argument("The domain-mapping dimension must be positive.");
|
|
||||||
if (m_options.vacuum_element_attribute <= 0)
|
|
||||||
throw std::invalid_argument("The vacuum element attribute must be positive.");
|
|
||||||
if (!m_exterior_map)
|
|
||||||
throw std::invalid_argument("DomainMapperStateless requires an exterior-domain mapping.");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool
|
|
||||||
DomainMapperStateless::IsCompactifiedElement(const mfem::ElementTransformation &transformation) const noexcept {
|
|
||||||
return transformation.Attribute == m_options.vacuum_element_attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DomainMapperStateless::GetDimension() const noexcept {
|
|
||||||
return m_options.dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
int DomainMapperStateless::GetVacuumElementAttribute() const noexcept {
|
|
||||||
return m_options.vacuum_element_attribute;
|
|
||||||
}
|
|
||||||
|
|
||||||
const compactification::ExteriorDomainMap &DomainMapperStateless::GetExteriorMap() const noexcept {
|
|
||||||
return *m_exterior_map;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DomainMapperStateless::ValidateElementData(const ElementMappingData &element_data) const {
|
|
||||||
const ElementDisplacementData &displacement = element_data.displacement;
|
|
||||||
const ElementCompactificationData &compactification = element_data.compactification;
|
|
||||||
|
|
||||||
if (displacement.GetDimension() != m_options.dimension) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Displacement field dimension does not match the domain mapper "
|
|
||||||
"dimension."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displacement.GetElement().GetDim() != m_options.dimension) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Displacement finite element dimension does not match the "
|
|
||||||
"domain "
|
|
||||||
"mapper dimension."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compactification.GetElement().GetDim() != m_options.dimension) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification finite element dimension does not match the "
|
|
||||||
"domain "
|
|
||||||
"mapper dimension."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (displacement.GetElement().GetGeomType() != compactification.GetElement().GetGeomType()) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Displacement and compactification finite elements have "
|
|
||||||
"different "
|
|
||||||
"geometries."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compactification.GetElement().GetRangeType() != mfem::FiniteElement::SCALAR) {
|
|
||||||
throw std::invalid_argument("Compactification coordinate requires a scalar finite element.");
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compactification.GetElement().GetMapType() != mfem::FiniteElement::VALUE) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification coordinate requires a value-mapped finite "
|
|
||||||
"element."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compactification.GetElement().GetDerivType() != mfem::FiniteElement::GRAD) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification coordinate finite element does not provide a "
|
|
||||||
"gradient."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (compactification.GetDofCount() != compactification.GetElement().GetDof()) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"Compactification coordinate DOF count does not match its "
|
|
||||||
"finite "
|
|
||||||
"element."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingStatus DomainMapperStateless::EvaluateCompactificationCoordinate(
|
|
||||||
const ElementCompactificationData &compactification,
|
|
||||||
mfem::ElementTransformation &transformation,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
Workspace &workspace,
|
|
||||||
CompactificationPointData &point_data
|
|
||||||
) const {
|
|
||||||
const mfem::FiniteElement &element = compactification.GetElement();
|
|
||||||
const mfem::Vector &dofs = compactification.GetDofs();
|
|
||||||
const int dof_count = element.GetDof();
|
|
||||||
|
|
||||||
if (workspace.GetDimension() != m_options.dimension || transformation.GetSpaceDim() != m_options.dimension ||
|
|
||||||
element.GetDim() != m_options.dimension) {
|
|
||||||
return MappingStatus::invalid_dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (dofs.Size() != dof_count) {
|
|
||||||
return MappingStatus::invalid_dimension;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < dofs.Size(); ++i) {
|
|
||||||
if (!std::isfinite(dofs(i)))
|
|
||||||
return MappingStatus::non_finite_input;
|
|
||||||
}
|
|
||||||
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
|
||||||
|
|
||||||
workspace.m_compactification_shape.SetSize(dof_count);
|
|
||||||
workspace.m_compactification_dshape.SetSize(dof_count, m_options.dimension);
|
|
||||||
|
|
||||||
element.CalcShape(integration_point, workspace.m_compactification_shape);
|
|
||||||
element.CalcPhysDShape(transformation, workspace.m_compactification_dshape);
|
|
||||||
|
|
||||||
point_data.coordinate = dofs * workspace.m_compactification_shape;
|
|
||||||
point_data.coordinate_gradient.SetSize(m_options.dimension);
|
|
||||||
workspace.m_compactification_dshape.MultTranspose(dofs, point_data.coordinate_gradient);
|
|
||||||
|
|
||||||
if (!std::isfinite(point_data.coordinate)) {
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int d = 0; d < point_data.coordinate_gradient.Size(); ++d) {
|
|
||||||
if (!std::isfinite(point_data.coordinate_gradient(d)))
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MappingStatus::valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
void DomainMapperStateless::EvaluateField(
|
|
||||||
const ElementDisplacementData &field,
|
|
||||||
mfem::ElementTransformation &transformation,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
Workspace &workspace,
|
|
||||||
mfem::Vector &value,
|
|
||||||
mfem::DenseMatrix &jacobian
|
|
||||||
) const {
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
|
||||||
|
|
||||||
const mfem::FiniteElement &element = field.GetElement();
|
|
||||||
const mfem::DenseMatrix &dof_matrix = field.GetDofMatrix();
|
|
||||||
|
|
||||||
workspace.m_shape.SetSize(element.GetDof());
|
|
||||||
workspace.m_mesh_dshape.SetSize(element.GetDof(), m_options.dimension);
|
|
||||||
|
|
||||||
element.CalcShape(integration_point, workspace.m_shape);
|
|
||||||
element.CalcPhysDShape(transformation, workspace.m_mesh_dshape);
|
|
||||||
|
|
||||||
value.SetSize(m_options.dimension);
|
|
||||||
dof_matrix.MultTranspose(workspace.m_shape, value);
|
|
||||||
|
|
||||||
jacobian.SetSize(m_options.dimension, m_options.dimension);
|
|
||||||
mfem::MultAtB(dof_matrix, workspace.m_mesh_dshape, jacobian);
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingStatus DomainMapperStateless::EvaluatePoint(
|
|
||||||
const ElementMappingData &element_data,
|
|
||||||
mfem::ElementTransformation &transformation,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
Workspace &workspace,
|
|
||||||
MappingPointContext &context
|
|
||||||
) const {
|
|
||||||
ValidateElementData(element_data);
|
|
||||||
|
|
||||||
if (workspace.GetDimension() != m_options.dimension)
|
|
||||||
throw std::invalid_argument("The mapping workspace has the wrong dimension.");
|
|
||||||
if (transformation.GetSpaceDim() != m_options.dimension)
|
|
||||||
throw std::invalid_argument("The element transformation has the wrong spatial dimension.");
|
|
||||||
if (transformation.GetGeometryType() != element_data.displacement.GetElement().GetGeomType())
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"The element transformation geometry does not match the "
|
|
||||||
"supplied "
|
|
||||||
"element data."
|
|
||||||
);
|
|
||||||
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
|
||||||
|
|
||||||
context.reference_position.SetSize(m_options.dimension);
|
|
||||||
transformation.Transform(integration_point, context.reference_position);
|
|
||||||
|
|
||||||
EvaluateField(
|
|
||||||
element_data.displacement, transformation, integration_point, workspace, workspace.m_field_value,
|
|
||||||
workspace.m_field_jacobian
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!vector_is_finite(context.reference_position) || !vector_is_finite(workspace.m_field_value) ||
|
|
||||||
!matrix_is_finite(workspace.m_field_jacobian)) {
|
|
||||||
return MappingStatus::non_finite_input;
|
|
||||||
}
|
|
||||||
|
|
||||||
context.displaced_position.SetSize(m_options.dimension);
|
|
||||||
context.displaced_position = context.reference_position;
|
|
||||||
context.displaced_position += workspace.m_field_value;
|
|
||||||
|
|
||||||
context.displacement_jacobian.SetSize(m_options.dimension, m_options.dimension);
|
|
||||||
context.displacement_jacobian = workspace.m_field_jacobian;
|
|
||||||
for (int i = 0; i < m_options.dimension; ++i)
|
|
||||||
context.displacement_jacobian(i, i) += 1.0;
|
|
||||||
|
|
||||||
context.compactified = IsCompactifiedElement(transformation);
|
|
||||||
|
|
||||||
if (context.compactified) {
|
|
||||||
const MappingStatus coordinate_status = EvaluateCompactificationCoordinate(
|
|
||||||
element_data.compactification, transformation, integration_point, workspace,
|
|
||||||
workspace.m_compactification_point
|
|
||||||
);
|
|
||||||
|
|
||||||
if (coordinate_status != MappingStatus::valid)
|
|
||||||
return coordinate_status;
|
|
||||||
|
|
||||||
const compactification::ExteriorMapInput exterior_input{
|
|
||||||
.reference_position = context.reference_position,
|
|
||||||
.displaced_position = context.displaced_position,
|
|
||||||
.displacement_jacobian = context.displacement_jacobian,
|
|
||||||
.compactification_coordinate = workspace.m_compactification_point.coordinate,
|
|
||||||
.compactification_coordinate_gradient = workspace.m_compactification_point.coordinate_gradient
|
|
||||||
};
|
|
||||||
|
|
||||||
const MappingStatus exterior_status = m_exterior_map->Evaluate(exterior_input, workspace.m_exterior_result);
|
|
||||||
if (exterior_status != MappingStatus::valid)
|
|
||||||
return exterior_status;
|
|
||||||
|
|
||||||
context.physical_position = workspace.m_exterior_result.physical_position;
|
|
||||||
context.mapping_jacobian = workspace.m_exterior_result.mapping_jacobian;
|
|
||||||
} else {
|
|
||||||
context.physical_position = context.displaced_position;
|
|
||||||
context.mapping_jacobian = context.displacement_jacobian;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!vector_is_finite(context.physical_position) || !matrix_is_finite(context.mapping_jacobian))
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
|
|
||||||
context.mapping_determinant = context.mapping_jacobian.Det();
|
|
||||||
if (!std::isfinite(context.mapping_determinant))
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
if (context.mapping_determinant <= 0.0)
|
|
||||||
return MappingStatus::non_positive_determinant;
|
|
||||||
|
|
||||||
context.inverse_mapping_jacobian.SetSize(m_options.dimension, m_options.dimension);
|
|
||||||
mfem::CalcInverse(context.mapping_jacobian, context.inverse_mapping_jacobian);
|
|
||||||
|
|
||||||
if (!matrix_is_finite(context.inverse_mapping_jacobian))
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
|
|
||||||
return MappingStatus::valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingStatus DomainMapperStateless::EvaluateVolume(
|
|
||||||
const ElementMappingData &element_data,
|
|
||||||
mfem::ElementTransformation &transformation,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
Workspace &workspace,
|
|
||||||
VolumeMappingContext &context
|
|
||||||
) const {
|
|
||||||
const MappingStatus point_status =
|
|
||||||
EvaluatePoint(element_data, transformation, integration_point, workspace, context.mapping);
|
|
||||||
if (point_status != MappingStatus::valid)
|
|
||||||
return point_status;
|
|
||||||
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
|
||||||
mfem::Mult(context.mapping.mapping_jacobian, transformation.Jacobian(), workspace.m_full_element_jacobian);
|
|
||||||
|
|
||||||
context.quadrature.J_inv.SetSize(m_options.dimension, m_options.dimension);
|
|
||||||
mfem::CalcInverse(workspace.m_full_element_jacobian, context.quadrature.J_inv);
|
|
||||||
|
|
||||||
context.quadrature.detJ = context.mapping.mapping_determinant;
|
|
||||||
context.quadrature.weight =
|
|
||||||
integration_point.weight * transformation.Weight() * context.mapping.mapping_determinant;
|
|
||||||
|
|
||||||
if (!matrix_is_finite(context.quadrature.J_inv) || !std::isfinite(context.quadrature.weight))
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
if (context.quadrature.weight <= 0.0)
|
|
||||||
return MappingStatus::non_positive_determinant;
|
|
||||||
|
|
||||||
return MappingStatus::valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::ElementTransformation &DomainMapperStateless::SelectFaceElementTransformation(
|
|
||||||
mfem::FaceElementTransformations &transformation,
|
|
||||||
const FaceElementSide side
|
|
||||||
) {
|
|
||||||
if (side == FaceElementSide::element_1) {
|
|
||||||
MFEM_VERIFY(transformation.Elem1 != nullptr, "The face does not have an element-1 transformation.");
|
|
||||||
return *transformation.Elem1;
|
|
||||||
}
|
|
||||||
|
|
||||||
MFEM_VERIFY(transformation.Elem2 != nullptr, "The face does not have an element-2 transformation.");
|
|
||||||
return *transformation.Elem2;
|
|
||||||
}
|
|
||||||
|
|
||||||
const mfem::IntegrationPoint &DomainMapperStateless::SelectFaceElementIntegrationPoint(
|
|
||||||
mfem::FaceElementTransformations &transformation,
|
|
||||||
const FaceElementSide side
|
|
||||||
) {
|
|
||||||
mfem::ElementTransformation &element_transformation = SelectFaceElementTransformation(transformation, side);
|
|
||||||
return element_transformation.GetIntPoint();
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingStatus DomainMapperStateless::EvaluateFace(
|
|
||||||
const ElementMappingData &element_data,
|
|
||||||
mfem::FaceElementTransformations &transformation,
|
|
||||||
const FaceElementSide side,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
Workspace &workspace,
|
|
||||||
FaceMappingContext &context
|
|
||||||
) const {
|
|
||||||
transformation.SetAllIntPoints(&integration_point);
|
|
||||||
mfem::ElementTransformation &element_transformation = SelectFaceElementTransformation(transformation, side);
|
|
||||||
const mfem::IntegrationPoint &element_integration_point =
|
|
||||||
SelectFaceElementIntegrationPoint(transformation, side);
|
|
||||||
|
|
||||||
const MappingStatus point_status =
|
|
||||||
EvaluatePoint(element_data, element_transformation, element_integration_point, workspace, context.mapping);
|
|
||||||
if (point_status != MappingStatus::valid)
|
|
||||||
return point_status;
|
|
||||||
|
|
||||||
workspace.m_reference_normal.SetSize(m_options.dimension);
|
|
||||||
mfem::CalcOrtho(transformation.Jacobian(), workspace.m_reference_normal);
|
|
||||||
if (side == FaceElementSide::element_2)
|
|
||||||
workspace.m_reference_normal *= -1.0;
|
|
||||||
|
|
||||||
const double reference_normal_magnitude = workspace.m_reference_normal.Norml2();
|
|
||||||
if (!std::isfinite(reference_normal_magnitude) || reference_normal_magnitude <= 0.0)
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
|
|
||||||
context.reference_normal.SetSize(m_options.dimension);
|
|
||||||
context.reference_normal = workspace.m_reference_normal;
|
|
||||||
context.reference_normal /= reference_normal_magnitude;
|
|
||||||
|
|
||||||
context.mapping.inverse_mapping_jacobian.MultTranspose(workspace.m_reference_normal, workspace.m_mapped_normal);
|
|
||||||
workspace.m_mapped_normal *= context.mapping.mapping_determinant;
|
|
||||||
|
|
||||||
const double mapped_normal_magnitude = workspace.m_mapped_normal.Norml2();
|
|
||||||
if (!std::isfinite(mapped_normal_magnitude) || mapped_normal_magnitude <= 0.0)
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
|
|
||||||
context.quadrature.normal.SetSize(m_options.dimension);
|
|
||||||
context.quadrature.normal = workspace.m_mapped_normal;
|
|
||||||
context.quadrature.normal /= mapped_normal_magnitude;
|
|
||||||
|
|
||||||
context.reference_surface_weight = integration_point.weight * reference_normal_magnitude;
|
|
||||||
context.physical_surface_weight = integration_point.weight * mapped_normal_magnitude;
|
|
||||||
|
|
||||||
context.quadrature.ds = context.reference_surface_weight;
|
|
||||||
context.quadrature.v_dot_n_scale = mapped_normal_magnitude / reference_normal_magnitude;
|
|
||||||
|
|
||||||
if (!vector_is_finite(context.quadrature.normal) || !std::isfinite(context.reference_surface_weight) ||
|
|
||||||
!std::isfinite(context.physical_surface_weight) || !std::isfinite(context.quadrature.v_dot_n_scale)) {
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MappingStatus::valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingStatus DomainMapperStateless::EvaluatePointVariation(
|
|
||||||
const ElementMappingData &element_data,
|
|
||||||
const ElementDisplacementData &direction,
|
|
||||||
mfem::ElementTransformation &transformation,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
const MappingPointContext &base_context,
|
|
||||||
Workspace &workspace,
|
|
||||||
MappingPointVariation &variation
|
|
||||||
) const {
|
|
||||||
ValidateElementData(element_data);
|
|
||||||
const ElementMappingData direction_data{
|
|
||||||
.displacement = direction, .compactification = element_data.compactification
|
|
||||||
};
|
|
||||||
ValidateElementData(direction_data);
|
|
||||||
|
|
||||||
if (element_data.displacement.GetDofCount() != direction.GetDofCount())
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"The displacement and direction elements have different "
|
|
||||||
"degree-of-freedom counts."
|
|
||||||
);
|
|
||||||
if (workspace.GetDimension() != m_options.dimension)
|
|
||||||
throw std::invalid_argument("The mapping workspace has the wrong dimension.");
|
|
||||||
if (base_context.compactified != IsCompactifiedElement(transformation))
|
|
||||||
throw std::invalid_argument(
|
|
||||||
"The base mapping context does not match the current element "
|
|
||||||
"domain."
|
|
||||||
);
|
|
||||||
|
|
||||||
EvaluateField(
|
|
||||||
direction, transformation, integration_point, workspace, workspace.m_field_value, workspace.m_field_jacobian
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!vector_is_finite(workspace.m_field_value) || !matrix_is_finite(workspace.m_field_jacobian))
|
|
||||||
return MappingStatus::non_finite_input;
|
|
||||||
|
|
||||||
variation.displacement_variation = workspace.m_field_value;
|
|
||||||
variation.displacement_jacobian_variation = workspace.m_field_jacobian;
|
|
||||||
|
|
||||||
if (base_context.compactified) {
|
|
||||||
const MappingStatus coordinate_status = EvaluateCompactificationCoordinate(
|
|
||||||
element_data.compactification, transformation, integration_point, workspace,
|
|
||||||
workspace.m_compactification_point
|
|
||||||
);
|
|
||||||
|
|
||||||
if (coordinate_status != MappingStatus::valid)
|
|
||||||
return coordinate_status;
|
|
||||||
|
|
||||||
const compactification::ExteriorMapInput exterior_input{
|
|
||||||
.reference_position = base_context.reference_position,
|
|
||||||
.displaced_position = base_context.displaced_position,
|
|
||||||
.displacement_jacobian = base_context.displacement_jacobian,
|
|
||||||
.compactification_coordinate = workspace.m_compactification_point.coordinate,
|
|
||||||
.compactification_coordinate_gradient = workspace.m_compactification_point.coordinate_gradient
|
|
||||||
};
|
|
||||||
|
|
||||||
workspace.m_exterior_result.physical_position = base_context.physical_position;
|
|
||||||
workspace.m_exterior_result.mapping_jacobian = base_context.mapping_jacobian;
|
|
||||||
|
|
||||||
const compactification::ExteriorMapDirection exterior_direction{
|
|
||||||
.displaced_position_variation = variation.displacement_variation,
|
|
||||||
.displacement_jacobian_variation = variation.displacement_jacobian_variation
|
|
||||||
};
|
|
||||||
|
|
||||||
// ReSharper disable once CppTooWideScopeInitStatement
|
|
||||||
const MappingStatus exterior_status = m_exterior_map->EvaluateVariation(
|
|
||||||
exterior_input, workspace.m_exterior_result, exterior_direction, workspace.m_exterior_variation
|
|
||||||
);
|
|
||||||
|
|
||||||
if (exterior_status != MappingStatus::valid) {
|
|
||||||
return exterior_status;
|
|
||||||
}
|
|
||||||
|
|
||||||
variation.physical_position_variation = workspace.m_exterior_variation.physical_position_variation;
|
|
||||||
variation.mapping_jacobian_variation = workspace.m_exterior_variation.mapping_jacobian_variation;
|
|
||||||
} else {
|
|
||||||
variation.physical_position_variation = variation.displacement_variation;
|
|
||||||
variation.mapping_jacobian_variation = variation.displacement_jacobian_variation;
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::Mult(
|
|
||||||
base_context.inverse_mapping_jacobian, variation.mapping_jacobian_variation, workspace.m_matrix_temp_1
|
|
||||||
);
|
|
||||||
|
|
||||||
double trace = 0.0;
|
|
||||||
for (int i = 0; i < m_options.dimension; ++i)
|
|
||||||
trace += workspace.m_matrix_temp_1(i, i);
|
|
||||||
variation.mapping_determinant_variation = base_context.mapping_determinant * trace;
|
|
||||||
|
|
||||||
variation.inverse_mapping_jacobian_variation.SetSize(m_options.dimension, m_options.dimension);
|
|
||||||
mfem::Mult(
|
|
||||||
workspace.m_matrix_temp_1, base_context.inverse_mapping_jacobian,
|
|
||||||
variation.inverse_mapping_jacobian_variation
|
|
||||||
);
|
|
||||||
variation.inverse_mapping_jacobian_variation *= -1.0;
|
|
||||||
|
|
||||||
if (!vector_is_finite(variation.physical_position_variation) ||
|
|
||||||
!matrix_is_finite(variation.mapping_jacobian_variation) ||
|
|
||||||
!matrix_is_finite(variation.inverse_mapping_jacobian_variation) ||
|
|
||||||
!std::isfinite(variation.mapping_determinant_variation)) {
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MappingStatus::valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingStatus DomainMapperStateless::EvaluateVolumeVariation(
|
|
||||||
const ElementMappingData &element_data,
|
|
||||||
const ElementDisplacementData &direction,
|
|
||||||
mfem::ElementTransformation &transformation,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
const VolumeMappingContext &base_context,
|
|
||||||
Workspace &workspace,
|
|
||||||
VolumeMappingVariation &variation
|
|
||||||
) const {
|
|
||||||
const MappingStatus point_status = EvaluatePointVariation(
|
|
||||||
element_data, direction, transformation, integration_point, base_context.mapping, workspace,
|
|
||||||
variation.mapping
|
|
||||||
);
|
|
||||||
if (point_status != MappingStatus::valid)
|
|
||||||
return point_status;
|
|
||||||
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
|
||||||
mfem::Mult(
|
|
||||||
variation.mapping.mapping_jacobian_variation, transformation.Jacobian(), workspace.m_full_element_jacobian
|
|
||||||
);
|
|
||||||
mfem::Mult(base_context.quadrature.J_inv, workspace.m_full_element_jacobian, workspace.m_matrix_temp_1);
|
|
||||||
|
|
||||||
variation.inverse_element_jacobian_variation.SetSize(m_options.dimension, m_options.dimension);
|
|
||||||
mfem::Mult(
|
|
||||||
workspace.m_matrix_temp_1, base_context.quadrature.J_inv, variation.inverse_element_jacobian_variation
|
|
||||||
);
|
|
||||||
variation.inverse_element_jacobian_variation *= -1.0;
|
|
||||||
|
|
||||||
variation.weight_variation =
|
|
||||||
integration_point.weight * transformation.Weight() * variation.mapping.mapping_determinant_variation;
|
|
||||||
|
|
||||||
if (!matrix_is_finite(variation.inverse_element_jacobian_variation) ||
|
|
||||||
!std::isfinite(variation.weight_variation))
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
|
|
||||||
return MappingStatus::valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
MappingStatus DomainMapperStateless::EvaluateFaceVariation(
|
|
||||||
const ElementMappingData &element_data,
|
|
||||||
const ElementDisplacementData &direction,
|
|
||||||
mfem::FaceElementTransformations &transformation,
|
|
||||||
const FaceElementSide side,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
|
||||||
const FaceMappingContext &base_context,
|
|
||||||
Workspace &workspace,
|
|
||||||
FaceMappingVariation &variation
|
|
||||||
) const {
|
|
||||||
transformation.SetAllIntPoints(&integration_point);
|
|
||||||
mfem::ElementTransformation &element_transformation = SelectFaceElementTransformation(transformation, side);
|
|
||||||
const mfem::IntegrationPoint &element_integration_point =
|
|
||||||
SelectFaceElementIntegrationPoint(transformation, side);
|
|
||||||
|
|
||||||
const MappingStatus point_status = EvaluatePointVariation(
|
|
||||||
element_data, direction, element_transformation, element_integration_point, base_context.mapping, workspace,
|
|
||||||
variation.mapping
|
|
||||||
);
|
|
||||||
if (point_status != MappingStatus::valid)
|
|
||||||
return point_status;
|
|
||||||
|
|
||||||
workspace.m_reference_normal.SetSize(m_options.dimension);
|
|
||||||
mfem::CalcOrtho(transformation.Jacobian(), workspace.m_reference_normal);
|
|
||||||
if (side == FaceElementSide::element_2)
|
|
||||||
workspace.m_reference_normal *= -1.0;
|
|
||||||
|
|
||||||
const double reference_normal_magnitude = workspace.m_reference_normal.Norml2();
|
|
||||||
if (!std::isfinite(reference_normal_magnitude) || reference_normal_magnitude <= 0.0)
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
|
|
||||||
base_context.mapping.inverse_mapping_jacobian.MultTranspose(
|
|
||||||
workspace.m_reference_normal, workspace.m_vector_temp
|
|
||||||
);
|
|
||||||
workspace.m_mapped_normal = workspace.m_vector_temp;
|
|
||||||
workspace.m_mapped_normal *= base_context.mapping.mapping_determinant;
|
|
||||||
|
|
||||||
variation.physical_normal_variation.SetSize(m_options.dimension);
|
|
||||||
variation.mapping.inverse_mapping_jacobian_variation.MultTranspose(
|
|
||||||
workspace.m_reference_normal, variation.physical_normal_variation
|
|
||||||
);
|
|
||||||
variation.physical_normal_variation *= base_context.mapping.mapping_determinant;
|
|
||||||
variation.physical_normal_variation.Add(
|
|
||||||
variation.mapping.mapping_determinant_variation, workspace.m_vector_temp
|
|
||||||
);
|
|
||||||
|
|
||||||
const double mapped_normal_magnitude = workspace.m_mapped_normal.Norml2();
|
|
||||||
if (!std::isfinite(mapped_normal_magnitude) || mapped_normal_magnitude <= 0.0)
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
|
|
||||||
const double mapped_normal_magnitude_variation =
|
|
||||||
base_context.quadrature.normal * variation.physical_normal_variation;
|
|
||||||
|
|
||||||
variation.physical_normal_variation.Add(-mapped_normal_magnitude_variation, base_context.quadrature.normal);
|
|
||||||
variation.physical_normal_variation /= mapped_normal_magnitude;
|
|
||||||
|
|
||||||
variation.physical_surface_weight_variation = integration_point.weight * mapped_normal_magnitude_variation;
|
|
||||||
variation.normal_flux_scale_variation = mapped_normal_magnitude_variation / reference_normal_magnitude;
|
|
||||||
|
|
||||||
if (!vector_is_finite(variation.physical_normal_variation) ||
|
|
||||||
!std::isfinite(variation.physical_surface_weight_variation) ||
|
|
||||||
!std::isfinite(variation.normal_flux_scale_variation)) {
|
|
||||||
return MappingStatus::non_finite_result;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MappingStatus::valid;
|
|
||||||
}
|
|
||||||
} // namespace mean_field::mapping
|
|
||||||
@@ -35,7 +35,7 @@ namespace {
|
|||||||
namespace mean_field::operators::context::barotropic {
|
namespace mean_field::operators::context::barotropic {
|
||||||
BarotropicClosureLinearizationContext::BarotropicClosureLinearizationContext(
|
BarotropicClosureLinearizationContext::BarotropicClosureLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const field::FieldDofMap &densityMap,
|
const field::FieldDofMap &densityMap,
|
||||||
const field::FieldDofMap &enthalpyMap,
|
const field::FieldDofMap &enthalpyMap,
|
||||||
const field::FieldDofMap &displacementMap
|
const field::FieldDofMap &displacementMap
|
||||||
|
|||||||
@@ -9,6 +9,29 @@ import :operators.context.gravity_field;
|
|||||||
namespace {
|
namespace {
|
||||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
|
[[nodiscard]] std::unique_ptr<mfem::ParMixedBilinearForm> make_divergence_operator(const mean_field::fem::FEM &f) {
|
||||||
|
auto divergence =
|
||||||
|
std::make_unique<mfem::ParMixedBilinearForm>(f.gravityFluxFes.get(), f.gravityPotentialFes.get());
|
||||||
|
|
||||||
|
divergence->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||||
|
|
||||||
|
auto integrator = std::make_unique<mfem::VectorFEDivergenceIntegrator>();
|
||||||
|
|
||||||
|
const mfem::FiniteElement &trialElement = *f.gravityFluxFes->GetTypicalFE();
|
||||||
|
const mfem::FiniteElement &testElement = *f.gravityPotentialFes->GetTypicalFE();
|
||||||
|
const mfem::ElementTransformation &transformation = *f.mesh->GetElementTransformation(0);
|
||||||
|
|
||||||
|
f.quadratureFactory->configure_gravity_divergence(
|
||||||
|
*integrator, mean_field::quadrature::QuadratureRole::discretization, trialElement, testElement,
|
||||||
|
transformation, mean_field::utils::DOMAINS::ALL, mean_field::quadrature::MappingKind::none
|
||||||
|
);
|
||||||
|
|
||||||
|
divergence->AddDomainIntegrator(integrator.release());
|
||||||
|
divergence->Assemble();
|
||||||
|
|
||||||
|
return divergence;
|
||||||
|
}
|
||||||
|
|
||||||
void validate_displacement(
|
void validate_displacement(
|
||||||
const mean_field::field::FieldDofMap &displacement_map,
|
const mean_field::field::FieldDofMap &displacement_map,
|
||||||
const mfem::Vector &displacement
|
const mfem::Vector &displacement
|
||||||
@@ -96,7 +119,7 @@ namespace {
|
|||||||
namespace mean_field::operators::context::gravity_field {
|
namespace mean_field::operators::context::gravity_field {
|
||||||
GravityFieldGeometryContext::GravityFieldGeometryContext(
|
GravityFieldGeometryContext::GravityFieldGeometryContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
const mapping::DomainMapper &domain_mapper
|
||||||
)
|
)
|
||||||
: m_fem(f),
|
: m_fem(f),
|
||||||
m_domain_mapper(domain_mapper),
|
m_domain_mapper(domain_mapper),
|
||||||
@@ -172,16 +195,21 @@ namespace mean_field::operators::context::gravity_field {
|
|||||||
if (discretization_changed) {
|
if (discretization_changed) {
|
||||||
auto mass_operator = std::make_unique<PreparedMappedHDivMassOperator>(m_fem, m_domain_mapper);
|
auto mass_operator = std::make_unique<PreparedMappedHDivMassOperator>(m_fem, m_domain_mapper);
|
||||||
auto source_operator = std::make_unique<PreparedMappedGravitySourceOperator>(m_fem, m_domain_mapper);
|
auto source_operator = std::make_unique<PreparedMappedGravitySourceOperator>(m_fem, m_domain_mapper);
|
||||||
|
auto divergence_operator = make_divergence_operator(m_fem);
|
||||||
|
auto transpose_divergence_operator = std::make_unique<mfem::TransposeOperator>(divergence_operator.get());
|
||||||
|
|
||||||
mass_operator->Prepare(displacement);
|
mass_operator->Prepare(displacement);
|
||||||
source_operator->Prepare(displacement);
|
source_operator->Prepare(displacement);
|
||||||
|
|
||||||
m_mass_operator = std::move(mass_operator);
|
m_mass_operator = std::move(mass_operator);
|
||||||
m_source_operator = std::move(source_operator);
|
m_source_operator = std::move(source_operator);
|
||||||
|
m_divergence_operator = std::move(divergence_operator);
|
||||||
|
m_transpose_divergence_operator = std::move(transpose_divergence_operator);
|
||||||
|
|
||||||
preparation.reconstructed_operators = true;
|
preparation.reconstructed_operators = true;
|
||||||
preparation.rebuilt_mass_operator = true;
|
preparation.rebuilt_mass_operator = true;
|
||||||
preparation.rebuilt_source_operator = true;
|
preparation.rebuilt_source_operator = true;
|
||||||
|
preparation.rebuilt_divergence_operator = true;
|
||||||
} else {
|
} else {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
m_mass_operator != nullptr, "GravityFieldGeometryContext has "
|
m_mass_operator != nullptr, "GravityFieldGeometryContext has "
|
||||||
@@ -231,6 +259,23 @@ namespace mean_field::operators::context::gravity_field {
|
|||||||
return *m_source_operator;
|
return *m_source_operator;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const mfem::Operator &GravityFieldGeometryContext::GetDivergenceOperator() const {
|
||||||
|
MFEM_VERIFY(m_is_prepared, "GravityFieldGeometryContext must be prepared before accessing divergence.");
|
||||||
|
MFEM_VERIFY(m_divergence_operator != nullptr, "GravityFieldGeometryContext has no divergence operator.");
|
||||||
|
return *m_divergence_operator;
|
||||||
|
}
|
||||||
|
|
||||||
|
const mfem::Operator &GravityFieldGeometryContext::GetTransposeDivergenceOperator() const {
|
||||||
|
MFEM_VERIFY(
|
||||||
|
m_is_prepared, "GravityFieldGeometryContext must be prepared before accessing transpose divergence."
|
||||||
|
);
|
||||||
|
MFEM_VERIFY(
|
||||||
|
m_transpose_divergence_operator != nullptr,
|
||||||
|
"GravityFieldGeometryContext has no transpose-divergence operator."
|
||||||
|
);
|
||||||
|
return *m_transpose_divergence_operator;
|
||||||
|
}
|
||||||
|
|
||||||
const mfem::Vector &GravityFieldGeometryContext::GetDisplacementTrue() const {
|
const mfem::Vector &GravityFieldGeometryContext::GetDisplacementTrue() const {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
m_is_prepared, "GravityFieldGeometryContext must be prepared before "
|
m_is_prepared, "GravityFieldGeometryContext must be prepared before "
|
||||||
@@ -257,7 +302,7 @@ namespace mean_field::operators::context::gravity_field {
|
|||||||
|
|
||||||
GravityFieldLinearizationContext::GravityFieldLinearizationContext(
|
GravityFieldLinearizationContext::GravityFieldLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
const mapping::DomainMapper &domain_mapper
|
||||||
)
|
)
|
||||||
: m_fem(f),
|
: m_fem(f),
|
||||||
m_geometry_context(
|
m_geometry_context(
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ namespace {
|
|||||||
namespace mean_field::operators::context::hydrostatic {
|
namespace mean_field::operators::context::hydrostatic {
|
||||||
HydrostaticEquilibriumContext::HydrostaticEquilibriumContext(
|
HydrostaticEquilibriumContext::HydrostaticEquilibriumContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper
|
const mapping::DomainMapper &domainMapper
|
||||||
)
|
)
|
||||||
: m_f(f),
|
: m_f(f),
|
||||||
m_domainMapper(domainMapper),
|
m_domainMapper(domainMapper),
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ namespace {
|
|||||||
namespace mean_field::operators::context::pressure_force {
|
namespace mean_field::operators::context::pressure_force {
|
||||||
PressureForceLinearizationContext::PressureForceLinearizationContext(
|
PressureForceLinearizationContext::PressureForceLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const field::FieldDofMap &enthalpyMap,
|
const field::FieldDofMap &enthalpyMap,
|
||||||
const field::FieldDofMap &displacementMap
|
const field::FieldDofMap &displacementMap
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ namespace {
|
|||||||
namespace mean_field::operators::context::rotational_displacement_force {
|
namespace mean_field::operators::context::rotational_displacement_force {
|
||||||
RotationalDisplacementForceLinearizationContext::RotationalDisplacementForceLinearizationContext(
|
RotationalDisplacementForceLinearizationContext::RotationalDisplacementForceLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper
|
const mapping::DomainMapper &domainMapper
|
||||||
)
|
)
|
||||||
: m_f(f),
|
: m_f(f),
|
||||||
m_densityMap(
|
m_densityMap(
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -129,7 +129,7 @@ namespace {
|
|||||||
namespace mean_field::operators {
|
namespace mean_field::operators {
|
||||||
GravityFieldJacobianOperator::GravityFieldJacobianOperator(
|
GravityFieldJacobianOperator::GravityFieldJacobianOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper,
|
const mapping::DomainMapper &domain_mapper,
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
const context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
||||||
const mfem::Array<int> &state_offsets,
|
const mfem::Array<int> &state_offsets,
|
||||||
const mfem::Array<int> &residual_offsets
|
const mfem::Array<int> &residual_offsets
|
||||||
@@ -159,13 +159,6 @@ namespace mean_field::operators {
|
|||||||
f.displacementFes != nullptr, "GravityFieldJacobianOperator requires the "
|
f.displacementFes != nullptr, "GravityFieldJacobianOperator requires the "
|
||||||
"displacement finite-element space."
|
"displacement finite-element space."
|
||||||
);
|
);
|
||||||
MFEM_VERIFY(
|
|
||||||
f.gravityContext.b_form != nullptr, "GravityFieldJacobianOperator requires the divergence operator."
|
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.gravityContext.BT != nullptr, "GravityFieldJacobianOperator requires the transpose divergence "
|
|
||||||
"operator."
|
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
f.quadratureFactory != nullptr, "GravityFieldJacobianOperator requires the quadrature-rule factory."
|
f.quadratureFactory != nullptr, "GravityFieldJacobianOperator requires the quadrature-rule factory."
|
||||||
);
|
);
|
||||||
@@ -263,14 +256,16 @@ namespace mean_field::operators {
|
|||||||
potential_map.gather(source_variation_action_true, source_variation_action);
|
potential_map.gather(source_variation_action_true, source_variation_action);
|
||||||
|
|
||||||
transpose_divergence_action_true.SetSize(flux_map.full_size());
|
transpose_divergence_action_true.SetSize(flux_map.full_size());
|
||||||
m_fem.gravityContext.BT->Mult(gravity_potential_direction_true, transpose_divergence_action_true);
|
geometry_context.GetTransposeDivergenceOperator().Mult(
|
||||||
|
gravity_potential_direction_true, transpose_divergence_action_true
|
||||||
|
);
|
||||||
flux_map.gather(transpose_divergence_action_true, transpose_divergence_action);
|
flux_map.gather(transpose_divergence_action_true, transpose_divergence_action);
|
||||||
|
|
||||||
gravity_gradient_action += transpose_divergence_action;
|
gravity_gradient_action += transpose_divergence_action;
|
||||||
gravity_gradient_action += mass_variation_action;
|
gravity_gradient_action += mass_variation_action;
|
||||||
|
|
||||||
divergence_action_true.SetSize(potential_map.full_size());
|
divergence_action_true.SetSize(potential_map.full_size());
|
||||||
m_fem.gravityContext.b_form->Mult(gravity_gradient_direction_true, divergence_action_true);
|
geometry_context.GetDivergenceOperator().Mult(gravity_gradient_direction_true, divergence_action_true);
|
||||||
potential_map.gather(divergence_action_true, gravity_poisson_action);
|
potential_map.gather(divergence_action_true, gravity_poisson_action);
|
||||||
|
|
||||||
gravity_poisson_action -= source_action;
|
gravity_poisson_action -= source_action;
|
||||||
|
|||||||
@@ -111,7 +111,7 @@ namespace {
|
|||||||
|
|
||||||
void validate_common_inputs(
|
void validate_common_inputs(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &displacementTrue
|
const mfem::Vector &displacementTrue
|
||||||
) {
|
) {
|
||||||
MFEM_VERIFY(f.mesh != nullptr, "The EOS closure kernel requires a mesh.");
|
MFEM_VERIFY(f.mesh != nullptr, "The EOS closure kernel requires a mesh.");
|
||||||
@@ -150,7 +150,7 @@ namespace {
|
|||||||
|
|
||||||
void apply_closure_action(
|
void apply_closure_action(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mean_field::eos::Polytrope &barotrope,
|
const mean_field::eos::Polytrope &barotrope,
|
||||||
const ClosureAction closureAction,
|
const ClosureAction closureAction,
|
||||||
const mfem::Vector *densityInputTrue,
|
const mfem::Vector *densityInputTrue,
|
||||||
@@ -204,7 +204,7 @@ namespace {
|
|||||||
mfem::Vector localAction(f.densityFes->GetVSize());
|
mfem::Vector localAction(f.densityFes->GetVSize());
|
||||||
localAction = 0.0;
|
localAction = 0.0;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
mean_field::mapping::DomainMapper::Workspace workspace(f.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Array<int> densityDofs;
|
mfem::Array<int> densityDofs;
|
||||||
mfem::Array<int> enthalpyDofs;
|
mfem::Array<int> enthalpyDofs;
|
||||||
@@ -365,7 +365,7 @@ namespace {
|
|||||||
namespace mean_field::operators::kernels {
|
namespace mean_field::operators::kernels {
|
||||||
void apply_barotropic_closure(
|
void apply_barotropic_closure(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &densityTrue,
|
const mfem::Vector &densityTrue,
|
||||||
const mfem::Vector &enthalpyTrue,
|
const mfem::Vector &enthalpyTrue,
|
||||||
@@ -380,7 +380,7 @@ namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_barotropic_closure_density_action(
|
void apply_barotropic_closure_density_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -394,7 +394,7 @@ namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_barotropic_closure_enthalpy_action(
|
void apply_barotropic_closure_enthalpy_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
const mfem::Vector &enthalpyVariationTrue,
|
const mfem::Vector &enthalpyVariationTrue,
|
||||||
@@ -409,7 +409,7 @@ namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_barotropic_closure_displacement_action(
|
void apply_barotropic_closure_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
@@ -490,7 +490,7 @@ namespace mean_field::operators::kernels {
|
|||||||
mfem::Vector localAction(f.densityFes->GetVSize());
|
mfem::Vector localAction(f.densityFes->GetVSize());
|
||||||
localAction = 0.0;
|
localAction = 0.0;
|
||||||
|
|
||||||
mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
mapping::DomainMapper::Workspace workspace(f.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Array<int> densityDofs;
|
mfem::Array<int> densityDofs;
|
||||||
mfem::Array<int> enthalpyDofs;
|
mfem::Array<int> enthalpyDofs;
|
||||||
|
|||||||
@@ -11,21 +11,30 @@ module mean_field;
|
|||||||
import :operators.kernels.gravity_displacement_force;
|
import :operators.kernels.gravity_displacement_force;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum class GravityDisplacementForceAction { residual, density, gravityGradient, displacement, complete };
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
void true_to_local(
|
[[nodiscard]] bool is_vacuum_attribute(const int attribute) {
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
return DomainSchema::template attribute_belongs_to<
|
||||||
const mfem::Vector &trueVector,
|
mean_field::utils::domain::Vacuum>(attribute);
|
||||||
mfem::Vector &localVector
|
}
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
enum class GravityDisplacementForceAction {
|
||||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
residual,
|
||||||
"The gravity-displacement-force true vector has the wrong size."
|
density,
|
||||||
);
|
gravityGradient,
|
||||||
|
displacement,
|
||||||
|
complete
|
||||||
|
};
|
||||||
|
|
||||||
|
void true_to_local(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
|
const mfem::Vector &trueVector, mfem::Vector &localVector) {
|
||||||
|
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||||
|
"The gravity-displacement-force true vector has the wrong size.");
|
||||||
|
|
||||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->Mult(trueVector, localVector);
|
prolongation->Mult(trueVector, localVector);
|
||||||
@@ -34,20 +43,17 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void local_to_true(
|
void local_to_true(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
const mfem::Vector &localVector, mfem::Vector &trueVector) {
|
||||||
const mfem::Vector &localVector,
|
|
||||||
mfem::Vector &trueVector
|
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||||
"The gravity-displacement-force local vector has the wrong size."
|
"The gravity-displacement-force local vector has the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||||
trueVector = 0.0;
|
trueVector = 0.0;
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->MultTranspose(localVector, trueVector);
|
prolongation->MultTranspose(localVector, trueVector);
|
||||||
@@ -56,13 +62,10 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] int vector_dof_index(
|
[[nodiscard]] int vector_dof_index(const mfem::Ordering::Type ordering,
|
||||||
const mfem::Ordering::Type ordering,
|
const int scalarDof, const int component,
|
||||||
const int scalarDof,
|
|
||||||
const int component,
|
|
||||||
const int scalarDofCount,
|
const int scalarDofCount,
|
||||||
const int dimension
|
const int dimension) {
|
||||||
) {
|
|
||||||
if (ordering == mfem::Ordering::byNODES) {
|
if (ordering == mfem::Ordering::byNODES) {
|
||||||
return scalarDof + component * scalarDofCount;
|
return scalarDof + component * scalarDofCount;
|
||||||
}
|
}
|
||||||
@@ -71,61 +74,53 @@ namespace {
|
|||||||
return scalarDof * dimension + component;
|
return scalarDof * dimension + component;
|
||||||
}
|
}
|
||||||
|
|
||||||
MFEM_ABORT(
|
MFEM_ABORT("The gravity-displacement-force test space uses an unsupported "
|
||||||
"The gravity-displacement-force test space uses an unsupported "
|
"ordering.");
|
||||||
"ordering."
|
|
||||||
);
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const mfem::IntegrationRule &get_gravity_force_rule(
|
[[nodiscard]] const mfem::IntegrationRule &
|
||||||
const mean_field::fem::FEM &f,
|
get_gravity_force_rule(const mean_field::fem::FEM &f,
|
||||||
const mfem::FiniteElement &densityElement,
|
const mfem::FiniteElement &densityElement,
|
||||||
const mfem::FiniteElement &gravityGradientElement,
|
const mfem::FiniteElement &gravityGradientElement,
|
||||||
const mfem::FiniteElement &displacementElement,
|
const mfem::FiniteElement &displacementElement,
|
||||||
const mfem::ElementTransformation &transformation
|
const mfem::ElementTransformation &transformation) {
|
||||||
) {
|
using DisplacementField =
|
||||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
mean_field::field::Field<mean_field::field::Displacement>;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(densityElement.GetOrder() ==
|
||||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
mean_field::field::Density::Scalar::familyOrder,
|
||||||
"The gravity-displacement-force density element does not match "
|
"The gravity-displacement-force density element does not match "
|
||||||
"the registered density field."
|
"the registered density field.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(gravityGradientElement.GetOrder() ==
|
||||||
gravityGradientElement.GetOrder() == mean_field::field::Gravity::Flux::familyOrder + 1,
|
mean_field::field::Gravity::Flux::familyOrder + 1,
|
||||||
"The gravity-displacement-force RT element does not match the "
|
"The gravity-displacement-force RT element does not match the "
|
||||||
"registered gravity-gradient field."
|
"registered gravity-gradient field.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementElement.GetOrder() ==
|
||||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
mean_field::field::Displacement::Vector::familyOrder,
|
||||||
"The gravity-displacement-force test element does not match the "
|
"The gravity-displacement-force test element does not match the "
|
||||||
"registered displacement field."
|
"registered displacement field.");
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::quadrature::Query query =
|
const mean_field::quadrature::Query query = DisplacementField::make_query<
|
||||||
DisplacementField::make_query<mean_field::field::Displacement::Form::GravityForce>(
|
mean_field::field::Displacement::Form::GravityForce>(
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||||
);
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const mean_field::quadrature::MfemRule rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
const mean_field::quadrature::MfemRule rule =
|
||||||
|
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(rule.integration_rule != nullptr,
|
||||||
rule.integration_rule != nullptr, "The quadrature policy did not return a gravity-displacement-"
|
"The quadrature policy did not return a gravity-displacement-"
|
||||||
"force integration rule."
|
"force integration rule.");
|
||||||
);
|
|
||||||
|
|
||||||
return *rule.integration_rule;
|
return *rule.integration_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_finite_vector(
|
void validate_finite_vector(const mfem::Vector &vector, const char *message) {
|
||||||
const mfem::Vector &vector,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
for (int index = 0; index < vector.Size(); ++index) {
|
for (int index = 0; index < vector.Size(); ++index) {
|
||||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||||
}
|
}
|
||||||
@@ -133,173 +128,153 @@ namespace {
|
|||||||
|
|
||||||
void validate_common_inputs(
|
void validate_common_inputs(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &displacementTrue
|
const mfem::Vector &displacementTrue) {
|
||||||
) {
|
MFEM_VERIFY(f.mesh != nullptr,
|
||||||
MFEM_VERIFY(f.mesh != nullptr, "The gravity-displacement-force kernel requires a mesh.");
|
"The gravity-displacement-force kernel requires a mesh.");
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.densityFes != nullptr,
|
||||||
f.densityFes != nullptr, "The gravity-displacement-force kernel requires the density "
|
"The gravity-displacement-force kernel requires the density "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.gravityFluxFes != nullptr,
|
||||||
f.gravityFluxFes != nullptr, "The gravity-displacement-force kernel requires the gravity-"
|
"The gravity-displacement-force kernel requires the gravity-"
|
||||||
"gradient finite-element space."
|
"gradient finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes != nullptr,
|
||||||
f.displacementFes != nullptr, "The gravity-displacement-force kernel requires the displacement "
|
"The gravity-displacement-force kernel requires the displacement "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.compactificationFes != nullptr &&
|
||||||
f.compactificationFes != nullptr && f.compactificationCoordinate != nullptr,
|
f.compactificationCoordinate != nullptr,
|
||||||
"The gravity-displacement-force kernel requires the "
|
"The gravity-displacement-force kernel requires the "
|
||||||
"compactification coordinate."
|
"compactification coordinate.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.quadratureFactory != nullptr,
|
||||||
f.quadratureFactory != nullptr, "The gravity-displacement-force kernel requires the quadrature "
|
"The gravity-displacement-force kernel requires the quadrature "
|
||||||
"rule factory."
|
"rule factory.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
|
||||||
"The gravity-displacement-force displacement vector has the "
|
"The gravity-displacement-force displacement vector has the "
|
||||||
"wrong size."
|
"wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
|
||||||
"The gravity-displacement-force mapper dimension does not match "
|
"The gravity-displacement-force mapper dimension does not match "
|
||||||
"the mesh dimension."
|
"the mesh dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
|
||||||
"The gravity-displacement-force displacement dimension does not "
|
"The gravity-displacement-force displacement dimension does not "
|
||||||
"match the mesh dimension."
|
"match the mesh dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
displacementTrue, "The gravity-displacement-force displacement contains a "
|
displacementTrue,
|
||||||
"non-finite value."
|
"The gravity-displacement-force displacement contains a "
|
||||||
);
|
"non-finite value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_density(
|
void validate_density(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const mfem::Vector &density, const char *message) {
|
||||||
const mfem::Vector &density,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
||||||
validate_finite_vector(density, message);
|
validate_finite_vector(density, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_gravity_gradient(
|
void validate_gravity_gradient(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
|
||||||
const mfem::Vector &gravityGradient,
|
const mfem::Vector &gravityGradient,
|
||||||
const char *message
|
const char *message) {
|
||||||
) {
|
MFEM_VERIFY(gravityGradient.Size() == f.gravityFluxFes->GetTrueVSize(),
|
||||||
MFEM_VERIFY(gravityGradient.Size() == f.gravityFluxFes->GetTrueVSize(), message);
|
message);
|
||||||
|
|
||||||
validate_finite_vector(gravityGradient, message);
|
validate_finite_vector(gravityGradient, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_gravity_displacement_force_action(
|
void apply_gravity_displacement_force_action(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const GravityDisplacementForceAction requestedAction,
|
const GravityDisplacementForceAction requestedAction,
|
||||||
const mfem::Vector *baseDensityTrue,
|
const mfem::Vector *baseDensityTrue,
|
||||||
const mfem::Vector *densityVariationTrue,
|
const mfem::Vector *densityVariationTrue,
|
||||||
const mfem::Vector *baseGravityGradientTrue,
|
const mfem::Vector *baseGravityGradientTrue,
|
||||||
const mfem::Vector *gravityGradientVariationTrue,
|
const mfem::Vector *gravityGradientVariationTrue,
|
||||||
const mfem::Vector *displacementVariationTrue,
|
const mfem::Vector *displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||||
|
|
||||||
const bool needsBaseDensity = requestedAction == GravityDisplacementForceAction::residual ||
|
const bool needsBaseDensity =
|
||||||
|
requestedAction == GravityDisplacementForceAction::residual ||
|
||||||
requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
||||||
requestedAction == GravityDisplacementForceAction::displacement ||
|
requestedAction == GravityDisplacementForceAction::displacement ||
|
||||||
requestedAction == GravityDisplacementForceAction::complete;
|
requestedAction == GravityDisplacementForceAction::complete;
|
||||||
|
|
||||||
const bool needsDensityVariation = requestedAction == GravityDisplacementForceAction::density ||
|
const bool needsDensityVariation =
|
||||||
|
requestedAction == GravityDisplacementForceAction::density ||
|
||||||
requestedAction == GravityDisplacementForceAction::complete;
|
requestedAction == GravityDisplacementForceAction::complete;
|
||||||
|
|
||||||
const bool needsBaseGravityGradient = requestedAction == GravityDisplacementForceAction::residual ||
|
const bool needsBaseGravityGradient =
|
||||||
|
requestedAction == GravityDisplacementForceAction::residual ||
|
||||||
requestedAction == GravityDisplacementForceAction::density ||
|
requestedAction == GravityDisplacementForceAction::density ||
|
||||||
requestedAction == GravityDisplacementForceAction::displacement ||
|
requestedAction == GravityDisplacementForceAction::displacement ||
|
||||||
requestedAction == GravityDisplacementForceAction::complete;
|
requestedAction == GravityDisplacementForceAction::complete;
|
||||||
|
|
||||||
const bool needsGravityGradientVariation = requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
const bool needsGravityGradientVariation =
|
||||||
|
requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
||||||
requestedAction == GravityDisplacementForceAction::complete;
|
requestedAction == GravityDisplacementForceAction::complete;
|
||||||
|
|
||||||
const bool needsDisplacementVariation = requestedAction == GravityDisplacementForceAction::displacement ||
|
const bool needsDisplacementVariation =
|
||||||
|
requestedAction == GravityDisplacementForceAction::displacement ||
|
||||||
requestedAction == GravityDisplacementForceAction::complete;
|
requestedAction == GravityDisplacementForceAction::complete;
|
||||||
|
|
||||||
if (needsBaseDensity) {
|
if (needsBaseDensity) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(baseDensityTrue != nullptr,
|
||||||
baseDensityTrue != nullptr, "The gravity-displacement-force action requires a base "
|
"The gravity-displacement-force action requires a base "
|
||||||
"density."
|
"density.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_density(f, *baseDensityTrue, "The gravity-displacement-force base density is invalid.");
|
validate_density(f, *baseDensityTrue,
|
||||||
|
"The gravity-displacement-force base density is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsDensityVariation) {
|
if (needsDensityVariation) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(densityVariationTrue != nullptr,
|
||||||
densityVariationTrue != nullptr, "The gravity-displacement-force action requires a density "
|
"The gravity-displacement-force action requires a density "
|
||||||
"variation."
|
"variation.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_density(
|
validate_density(f, *densityVariationTrue,
|
||||||
f, *densityVariationTrue,
|
|
||||||
"The gravity-displacement-force density variation is "
|
"The gravity-displacement-force density variation is "
|
||||||
"invalid."
|
"invalid.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsBaseGravityGradient) {
|
if (needsBaseGravityGradient) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(baseGravityGradientTrue != nullptr,
|
||||||
baseGravityGradientTrue != nullptr, "The gravity-displacement-force action requires a base "
|
"The gravity-displacement-force action requires a base "
|
||||||
"gravity gradient."
|
"gravity gradient.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_gravity_gradient(
|
validate_gravity_gradient(
|
||||||
f, *baseGravityGradientTrue,
|
f, *baseGravityGradientTrue,
|
||||||
"The gravity-displacement-force base gravity gradient is "
|
"The gravity-displacement-force base gravity gradient is "
|
||||||
"invalid."
|
"invalid.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsGravityGradientVariation) {
|
if (needsGravityGradientVariation) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(gravityGradientVariationTrue != nullptr,
|
||||||
gravityGradientVariationTrue != nullptr, "The gravity-displacement-force action requires a gravity-"
|
"The gravity-displacement-force action requires a gravity-"
|
||||||
"gradient variation."
|
"gradient variation.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_gravity_gradient(
|
validate_gravity_gradient(
|
||||||
f, *gravityGradientVariationTrue,
|
f, *gravityGradientVariationTrue,
|
||||||
"The gravity-displacement-force gravity-gradient variation "
|
"The gravity-displacement-force gravity-gradient variation "
|
||||||
"is invalid."
|
"is invalid.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementVariationTrue != nullptr &&
|
||||||
displacementVariationTrue != nullptr &&
|
displacementVariationTrue->Size() ==
|
||||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
f.displacementFes->GetTrueVSize(),
|
||||||
"The gravity-displacement-force displacement variation is "
|
"The gravity-displacement-force displacement variation is "
|
||||||
"invalid."
|
"invalid.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
*displacementVariationTrue, "The gravity-displacement-force displacement variation "
|
*displacementVariationTrue,
|
||||||
"contains a non-finite value."
|
"The gravity-displacement-force displacement variation "
|
||||||
);
|
"contains a non-finite value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector baseDensityLocal;
|
mfem::Vector baseDensityLocal;
|
||||||
@@ -318,23 +293,27 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needsBaseGravityGradient) {
|
if (needsBaseGravityGradient) {
|
||||||
true_to_local(*f.gravityFluxFes, *baseGravityGradientTrue, baseGravityGradientLocal);
|
true_to_local(*f.gravityFluxFes, *baseGravityGradientTrue,
|
||||||
|
baseGravityGradientLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsGravityGradientVariation) {
|
if (needsGravityGradientVariation) {
|
||||||
true_to_local(*f.gravityFluxFes, *gravityGradientVariationTrue, gravityGradientVariationLocal);
|
true_to_local(*f.gravityFluxFes, *gravityGradientVariationTrue,
|
||||||
|
gravityGradientVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
true_to_local(*f.displacementFes, *displacementVariationTrue,
|
||||||
|
displacementVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||||
localAction = 0.0;
|
localAction = 0.0;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
mean_field::mapping::DomainMapper::Workspace workspace(
|
||||||
|
f.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Array<int> densityDofs;
|
mfem::Array<int> densityDofs;
|
||||||
mfem::Array<int> gravityGradientDofs;
|
mfem::Array<int> gravityGradientDofs;
|
||||||
@@ -365,31 +344,35 @@ namespace {
|
|||||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||||
|
|
||||||
const int dimension = f.mesh->Dimension();
|
const int dimension = f.mesh->Dimension();
|
||||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
|
||||||
|
|
||||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
const mfem::Ordering::Type displacementOrdering =
|
||||||
|
f.displacementFes->GetOrdering();
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
f.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(transformation != nullptr,
|
||||||
transformation != nullptr, "The gravity-displacement-force kernel received a null "
|
"The gravity-displacement-force kernel received a null "
|
||||||
"element transformation."
|
"element transformation.");
|
||||||
);
|
|
||||||
|
|
||||||
if (transformation->Attribute == vacuumAttribute) {
|
if (is_vacuum_attribute(transformation->Attribute)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &gravityGradientElement = *f.gravityFluxFes->GetFE(elementId);
|
const mfem::FiniteElement &gravityGradientElement =
|
||||||
|
*f.gravityFluxFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
const mfem::FiniteElement &displacementElement =
|
||||||
|
*f.displacementFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
const mfem::FiniteElement &compactificationElement =
|
||||||
|
*f.compactificationFes->GetFE(elementId);
|
||||||
|
|
||||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
mfem::DofTransformation *densityDofTransformation =
|
||||||
|
f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||||
|
|
||||||
mfem::DofTransformation *gravityGradientDofTransformation =
|
mfem::DofTransformation *gravityGradientDofTransformation =
|
||||||
f.gravityFluxFes->GetElementVDofs(elementId, gravityGradientDofs);
|
f.gravityFluxFes->GetElementVDofs(elementId, gravityGradientDofs);
|
||||||
@@ -409,20 +392,24 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needsBaseGravityGradient) {
|
if (needsBaseGravityGradient) {
|
||||||
baseGravityGradientLocal.GetSubVector(gravityGradientDofs, elementBaseGravityGradient);
|
baseGravityGradientLocal.GetSubVector(gravityGradientDofs,
|
||||||
|
elementBaseGravityGradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsGravityGradientVariation) {
|
if (needsGravityGradientVariation) {
|
||||||
gravityGradientVariationLocal.GetSubVector(gravityGradientDofs, elementGravityGradientVariation);
|
gravityGradientVariationLocal.GetSubVector(
|
||||||
|
gravityGradientDofs, elementGravityGradientVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
displacementVariationLocal.GetSubVector(displacementDofs,
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
f.compactificationCoordinate->GetSubVector(compactificationDofs,
|
||||||
|
elementCompactification);
|
||||||
|
|
||||||
if (densityDofTransformation != nullptr) {
|
if (densityDofTransformation != nullptr) {
|
||||||
if (needsBaseDensity) {
|
if (needsBaseDensity) {
|
||||||
@@ -436,11 +423,13 @@ namespace {
|
|||||||
|
|
||||||
if (gravityGradientDofTransformation != nullptr) {
|
if (gravityGradientDofTransformation != nullptr) {
|
||||||
if (needsBaseGravityGradient) {
|
if (needsBaseGravityGradient) {
|
||||||
gravityGradientDofTransformation->InvTransformPrimal(elementBaseGravityGradient);
|
gravityGradientDofTransformation->InvTransformPrimal(
|
||||||
|
elementBaseGravityGradient);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsGravityGradientVariation) {
|
if (needsGravityGradientVariation) {
|
||||||
gravityGradientDofTransformation->InvTransformPrimal(elementGravityGradientVariation);
|
gravityGradientDofTransformation->InvTransformPrimal(
|
||||||
|
elementGravityGradientVariation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,42 +437,42 @@ namespace {
|
|||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
displacementDofTransformation->InvTransformPrimal(
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compactificationDofTransformation != nullptr) {
|
if (compactificationDofTransformation != nullptr) {
|
||||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
compactificationDofTransformation->InvTransformPrimal(
|
||||||
|
elementCompactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
|
displacementElement, elementDisplacement);
|
||||||
|
|
||||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||||
compactificationElement, elementCompactification
|
compactificationElement, elementCompactification);
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::mapping::ElementMappingData mappingData{
|
const mean_field::mapping::ElementMappingData mappingData{
|
||||||
.displacement = displacementData, .compactification = compactificationData
|
.displacement = displacementData,
|
||||||
};
|
.compactification = compactificationData};
|
||||||
|
|
||||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
std::optional<mean_field::mapping::ElementDisplacementData>
|
||||||
|
displacementVariationData;
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
displacementVariationData.emplace(
|
displacementVariationData.emplace(
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
displacementElement, elementDisplacementVariation
|
displacementElement, elementDisplacementVariation));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementDofs.Size() ==
|
||||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
scalarDisplacementDofCount * dimension,
|
||||||
"The gravity-displacement-force element displacement vector "
|
"The gravity-displacement-force element displacement vector "
|
||||||
"has the wrong size."
|
"has the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
densityShape.SetSize(densityElement.GetDof());
|
densityShape.SetSize(densityElement.GetDof());
|
||||||
displacementShape.SetSize(scalarDisplacementDofCount);
|
displacementShape.SetSize(scalarDisplacementDofCount);
|
||||||
@@ -500,38 +489,42 @@ namespace {
|
|||||||
elementAction = 0.0;
|
elementAction = 0.0;
|
||||||
|
|
||||||
const mfem::IntegrationRule &integrationRule =
|
const mfem::IntegrationRule &integrationRule =
|
||||||
get_gravity_force_rule(f, densityElement, gravityGradientElement, displacementElement, *transformation);
|
get_gravity_force_rule(f, densityElement, gravityGradientElement,
|
||||||
|
displacementElement, *transformation);
|
||||||
|
|
||||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
for (int quadratureIndex = 0;
|
||||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||||
|
const mfem::IntegrationPoint &integrationPoint =
|
||||||
|
integrationRule.IntPoint(quadratureIndex);
|
||||||
|
|
||||||
transformation->SetIntPoint(&integrationPoint);
|
transformation->SetIntPoint(&integrationPoint);
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
const mean_field::mapping::MappingStatus mappingStatus =
|
||||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
domainMapper.EvaluateVolume(mappingData, *transformation,
|
||||||
);
|
integrationPoint, workspace,
|
||||||
|
mappingContext);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
|
||||||
"Stateless mapping failed in the gravity-displacement-"
|
"Stateless mapping failed in the gravity-displacement-"
|
||||||
"force kernel. Element: "
|
"force kernel. Element: "
|
||||||
<< elementId << ", attribute: " << transformation->Attribute
|
<< elementId
|
||||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
<< ", attribute: " << transformation->Attribute
|
||||||
);
|
<< ", quadrature point: " << quadratureIndex
|
||||||
|
<< ", status: " << static_cast<int>(mappingStatus));
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
const mean_field::mapping::MappingStatus variationStatus =
|
||||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
domainMapper.EvaluateVolumeVariation(
|
||||||
workspace, mappingVariation
|
mappingData, *displacementVariationData, *transformation,
|
||||||
);
|
integrationPoint, mappingContext, workspace, mappingVariation);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
"Stateless mapping variation failed in the gravity-"
|
"Stateless mapping variation failed in the gravity-"
|
||||||
"displacement-force kernel. Element: "
|
"displacement-force kernel. Element: "
|
||||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
<< elementId << ", attribute: " << transformation->Attribute
|
||||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
<< ", quadrature point: " << quadratureIndex
|
||||||
);
|
<< ", status: " << static_cast<int>(variationStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
densityElement.CalcShape(integrationPoint, densityShape);
|
densityElement.CalcShape(integrationPoint, densityShape);
|
||||||
@@ -552,27 +545,28 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (needsBaseGravityGradient) {
|
if (needsBaseGravityGradient) {
|
||||||
gravityGradientShape.MultTranspose(elementBaseGravityGradient, baseGravityReferenceValue);
|
gravityGradientShape.MultTranspose(elementBaseGravityGradient,
|
||||||
|
baseGravityReferenceValue);
|
||||||
|
|
||||||
mappingContext.mapping.mapping_jacobian.Mult(baseGravityReferenceValue, mappedBaseGravity);
|
mappingContext.mapping.mapping_jacobian.Mult(baseGravityReferenceValue,
|
||||||
|
mappedBaseGravity);
|
||||||
} else {
|
} else {
|
||||||
mappedBaseGravity = 0.0;
|
mappedBaseGravity = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsGravityGradientVariation) {
|
if (needsGravityGradientVariation) {
|
||||||
gravityGradientShape.MultTranspose(elementGravityGradientVariation, gravityVariationReferenceValue);
|
gravityGradientShape.MultTranspose(elementGravityGradientVariation,
|
||||||
|
gravityVariationReferenceValue);
|
||||||
|
|
||||||
mappingContext.mapping.mapping_jacobian.Mult(
|
mappingContext.mapping.mapping_jacobian.Mult(
|
||||||
gravityVariationReferenceValue, mappedGravityVariation
|
gravityVariationReferenceValue, mappedGravityVariation);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
mappedGravityVariation = 0.0;
|
mappedGravityVariation = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
mappingVariation.mapping.mapping_jacobian_variation.Mult(
|
mappingVariation.mapping.mapping_jacobian_variation.Mult(
|
||||||
baseGravityReferenceValue, mappedGeometryVariation
|
baseGravityReferenceValue, mappedGeometryVariation);
|
||||||
);
|
|
||||||
} else {
|
} else {
|
||||||
mappedGeometryVariation = 0.0;
|
mappedGeometryVariation = 0.0;
|
||||||
}
|
}
|
||||||
@@ -607,22 +601,24 @@ namespace {
|
|||||||
* differentiating the Piola map and physical volume weight,
|
* differentiating the Piola map and physical volume weight,
|
||||||
* but avoids a numerically pointless cancellation.
|
* but avoids a numerically pointless cancellation.
|
||||||
*/
|
*/
|
||||||
const double referenceWeight = integrationPoint.weight * transformation->Weight();
|
const double referenceWeight =
|
||||||
|
integrationPoint.weight * transformation->Weight();
|
||||||
|
|
||||||
forceValue *= referenceWeight;
|
forceValue *= referenceWeight;
|
||||||
|
|
||||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount;
|
||||||
|
++scalarDof) {
|
||||||
for (int component = 0; component < dimension; ++component) {
|
for (int component = 0; component < dimension; ++component) {
|
||||||
const int vectorDof = vector_dof_index(
|
const int vectorDof =
|
||||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
vector_dof_index(displacementOrdering, scalarDof, component,
|
||||||
);
|
scalarDisplacementDofCount, dimension);
|
||||||
|
|
||||||
const double contribution = displacementShape(scalarDof) * forceValue(component);
|
const double contribution =
|
||||||
|
displacementShape(scalarDof) * forceValue(component);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(contribution),
|
||||||
std::isfinite(contribution), "The gravity-displacement-force kernel "
|
"The gravity-displacement-force kernel "
|
||||||
"encountered a non-finite contribution."
|
"encountered a non-finite contribution.");
|
||||||
);
|
|
||||||
|
|
||||||
elementAction(vectorDof) += contribution;
|
elementAction(vectorDof) += contribution;
|
||||||
}
|
}
|
||||||
@@ -642,77 +638,61 @@ namespace {
|
|||||||
|
|
||||||
namespace mean_field::operators::kernels {
|
namespace mean_field::operators::kernels {
|
||||||
void apply_gravity_displacement_force_residual(
|
void apply_gravity_displacement_force_residual(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mfem::Vector &densityTrue, const mfem::Vector &gravityGradientTrue,
|
||||||
const mfem::Vector &densityTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &residualTrue) {
|
||||||
const mfem::Vector &gravityGradientTrue,
|
|
||||||
const mfem::Vector &displacementTrue,
|
|
||||||
mfem::Vector &residualTrue
|
|
||||||
) {
|
|
||||||
apply_gravity_displacement_force_action(
|
apply_gravity_displacement_force_action(
|
||||||
f, domainMapper, GravityDisplacementForceAction::residual, &densityTrue, nullptr, &gravityGradientTrue,
|
f, domainMapper, GravityDisplacementForceAction::residual, &densityTrue,
|
||||||
nullptr, nullptr, displacementTrue, residualTrue
|
nullptr, &gravityGradientTrue, nullptr, nullptr, displacementTrue,
|
||||||
);
|
residualTrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_gravity_displacement_force_density_action(
|
void apply_gravity_displacement_force_density_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &baseGravityGradientTrue,
|
const mfem::Vector &baseGravityGradientTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_gravity_displacement_force_action(
|
apply_gravity_displacement_force_action(
|
||||||
f, domainMapper, GravityDisplacementForceAction::density, nullptr, &densityVariationTrue,
|
f, domainMapper, GravityDisplacementForceAction::density, nullptr,
|
||||||
&baseGravityGradientTrue, nullptr, nullptr, displacementTrue, actionTrue
|
&densityVariationTrue, &baseGravityGradientTrue, nullptr, nullptr,
|
||||||
);
|
displacementTrue, actionTrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_gravity_displacement_force_gradient_action(
|
void apply_gravity_displacement_force_gradient_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &gravityGradientVariationTrue,
|
const mfem::Vector &gravityGradientVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_gravity_displacement_force_action(
|
apply_gravity_displacement_force_action(
|
||||||
f, domainMapper, GravityDisplacementForceAction::gravityGradient, &baseDensityTrue, nullptr, nullptr,
|
f, domainMapper, GravityDisplacementForceAction::gravityGradient,
|
||||||
&gravityGradientVariationTrue, nullptr, displacementTrue, actionTrue
|
&baseDensityTrue, nullptr, nullptr, &gravityGradientVariationTrue,
|
||||||
);
|
nullptr, displacementTrue, actionTrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_gravity_displacement_force_displacement_action(
|
void apply_gravity_displacement_force_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &baseGravityGradientTrue,
|
const mfem::Vector &baseGravityGradientTrue,
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_gravity_displacement_force_action(
|
apply_gravity_displacement_force_action(
|
||||||
f, domainMapper, GravityDisplacementForceAction::displacement, &baseDensityTrue, nullptr,
|
f, domainMapper, GravityDisplacementForceAction::displacement,
|
||||||
&baseGravityGradientTrue, nullptr, &displacementVariationTrue, displacementTrue, actionTrue
|
&baseDensityTrue, nullptr, &baseGravityGradientTrue, nullptr,
|
||||||
);
|
&displacementVariationTrue, displacementTrue, actionTrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_gravity_displacement_force_complete_action(
|
void apply_gravity_displacement_force_complete_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &baseGravityGradientTrue,
|
const mfem::Vector &baseGravityGradientTrue,
|
||||||
const mfem::Vector &gravityGradientVariationTrue,
|
const mfem::Vector &gravityGradientVariationTrue,
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_gravity_displacement_force_action(
|
apply_gravity_displacement_force_action(
|
||||||
f, domainMapper, GravityDisplacementForceAction::complete, &baseDensityTrue, &densityVariationTrue,
|
f, domainMapper, GravityDisplacementForceAction::complete,
|
||||||
&baseGravityGradientTrue, &gravityGradientVariationTrue, &displacementVariationTrue, displacementTrue,
|
&baseDensityTrue, &densityVariationTrue, &baseGravityGradientTrue,
|
||||||
actionTrue
|
&gravityGradientVariationTrue, &displacementVariationTrue,
|
||||||
);
|
displacementTrue, actionTrue);
|
||||||
}
|
}
|
||||||
} // namespace mean_field::operators::kernels
|
} // namespace mean_field::operators::kernels
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -11,16 +11,22 @@ module mean_field;
|
|||||||
import :operators.kernels.hydrostatic_equilibrium;
|
import :operators.kernels.hydrostatic_equilibrium;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void true_to_local(
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
|
||||||
const mfem::Vector &trueVector,
|
[[nodiscard]] bool is_vacuum_attribute(const int attribute) {
|
||||||
mfem::Vector &localVector
|
return DomainSchema::template attribute_belongs_to<
|
||||||
) {
|
mean_field::utils::domain::Vacuum>(attribute);
|
||||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
}
|
||||||
|
|
||||||
|
void true_to_local(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
|
const mfem::Vector &trueVector, mfem::Vector &localVector) {
|
||||||
|
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||||
|
"True vector has the wrong size.");
|
||||||
|
|
||||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->Mult(trueVector, localVector);
|
prolongation->Mult(trueVector, localVector);
|
||||||
@@ -29,18 +35,17 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void local_to_true(
|
void local_to_true(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
const mfem::Vector &localVector, mfem::Vector &trueVector) {
|
||||||
const mfem::Vector &localVector,
|
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(),
|
||||||
mfem::Vector &trueVector
|
"Local vector has the wrong size.");
|
||||||
) {
|
|
||||||
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(), "Local vector has the wrong size.");
|
|
||||||
|
|
||||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||||
|
|
||||||
trueVector = 0.0;
|
trueVector = 0.0;
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->MultTranspose(localVector, trueVector);
|
prolongation->MultTranspose(localVector, trueVector);
|
||||||
@@ -51,100 +56,93 @@ namespace {
|
|||||||
|
|
||||||
void validate_fem(
|
void validate_fem(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper
|
const mean_field::mapping::DomainMapper &domainMapper) {
|
||||||
) {
|
|
||||||
MFEM_VERIFY(f.mesh != nullptr, "The hydrostatic kernel requires a mesh.");
|
MFEM_VERIFY(f.mesh != nullptr, "The hydrostatic kernel requires a mesh.");
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.enthalpyFes != nullptr, "The hydrostatic kernel requires the "
|
||||||
f.enthalpyFes != nullptr, "The hydrostatic kernel requires the "
|
"enthalpy finite-element space.");
|
||||||
"enthalpy finite-element space."
|
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.gravityPotentialFes != nullptr,
|
||||||
f.gravityPotentialFes != nullptr, "The hydrostatic kernel requires the "
|
"The hydrostatic kernel requires the "
|
||||||
"gravity-potential finite-element space."
|
"gravity-potential finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes != nullptr,
|
||||||
f.displacementFes != nullptr, "The hydrostatic kernel requires the "
|
"The hydrostatic kernel requires the "
|
||||||
"displacement finite-element space."
|
"displacement finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.compactificationFes != nullptr,
|
||||||
f.compactificationFes != nullptr, "The hydrostatic kernel requires the "
|
"The hydrostatic kernel requires the "
|
||||||
"compactification finite-element space."
|
"compactification finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.compactificationCoordinate != nullptr,
|
||||||
f.compactificationCoordinate != nullptr, "The hydrostatic kernel requires the "
|
"The hydrostatic kernel requires the "
|
||||||
"compactification coordinate."
|
"compactification coordinate.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.quadratureFactory != nullptr,
|
||||||
f.quadratureFactory != nullptr, "The hydrostatic kernel requires the "
|
"The hydrostatic kernel requires the "
|
||||||
"quadrature-rule factory."
|
"quadrature-rule factory.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.mesh->Dimension() == 3,
|
||||||
f.mesh->Dimension() == 3, "The rigid-rotation hydrostatic kernel "
|
"The rigid-rotation hydrostatic kernel "
|
||||||
"currently requires a three-dimensional mesh."
|
"currently requires a three-dimensional mesh.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The domain-mapper dimension does not match "
|
"The domain-mapper dimension does not match "
|
||||||
"the mesh dimension."
|
"the mesh dimension.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::IntegrationRule &get_hydrostatic_rule(
|
const mfem::IntegrationRule &
|
||||||
const mean_field::fem::FEM &f,
|
get_hydrostatic_rule(const mean_field::fem::FEM &f,
|
||||||
const mfem::FiniteElement &enthalpyElement,
|
const mfem::FiniteElement &enthalpyElement,
|
||||||
const mfem::FiniteElement &potentialElement,
|
const mfem::FiniteElement &potentialElement,
|
||||||
const mfem::ElementTransformation &transformation
|
const mfem::ElementTransformation &transformation) {
|
||||||
) {
|
|
||||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(enthalpyElement.GetOrder() ==
|
||||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||||
"The hydrostatic test element does not match "
|
"The hydrostatic test element does not match "
|
||||||
"the registered enthalpy field."
|
"the registered enthalpy field.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(potentialElement.GetOrder() ==
|
||||||
potentialElement.GetOrder() == mean_field::field::Gravity::Potential::familyOrder,
|
mean_field::field::Gravity::Potential::familyOrder,
|
||||||
"The hydrostatic potential element does not "
|
"The hydrostatic potential element does not "
|
||||||
"match the registered gravity-potential field."
|
"match the registered gravity-potential field.");
|
||||||
);
|
|
||||||
|
|
||||||
const auto enthalpyQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumEnthalpy>(
|
const auto enthalpyQuery = EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
mean_field::field::Enthalpy::Form::EquilibriumEnthalpy>(
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
);
|
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const auto gravityQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumGravity>(
|
const auto gravityQuery = EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
mean_field::field::Enthalpy::Form::EquilibriumGravity>(
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
);
|
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const auto rotationQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumRotation>(
|
const auto rotationQuery = EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), std::array<int, 1>{2},
|
mean_field::field::Enthalpy::Form::EquilibriumRotation>(
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
);
|
transformation.OrderW(), std::array<int, 1>{2},
|
||||||
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const auto constantQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumConstant>(
|
const auto constantQuery = EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
mean_field::field::Enthalpy::Form::EquilibriumConstant>(
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
);
|
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
int integrationOrder = 0;
|
int integrationOrder = 0;
|
||||||
|
|
||||||
const auto update_order = [&f, &transformation, &integrationOrder](const mean_field::quadrature::Query &query) {
|
const auto update_order = [&f, &transformation, &integrationOrder](
|
||||||
const auto rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
const mean_field::quadrature::Query &query) {
|
||||||
|
const auto rule =
|
||||||
|
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(rule.integration_rule != nullptr,
|
||||||
rule.integration_rule != nullptr, "The quadrature policy did not return "
|
"The quadrature policy did not return "
|
||||||
"a hydrostatic-equilibrium rule."
|
"a hydrostatic-equilibrium rule.");
|
||||||
);
|
|
||||||
|
|
||||||
integrationOrder = std::max(integrationOrder, rule.resolution.order);
|
integrationOrder = std::max(integrationOrder, rule.resolution.order);
|
||||||
};
|
};
|
||||||
@@ -175,74 +173,66 @@ namespace {
|
|||||||
|
|
||||||
void assemble_hydrostatic_form(
|
void assemble_hydrostatic_form(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
const HydrostaticAssemblyRequest &request,
|
const HydrostaticAssemblyRequest &request, mfem::Vector &result) {
|
||||||
mfem::Vector &result
|
|
||||||
) {
|
|
||||||
validate_fem(f, domainMapper);
|
validate_fem(f, domainMapper);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(), "The hydrostatic displacement vector has "
|
"The hydrostatic displacement vector has "
|
||||||
"the wrong size."
|
"the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(std::isfinite(request.bernoulliConstant), "The Bernoulli constant is non-finite.");
|
MFEM_VERIFY(std::isfinite(request.bernoulliConstant),
|
||||||
|
"The Bernoulli constant is non-finite.");
|
||||||
|
|
||||||
MFEM_VERIFY(std::isfinite(request.constantVariation), "The Bernoulli-constant variation is non-finite.");
|
MFEM_VERIFY(std::isfinite(request.constantVariation),
|
||||||
|
"The Bernoulli-constant variation is non-finite.");
|
||||||
|
|
||||||
const bool requiresBaseState = request.buildResidual || request.displacementVariationTrue != nullptr;
|
const bool requiresBaseState =
|
||||||
|
request.buildResidual || request.displacementVariationTrue != nullptr;
|
||||||
|
|
||||||
if (requiresBaseState) {
|
if (requiresBaseState) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.rotation != nullptr,
|
||||||
request.rotation != nullptr, "The hydrostatic residual or geometry "
|
"The hydrostatic residual or geometry "
|
||||||
"action requires the rotation model."
|
"action requires the rotation model.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.baseEnthalpyTrue != nullptr,
|
||||||
request.baseEnthalpyTrue != nullptr, "The hydrostatic residual or geometry "
|
"The hydrostatic residual or geometry "
|
||||||
"action requires the base enthalpy."
|
"action requires the base enthalpy.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.basePotentialTrue != nullptr,
|
||||||
request.basePotentialTrue != nullptr, "The hydrostatic residual or geometry "
|
"The hydrostatic residual or geometry "
|
||||||
"action requires the base potential."
|
"action requires the base potential.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.baseEnthalpyTrue != nullptr) {
|
if (request.baseEnthalpyTrue != nullptr) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.baseEnthalpyTrue->Size() ==
|
||||||
request.baseEnthalpyTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
f.enthalpyFes->GetTrueVSize(),
|
||||||
"The base enthalpy vector has the wrong size."
|
"The base enthalpy vector has the wrong size.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.basePotentialTrue != nullptr) {
|
if (request.basePotentialTrue != nullptr) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.basePotentialTrue->Size() ==
|
||||||
request.basePotentialTrue->Size() == f.gravityPotentialFes->GetTrueVSize(),
|
f.gravityPotentialFes->GetTrueVSize(),
|
||||||
"The base potential vector has the wrong size."
|
"The base potential vector has the wrong size.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.enthalpyVariationTrue != nullptr) {
|
if (request.enthalpyVariationTrue != nullptr) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.enthalpyVariationTrue->Size() ==
|
||||||
request.enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
f.enthalpyFes->GetTrueVSize(),
|
||||||
"The enthalpy variation has the wrong size."
|
"The enthalpy variation has the wrong size.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.potentialVariationTrue != nullptr) {
|
if (request.potentialVariationTrue != nullptr) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.potentialVariationTrue->Size() ==
|
||||||
request.potentialVariationTrue->Size() == f.gravityPotentialFes->GetTrueVSize(),
|
f.gravityPotentialFes->GetTrueVSize(),
|
||||||
"The potential variation has the wrong size."
|
"The potential variation has the wrong size.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.displacementVariationTrue != nullptr) {
|
if (request.displacementVariationTrue != nullptr) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(request.displacementVariationTrue->Size() ==
|
||||||
request.displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
f.displacementFes->GetTrueVSize(),
|
||||||
"The displacement variation has the wrong size."
|
"The displacement variation has the wrong size.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector displacementLocal;
|
mfem::Vector displacementLocal;
|
||||||
@@ -259,26 +249,31 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request.basePotentialTrue != nullptr) {
|
if (request.basePotentialTrue != nullptr) {
|
||||||
true_to_local(*f.gravityPotentialFes, *request.basePotentialTrue, basePotentialLocal);
|
true_to_local(*f.gravityPotentialFes, *request.basePotentialTrue,
|
||||||
|
basePotentialLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.enthalpyVariationTrue != nullptr) {
|
if (request.enthalpyVariationTrue != nullptr) {
|
||||||
true_to_local(*f.enthalpyFes, *request.enthalpyVariationTrue, enthalpyVariationLocal);
|
true_to_local(*f.enthalpyFes, *request.enthalpyVariationTrue,
|
||||||
|
enthalpyVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.potentialVariationTrue != nullptr) {
|
if (request.potentialVariationTrue != nullptr) {
|
||||||
true_to_local(*f.gravityPotentialFes, *request.potentialVariationTrue, potentialVariationLocal);
|
true_to_local(*f.gravityPotentialFes, *request.potentialVariationTrue,
|
||||||
|
potentialVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.displacementVariationTrue != nullptr) {
|
if (request.displacementVariationTrue != nullptr) {
|
||||||
true_to_local(*f.displacementFes, *request.displacementVariationTrue, displacementVariationLocal);
|
true_to_local(*f.displacementFes, *request.displacementVariationTrue,
|
||||||
|
displacementVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector localResult(f.enthalpyFes->GetVSize());
|
mfem::Vector localResult(f.enthalpyFes->GetVSize());
|
||||||
|
|
||||||
localResult = 0.0;
|
localResult = 0.0;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
mean_field::mapping::DomainMapper::Workspace workspace(
|
||||||
|
f.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Array<int> enthalpyDofs;
|
mfem::Array<int> enthalpyDofs;
|
||||||
mfem::Array<int> potentialDofs;
|
mfem::Array<int> potentialDofs;
|
||||||
@@ -297,29 +292,32 @@ namespace {
|
|||||||
mfem::Vector enthalpyShape;
|
mfem::Vector enthalpyShape;
|
||||||
mfem::Vector potentialShape;
|
mfem::Vector potentialShape;
|
||||||
|
|
||||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
f.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(transformation != nullptr,
|
||||||
transformation != nullptr, "The hydrostatic kernel received a null "
|
"The hydrostatic kernel received a null "
|
||||||
"element transformation."
|
"element transformation.");
|
||||||
);
|
|
||||||
|
|
||||||
if (transformation->Attribute == vacuumAttribute) {
|
if (is_vacuum_attribute(transformation->Attribute)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
const mfem::FiniteElement &enthalpyElement =
|
||||||
|
*f.enthalpyFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &potentialElement = *f.gravityPotentialFes->GetFE(elementId);
|
const mfem::FiniteElement &potentialElement =
|
||||||
|
*f.gravityPotentialFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
const mfem::FiniteElement &displacementElement =
|
||||||
|
*f.displacementFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
const mfem::FiniteElement &compactificationElement =
|
||||||
|
*f.compactificationFes->GetFE(elementId);
|
||||||
|
|
||||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
mfem::DofTransformation *enthalpyDofTransformation =
|
||||||
|
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||||
|
|
||||||
mfem::DofTransformation *potentialDofTransformation =
|
mfem::DofTransformation *potentialDofTransformation =
|
||||||
f.gravityPotentialFes->GetElementDofs(elementId, potentialDofs);
|
f.gravityPotentialFes->GetElementDofs(elementId, potentialDofs);
|
||||||
@@ -332,7 +330,8 @@ namespace {
|
|||||||
|
|
||||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||||
|
|
||||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
f.compactificationCoordinate->GetSubVector(compactificationDofs,
|
||||||
|
elementCompactification);
|
||||||
|
|
||||||
if (request.baseEnthalpyTrue != nullptr) {
|
if (request.baseEnthalpyTrue != nullptr) {
|
||||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||||
@@ -343,15 +342,18 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request.enthalpyVariationTrue != nullptr) {
|
if (request.enthalpyVariationTrue != nullptr) {
|
||||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
enthalpyVariationLocal.GetSubVector(enthalpyDofs,
|
||||||
|
elementEnthalpyVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.potentialVariationTrue != nullptr) {
|
if (request.potentialVariationTrue != nullptr) {
|
||||||
potentialVariationLocal.GetSubVector(potentialDofs, elementPotentialVariation);
|
potentialVariationLocal.GetSubVector(potentialDofs,
|
||||||
|
elementPotentialVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.displacementVariationTrue != nullptr) {
|
if (request.displacementVariationTrue != nullptr) {
|
||||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
displacementVariationLocal.GetSubVector(displacementDofs,
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (enthalpyDofTransformation != nullptr) {
|
if (enthalpyDofTransformation != nullptr) {
|
||||||
@@ -370,7 +372,8 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (request.potentialVariationTrue != nullptr) {
|
if (request.potentialVariationTrue != nullptr) {
|
||||||
potentialDofTransformation->InvTransformPrimal(elementPotentialVariation);
|
potentialDofTransformation->InvTransformPrimal(
|
||||||
|
elementPotentialVariation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -378,33 +381,34 @@ namespace {
|
|||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||||
|
|
||||||
if (request.displacementVariationTrue != nullptr) {
|
if (request.displacementVariationTrue != nullptr) {
|
||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
displacementDofTransformation->InvTransformPrimal(
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compactificationDofTransformation != nullptr) {
|
if (compactificationDofTransformation != nullptr) {
|
||||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
compactificationDofTransformation->InvTransformPrimal(
|
||||||
|
elementCompactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
|
displacementElement, elementDisplacement);
|
||||||
|
|
||||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||||
compactificationElement, elementCompactification
|
compactificationElement, elementCompactification);
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::mapping::ElementMappingData mappingData{
|
const mean_field::mapping::ElementMappingData mappingData{
|
||||||
.displacement = displacementData, .compactification = compactificationData
|
.displacement = displacementData,
|
||||||
};
|
.compactification = compactificationData};
|
||||||
|
|
||||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
std::optional<mean_field::mapping::ElementDisplacementData>
|
||||||
|
displacementVariationData;
|
||||||
|
|
||||||
if (request.displacementVariationTrue != nullptr) {
|
if (request.displacementVariationTrue != nullptr) {
|
||||||
displacementVariationData.emplace(
|
displacementVariationData.emplace(
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
displacementElement, elementDisplacementVariation
|
displacementElement, elementDisplacementVariation));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
elementResult.SetSize(enthalpyElement.GetDof());
|
elementResult.SetSize(enthalpyElement.GetDof());
|
||||||
@@ -415,27 +419,28 @@ namespace {
|
|||||||
|
|
||||||
potentialShape.SetSize(potentialElement.GetDof());
|
potentialShape.SetSize(potentialElement.GetDof());
|
||||||
|
|
||||||
const mfem::IntegrationRule &integrationRule =
|
const mfem::IntegrationRule &integrationRule = get_hydrostatic_rule(
|
||||||
get_hydrostatic_rule(f, enthalpyElement, potentialElement, *transformation);
|
f, enthalpyElement, potentialElement, *transformation);
|
||||||
|
|
||||||
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
for (int quadraturePoint = 0;
|
||||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
||||||
|
const mfem::IntegrationPoint &integrationPoint =
|
||||||
|
integrationRule.IntPoint(quadraturePoint);
|
||||||
|
|
||||||
transformation->SetIntPoint(&integrationPoint);
|
transformation->SetIntPoint(&integrationPoint);
|
||||||
|
|
||||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
const mean_field::mapping::MappingStatus mappingStatus =
|
||||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
domainMapper.EvaluateVolume(mappingData, *transformation,
|
||||||
);
|
integrationPoint, workspace,
|
||||||
|
mappingContext);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
|
||||||
"The base mapping is invalid in the "
|
"The base mapping is invalid in the "
|
||||||
"hydrostatic kernel. Element: "
|
"hydrostatic kernel. Element: "
|
||||||
<< elementId << ", quadrature point: " << quadraturePoint
|
<< elementId << ", quadrature point: " << quadraturePoint
|
||||||
<< ", status: " << static_cast<int>(mappingStatus)
|
<< ", status: " << static_cast<int>(mappingStatus));
|
||||||
);
|
|
||||||
|
|
||||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||||
|
|
||||||
@@ -448,14 +453,16 @@ namespace {
|
|||||||
|
|
||||||
const double potentialValue = elementBasePotential * potentialShape;
|
const double potentialValue = elementBasePotential * potentialShape;
|
||||||
|
|
||||||
const double rotationPotential =
|
const double rotationPotential = request.rotation->potential(
|
||||||
request.rotation->potential(mappingContext.mapping.physical_position);
|
mappingContext.mapping.physical_position);
|
||||||
|
|
||||||
baseIntegrand = enthalpyValue + potentialValue - rotationPotential - request.bernoulliConstant;
|
baseIntegrand = enthalpyValue + potentialValue - rotationPotential -
|
||||||
|
request.bernoulliConstant;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (request.buildResidual) {
|
if (request.buildResidual) {
|
||||||
elementResult.Add(mappingContext.quadrature.weight * baseIntegrand, enthalpyShape);
|
elementResult.Add(mappingContext.quadrature.weight * baseIntegrand,
|
||||||
|
enthalpyShape);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -470,27 +477,29 @@ namespace {
|
|||||||
materialVariation += elementPotentialVariation * potentialShape;
|
materialVariation += elementPotentialVariation * potentialShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
double weightedVariation = mappingContext.quadrature.weight * materialVariation;
|
double weightedVariation =
|
||||||
|
mappingContext.quadrature.weight * materialVariation;
|
||||||
|
|
||||||
if (request.displacementVariationTrue != nullptr) {
|
if (request.displacementVariationTrue != nullptr) {
|
||||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
const mean_field::mapping::MappingStatus variationStatus =
|
||||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
domainMapper.EvaluateVolumeVariation(
|
||||||
workspace, mappingVariation
|
mappingData, *displacementVariationData, *transformation,
|
||||||
);
|
integrationPoint, mappingContext, workspace, mappingVariation);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(variationStatus ==
|
||||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
mean_field::mapping::MappingStatus::valid,
|
||||||
"The mapping variation is invalid "
|
"The mapping variation is invalid "
|
||||||
"in the hydrostatic kernel."
|
"in the hydrostatic kernel.");
|
||||||
);
|
|
||||||
|
|
||||||
const double rotationVariation = request.rotation->potential_directional_derivative(
|
const double rotationVariation =
|
||||||
mappingContext.mapping.physical_position, mappingVariation.mapping.physical_position_variation
|
request.rotation->potential_directional_derivative(
|
||||||
);
|
mappingContext.mapping.physical_position,
|
||||||
|
mappingVariation.mapping.physical_position_variation);
|
||||||
|
|
||||||
weightedVariation += baseIntegrand * mappingVariation.weight_variation -
|
weightedVariation +=
|
||||||
|
baseIntegrand * mappingVariation.weight_variation -
|
||||||
rotationVariation * mappingContext.quadrature.weight;
|
rotationVariation * mappingContext.quadrature.weight;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,15 +519,10 @@ namespace {
|
|||||||
|
|
||||||
namespace mean_field::operators::kernels {
|
namespace mean_field::operators::kernels {
|
||||||
void apply_hydrostatic_equilibrium(
|
void apply_hydrostatic_equilibrium(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const physics::RigidRotation &rotation, const mfem::Vector &enthalpyTrue,
|
||||||
const physics::RigidRotation &rotation,
|
const mfem::Vector &potentialTrue, const mfem::Vector &displacementTrue,
|
||||||
const mfem::Vector &enthalpyTrue,
|
const double bernoulliConstant, mfem::Vector &residual) {
|
||||||
const mfem::Vector &potentialTrue,
|
|
||||||
const mfem::Vector &displacementTrue,
|
|
||||||
const double bernoulliConstant,
|
|
||||||
mfem::Vector &residual
|
|
||||||
) {
|
|
||||||
HydrostaticAssemblyRequest request;
|
HydrostaticAssemblyRequest request;
|
||||||
|
|
||||||
request.rotation = &rotation;
|
request.rotation = &rotation;
|
||||||
@@ -527,16 +531,14 @@ namespace mean_field::operators::kernels {
|
|||||||
request.bernoulliConstant = bernoulliConstant;
|
request.bernoulliConstant = bernoulliConstant;
|
||||||
request.buildResidual = true;
|
request.buildResidual = true;
|
||||||
|
|
||||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, residual);
|
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request,
|
||||||
|
residual);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_hydrostatic_equilibrium_enthalpy_action(
|
void apply_hydrostatic_equilibrium_enthalpy_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const mfem::Vector &enthalpyVariationTrue,
|
const mfem::Vector &enthalpyVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &action) {
|
||||||
mfem::Vector &action
|
|
||||||
) {
|
|
||||||
HydrostaticAssemblyRequest request;
|
HydrostaticAssemblyRequest request;
|
||||||
|
|
||||||
request.enthalpyVariationTrue = &enthalpyVariationTrue;
|
request.enthalpyVariationTrue = &enthalpyVariationTrue;
|
||||||
@@ -545,12 +547,9 @@ namespace mean_field::operators::kernels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void apply_hydrostatic_equilibrium_potential_action(
|
void apply_hydrostatic_equilibrium_potential_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const mfem::Vector &potentialVariationTrue,
|
const mfem::Vector &potentialVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &action) {
|
||||||
mfem::Vector &action
|
|
||||||
) {
|
|
||||||
HydrostaticAssemblyRequest request;
|
HydrostaticAssemblyRequest request;
|
||||||
|
|
||||||
request.potentialVariationTrue = &potentialVariationTrue;
|
request.potentialVariationTrue = &potentialVariationTrue;
|
||||||
@@ -559,12 +558,9 @@ namespace mean_field::operators::kernels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void apply_hydrostatic_equilibrium_constant_action(
|
void apply_hydrostatic_equilibrium_constant_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const double constantVariation, const mfem::Vector &displacementTrue,
|
||||||
const double constantVariation,
|
mfem::Vector &action) {
|
||||||
const mfem::Vector &displacementTrue,
|
|
||||||
mfem::Vector &action
|
|
||||||
) {
|
|
||||||
HydrostaticAssemblyRequest request;
|
HydrostaticAssemblyRequest request;
|
||||||
|
|
||||||
request.constantVariation = constantVariation;
|
request.constantVariation = constantVariation;
|
||||||
@@ -573,16 +569,12 @@ namespace mean_field::operators::kernels {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void apply_hydrostatic_equilibrium_displacement_action(
|
void apply_hydrostatic_equilibrium_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue, const mfem::Vector &basePotentialTrue,
|
||||||
const mfem::Vector &basePotentialTrue,
|
|
||||||
const mfem::Vector &baseDisplacementTrue,
|
const mfem::Vector &baseDisplacementTrue,
|
||||||
const double baseBernoulliConstant,
|
const double baseBernoulliConstant,
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue, mfem::Vector &action) {
|
||||||
mfem::Vector &action
|
|
||||||
) {
|
|
||||||
HydrostaticAssemblyRequest request;
|
HydrostaticAssemblyRequest request;
|
||||||
|
|
||||||
request.rotation = &rotation;
|
request.rotation = &rotation;
|
||||||
@@ -591,23 +583,19 @@ namespace mean_field::operators::kernels {
|
|||||||
request.displacementVariationTrue = &displacementVariationTrue;
|
request.displacementVariationTrue = &displacementVariationTrue;
|
||||||
request.bernoulliConstant = baseBernoulliConstant;
|
request.bernoulliConstant = baseBernoulliConstant;
|
||||||
|
|
||||||
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request, action);
|
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request,
|
||||||
|
action);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_hydrostatic_equilibrium_action(
|
void apply_hydrostatic_equilibrium_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue, const mfem::Vector &basePotentialTrue,
|
||||||
const mfem::Vector &basePotentialTrue,
|
|
||||||
const mfem::Vector &baseDisplacementTrue,
|
const mfem::Vector &baseDisplacementTrue,
|
||||||
const double baseBernoulliConstant,
|
const double baseBernoulliConstant,
|
||||||
const mfem::Vector &enthalpyVariationTrue,
|
const mfem::Vector &enthalpyVariationTrue,
|
||||||
const mfem::Vector &potentialVariationTrue,
|
const mfem::Vector &potentialVariationTrue, const double constantVariation,
|
||||||
const double constantVariation,
|
const mfem::Vector &displacementVariationTrue, mfem::Vector &action) {
|
||||||
const mfem::Vector &displacementVariationTrue,
|
|
||||||
mfem::Vector &action
|
|
||||||
) {
|
|
||||||
HydrostaticAssemblyRequest request;
|
HydrostaticAssemblyRequest request;
|
||||||
|
|
||||||
request.rotation = &rotation;
|
request.rotation = &rotation;
|
||||||
@@ -619,6 +607,7 @@ namespace mean_field::operators::kernels {
|
|||||||
request.bernoulliConstant = baseBernoulliConstant;
|
request.bernoulliConstant = baseBernoulliConstant;
|
||||||
request.constantVariation = constantVariation;
|
request.constantVariation = constantVariation;
|
||||||
|
|
||||||
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request, action);
|
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request,
|
||||||
|
action);
|
||||||
}
|
}
|
||||||
} // namespace mean_field::operators::kernels
|
} // namespace mean_field::operators::kernels
|
||||||
@@ -12,20 +12,24 @@ module mean_field;
|
|||||||
import :operators.kernels.pressure_force;
|
import :operators.kernels.pressure_force;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
|
[[nodiscard]] bool is_vacuum_attribute(const int attribute) {
|
||||||
|
return DomainSchema::template attribute_belongs_to<
|
||||||
|
mean_field::utils::domain::Vacuum>(attribute);
|
||||||
|
}
|
||||||
|
|
||||||
enum class PressureForceAction { residual, enthalpy, displacement };
|
enum class PressureForceAction { residual, enthalpy, displacement };
|
||||||
|
|
||||||
void true_to_local(
|
void true_to_local(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
const mfem::Vector &trueVector, mfem::Vector &localVector) {
|
||||||
const mfem::Vector &trueVector,
|
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||||
mfem::Vector &localVector
|
"The pressure-force true vector has the wrong size.");
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
|
||||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(), "The pressure-force true vector has the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->Mult(trueVector, localVector);
|
prolongation->Mult(trueVector, localVector);
|
||||||
@@ -34,19 +38,16 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void local_to_true(
|
void local_to_true(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
const mfem::Vector &localVector, mfem::Vector &trueVector) {
|
||||||
const mfem::Vector &localVector,
|
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(),
|
||||||
mfem::Vector &trueVector
|
"The pressure-force local vector has the wrong size.");
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
|
||||||
localVector.Size() == finiteElementSpace.GetVSize(), "The pressure-force local vector has the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||||
trueVector = 0.0;
|
trueVector = 0.0;
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->MultTranspose(localVector, trueVector);
|
prolongation->MultTranspose(localVector, trueVector);
|
||||||
@@ -55,13 +56,10 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] int vector_dof_index(
|
[[nodiscard]] int vector_dof_index(const mfem::Ordering::Type ordering,
|
||||||
const mfem::Ordering::Type ordering,
|
const int scalarDof, const int component,
|
||||||
const int scalarDof,
|
|
||||||
const int component,
|
|
||||||
const int scalarDofCount,
|
const int scalarDofCount,
|
||||||
const int dimension
|
const int dimension) {
|
||||||
) {
|
|
||||||
if (ordering == mfem::Ordering::byNODES) {
|
if (ordering == mfem::Ordering::byNODES) {
|
||||||
return scalarDof + component * scalarDofCount;
|
return scalarDof + component * scalarDofCount;
|
||||||
}
|
}
|
||||||
@@ -74,7 +72,8 @@ namespace {
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] int get_pressure_extra_order(const mean_field::eos::Polytrope &barotrope) {
|
[[nodiscard]] int
|
||||||
|
get_pressure_extra_order(const mean_field::eos::Polytrope &barotrope) {
|
||||||
/*
|
/*
|
||||||
* Pressure has the enthalpy dependence
|
* Pressure has the enthalpy dependence
|
||||||
*
|
*
|
||||||
@@ -85,108 +84,92 @@ namespace {
|
|||||||
* contribution is therefore n times that order.
|
* contribution is therefore n times that order.
|
||||||
*/
|
*/
|
||||||
const double extraOrder =
|
const double extraOrder =
|
||||||
barotrope.polytropic_index() * static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
barotrope.polytropic_index() *
|
||||||
|
static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(extraOrder) && extraOrder >= 0.0 &&
|
||||||
std::isfinite(extraOrder) && extraOrder >= 0.0 &&
|
extraOrder <=
|
||||||
extraOrder <= static_cast<double>(std::numeric_limits<int>::max()),
|
static_cast<double>(std::numeric_limits<int>::max()),
|
||||||
"The pressure EOS effective polynomial order is invalid."
|
"The pressure EOS effective polynomial order is invalid.");
|
||||||
);
|
|
||||||
|
|
||||||
return static_cast<int>(std::ceil(extraOrder));
|
return static_cast<int>(std::ceil(extraOrder));
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const mfem::IntegrationRule &get_pressure_force_rule(
|
[[nodiscard]] const mfem::IntegrationRule &
|
||||||
const mean_field::fem::FEM &f,
|
get_pressure_force_rule(const mean_field::fem::FEM &f,
|
||||||
const mean_field::eos::Polytrope &barotrope,
|
const mean_field::eos::Polytrope &barotrope,
|
||||||
const mfem::FiniteElement &enthalpyElement,
|
const mfem::FiniteElement &enthalpyElement,
|
||||||
const mfem::FiniteElement &displacementElement,
|
const mfem::FiniteElement &displacementElement,
|
||||||
const mfem::ElementTransformation &transformation
|
const mfem::ElementTransformation &transformation) {
|
||||||
) {
|
|
||||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(enthalpyElement.GetOrder() ==
|
||||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||||
"The pressure-force enthalpy element does not match the "
|
"The pressure-force enthalpy element does not match the "
|
||||||
"registered enthalpy field."
|
"registered enthalpy field.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementElement.GetOrder() ==
|
||||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
mean_field::field::Displacement::Vector::familyOrder,
|
||||||
"The pressure-force test element does not match the "
|
"The pressure-force test element does not match the "
|
||||||
"registered displacement field."
|
"registered displacement field.");
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::quadrature::Query query =
|
const mean_field::quadrature::Query query = EnthalpyField::make_query<
|
||||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureForce>(
|
mean_field::field::Enthalpy::Form::PressureForce>(
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(),
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
std::array<int, 1>{get_pressure_extra_order(barotrope)}, mean_field::utils::DOMAINS::STELLAR,
|
transformation.OrderW(),
|
||||||
mean_field::quadrature::MappingKind::general
|
std::array<int, 1>{get_pressure_extra_order(barotrope)},
|
||||||
);
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const mean_field::quadrature::MfemRule rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
const mean_field::quadrature::MfemRule rule =
|
||||||
|
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(rule.integration_rule != nullptr,
|
||||||
rule.integration_rule != nullptr, "The quadrature policy did not return a pressure-force "
|
"The quadrature policy did not return a pressure-force "
|
||||||
"integration rule."
|
"integration rule.");
|
||||||
);
|
|
||||||
|
|
||||||
return *rule.integration_rule;
|
return *rule.integration_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_inputs(
|
void validate_inputs(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &enthalpyTrue,
|
const mfem::Vector &enthalpyTrue, const mfem::Vector &displacementTrue) {
|
||||||
const mfem::Vector &displacementTrue
|
|
||||||
) {
|
|
||||||
MFEM_VERIFY(f.mesh != nullptr, "The pressure-force kernel requires a mesh.");
|
MFEM_VERIFY(f.mesh != nullptr, "The pressure-force kernel requires a mesh.");
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.enthalpyFes != nullptr,
|
||||||
f.enthalpyFes != nullptr, "The pressure-force kernel requires the enthalpy "
|
"The pressure-force kernel requires the enthalpy "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes != nullptr,
|
||||||
f.displacementFes != nullptr, "The pressure-force kernel requires the displacement "
|
"The pressure-force kernel requires the displacement "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.compactificationFes != nullptr,
|
||||||
f.compactificationFes != nullptr, "The pressure-force kernel requires the compactification "
|
"The pressure-force kernel requires the compactification "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.compactificationCoordinate != nullptr,
|
||||||
f.compactificationCoordinate != nullptr, "The pressure-force kernel requires the compactification "
|
"The pressure-force kernel requires the compactification "
|
||||||
"coordinate."
|
"coordinate.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.quadratureFactory != nullptr,
|
||||||
f.quadratureFactory != nullptr, "The pressure-force kernel requires the quadrature "
|
"The pressure-force kernel requires the quadrature "
|
||||||
"rule factory."
|
"rule factory.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(enthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(),
|
||||||
enthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(),
|
"The pressure-force enthalpy vector has the wrong size.");
|
||||||
"The pressure-force enthalpy vector has the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
"The pressure-force displacement vector has the wrong size.");
|
||||||
"The pressure-force displacement vector has the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
|
||||||
"The pressure-force domain-mapper dimension does not match "
|
"The pressure-force domain-mapper dimension does not match "
|
||||||
"the mesh dimension."
|
"the mesh dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||||
f.displacementFes->GetVDim() == f.mesh->Dimension(), "The displacement vector dimension does not match the "
|
"The displacement vector dimension does not match the "
|
||||||
"mesh dimension."
|
"mesh dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ElementDisplacementDataFromElementVDofs currently consumes the
|
* ElementDisplacementDataFromElementVDofs currently consumes the
|
||||||
@@ -194,40 +177,35 @@ namespace {
|
|||||||
* registry change fails immediately rather than silently
|
* registry change fails immediately rather than silently
|
||||||
* corrupting the geometry.
|
* corrupting the geometry.
|
||||||
*/
|
*/
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes->GetOrdering() == mfem::Ordering::byNODES,
|
||||||
f.displacementFes->GetOrdering() == mfem::Ordering::byNODES,
|
|
||||||
"The pressure-force kernel requires the registered byNODES "
|
"The pressure-force kernel requires the registered byNODES "
|
||||||
"displacement ordering."
|
"displacement ordering.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_pressure_force_action(
|
void apply_pressure_force_action(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mean_field::eos::Polytrope &barotrope,
|
const mean_field::eos::Polytrope &barotrope,
|
||||||
const PressureForceAction pressureForceAction,
|
const PressureForceAction pressureForceAction,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
const mfem::Vector *enthalpyVariationTrue,
|
const mfem::Vector *enthalpyVariationTrue,
|
||||||
const mfem::Vector *displacementVariationTrue,
|
const mfem::Vector *displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
validate_inputs(f, domainMapper, baseEnthalpyTrue, displacementTrue);
|
validate_inputs(f, domainMapper, baseEnthalpyTrue, displacementTrue);
|
||||||
|
|
||||||
if (pressureForceAction == PressureForceAction::enthalpy) {
|
if (pressureForceAction == PressureForceAction::enthalpy) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(enthalpyVariationTrue != nullptr &&
|
||||||
enthalpyVariationTrue != nullptr && enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
enthalpyVariationTrue->Size() ==
|
||||||
"The pressure-force enthalpy variation has the wrong size."
|
f.enthalpyFes->GetTrueVSize(),
|
||||||
);
|
"The pressure-force enthalpy variation has the wrong size.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pressureForceAction == PressureForceAction::displacement) {
|
if (pressureForceAction == PressureForceAction::displacement) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementVariationTrue != nullptr &&
|
||||||
displacementVariationTrue != nullptr &&
|
displacementVariationTrue->Size() ==
|
||||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
f.displacementFes->GetTrueVSize(),
|
||||||
"The pressure-force displacement variation has the wrong "
|
"The pressure-force displacement variation has the wrong "
|
||||||
"size."
|
"size.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector baseEnthalpyLocal;
|
mfem::Vector baseEnthalpyLocal;
|
||||||
@@ -238,19 +216,22 @@ namespace {
|
|||||||
true_to_local(*f.enthalpyFes, baseEnthalpyTrue, baseEnthalpyLocal);
|
true_to_local(*f.enthalpyFes, baseEnthalpyTrue, baseEnthalpyLocal);
|
||||||
|
|
||||||
if (enthalpyVariationTrue != nullptr) {
|
if (enthalpyVariationTrue != nullptr) {
|
||||||
true_to_local(*f.enthalpyFes, *enthalpyVariationTrue, enthalpyVariationLocal);
|
true_to_local(*f.enthalpyFes, *enthalpyVariationTrue,
|
||||||
|
enthalpyVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||||
|
|
||||||
if (displacementVariationTrue != nullptr) {
|
if (displacementVariationTrue != nullptr) {
|
||||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
true_to_local(*f.displacementFes, *displacementVariationTrue,
|
||||||
|
displacementVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||||
localAction = 0.0;
|
localAction = 0.0;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
mean_field::mapping::DomainMapper::Workspace workspace(
|
||||||
|
f.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Array<int> enthalpyDofsofs;
|
mfem::Array<int> enthalpyDofsofs;
|
||||||
mfem::Array<int> displacementDofs;
|
mfem::Array<int> displacementDofs;
|
||||||
@@ -273,33 +254,37 @@ namespace {
|
|||||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||||
|
|
||||||
const int dimension = f.mesh->Dimension();
|
const int dimension = f.mesh->Dimension();
|
||||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
|
||||||
|
|
||||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
const mfem::Ordering::Type displacementOrdering =
|
||||||
|
f.displacementFes->GetOrdering();
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
f.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(transformation != nullptr,
|
||||||
transformation != nullptr, "The pressure-force kernel received a null element "
|
"The pressure-force kernel received a null element "
|
||||||
"transformation."
|
"transformation.");
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Skip vacuum before constructing or evaluating any mapping
|
* Skip vacuum before constructing or evaluating any mapping
|
||||||
* data for the element.
|
* data for the element.
|
||||||
*/
|
*/
|
||||||
if (transformation->Attribute == vacuumAttribute) {
|
if (is_vacuum_attribute(transformation->Attribute)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
const mfem::FiniteElement &enthalpyElement =
|
||||||
|
*f.enthalpyFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
const mfem::FiniteElement &displacementElement =
|
||||||
|
*f.displacementFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
const mfem::FiniteElement &compactificationElement =
|
||||||
|
*f.compactificationFes->GetFE(elementId);
|
||||||
|
|
||||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
mfem::DofTransformation *enthalpyDofTransformation =
|
||||||
|
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||||
|
|
||||||
mfem::DofTransformation *displacementDofTransformation =
|
mfem::DofTransformation *displacementDofTransformation =
|
||||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||||
@@ -310,16 +295,19 @@ namespace {
|
|||||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||||
|
|
||||||
if (enthalpyVariationTrue != nullptr) {
|
if (enthalpyVariationTrue != nullptr) {
|
||||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
enthalpyVariationLocal.GetSubVector(enthalpyDofs,
|
||||||
|
elementEnthalpyVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||||
|
|
||||||
if (displacementVariationTrue != nullptr) {
|
if (displacementVariationTrue != nullptr) {
|
||||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
displacementVariationLocal.GetSubVector(displacementDofs,
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
f.compactificationCoordinate->GetSubVector(compactificationDofs,
|
||||||
|
elementCompactification);
|
||||||
|
|
||||||
if (enthalpyDofTransformation != nullptr) {
|
if (enthalpyDofTransformation != nullptr) {
|
||||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||||
@@ -333,42 +321,42 @@ namespace {
|
|||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||||
|
|
||||||
if (displacementVariationTrue != nullptr) {
|
if (displacementVariationTrue != nullptr) {
|
||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
displacementDofTransformation->InvTransformPrimal(
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compactificationDofTransformation != nullptr) {
|
if (compactificationDofTransformation != nullptr) {
|
||||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
compactificationDofTransformation->InvTransformPrimal(
|
||||||
|
elementCompactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
|
displacementElement, elementDisplacement);
|
||||||
|
|
||||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||||
compactificationElement, elementCompactification
|
compactificationElement, elementCompactification);
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::mapping::ElementMappingData mappingData{
|
const mean_field::mapping::ElementMappingData mappingData{
|
||||||
.displacement = displacementData, .compactification = compactificationData
|
.displacement = displacementData,
|
||||||
};
|
.compactification = compactificationData};
|
||||||
|
|
||||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
std::optional<mean_field::mapping::ElementDisplacementData>
|
||||||
|
displacementVariationData;
|
||||||
|
|
||||||
if (displacementVariationTrue != nullptr) {
|
if (displacementVariationTrue != nullptr) {
|
||||||
displacementVariationData.emplace(
|
displacementVariationData.emplace(
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
displacementElement, elementDisplacementVariation
|
displacementElement, elementDisplacementVariation));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementDofs.Size() ==
|
||||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
scalarDisplacementDofCount * dimension,
|
||||||
"The pressure-force element displacement vector has "
|
"The pressure-force element displacement vector has "
|
||||||
"the wrong size."
|
"the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||||
|
|
||||||
@@ -376,30 +364,34 @@ namespace {
|
|||||||
|
|
||||||
displacementDShapePhysical.SetSize(scalarDisplacementDofCount, dimension);
|
displacementDShapePhysical.SetSize(scalarDisplacementDofCount, dimension);
|
||||||
|
|
||||||
displacementDShapePhysicalVariation.SetSize(scalarDisplacementDofCount, dimension);
|
displacementDShapePhysicalVariation.SetSize(scalarDisplacementDofCount,
|
||||||
|
dimension);
|
||||||
|
|
||||||
elementAction.SetSize(displacementDofs.Size());
|
elementAction.SetSize(displacementDofs.Size());
|
||||||
elementAction = 0.0;
|
elementAction = 0.0;
|
||||||
|
|
||||||
const mfem::IntegrationRule &integrationRule =
|
const mfem::IntegrationRule &integrationRule = get_pressure_force_rule(
|
||||||
get_pressure_force_rule(f, barotrope, enthalpyElement, displacementElement, *transformation);
|
f, barotrope, enthalpyElement, displacementElement, *transformation);
|
||||||
|
|
||||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
for (int quadratureIndex = 0;
|
||||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||||
|
const mfem::IntegrationPoint &integrationPoint =
|
||||||
|
integrationRule.IntPoint(quadratureIndex);
|
||||||
|
|
||||||
transformation->SetIntPoint(&integrationPoint);
|
transformation->SetIntPoint(&integrationPoint);
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
const mean_field::mapping::MappingStatus mappingStatus =
|
||||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
domainMapper.EvaluateVolume(mappingData, *transformation,
|
||||||
);
|
integrationPoint, workspace,
|
||||||
|
mappingContext);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
|
||||||
"Stateless mapping failed in the pressure-force "
|
"Stateless mapping failed in the pressure-force "
|
||||||
"kernel. Element: "
|
"kernel. Element: "
|
||||||
<< elementId << ", attribute: " << transformation->Attribute
|
<< elementId
|
||||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
<< ", attribute: " << transformation->Attribute
|
||||||
);
|
<< ", quadrature point: " << quadratureIndex
|
||||||
|
<< ", status: " << static_cast<int>(mappingStatus));
|
||||||
|
|
||||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||||
|
|
||||||
@@ -411,13 +403,16 @@ namespace {
|
|||||||
pressureForceAction == PressureForceAction::displacement) {
|
pressureForceAction == PressureForceAction::displacement) {
|
||||||
pressureFactor = barotrope.pressure_from_enthalpy(enthalpyValue);
|
pressureFactor = barotrope.pressure_from_enthalpy(enthalpyValue);
|
||||||
} else {
|
} else {
|
||||||
const double enthalpyVariationValue = elementEnthalpyVariation * enthalpyShape;
|
const double enthalpyVariationValue =
|
||||||
|
elementEnthalpyVariation * enthalpyShape;
|
||||||
|
|
||||||
pressureFactor =
|
pressureFactor =
|
||||||
barotrope.pressure_derivative_from_enthalpy(enthalpyValue) * enthalpyVariationValue;
|
barotrope.pressure_derivative_from_enthalpy(enthalpyValue) *
|
||||||
|
enthalpyVariationValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
displacementElement.CalcDShape(integrationPoint, displacementDShapeReference);
|
displacementElement.CalcDShape(integrationPoint,
|
||||||
|
displacementDShapeReference);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Row i of DShape is grad_reference(N_i). Multiplication
|
* Row i of DShape is grad_reference(N_i). Multiplication
|
||||||
@@ -426,25 +421,27 @@ namespace {
|
|||||||
* grad_physical(N_i)
|
* grad_physical(N_i)
|
||||||
* = grad_reference(N_i) J^{-1}.
|
* = grad_reference(N_i) J^{-1}.
|
||||||
*/
|
*/
|
||||||
mfem::Mult(displacementDShapeReference, mappingContext.quadrature.J_inv, displacementDShapePhysical);
|
mfem::Mult(displacementDShapeReference, mappingContext.quadrature.J_inv,
|
||||||
|
displacementDShapePhysical);
|
||||||
|
|
||||||
std::optional<mean_field::mapping::VolumeMappingVariation> mappingVariation;
|
std::optional<mean_field::mapping::VolumeMappingVariation>
|
||||||
|
mappingVariation;
|
||||||
|
|
||||||
if (pressureForceAction == PressureForceAction::displacement) {
|
if (pressureForceAction == PressureForceAction::displacement) {
|
||||||
mappingVariation.emplace();
|
mappingVariation.emplace();
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
const mean_field::mapping::MappingStatus variationStatus =
|
||||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
domainMapper.EvaluateVolumeVariation(
|
||||||
workspace, *mappingVariation
|
mappingData, *displacementVariationData, *transformation,
|
||||||
);
|
integrationPoint, mappingContext, workspace, *mappingVariation);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
"Stateless mapping variation failed in the "
|
"Stateless mapping variation failed in the "
|
||||||
"pressure-force kernel. Element: "
|
"pressure-force kernel. Element: "
|
||||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
<< elementId << ", attribute: " << transformation->Attribute
|
||||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
<< ", quadrature point: " << quadratureIndex
|
||||||
);
|
<< ", status: " << static_cast<int>(variationStatus));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Differentiating
|
* Differentiating
|
||||||
@@ -455,19 +452,18 @@ namespace {
|
|||||||
* test-gradient variation used by the geometric
|
* test-gradient variation used by the geometric
|
||||||
* pressure block.
|
* pressure block.
|
||||||
*/
|
*/
|
||||||
mfem::Mult(
|
mfem::Mult(displacementDShapeReference,
|
||||||
displacementDShapeReference, mappingVariation->inverse_element_jacobian_variation,
|
mappingVariation->inverse_element_jacobian_variation,
|
||||||
displacementDShapePhysicalVariation
|
displacementDShapePhysicalVariation);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const double weightedPressureFactor = pressureFactor * mappingContext.quadrature.weight;
|
const double weightedPressureFactor =
|
||||||
|
pressureFactor * mappingContext.quadrature.weight;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(pressureFactor) &&
|
||||||
std::isfinite(pressureFactor) && std::isfinite(weightedPressureFactor),
|
std::isfinite(weightedPressureFactor),
|
||||||
"The pressure-force kernel encountered a non-finite "
|
"The pressure-force kernel encountered a non-finite "
|
||||||
"quadrature value."
|
"quadrature value.");
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For the vector basis N_i e_c,
|
* For the vector basis N_i e_c,
|
||||||
@@ -479,11 +475,12 @@ namespace {
|
|||||||
* R_(i,c)
|
* R_(i,c)
|
||||||
* = -integral P partial_c N_i dV.
|
* = -integral P partial_c N_i dV.
|
||||||
*/
|
*/
|
||||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount;
|
||||||
|
++scalarDof) {
|
||||||
for (int component = 0; component < dimension; ++component) {
|
for (int component = 0; component < dimension; ++component) {
|
||||||
const int vectorDof = vector_dof_index(
|
const int vectorDof =
|
||||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
vector_dof_index(displacementOrdering, scalarDof, component,
|
||||||
);
|
scalarDisplacementDofCount, dimension);
|
||||||
|
|
||||||
if (pressureForceAction == PressureForceAction::displacement) {
|
if (pressureForceAction == PressureForceAction::displacement) {
|
||||||
/*
|
/*
|
||||||
@@ -497,20 +494,22 @@ namespace {
|
|||||||
const double gradientWeightVariation =
|
const double gradientWeightVariation =
|
||||||
mappingContext.quadrature.weight *
|
mappingContext.quadrature.weight *
|
||||||
displacementDShapePhysicalVariation(scalarDof, component) +
|
displacementDShapePhysicalVariation(scalarDof, component) +
|
||||||
mappingVariation->weight_variation * displacementDShapePhysical(scalarDof, component);
|
mappingVariation->weight_variation *
|
||||||
|
displacementDShapePhysical(scalarDof, component);
|
||||||
|
|
||||||
const double contribution = pressureFactor * gradientWeightVariation;
|
const double contribution =
|
||||||
|
pressureFactor * gradientWeightVariation;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(gradientWeightVariation) &&
|
||||||
std::isfinite(gradientWeightVariation) && std::isfinite(contribution),
|
std::isfinite(contribution),
|
||||||
"The pressure-force geometry action "
|
"The pressure-force geometry action "
|
||||||
"encountered a non-finite contribution."
|
"encountered a non-finite contribution.");
|
||||||
);
|
|
||||||
|
|
||||||
elementAction(vectorDof) -= contribution;
|
elementAction(vectorDof) -= contribution;
|
||||||
} else {
|
} else {
|
||||||
elementAction(vectorDof) -=
|
elementAction(vectorDof) -=
|
||||||
weightedPressureFactor * displacementDShapePhysical(scalarDof, component);
|
weightedPressureFactor *
|
||||||
|
displacementDShapePhysical(scalarDof, component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -529,46 +528,33 @@ namespace {
|
|||||||
|
|
||||||
namespace mean_field::operators::kernels {
|
namespace mean_field::operators::kernels {
|
||||||
void apply_pressure_force_residual(
|
void apply_pressure_force_residual(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const eos::Polytrope &barotrope, const mfem::Vector &enthalpyTrue,
|
||||||
const eos::Polytrope &barotrope,
|
const mfem::Vector &displacementTrue, mfem::Vector &residualTrue) {
|
||||||
const mfem::Vector &enthalpyTrue,
|
apply_pressure_force_action(f, domainMapper, barotrope,
|
||||||
const mfem::Vector &displacementTrue,
|
PressureForceAction::residual, enthalpyTrue,
|
||||||
mfem::Vector &residualTrue
|
nullptr, nullptr, displacementTrue, residualTrue);
|
||||||
) {
|
|
||||||
apply_pressure_force_action(
|
|
||||||
f, domainMapper, barotrope, PressureForceAction::residual, enthalpyTrue, nullptr, nullptr, displacementTrue,
|
|
||||||
residualTrue
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_pressure_force_enthalpy_action(
|
void apply_pressure_force_enthalpy_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const eos::Polytrope &barotrope, const mfem::Vector &baseEnthalpyTrue,
|
||||||
const eos::Polytrope &barotrope,
|
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
|
||||||
const mfem::Vector &enthalpyVariationTrue,
|
const mfem::Vector &enthalpyVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
apply_pressure_force_action(f, domainMapper, barotrope,
|
||||||
) {
|
PressureForceAction::enthalpy, baseEnthalpyTrue,
|
||||||
apply_pressure_force_action(
|
&enthalpyVariationTrue, nullptr, displacementTrue,
|
||||||
f, domainMapper, barotrope, PressureForceAction::enthalpy, baseEnthalpyTrue, &enthalpyVariationTrue,
|
actionTrue);
|
||||||
nullptr, displacementTrue, actionTrue
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_pressure_force_displacement_action(
|
void apply_pressure_force_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const eos::Polytrope &barotrope, const mfem::Vector &baseEnthalpyTrue,
|
||||||
const eos::Polytrope &barotrope,
|
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_pressure_force_action(
|
apply_pressure_force_action(
|
||||||
f, domainMapper, barotrope, PressureForceAction::displacement, baseEnthalpyTrue, nullptr,
|
f, domainMapper, barotrope, PressureForceAction::displacement,
|
||||||
&displacementVariationTrue, displacementTrue, actionTrue
|
baseEnthalpyTrue, nullptr, &displacementVariationTrue, displacementTrue,
|
||||||
);
|
actionTrue);
|
||||||
}
|
}
|
||||||
} // namespace mean_field::operators::kernels
|
} // namespace mean_field::operators::kernels
|
||||||
|
|||||||
@@ -11,22 +11,30 @@ module mean_field;
|
|||||||
import :operators.kernels.rotational_displacement_force;
|
import :operators.kernels.rotational_displacement_force;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
enum class RotationalDisplacementForceAction { residual, density, displacement, complete };
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
void true_to_local(
|
[[nodiscard]] bool is_vacuum_attribute(const int attribute) {
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
return DomainSchema::template attribute_belongs_to<
|
||||||
const mfem::Vector &trueVector,
|
mean_field::utils::domain::Vacuum>(attribute);
|
||||||
mfem::Vector &localVector
|
}
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
enum class RotationalDisplacementForceAction {
|
||||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
residual,
|
||||||
|
density,
|
||||||
|
displacement,
|
||||||
|
complete
|
||||||
|
};
|
||||||
|
|
||||||
|
void true_to_local(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
|
const mfem::Vector &trueVector, mfem::Vector &localVector) {
|
||||||
|
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||||
"The rotational-displacement-force true vector has the wrong "
|
"The rotational-displacement-force true vector has the wrong "
|
||||||
"size."
|
"size.");
|
||||||
);
|
|
||||||
|
|
||||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->Mult(trueVector, localVector);
|
prolongation->Mult(trueVector, localVector);
|
||||||
@@ -35,21 +43,17 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void local_to_true(
|
void local_to_true(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
const mfem::Vector &localVector, mfem::Vector &trueVector) {
|
||||||
const mfem::Vector &localVector,
|
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(),
|
||||||
mfem::Vector &trueVector
|
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
|
||||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
|
||||||
"The rotational-displacement-force local vector has the wrong "
|
"The rotational-displacement-force local vector has the wrong "
|
||||||
"size."
|
"size.");
|
||||||
);
|
|
||||||
|
|
||||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||||
trueVector = 0.0;
|
trueVector = 0.0;
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->MultTranspose(localVector, trueVector);
|
prolongation->MultTranspose(localVector, trueVector);
|
||||||
@@ -58,13 +62,10 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] int vector_dof_index(
|
[[nodiscard]] int vector_dof_index(const mfem::Ordering::Type ordering,
|
||||||
const mfem::Ordering::Type ordering,
|
const int scalarDof, const int component,
|
||||||
const int scalarDof,
|
|
||||||
const int component,
|
|
||||||
const int scalarDofCount,
|
const int scalarDofCount,
|
||||||
const int dimension
|
const int dimension) {
|
||||||
) {
|
|
||||||
if (ordering == mfem::Ordering::byNODES) {
|
if (ordering == mfem::Ordering::byNODES) {
|
||||||
return scalarDof + component * scalarDofCount;
|
return scalarDof + component * scalarDofCount;
|
||||||
}
|
}
|
||||||
@@ -73,58 +74,52 @@ namespace {
|
|||||||
return scalarDof * dimension + component;
|
return scalarDof * dimension + component;
|
||||||
}
|
}
|
||||||
|
|
||||||
MFEM_ABORT(
|
MFEM_ABORT("The rotational-displacement-force test space uses an "
|
||||||
"The rotational-displacement-force test space uses an "
|
"unsupported ordering.");
|
||||||
"unsupported ordering."
|
|
||||||
);
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] const mfem::IntegrationRule &get_rotation_force_rule(
|
[[nodiscard]] const mfem::IntegrationRule &
|
||||||
const mean_field::fem::FEM &f,
|
get_rotation_force_rule(const mean_field::fem::FEM &f,
|
||||||
const mfem::FiniteElement &densityElement,
|
const mfem::FiniteElement &densityElement,
|
||||||
const mfem::FiniteElement &displacementElement,
|
const mfem::FiniteElement &displacementElement,
|
||||||
const mfem::ElementTransformation &transformation
|
const mfem::ElementTransformation &transformation) {
|
||||||
) {
|
using DisplacementField =
|
||||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
mean_field::field::Field<mean_field::field::Displacement>;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(densityElement.GetOrder() ==
|
||||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
mean_field::field::Density::Scalar::familyOrder,
|
||||||
"The rotational-displacement-force density element does not "
|
"The rotational-displacement-force density element does not "
|
||||||
"match the registered density field."
|
"match the registered density field.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementElement.GetOrder() ==
|
||||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
mean_field::field::Displacement::Vector::familyOrder,
|
||||||
"The rotational-displacement-force test element does not match "
|
"The rotational-displacement-force test element does not match "
|
||||||
"the registered displacement field."
|
"the registered displacement field.");
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* grad(Psi_rotation) is linear in physical position, so it adds one
|
* grad(Psi_rotation) is linear in physical position, so it adds one
|
||||||
* dynamic polynomial-order contribution.
|
* dynamic polynomial-order contribution.
|
||||||
*/
|
*/
|
||||||
const mean_field::quadrature::Query query =
|
const mean_field::quadrature::Query query = DisplacementField::make_query<
|
||||||
DisplacementField::make_query<mean_field::field::Displacement::Form::CentrifugalForce>(
|
mean_field::field::Displacement::Form::CentrifugalForce>(
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), std::array<int, 1>{1},
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
transformation.OrderW(), std::array<int, 1>{1},
|
||||||
);
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const mean_field::quadrature::MfemRule rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
const mean_field::quadrature::MfemRule rule =
|
||||||
|
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(rule.integration_rule != nullptr,
|
||||||
rule.integration_rule != nullptr, "The quadrature policy did not return a rotational-"
|
"The quadrature policy did not return a rotational-"
|
||||||
"displacement-force integration rule."
|
"displacement-force integration rule.");
|
||||||
);
|
|
||||||
|
|
||||||
return *rule.integration_rule;
|
return *rule.integration_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_finite_vector(
|
void validate_finite_vector(const mfem::Vector &vector, const char *message) {
|
||||||
const mfem::Vector &vector,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
for (int index = 0; index < vector.Size(); ++index) {
|
for (int index = 0; index < vector.Size(); ++index) {
|
||||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||||
}
|
}
|
||||||
@@ -132,127 +127,111 @@ namespace {
|
|||||||
|
|
||||||
void validate_common_inputs(
|
void validate_common_inputs(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &displacementTrue
|
const mfem::Vector &displacementTrue) {
|
||||||
) {
|
MFEM_VERIFY(f.mesh != nullptr,
|
||||||
MFEM_VERIFY(f.mesh != nullptr, "The rotational-displacement-force kernel requires a mesh.");
|
"The rotational-displacement-force kernel requires a mesh.");
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.mesh->Dimension() == 3,
|
||||||
f.mesh->Dimension() == 3, "The rotational-displacement-force kernel requires a "
|
"The rotational-displacement-force kernel requires a "
|
||||||
"three-dimensional mesh."
|
"three-dimensional mesh.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.densityFes != nullptr,
|
||||||
f.densityFes != nullptr, "The rotational-displacement-force kernel requires the density "
|
"The rotational-displacement-force kernel requires the density "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes != nullptr,
|
||||||
f.displacementFes != nullptr, "The rotational-displacement-force kernel requires the "
|
|
||||||
"displacement finite-element space."
|
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.compactificationFes != nullptr && f.compactificationCoordinate != nullptr,
|
|
||||||
"The rotational-displacement-force kernel requires the "
|
"The rotational-displacement-force kernel requires the "
|
||||||
"compactification coordinate."
|
"displacement finite-element space.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.compactificationFes != nullptr &&
|
||||||
f.quadratureFactory != nullptr, "The rotational-displacement-force kernel requires the "
|
f.compactificationCoordinate != nullptr,
|
||||||
"quadrature-rule factory."
|
"The rotational-displacement-force kernel requires the "
|
||||||
);
|
"compactification coordinate.");
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.quadratureFactory != nullptr,
|
||||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
"The rotational-displacement-force kernel requires the "
|
||||||
|
"quadrature-rule factory.");
|
||||||
|
|
||||||
|
MFEM_VERIFY(displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||||
"The rotational-displacement-force displacement vector has the "
|
"The rotational-displacement-force displacement vector has the "
|
||||||
"wrong size."
|
"wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
|
||||||
"The rotational-displacement-force mapper dimension does not "
|
"The rotational-displacement-force mapper dimension does not "
|
||||||
"match the mesh dimension."
|
"match the mesh dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
|
||||||
"The rotational-displacement-force displacement dimension does "
|
"The rotational-displacement-force displacement dimension does "
|
||||||
"not match the mesh dimension."
|
"not match the mesh dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
displacementTrue, "The rotational-displacement-force displacement contains a "
|
displacementTrue,
|
||||||
"non-finite value."
|
"The rotational-displacement-force displacement contains a "
|
||||||
);
|
"non-finite value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_density(
|
void validate_density(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const mfem::Vector &density, const char *message) {
|
||||||
const mfem::Vector &density,
|
|
||||||
const char *message
|
|
||||||
) {
|
|
||||||
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
||||||
validate_finite_vector(density, message);
|
validate_finite_vector(density, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_rotational_displacement_force_action(
|
void apply_rotational_displacement_force_action(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mean_field::physics::RigidRotation &rotation,
|
const mean_field::physics::RigidRotation &rotation,
|
||||||
const RotationalDisplacementForceAction requestedAction,
|
const RotationalDisplacementForceAction requestedAction,
|
||||||
const mfem::Vector *baseDensityTrue,
|
const mfem::Vector *baseDensityTrue,
|
||||||
const mfem::Vector *densityVariationTrue,
|
const mfem::Vector *densityVariationTrue,
|
||||||
const mfem::Vector *displacementVariationTrue,
|
const mfem::Vector *displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||||
|
|
||||||
const bool needsBaseDensity = requestedAction == RotationalDisplacementForceAction::residual ||
|
const bool needsBaseDensity =
|
||||||
|
requestedAction == RotationalDisplacementForceAction::residual ||
|
||||||
requestedAction == RotationalDisplacementForceAction::displacement ||
|
requestedAction == RotationalDisplacementForceAction::displacement ||
|
||||||
requestedAction == RotationalDisplacementForceAction::complete;
|
requestedAction == RotationalDisplacementForceAction::complete;
|
||||||
|
|
||||||
const bool needsDensityVariation = requestedAction == RotationalDisplacementForceAction::density ||
|
const bool needsDensityVariation =
|
||||||
|
requestedAction == RotationalDisplacementForceAction::density ||
|
||||||
requestedAction == RotationalDisplacementForceAction::complete;
|
requestedAction == RotationalDisplacementForceAction::complete;
|
||||||
|
|
||||||
const bool needsDisplacementVariation = requestedAction == RotationalDisplacementForceAction::displacement ||
|
const bool needsDisplacementVariation =
|
||||||
|
requestedAction == RotationalDisplacementForceAction::displacement ||
|
||||||
requestedAction == RotationalDisplacementForceAction::complete;
|
requestedAction == RotationalDisplacementForceAction::complete;
|
||||||
|
|
||||||
if (needsBaseDensity) {
|
if (needsBaseDensity) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(baseDensityTrue != nullptr,
|
||||||
baseDensityTrue != nullptr, "The rotational-displacement-force action requires a base "
|
"The rotational-displacement-force action requires a base "
|
||||||
"density."
|
"density.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_density(f, *baseDensityTrue, "The rotational-displacement-force base density is invalid.");
|
validate_density(
|
||||||
|
f, *baseDensityTrue,
|
||||||
|
"The rotational-displacement-force base density is invalid.");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsDensityVariation) {
|
if (needsDensityVariation) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(densityVariationTrue != nullptr,
|
||||||
densityVariationTrue != nullptr, "The rotational-displacement-force action requires a "
|
"The rotational-displacement-force action requires a "
|
||||||
"density variation."
|
"density variation.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_density(
|
validate_density(f, *densityVariationTrue,
|
||||||
f, *densityVariationTrue,
|
|
||||||
"The rotational-displacement-force density variation is "
|
"The rotational-displacement-force density variation is "
|
||||||
"invalid."
|
"invalid.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementVariationTrue != nullptr &&
|
||||||
displacementVariationTrue != nullptr &&
|
displacementVariationTrue->Size() ==
|
||||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
f.displacementFes->GetTrueVSize(),
|
||||||
"The rotational-displacement-force displacement variation "
|
"The rotational-displacement-force displacement variation "
|
||||||
"is invalid."
|
"is invalid.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
*displacementVariationTrue, "The rotational-displacement-force displacement variation "
|
*displacementVariationTrue,
|
||||||
"contains a non-finite value."
|
"The rotational-displacement-force displacement variation "
|
||||||
);
|
"contains a non-finite value.");
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector baseDensityLocal;
|
mfem::Vector baseDensityLocal;
|
||||||
@@ -271,13 +250,15 @@ namespace {
|
|||||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
true_to_local(*f.displacementFes, *displacementVariationTrue,
|
||||||
|
displacementVariationLocal);
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||||
localAction = 0.0;
|
localAction = 0.0;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
mean_field::mapping::DomainMapper::Workspace workspace(
|
||||||
|
f.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Array<int> densityDofs;
|
mfem::Array<int> densityDofs;
|
||||||
mfem::Array<int> displacementDofs;
|
mfem::Array<int> displacementDofs;
|
||||||
@@ -302,29 +283,32 @@ namespace {
|
|||||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||||
|
|
||||||
const int dimension = f.mesh->Dimension();
|
const int dimension = f.mesh->Dimension();
|
||||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
|
||||||
|
|
||||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
const mfem::Ordering::Type displacementOrdering =
|
||||||
|
f.displacementFes->GetOrdering();
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
f.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(transformation != nullptr,
|
||||||
transformation != nullptr, "The rotational-displacement-force kernel received a null "
|
"The rotational-displacement-force kernel received a null "
|
||||||
"element transformation."
|
"element transformation.");
|
||||||
);
|
|
||||||
|
|
||||||
if (transformation->Attribute == vacuumAttribute) {
|
if (is_vacuum_attribute(transformation->Attribute)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
const mfem::FiniteElement &displacementElement =
|
||||||
|
*f.displacementFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
const mfem::FiniteElement &compactificationElement =
|
||||||
|
*f.compactificationFes->GetFE(elementId);
|
||||||
|
|
||||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
mfem::DofTransformation *densityDofTransformation =
|
||||||
|
f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||||
|
|
||||||
mfem::DofTransformation *displacementDofTransformation =
|
mfem::DofTransformation *displacementDofTransformation =
|
||||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||||
@@ -343,10 +327,12 @@ namespace {
|
|||||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
displacementVariationLocal.GetSubVector(displacementDofs,
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
f.compactificationCoordinate->GetSubVector(compactificationDofs,
|
||||||
|
elementCompactification);
|
||||||
|
|
||||||
if (densityDofTransformation != nullptr) {
|
if (densityDofTransformation != nullptr) {
|
||||||
if (needsBaseDensity) {
|
if (needsBaseDensity) {
|
||||||
@@ -362,42 +348,42 @@ namespace {
|
|||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
displacementDofTransformation->InvTransformPrimal(
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compactificationDofTransformation != nullptr) {
|
if (compactificationDofTransformation != nullptr) {
|
||||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
compactificationDofTransformation->InvTransformPrimal(
|
||||||
|
elementCompactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
|
displacementElement, elementDisplacement);
|
||||||
|
|
||||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||||
compactificationElement, elementCompactification
|
compactificationElement, elementCompactification);
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::mapping::ElementMappingData mappingData{
|
const mean_field::mapping::ElementMappingData mappingData{
|
||||||
.displacement = displacementData, .compactification = compactificationData
|
.displacement = displacementData,
|
||||||
};
|
.compactification = compactificationData};
|
||||||
|
|
||||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
std::optional<mean_field::mapping::ElementDisplacementData>
|
||||||
|
displacementVariationData;
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
displacementVariationData.emplace(
|
displacementVariationData.emplace(
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
displacementElement, elementDisplacementVariation
|
displacementElement, elementDisplacementVariation));
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementDofs.Size() ==
|
||||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
scalarDisplacementDofCount * dimension,
|
||||||
"The rotational-displacement-force element displacement "
|
"The rotational-displacement-force element displacement "
|
||||||
"vector has the wrong size."
|
"vector has the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
densityShape.SetSize(densityElement.GetDof());
|
densityShape.SetSize(densityElement.GetDof());
|
||||||
displacementShape.SetSize(scalarDisplacementDofCount);
|
displacementShape.SetSize(scalarDisplacementDofCount);
|
||||||
@@ -410,39 +396,42 @@ namespace {
|
|||||||
elementAction.SetSize(displacementDofs.Size());
|
elementAction.SetSize(displacementDofs.Size());
|
||||||
elementAction = 0.0;
|
elementAction = 0.0;
|
||||||
|
|
||||||
const mfem::IntegrationRule &integrationRule =
|
const mfem::IntegrationRule &integrationRule = get_rotation_force_rule(
|
||||||
get_rotation_force_rule(f, densityElement, displacementElement, *transformation);
|
f, densityElement, displacementElement, *transformation);
|
||||||
|
|
||||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
for (int quadratureIndex = 0;
|
||||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||||
|
const mfem::IntegrationPoint &integrationPoint =
|
||||||
|
integrationRule.IntPoint(quadratureIndex);
|
||||||
|
|
||||||
transformation->SetIntPoint(&integrationPoint);
|
transformation->SetIntPoint(&integrationPoint);
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
const mean_field::mapping::MappingStatus mappingStatus =
|
||||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
domainMapper.EvaluateVolume(mappingData, *transformation,
|
||||||
);
|
integrationPoint, workspace,
|
||||||
|
mappingContext);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
|
||||||
"Stateless mapping failed in the rotational-"
|
"Stateless mapping failed in the rotational-"
|
||||||
"displacement-force kernel. Element: "
|
"displacement-force kernel. Element: "
|
||||||
<< elementId << ", attribute: " << transformation->Attribute
|
<< elementId
|
||||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
<< ", attribute: " << transformation->Attribute
|
||||||
);
|
<< ", quadrature point: " << quadratureIndex
|
||||||
|
<< ", status: " << static_cast<int>(mappingStatus));
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
const mean_field::mapping::MappingStatus variationStatus =
|
||||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
domainMapper.EvaluateVolumeVariation(
|
||||||
workspace, mappingVariation
|
mappingData, *displacementVariationData, *transformation,
|
||||||
);
|
integrationPoint, mappingContext, workspace, mappingVariation);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
"Stateless mapping variation failed in the "
|
"Stateless mapping variation failed in the "
|
||||||
"rotational-displacement-force kernel. Element: "
|
"rotational-displacement-force kernel. Element: "
|
||||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
<< elementId << ", attribute: " << transformation->Attribute
|
||||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
<< ", quadrature point: " << quadratureIndex
|
||||||
);
|
<< ", status: " << static_cast<int>(variationStatus));
|
||||||
}
|
}
|
||||||
|
|
||||||
densityElement.CalcShape(integrationPoint, densityShape);
|
densityElement.CalcShape(integrationPoint, densityShape);
|
||||||
@@ -460,15 +449,16 @@ namespace {
|
|||||||
densityVariationValue = elementDensityVariation * densityShape;
|
densityVariationValue = elementDensityVariation * densityShape;
|
||||||
}
|
}
|
||||||
|
|
||||||
rotation.potential_gradient(mappingContext.mapping.physical_position, potentialGradient);
|
rotation.potential_gradient(mappingContext.mapping.physical_position,
|
||||||
|
potentialGradient);
|
||||||
|
|
||||||
centrifugalAcceleration = potentialGradient;
|
centrifugalAcceleration = potentialGradient;
|
||||||
centrifugalAcceleration *= -1.0;
|
centrifugalAcceleration *= -1.0;
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
rotation.potential_gradient_directional_derivative(
|
rotation.potential_gradient_directional_derivative(
|
||||||
mappingVariation.mapping.physical_position_variation, potentialGradientVariation
|
mappingVariation.mapping.physical_position_variation,
|
||||||
);
|
potentialGradientVariation);
|
||||||
|
|
||||||
centrifugalAccelerationVariation = potentialGradientVariation;
|
centrifugalAccelerationVariation = potentialGradientVariation;
|
||||||
|
|
||||||
@@ -480,37 +470,38 @@ namespace {
|
|||||||
weightedForce = 0.0;
|
weightedForce = 0.0;
|
||||||
|
|
||||||
if (requestedAction == RotationalDisplacementForceAction::residual) {
|
if (requestedAction == RotationalDisplacementForceAction::residual) {
|
||||||
weightedForce.Add(baseDensityValue * mappingContext.quadrature.weight, centrifugalAcceleration);
|
weightedForce.Add(baseDensityValue * mappingContext.quadrature.weight,
|
||||||
|
centrifugalAcceleration);
|
||||||
} else {
|
} else {
|
||||||
if (needsDensityVariation) {
|
if (needsDensityVariation) {
|
||||||
weightedForce.Add(
|
weightedForce.Add(densityVariationValue *
|
||||||
densityVariationValue * mappingContext.quadrature.weight, centrifugalAcceleration
|
mappingContext.quadrature.weight,
|
||||||
);
|
centrifugalAcceleration);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (needsDisplacementVariation) {
|
if (needsDisplacementVariation) {
|
||||||
weightedForce.Add(
|
weightedForce.Add(baseDensityValue * mappingContext.quadrature.weight,
|
||||||
baseDensityValue * mappingContext.quadrature.weight, centrifugalAccelerationVariation
|
centrifugalAccelerationVariation);
|
||||||
);
|
|
||||||
|
|
||||||
weightedForce.Add(
|
weightedForce.Add(baseDensityValue *
|
||||||
baseDensityValue * mappingVariation.weight_variation, centrifugalAcceleration
|
mappingVariation.weight_variation,
|
||||||
);
|
centrifugalAcceleration);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount;
|
||||||
|
++scalarDof) {
|
||||||
for (int component = 0; component < dimension; ++component) {
|
for (int component = 0; component < dimension; ++component) {
|
||||||
const int vectorDof = vector_dof_index(
|
const int vectorDof =
|
||||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
vector_dof_index(displacementOrdering, scalarDof, component,
|
||||||
);
|
scalarDisplacementDofCount, dimension);
|
||||||
|
|
||||||
const double contribution = displacementShape(scalarDof) * weightedForce(component);
|
const double contribution =
|
||||||
|
displacementShape(scalarDof) * weightedForce(component);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(contribution),
|
||||||
std::isfinite(contribution), "The rotational-displacement-force kernel "
|
"The rotational-displacement-force kernel "
|
||||||
"encountered a non-finite contribution."
|
"encountered a non-finite contribution.");
|
||||||
);
|
|
||||||
|
|
||||||
elementAction(vectorDof) += contribution;
|
elementAction(vectorDof) += contribution;
|
||||||
}
|
}
|
||||||
@@ -530,61 +521,44 @@ namespace {
|
|||||||
|
|
||||||
namespace mean_field::operators::kernels {
|
namespace mean_field::operators::kernels {
|
||||||
void apply_rotational_displacement_force_residual(
|
void apply_rotational_displacement_force_residual(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const physics::RigidRotation &rotation, const mfem::Vector &densityTrue,
|
||||||
const physics::RigidRotation &rotation,
|
const mfem::Vector &displacementTrue, mfem::Vector &residualTrue) {
|
||||||
const mfem::Vector &densityTrue,
|
|
||||||
const mfem::Vector &displacementTrue,
|
|
||||||
mfem::Vector &residualTrue
|
|
||||||
) {
|
|
||||||
apply_rotational_displacement_force_action(
|
apply_rotational_displacement_force_action(
|
||||||
f, domainMapper, rotation, RotationalDisplacementForceAction::residual, &densityTrue, nullptr, nullptr,
|
f, domainMapper, rotation, RotationalDisplacementForceAction::residual,
|
||||||
displacementTrue, residualTrue
|
&densityTrue, nullptr, nullptr, displacementTrue, residualTrue);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_rotational_displacement_force_density_action(
|
void apply_rotational_displacement_force_density_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_rotational_displacement_force_action(
|
apply_rotational_displacement_force_action(
|
||||||
f, domainMapper, rotation, RotationalDisplacementForceAction::density, nullptr, &densityVariationTrue,
|
f, domainMapper, rotation, RotationalDisplacementForceAction::density,
|
||||||
nullptr, displacementTrue, actionTrue
|
nullptr, &densityVariationTrue, nullptr, displacementTrue, actionTrue);
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_rotational_displacement_force_displacement_action(
|
void apply_rotational_displacement_force_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const physics::RigidRotation &rotation, const mfem::Vector &baseDensityTrue,
|
||||||
const physics::RigidRotation &rotation,
|
|
||||||
const mfem::Vector &baseDensityTrue,
|
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_rotational_displacement_force_action(
|
apply_rotational_displacement_force_action(
|
||||||
f, domainMapper, rotation, RotationalDisplacementForceAction::displacement, &baseDensityTrue, nullptr,
|
f, domainMapper, rotation,
|
||||||
&displacementVariationTrue, displacementTrue, actionTrue
|
RotationalDisplacementForceAction::displacement, &baseDensityTrue,
|
||||||
);
|
nullptr, &displacementVariationTrue, displacementTrue, actionTrue);
|
||||||
}
|
}
|
||||||
|
|
||||||
void apply_rotational_displacement_force_complete_action(
|
void apply_rotational_displacement_force_complete_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const physics::RigidRotation &rotation, const mfem::Vector &baseDensityTrue,
|
||||||
const physics::RigidRotation &rotation,
|
|
||||||
const mfem::Vector &baseDensityTrue,
|
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue, mfem::Vector &actionTrue) {
|
||||||
mfem::Vector &actionTrue
|
|
||||||
) {
|
|
||||||
apply_rotational_displacement_force_action(
|
apply_rotational_displacement_force_action(
|
||||||
f, domainMapper, rotation, RotationalDisplacementForceAction::complete, &baseDensityTrue,
|
f, domainMapper, rotation, RotationalDisplacementForceAction::complete,
|
||||||
&densityVariationTrue, &displacementVariationTrue, displacementTrue, actionTrue
|
&baseDensityTrue, &densityVariationTrue, &displacementVariationTrue,
|
||||||
);
|
displacementTrue, actionTrue);
|
||||||
}
|
}
|
||||||
} // namespace mean_field::operators::kernels
|
} // namespace mean_field::operators::kernels
|
||||||
|
|||||||
@@ -183,7 +183,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedBarotropicClosureOperator::PreparedBarotropicClosureOperator(
|
PreparedBarotropicClosureOperator::PreparedBarotropicClosureOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState
|
const eos::Polytrope &equationOfState
|
||||||
)
|
)
|
||||||
: PreparedBarotropicClosureOperator(
|
: PreparedBarotropicClosureOperator(
|
||||||
@@ -196,7 +196,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedBarotropicClosureOperator::PreparedBarotropicClosureOperator(
|
PreparedBarotropicClosureOperator::PreparedBarotropicClosureOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
ConstructionData constructionData
|
ConstructionData constructionData
|
||||||
)
|
)
|
||||||
@@ -285,7 +285,7 @@ namespace mean_field::operators {
|
|||||||
true_to_local(*m_fem.enthalpyFes, m_baseEnthalpyTrue, baseEnthalpyLocal);
|
true_to_local(*m_fem.enthalpyFes, m_baseEnthalpyTrue, baseEnthalpyLocal);
|
||||||
true_to_local(*m_fem.displacementFes, m_baseDisplacementTrue, displacementLocal);
|
true_to_local(*m_fem.displacementFes, m_baseDisplacementTrue, displacementLocal);
|
||||||
|
|
||||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Array<int> displacementDofs;
|
mfem::Array<int> displacementDofs;
|
||||||
mfem::Array<int> compactificationDofs;
|
mfem::Array<int> compactificationDofs;
|
||||||
|
|||||||
@@ -76,7 +76,7 @@ namespace {
|
|||||||
namespace mean_field::operators {
|
namespace mean_field::operators {
|
||||||
PreparedDisplacementResidualOperator::PreparedDisplacementResidualOperator(
|
PreparedDisplacementResidualOperator::PreparedDisplacementResidualOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ namespace {
|
|||||||
namespace mean_field::operators {
|
namespace mean_field::operators {
|
||||||
PreparedGravityDisplacementForceOperator::PreparedGravityDisplacementForceOperator(
|
PreparedGravityDisplacementForceOperator::PreparedGravityDisplacementForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||||
)
|
)
|
||||||
: m_fem(f),
|
: m_fem(f),
|
||||||
|
|||||||
@@ -12,32 +12,32 @@ namespace {
|
|||||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
int get_operator_height(const mean_field::fem::FEM &f) {
|
int get_operator_height(const mean_field::fem::FEM &f) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.gravityPotentialFes != nullptr,
|
||||||
f.gravityPotentialFes != nullptr, "PreparedMappedGravitySourceOperator requires the "
|
"PreparedMappedGravitySourceOperator requires the "
|
||||||
"gravity-potential "
|
"gravity-potential "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
return mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
return mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes)
|
DomainSchema>(
|
||||||
|
*f.gravityPotentialFes)
|
||||||
.reduced_size();
|
.reduced_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_operator_width(const mean_field::fem::FEM &f) {
|
int get_operator_width(const mean_field::fem::FEM &f) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.densityFes != nullptr,
|
||||||
f.densityFes != nullptr, "PreparedMappedGravitySourceOperator requires the density "
|
"PreparedMappedGravitySourceOperator requires the density "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
return mean_field::field::make_field_dof_map<mean_field::field::Density,
|
||||||
return mean_field::field::make_field_dof_map<mean_field::field::Density, DomainSchema>(*f.densityFes)
|
DomainSchema>(*f.densityFes)
|
||||||
.reduced_size();
|
.reduced_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void true_to_local(
|
void true_to_local(const mfem::ParFiniteElementSpace &finite_element_space,
|
||||||
const mfem::ParFiniteElementSpace &finite_element_space,
|
|
||||||
const mfem::Vector &true_vector,
|
const mfem::Vector &true_vector,
|
||||||
mfem::Vector &local_vector
|
mfem::Vector &local_vector) {
|
||||||
) {
|
|
||||||
local_vector.SetSize(finite_element_space.GetVSize());
|
local_vector.SetSize(finite_element_space.GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finite_element_space.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->Mult(true_vector, local_vector);
|
prolongation->Mult(true_vector, local_vector);
|
||||||
@@ -46,17 +46,17 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void local_to_true(
|
void local_to_true(const mfem::ParFiniteElementSpace &finite_element_space,
|
||||||
const mfem::ParFiniteElementSpace &finite_element_space,
|
|
||||||
const mfem::Vector &local_vector,
|
const mfem::Vector &local_vector,
|
||||||
mfem::Vector &true_vector
|
mfem::Vector &true_vector) {
|
||||||
) {
|
MFEM_VERIFY(local_vector.Size() == finite_element_space.GetVSize(),
|
||||||
MFEM_VERIFY(local_vector.Size() == finite_element_space.GetVSize(), "Local vector has the wrong size.");
|
"Local vector has the wrong size.");
|
||||||
|
|
||||||
true_vector.SetSize(finite_element_space.GetTrueVSize());
|
true_vector.SetSize(finite_element_space.GetTrueVSize());
|
||||||
true_vector = 0.0;
|
true_vector = 0.0;
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finite_element_space.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->MultTranspose(local_vector, true_vector);
|
prolongation->MultTranspose(local_vector, true_vector);
|
||||||
@@ -65,75 +65,72 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::IntegrationRule &get_source_rule(
|
const mfem::IntegrationRule &
|
||||||
const mean_field::fem::FEM &f,
|
get_source_rule(const mean_field::fem::FEM &f,
|
||||||
const mfem::FiniteElement &density_element,
|
const mfem::FiniteElement &density_element,
|
||||||
const mfem::FiniteElement &potential_element,
|
const mfem::FiniteElement &potential_element,
|
||||||
const mfem::ElementTransformation &transformation
|
const mfem::ElementTransformation &transformation) {
|
||||||
) {
|
|
||||||
using GravityField = mean_field::field::Field<mean_field::field::Gravity>;
|
using GravityField = mean_field::field::Field<mean_field::field::Gravity>;
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(density_element.GetOrder() ==
|
||||||
density_element.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
mean_field::field::Density::Scalar::familyOrder,
|
||||||
"The prepared source trial element does not match the registered "
|
"The prepared source trial element does not match the registered "
|
||||||
"density field."
|
"density field.");
|
||||||
);
|
MFEM_VERIFY(potential_element.GetOrder() ==
|
||||||
MFEM_VERIFY(
|
mean_field::field::Gravity::Potential::familyOrder,
|
||||||
potential_element.GetOrder() == mean_field::field::Gravity::Potential::familyOrder,
|
|
||||||
"The prepared source test element does not match the registered "
|
"The prepared source test element does not match the registered "
|
||||||
"gravity potential."
|
"gravity potential.");
|
||||||
);
|
const mean_field::quadrature::Query query = GravityField::make_query<
|
||||||
const mean_field::quadrature::Query query =
|
mean_field::field::Gravity::Form::SourceProjection>(
|
||||||
GravityField::make_query<mean_field::field::Gravity::Form::SourceProjection>(
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
mean_field::quadrature::MappingKind::general);
|
||||||
);
|
|
||||||
|
|
||||||
return *f.quadratureFactory->get(query, transformation.GetGeometryType()).integration_rule;
|
return *f.quadratureFactory->get(query, transformation.GetGeometryType())
|
||||||
|
.integration_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
class FrozenMappedGravitySourceCoefficient final : public mfem::Coefficient {
|
class FrozenMappedGravitySourceCoefficient final : public mfem::Coefficient {
|
||||||
public:
|
public:
|
||||||
FrozenMappedGravitySourceCoefficient(
|
FrozenMappedGravitySourceCoefficient(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domain_mapper,
|
const mean_field::mapping::DomainMapper &domain_mapper,
|
||||||
const mfem::Vector &displacement_true
|
const mfem::Vector &displacement_true)
|
||||||
)
|
: m_fem(f), m_domain_mapper(domain_mapper),
|
||||||
: m_fem(f),
|
|
||||||
m_domain_mapper(domain_mapper),
|
|
||||||
m_workspace(domain_mapper.GetDimension()) {
|
m_workspace(domain_mapper.GetDimension()) {
|
||||||
true_to_local(*m_fem.displacementFes, displacement_true, m_displacement_local);
|
true_to_local(*m_fem.displacementFes, displacement_true,
|
||||||
|
m_displacement_local);
|
||||||
}
|
}
|
||||||
|
|
||||||
double Eval(
|
double Eval(mfem::ElementTransformation &transformation,
|
||||||
mfem::ElementTransformation &transformation,
|
const mfem::IntegrationPoint &integration_point) override {
|
||||||
const mfem::IntegrationPoint &integration_point
|
|
||||||
) override {
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
transformation.SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const int element_id = transformation.ElementNo;
|
const int element_id = transformation.ElementNo;
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(element_id >= 0 && element_id < m_fem.mesh->GetNE(),
|
||||||
element_id >= 0 && element_id < m_fem.mesh->GetNE(),
|
|
||||||
"Mapped gravity source coefficient received an invalid element "
|
"Mapped gravity source coefficient received an invalid element "
|
||||||
"ID."
|
"ID.");
|
||||||
);
|
if (DomainSchema::template attribute_belongs_to<
|
||||||
if (transformation.Attribute == m_domain_mapper.GetVacuumElementAttribute()) {
|
mean_field::utils::domain::Vacuum>(transformation.Attribute)) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
LoadElement(element_id);
|
LoadElement(element_id);
|
||||||
const mean_field::mapping::ElementMappingData mapping_data{
|
const mean_field::mapping::ElementMappingData mapping_data{
|
||||||
.displacement = *m_displacement_data, .compactification = *m_compactification_data
|
.displacement = *m_displacement_data,
|
||||||
};
|
.compactification = *m_compactification_data};
|
||||||
|
|
||||||
mean_field::mapping::VolumeMappingContext mapping_context;
|
mean_field::mapping::VolumeMappingContext mapping_context;
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus status = m_domain_mapper.EvaluateVolume(
|
const mean_field::mapping::MappingStatus status =
|
||||||
mapping_data, transformation, integration_point, m_workspace, mapping_context
|
m_domain_mapper.EvaluateVolume(mapping_data, transformation,
|
||||||
);
|
integration_point, m_workspace,
|
||||||
|
mapping_context);
|
||||||
|
|
||||||
if (status != mean_field::mapping::MappingStatus::valid) {
|
if (status != mean_field::mapping::MappingStatus::valid) {
|
||||||
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(element_id);
|
const mfem::FiniteElement &displacement_element =
|
||||||
const mfem::FiniteElement &compactification_element = *m_fem.compactificationFes->GetFE(element_id);
|
*m_fem.displacementFes->GetFE(element_id);
|
||||||
|
const mfem::FiniteElement &compactification_element =
|
||||||
|
*m_fem.compactificationFes->GetFE(element_id);
|
||||||
|
|
||||||
mfem::Vector displacement_shape(displacement_element.GetDof());
|
mfem::Vector displacement_shape(displacement_element.GetDof());
|
||||||
mfem::Vector compactification_shape(compactification_element.GetDof());
|
mfem::Vector compactification_shape(compactification_element.GetDof());
|
||||||
@@ -141,36 +138,41 @@ namespace {
|
|||||||
mfem::Vector displacement_value(m_domain_mapper.GetDimension());
|
mfem::Vector displacement_value(m_domain_mapper.GetDimension());
|
||||||
|
|
||||||
displacement_element.CalcShape(integration_point, displacement_shape);
|
displacement_element.CalcShape(integration_point, displacement_shape);
|
||||||
compactification_element.CalcShape(integration_point, compactification_shape);
|
compactification_element.CalcShape(integration_point,
|
||||||
|
compactification_shape);
|
||||||
transformation.Transform(integration_point, reference_position);
|
transformation.Transform(integration_point, reference_position);
|
||||||
m_displacement_data->GetDofMatrix().MultTranspose(displacement_shape, displacement_value);
|
m_displacement_data->GetDofMatrix().MultTranspose(displacement_shape,
|
||||||
|
displacement_value);
|
||||||
|
|
||||||
const double compactification_coordinate = m_compactification_data->GetDofs() * compactification_shape;
|
const double compactification_coordinate =
|
||||||
|
m_compactification_data->GetDofs() * compactification_shape;
|
||||||
|
|
||||||
MFEM_ABORT(
|
MFEM_ABORT(
|
||||||
"Stateless domain mapping failed while preparing the "
|
"Stateless domain mapping failed while preparing the "
|
||||||
"gravity "
|
"gravity "
|
||||||
"source operator."
|
"source operator."
|
||||||
<< "\nMapping status = " << static_cast<int>(status) << "\nElement ID = " << element_id
|
<< "\nMapping status = " << static_cast<int>(status)
|
||||||
|
<< "\nElement ID = " << element_id
|
||||||
<< "\nElement attribute = " << transformation.Attribute
|
<< "\nElement attribute = " << transformation.Attribute
|
||||||
<< "\nIntegration-point index = " << integration_point.index << "\nIntegration point = <"
|
<< "\nIntegration-point index = " << integration_point.index
|
||||||
<< integration_point.x << ", " << integration_point.y << ", " << integration_point.z << ">"
|
<< "\nIntegration point = <" << integration_point.x << ", "
|
||||||
<< "\nReference position = <" << reference_position(0) << ", " << reference_position(1) << ", "
|
<< integration_point.y << ", " << integration_point.z << ">"
|
||||||
<< reference_position(2) << ">"
|
<< "\nReference position = <" << reference_position(0) << ", "
|
||||||
<< "\nReference radius = " << reference_position.Norml2() << "\nDisplacement value = <"
|
<< reference_position(1) << ", " << reference_position(2) << ">"
|
||||||
<< displacement_value(0) << ", " << displacement_value(1) << ", " << displacement_value(2) << ">"
|
<< "\nReference radius = " << reference_position.Norml2()
|
||||||
|
<< "\nDisplacement value = <" << displacement_value(0) << ", "
|
||||||
|
<< displacement_value(1) << ", " << displacement_value(2) << ">"
|
||||||
<< "\nDisplacement magnitude = " << displacement_value.Norml2()
|
<< "\nDisplacement magnitude = " << displacement_value.Norml2()
|
||||||
<< "\nCompactification coordinate = " << compactification_coordinate
|
<< "\nCompactification coordinate = " << compactification_coordinate
|
||||||
<< "\nDisplacement ordering = " << static_cast<int>(m_fem.displacementFes->GetOrdering())
|
<< "\nDisplacement ordering = "
|
||||||
);
|
<< static_cast<int>(m_fem.displacementFes->GetOrdering()));
|
||||||
}
|
}
|
||||||
const double mapping_determinant = mapping_context.mapping.mapping_determinant;
|
const double mapping_determinant =
|
||||||
MFEM_VERIFY(
|
mapping_context.mapping.mapping_determinant;
|
||||||
std::isfinite(mapping_determinant) && mapping_determinant > 0.0,
|
MFEM_VERIFY(std::isfinite(mapping_determinant) && mapping_determinant > 0.0,
|
||||||
"Prepared gravity source operator encountered a non-positive "
|
"Prepared gravity source operator encountered a non-positive "
|
||||||
"or "
|
"or "
|
||||||
"non-finite mapping determinant."
|
"non-finite mapping determinant.");
|
||||||
);
|
|
||||||
|
|
||||||
return 4.0 * std::numbers::pi * mean_field::utils::G * mapping_determinant;
|
return 4.0 * std::numbers::pi * mean_field::utils::G * mapping_determinant;
|
||||||
}
|
}
|
||||||
@@ -181,40 +183,46 @@ namespace {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(element_id);
|
const mfem::FiniteElement &displacement_element =
|
||||||
const mfem::FiniteElement &compactification_element = *m_fem.compactificationFes->GetFE(element_id);
|
*m_fem.displacementFes->GetFE(element_id);
|
||||||
|
const mfem::FiniteElement &compactification_element =
|
||||||
|
*m_fem.compactificationFes->GetFE(element_id);
|
||||||
|
|
||||||
mfem::DofTransformation *displacement_dof_transformation =
|
mfem::DofTransformation *displacement_dof_transformation =
|
||||||
m_fem.displacementFes->GetElementVDofs(element_id, m_displacement_dofs);
|
m_fem.displacementFes->GetElementVDofs(element_id, m_displacement_dofs);
|
||||||
mfem::DofTransformation *compactification_dof_transformation =
|
mfem::DofTransformation *compactification_dof_transformation =
|
||||||
m_fem.compactificationFes->GetElementDofs(element_id, m_compactification_dofs);
|
m_fem.compactificationFes->GetElementDofs(element_id,
|
||||||
|
m_compactification_dofs);
|
||||||
|
|
||||||
m_displacement_local.GetSubVector(m_displacement_dofs, m_element_displacement);
|
m_displacement_local.GetSubVector(m_displacement_dofs,
|
||||||
m_fem.compactificationCoordinate->GetSubVector(m_compactification_dofs, m_element_compactification);
|
m_element_displacement);
|
||||||
|
m_fem.compactificationCoordinate->GetSubVector(m_compactification_dofs,
|
||||||
|
m_element_compactification);
|
||||||
|
|
||||||
if (displacement_dof_transformation != nullptr) {
|
if (displacement_dof_transformation != nullptr) {
|
||||||
displacement_dof_transformation->InvTransformPrimal(m_element_displacement);
|
displacement_dof_transformation->InvTransformPrimal(
|
||||||
|
m_element_displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compactification_dof_transformation != nullptr) {
|
if (compactification_dof_transformation != nullptr) {
|
||||||
compactification_dof_transformation->InvTransformPrimal(m_element_compactification);
|
compactification_dof_transformation->InvTransformPrimal(
|
||||||
|
m_element_compactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_displacement_data = std::make_unique<mean_field::mapping::ElementDisplacementData>(
|
m_displacement_data =
|
||||||
|
std::make_unique<mean_field::mapping::ElementDisplacementData>(
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
displacement_element, m_element_displacement
|
displacement_element, m_element_displacement));
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
m_compactification_data = std::make_unique<mean_field::mapping::ElementCompactificationData>(
|
m_compactification_data =
|
||||||
compactification_element, m_element_compactification
|
std::make_unique<mean_field::mapping::ElementCompactificationData>(
|
||||||
);
|
compactification_element, m_element_compactification);
|
||||||
|
|
||||||
m_cached_element_id = element_id;
|
m_cached_element_id = element_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mean_field::fem::FEM &m_fem;
|
const mean_field::fem::FEM &m_fem;
|
||||||
const mean_field::mapping::DomainMapperStateless &m_domain_mapper;
|
const mean_field::mapping::DomainMapper &m_domain_mapper;
|
||||||
|
|
||||||
mfem::Vector m_displacement_local;
|
mfem::Vector m_displacement_local;
|
||||||
|
|
||||||
@@ -224,89 +232,71 @@ namespace {
|
|||||||
mfem::Vector m_element_displacement;
|
mfem::Vector m_element_displacement;
|
||||||
mfem::Vector m_element_compactification;
|
mfem::Vector m_element_compactification;
|
||||||
|
|
||||||
std::unique_ptr<mean_field::mapping::ElementDisplacementData> m_displacement_data;
|
std::unique_ptr<mean_field::mapping::ElementDisplacementData>
|
||||||
std::unique_ptr<mean_field::mapping::ElementCompactificationData> m_compactification_data;
|
m_displacement_data;
|
||||||
|
std::unique_ptr<mean_field::mapping::ElementCompactificationData>
|
||||||
|
m_compactification_data;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace m_workspace;
|
mean_field::mapping::DomainMapper::Workspace m_workspace;
|
||||||
int m_cached_element_id{-1};
|
int m_cached_element_id{-1};
|
||||||
};
|
};
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace mean_field::operators {
|
namespace mean_field::operators {
|
||||||
PreparedMappedGravitySourceOperator::PreparedMappedGravitySourceOperator(
|
PreparedMappedGravitySourceOperator::PreparedMappedGravitySourceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domain_mapper)
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
: Operator(get_operator_height(f), get_operator_width(f)), m_fem(f),
|
||||||
)
|
|
||||||
: Operator(
|
|
||||||
get_operator_height(f),
|
|
||||||
get_operator_width(f)
|
|
||||||
),
|
|
||||||
m_fem(f),
|
|
||||||
m_domain_mapper(domain_mapper),
|
m_domain_mapper(domain_mapper),
|
||||||
m_density_map(
|
m_density_map(field::make_field_dof_map<field::Density, DomainSchema>(
|
||||||
field::make_field_dof_map<
|
*f.densityFes)),
|
||||||
field::Density,
|
m_potential_map(field::make_field_dof_map<field::Gravity, DomainSchema>(
|
||||||
DomainSchema>(*f.densityFes)
|
*f.gravityPotentialFes)),
|
||||||
),
|
|
||||||
m_potential_map(
|
|
||||||
field::make_field_dof_map<
|
|
||||||
field::Gravity,
|
|
||||||
DomainSchema>(*f.gravityPotentialFes)
|
|
||||||
),
|
|
||||||
m_displacement_map(
|
m_displacement_map(
|
||||||
field::make_field_dof_map<
|
field::make_field_dof_map<field::Displacement, DomainSchema>(
|
||||||
field::Displacement,
|
*f.displacementFes)) {
|
||||||
DomainSchema>(*f.displacementFes)
|
MFEM_VERIFY(f.mesh != nullptr,
|
||||||
) {
|
"PreparedMappedGravitySourceOperator requires a mesh.");
|
||||||
MFEM_VERIFY(f.mesh != nullptr, "PreparedMappedGravitySourceOperator requires a mesh.");
|
MFEM_VERIFY(f.densityFes != nullptr,
|
||||||
MFEM_VERIFY(
|
"PreparedMappedGravitySourceOperator requires the density "
|
||||||
f.densityFes != nullptr, "PreparedMappedGravitySourceOperator requires the density "
|
"finite-element space.");
|
||||||
"finite-element space."
|
MFEM_VERIFY(f.gravityPotentialFes != nullptr,
|
||||||
);
|
"PreparedMappedGravitySourceOperator requires the "
|
||||||
MFEM_VERIFY(
|
|
||||||
f.gravityPotentialFes != nullptr, "PreparedMappedGravitySourceOperator requires the "
|
|
||||||
"gravity-potential "
|
"gravity-potential "
|
||||||
"finite-element space."
|
"finite-element space.");
|
||||||
);
|
MFEM_VERIFY(f.displacementFes != nullptr,
|
||||||
|
"PreparedMappedGravitySourceOperator requires "
|
||||||
|
"the displacement finite-element space.");
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
f.displacementFes != nullptr, "PreparedMappedGravitySourceOperator requires "
|
f.compactificationFes != nullptr,
|
||||||
"the displacement finite-element space."
|
"PreparedMappedGravitySourceOperator requires the compactification "
|
||||||
);
|
"finite-element space.");
|
||||||
MFEM_VERIFY(
|
|
||||||
f.compactificationFes != nullptr, "PreparedMappedGravitySourceOperator requires the compactification "
|
|
||||||
"finite-element space."
|
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
f.compactificationCoordinate != nullptr,
|
f.compactificationCoordinate != nullptr,
|
||||||
"PreparedMappedGravitySourceOperator requires the compactification "
|
"PreparedMappedGravitySourceOperator requires the compactification "
|
||||||
"coordinate."
|
"coordinate.");
|
||||||
);
|
MFEM_VERIFY(f.quadratureFactory != nullptr,
|
||||||
MFEM_VERIFY(
|
"PreparedMappedGravitySourceOperator "
|
||||||
f.quadratureFactory != nullptr, "PreparedMappedGravitySourceOperator "
|
"requires the quadrature-rule factory.");
|
||||||
"requires the quadrature-rule factory."
|
MFEM_VERIFY(domain_mapper.GetDimension() == f.mesh->Dimension(),
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
|
||||||
domain_mapper.GetDimension() == f.mesh->Dimension(),
|
|
||||||
"The stateless domain-mapper dimension does not match the mesh "
|
"The stateless domain-mapper dimension does not match the mesh "
|
||||||
"dimension."
|
"dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
utils::populate_element_mask(f.mesh.get(), utils::DOMAINS::STELLAR, m_stellar_marker);
|
m_stellar_marker =
|
||||||
|
utils::domain::make_attribute_marker<utils::domain::Stellar,
|
||||||
|
DomainSchema>(*f.mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMappedGravitySourceOperator::Prepare(const mfem::Vector &displacement) {
|
void PreparedMappedGravitySourceOperator::Prepare(
|
||||||
MFEM_VERIFY(
|
const mfem::Vector &displacement) {
|
||||||
displacement.Size() == m_displacement_map.reduced_size(),
|
MFEM_VERIFY(displacement.Size() == m_displacement_map.reduced_size(),
|
||||||
"PreparedMappedGravitySourceOperator received a displacement "
|
"PreparedMappedGravitySourceOperator received a displacement "
|
||||||
"vector "
|
"vector "
|
||||||
"with the wrong size."
|
"with the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < displacement.Size(); ++i) {
|
for (int i = 0; i < displacement.Size(); ++i) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(displacement(i)),
|
||||||
std::isfinite(displacement(i)), "PreparedMappedGravitySourceOperator received a non-finite "
|
"PreparedMappedGravitySourceOperator received a non-finite "
|
||||||
"displacement value."
|
"displacement value.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_is_prepared = false;
|
m_is_prepared = false;
|
||||||
@@ -315,12 +305,14 @@ namespace mean_field::operators {
|
|||||||
m_elements.clear();
|
m_elements.clear();
|
||||||
m_elements.reserve(m_fem.mesh->GetNE());
|
m_elements.reserve(m_fem.mesh->GetNE());
|
||||||
|
|
||||||
FrozenMappedGravitySourceCoefficient source_coefficient(m_fem, m_domain_mapper, m_displacement_true);
|
FrozenMappedGravitySourceCoefficient source_coefficient(
|
||||||
|
m_fem, m_domain_mapper, m_displacement_true);
|
||||||
|
|
||||||
for (int element_id = 0; element_id < m_fem.mesh->GetNE(); ++element_id) {
|
for (int element_id = 0; element_id < m_fem.mesh->GetNE(); ++element_id) {
|
||||||
const int attribute = m_fem.mesh->GetAttribute(element_id);
|
const int attribute = m_fem.mesh->GetAttribute(element_id);
|
||||||
|
|
||||||
if (attribute <= 0 || attribute > m_stellar_marker.Size() || m_stellar_marker[attribute - 1] == 0) {
|
if (attribute <= 0 || attribute > m_stellar_marker.Size() ||
|
||||||
|
m_stellar_marker[attribute - 1] == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,19 +321,24 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
data.element_id = element_id;
|
data.element_id = element_id;
|
||||||
|
|
||||||
data.density_dof_transformation = m_fem.densityFes->GetElementDofs(element_id, data.density_dofs);
|
data.density_dof_transformation =
|
||||||
|
m_fem.densityFes->GetElementDofs(element_id, data.density_dofs);
|
||||||
|
|
||||||
data.potential_dof_transformation =
|
data.potential_dof_transformation =
|
||||||
m_fem.gravityPotentialFes->GetElementDofs(element_id, data.potential_dofs);
|
m_fem.gravityPotentialFes->GetElementDofs(element_id,
|
||||||
|
data.potential_dofs);
|
||||||
|
|
||||||
const mfem::FiniteElement &density_element = *m_fem.densityFes->GetFE(element_id);
|
const mfem::FiniteElement &density_element =
|
||||||
|
*m_fem.densityFes->GetFE(element_id);
|
||||||
|
|
||||||
const mfem::FiniteElement &potential_element = *m_fem.gravityPotentialFes->GetFE(element_id);
|
const mfem::FiniteElement &potential_element =
|
||||||
|
*m_fem.gravityPotentialFes->GetFE(element_id);
|
||||||
|
|
||||||
mfem::ElementTransformation &transformation = *m_fem.mesh->GetElementTransformation(element_id);
|
mfem::ElementTransformation &transformation =
|
||||||
|
*m_fem.mesh->GetElementTransformation(element_id);
|
||||||
|
|
||||||
const mfem::IntegrationRule &integration_rule =
|
const mfem::IntegrationRule &integration_rule = get_source_rule(
|
||||||
get_source_rule(m_fem, density_element, potential_element, transformation);
|
m_fem, density_element, potential_element, transformation);
|
||||||
|
|
||||||
const int quadrature_point_count = integration_rule.GetNPoints();
|
const int quadrature_point_count = integration_rule.GetNPoints();
|
||||||
|
|
||||||
@@ -358,8 +355,10 @@ namespace mean_field::operators {
|
|||||||
mfem::Vector density_shape(density_dof_count);
|
mfem::Vector density_shape(density_dof_count);
|
||||||
mfem::Vector potential_shape(potential_dof_count);
|
mfem::Vector potential_shape(potential_dof_count);
|
||||||
|
|
||||||
for (int quadrature_point = 0; quadrature_point < quadrature_point_count; ++quadrature_point) {
|
for (int quadrature_point = 0; quadrature_point < quadrature_point_count;
|
||||||
const mfem::IntegrationPoint &integration_point = integration_rule.IntPoint(quadrature_point);
|
++quadrature_point) {
|
||||||
|
const mfem::IntegrationPoint &integration_point =
|
||||||
|
integration_rule.IntPoint(quadrature_point);
|
||||||
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
transformation.SetIntPoint(&integration_point);
|
||||||
|
|
||||||
@@ -377,41 +376,40 @@ namespace mean_field::operators {
|
|||||||
data.potential_basis(quadrature_point, i) = potential_shape(i);
|
data.potential_basis(quadrature_point, i) = potential_shape(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
const double coefficient_value = source_coefficient.Eval(transformation, integration_point);
|
const double coefficient_value =
|
||||||
|
source_coefficient.Eval(transformation, integration_point);
|
||||||
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
transformation.SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const double quadrature_value = integration_point.weight * transformation.Weight() * coefficient_value;
|
const double quadrature_value = integration_point.weight *
|
||||||
|
transformation.Weight() *
|
||||||
|
coefficient_value;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(quadrature_value) && quadrature_value > 0.0,
|
||||||
std::isfinite(quadrature_value) && quadrature_value > 0.0,
|
|
||||||
"Prepared gravity source operator encountered invalid "
|
"Prepared gravity source operator encountered invalid "
|
||||||
"quadrature data on element "
|
"quadrature data on element "
|
||||||
<< element_id << ", quadrature point " << quadrature_point << "."
|
<< element_id << ", quadrature point " << quadrature_point
|
||||||
);
|
<< ".");
|
||||||
|
|
||||||
data.quadrature_data(quadrature_point) = quadrature_value;
|
data.quadrature_data(quadrature_point) = quadrature_value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
MFEM_VERIFY(!m_elements.empty(), "PreparedMappedGravitySourceOperator found no stellar elements.");
|
MFEM_VERIFY(!m_elements.empty(),
|
||||||
|
"PreparedMappedGravitySourceOperator found no stellar elements.");
|
||||||
|
|
||||||
m_is_prepared = true;
|
m_is_prepared = true;
|
||||||
++m_preparation_count;
|
++m_preparation_count;
|
||||||
}
|
}
|
||||||
void PreparedMappedGravitySourceOperator::Mult(
|
void PreparedMappedGravitySourceOperator::Mult(const mfem::Vector &density,
|
||||||
const mfem::Vector &density,
|
mfem::Vector &action) const {
|
||||||
mfem::Vector &action
|
MFEM_VERIFY(m_is_prepared,
|
||||||
) const {
|
"PreparedMappedGravitySourceOperator must be prepared before "
|
||||||
MFEM_VERIFY(
|
"Mult is called.");
|
||||||
m_is_prepared, "PreparedMappedGravitySourceOperator must be prepared before "
|
|
||||||
"Mult is called."
|
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(density.Size() == Width(),
|
||||||
density.Size() == Width(), "PreparedMappedGravitySourceOperator received a density vector "
|
"PreparedMappedGravitySourceOperator received a density vector "
|
||||||
"with the wrong size."
|
"with the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
m_density_true.SetSize(m_density_map.full_size());
|
m_density_true.SetSize(m_density_map.full_size());
|
||||||
m_density_map.scatter(density, m_density_true);
|
m_density_map.scatter(density, m_density_true);
|
||||||
@@ -462,18 +460,14 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMappedGravitySourceOperator::MultTranspose(
|
void PreparedMappedGravitySourceOperator::MultTranspose(
|
||||||
const mfem::Vector &potential,
|
const mfem::Vector &potential, mfem::Vector &action) const {
|
||||||
mfem::Vector &action
|
MFEM_VERIFY(m_is_prepared,
|
||||||
) const {
|
"PreparedMappedGravitySourceOperator must be prepared before "
|
||||||
MFEM_VERIFY(
|
"MultTranspose is called.");
|
||||||
m_is_prepared, "PreparedMappedGravitySourceOperator must be prepared before "
|
|
||||||
"MultTranspose is called."
|
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(potential.Size() == Height(),
|
||||||
potential.Size() == Height(), "PreparedMappedGravitySourceOperator received a potential vector "
|
"PreparedMappedGravitySourceOperator received a potential vector "
|
||||||
"with the wrong size."
|
"with the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
m_potential_true.SetSize(m_potential_map.full_size());
|
m_potential_true.SetSize(m_potential_map.full_size());
|
||||||
m_potential_map.scatter(potential, m_potential_true);
|
m_potential_map.scatter(potential, m_potential_true);
|
||||||
@@ -523,19 +517,23 @@ namespace mean_field::operators {
|
|||||||
return m_is_prepared;
|
return m_is_prepared;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t PreparedMappedGravitySourceOperator::GetPreparationCount() const noexcept {
|
std::uint64_t
|
||||||
|
PreparedMappedGravitySourceOperator::GetPreparationCount() const noexcept {
|
||||||
return m_preparation_count;
|
return m_preparation_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field::FieldDofMap &PreparedMappedGravitySourceOperator::GetDensityMap() const noexcept {
|
const field::FieldDofMap &
|
||||||
|
PreparedMappedGravitySourceOperator::GetDensityMap() const noexcept {
|
||||||
return m_density_map;
|
return m_density_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field::FieldDofMap &PreparedMappedGravitySourceOperator::GetPotentialMap() const noexcept {
|
const field::FieldDofMap &
|
||||||
|
PreparedMappedGravitySourceOperator::GetPotentialMap() const noexcept {
|
||||||
return m_potential_map;
|
return m_potential_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field::FieldDofMap &PreparedMappedGravitySourceOperator::GetDisplacementMap() const noexcept {
|
const field::FieldDofMap &
|
||||||
|
PreparedMappedGravitySourceOperator::GetDisplacementMap() const noexcept {
|
||||||
return m_displacement_map;
|
return m_displacement_map;
|
||||||
}
|
}
|
||||||
} // namespace mean_field::operators
|
} // namespace mean_field::operators
|
||||||
|
|||||||
@@ -11,22 +11,21 @@ namespace {
|
|||||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
int get_operator_size(const mean_field::fem::FEM &f) {
|
int get_operator_size(const mean_field::fem::FEM &f) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.gravityFluxFes != nullptr,
|
||||||
f.gravityFluxFes != nullptr, "PreparedMappedHDivMassOperator requires the "
|
"PreparedMappedHDivMassOperator requires the "
|
||||||
"gravity-gradient finite-element space."
|
"gravity-gradient finite-element space.");
|
||||||
);
|
return mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
return mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityFluxFes)
|
DomainSchema>(*f.gravityFluxFes)
|
||||||
.reduced_size();
|
.reduced_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void true_to_local(
|
void true_to_local(const mfem::ParFiniteElementSpace &finite_element_space,
|
||||||
const mfem::ParFiniteElementSpace &finite_element_space,
|
|
||||||
const mfem::Vector &true_vector,
|
const mfem::Vector &true_vector,
|
||||||
mfem::Vector &local_vector
|
mfem::Vector &local_vector) {
|
||||||
) {
|
|
||||||
local_vector.SetSize(finite_element_space.GetVSize());
|
local_vector.SetSize(finite_element_space.GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finite_element_space.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->Mult(true_vector, local_vector);
|
prolongation->Mult(true_vector, local_vector);
|
||||||
@@ -35,14 +34,13 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int find_representative_element(
|
int find_representative_element(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const mfem::Array<int> &marker) {
|
||||||
const mfem::Array<int> &marker
|
|
||||||
) {
|
|
||||||
for (int element_id = 0; element_id < f.mesh->GetNE(); ++element_id) {
|
for (int element_id = 0; element_id < f.mesh->GetNE(); ++element_id) {
|
||||||
const int attribute = f.mesh->GetAttribute(element_id);
|
const int attribute = f.mesh->GetAttribute(element_id);
|
||||||
|
|
||||||
if (attribute > 0 && attribute <= marker.Size() && marker[attribute - 1] != 0) {
|
if (attribute > 0 && attribute <= marker.Size() &&
|
||||||
|
marker[attribute - 1] != 0) {
|
||||||
return element_id;
|
return element_id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -51,40 +49,36 @@ namespace {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void validate_uniform_domain_discretization(
|
void validate_uniform_domain_discretization(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f, const mfem::Array<int> &marker,
|
||||||
const mfem::Array<int> &marker,
|
const int representative_element_id) {
|
||||||
const int representative_element_id
|
const mfem::FiniteElement &representative_element =
|
||||||
) {
|
*f.gravityFluxFes->GetFE(representative_element_id);
|
||||||
const mfem::FiniteElement &representative_element = *f.gravityFluxFes->GetFE(representative_element_id);
|
|
||||||
const mfem::ElementTransformation &representative_transformation =
|
const mfem::ElementTransformation &representative_transformation =
|
||||||
*f.mesh->GetElementTransformation(representative_element_id);
|
*f.mesh->GetElementTransformation(representative_element_id);
|
||||||
|
|
||||||
for (int element_id = 0; element_id < f.mesh->GetNE(); ++element_id) {
|
for (int element_id = 0; element_id < f.mesh->GetNE(); ++element_id) {
|
||||||
const int attribute = f.mesh->GetAttribute(element_id);
|
const int attribute = f.mesh->GetAttribute(element_id);
|
||||||
|
|
||||||
if (attribute <= 0 || attribute > marker.Size() || marker[attribute - 1] == 0) {
|
if (attribute <= 0 || attribute > marker.Size() ||
|
||||||
|
marker[attribute - 1] == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &element = *f.gravityFluxFes->GetFE(element_id);
|
const mfem::FiniteElement &element = *f.gravityFluxFes->GetFE(element_id);
|
||||||
const mfem::ElementTransformation &transformation = *f.mesh->GetElementTransformation(element_id);
|
const mfem::ElementTransformation &transformation =
|
||||||
|
*f.mesh->GetElementTransformation(element_id);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(element.GetGeomType() == representative_element.GetGeomType(),
|
||||||
element.GetGeomType() == representative_element.GetGeomType(),
|
|
||||||
"Prepared H(div) mass domains currently require a uniform "
|
"Prepared H(div) mass domains currently require a uniform "
|
||||||
"element "
|
"element "
|
||||||
"geometry."
|
"geometry.");
|
||||||
);
|
MFEM_VERIFY(element.GetOrder() == representative_element.GetOrder(),
|
||||||
MFEM_VERIFY(
|
|
||||||
element.GetOrder() == representative_element.GetOrder(),
|
|
||||||
"Prepared H(div) mass domains currently require a uniform "
|
"Prepared H(div) mass domains currently require a uniform "
|
||||||
"finite-element order."
|
"finite-element order.");
|
||||||
);
|
MFEM_VERIFY(transformation.OrderW() ==
|
||||||
MFEM_VERIFY(
|
representative_transformation.OrderW(),
|
||||||
transformation.OrderW() == representative_transformation.OrderW(),
|
|
||||||
"Prepared H(div) mass domains currently require a uniform "
|
"Prepared H(div) mass domains currently require a uniform "
|
||||||
"geometry-weight order."
|
"geometry-weight order.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,32 +86,28 @@ namespace {
|
|||||||
public:
|
public:
|
||||||
FrozenMappedHDivMassCoefficient(
|
FrozenMappedHDivMassCoefficient(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domain_mapper,
|
const mean_field::mapping::DomainMapper &domain_mapper,
|
||||||
const mfem::Vector &displacement_true,
|
const mfem::Vector &displacement_true, bool elevates_vacuum)
|
||||||
bool elevates_vacuum
|
: MatrixCoefficient(domain_mapper.GetDimension()), m_fem(f),
|
||||||
)
|
|
||||||
: MatrixCoefficient(domain_mapper.GetDimension()),
|
|
||||||
m_fem(f),
|
|
||||||
m_domain_mapper(domain_mapper),
|
m_domain_mapper(domain_mapper),
|
||||||
m_workspace(domain_mapper.GetDimension()),
|
m_workspace(domain_mapper.GetDimension()),
|
||||||
m_elevates_vacuum(elevates_vacuum) {
|
m_elevates_vacuum(elevates_vacuum) {
|
||||||
true_to_local(*m_fem.displacementFes, displacement_true, m_displacement_local);
|
true_to_local(*m_fem.displacementFes, displacement_true,
|
||||||
|
m_displacement_local);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Eval(
|
void Eval(mfem::DenseMatrix &mass_tensor,
|
||||||
mfem::DenseMatrix &mass_tensor,
|
|
||||||
mfem::ElementTransformation &transformation,
|
mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point
|
const mfem::IntegrationPoint &integration_point) override {
|
||||||
) override {
|
|
||||||
transformation.SetIntPoint(&integration_point);
|
transformation.SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const int element_id = transformation.ElementNo;
|
const int element_id = transformation.ElementNo;
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
element_id >= 0 && element_id < m_fem.mesh->GetNE(),
|
element_id >= 0 && element_id < m_fem.mesh->GetNE(),
|
||||||
"Mapped H(div) mass coefficient received an invalid element ID."
|
"Mapped H(div) mass coefficient received an invalid element ID.");
|
||||||
);
|
|
||||||
|
|
||||||
const bool element_is_vacuum = transformation.Attribute == m_domain_mapper.GetVacuumElementAttribute();
|
const bool element_is_vacuum = DomainSchema::template attribute_belongs_to<
|
||||||
|
mean_field::utils::domain::Vacuum>(transformation.Attribute);
|
||||||
|
|
||||||
if (element_is_vacuum != m_elevates_vacuum) {
|
if (element_is_vacuum != m_elevates_vacuum) {
|
||||||
mass_tensor.SetSize(m_domain_mapper.GetDimension());
|
mass_tensor.SetSize(m_domain_mapper.GetDimension());
|
||||||
@@ -128,33 +118,34 @@ namespace {
|
|||||||
LoadElement(element_id);
|
LoadElement(element_id);
|
||||||
|
|
||||||
const mean_field::mapping::ElementMappingData mapping_data{
|
const mean_field::mapping::ElementMappingData mapping_data{
|
||||||
.displacement = *m_displacement_data, .compactification = *m_compactification_data
|
.displacement = *m_displacement_data,
|
||||||
};
|
.compactification = *m_compactification_data};
|
||||||
|
|
||||||
mean_field::mapping::VolumeMappingContext mapping_context;
|
mean_field::mapping::VolumeMappingContext mapping_context;
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus status = m_domain_mapper.EvaluateVolume(
|
const mean_field::mapping::MappingStatus status =
|
||||||
mapping_data, transformation, integration_point, m_workspace, mapping_context
|
m_domain_mapper.EvaluateVolume(mapping_data, transformation,
|
||||||
);
|
integration_point, m_workspace,
|
||||||
|
mapping_context);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(status == mean_field::mapping::MappingStatus::valid,
|
||||||
status == mean_field::mapping::MappingStatus::valid,
|
|
||||||
"Stateless domain mapping failed while preparing the H(div) "
|
"Stateless domain mapping failed while preparing the H(div) "
|
||||||
"mass "
|
"mass "
|
||||||
"operator. Mapping status = "
|
"operator. Mapping status = "
|
||||||
<< static_cast<int>(status) << ", element ID = " << element_id
|
<< static_cast<int>(status)
|
||||||
|
<< ", element ID = " << element_id
|
||||||
<< ", element attribute = " << transformation.Attribute
|
<< ", element attribute = " << transformation.Attribute
|
||||||
<< ", coefficient domain = " << (m_elevates_vacuum ? "vacuum" : "stellar")
|
<< ", coefficient domain = "
|
||||||
);
|
<< (m_elevates_vacuum ? "vacuum" : "stellar"));
|
||||||
|
|
||||||
const mfem::DenseMatrix &mapping_jacobian = mapping_context.mapping.mapping_jacobian;
|
const mfem::DenseMatrix &mapping_jacobian =
|
||||||
const double mapping_determinant = mapping_context.mapping.mapping_determinant;
|
mapping_context.mapping.mapping_jacobian;
|
||||||
|
const double mapping_determinant =
|
||||||
|
mapping_context.mapping.mapping_determinant;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(mapping_determinant) && mapping_determinant > 0.0,
|
||||||
std::isfinite(mapping_determinant) && mapping_determinant > 0.0,
|
|
||||||
"Prepared H(div) mass operator encountered a non-positive or "
|
"Prepared H(div) mass operator encountered a non-positive or "
|
||||||
"non-finite mapping determinant."
|
"non-finite mapping determinant.");
|
||||||
);
|
|
||||||
|
|
||||||
mfem::MultAtB(mapping_jacobian, mapping_jacobian, mass_tensor);
|
mfem::MultAtB(mapping_jacobian, mapping_jacobian, mass_tensor);
|
||||||
mass_tensor *= 1.0 / mapping_determinant;
|
mass_tensor *= 1.0 / mapping_determinant;
|
||||||
@@ -166,40 +157,46 @@ namespace {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(element_id);
|
const mfem::FiniteElement &displacement_element =
|
||||||
const mfem::FiniteElement &compactification_element = *m_fem.compactificationFes->GetFE(element_id);
|
*m_fem.displacementFes->GetFE(element_id);
|
||||||
|
const mfem::FiniteElement &compactification_element =
|
||||||
|
*m_fem.compactificationFes->GetFE(element_id);
|
||||||
|
|
||||||
mfem::DofTransformation *displacement_dof_transformation =
|
mfem::DofTransformation *displacement_dof_transformation =
|
||||||
m_fem.displacementFes->GetElementVDofs(element_id, m_displacement_dofs);
|
m_fem.displacementFes->GetElementVDofs(element_id, m_displacement_dofs);
|
||||||
mfem::DofTransformation *compactification_dof_transformation =
|
mfem::DofTransformation *compactification_dof_transformation =
|
||||||
m_fem.compactificationFes->GetElementDofs(element_id, m_compactification_dofs);
|
m_fem.compactificationFes->GetElementDofs(element_id,
|
||||||
|
m_compactification_dofs);
|
||||||
|
|
||||||
m_displacement_local.GetSubVector(m_displacement_dofs, m_element_displacement);
|
m_displacement_local.GetSubVector(m_displacement_dofs,
|
||||||
m_fem.compactificationCoordinate->GetSubVector(m_compactification_dofs, m_element_compactification);
|
m_element_displacement);
|
||||||
|
m_fem.compactificationCoordinate->GetSubVector(m_compactification_dofs,
|
||||||
|
m_element_compactification);
|
||||||
|
|
||||||
if (displacement_dof_transformation != nullptr) {
|
if (displacement_dof_transformation != nullptr) {
|
||||||
displacement_dof_transformation->InvTransformPrimal(m_element_displacement);
|
displacement_dof_transformation->InvTransformPrimal(
|
||||||
|
m_element_displacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (compactification_dof_transformation != nullptr) {
|
if (compactification_dof_transformation != nullptr) {
|
||||||
compactification_dof_transformation->InvTransformPrimal(m_element_compactification);
|
compactification_dof_transformation->InvTransformPrimal(
|
||||||
|
m_element_compactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_displacement_data = std::make_unique<mean_field::mapping::ElementDisplacementData>(
|
m_displacement_data =
|
||||||
|
std::make_unique<mean_field::mapping::ElementDisplacementData>(
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
displacement_element, m_element_displacement
|
displacement_element, m_element_displacement));
|
||||||
)
|
|
||||||
);
|
|
||||||
|
|
||||||
m_compactification_data = std::make_unique<mean_field::mapping::ElementCompactificationData>(
|
m_compactification_data =
|
||||||
compactification_element, m_element_compactification
|
std::make_unique<mean_field::mapping::ElementCompactificationData>(
|
||||||
);
|
compactification_element, m_element_compactification);
|
||||||
|
|
||||||
m_cached_element_id = element_id;
|
m_cached_element_id = element_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mean_field::fem::FEM &m_fem;
|
const mean_field::fem::FEM &m_fem;
|
||||||
const mean_field::mapping::DomainMapperStateless &m_domain_mapper;
|
const mean_field::mapping::DomainMapper &m_domain_mapper;
|
||||||
|
|
||||||
mfem::Vector m_displacement_local;
|
mfem::Vector m_displacement_local;
|
||||||
|
|
||||||
@@ -209,10 +206,12 @@ namespace {
|
|||||||
mfem::Vector m_element_displacement;
|
mfem::Vector m_element_displacement;
|
||||||
mfem::Vector m_element_compactification;
|
mfem::Vector m_element_compactification;
|
||||||
|
|
||||||
std::unique_ptr<mean_field::mapping::ElementDisplacementData> m_displacement_data;
|
std::unique_ptr<mean_field::mapping::ElementDisplacementData>
|
||||||
std::unique_ptr<mean_field::mapping::ElementCompactificationData> m_compactification_data;
|
m_displacement_data;
|
||||||
|
std::unique_ptr<mean_field::mapping::ElementCompactificationData>
|
||||||
|
m_compactification_data;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace m_workspace;
|
mean_field::mapping::DomainMapper::Workspace m_workspace;
|
||||||
int m_cached_element_id{-1};
|
int m_cached_element_id{-1};
|
||||||
bool m_elevates_vacuum;
|
bool m_elevates_vacuum;
|
||||||
};
|
};
|
||||||
@@ -220,167 +219,194 @@ namespace {
|
|||||||
|
|
||||||
namespace mean_field::operators {
|
namespace mean_field::operators {
|
||||||
PreparedMappedHDivMassOperator::PreparedMappedHDivMassOperator(
|
PreparedMappedHDivMassOperator::PreparedMappedHDivMassOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domain_mapper)
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
: Operator(get_operator_size(f)), m_fem(f), m_domain_mapper(domain_mapper),
|
||||||
)
|
m_flux_map(field::make_field_dof_map<field::Gravity, DomainSchema>(
|
||||||
: Operator(get_operator_size(f)),
|
*f.gravityFluxFes)),
|
||||||
m_fem(f),
|
|
||||||
m_domain_mapper(domain_mapper),
|
|
||||||
m_flux_map(
|
|
||||||
field::make_field_dof_map<
|
|
||||||
field::Gravity,
|
|
||||||
DomainSchema>(*f.gravityFluxFes)
|
|
||||||
),
|
|
||||||
m_displacement_map(
|
m_displacement_map(
|
||||||
field::make_field_dof_map<
|
field::make_field_dof_map<field::Displacement, DomainSchema>(
|
||||||
field::Displacement,
|
*f.displacementFes)) {
|
||||||
DomainSchema>(*f.displacementFes)
|
MFEM_VERIFY(f.mesh != nullptr,
|
||||||
) {
|
"PreparedMappedHDivMassOperator requires a mesh.");
|
||||||
MFEM_VERIFY(f.mesh != nullptr, "PreparedMappedHDivMassOperator requires a mesh.");
|
MFEM_VERIFY(f.gravityFluxFes != nullptr,
|
||||||
MFEM_VERIFY(
|
"PreparedMappedHDivMassOperator requires the "
|
||||||
f.gravityFluxFes != nullptr, "PreparedMappedHDivMassOperator requires the "
|
"gravity-gradient finite-element space.");
|
||||||
"gravity-gradient finite-element space."
|
MFEM_VERIFY(f.displacementFes != nullptr,
|
||||||
);
|
"PreparedMappedHDivMassOperator requires the "
|
||||||
MFEM_VERIFY(
|
"displacement finite-element space.");
|
||||||
f.displacementFes != nullptr, "PreparedMappedHDivMassOperator requires the "
|
MFEM_VERIFY(f.compactificationFes != nullptr,
|
||||||
"displacement finite-element space."
|
"PreparedMappedHDivMassOperator requires the compactification "
|
||||||
);
|
"finite-element space.");
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.compactificationCoordinate != nullptr,
|
||||||
f.compactificationFes != nullptr, "PreparedMappedHDivMassOperator requires the compactification "
|
"PreparedMappedHDivMassOperator requires the compactification "
|
||||||
"finite-element space."
|
"coordinate.");
|
||||||
);
|
MFEM_VERIFY(f.quadratureFactory != nullptr,
|
||||||
MFEM_VERIFY(
|
"PreparedMappedHDivMassOperator requires the quadrature-rule "
|
||||||
f.compactificationCoordinate != nullptr, "PreparedMappedHDivMassOperator requires the compactification "
|
"factory.");
|
||||||
"coordinate."
|
MFEM_VERIFY(domain_mapper.GetDimension() == f.mesh->Dimension(),
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.quadratureFactory != nullptr, "PreparedMappedHDivMassOperator requires the quadrature-rule "
|
|
||||||
"factory."
|
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
|
||||||
domain_mapper.GetDimension() == f.mesh->Dimension(),
|
|
||||||
"The stateless domain-mapper dimension does not match the mesh "
|
"The stateless domain-mapper dimension does not match the mesh "
|
||||||
"dimension."
|
"dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
utils::populate_element_mask(f.mesh.get(), utils::DOMAINS::STELLAR, m_stellar_marker);
|
m_stellar_marker =
|
||||||
utils::populate_element_mask(f.mesh.get(), utils::DOMAINS::VACUUM, m_vacuum_marker);
|
utils::domain::make_attribute_marker<utils::domain::Stellar,
|
||||||
|
DomainSchema>(*f.mesh);
|
||||||
|
m_vacuum_marker =
|
||||||
|
utils::domain::make_attribute_marker<utils::domain::Vacuum, DomainSchema>(
|
||||||
|
*f.mesh);
|
||||||
|
|
||||||
const int stellar_element_id = find_representative_element(f, m_stellar_marker);
|
const int stellar_element_id =
|
||||||
|
find_representative_element(f, m_stellar_marker);
|
||||||
const int vacuum_element_id = find_representative_element(f, m_vacuum_marker);
|
const int vacuum_element_id = find_representative_element(f, m_vacuum_marker);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(stellar_element_id >= 0,
|
||||||
stellar_element_id >= 0, "PreparedMappedHDivMassOperator requires "
|
"PreparedMappedHDivMassOperator requires "
|
||||||
"at least one stellar element."
|
"at least one stellar element.");
|
||||||
);
|
MFEM_VERIFY(vacuum_element_id >= 0,
|
||||||
MFEM_VERIFY(
|
"PreparedMappedHDivMassOperator requires at "
|
||||||
vacuum_element_id >= 0, "PreparedMappedHDivMassOperator requires at "
|
"least one compactified vacuum element.");
|
||||||
"least one compactified vacuum element."
|
|
||||||
);
|
|
||||||
|
|
||||||
validate_uniform_domain_discretization(f, m_stellar_marker, stellar_element_id);
|
validate_uniform_domain_discretization(f, m_stellar_marker,
|
||||||
|
stellar_element_id);
|
||||||
validate_uniform_domain_discretization(f, m_vacuum_marker, vacuum_element_id);
|
validate_uniform_domain_discretization(f, m_vacuum_marker, vacuum_element_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMappedHDivMassOperator::Prepare(const mfem::Vector &displacement) {
|
void PreparedMappedHDivMassOperator::Prepare(const mfem::Vector &displacement) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacement.Size() == m_displacement_map.reduced_size(),
|
||||||
displacement.Size() == m_displacement_map.reduced_size(),
|
|
||||||
"PreparedMappedHDivMassOperator received a displacement vector "
|
"PreparedMappedHDivMassOperator received a displacement vector "
|
||||||
"with "
|
"with "
|
||||||
"the wrong size."
|
"the wrong size.");
|
||||||
);
|
|
||||||
|
|
||||||
for (int i = 0; i < displacement.Size(); ++i) {
|
for (int i = 0; i < displacement.Size(); ++i) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(displacement(i)),
|
||||||
std::isfinite(displacement(i)), "PreparedMappedHDivMassOperator received a non-finite "
|
"PreparedMappedHDivMassOperator received a non-finite "
|
||||||
"displacement "
|
"displacement "
|
||||||
"value."
|
"value.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
m_displacement_true.SetSize(m_displacement_map.full_size());
|
m_displacement_true.SetSize(m_displacement_map.full_size());
|
||||||
m_displacement_map.scatter(displacement, m_displacement_true);
|
m_displacement_map.scatter(displacement, m_displacement_true);
|
||||||
|
|
||||||
const int stellar_element_id = find_representative_element(m_fem, m_stellar_marker);
|
const int stellar_element_id =
|
||||||
const int vacuum_element_id = find_representative_element(m_fem, m_vacuum_marker);
|
find_representative_element(m_fem, m_stellar_marker);
|
||||||
|
const int vacuum_element_id =
|
||||||
|
find_representative_element(m_fem, m_vacuum_marker);
|
||||||
|
|
||||||
const mfem::FiniteElement &stellar_element = *m_fem.gravityFluxFes->GetFE(stellar_element_id);
|
const mfem::FiniteElement &stellar_element =
|
||||||
const mfem::FiniteElement &vacuum_element = *m_fem.gravityFluxFes->GetFE(vacuum_element_id);
|
*m_fem.gravityFluxFes->GetFE(stellar_element_id);
|
||||||
|
const mfem::FiniteElement &vacuum_element =
|
||||||
|
*m_fem.gravityFluxFes->GetFE(vacuum_element_id);
|
||||||
|
|
||||||
mfem::ElementTransformation &stellar_transformation = *m_fem.mesh->GetElementTransformation(stellar_element_id);
|
mfem::ElementTransformation &stellar_transformation =
|
||||||
mfem::ElementTransformation &vacuum_transformation = *m_fem.mesh->GetElementTransformation(vacuum_element_id);
|
*m_fem.mesh->GetElementTransformation(stellar_element_id);
|
||||||
|
mfem::ElementTransformation &vacuum_transformation =
|
||||||
|
*m_fem.mesh->GetElementTransformation(vacuum_element_id);
|
||||||
|
|
||||||
m_mass_form.reset();
|
m_stellar_mass_form.reset();
|
||||||
|
m_vacuum_mass_form.reset();
|
||||||
m_stellar_mass_coefficient.reset();
|
m_stellar_mass_coefficient.reset();
|
||||||
m_vacuum_mass_coefficient.reset();
|
m_vacuum_mass_coefficient.reset();
|
||||||
|
|
||||||
m_stellar_mass_coefficient =
|
m_stellar_mass_coefficient =
|
||||||
std::make_unique<FrozenMappedHDivMassCoefficient>(m_fem, m_domain_mapper, m_displacement_true, false);
|
std::make_unique<FrozenMappedHDivMassCoefficient>(
|
||||||
m_vacuum_mass_coefficient =
|
m_fem, m_domain_mapper, m_displacement_true, false);
|
||||||
std::make_unique<FrozenMappedHDivMassCoefficient>(m_fem, m_domain_mapper, m_displacement_true, true);
|
m_vacuum_mass_coefficient = std::make_unique<FrozenMappedHDivMassCoefficient>(
|
||||||
|
m_fem, m_domain_mapper, m_displacement_true, true);
|
||||||
|
|
||||||
m_mass_form = std::make_unique<mfem::ParBilinearForm>(m_fem.gravityFluxFes.get());
|
m_stellar_mass_form =
|
||||||
m_mass_form->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
std::make_unique<mfem::ParBilinearForm>(m_fem.gravityFluxFes.get());
|
||||||
|
m_vacuum_mass_form =
|
||||||
|
std::make_unique<mfem::ParBilinearForm>(m_fem.gravityFluxFes.get());
|
||||||
|
m_stellar_mass_form->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||||
|
m_vacuum_mass_form->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
||||||
|
|
||||||
auto stellar_integrator = std::make_unique<mfem::VectorFEMassIntegrator>(*m_stellar_mass_coefficient);
|
auto stellar_integrator = std::make_unique<mfem::VectorFEMassIntegrator>(
|
||||||
auto vacuum_integrator = std::make_unique<mfem::VectorFEMassIntegrator>(*m_vacuum_mass_coefficient);
|
*m_stellar_mass_coefficient);
|
||||||
|
auto vacuum_integrator = std::make_unique<mfem::VectorFEMassIntegrator>(
|
||||||
|
*m_vacuum_mass_coefficient);
|
||||||
|
|
||||||
m_fem.quadratureFactory->configure_gravity_hdiv_mass(
|
m_fem.quadratureFactory->configure_gravity_hdiv_mass(
|
||||||
*stellar_integrator, quadrature::QuadratureRole::discretization, stellar_element, stellar_transformation,
|
*stellar_integrator, quadrature::QuadratureRole::discretization,
|
||||||
utils::DOMAINS::STELLAR, quadrature::MappingKind::general
|
stellar_element, stellar_transformation, utils::DOMAINS::STELLAR,
|
||||||
);
|
quadrature::MappingKind::general);
|
||||||
|
|
||||||
m_fem.quadratureFactory->configure_gravity_hdiv_mass(
|
m_fem.quadratureFactory->configure_gravity_hdiv_mass(
|
||||||
*vacuum_integrator, quadrature::QuadratureRole::discretization, vacuum_element, vacuum_transformation,
|
*vacuum_integrator, quadrature::QuadratureRole::discretization,
|
||||||
utils::DOMAINS::VACUUM, quadrature::MappingKind::kelvin
|
vacuum_element, vacuum_transformation, utils::DOMAINS::VACUUM,
|
||||||
);
|
quadrature::MappingKind::kelvin);
|
||||||
|
|
||||||
m_mass_form->AddDomainIntegrator(stellar_integrator.release(), m_stellar_marker);
|
m_stellar_mass_form->AddDomainIntegrator(stellar_integrator.release(),
|
||||||
m_mass_form->AddDomainIntegrator(vacuum_integrator.release(), m_vacuum_marker);
|
m_stellar_marker);
|
||||||
m_mass_form->Assemble();
|
m_vacuum_mass_form->AddDomainIntegrator(vacuum_integrator.release(),
|
||||||
|
m_vacuum_marker);
|
||||||
|
m_stellar_mass_form->Assemble();
|
||||||
|
m_vacuum_mass_form->Assemble();
|
||||||
|
|
||||||
m_is_prepared = true;
|
m_is_prepared = true;
|
||||||
++m_preparation_count;
|
++m_preparation_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMappedHDivMassOperator::Mult(
|
void PreparedMappedHDivMassOperator::Mult(const mfem::Vector &gravity_gradient,
|
||||||
const mfem::Vector &gravity_gradient,
|
mfem::Vector &action) const {
|
||||||
mfem::Vector &action
|
MFEM_VERIFY(m_is_prepared, "PreparedMappedHDivMassOperator must be prepared "
|
||||||
) const {
|
"before Mult is called.");
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
m_is_prepared, "PreparedMappedHDivMassOperator must be prepared "
|
m_stellar_mass_form != nullptr && m_vacuum_mass_form != nullptr,
|
||||||
"before Mult is called."
|
"PreparedMappedHDivMassOperator has incomplete domain mass forms.");
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
m_mass_form != nullptr, "PreparedMappedHDivMassOperator has no "
|
gravity_gradient.Size() == Width(),
|
||||||
"assembled partial-assembly form."
|
"PreparedMappedHDivMassOperator received a gravity-gradient vector "
|
||||||
);
|
"with the wrong size.");
|
||||||
MFEM_VERIFY(
|
|
||||||
gravity_gradient.Size() == Width(), "PreparedMappedHDivMassOperator received a gravity-gradient vector "
|
|
||||||
"with the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
m_flux_true.SetSize(m_flux_map.full_size());
|
m_flux_true.SetSize(m_flux_map.full_size());
|
||||||
m_action_true.SetSize(m_flux_map.full_size());
|
m_action_true.SetSize(m_flux_map.full_size());
|
||||||
|
m_domain_action_true.SetSize(m_flux_map.full_size());
|
||||||
m_flux_map.scatter(gravity_gradient, m_flux_true);
|
m_flux_map.scatter(gravity_gradient, m_flux_true);
|
||||||
m_mass_form->Mult(m_flux_true, m_action_true);
|
m_stellar_mass_form->Mult(m_flux_true, m_action_true);
|
||||||
|
m_vacuum_mass_form->Mult(m_flux_true, m_domain_action_true);
|
||||||
|
m_action_true += m_domain_action_true;
|
||||||
action.SetSize(Height());
|
action.SetSize(Height());
|
||||||
m_flux_map.gather(m_action_true, action);
|
m_flux_map.gather(m_action_true, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PreparedMappedHDivMassOperator::AssembleDiagonal(
|
||||||
|
mfem::Vector &diagonal) const {
|
||||||
|
mfem::Vector true_diagonal;
|
||||||
|
AssembleTrueDiagonal(true_diagonal);
|
||||||
|
diagonal.SetSize(Height());
|
||||||
|
m_flux_map.gather(true_diagonal, diagonal);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PreparedMappedHDivMassOperator::AssembleTrueDiagonal(
|
||||||
|
mfem::Vector &diagonal) const {
|
||||||
|
MFEM_VERIFY(m_is_prepared, "PreparedMappedHDivMassOperator must be prepared "
|
||||||
|
"before assembling its diagonal.");
|
||||||
|
MFEM_VERIFY(
|
||||||
|
m_stellar_mass_form != nullptr && m_vacuum_mass_form != nullptr,
|
||||||
|
"PreparedMappedHDivMassOperator has incomplete domain mass forms.");
|
||||||
|
|
||||||
|
diagonal.SetSize(m_flux_map.full_size());
|
||||||
|
mfem::Vector domain_diagonal(m_flux_map.full_size());
|
||||||
|
m_stellar_mass_form->AssembleDiagonal(diagonal);
|
||||||
|
m_vacuum_mass_form->AssembleDiagonal(domain_diagonal);
|
||||||
|
diagonal += domain_diagonal;
|
||||||
|
}
|
||||||
|
|
||||||
bool PreparedMappedHDivMassOperator::IsPrepared() const noexcept {
|
bool PreparedMappedHDivMassOperator::IsPrepared() const noexcept {
|
||||||
return m_is_prepared;
|
return m_is_prepared;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t PreparedMappedHDivMassOperator::GetPreparationCount() const noexcept {
|
std::uint64_t
|
||||||
|
PreparedMappedHDivMassOperator::GetPreparationCount() const noexcept {
|
||||||
return m_preparation_count;
|
return m_preparation_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field::FieldDofMap &PreparedMappedHDivMassOperator::GetFluxMap() const noexcept {
|
const field::FieldDofMap &
|
||||||
|
PreparedMappedHDivMassOperator::GetFluxMap() const noexcept {
|
||||||
return m_flux_map;
|
return m_flux_map;
|
||||||
}
|
}
|
||||||
|
|
||||||
const field::FieldDofMap &PreparedMappedHDivMassOperator::GetDisplacementMap() const noexcept {
|
const field::FieldDofMap &
|
||||||
|
PreparedMappedHDivMassOperator::GetDisplacementMap() const noexcept {
|
||||||
return m_displacement_map;
|
return m_displacement_map;
|
||||||
}
|
}
|
||||||
} // namespace mean_field::operators
|
} // namespace mean_field::operators
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,25 +9,28 @@ module mean_field;
|
|||||||
import :operators.prepared_mass_normalization;
|
import :operators.prepared_mass_normalization;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
void validate_finite_vector(
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
const mfem::Vector &vector,
|
|
||||||
const char *message
|
[[nodiscard]] bool is_vacuum_attribute(const int attribute) {
|
||||||
) {
|
return DomainSchema::template attribute_belongs_to<
|
||||||
|
mean_field::utils::domain::Vacuum>(attribute);
|
||||||
|
}
|
||||||
|
|
||||||
|
void validate_finite_vector(const mfem::Vector &vector, const char *message) {
|
||||||
for (int index = 0; index < vector.Size(); ++index) {
|
for (int index = 0; index < vector.Size(); ++index) {
|
||||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void true_to_local(
|
void true_to_local(const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
const mfem::Vector &trueVector, mfem::Vector &localVector) {
|
||||||
const mfem::Vector &trueVector,
|
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||||
mfem::Vector &localVector
|
"True vector has the wrong size.");
|
||||||
) {
|
|
||||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
|
||||||
|
|
||||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
const mfem::Operator *prolongation =
|
||||||
|
finiteElementSpace.GetProlongationMatrix();
|
||||||
|
|
||||||
if (prolongation != nullptr) {
|
if (prolongation != nullptr) {
|
||||||
prolongation->Mult(trueVector, localVector);
|
prolongation->Mult(trueVector, localVector);
|
||||||
@@ -36,42 +39,41 @@ namespace {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::IntegrationRule &get_mass_normalization_rule(
|
const mfem::IntegrationRule &
|
||||||
const mean_field::fem::FEM &f,
|
get_mass_normalization_rule(const mean_field::fem::FEM &f,
|
||||||
const mfem::FiniteElement &densityElement,
|
const mfem::FiniteElement &densityElement,
|
||||||
const mfem::ElementTransformation &transformation
|
const mfem::ElementTransformation &transformation) {
|
||||||
) {
|
|
||||||
using DensityField = mean_field::field::Field<mean_field::field::Density>;
|
using DensityField = mean_field::field::Field<mean_field::field::Density>;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(densityElement.GetOrder() ==
|
||||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
mean_field::field::Density::Scalar::familyOrder,
|
||||||
"The mass-normalization element does not match the registered "
|
"The mass-normalization element does not match the registered "
|
||||||
"density field."
|
"density field.");
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::quadrature::Query query =
|
const mean_field::quadrature::Query query = DensityField::make_query<
|
||||||
DensityField::make_query<mean_field::field::Density::Form::MassNormalization>(
|
mean_field::field::Density::Form::MassNormalization>(
|
||||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), std::array<int, 0>{},
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
transformation.OrderW(), std::array<int, 0>{},
|
||||||
);
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const auto resolution = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
const auto resolution =
|
||||||
|
f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
resolution.integration_rule != nullptr, "The quadrature policy did not return a mass-normalization rule."
|
resolution.integration_rule != nullptr,
|
||||||
);
|
"The quadrature policy did not return a mass-normalization rule.");
|
||||||
|
|
||||||
return *resolution.integration_rule;
|
return *resolution.integration_rule;
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_shared_gravity_revisions(
|
void validate_shared_gravity_revisions(
|
||||||
const mean_field::operators::context::gravity_field::GravityFieldLinearizationContext &gravityContext,
|
const mean_field::operators::context::gravity_field::
|
||||||
const mean_field::operators::MassNormalizationDependencies &dependencies
|
GravityFieldLinearizationContext &gravityContext,
|
||||||
) {
|
const mean_field::operators::MassNormalizationDependencies &dependencies) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(gravityContext.IsPrepared(),
|
||||||
gravityContext.IsPrepared(), "PreparedMassNormalizationOperator requires the shared gravity "
|
"PreparedMassNormalizationOperator requires the shared gravity "
|
||||||
"linearization context to be prepared first."
|
"linearization context to be prepared first.");
|
||||||
);
|
|
||||||
|
|
||||||
const auto &revisions = gravityContext.GetRevisions();
|
const auto &revisions = gravityContext.GetRevisions();
|
||||||
|
|
||||||
@@ -80,60 +82,55 @@ namespace {
|
|||||||
revisions.density.value == dependencies.density.revision &&
|
revisions.density.value == dependencies.density.revision &&
|
||||||
revisions.displacement.value == dependencies.displacement.revision,
|
revisions.displacement.value == dependencies.displacement.revision,
|
||||||
"PreparedMassNormalizationOperator received dependency revisions "
|
"PreparedMassNormalizationOperator received dependency revisions "
|
||||||
"that do not match the shared gravity context."
|
"that do not match the shared gravity context.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void validate_shared_identity_transition(
|
void validate_shared_identity_transition(
|
||||||
const mean_field::operators::MassNormalizationDependencyStamp &prepared,
|
const mean_field::operators::MassNormalizationDependencyStamp &prepared,
|
||||||
const mean_field::operators::MassNormalizationDependencyStamp &requested,
|
const mean_field::operators::MassNormalizationDependencyStamp &requested,
|
||||||
const char *message
|
const char *message) {
|
||||||
) {
|
MFEM_VERIFY(prepared.identity == requested.identity ||
|
||||||
MFEM_VERIFY(prepared.identity == requested.identity || prepared.revision != requested.revision, message);
|
prepared.revision != requested.revision,
|
||||||
|
message);
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
namespace mean_field::operators {
|
namespace mean_field::operators {
|
||||||
PreparedMassNormalizationOperator::PreparedMassNormalizationOperator(
|
PreparedMassNormalizationOperator::PreparedMassNormalizationOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f, const mapping::DomainMapper &domainMapper,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const context::gravity_field::GravityFieldLinearizationContext
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
&gravityContext)
|
||||||
)
|
: m_fem(f), m_domainMapper(domainMapper), m_gravityContext(gravityContext) {
|
||||||
: m_fem(f),
|
MFEM_VERIFY(m_fem.mesh != nullptr,
|
||||||
m_domainMapper(domainMapper),
|
"PreparedMassNormalizationOperator requires a mesh.");
|
||||||
m_gravityContext(gravityContext) {
|
MFEM_VERIFY(m_fem.densityFes != nullptr && m_fem.displacementFes != nullptr &&
|
||||||
MFEM_VERIFY(m_fem.mesh != nullptr, "PreparedMassNormalizationOperator requires a mesh.");
|
m_fem.compactificationFes != nullptr &&
|
||||||
MFEM_VERIFY(
|
m_fem.compactificationCoordinate != nullptr &&
|
||||||
m_fem.densityFes != nullptr && m_fem.displacementFes != nullptr && m_fem.compactificationFes != nullptr &&
|
m_fem.quadratureFactory != nullptr,
|
||||||
m_fem.compactificationCoordinate != nullptr && m_fem.quadratureFactory != nullptr,
|
|
||||||
"PreparedMassNormalizationOperator requires density, "
|
"PreparedMassNormalizationOperator requires density, "
|
||||||
"displacement, compactification, and quadrature data."
|
"displacement, compactification, and quadrature data.");
|
||||||
);
|
MFEM_VERIFY(m_domainMapper.GetDimension() == m_fem.mesh->Dimension(),
|
||||||
MFEM_VERIFY(
|
|
||||||
m_domainMapper.GetDimension() == m_fem.mesh->Dimension(),
|
|
||||||
"PreparedMassNormalizationOperator received a mapper with the "
|
"PreparedMassNormalizationOperator received a mapper with the "
|
||||||
"wrong dimension."
|
"wrong dimension.");
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(m_gravityContext.GetDensityMap().full_size() ==
|
||||||
m_gravityContext.GetDensityMap().full_size() == m_fem.densityFes->GetTrueVSize() &&
|
m_fem.densityFes->GetTrueVSize() &&
|
||||||
m_gravityContext.GetDisplacementMap().full_size() == m_fem.displacementFes->GetTrueVSize(),
|
m_gravityContext.GetDisplacementMap().full_size() ==
|
||||||
"PreparedMassNormalizationOperator received incompatible shared FieldDof maps."
|
m_fem.displacementFes->GetTrueVSize(),
|
||||||
);
|
"PreparedMassNormalizationOperator received incompatible shared "
|
||||||
|
"FieldDof maps.");
|
||||||
|
|
||||||
m_densityVariationTrue.SetSize(m_gravityContext.GetDensityMap().full_size());
|
m_densityVariationTrue.SetSize(m_gravityContext.GetDensityMap().full_size());
|
||||||
m_displacementVariationTrue.SetSize(m_gravityContext.GetDisplacementMap().full_size());
|
m_displacementVariationTrue.SetSize(
|
||||||
|
m_gravityContext.GetDisplacementMap().full_size());
|
||||||
}
|
}
|
||||||
|
|
||||||
PreparedMassNormalizationReport PreparedMassNormalizationOperator::Prepare(
|
PreparedMassNormalizationReport PreparedMassNormalizationOperator::Prepare(
|
||||||
const MassNormalizationStateView &state,
|
const MassNormalizationStateView &state,
|
||||||
const MassNormalizationDependencies &dependencies
|
const MassNormalizationDependencies &dependencies) {
|
||||||
) {
|
MFEM_VERIFY(std::isfinite(state.targetMass) && state.targetMass > 0.0,
|
||||||
MFEM_VERIFY(
|
|
||||||
std::isfinite(state.targetMass) && state.targetMass > 0.0,
|
|
||||||
"PreparedMassNormalizationOperator requires a finite, positive "
|
"PreparedMassNormalizationOperator requires a finite, positive "
|
||||||
"target mass."
|
"target mass.");
|
||||||
);
|
|
||||||
|
|
||||||
validate_shared_gravity_revisions(m_gravityContext, dependencies);
|
validate_shared_gravity_revisions(m_gravityContext, dependencies);
|
||||||
|
|
||||||
@@ -141,29 +138,32 @@ namespace mean_field::operators {
|
|||||||
validate_shared_identity_transition(
|
validate_shared_identity_transition(
|
||||||
m_preparedDependencies.discretization, dependencies.discretization,
|
m_preparedDependencies.discretization, dependencies.discretization,
|
||||||
"A new mass-normalization discretization identity must also "
|
"A new mass-normalization discretization identity must also "
|
||||||
"change the shared gravity revision."
|
"change the shared gravity revision.");
|
||||||
);
|
|
||||||
validate_shared_identity_transition(
|
validate_shared_identity_transition(
|
||||||
m_preparedDependencies.density, dependencies.density,
|
m_preparedDependencies.density, dependencies.density,
|
||||||
"A new mass-normalization density identity must also change "
|
"A new mass-normalization density identity must also change "
|
||||||
"the shared gravity revision."
|
"the shared gravity revision.");
|
||||||
);
|
|
||||||
validate_shared_identity_transition(
|
validate_shared_identity_transition(
|
||||||
m_preparedDependencies.displacement, dependencies.displacement,
|
m_preparedDependencies.displacement, dependencies.displacement,
|
||||||
"A new mass-normalization displacement identity must also "
|
"A new mass-normalization displacement identity must also "
|
||||||
"change the shared gravity revision."
|
"change the shared gravity revision.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool rebuildStaticPlan =
|
const bool rebuildStaticPlan =
|
||||||
!m_isPrepared || dependencies.discretization != m_preparedDependencies.discretization;
|
!m_isPrepared ||
|
||||||
|
dependencies.discretization != m_preparedDependencies.discretization;
|
||||||
|
|
||||||
const bool refreshGeometry =
|
const bool refreshGeometry =
|
||||||
rebuildStaticPlan || dependencies.displacement != m_preparedDependencies.displacement;
|
rebuildStaticPlan ||
|
||||||
|
dependencies.displacement != m_preparedDependencies.displacement;
|
||||||
|
|
||||||
const bool refreshDensity = rebuildStaticPlan || dependencies.density != m_preparedDependencies.density;
|
const bool refreshDensity =
|
||||||
|
rebuildStaticPlan ||
|
||||||
|
dependencies.density != m_preparedDependencies.density;
|
||||||
|
|
||||||
const bool updateTargetMass = !m_isPrepared || dependencies.targetMass != m_preparedDependencies.targetMass ||
|
const bool updateTargetMass =
|
||||||
|
!m_isPrepared ||
|
||||||
|
dependencies.targetMass != m_preparedDependencies.targetMass ||
|
||||||
state.targetMass != m_targetMass;
|
state.targetMass != m_targetMass;
|
||||||
|
|
||||||
m_isPrepared = false;
|
m_isPrepared = false;
|
||||||
@@ -176,7 +176,8 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (refreshGeometry) {
|
if (refreshGeometry) {
|
||||||
RefreshGeometry(m_gravityContext.GetGeometryContext().GetDisplacementTrue());
|
RefreshGeometry(
|
||||||
|
m_gravityContext.GetGeometryContext().GetDisplacementTrue());
|
||||||
report.refreshedGeometry = true;
|
report.refreshedGeometry = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -209,19 +210,17 @@ namespace mean_field::operators {
|
|||||||
m_elements.clear();
|
m_elements.clear();
|
||||||
m_elements.reserve(m_fem.mesh->GetNE());
|
m_elements.reserve(m_fem.mesh->GetNE());
|
||||||
|
|
||||||
const int vacuumAttribute = m_domainMapper.GetVacuumElementAttribute();
|
|
||||||
|
|
||||||
int localStellarElementCount = 0;
|
int localStellarElementCount = 0;
|
||||||
|
|
||||||
for (int elementId = 0; elementId < m_fem.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < m_fem.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
m_fem.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(transformation != nullptr,
|
||||||
transformation != nullptr, "PreparedMassNormalizationOperator received a null element "
|
"PreparedMassNormalizationOperator received a null element "
|
||||||
"transformation."
|
"transformation.");
|
||||||
);
|
|
||||||
|
|
||||||
if (transformation->Attribute == vacuumAttribute) {
|
if (is_vacuum_attribute(transformation->Attribute)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -230,22 +229,26 @@ namespace mean_field::operators {
|
|||||||
ElementPAData &data = m_elements.back();
|
ElementPAData &data = m_elements.back();
|
||||||
data.elementId = elementId;
|
data.elementId = elementId;
|
||||||
|
|
||||||
data.densityDofTransformation = m_fem.densityFes->GetElementDofs(elementId, data.densityDofs);
|
data.densityDofTransformation =
|
||||||
|
m_fem.densityFes->GetElementDofs(elementId, data.densityDofs);
|
||||||
|
|
||||||
data.displacementDofTransformation =
|
data.displacementDofTransformation = m_fem.displacementFes->GetElementVDofs(
|
||||||
m_fem.displacementFes->GetElementVDofs(elementId, data.displacementDofs);
|
elementId, data.displacementDofs);
|
||||||
|
|
||||||
data.compactificationDofTransformation =
|
data.compactificationDofTransformation =
|
||||||
m_fem.compactificationFes->GetElementDofs(elementId, data.compactificationDofs);
|
m_fem.compactificationFes->GetElementDofs(elementId,
|
||||||
|
data.compactificationDofs);
|
||||||
|
|
||||||
const mfem::FiniteElement &densityElement = *m_fem.densityFes->GetFE(elementId);
|
const mfem::FiniteElement &densityElement =
|
||||||
|
*m_fem.densityFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::IntegrationRule &integrationRule =
|
const mfem::IntegrationRule &integrationRule =
|
||||||
get_mass_normalization_rule(m_fem, densityElement, *transformation);
|
get_mass_normalization_rule(m_fem, densityElement, *transformation);
|
||||||
|
|
||||||
data.quadraturePoints.resize(integrationRule.GetNPoints());
|
data.quadraturePoints.resize(integrationRule.GetNPoints());
|
||||||
|
|
||||||
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
for (int quadraturePoint = 0;
|
||||||
|
quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
||||||
QuadraturePointData &point = data.quadraturePoints[quadraturePoint];
|
QuadraturePointData &point = data.quadraturePoints[quadraturePoint];
|
||||||
|
|
||||||
point.integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
point.integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
||||||
@@ -256,85 +259,88 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int globalStellarElementCount = 0;
|
int globalStellarElementCount = 0;
|
||||||
MPI_Allreduce(
|
MPI_Allreduce(&localStellarElementCount, &globalStellarElementCount, 1,
|
||||||
&localStellarElementCount, &globalStellarElementCount, 1, MPI_INT, MPI_SUM, m_fem.mesh->GetComm()
|
MPI_INT, MPI_SUM, m_fem.mesh->GetComm());
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(globalStellarElementCount > 0, "PreparedMassNormalizationOperator found no stellar elements.");
|
MFEM_VERIFY(globalStellarElementCount > 0,
|
||||||
|
"PreparedMassNormalizationOperator found no stellar elements.");
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationOperator::RefreshGeometry(const mfem::Vector &displacement) {
|
void PreparedMassNormalizationOperator::RefreshGeometry(
|
||||||
MFEM_VERIFY(
|
const mfem::Vector &displacement) {
|
||||||
displacement.Size() == m_fem.displacementFes->GetTrueVSize(),
|
MFEM_VERIFY(displacement.Size() == m_fem.displacementFes->GetTrueVSize(),
|
||||||
"PreparedMassNormalizationOperator received a displacement "
|
"PreparedMassNormalizationOperator received a displacement "
|
||||||
"vector with the wrong size."
|
"vector with the wrong size.");
|
||||||
);
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
displacement, "PreparedMassNormalizationOperator received a non-finite "
|
displacement, "PreparedMassNormalizationOperator received a non-finite "
|
||||||
"displacement value."
|
"displacement value.");
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector displacementLocal;
|
mfem::Vector displacementLocal;
|
||||||
true_to_local(*m_fem.displacementFes, displacement, displacementLocal);
|
true_to_local(*m_fem.displacementFes, displacement, displacementLocal);
|
||||||
|
|
||||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
|
||||||
|
|
||||||
for (ElementPAData &data : m_elements) {
|
for (ElementPAData &data : m_elements) {
|
||||||
displacementLocal.GetSubVector(data.displacementDofs, data.baseDisplacement);
|
displacementLocal.GetSubVector(data.displacementDofs,
|
||||||
|
data.baseDisplacement);
|
||||||
|
|
||||||
m_fem.compactificationCoordinate->GetSubVector(data.compactificationDofs, data.compactification);
|
m_fem.compactificationCoordinate->GetSubVector(data.compactificationDofs,
|
||||||
|
data.compactification);
|
||||||
|
|
||||||
if (data.displacementDofTransformation != nullptr) {
|
if (data.displacementDofTransformation != nullptr) {
|
||||||
data.displacementDofTransformation->InvTransformPrimal(data.baseDisplacement);
|
data.displacementDofTransformation->InvTransformPrimal(
|
||||||
|
data.baseDisplacement);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (data.compactificationDofTransformation != nullptr) {
|
if (data.compactificationDofTransformation != nullptr) {
|
||||||
data.compactificationDofTransformation->InvTransformPrimal(data.compactification);
|
data.compactificationDofTransformation->InvTransformPrimal(
|
||||||
|
data.compactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(data.elementId);
|
const mfem::FiniteElement &displacementElement =
|
||||||
|
*m_fem.displacementFes->GetFE(data.elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &compactificationElement = *m_fem.compactificationFes->GetFE(data.elementId);
|
const mfem::FiniteElement &compactificationElement =
|
||||||
|
*m_fem.compactificationFes->GetFE(data.elementId);
|
||||||
|
|
||||||
const mapping::ElementDisplacementData displacementData =
|
const mapping::ElementDisplacementData displacementData =
|
||||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, data.baseDisplacement);
|
mapping::ElementDisplacementDataFromElementVDofs(displacementElement,
|
||||||
|
data.baseDisplacement);
|
||||||
|
|
||||||
const mapping::ElementCompactificationData compactificationData(
|
const mapping::ElementCompactificationData compactificationData(
|
||||||
compactificationElement, data.compactification
|
compactificationElement, data.compactification);
|
||||||
);
|
|
||||||
|
|
||||||
const mapping::ElementMappingData mappingData{
|
const mapping::ElementMappingData mappingData{
|
||||||
.displacement = displacementData, .compactification = compactificationData
|
.displacement = displacementData,
|
||||||
};
|
.compactification = compactificationData};
|
||||||
|
|
||||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
m_fem.mesh->GetElementTransformation(data.elementId);
|
||||||
|
|
||||||
for (QuadraturePointData &point : data.quadraturePoints) {
|
for (QuadraturePointData &point : data.quadraturePoints) {
|
||||||
const mapping::MappingStatus status = m_domainMapper.EvaluateVolume(
|
const mapping::MappingStatus status = m_domainMapper.EvaluateVolume(
|
||||||
mappingData, *transformation, point.integrationPoint, workspace, point.mappingContext
|
mappingData, *transformation, point.integrationPoint, workspace,
|
||||||
);
|
point.mappingContext);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(status == mapping::MappingStatus::valid,
|
||||||
status == mapping::MappingStatus::valid, "Stateless mapping failed while preparing mass "
|
"Stateless mapping failed while preparing mass "
|
||||||
"normalization. Element: "
|
"normalization. Element: "
|
||||||
<< data.elementId
|
<< data.elementId
|
||||||
<< ", attribute: " << transformation->Attribute
|
<< ", attribute: " << transformation->Attribute
|
||||||
<< ", status: " << static_cast<int>(status)
|
<< ", status: " << static_cast<int>(status));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationOperator::RefreshDensity(const mfem::Vector &density) {
|
void PreparedMassNormalizationOperator::RefreshDensity(
|
||||||
MFEM_VERIFY(
|
const mfem::Vector &density) {
|
||||||
density.Size() == m_fem.densityFes->GetTrueVSize(),
|
MFEM_VERIFY(density.Size() == m_fem.densityFes->GetTrueVSize(),
|
||||||
"PreparedMassNormalizationOperator received a density vector "
|
"PreparedMassNormalizationOperator received a density vector "
|
||||||
"with the wrong size."
|
"with the wrong size.");
|
||||||
);
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
density, "PreparedMassNormalizationOperator received a non-finite density "
|
density,
|
||||||
"value."
|
"PreparedMassNormalizationOperator received a non-finite density "
|
||||||
);
|
"value.");
|
||||||
|
|
||||||
mfem::Vector densityLocal;
|
mfem::Vector densityLocal;
|
||||||
true_to_local(*m_fem.densityFes, density, densityLocal);
|
true_to_local(*m_fem.densityFes, density, densityLocal);
|
||||||
@@ -350,10 +356,9 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
for (QuadraturePointData &point : data.quadraturePoints) {
|
for (QuadraturePointData &point : data.quadraturePoints) {
|
||||||
point.density = elementDensity * point.densityShape;
|
point.density = elementDensity * point.densityShape;
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(point.density),
|
||||||
std::isfinite(point.density), "PreparedMassNormalizationOperator produced a non-finite "
|
"PreparedMassNormalizationOperator produced a non-finite "
|
||||||
"quadrature density."
|
"quadrature density.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -368,26 +373,29 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
m_currentMass = GlobalSum(localMass);
|
m_currentMass = GlobalSum(localMass);
|
||||||
MFEM_VERIFY(std::isfinite(m_currentMass), "PreparedMassNormalizationOperator assembled a non-finite mass.");
|
MFEM_VERIFY(std::isfinite(m_currentMass),
|
||||||
|
"PreparedMassNormalizationOperator assembled a non-finite mass.");
|
||||||
|
|
||||||
m_cachedResidual.SetSize(1);
|
m_cachedResidual.SetSize(1);
|
||||||
m_cachedResidual(0) = m_currentMass - m_targetMass;
|
m_cachedResidual(0) = m_currentMass - m_targetMass;
|
||||||
++m_preparationCount;
|
++m_preparationCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationOperator::BuildResidual(mfem::Vector &residual) const {
|
void PreparedMassNormalizationOperator::BuildResidual(
|
||||||
|
mfem::Vector &residual) const {
|
||||||
VerifyPrepared();
|
VerifyPrepared();
|
||||||
residual = m_cachedResidual;
|
residual = m_cachedResidual;
|
||||||
++m_residualApplicationCount;
|
++m_residualApplicationCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
double PreparedMassNormalizationOperator::EvaluateDensityActionLocal(const mfem::Vector &densityVariation) const {
|
double PreparedMassNormalizationOperator::EvaluateDensityActionLocal(
|
||||||
MFEM_VERIFY(
|
const mfem::Vector &densityVariation) const {
|
||||||
densityVariation.Size() == m_fem.densityFes->GetTrueVSize(),
|
MFEM_VERIFY(densityVariation.Size() == m_fem.densityFes->GetTrueVSize(),
|
||||||
"Mass-normalization density action received a vector with the "
|
"Mass-normalization density action received a vector with the "
|
||||||
"wrong size."
|
"wrong size.");
|
||||||
);
|
validate_finite_vector(
|
||||||
validate_finite_vector(densityVariation, "Mass-normalization density action received a non-finite value.");
|
densityVariation,
|
||||||
|
"Mass-normalization density action received a non-finite value.");
|
||||||
|
|
||||||
mfem::Vector densityVariationLocal;
|
mfem::Vector densityVariationLocal;
|
||||||
true_to_local(*m_fem.densityFes, densityVariation, densityVariationLocal);
|
true_to_local(*m_fem.densityFes, densityVariation, densityVariationLocal);
|
||||||
@@ -396,14 +404,17 @@ namespace mean_field::operators {
|
|||||||
double localAction = 0.0;
|
double localAction = 0.0;
|
||||||
|
|
||||||
for (const ElementPAData &data : m_elements) {
|
for (const ElementPAData &data : m_elements) {
|
||||||
densityVariationLocal.GetSubVector(data.densityDofs, elementDensityVariation);
|
densityVariationLocal.GetSubVector(data.densityDofs,
|
||||||
|
elementDensityVariation);
|
||||||
|
|
||||||
if (data.densityDofTransformation != nullptr) {
|
if (data.densityDofTransformation != nullptr) {
|
||||||
data.densityDofTransformation->InvTransformPrimal(elementDensityVariation);
|
data.densityDofTransformation->InvTransformPrimal(
|
||||||
|
elementDensityVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const QuadraturePointData &point : data.quadraturePoints) {
|
for (const QuadraturePointData &point : data.quadraturePoints) {
|
||||||
localAction += (elementDensityVariation * point.densityShape) * point.mappingContext.quadrature.weight;
|
localAction += (elementDensityVariation * point.densityShape) *
|
||||||
|
point.mappingContext.quadrature.weight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -411,67 +422,72 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
double PreparedMassNormalizationOperator::EvaluateDisplacementActionLocal(
|
double PreparedMassNormalizationOperator::EvaluateDisplacementActionLocal(
|
||||||
const mfem::Vector &displacementVariation
|
const mfem::Vector &displacementVariation) const {
|
||||||
) const {
|
MFEM_VERIFY(displacementVariation.Size() ==
|
||||||
MFEM_VERIFY(
|
m_fem.displacementFes->GetTrueVSize(),
|
||||||
displacementVariation.Size() == m_fem.displacementFes->GetTrueVSize(),
|
|
||||||
"Mass-normalization displacement action received a vector with "
|
"Mass-normalization displacement action received a vector with "
|
||||||
"the wrong size."
|
"the wrong size.");
|
||||||
);
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
displacementVariation, "Mass-normalization displacement action received a non-finite "
|
displacementVariation,
|
||||||
"value."
|
"Mass-normalization displacement action received a non-finite "
|
||||||
);
|
"value.");
|
||||||
|
|
||||||
mfem::Vector displacementVariationLocal;
|
mfem::Vector displacementVariationLocal;
|
||||||
true_to_local(*m_fem.displacementFes, displacementVariation, displacementVariationLocal);
|
true_to_local(*m_fem.displacementFes, displacementVariation,
|
||||||
|
displacementVariationLocal);
|
||||||
|
|
||||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Vector elementDisplacementVariation;
|
mfem::Vector elementDisplacementVariation;
|
||||||
double localAction = 0.0;
|
double localAction = 0.0;
|
||||||
|
|
||||||
for (const ElementPAData &data : m_elements) {
|
for (const ElementPAData &data : m_elements) {
|
||||||
displacementVariationLocal.GetSubVector(data.displacementDofs, elementDisplacementVariation);
|
displacementVariationLocal.GetSubVector(data.displacementDofs,
|
||||||
|
elementDisplacementVariation);
|
||||||
|
|
||||||
if (data.displacementDofTransformation != nullptr) {
|
if (data.displacementDofTransformation != nullptr) {
|
||||||
data.displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
data.displacementDofTransformation->InvTransformPrimal(
|
||||||
|
elementDisplacementVariation);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(data.elementId);
|
const mfem::FiniteElement &displacementElement =
|
||||||
|
*m_fem.displacementFes->GetFE(data.elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &compactificationElement = *m_fem.compactificationFes->GetFE(data.elementId);
|
const mfem::FiniteElement &compactificationElement =
|
||||||
|
*m_fem.compactificationFes->GetFE(data.elementId);
|
||||||
|
|
||||||
const mapping::ElementDisplacementData baseDisplacementData =
|
const mapping::ElementDisplacementData baseDisplacementData =
|
||||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, data.baseDisplacement);
|
mapping::ElementDisplacementDataFromElementVDofs(displacementElement,
|
||||||
|
data.baseDisplacement);
|
||||||
|
|
||||||
const mapping::ElementDisplacementData directionData =
|
const mapping::ElementDisplacementData directionData =
|
||||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacementVariation);
|
mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
|
displacementElement, elementDisplacementVariation);
|
||||||
|
|
||||||
const mapping::ElementCompactificationData compactificationData(
|
const mapping::ElementCompactificationData compactificationData(
|
||||||
compactificationElement, data.compactification
|
compactificationElement, data.compactification);
|
||||||
);
|
|
||||||
|
|
||||||
const mapping::ElementMappingData mappingData{
|
const mapping::ElementMappingData mappingData{
|
||||||
.displacement = baseDisplacementData, .compactification = compactificationData
|
.displacement = baseDisplacementData,
|
||||||
};
|
.compactification = compactificationData};
|
||||||
|
|
||||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
m_fem.mesh->GetElementTransformation(data.elementId);
|
||||||
|
|
||||||
for (const QuadraturePointData &point : data.quadraturePoints) {
|
for (const QuadraturePointData &point : data.quadraturePoints) {
|
||||||
mapping::VolumeMappingVariation variation;
|
mapping::VolumeMappingVariation variation;
|
||||||
|
|
||||||
const mapping::MappingStatus status = m_domainMapper.EvaluateVolumeVariation(
|
const mapping::MappingStatus status =
|
||||||
mappingData, directionData, *transformation, point.integrationPoint, point.mappingContext,
|
m_domainMapper.EvaluateVolumeVariation(
|
||||||
workspace, variation
|
mappingData, directionData, *transformation,
|
||||||
);
|
point.integrationPoint, point.mappingContext, workspace,
|
||||||
|
variation);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(status == mapping::MappingStatus::valid,
|
||||||
status == mapping::MappingStatus::valid, "Stateless mapping variation failed in the "
|
"Stateless mapping variation failed in the "
|
||||||
"mass-normalization displacement action. Element: "
|
"mass-normalization displacement action. Element: "
|
||||||
<< data.elementId
|
<< data.elementId
|
||||||
<< ", status: " << static_cast<int>(status)
|
<< ", status: " << static_cast<int>(status));
|
||||||
);
|
|
||||||
|
|
||||||
localAction += point.density * variation.weight_variation;
|
localAction += point.density * variation.weight_variation;
|
||||||
}
|
}
|
||||||
@@ -481,17 +497,18 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationOperator::ApplyDensityJacobianAction(
|
void PreparedMassNormalizationOperator::ApplyDensityJacobianAction(
|
||||||
const mfem::Vector &densityVariation,
|
const mfem::Vector &densityVariation, mfem::Vector &action) const {
|
||||||
mfem::Vector &action
|
|
||||||
) const {
|
|
||||||
VerifyPrepared();
|
VerifyPrepared();
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(densityVariation.Size() ==
|
||||||
densityVariation.Size() == m_gravityContext.GetDensityMap().reduced_size(),
|
m_gravityContext.GetDensityMap().reduced_size(),
|
||||||
"Mass-normalization density action received a supported vector with the wrong size."
|
"Mass-normalization density action received a supported vector "
|
||||||
);
|
"with the wrong size.");
|
||||||
validate_finite_vector(densityVariation, "Mass-normalization density action received a non-finite value.");
|
validate_finite_vector(
|
||||||
m_gravityContext.GetDensityMap().scatter(densityVariation, m_densityVariationTrue);
|
densityVariation,
|
||||||
|
"Mass-normalization density action received a non-finite value.");
|
||||||
|
m_gravityContext.GetDensityMap().scatter(densityVariation,
|
||||||
|
m_densityVariationTrue);
|
||||||
|
|
||||||
action.SetSize(1);
|
action.SetSize(1);
|
||||||
action(0) = GlobalSum(EvaluateDensityActionLocal(m_densityVariationTrue));
|
action(0) = GlobalSum(EvaluateDensityActionLocal(m_densityVariationTrue));
|
||||||
@@ -499,47 +516,49 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationOperator::ApplyDisplacementJacobianAction(
|
void PreparedMassNormalizationOperator::ApplyDisplacementJacobianAction(
|
||||||
const mfem::Vector &displacementVariation,
|
const mfem::Vector &displacementVariation, mfem::Vector &action) const {
|
||||||
mfem::Vector &action
|
|
||||||
) const {
|
|
||||||
VerifyPrepared();
|
VerifyPrepared();
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementVariation.Size() ==
|
||||||
displacementVariation.Size() == m_gravityContext.GetDisplacementMap().reduced_size(),
|
m_gravityContext.GetDisplacementMap().reduced_size(),
|
||||||
"Mass-normalization displacement action received a supported vector with the wrong size."
|
"Mass-normalization displacement action received a supported "
|
||||||
);
|
"vector with the wrong size.");
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
displacementVariation, "Mass-normalization displacement action received a non-finite value."
|
displacementVariation,
|
||||||
);
|
"Mass-normalization displacement action received a non-finite value.");
|
||||||
m_gravityContext.GetDisplacementMap().scatter(displacementVariation, m_displacementVariationTrue);
|
m_gravityContext.GetDisplacementMap().scatter(displacementVariation,
|
||||||
|
m_displacementVariationTrue);
|
||||||
|
|
||||||
action.SetSize(1);
|
action.SetSize(1);
|
||||||
action(0) = GlobalSum(EvaluateDisplacementActionLocal(m_displacementVariationTrue));
|
action(0) =
|
||||||
|
GlobalSum(EvaluateDisplacementActionLocal(m_displacementVariationTrue));
|
||||||
++m_actionStatistics.displacementApplications;
|
++m_actionStatistics.displacementApplications;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationOperator::ApplyCompleteJacobianAction(
|
void PreparedMassNormalizationOperator::ApplyCompleteJacobianAction(
|
||||||
const mfem::Vector &densityVariation,
|
const mfem::Vector &densityVariation,
|
||||||
const mfem::Vector &displacementVariation,
|
const mfem::Vector &displacementVariation, mfem::Vector &action) const {
|
||||||
mfem::Vector &action
|
|
||||||
) const {
|
|
||||||
VerifyPrepared();
|
VerifyPrepared();
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(densityVariation.Size() ==
|
||||||
densityVariation.Size() == m_gravityContext.GetDensityMap().reduced_size(),
|
m_gravityContext.GetDensityMap().reduced_size(),
|
||||||
"Mass-normalization complete action received a supported density vector with the wrong size."
|
"Mass-normalization complete action received a supported density "
|
||||||
);
|
"vector with the wrong size.");
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementVariation.Size() ==
|
||||||
displacementVariation.Size() == m_gravityContext.GetDisplacementMap().reduced_size(),
|
m_gravityContext.GetDisplacementMap().reduced_size(),
|
||||||
"Mass-normalization complete action received a supported displacement vector with the wrong size."
|
"Mass-normalization complete action received a supported "
|
||||||
);
|
"displacement vector with the wrong size.");
|
||||||
validate_finite_vector(densityVariation, "Mass-normalization complete action received a non-finite density.");
|
|
||||||
validate_finite_vector(
|
validate_finite_vector(
|
||||||
displacementVariation, "Mass-normalization complete action received a non-finite displacement."
|
densityVariation,
|
||||||
);
|
"Mass-normalization complete action received a non-finite density.");
|
||||||
|
validate_finite_vector(
|
||||||
|
displacementVariation,
|
||||||
|
"Mass-normalization complete action received a non-finite displacement.");
|
||||||
|
|
||||||
m_gravityContext.GetDensityMap().scatter(densityVariation, m_densityVariationTrue);
|
m_gravityContext.GetDensityMap().scatter(densityVariation,
|
||||||
m_gravityContext.GetDisplacementMap().scatter(displacementVariation, m_displacementVariationTrue);
|
m_densityVariationTrue);
|
||||||
|
m_gravityContext.GetDisplacementMap().scatter(displacementVariation,
|
||||||
|
m_displacementVariationTrue);
|
||||||
|
|
||||||
const double localAction =
|
const double localAction =
|
||||||
EvaluateDensityActionLocal(m_densityVariationTrue) +
|
EvaluateDensityActionLocal(m_densityVariationTrue) +
|
||||||
@@ -550,9 +569,11 @@ namespace mean_field::operators {
|
|||||||
++m_actionStatistics.completeApplications;
|
++m_actionStatistics.completeApplications;
|
||||||
}
|
}
|
||||||
|
|
||||||
double PreparedMassNormalizationOperator::GlobalSum(const double localValue) const {
|
double
|
||||||
|
PreparedMassNormalizationOperator::GlobalSum(const double localValue) const {
|
||||||
double globalValue = 0.0;
|
double globalValue = 0.0;
|
||||||
MPI_Allreduce(&localValue, &globalValue, 1, MPI_DOUBLE, MPI_SUM, m_fem.mesh->GetComm());
|
MPI_Allreduce(&localValue, &globalValue, 1, MPI_DOUBLE, MPI_SUM,
|
||||||
|
m_fem.mesh->GetComm());
|
||||||
return globalValue;
|
return globalValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -562,9 +583,11 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const auto &revisions = m_gravityContext.GetRevisions();
|
const auto &revisions = m_gravityContext.GetRevisions();
|
||||||
return revisions.discretization.value == m_preparedDependencies.discretization.revision &&
|
return revisions.discretization.value ==
|
||||||
|
m_preparedDependencies.discretization.revision &&
|
||||||
revisions.density.value == m_preparedDependencies.density.revision &&
|
revisions.density.value == m_preparedDependencies.density.revision &&
|
||||||
revisions.displacement.value == m_preparedDependencies.displacement.revision;
|
revisions.displacement.value ==
|
||||||
|
m_preparedDependencies.displacement.revision;
|
||||||
}
|
}
|
||||||
|
|
||||||
double PreparedMassNormalizationOperator::GetCurrentMass() const {
|
double PreparedMassNormalizationOperator::GetCurrentMass() const {
|
||||||
@@ -577,11 +600,13 @@ namespace mean_field::operators {
|
|||||||
return m_targetMass;
|
return m_targetMass;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t PreparedMassNormalizationOperator::GetPreparationCount() const noexcept {
|
std::uint64_t
|
||||||
|
PreparedMassNormalizationOperator::GetPreparationCount() const noexcept {
|
||||||
return m_preparationCount;
|
return m_preparationCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::uint64_t PreparedMassNormalizationOperator::GetResidualApplicationCount() const noexcept {
|
std::uint64_t PreparedMassNormalizationOperator::GetResidualApplicationCount()
|
||||||
|
const noexcept {
|
||||||
return m_residualApplicationCount;
|
return m_residualApplicationCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -600,56 +625,54 @@ namespace mean_field::operators {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationOperator::VerifyPrepared() const {
|
void PreparedMassNormalizationOperator::VerifyPrepared() const {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(IsPrepared(),
|
||||||
IsPrepared(), "PreparedMassNormalizationOperator must be prepared for the "
|
"PreparedMassNormalizationOperator must be prepared for the "
|
||||||
"current shared gravity-context revisions."
|
"current shared gravity-context revisions.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PreparedMassNormalizationJacobianOperator::PreparedMassNormalizationJacobianOperator(
|
PreparedMassNormalizationJacobianOperator::
|
||||||
|
PreparedMassNormalizationJacobianOperator(
|
||||||
const MassNormalizationLayout &layout,
|
const MassNormalizationLayout &layout,
|
||||||
const PreparedMassNormalizationOperator &preparedOperator
|
const PreparedMassNormalizationOperator &preparedOperator)
|
||||||
)
|
: mfem::Operator(layout.residual_offsets().Last(),
|
||||||
: mfem::Operator(
|
layout.value_offsets().Last()),
|
||||||
layout.residual_offsets().Last(),
|
m_layout(layout), m_preparedOperator(preparedOperator) {
|
||||||
layout.value_offsets().Last()
|
|
||||||
),
|
|
||||||
m_layout(layout),
|
|
||||||
m_preparedOperator(preparedOperator) {
|
|
||||||
const fem::FEM &f = m_preparedOperator.GetFEM();
|
const fem::FEM &f = m_preparedOperator.GetFEM();
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(f.densityFes != nullptr && f.displacementFes != nullptr &&
|
||||||
f.densityFes != nullptr && f.displacementFes != nullptr && f.gravityFluxFes != nullptr &&
|
f.gravityFluxFes != nullptr &&
|
||||||
f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr,
|
f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr,
|
||||||
"Prepared mass-normalization MFEM adapter requires every "
|
"Prepared mass-normalization MFEM adapter requires every "
|
||||||
"finite-element space in the barotropic equilibrium layout."
|
"finite-element space in the barotropic equilibrium layout.");
|
||||||
);
|
|
||||||
|
|
||||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||||
|
|
||||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
constexpr auto densityValue = utils::blocks::get_value_block<Form>(
|
||||||
constexpr auto displacementValue =
|
utils::blocks::density_field.mass_term);
|
||||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
constexpr auto displacementValue = utils::blocks::get_value_block<Form>(
|
||||||
constexpr auto gravityGradientValue =
|
utils::blocks::displacement_field.geometry_term);
|
||||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.gradient_term);
|
constexpr auto gravityGradientValue = utils::blocks::get_value_block<Form>(
|
||||||
constexpr auto gravityPotentialValue =
|
utils::blocks::gravity_field.gradient_term);
|
||||||
utils::blocks::get_value_block<Form>(utils::blocks::gravity_field.poisson_term);
|
constexpr auto gravityPotentialValue = utils::blocks::get_value_block<Form>(
|
||||||
constexpr auto enthalpyValue =
|
utils::blocks::gravity_field.poisson_term);
|
||||||
utils::blocks::get_value_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
constexpr auto enthalpyValue = utils::blocks::get_value_block<Form>(
|
||||||
constexpr auto barotropicConstantValue =
|
utils::blocks::enthalpy_field.specific_term);
|
||||||
utils::blocks::get_value_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
constexpr auto barotropicConstantValue = utils::blocks::get_value_block<Form>(
|
||||||
|
utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||||
constexpr auto gravityGradientResidual =
|
constexpr auto gravityGradientResidual =
|
||||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.gradient_term);
|
utils::blocks::get_residual_block<Form>(
|
||||||
|
utils::blocks::gravity_field.gradient_term);
|
||||||
constexpr auto gravityPotentialResidual =
|
constexpr auto gravityPotentialResidual =
|
||||||
utils::blocks::get_residual_block<Form>(utils::blocks::gravity_field.poisson_term);
|
utils::blocks::get_residual_block<Form>(
|
||||||
constexpr auto densityResidual =
|
utils::blocks::gravity_field.poisson_term);
|
||||||
utils::blocks::get_residual_block<Form>(utils::blocks::density_field.mass_term);
|
constexpr auto densityResidual = utils::blocks::get_residual_block<Form>(
|
||||||
constexpr auto displacementResidual =
|
utils::blocks::density_field.mass_term);
|
||||||
utils::blocks::get_residual_block<Form>(utils::blocks::displacement_field.geometry_term);
|
constexpr auto displacementResidual = utils::blocks::get_residual_block<Form>(
|
||||||
constexpr auto enthalpyResidual =
|
utils::blocks::displacement_field.geometry_term);
|
||||||
utils::blocks::get_residual_block<Form>(utils::blocks::enthalpy_field.specific_term);
|
constexpr auto enthalpyResidual = utils::blocks::get_residual_block<Form>(
|
||||||
constexpr auto massResidual =
|
utils::blocks::enthalpy_field.specific_term);
|
||||||
utils::blocks::get_residual_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
constexpr auto massResidual = utils::blocks::get_residual_block<Form>(
|
||||||
|
utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||||
|
|
||||||
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
@@ -658,62 +681,70 @@ namespace mean_field::operators {
|
|||||||
const field::FieldDofMap enthalpyMap =
|
const field::FieldDofMap enthalpyMap =
|
||||||
field::make_field_dof_map<field::Enthalpy, DomainSchema>(*f.enthalpyFes);
|
field::make_field_dof_map<field::Enthalpy, DomainSchema>(*f.enthalpyFes);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(m_layout.size(densityValue) ==
|
||||||
m_layout.size(densityValue) == gravityContext.GetDensityMap().reduced_size() &&
|
gravityContext.GetDensityMap().reduced_size() &&
|
||||||
m_layout.size(displacementValue) == gravityContext.GetDisplacementMap().reduced_size() &&
|
m_layout.size(displacementValue) ==
|
||||||
m_layout.size(gravityGradientValue) == gravityContext.GetGravityGradientMap().reduced_size() &&
|
gravityContext.GetDisplacementMap().reduced_size() &&
|
||||||
m_layout.size(gravityPotentialValue) == gravityContext.GetGravityPotentialMap().reduced_size() &&
|
m_layout.size(gravityGradientValue) ==
|
||||||
|
gravityContext.GetGravityGradientMap().reduced_size() &&
|
||||||
|
m_layout.size(gravityPotentialValue) ==
|
||||||
|
gravityContext.GetGravityPotentialMap().reduced_size() &&
|
||||||
m_layout.size(enthalpyValue) == enthalpyMap.reduced_size() &&
|
m_layout.size(enthalpyValue) == enthalpyMap.reduced_size() &&
|
||||||
m_layout.size(barotropicConstantValue) == 1 &&
|
m_layout.size(barotropicConstantValue) == 1 &&
|
||||||
m_layout.size(gravityGradientResidual) == gravityContext.GetGravityGradientMap().reduced_size() &&
|
m_layout.size(gravityGradientResidual) ==
|
||||||
m_layout.size(gravityPotentialResidual) == gravityContext.GetGravityPotentialMap().reduced_size() &&
|
gravityContext.GetGravityGradientMap().reduced_size() &&
|
||||||
m_layout.size(densityResidual) == gravityContext.GetDensityMap().reduced_size() &&
|
m_layout.size(gravityPotentialResidual) ==
|
||||||
m_layout.size(displacementResidual) == gravityContext.GetDisplacementMap().reduced_size() &&
|
gravityContext.GetGravityPotentialMap().reduced_size() &&
|
||||||
m_layout.size(enthalpyResidual) == enthalpyMap.reduced_size() && m_layout.size(massResidual) == 1,
|
m_layout.size(densityResidual) ==
|
||||||
|
gravityContext.GetDensityMap().reduced_size() &&
|
||||||
|
m_layout.size(displacementResidual) ==
|
||||||
|
gravityContext.GetDisplacementMap().reduced_size() &&
|
||||||
|
m_layout.size(enthalpyResidual) ==
|
||||||
|
enthalpyMap.reduced_size() &&
|
||||||
|
m_layout.size(massResidual) == 1,
|
||||||
"Prepared mass-normalization MFEM adapter received incompatible "
|
"Prepared mass-normalization MFEM adapter received incompatible "
|
||||||
"barotropic block sizes."
|
"barotropic block sizes.");
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PreparedMassNormalizationJacobianOperator::Mult(
|
void PreparedMassNormalizationJacobianOperator::Mult(
|
||||||
const mfem::Vector &direction,
|
const mfem::Vector &direction, mfem::Vector &action) const {
|
||||||
mfem::Vector &action
|
MFEM_VERIFY(m_preparedOperator.IsPrepared(),
|
||||||
) const {
|
"Prepared mass-normalization MFEM adapter requires a prepared "
|
||||||
MFEM_VERIFY(
|
"row operator.");
|
||||||
m_preparedOperator.IsPrepared(), "Prepared mass-normalization MFEM adapter requires a prepared "
|
MFEM_VERIFY(direction.Size() == Width(),
|
||||||
"row operator."
|
"Prepared mass-normalization MFEM adapter received a direction "
|
||||||
);
|
"with the wrong size.");
|
||||||
MFEM_VERIFY(
|
|
||||||
direction.Size() == Width(), "Prepared mass-normalization MFEM adapter received a direction "
|
|
||||||
"with the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
using Form = utils::blocks::barotropic_equilibrium_form;
|
using Form = utils::blocks::barotropic_equilibrium_form;
|
||||||
|
|
||||||
constexpr auto densityValue = utils::blocks::get_value_block<Form>(utils::blocks::density_field.mass_term);
|
constexpr auto densityValue = utils::blocks::get_value_block<Form>(
|
||||||
constexpr auto displacementValue =
|
utils::blocks::density_field.mass_term);
|
||||||
utils::blocks::get_value_block<Form>(utils::blocks::displacement_field.geometry_term);
|
constexpr auto displacementValue = utils::blocks::get_value_block<Form>(
|
||||||
constexpr auto massResidual =
|
utils::blocks::displacement_field.geometry_term);
|
||||||
utils::blocks::get_residual_block<Form>(utils::blocks::barotropic_constant_field.mass_normalization_term);
|
constexpr auto massResidual = utils::blocks::get_residual_block<Form>(
|
||||||
|
utils::blocks::barotropic_constant_field.mass_normalization_term);
|
||||||
|
|
||||||
const mfem::Vector densityVariation(
|
const mfem::Vector densityVariation(
|
||||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(densityValue), m_layout.size(densityValue)
|
const_cast<mfem::real_t *>(direction.GetData()) +
|
||||||
);
|
m_layout.offset(densityValue),
|
||||||
|
m_layout.size(densityValue));
|
||||||
|
|
||||||
const mfem::Vector displacementVariation(
|
const mfem::Vector displacementVariation(
|
||||||
const_cast<mfem::real_t *>(direction.GetData()) + m_layout.offset(displacementValue),
|
const_cast<mfem::real_t *>(direction.GetData()) +
|
||||||
m_layout.size(displacementValue)
|
m_layout.offset(displacementValue),
|
||||||
);
|
m_layout.size(displacementValue));
|
||||||
|
|
||||||
mfem::Vector massAction;
|
mfem::Vector massAction;
|
||||||
m_preparedOperator.ApplyCompleteJacobianAction(densityVariation, displacementVariation, massAction);
|
m_preparedOperator.ApplyCompleteJacobianAction(
|
||||||
|
densityVariation, displacementVariation, massAction);
|
||||||
|
|
||||||
action.SetSize(Height());
|
action.SetSize(Height());
|
||||||
action = 0.0;
|
action = 0.0;
|
||||||
action(m_layout.offset(massResidual)) = massAction(0);
|
action(m_layout.offset(massResidual)) = massAction(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
const MassNormalizationLayout &PreparedMassNormalizationJacobianOperator::GetLayout() const noexcept {
|
const MassNormalizationLayout &
|
||||||
|
PreparedMassNormalizationJacobianOperator::GetLayout() const noexcept {
|
||||||
return m_layout;
|
return m_layout;
|
||||||
}
|
}
|
||||||
} // namespace mean_field::operators
|
} // namespace mean_field::operators
|
||||||
|
|||||||
@@ -213,7 +213,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedPressureForceOperator::PreparedPressureForceOperator(
|
PreparedPressureForceOperator::PreparedPressureForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState
|
const eos::Polytrope &equationOfState
|
||||||
)
|
)
|
||||||
: PreparedPressureForceOperator(
|
: PreparedPressureForceOperator(
|
||||||
@@ -226,7 +226,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedPressureForceOperator::PreparedPressureForceOperator(
|
PreparedPressureForceOperator::PreparedPressureForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
ConstructionData constructionData
|
ConstructionData constructionData
|
||||||
)
|
)
|
||||||
@@ -460,7 +460,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
true_to_local(*m_fem.displacementFes, m_baseDisplacementTrue, displacementLocal);
|
true_to_local(*m_fem.displacementFes, m_baseDisplacementTrue, displacementLocal);
|
||||||
|
|
||||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Vector elementDisplacement;
|
mfem::Vector elementDisplacement;
|
||||||
mfem::Vector elementCompactification;
|
mfem::Vector elementCompactification;
|
||||||
@@ -807,7 +807,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
localAction = 0.0;
|
localAction = 0.0;
|
||||||
|
|
||||||
mapping::DomainMapperStateless::Workspace workspace(m_fem.mesh->Dimension());
|
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
|
||||||
|
|
||||||
mfem::Vector elementDisplacementVariation;
|
mfem::Vector elementDisplacementVariation;
|
||||||
mfem::Vector elementAction;
|
mfem::Vector elementAction;
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import :operators.prepared_rotational_displacement_force;
|
|||||||
namespace mean_field::operators {
|
namespace mean_field::operators {
|
||||||
PreparedRotationalDisplacementForceOperator::PreparedRotationalDisplacementForceOperator(
|
PreparedRotationalDisplacementForceOperator::PreparedRotationalDisplacementForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper
|
const mapping::DomainMapper &domainMapper
|
||||||
)
|
)
|
||||||
: m_fem(f),
|
: m_fem(f),
|
||||||
m_domainMapper(domainMapper),
|
m_domainMapper(domainMapper),
|
||||||
|
|||||||
@@ -9,28 +9,16 @@ module;
|
|||||||
module mean_field;
|
module mean_field;
|
||||||
|
|
||||||
import :operators.prepared_stellar_equilibrium;
|
import :operators.prepared_stellar_equilibrium;
|
||||||
import :physics.gravity;
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
|
||||||
[[nodiscard]] mean_field::fem::FEM &ensure_gravity_static_operators(mean_field::fem::FEM &f) {
|
void verify_coupled_discretization(const mean_field::fem::FEM &f) {
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
f.mesh != nullptr && f.densityFes != nullptr && f.displacementFes != nullptr &&
|
f.mesh != nullptr && f.densityFes != nullptr && f.displacementFes != nullptr &&
|
||||||
f.gravityFluxFes != nullptr && f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr,
|
f.gravityFluxFes != nullptr && f.gravityPotentialFes != nullptr && f.enthalpyFes != nullptr,
|
||||||
"PreparedStellarEquilibriumOperator requires the complete coupled finite-element discretization."
|
"PreparedStellarEquilibriumOperator requires the complete coupled finite-element discretization."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (f.gravityContext.b_form == nullptr || f.gravityContext.BT == nullptr) {
|
|
||||||
mean_field::physics::update_stiffness_matrix(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.gravityContext.b_form != nullptr && f.gravityContext.BT != nullptr,
|
|
||||||
"PreparedStellarEquilibriumOperator could not initialize the static gravity divergence operators."
|
|
||||||
);
|
|
||||||
|
|
||||||
return f;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mean_field::operators::StellarEquilibriumLayout make_layout(
|
[[nodiscard]] mean_field::operators::StellarEquilibriumLayout make_layout(
|
||||||
@@ -318,13 +306,13 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedStellarEquilibriumOperator::ConstructionData
|
PreparedStellarEquilibriumOperator::ConstructionData
|
||||||
PreparedStellarEquilibriumOperator::MakeConstructionData(fem::FEM &f) {
|
PreparedStellarEquilibriumOperator::MakeConstructionData(fem::FEM &f) {
|
||||||
ensure_gravity_static_operators(f);
|
verify_coupled_discretization(f);
|
||||||
return ConstructionData(f);
|
return ConstructionData(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const models::StellarModel &stellarModel
|
const models::StellarModel &stellarModel
|
||||||
)
|
)
|
||||||
@@ -338,7 +326,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const double targetMass
|
const double targetMass
|
||||||
)
|
)
|
||||||
@@ -353,7 +341,7 @@ namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
PreparedStellarEquilibriumOperator::PreparedStellarEquilibriumOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const double targetMass,
|
const double targetMass,
|
||||||
ConstructionData constructionData
|
ConstructionData constructionData
|
||||||
@@ -587,8 +575,7 @@ namespace mean_field::operators {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assign_residual_block(
|
assign_residual_block(
|
||||||
m_cachedResidual, m_layout, enthalpyResidual, hydrostatic,
|
m_cachedResidual, m_layout, enthalpyResidual, hydrostatic, "The hydrostatic residual has the wrong size."
|
||||||
"The hydrostatic residual has the wrong size."
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assign_residual_block(
|
assign_residual_block(
|
||||||
@@ -712,8 +699,7 @@ namespace mean_field::operators {
|
|||||||
);
|
);
|
||||||
|
|
||||||
assign_residual_block(
|
assign_residual_block(
|
||||||
action, m_layout, enthalpyResidual, hydrostaticAction,
|
action, m_layout, enthalpyResidual, hydrostaticAction, "The hydrostatic Jacobian action has the wrong size."
|
||||||
"The hydrostatic Jacobian action has the wrong size."
|
|
||||||
);
|
);
|
||||||
|
|
||||||
assign_residual_block(
|
assign_residual_block(
|
||||||
|
|||||||
@@ -2,171 +2,10 @@ module;
|
|||||||
#include "mfem.hpp"
|
#include "mfem.hpp"
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <format>
|
|
||||||
#include <source_location>
|
|
||||||
#include <string_view>
|
|
||||||
#include <unordered_map>
|
|
||||||
|
|
||||||
module mean_field;
|
module mean_field;
|
||||||
import :mapping.coefficients;
|
|
||||||
import :analysis.integral;
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
double centrifugal_potential(
|
|
||||||
const mfem::Vector &phys_x,
|
|
||||||
const double omega
|
|
||||||
) {
|
|
||||||
const double s2 = std::pow(phys_x(0), 2) + std::pow(phys_x(1), 2);
|
|
||||||
return -0.5 * s2 * std::pow(omega, 2);
|
|
||||||
}
|
|
||||||
|
|
||||||
void grid_function_to_true_dofs(
|
|
||||||
const mfem::ParFiniteElementSpace &finite_element_space,
|
|
||||||
const mfem::GridFunction &grid_function,
|
|
||||||
mfem::Vector &true_dofs
|
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
|
||||||
grid_function.Size() == finite_element_space.GetVSize(),
|
|
||||||
"The grid function does not match the requested finite-element "
|
|
||||||
"space."
|
|
||||||
);
|
|
||||||
|
|
||||||
true_dofs.SetSize(finite_element_space.GetTrueVSize());
|
|
||||||
|
|
||||||
const mfem::Operator *restriction = finite_element_space.GetRestrictionMatrix();
|
|
||||||
|
|
||||||
if (restriction != nullptr) {
|
|
||||||
restriction->Mult(grid_function, true_dofs);
|
|
||||||
} else {
|
|
||||||
MFEM_VERIFY(
|
|
||||||
grid_function.Size() == true_dofs.Size(), "A finite-element space without a restriction operator must "
|
|
||||||
"have "
|
|
||||||
"matching local and true sizes."
|
|
||||||
);
|
|
||||||
|
|
||||||
true_dofs = grid_function;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
namespace mean_field::physics {
|
namespace mean_field::physics {
|
||||||
GravitySolution grav_potential(
|
|
||||||
fem::FEM &f,
|
|
||||||
const utils::Args &args,
|
|
||||||
const mfem::GridFunction &rho,
|
|
||||||
const bool phi_warm
|
|
||||||
) {
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.densityFes != nullptr && rho.FESpace() == f.densityFes.get(),
|
|
||||||
"Gravity solve requires rho to use the registered density space."
|
|
||||||
);
|
|
||||||
MFEM_VERIFY(f.gravityPotentialFes != nullptr, "Gravity solve requires the registered gravity-potential space.");
|
|
||||||
|
|
||||||
mfem::Array<int> outer_bdr_marker(f.mesh->bdr_attributes.Max());
|
|
||||||
outer_bdr_marker = 0;
|
|
||||||
outer_bdr_marker[1] = 1;
|
|
||||||
|
|
||||||
mfem::ParLinearForm g_rhs(f.gravityFluxFes.get());
|
|
||||||
|
|
||||||
// ReSharper disable once CppTooWideScope
|
|
||||||
std::unique_ptr<mfem::Coefficient> boundary_potential_coeff;
|
|
||||||
|
|
||||||
if (!f.has_mapping()) { // We only need to explicitly add a boundary
|
|
||||||
// integrator if a mapping is not being used. In
|
|
||||||
// the case where the outer domain has been
|
|
||||||
// compactified the φ=0 boundary condition is
|
|
||||||
// the natural condition and MFEM automatically
|
|
||||||
// handles this
|
|
||||||
auto boundary_potential = [&f](const mfem::Vector &x_physical) {
|
|
||||||
return l2_multipole_potential(f, utils::MASS, x_physical);
|
|
||||||
};
|
|
||||||
|
|
||||||
boundary_potential_coeff = std::make_unique<mfem::FunctionCoefficient>(boundary_potential);
|
|
||||||
auto boundary_integrator =
|
|
||||||
std::make_unique<mfem::VectorFEBoundaryFluxLFIntegrator>(*boundary_potential_coeff);
|
|
||||||
const mfem::FiniteElement &boundary_element = *f.gravityFluxFes->GetTypicalTraceElement();
|
|
||||||
|
|
||||||
f.quadratureFactory->configure_gravity_boundary(
|
|
||||||
*boundary_integrator, quadrature::QuadratureRole::discretization, boundary_element,
|
|
||||||
utils::DOMAINS::VACUUM, quadrature::MappingKind::none
|
|
||||||
);
|
|
||||||
g_rhs.AddBoundaryIntegrator(boundary_integrator.release(), outer_bdr_marker);
|
|
||||||
}
|
|
||||||
|
|
||||||
g_rhs.Assemble();
|
|
||||||
mfem::GridFunctionCoefficient rho_coeff(&rho);
|
|
||||||
mfem::ConstantCoefficient G4pi(4.0 * M_PI * utils::G);
|
|
||||||
mfem::ProductCoefficient source_coeff(G4pi, rho_coeff);
|
|
||||||
mfem::ParLinearForm f_rhs(f.gravityPotentialFes.get());
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::Coefficient> mapped_source_coeff;
|
|
||||||
mfem::Coefficient *active_source_coeff = &source_coeff;
|
|
||||||
quadrature::MappingKind source_mapping_kind = quadrature::MappingKind::none;
|
|
||||||
|
|
||||||
if (f.has_mapping()) {
|
|
||||||
mapped_source_coeff = std::make_unique<mapping::MappedScalarCoefficient>(*f.mapping, source_coeff);
|
|
||||||
active_source_coeff = mapped_source_coeff.get();
|
|
||||||
source_mapping_kind = quadrature::MappingKind::general;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto source_integrator = std::make_unique<mfem::DomainLFIntegrator>(*active_source_coeff);
|
|
||||||
const mfem::FiniteElement &source_test_element = *f.gravityPotentialFes->GetTypicalFE();
|
|
||||||
const mfem::ElementTransformation &source_transformation = *f.mesh->GetElementTransformation(0);
|
|
||||||
const int source_coefficient_order = f.densityFes->GetMaxElementOrder();
|
|
||||||
|
|
||||||
f.quadratureFactory->configure_gravity_source(
|
|
||||||
*source_integrator, quadrature::QuadratureRole::discretization, source_test_element, source_transformation,
|
|
||||||
source_coefficient_order, utils::DOMAINS::STELLAR, source_mapping_kind
|
|
||||||
);
|
|
||||||
f_rhs.AddDomainIntegrator(source_integrator.release(), f.gravityContext.stellar_mask);
|
|
||||||
f_rhs.Assemble();
|
|
||||||
|
|
||||||
mfem::BlockVector RHS(f.gravityBlockTrueOffsets);
|
|
||||||
RHS.GetBlock(0) = *g_rhs.ParallelAssemble();
|
|
||||||
RHS.GetBlock(1) = *f_rhs.ParallelAssemble();
|
|
||||||
|
|
||||||
mfem::BlockVector X(f.gravityBlockTrueOffsets);
|
|
||||||
X = 0.0;
|
|
||||||
f.gravityContext.minres->SetOperator(*f.gravityContext.block_A);
|
|
||||||
f.gravityContext.minres->Mult(RHS, X);
|
|
||||||
|
|
||||||
GravitySolution solution(f);
|
|
||||||
solution.gradPhi.SetFromTrueDofs(X.GetBlock(0));
|
|
||||||
solution.phi.SetFromTrueDofs(X.GetBlock(1));
|
|
||||||
|
|
||||||
return solution;
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::GridFunction get_potential(
|
|
||||||
fem::FEM &fem,
|
|
||||||
const utils::Args &args,
|
|
||||||
const mfem::GridFunction &rho,
|
|
||||||
const bool warm
|
|
||||||
) {
|
|
||||||
auto phi = grav_potential(fem, args, rho, warm);
|
|
||||||
|
|
||||||
if (args.r.enabled) {
|
|
||||||
auto rot = [&fem, &args](const mfem::Vector &x) {
|
|
||||||
mfem::Vector rel_x = x;
|
|
||||||
rel_x -= fem.com;
|
|
||||||
return centrifugal_potential(rel_x, args.r.omega);
|
|
||||||
};
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::Coefficient> centrifugal_coeff;
|
|
||||||
if (fem.has_mapping()) {
|
|
||||||
centrifugal_coeff = std::make_unique<mapping::PhysicalPositionFunctionCoefficient>(*fem.mapping, rot);
|
|
||||||
} else {
|
|
||||||
centrifugal_coeff = std::make_unique<mfem::FunctionCoefficient>(rot);
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::GridFunction centrifugal_gf(fem.gravityPotentialFes.get());
|
|
||||||
centrifugal_gf.ProjectCoefficient(*centrifugal_coeff);
|
|
||||||
|
|
||||||
phi.phi += centrifugal_gf;
|
|
||||||
}
|
|
||||||
return phi.phi;
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::DenseMatrix compute_quadrupole_moment_tensor(
|
mfem::DenseMatrix compute_quadrupole_moment_tensor(
|
||||||
const fem::FEM &fem,
|
const fem::FEM &fem,
|
||||||
const mfem::GridFunction &rho,
|
const mfem::GridFunction &rho,
|
||||||
@@ -175,9 +14,15 @@ namespace mean_field::physics {
|
|||||||
const int dim = fem.mesh->Dimension();
|
const int dim = fem.mesh->Dimension();
|
||||||
mfem::DenseMatrix local_Q(dim, dim);
|
mfem::DenseMatrix local_Q(dim, dim);
|
||||||
local_Q = 0.0;
|
local_Q = 0.0;
|
||||||
|
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate
|
||||||
|
);
|
||||||
|
|
||||||
for (int i = 0; i < fem.mesh->GetNE(); ++i) {
|
for (int i = 0; i < fem.mesh->GetNE(); ++i) {
|
||||||
if (fem.mesh->GetAttribute(i) == 3)
|
if (!DomainSchema::template attribute_belongs_to<utils::domain::Stellar>(
|
||||||
|
fem.mesh->GetAttribute(i)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mfem::ElementTransformation *trans = fem.mesh->GetElementTransformation(i);
|
mfem::ElementTransformation *trans = fem.mesh->GetElementTransformation(i);
|
||||||
@@ -193,20 +38,17 @@ namespace mean_field::physics {
|
|||||||
const mfem::IntegrationPoint &ip = ir.IntPoint(j);
|
const mfem::IntegrationPoint &ip = ir.IntPoint(j);
|
||||||
trans->SetIntPoint(&ip);
|
trans->SetIntPoint(&ip);
|
||||||
|
|
||||||
double weight = trans->Weight() * ip.weight;
|
mapping::VolumeMappingContext mapping_context;
|
||||||
|
MFEM_VERIFY(
|
||||||
if (fem.has_mapping()) {
|
mapping_evaluator.EvaluateVolume(*trans, ip, mapping_context) ==
|
||||||
weight *= fem.mapping->ComputeDetJ(*trans, ip);
|
mapping::MappingStatus::valid,
|
||||||
}
|
"Quadrupole integration encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
const double weight = mapping_context.quadrature.weight;
|
||||||
|
|
||||||
const double rho_val = rho.GetValue(i, ip);
|
const double rho_val = rho.GetValue(i, ip);
|
||||||
|
|
||||||
mfem::Vector phys_point(dim);
|
const mfem::Vector &phys_point = mapping_context.mapping.physical_position;
|
||||||
if (fem.has_mapping()) {
|
|
||||||
fem.mapping->GetPhysicalPoint(*trans, ip, phys_point);
|
|
||||||
} else {
|
|
||||||
trans->Transform(ip, phys_point);
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::Vector x_prime(dim);
|
mfem::Vector x_prime(dim);
|
||||||
double r_sq = 0.0;
|
double r_sq = 0.0;
|
||||||
@@ -261,141 +103,7 @@ namespace mean_field::physics {
|
|||||||
return l0_contrib + l2_contrib;
|
return l0_contrib + l2_contrib;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_stiffness_matrix(fem::FEM &f) {
|
GravitySolution solve_gravity_field(
|
||||||
mfem::Array<int> empty_tdofs;
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 1. Partially Assemble the High-Order Mass Block
|
|
||||||
// ==========================================
|
|
||||||
f.gravityContext.m_form = std::make_unique<mfem::ParBilinearForm>(f.gravityFluxFes.get());
|
|
||||||
f.gravityContext.m_form->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::VectorFEMassIntegrator> hdiv_mass_integrator;
|
|
||||||
|
|
||||||
if (f.has_mapping()) {
|
|
||||||
f.gravityContext.mapped_hdiv_mass_coeff =
|
|
||||||
std::make_unique<mapping::MappedHDivMassCoefficient>(*f.mapping, f.mesh->Dimension());
|
|
||||||
hdiv_mass_integrator =
|
|
||||||
std::make_unique<mfem::VectorFEMassIntegrator>(*f.gravityContext.mapped_hdiv_mass_coeff);
|
|
||||||
} else {
|
|
||||||
f.gravityContext.mapped_hdiv_mass_coeff.reset();
|
|
||||||
hdiv_mass_integrator = std::make_unique<mfem::VectorFEMassIntegrator>();
|
|
||||||
}
|
|
||||||
|
|
||||||
const mfem::FiniteElement &hdiv_element = *f.gravityFluxFes->GetTypicalFE();
|
|
||||||
const mfem::ElementTransformation &hdiv_transformation = *f.mesh->GetElementTransformation(0);
|
|
||||||
const quadrature::MappingKind mapping_kind =
|
|
||||||
f.has_mapping() ? quadrature::MappingKind::general : quadrature::MappingKind::none;
|
|
||||||
|
|
||||||
f.quadratureFactory->configure_gravity_hdiv_mass(
|
|
||||||
*hdiv_mass_integrator, quadrature::QuadratureRole::discretization, hdiv_element, hdiv_transformation,
|
|
||||||
utils::DOMAINS::ALL, mapping_kind
|
|
||||||
);
|
|
||||||
f.gravityContext.m_form->AddDomainIntegrator(hdiv_mass_integrator.release());
|
|
||||||
|
|
||||||
f.gravityContext.m_form->Assemble();
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 2. Partially Assemble the High-Order Divergence Block
|
|
||||||
// ==========================================
|
|
||||||
f.gravityContext.b_form =
|
|
||||||
std::make_unique<mfem::ParMixedBilinearForm>(f.gravityFluxFes.get(), f.gravityPotentialFes.get());
|
|
||||||
f.gravityContext.b_form->SetAssemblyLevel(mfem::AssemblyLevel::PARTIAL);
|
|
||||||
|
|
||||||
auto divergence_discretization_integrator = std::make_unique<mfem::VectorFEDivergenceIntegrator>();
|
|
||||||
const mfem::FiniteElement &divergence_discretization_test_element = *f.gravityPotentialFes->GetTypicalFE();
|
|
||||||
|
|
||||||
f.quadratureFactory->configure_gravity_divergence(
|
|
||||||
*divergence_discretization_integrator, quadrature::QuadratureRole::discretization, hdiv_element,
|
|
||||||
divergence_discretization_test_element, hdiv_transformation, utils::DOMAINS::ALL,
|
|
||||||
quadrature::MappingKind::none
|
|
||||||
);
|
|
||||||
f.gravityContext.b_form->AddDomainIntegrator(divergence_discretization_integrator.release());
|
|
||||||
|
|
||||||
f.gravityContext.b_form->Assemble();
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.domainMapperStateless != nullptr, "Gravity source partial assembly requires the stateless domain "
|
|
||||||
"mapper."
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector displacement_true(f.displacementFes->GetTrueVSize());
|
|
||||||
displacement_true = 0.0;
|
|
||||||
|
|
||||||
const mfem::GridFunction *active_displacement = f.mapping->GetDisplacement();
|
|
||||||
|
|
||||||
if (active_displacement != nullptr) {
|
|
||||||
grid_function_to_true_dofs(*f.displacementFes, *active_displacement, displacement_true);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto source_form =
|
|
||||||
std::make_unique<operators::PreparedMappedGravitySourceOperator>(f, *f.domainMapperStateless);
|
|
||||||
|
|
||||||
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
|
||||||
const field::FieldDofMap displacement_map =
|
|
||||||
field::make_field_dof_map<field::Displacement, DomainSchema>(*f.displacementFes);
|
|
||||||
source_form->Prepare(displacement_map.gather(displacement_true));
|
|
||||||
|
|
||||||
f.gravityContext.source_form = std::move(source_form);
|
|
||||||
// ==========================================
|
|
||||||
// 3. Assemble Global Block Operator
|
|
||||||
// ==========================================
|
|
||||||
f.gravityContext.BT = std::make_unique<mfem::TransposeOperator>(f.gravityContext.b_form.get());
|
|
||||||
|
|
||||||
f.gravityContext.block_A = std::make_unique<mfem::BlockOperator>(f.gravityBlockTrueOffsets);
|
|
||||||
f.gravityContext.block_A->SetBlock(0, 0, f.gravityContext.m_form.get());
|
|
||||||
f.gravityContext.block_A->SetBlock(0, 1, f.gravityContext.BT.get());
|
|
||||||
f.gravityContext.block_A->SetBlock(1, 0, f.gravityContext.b_form.get());
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 4. Construct a mapped Schur preconditioner
|
|
||||||
// ==========================================
|
|
||||||
mfem::Vector mass_diagonal(f.gravityFluxFes->GetTrueVSize());
|
|
||||||
f.gravityContext.m_form->AssembleDiagonal(mass_diagonal);
|
|
||||||
|
|
||||||
mfem::Vector inverse_mass_diagonal(mass_diagonal);
|
|
||||||
|
|
||||||
for (int i = 0; i < inverse_mass_diagonal.Size(); ++i) {
|
|
||||||
MFEM_VERIFY(
|
|
||||||
std::isfinite(inverse_mass_diagonal(i)) && inverse_mass_diagonal(i) > 0.0,
|
|
||||||
"Mapped RT mass matrix has a non-positive or non-finite "
|
|
||||||
"diagonal "
|
|
||||||
"entry."
|
|
||||||
);
|
|
||||||
inverse_mass_diagonal(i) = 1.0 / inverse_mass_diagonal(i);
|
|
||||||
}
|
|
||||||
|
|
||||||
mfem::ParMixedBilinearForm b_preconditioner(f.gravityFluxFes.get(), f.gravityPotentialFes.get());
|
|
||||||
auto divergence_preconditioner_integrator = std::make_unique<mfem::VectorFEDivergenceIntegrator>();
|
|
||||||
|
|
||||||
const mfem::FiniteElement &divergence_trial_element = *f.gravityFluxFes->GetTypicalFE();
|
|
||||||
const mfem::FiniteElement &divergence_test_element = *f.gravityPotentialFes->GetTypicalFE();
|
|
||||||
const mfem::ElementTransformation &divergence_transformation = *f.mesh->GetElementTransformation(0);
|
|
||||||
|
|
||||||
f.quadratureFactory->configure_gravity_divergence(
|
|
||||||
*divergence_preconditioner_integrator, quadrature::QuadratureRole::preconditioner, divergence_trial_element,
|
|
||||||
divergence_test_element, divergence_transformation, utils::DOMAINS::ALL, quadrature::MappingKind::none
|
|
||||||
);
|
|
||||||
b_preconditioner.AddDomainIntegrator(divergence_preconditioner_integrator.release());
|
|
||||||
b_preconditioner.Assemble();
|
|
||||||
b_preconditioner.Finalize();
|
|
||||||
std::unique_ptr<mfem::HypreParMatrix> b_matrix(b_preconditioner.ParallelAssemble());
|
|
||||||
std::unique_ptr<mfem::HypreParMatrix> inverse_mass_b_transpose(b_matrix->Transpose());
|
|
||||||
|
|
||||||
inverse_mass_b_transpose->ScaleRows(inverse_mass_diagonal);
|
|
||||||
|
|
||||||
f.gravityContext.Schur.reset(mfem::ParMult(b_matrix.get(), inverse_mass_b_transpose.get()));
|
|
||||||
|
|
||||||
// ==========================================
|
|
||||||
// 5. Wire Up the preconditioners
|
|
||||||
// ==========================================
|
|
||||||
f.gravityContext.prec_M = std::make_unique<mfem::OperatorJacobiSmoother>(mass_diagonal, empty_tdofs);
|
|
||||||
f.gravityContext.prec_Phi->SetOperator(*f.gravityContext.Schur);
|
|
||||||
f.gravityContext.block_prec->SetDiagonalBlock(0, f.gravityContext.prec_M.get());
|
|
||||||
f.gravityContext.block_prec->SetDiagonalBlock(1, f.gravityContext.prec_Phi.get());
|
|
||||||
}
|
|
||||||
|
|
||||||
GravitySolution grav_potential_new(
|
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const utils::Args &args,
|
const utils::Args &args,
|
||||||
const mfem::GridFunction &rho,
|
const mfem::GridFunction &rho,
|
||||||
@@ -417,13 +125,6 @@ namespace mean_field::physics {
|
|||||||
"displacement finite-element space."
|
"displacement finite-element space."
|
||||||
);
|
);
|
||||||
MFEM_VERIFY(f.domainMapperStateless != nullptr, "Gravity initialization requires the stateless domain mapper.");
|
MFEM_VERIFY(f.domainMapperStateless != nullptr, "Gravity initialization requires the stateless domain mapper.");
|
||||||
MFEM_VERIFY(f.gravityContext.b_form != nullptr, "Gravity initialization requires the divergence operator.");
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.gravityContext.BT != nullptr, "Gravity initialization requires the transpose divergence operator."
|
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
|
||||||
f.gravityContext.block_prec != nullptr, "Gravity initialization requires the gravity block preconditioner."
|
|
||||||
);
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(
|
||||||
rho.FESpace() == f.densityFes.get(), "Gravity initialization requires density to use the FEM density "
|
rho.FESpace() == f.densityFes.get(), "Gravity initialization requires density to use the FEM density "
|
||||||
"space."
|
"space."
|
||||||
@@ -434,6 +135,7 @@ namespace mean_field::physics {
|
|||||||
"Vec_H1 "
|
"Vec_H1 "
|
||||||
"space."
|
"space."
|
||||||
);
|
);
|
||||||
|
MFEM_VERIFY(args.p.max_iters > 0, "Gravity solve requires a positive MINRES iteration limit.");
|
||||||
|
|
||||||
using form = utils::blocks::gravity_field_form;
|
using form = utils::blocks::gravity_field_form;
|
||||||
|
|
||||||
@@ -444,13 +146,19 @@ namespace mean_field::physics {
|
|||||||
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.poisson_term);
|
utils::blocks::get_residual_block<form>(utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
const field::FieldDofMap density_map = field::make_field_dof_map<field::Density, DomainSchema>(*f.densityFes);
|
const field::FieldDofGridFunctionAdapter density_adapter =
|
||||||
const field::FieldDofMap displacement_map =
|
field::make_field_dof_grid_function_adapter<field::Density, DomainSchema>(*f.densityFes);
|
||||||
field::make_field_dof_map<field::Displacement, DomainSchema>(*f.displacementFes);
|
const field::FieldDofGridFunctionAdapter displacement_adapter =
|
||||||
const field::FieldDofMap gravity_flux_map =
|
field::make_field_dof_grid_function_adapter<field::Displacement, DomainSchema>(*f.displacementFes);
|
||||||
field::make_field_dof_map<field::Gravity, DomainSchema>(*f.gravityFluxFes);
|
const field::FieldDofGridFunctionAdapter gravity_flux_adapter =
|
||||||
const field::FieldDofMap gravity_potential_map =
|
field::make_field_dof_grid_function_adapter<field::Gravity, DomainSchema>(*f.gravityFluxFes);
|
||||||
field::make_field_dof_map<field::Gravity, DomainSchema>(*f.gravityPotentialFes);
|
const field::FieldDofGridFunctionAdapter gravity_potential_adapter =
|
||||||
|
field::make_field_dof_grid_function_adapter<field::Gravity, DomainSchema>(*f.gravityPotentialFes);
|
||||||
|
|
||||||
|
const field::FieldDofMap &density_map = density_adapter.dof_map();
|
||||||
|
const field::FieldDofMap &displacement_map = displacement_adapter.dof_map();
|
||||||
|
const field::FieldDofMap &gravity_flux_map = gravity_flux_adapter.dof_map();
|
||||||
|
const field::FieldDofMap &gravity_potential_map = gravity_potential_adapter.dof_map();
|
||||||
|
|
||||||
const std::array<int, form::value_block_count> value_sizes{
|
const std::array<int, form::value_block_count> value_sizes{
|
||||||
density_map.reduced_size(), displacement_map.reduced_size(), gravity_flux_map.reduced_size(),
|
density_map.reduced_size(), displacement_map.reduced_size(), gravity_flux_map.reduced_size(),
|
||||||
@@ -463,14 +171,8 @@ namespace mean_field::physics {
|
|||||||
|
|
||||||
const utils::blocks::form_layout<form> layout(value_sizes, residual_sizes);
|
const utils::blocks::form_layout<form> layout(value_sizes, residual_sizes);
|
||||||
|
|
||||||
mfem::Vector density_true;
|
const mfem::Vector density = density_adapter.gather(rho);
|
||||||
mfem::Vector displacement_true;
|
const mfem::Vector reduced_displacement = displacement_adapter.gather(displacement);
|
||||||
|
|
||||||
grid_function_to_true_dofs(*f.densityFes, rho, density_true);
|
|
||||||
grid_function_to_true_dofs(*f.displacementFes, displacement, displacement_true);
|
|
||||||
|
|
||||||
const mfem::Vector density = density_map.gather(density_true);
|
|
||||||
const mfem::Vector reduced_displacement = displacement_map.gather(displacement_true);
|
|
||||||
|
|
||||||
operators::context::gravity_field::GravityFieldLinearizationContext linearization_context(
|
operators::context::gravity_field::GravityFieldLinearizationContext linearization_context(
|
||||||
f, *f.domainMapperStateless
|
f, *f.domainMapperStateless
|
||||||
@@ -491,6 +193,7 @@ namespace mean_field::physics {
|
|||||||
operators::ReducedGravityFieldOperator reduced_operator(
|
operators::ReducedGravityFieldOperator reduced_operator(
|
||||||
gravity_operator, reduced_geometry_context, reduced_displacement
|
gravity_operator, reduced_geometry_context, reduced_displacement
|
||||||
);
|
);
|
||||||
|
operators::ReducedGravityFieldPreconditioner reduced_preconditioner(f, reduced_geometry_context);
|
||||||
|
|
||||||
mfem::Vector right_hand_side;
|
mfem::Vector right_hand_side;
|
||||||
reduced_operator.BuildRightHandSide(density, right_hand_side);
|
reduced_operator.BuildRightHandSide(density, right_hand_side);
|
||||||
@@ -505,25 +208,24 @@ namespace mean_field::physics {
|
|||||||
|
|
||||||
mfem::MINRESSolver minres(f.mesh->GetComm());
|
mfem::MINRESSolver minres(f.mesh->GetComm());
|
||||||
minres.SetOperator(reduced_operator);
|
minres.SetOperator(reduced_operator);
|
||||||
minres.SetPreconditioner(*f.gravityContext.block_prec);
|
minres.SetPreconditioner(reduced_preconditioner);
|
||||||
minres.SetRelTol(args.p.rtol);
|
minres.SetRelTol(args.p.rtol);
|
||||||
minres.SetAbsTol(args.p.atol);
|
minres.SetAbsTol(args.p.atol);
|
||||||
minres.SetMaxIter(args.p.max_iters);
|
minres.SetMaxIter(args.p.max_iters);
|
||||||
minres.SetPrintLevel(1);
|
// minres.SetPrintLevel(args.verbose ? 1 : 0);
|
||||||
|
minres.SetPrintLevel(0);
|
||||||
minres.Mult(right_hand_side, gravity_state);
|
minres.Mult(right_hand_side, gravity_state);
|
||||||
|
|
||||||
MFEM_VERIFY(minres.GetConverged(), "The reduced gravity solve failed to converge.");
|
MFEM_VERIFY(minres.GetConverged(), "The reduced gravity solve failed to converge.");
|
||||||
|
|
||||||
GravitySolution solution(f);
|
GravitySolution solution(f);
|
||||||
|
|
||||||
const mfem::Vector gravity_flux_true =
|
gravity_flux_adapter.scatter(
|
||||||
gravity_flux_map.scatter(gravity_state.GetBlock(gravity_gradient_residual_block));
|
gravity_state.GetBlock(gravity_gradient_residual_block), solution.gradPhi
|
||||||
const mfem::Vector gravity_potential_true =
|
);
|
||||||
gravity_potential_map.scatter(gravity_state.GetBlock(gravity_poisson_residual_block));
|
gravity_potential_adapter.scatter(
|
||||||
|
gravity_state.GetBlock(gravity_poisson_residual_block), solution.phi
|
||||||
solution.gradPhi.SetFromTrueDofs(gravity_flux_true);
|
);
|
||||||
|
|
||||||
solution.phi.SetFromTrueDofs(gravity_potential_true);
|
|
||||||
|
|
||||||
return solution;
|
return solution;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,9 +10,15 @@ namespace mean_field::physics {
|
|||||||
const mfem::GridFunction &rho_ref
|
const mfem::GridFunction &rho_ref
|
||||||
) {
|
) {
|
||||||
double local_I = 0.0;
|
double local_I = 0.0;
|
||||||
|
using DomainSchema = utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate
|
||||||
|
);
|
||||||
|
|
||||||
for (int i = 0; i < fem.mesh->GetNE(); i++) {
|
for (int i = 0; i < fem.mesh->GetNE(); i++) {
|
||||||
if (fem.mesh->GetAttribute(i) == 3)
|
if (!DomainSchema::template attribute_belongs_to<utils::domain::Stellar>(
|
||||||
|
fem.mesh->GetAttribute(i)))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
mfem::ElementTransformation *T = fem.mesh->GetElementTransformation(i);
|
mfem::ElementTransformation *T = fem.mesh->GetElementTransformation(i);
|
||||||
@@ -29,12 +35,16 @@ namespace mean_field::physics {
|
|||||||
|
|
||||||
const double rho_hat = rho_ref.GetValue(i, ip);
|
const double rho_hat = rho_ref.GetValue(i, ip);
|
||||||
|
|
||||||
mfem::Vector x_phys;
|
mapping::VolumeMappingContext mapping_context;
|
||||||
fem.mapping->GetPhysicalPoint(*T, ip, x_phys);
|
MFEM_VERIFY(
|
||||||
|
mapping_evaluator.EvaluateVolume(*T, ip, mapping_context) ==
|
||||||
|
mapping::MappingStatus::valid,
|
||||||
|
"Moment-of-inertia integration encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
const mfem::Vector &x_phys = mapping_context.mapping.physical_position;
|
||||||
|
|
||||||
const double r_cyl_sq = x_phys(0) * x_phys(0) + x_phys(1) * x_phys(1);
|
const double r_cyl_sq = x_phys(0) * x_phys(0) + x_phys(1) * x_phys(1);
|
||||||
const double detJ = std::fabs(fem.mapping->ComputeDetJ(*T, ip));
|
const double weight = mapping_context.quadrature.weight;
|
||||||
const double weight = T->Weight() * ip.weight * detJ;
|
|
||||||
|
|
||||||
local_I += rho_hat * r_cyl_sq * weight;
|
local_I += rho_hat * r_cyl_sq * weight;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,6 +12,10 @@ namespace mean_field::utils {
|
|||||||
) {
|
) {
|
||||||
const int dim = fem.mesh->Dimension();
|
const int dim = fem.mesh->Dimension();
|
||||||
x_ref = x_phys_target;
|
x_ref = x_phys_target;
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*fem.domainMapperStateless, *fem.displacement,
|
||||||
|
*fem.compactificationCoordinate
|
||||||
|
);
|
||||||
|
|
||||||
mfem::Array<int> init_elem;
|
mfem::Array<int> init_elem;
|
||||||
mfem::Array<mfem::IntegrationPoint> init_ip;
|
mfem::Array<mfem::IntegrationPoint> init_ip;
|
||||||
@@ -29,15 +33,18 @@ namespace mean_field::utils {
|
|||||||
mfem::Array<mfem::IntegrationPoint> origin_ip;
|
mfem::Array<mfem::IntegrationPoint> origin_ip;
|
||||||
fem.mesh->FindPoints(P_origin, origin_elem, origin_ip, false);
|
fem.mesh->FindPoints(P_origin, origin_elem, origin_ip, false);
|
||||||
|
|
||||||
if (origin_elem.Size() > 0 && origin_elem[0] >= 0 && fem.mapping->HasDisplacementField()) {
|
if (origin_elem.Size() > 0 && origin_elem[0] >= 0) {
|
||||||
mfem::ElementTransformation *T0 = fem.mesh->GetElementTransformation(origin_elem[0]);
|
mfem::ElementTransformation *T0 = fem.mesh->GetElementTransformation(origin_elem[0]);
|
||||||
T0->SetIntPoint(&origin_ip[0]);
|
T0->SetIntPoint(&origin_ip[0]);
|
||||||
|
|
||||||
mfem::DenseMatrix J0(dim, dim), J0_inv(dim, dim);
|
mapping::MappingPointContext context;
|
||||||
fem.mapping->ComputeJacobian(*T0, J0);
|
MFEM_VERIFY(
|
||||||
mfem::CalcInverse(J0, J0_inv);
|
mapping_evaluator.EvaluatePoint(*T0, origin_ip[0], context) ==
|
||||||
|
mapping::MappingStatus::valid,
|
||||||
|
"Reference-point initialization encountered an invalid mapping."
|
||||||
|
);
|
||||||
|
|
||||||
J0_inv.Mult(x_phys_target, x_ref);
|
context.inverse_mapping_jacobian.Mult(x_phys_target, x_ref);
|
||||||
}
|
}
|
||||||
|
|
||||||
init_P.SetCol(0, x_ref);
|
init_P.SetCol(0, x_ref);
|
||||||
@@ -70,9 +77,6 @@ namespace mean_field::utils {
|
|||||||
mfem::Vector residual(dim);
|
mfem::Vector residual(dim);
|
||||||
mfem::Vector step(dim);
|
mfem::Vector step(dim);
|
||||||
|
|
||||||
mfem::DenseMatrix J_map(dim, dim);
|
|
||||||
mfem::DenseMatrix J_map_inv(dim, dim);
|
|
||||||
|
|
||||||
int find_failures = 0;
|
int find_failures = 0;
|
||||||
|
|
||||||
for (int iter = 0; iter < max_iter; ++iter) {
|
for (int iter = 0; iter < max_iter; ++iter) {
|
||||||
@@ -99,8 +103,12 @@ namespace mean_field::utils {
|
|||||||
mfem::ElementTransformation *T = fem.mesh->GetElementTransformation(elemID);
|
mfem::ElementTransformation *T = fem.mesh->GetElementTransformation(elemID);
|
||||||
T->SetIntPoint(&ip);
|
T->SetIntPoint(&ip);
|
||||||
|
|
||||||
mfem::Vector current_x_phys(dim);
|
mapping::MappingPointContext context;
|
||||||
fem.mapping->GetPhysicalPoint(*T, ip, current_x_phys);
|
if (mapping_evaluator.EvaluatePoint(*T, ip, context) !=
|
||||||
|
mapping::MappingStatus::valid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const mfem::Vector ¤t_x_phys = context.physical_position;
|
||||||
|
|
||||||
for (int i = 0; i < dim; ++i) {
|
for (int i = 0; i < dim; ++i) {
|
||||||
residual(i) = current_x_phys(i) - x_phys_target(i);
|
residual(i) = current_x_phys(i) - x_phys_target(i);
|
||||||
@@ -110,9 +118,7 @@ namespace mean_field::utils {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
fem.mapping->ComputeJacobian(*T, J_map);
|
context.inverse_mapping_jacobian.Mult(residual, step);
|
||||||
mfem::CalcInverse(J_map, J_map_inv);
|
|
||||||
J_map_inv.Mult(residual, step);
|
|
||||||
|
|
||||||
double alpha = 1.0;
|
double alpha = 1.0;
|
||||||
mfem::Vector x_ref_candidate(dim);
|
mfem::Vector x_ref_candidate(dim);
|
||||||
|
|||||||
@@ -1,116 +1,17 @@
|
|||||||
module;
|
module;
|
||||||
#include <expected>
|
|
||||||
#include <mfem.hpp>
|
#include <mfem.hpp>
|
||||||
|
|
||||||
module mean_field;
|
module mean_field;
|
||||||
import :boundary.contexts;
|
|
||||||
|
|
||||||
namespace mean_field::utils {
|
namespace mean_field::utils {
|
||||||
DOMAINS operator|(
|
DOMAINS operator|(DOMAINS lhs, DOMAINS rhs) {
|
||||||
DOMAINS lhs,
|
return static_cast<DOMAINS>(static_cast<uint8_t>(lhs) |
|
||||||
DOMAINS rhs
|
static_cast<uint8_t>(rhs));
|
||||||
) {
|
|
||||||
return static_cast<DOMAINS>(static_cast<uint8_t>(lhs) | static_cast<uint8_t>(rhs));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
DOMAINS operator&(
|
DOMAINS operator&(DOMAINS lhs, DOMAINS rhs) {
|
||||||
DOMAINS lhs,
|
return static_cast<DOMAINS>(static_cast<uint8_t>(lhs) &
|
||||||
DOMAINS rhs
|
static_cast<uint8_t>(rhs));
|
||||||
) {
|
|
||||||
return static_cast<DOMAINS>(static_cast<uint8_t>(lhs) & static_cast<uint8_t>(rhs));
|
|
||||||
}
|
|
||||||
|
|
||||||
void populate_element_mask(
|
|
||||||
const mfem::Mesh *mesh,
|
|
||||||
const DOMAINS domain,
|
|
||||||
mfem::Array<int> &mask
|
|
||||||
) {
|
|
||||||
const int max_attr = mesh->attributes.Max();
|
|
||||||
mask.SetSize(max_attr);
|
|
||||||
mask = 0;
|
|
||||||
|
|
||||||
if ((domain & DOMAINS::CORE) == DOMAINS::CORE && max_attr >= 1) {
|
|
||||||
mask[0] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((domain & DOMAINS::ENVELOPE) == DOMAINS::ENVELOPE && max_attr >= 2) {
|
|
||||||
mask[1] = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((domain & DOMAINS::VACUUM) == DOMAINS::VACUUM && max_attr >= 3) {
|
|
||||||
mask[2] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void populate_domain_tdofs(
|
|
||||||
const mfem::ParFiniteElementSpace *fes,
|
|
||||||
const mfem::Array<int> &element_mask,
|
|
||||||
mfem::Array<int> &ess_tdof
|
|
||||||
) {
|
|
||||||
mfem::Array<int> vdof_marker(fes->GetVSize());
|
|
||||||
vdof_marker = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < fes->GetMesh()->GetNE(); i++) {
|
|
||||||
const int attr = fes->GetMesh()->GetAttribute(i);
|
|
||||||
|
|
||||||
if (element_mask[attr - 1]) {
|
|
||||||
mfem::Array<int> dofs;
|
|
||||||
fes->GetElementVDofs(i, dofs);
|
|
||||||
|
|
||||||
for (int j = 0; j < dofs.Size(); j++) {
|
|
||||||
int index = dofs[j];
|
|
||||||
if (index < 0)
|
|
||||||
index = -1 - index;
|
|
||||||
vdof_marker[index] = 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fes->MarkerToList(vdof_marker, ess_tdof);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::expected<
|
|
||||||
boundary::Bounds,
|
|
||||||
boundary::BoundsError>
|
|
||||||
discover_bounds(
|
|
||||||
const mfem::Mesh *mesh,
|
|
||||||
const int vacuum_attr
|
|
||||||
) {
|
|
||||||
double local_min_r = std::numeric_limits<double>::max();
|
|
||||||
double local_max_r = -std::numeric_limits<double>::max();
|
|
||||||
bool found_vacuum = false;
|
|
||||||
|
|
||||||
for (int i = 0; i < mesh->GetNE(); ++i) {
|
|
||||||
if (mesh->GetAttribute(i) == vacuum_attr) {
|
|
||||||
found_vacuum = true;
|
|
||||||
mfem::Array<int> vertices;
|
|
||||||
mesh->GetElementVertices(i, vertices);
|
|
||||||
for (const int v : vertices) {
|
|
||||||
const double *coords = mesh->GetVertex(v);
|
|
||||||
double r = std::sqrt(coords[0] * coords[0] + coords[1] * coords[1] + coords[2] * coords[2]);
|
|
||||||
local_min_r = std::min(local_min_r, r);
|
|
||||||
local_max_r = std::max(local_max_r, r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double global_min_r, global_max_r;
|
|
||||||
int global_found_vacuum;
|
|
||||||
int l_found = found_vacuum ? 1 : 0;
|
|
||||||
|
|
||||||
MPI_Comm comm = MPI_COMM_WORLD;
|
|
||||||
if (const auto *pmesh = dynamic_cast<const mfem::ParMesh *>(mesh)) {
|
|
||||||
comm = pmesh->GetComm();
|
|
||||||
}
|
|
||||||
|
|
||||||
MPI_Allreduce(&local_min_r, &global_min_r, 1, MPI_DOUBLE, MPI_MIN, comm);
|
|
||||||
MPI_Allreduce(&local_max_r, &global_max_r, 1, MPI_DOUBLE, MPI_MAX, comm);
|
|
||||||
MPI_Allreduce(&l_found, &global_found_vacuum, 1, MPI_INT, MPI_MAX, comm);
|
|
||||||
|
|
||||||
if (global_found_vacuum) {
|
|
||||||
return boundary::Bounds(global_min_r, global_max_r);
|
|
||||||
}
|
|
||||||
return std::unexpected(boundary::BoundsError::CANNOT_FIND_VACUUM);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_mesh_order(const mfem::Mesh &mesh) {
|
int get_mesh_order(const mfem::Mesh &mesh) {
|
||||||
|
|||||||
@@ -121,7 +121,7 @@ export namespace mean_field::eos {
|
|||||||
std::pow(density, 1.0 / m_polytropic_index);
|
std::pow(density, 1.0 / m_polytropic_index);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double enthalpy_from_pressure(double pressure) const override {
|
[[nodiscard]] double enthalpy_from_pressure(const double pressure) const override {
|
||||||
validate_nonnegativity(pressure, "pressure");
|
validate_nonnegativity(pressure, "pressure");
|
||||||
const double np1 = m_polytropic_index + 1;
|
const double np1 = m_polytropic_index + 1;
|
||||||
return np1 * std::pow(m_polytropic_constant, m_polytropic_index / np1) * std::pow(pressure, 1.0 / np1);
|
return np1 * std::pow(m_polytropic_constant, m_polytropic_index / np1) * std::pow(pressure, 1.0 / np1);
|
||||||
@@ -159,10 +159,6 @@ export namespace mean_field::eos {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
|
||||||
|
|
||||||
private:
|
|
||||||
double m_polytropic_index;
|
double m_polytropic_index;
|
||||||
double m_polytropic_constant;
|
double m_polytropic_constant;
|
||||||
double m_enthalpy_scale;
|
double m_enthalpy_scale;
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ module;
|
|||||||
|
|
||||||
export module mean_field:fem;
|
export module mean_field:fem;
|
||||||
|
|
||||||
export import :physics.contexts;
|
|
||||||
export import :boundary.contexts;
|
export import :boundary.contexts;
|
||||||
export import :mapping.domain_mapper;
|
export import :mapping.domain_mapper;
|
||||||
export import :utils.misc;
|
export import :utils.misc;
|
||||||
@@ -92,38 +91,9 @@ export namespace mean_field::fem {
|
|||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Domain mapping
|
// Domain mapping
|
||||||
//
|
|
||||||
// These are declared after displacement so that they are destroyed
|
|
||||||
// before the displacement grid function to which mapping may refer.
|
|
||||||
// DomainMapper is retained only for legacy integrators. New operators
|
|
||||||
// use DomainMapperStateless exclusively.
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
std::unique_ptr<mapping::DomainMapper> mapping;
|
std::unique_ptr<mapping::DomainMapper> domainMapperStateless;
|
||||||
|
|
||||||
std::unique_ptr<mapping::DomainMapperStateless> domainMapperStateless;
|
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
// Block layouts
|
|
||||||
//
|
|
||||||
// These arrays are retained only for legacy code. Canonical operator
|
|
||||||
// layouts are defined by the compile-time forms in :utils.blocks.
|
|
||||||
//
|
|
||||||
// Main system: [Displacement | Density]
|
|
||||||
// Gravity system: [Flux | Potential]
|
|
||||||
// =====================================================================
|
|
||||||
|
|
||||||
mfem::Array<int> blockTrueOffsets;
|
|
||||||
mfem::Array<int> gravityBlockTrueOffsets;
|
|
||||||
|
|
||||||
// =====================================================================
|
|
||||||
// Boundary conditions and domain masks
|
|
||||||
// =====================================================================
|
|
||||||
|
|
||||||
mfem::Array<int> essentialDisplacementTdofs;
|
|
||||||
mfem::Array<int> vacuumDensityTdofs;
|
|
||||||
mfem::Array<int> vacuumEnthalpyTdofs;
|
|
||||||
mfem::Array<int> vacuumDisplacementTdofs;
|
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Global diagnostics
|
// Global diagnostics
|
||||||
@@ -133,10 +103,9 @@ export namespace mean_field::fem {
|
|||||||
mfem::DenseMatrix Q;
|
mfem::DenseMatrix Q;
|
||||||
|
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
// Physics and boundary contexts
|
// Boundary context
|
||||||
// =====================================================================
|
// =====================================================================
|
||||||
|
|
||||||
physics::GravityContext gravityContext;
|
|
||||||
boundary::BoundaryContext boundaryContext;
|
boundary::BoundaryContext boundaryContext;
|
||||||
|
|
||||||
std::unique_ptr<quadrature::RuleFactory> quadratureFactory;
|
std::unique_ptr<quadrature::RuleFactory> quadratureFactory;
|
||||||
@@ -160,13 +129,11 @@ export namespace mean_field::fem {
|
|||||||
compactificationFec != nullptr && compactificationFes != nullptr &&
|
compactificationFec != nullptr && compactificationFes != nullptr &&
|
||||||
compactificationCoordinate != nullptr &&
|
compactificationCoordinate != nullptr &&
|
||||||
|
|
||||||
mapping != nullptr && domainMapperStateless != nullptr && quadratureFactory != nullptr &&
|
domainMapperStateless != nullptr && quadratureFactory != nullptr;
|
||||||
|
|
||||||
blockTrueOffsets.Size() == 3 && gravityBlockTrueOffsets.Size() == 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] bool has_mapping() const {
|
[[nodiscard]] bool has_mapping() const {
|
||||||
return mapping != nullptr;
|
return domainMapperStateless != nullptr && displacement != nullptr && compactificationCoordinate != nullptr;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ module;
|
|||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
#include <mfem.hpp>
|
#include <mfem.hpp>
|
||||||
|
|
||||||
@@ -887,6 +888,110 @@ export namespace mean_field::field {
|
|||||||
mfem::Array<int> m_trueToReduced;
|
mfem::Array<int> m_trueToReduced;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Canonical adapter between an MFEM GridFunction and a reduced field
|
||||||
|
* vector.
|
||||||
|
*
|
||||||
|
* FieldDofMap deliberately contains only indexing information. This
|
||||||
|
* adapter binds that indexing to the exact finite-element space whose true
|
||||||
|
* DOFs the map describes. Consequently, a grid function from another
|
||||||
|
* finite-element space is rejected even when it happens to have the same
|
||||||
|
* vector size.
|
||||||
|
*
|
||||||
|
* The finite-element space must outlive the adapter.
|
||||||
|
*/
|
||||||
|
class FieldDofGridFunctionAdapter {
|
||||||
|
public:
|
||||||
|
FieldDofGridFunctionAdapter(
|
||||||
|
FieldDofMap dofMap,
|
||||||
|
const mfem::FiniteElementSpace &finiteElementSpace
|
||||||
|
)
|
||||||
|
: m_dofMap(std::move(dofMap)),
|
||||||
|
m_finiteElementSpace(&finiteElementSpace) {
|
||||||
|
if (m_dofMap.full_size() != finiteElementSpace.GetTrueVSize()) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"FieldDofGridFunctionAdapter map and finite-element "
|
||||||
|
"space have incompatible true-DOF sizes."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const FieldDofMap &dof_map() const noexcept {
|
||||||
|
return m_dofMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const mfem::FiniteElementSpace &finite_element_space() const noexcept {
|
||||||
|
return *m_finiteElementSpace;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gather the grid function's true DOFs into reduced field ordering.
|
||||||
|
* The output vector is not resized so MFEM vector views remain valid.
|
||||||
|
*/
|
||||||
|
void gather(
|
||||||
|
const mfem::GridFunction &gridFunction,
|
||||||
|
mfem::Vector &reduced
|
||||||
|
) const {
|
||||||
|
validate_grid_function(gridFunction);
|
||||||
|
|
||||||
|
mfem::Vector full;
|
||||||
|
gridFunction.GetTrueDofs(full);
|
||||||
|
m_dofMap.gather(full, reduced);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
mfem::Vector gather(const mfem::GridFunction &gridFunction) const {
|
||||||
|
mfem::Vector reduced(m_dofMap.reduced_size());
|
||||||
|
gather(gridFunction, reduced);
|
||||||
|
return reduced;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scatter with projection semantics. Unsupported true DOFs are zeroed
|
||||||
|
* before the complete true vector is distributed to the grid function.
|
||||||
|
*/
|
||||||
|
void scatter(
|
||||||
|
const mfem::Vector &reduced,
|
||||||
|
mfem::GridFunction &gridFunction
|
||||||
|
) const {
|
||||||
|
validate_grid_function(gridFunction);
|
||||||
|
|
||||||
|
const mfem::Vector full = m_dofMap.scatter(reduced);
|
||||||
|
gridFunction.SetFromTrueDofs(full);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Scatter while preserving the grid function's existing unsupported
|
||||||
|
* true DOFs.
|
||||||
|
*/
|
||||||
|
void scatter_into(
|
||||||
|
const mfem::Vector &reduced,
|
||||||
|
mfem::GridFunction &gridFunction
|
||||||
|
) const {
|
||||||
|
validate_grid_function(gridFunction);
|
||||||
|
|
||||||
|
mfem::Vector full;
|
||||||
|
gridFunction.GetTrueDofs(full);
|
||||||
|
m_dofMap.scatter_into(reduced, full);
|
||||||
|
gridFunction.SetFromTrueDofs(full);
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void validate_grid_function(const mfem::GridFunction &gridFunction) const {
|
||||||
|
if (gridFunction.FESpace() != m_finiteElementSpace) {
|
||||||
|
throw std::invalid_argument(
|
||||||
|
"FieldDofGridFunctionAdapter received a grid function "
|
||||||
|
"from a different finite-element space."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FieldDofMap m_dofMap;
|
||||||
|
const mfem::FiniteElementSpace *m_finiteElementSpace;
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Construct the canonical solver map for a registered spatial field.
|
* Construct the canonical solver map for a registered spatial field.
|
||||||
*
|
*
|
||||||
@@ -903,4 +1008,16 @@ export namespace mean_field::field {
|
|||||||
|
|
||||||
return FieldDofMap(support);
|
return FieldDofMap(support);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <
|
||||||
|
MfemDomainField FieldT,
|
||||||
|
utils::domain::IsSchema SchemaT>
|
||||||
|
[[nodiscard]]
|
||||||
|
FieldDofGridFunctionAdapter
|
||||||
|
make_field_dof_grid_function_adapter(const mfem::ParFiniteElementSpace &finiteElementSpace) {
|
||||||
|
return FieldDofGridFunctionAdapter(
|
||||||
|
make_field_dof_map<FieldT, SchemaT>(finiteElementSpace),
|
||||||
|
finiteElementSpace
|
||||||
|
);
|
||||||
|
}
|
||||||
} // namespace mean_field::field
|
} // namespace mean_field::field
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ import :mapping.domain_mapper;
|
|||||||
export namespace mean_field::integrators {
|
export namespace mean_field::integrators {
|
||||||
class AdvectionIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
class AdvectionIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
explicit AdvectionIntegrator(const mapping::DomainMapper &map);
|
AdvectionIntegrator(
|
||||||
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate
|
||||||
|
);
|
||||||
|
|
||||||
void AssembleElementVector(
|
void AssembleElementVector(
|
||||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||||
@@ -23,6 +27,6 @@ export namespace mean_field::integrators {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
};
|
};
|
||||||
} // namespace mean_field::integrators
|
} // namespace mean_field::integrators
|
||||||
@@ -7,7 +7,9 @@ export namespace mean_field::integrators {
|
|||||||
class CentrifugalForceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
class CentrifugalForceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
CentrifugalForceIntegrator(
|
CentrifugalForceIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const mfem::Vector &omega
|
const mfem::Vector &omega
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -29,7 +31,7 @@ export namespace mean_field::integrators {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
mfem::Vector m_omega;
|
mfem::Vector m_omega;
|
||||||
const mfem::IntegrationRule *m_ir = nullptr;
|
const mfem::IntegrationRule *m_ir = nullptr;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ export namespace mean_field::integrators {
|
|||||||
class CoriolisIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
class CoriolisIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
CoriolisIntegrator(
|
CoriolisIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const mfem::Vector &omega
|
const mfem::Vector &omega
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -26,7 +28,7 @@ export namespace mean_field::integrators {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
mfem::Vector m_omega;
|
mfem::Vector m_omega;
|
||||||
mfem::DenseMatrix m_omega_mat;
|
mfem::DenseMatrix m_omega_mat;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ export namespace mean_field::integrators {
|
|||||||
class GravityMomentumIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
class GravityMomentumIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
explicit GravityMomentumIntegrator(
|
explicit GravityMomentumIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
GravityForceJacobianMode jacobian_mode = GravityForceJacobianMode::field_coupled
|
GravityForceJacobianMode jacobian_mode = GravityForceJacobianMode::field_coupled
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ export namespace mean_field::integrators {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
GravityForceJacobianMode m_jacobian_mode;
|
GravityForceJacobianMode m_jacobian_mode;
|
||||||
const mfem::IntegrationRule *m_integration_rule{nullptr};
|
const mfem::IntegrationRule *m_integration_rule{nullptr};
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -6,7 +6,11 @@ import :mapping.domain_mapper;
|
|||||||
export namespace mean_field::integrators {
|
export namespace mean_field::integrators {
|
||||||
class ContinuityVolumeIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
class ContinuityVolumeIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
explicit ContinuityVolumeIntegrator(const mapping::DomainMapper &map);
|
ContinuityVolumeIntegrator(
|
||||||
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate
|
||||||
|
);
|
||||||
|
|
||||||
void AssembleElementVector(
|
void AssembleElementVector(
|
||||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||||
@@ -23,12 +27,16 @@ export namespace mean_field::integrators {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
class ContinuityFaceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
class ContinuityFaceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
explicit ContinuityFaceIntegrator(const mapping::DomainMapper &map);
|
ContinuityFaceIntegrator(
|
||||||
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate
|
||||||
|
);
|
||||||
|
|
||||||
void AssembleFaceVector(
|
void AssembleFaceVector(
|
||||||
const mfem::Array<const mfem::FiniteElement *> &el1,
|
const mfem::Array<const mfem::FiniteElement *> &el1,
|
||||||
@@ -58,7 +66,7 @@ export namespace mean_field::integrators {
|
|||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mean_field::integrators
|
} // namespace mean_field::integrators
|
||||||
|
|||||||
@@ -10,7 +10,9 @@ export namespace mean_field::integrators {
|
|||||||
template <utils::is_xad EOS_T> class PressureGradientIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
template <utils::is_xad EOS_T> class PressureGradientIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
PressureGradientIntegrator(
|
PressureGradientIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
utils::EOS_P<EOS_T> eos
|
utils::EOS_P<EOS_T> eos
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -28,16 +30,18 @@ export namespace mean_field::integrators {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
utils::EOS_P<EOS_T> m_eos;
|
utils::EOS_P<EOS_T> m_eos;
|
||||||
};
|
};
|
||||||
|
|
||||||
template <utils::is_xad EOS_T>
|
template <utils::is_xad EOS_T>
|
||||||
PressureGradientIntegrator<EOS_T>::PressureGradientIntegrator(
|
PressureGradientIntegrator<EOS_T>::PressureGradientIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
utils::EOS_P<EOS_T> eos
|
utils::EOS_P<EOS_T> eos
|
||||||
)
|
)
|
||||||
: m_map(map),
|
: m_mapping(mapper, displacement, compactification_coordinate),
|
||||||
m_eos(std::move(eos)) {
|
m_eos(std::move(eos)) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,6 +52,8 @@ export namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array<mfem::Vector *> &elvec
|
const mfem::Array<mfem::Vector *> &elvec
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
if (utils::is_vacuum(Tr, elvec)) {
|
if (utils::is_vacuum(Tr, elvec)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -78,7 +84,7 @@ export namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||||
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
||||||
@@ -111,6 +117,8 @@ export namespace mean_field::integrators {
|
|||||||
const mfem::Array<const mfem::Vector *> &elfun,
|
const mfem::Array<const mfem::Vector *> &elfun,
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||||
) {
|
) {
|
||||||
|
m_mapping.InvalidateCache();
|
||||||
|
|
||||||
const mfem::FiniteElement *fe_v = el[0];
|
const mfem::FiniteElement *fe_v = el[0];
|
||||||
const mfem::FiniteElement *fe_rho = el[1];
|
const mfem::FiniteElement *fe_rho = el[1];
|
||||||
|
|
||||||
@@ -141,7 +149,7 @@ export namespace mean_field::integrators {
|
|||||||
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
|
||||||
Tr.SetIntPoint(&ip);
|
Tr.SetIntPoint(&ip);
|
||||||
|
|
||||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
auto [J_inv, detJ, weight] = m_mapping.GetQuadratureContext(Tr, ip);
|
||||||
|
|
||||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||||
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ export namespace mean_field::integrators {
|
|||||||
class ViscosityIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
class ViscosityIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||||
public:
|
public:
|
||||||
ViscosityIntegrator(
|
ViscosityIntegrator(
|
||||||
const mapping::DomainMapper &map,
|
const mapping::DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
double mu,
|
double mu,
|
||||||
int quad_boost
|
int quad_boost
|
||||||
);
|
);
|
||||||
@@ -29,7 +31,7 @@ export namespace mean_field::integrators {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mapping::DomainMapper &m_map;
|
mapping::GridFunctionMappingEvaluator m_mapping;
|
||||||
double m_mu;
|
double m_mu;
|
||||||
int m_quad_boost;
|
int m_quad_boost;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -9,7 +9,9 @@ export namespace mean_field::mapping {
|
|||||||
class MappedScalarCoefficient : public mfem::Coefficient {
|
class MappedScalarCoefficient : public mfem::Coefficient {
|
||||||
public:
|
public:
|
||||||
MappedScalarCoefficient(
|
MappedScalarCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
Coefficient &coeff,
|
Coefficient &coeff,
|
||||||
COORDINATE_SPACE coord_space = COORDINATE_SPACE::PHYSICAL
|
COORDINATE_SPACE coord_space = COORDINATE_SPACE::PHYSICAL
|
||||||
);
|
);
|
||||||
@@ -27,7 +29,7 @@ export namespace mean_field::mapping {
|
|||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const DomainMapper &m_map;
|
GridFunctionMappingEvaluator m_mapping;
|
||||||
Coefficient &m_coeff;
|
Coefficient &m_coeff;
|
||||||
COORDINATE_SPACE m_coord_space;
|
COORDINATE_SPACE m_coord_space;
|
||||||
};
|
};
|
||||||
@@ -35,13 +37,17 @@ export namespace mean_field::mapping {
|
|||||||
class MappedDiffusionCoefficient : public mfem::MatrixCoefficient {
|
class MappedDiffusionCoefficient : public mfem::MatrixCoefficient {
|
||||||
public:
|
public:
|
||||||
MappedDiffusionCoefficient(
|
MappedDiffusionCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
mfem::Coefficient &sigma,
|
mfem::Coefficient &sigma,
|
||||||
int dim
|
int dim
|
||||||
);
|
);
|
||||||
|
|
||||||
MappedDiffusionCoefficient(
|
MappedDiffusionCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
MatrixCoefficient &sigma
|
MatrixCoefficient &sigma
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -52,7 +58,7 @@ export namespace mean_field::mapping {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const DomainMapper &m_map;
|
GridFunctionMappingEvaluator m_mapping;
|
||||||
mfem::Coefficient *m_scalar;
|
mfem::Coefficient *m_scalar;
|
||||||
MatrixCoefficient *m_tensor;
|
MatrixCoefficient *m_tensor;
|
||||||
};
|
};
|
||||||
@@ -60,7 +66,9 @@ export namespace mean_field::mapping {
|
|||||||
class MappedVectorCoefficient : public mfem::VectorCoefficient {
|
class MappedVectorCoefficient : public mfem::VectorCoefficient {
|
||||||
public:
|
public:
|
||||||
MappedVectorCoefficient(
|
MappedVectorCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
VectorCoefficient &coeff
|
VectorCoefficient &coeff
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -71,7 +79,7 @@ export namespace mean_field::mapping {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const DomainMapper &m_map;
|
GridFunctionMappingEvaluator m_mapping;
|
||||||
VectorCoefficient &m_coeff;
|
VectorCoefficient &m_coeff;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -80,7 +88,9 @@ export namespace mean_field::mapping {
|
|||||||
using Func = std::function<double(const mfem::Vector &x)>;
|
using Func = std::function<double(const mfem::Vector &x)>;
|
||||||
|
|
||||||
PhysicalPositionFunctionCoefficient(
|
PhysicalPositionFunctionCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
Func f
|
Func f
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -91,13 +101,15 @@ export namespace mean_field::mapping {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
Func m_f;
|
Func m_f;
|
||||||
const DomainMapper &m_map;
|
GridFunctionMappingEvaluator m_mapping;
|
||||||
};
|
};
|
||||||
|
|
||||||
class MappedHDivMassCoefficient final : public mfem::MatrixCoefficient {
|
class MappedHDivMassCoefficient final : public mfem::MatrixCoefficient {
|
||||||
public:
|
public:
|
||||||
MappedHDivMassCoefficient(
|
MappedHDivMassCoefficient(
|
||||||
const DomainMapper &map,
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate,
|
||||||
const int dim
|
const int dim
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -108,6 +120,6 @@ export namespace mean_field::mapping {
|
|||||||
) override;
|
) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const DomainMapper &m_map;
|
GridFunctionMappingEvaluator m_mapping;
|
||||||
};
|
};
|
||||||
} // namespace mean_field::mapping
|
} // namespace mean_field::mapping
|
||||||
|
|||||||
@@ -13,10 +13,8 @@ export namespace mean_field::mapping {
|
|||||||
class ElementDisplacementData {
|
class ElementDisplacementData {
|
||||||
public:
|
public:
|
||||||
ElementDisplacementData(
|
ElementDisplacementData(
|
||||||
const mfem::FiniteElement &element,
|
const mfem::FiniteElement &element, const mfem::Vector &displacement_dofs,
|
||||||
const mfem::Vector &displacement_dofs,
|
mfem::Ordering::Type ordering = mfem::Ordering::byNODES);
|
||||||
mfem::Ordering::Type ordering = mfem::Ordering::byNODES
|
|
||||||
);
|
|
||||||
|
|
||||||
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
||||||
[[nodiscard]] const mfem::DenseMatrix &GetDofMatrix() const noexcept;
|
[[nodiscard]] const mfem::DenseMatrix &GetDofMatrix() const noexcept;
|
||||||
@@ -36,17 +34,14 @@ export namespace mean_field::mapping {
|
|||||||
mfem::Vector coordinate_gradient;
|
mfem::Vector coordinate_gradient;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] ElementDisplacementData ElementDisplacementDataFromElementVDofs(
|
[[nodiscard]] ElementDisplacementData
|
||||||
const mfem::FiniteElement &element,
|
ElementDisplacementDataFromElementVDofs(const mfem::FiniteElement &element,
|
||||||
const mfem::Vector &displacement_dofs
|
const mfem::Vector &displacement_dofs);
|
||||||
);
|
|
||||||
|
|
||||||
class ElementCompactificationData {
|
class ElementCompactificationData {
|
||||||
public:
|
public:
|
||||||
ElementCompactificationData(
|
ElementCompactificationData(const mfem::FiniteElement &element,
|
||||||
const mfem::FiniteElement &element,
|
const mfem::Vector &dofs);
|
||||||
const mfem::Vector &dofs
|
|
||||||
);
|
|
||||||
|
|
||||||
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
[[nodiscard]] const mfem::FiniteElement &GetElement() const noexcept;
|
||||||
[[nodiscard]] const mfem::Vector &GetDofs() const noexcept;
|
[[nodiscard]] const mfem::Vector &GetDofs() const noexcept;
|
||||||
@@ -62,7 +57,7 @@ export namespace mean_field::mapping {
|
|||||||
const ElementCompactificationData &compactification;
|
const ElementCompactificationData &compactification;
|
||||||
};
|
};
|
||||||
|
|
||||||
class DomainMapperStateless {
|
class DomainMapper {
|
||||||
public:
|
public:
|
||||||
class Workspace {
|
class Workspace {
|
||||||
public:
|
public:
|
||||||
@@ -73,7 +68,7 @@ export namespace mean_field::mapping {
|
|||||||
[[nodiscard]] int GetDimension() const noexcept;
|
[[nodiscard]] int GetDimension() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend class DomainMapperStateless;
|
friend class DomainMapper;
|
||||||
|
|
||||||
int m_dimension;
|
int m_dimension;
|
||||||
|
|
||||||
@@ -99,256 +94,173 @@ export namespace mean_field::mapping {
|
|||||||
};
|
};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DomainMapperStateless(
|
DomainMapper(
|
||||||
utils::DomainMapperStatelessOptions options,
|
utils::DomainMapperOptions options,
|
||||||
std::unique_ptr<const compactification::ExteriorDomainMap> exterior_map
|
std::unique_ptr<const compactification::ExteriorDomainMap> exterior_map);
|
||||||
);
|
|
||||||
|
|
||||||
DomainMapperStateless(const DomainMapperStateless &) = delete;
|
DomainMapper(const DomainMapper &) = delete;
|
||||||
DomainMapperStateless &operator=(const DomainMapperStateless &) = delete;
|
DomainMapper &operator=(const DomainMapper &) = delete;
|
||||||
DomainMapperStateless(DomainMapperStateless &&) = default;
|
DomainMapper(DomainMapper &&) = default;
|
||||||
DomainMapperStateless &operator=(DomainMapperStateless &&) = default;
|
DomainMapper &operator=(DomainMapper &&) = default;
|
||||||
|
|
||||||
[[nodiscard]] MappingStatus EvaluatePoint(
|
[[nodiscard]] MappingStatus
|
||||||
const ElementMappingData &element_data,
|
EvaluatePoint(const ElementMappingData &element_data,
|
||||||
mfem::ElementTransformation &transformation,
|
mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
Workspace &workspace,
|
Workspace &workspace, MappingPointContext &context) const;
|
||||||
MappingPointContext &context
|
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] MappingStatus EvaluateVolume(
|
[[nodiscard]] MappingStatus
|
||||||
const ElementMappingData &element_data,
|
EvaluateVolume(const ElementMappingData &element_data,
|
||||||
mfem::ElementTransformation &transformation,
|
mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
Workspace &workspace,
|
Workspace &workspace, VolumeMappingContext &context) const;
|
||||||
VolumeMappingContext &context
|
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] MappingStatus EvaluateFace(
|
[[nodiscard]] MappingStatus
|
||||||
const ElementMappingData &element_data,
|
EvaluateFace(const ElementMappingData &element_data,
|
||||||
mfem::FaceElementTransformations &transformation,
|
mfem::FaceElementTransformations &transformation,
|
||||||
FaceElementSide side,
|
FaceElementSide side,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
Workspace &workspace,
|
Workspace &workspace, FaceMappingContext &context) const;
|
||||||
FaceMappingContext &context
|
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] MappingStatus EvaluatePointVariation(
|
[[nodiscard]] MappingStatus
|
||||||
const ElementMappingData &element_data,
|
EvaluatePointVariation(const ElementMappingData &element_data,
|
||||||
const ElementDisplacementData &direction,
|
const ElementDisplacementData &direction,
|
||||||
mfem::ElementTransformation &transformation,
|
mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
const MappingPointContext &base_context,
|
const MappingPointContext &base_context,
|
||||||
Workspace &workspace,
|
Workspace &workspace,
|
||||||
MappingPointVariation &variation
|
MappingPointVariation &variation) const;
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] MappingStatus EvaluateVolumeVariation(
|
[[nodiscard]] MappingStatus
|
||||||
const ElementMappingData &element_data,
|
EvaluateVolumeVariation(const ElementMappingData &element_data,
|
||||||
const ElementDisplacementData &direction,
|
const ElementDisplacementData &direction,
|
||||||
mfem::ElementTransformation &transformation,
|
mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
const VolumeMappingContext &base_context,
|
const VolumeMappingContext &base_context,
|
||||||
Workspace &workspace,
|
Workspace &workspace,
|
||||||
VolumeMappingVariation &variation
|
VolumeMappingVariation &variation) const;
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] MappingStatus EvaluateFaceVariation(
|
[[nodiscard]] MappingStatus EvaluateFaceVariation(
|
||||||
const ElementMappingData &element_data,
|
const ElementMappingData &element_data,
|
||||||
const ElementDisplacementData &direction,
|
const ElementDisplacementData &direction,
|
||||||
mfem::FaceElementTransformations &transformation,
|
mfem::FaceElementTransformations &transformation, FaceElementSide side,
|
||||||
FaceElementSide side,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
const FaceMappingContext &base_context,
|
const FaceMappingContext &base_context, Workspace &workspace,
|
||||||
Workspace &workspace,
|
FaceMappingVariation &variation) const;
|
||||||
FaceMappingVariation &variation
|
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsCompactifiedElement(const mfem::ElementTransformation &transformation) const noexcept;
|
[[nodiscard]] bool IsCompactifiedElement(
|
||||||
|
const mfem::ElementTransformation &transformation) const noexcept;
|
||||||
[[nodiscard]] int GetDimension() const noexcept;
|
[[nodiscard]] int GetDimension() const noexcept;
|
||||||
[[nodiscard]] int GetVacuumElementAttribute() const noexcept;
|
[[nodiscard]] const compactification::ExteriorDomainMap &
|
||||||
[[nodiscard]] const compactification::ExteriorDomainMap &GetExteriorMap() const noexcept;
|
GetExteriorMap() const noexcept;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void ValidateElementData(const ElementMappingData &element_data) const;
|
void ValidateElementData(const ElementMappingData &element_data) const;
|
||||||
|
|
||||||
void EvaluateField(
|
void EvaluateField(const ElementDisplacementData &field,
|
||||||
const ElementDisplacementData &field,
|
|
||||||
mfem::ElementTransformation &transformation,
|
mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
Workspace &workspace,
|
Workspace &workspace, mfem::Vector &value,
|
||||||
mfem::Vector &value,
|
mfem::DenseMatrix &jacobian) const;
|
||||||
mfem::DenseMatrix &jacobian
|
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] MappingStatus EvaluateCompactificationCoordinate(
|
[[nodiscard]] MappingStatus EvaluateCompactificationCoordinate(
|
||||||
const ElementCompactificationData &compactification,
|
const ElementCompactificationData &compactification,
|
||||||
mfem::ElementTransformation &transformation,
|
mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point, Workspace &workspace,
|
||||||
Workspace &workspace,
|
CompactificationPointData &point_data) const;
|
||||||
CompactificationPointData &point_data
|
|
||||||
) const;
|
|
||||||
|
|
||||||
[[nodiscard]] static mfem::ElementTransformation &SelectFaceElementTransformation(
|
[[nodiscard]] static mfem::ElementTransformation &
|
||||||
mfem::FaceElementTransformations &transformation,
|
SelectFaceElementTransformation(
|
||||||
FaceElementSide side
|
mfem::FaceElementTransformations &transformation, FaceElementSide side);
|
||||||
);
|
|
||||||
|
|
||||||
[[nodiscard]] static const mfem::IntegrationPoint &SelectFaceElementIntegrationPoint(
|
[[nodiscard]] static const mfem::IntegrationPoint &
|
||||||
mfem::FaceElementTransformations &transformation,
|
SelectFaceElementIntegrationPoint(
|
||||||
FaceElementSide side
|
mfem::FaceElementTransformations &transformation, FaceElementSide side);
|
||||||
);
|
|
||||||
|
|
||||||
utils::DomainMapperStatelessOptions m_options;
|
utils::DomainMapperOptions m_options;
|
||||||
std::unique_ptr<const compactification::ExteriorDomainMap> m_exterior_map;
|
std::unique_ptr<const compactification::ExteriorDomainMap> m_exterior_map;
|
||||||
};
|
};
|
||||||
class DomainMapper {
|
|
||||||
|
|
||||||
|
class GridFunctionMappingEvaluator {
|
||||||
public:
|
public:
|
||||||
explicit DomainMapper(
|
/*
|
||||||
const double r_star_ref,
|
* The evaluator references the supplied grid functions and caches copies of
|
||||||
const double r_inf_ref
|
* their element-local DOFs. Call InvalidateCache() or Refresh() after either
|
||||||
);
|
* grid function's values are modified. Finite-element-space sequence changes
|
||||||
|
* are detected automatically.
|
||||||
|
*
|
||||||
|
* This object owns mutable workspace and cache state and is not thread-safe.
|
||||||
|
*/
|
||||||
|
GridFunctionMappingEvaluator(
|
||||||
|
const DomainMapper &mapper,
|
||||||
|
const mfem::GridFunction &displacement,
|
||||||
|
const mfem::GridFunction &compactification_coordinate);
|
||||||
|
|
||||||
explicit DomainMapper(
|
/*
|
||||||
const mfem::GridFunction &d,
|
* Discard all element-local field data. The next evaluation reloads its
|
||||||
const double r_star_ref,
|
* requested element lazily. This operation is idempotent.
|
||||||
const double r_inf_ref
|
*/
|
||||||
);
|
void InvalidateCache() noexcept;
|
||||||
|
|
||||||
[[nodiscard]] bool is_vacuum(const mfem::ElementTransformation &T) const;
|
/*
|
||||||
|
* Reload the currently cached element immediately. If no element has been
|
||||||
|
* evaluated yet, Refresh() is a validated no-op. If either finite-element
|
||||||
|
* space changed sequence, the old element ID is discarded and the next
|
||||||
|
* evaluation reloads lazily against the updated spaces.
|
||||||
|
*/
|
||||||
|
void Refresh();
|
||||||
|
|
||||||
void SetDisplacement(const mfem::GridFunction &d);
|
[[nodiscard]] MappingStatus
|
||||||
|
EvaluatePoint(mfem::ElementTransformation &transformation,
|
||||||
[[nodiscard]] bool HasCompactification() const noexcept;
|
|
||||||
[[nodiscard]] bool HasDisplacementField() const noexcept;
|
|
||||||
[[nodiscard]] bool CalcIsIdentity() const;
|
|
||||||
|
|
||||||
void ResetDisplacement();
|
|
||||||
|
|
||||||
void ComputeJacobian(
|
|
||||||
mfem::ElementTransformation &T,
|
|
||||||
mfem::DenseMatrix &J
|
|
||||||
) const;
|
|
||||||
|
|
||||||
double ComputeDetJ(
|
|
||||||
mfem::ElementTransformation &T,
|
|
||||||
const mfem::IntegrationPoint &ip
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void ComputeMappedDiffusionTensor(
|
|
||||||
mfem::ElementTransformation &T,
|
|
||||||
mfem::DenseMatrix &D
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void ComputeInverseJacobian(
|
|
||||||
mfem::ElementTransformation &T,
|
|
||||||
mfem::DenseMatrix &JInv
|
|
||||||
) const;
|
|
||||||
|
|
||||||
VolumeQuadratureContext GetQuadratureContext(
|
|
||||||
mfem::ElementTransformation &T,
|
|
||||||
const mfem::IntegrationPoint &ip
|
|
||||||
) const;
|
|
||||||
|
|
||||||
FaceQuadratureContext GetFaceQuadratureContext(
|
|
||||||
mfem::FaceElementTransformations &T,
|
|
||||||
const mfem::IntegrationPoint &ip
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void GetPhysicalPoint(
|
|
||||||
mfem::ElementTransformation &T,
|
|
||||||
const mfem::IntegrationPoint &ip,
|
|
||||||
mfem::Vector &x_phys
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void GetVectorValue(
|
|
||||||
const int i,
|
|
||||||
const mfem::IntegrationPoint &ip,
|
|
||||||
mfem::Vector &val
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void MapHDivFluxToPhysical(
|
|
||||||
mfem::ElementTransformation &transformation,
|
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
const mfem::Vector &reference_flux,
|
MappingPointContext &context);
|
||||||
mfem::Vector &physical_flux
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void MapPhysicalFluxToHDivReference(
|
[[nodiscard]] MappingStatus
|
||||||
mfem::ElementTransformation &transformation,
|
EvaluateVolume(mfem::ElementTransformation &transformation,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
const mfem::Vector &physical_flux,
|
VolumeMappingContext &context);
|
||||||
mfem::Vector &reference_flux
|
|
||||||
) const;
|
|
||||||
|
|
||||||
void MapReferenceGradientToPhysical(
|
[[nodiscard]] MappingStatus
|
||||||
mfem::ElementTransformation &transformation,
|
EvaluateFace(mfem::FaceElementTransformations &transformation,
|
||||||
|
FaceElementSide side,
|
||||||
const mfem::IntegrationPoint &integration_point,
|
const mfem::IntegrationPoint &integration_point,
|
||||||
const mfem::Vector &reference_gradient,
|
FaceMappingContext &context);
|
||||||
mfem::Vector &physical_gradient
|
|
||||||
) const;
|
|
||||||
[[nodiscard]] const mfem::GridFunction *GetDisplacement() const;
|
|
||||||
|
|
||||||
[[nodiscard]] double GetPhysInfRadius() const;
|
[[nodiscard]] VolumeQuadratureContext
|
||||||
|
GetQuadratureContext(mfem::ElementTransformation &transformation,
|
||||||
|
const mfem::IntegrationPoint &integration_point);
|
||||||
|
|
||||||
[[nodiscard]] size_t GetCacheHits() const;
|
[[nodiscard]] FaceQuadratureContext
|
||||||
|
GetFaceQuadratureContext(
|
||||||
|
mfem::FaceElementTransformations &transformation,
|
||||||
|
const mfem::IntegrationPoint &integration_point,
|
||||||
|
FaceElementSide side = FaceElementSide::element_1);
|
||||||
|
|
||||||
[[nodiscard]] size_t GetCacheMisses() const;
|
void GetPhysicalPoint(mfem::ElementTransformation &transformation,
|
||||||
|
const mfem::IntegrationPoint &integration_point,
|
||||||
[[nodiscard]] double GetCacheHitRate() const;
|
mfem::Vector &physical_position);
|
||||||
|
|
||||||
void ResetCacheStats() const;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void InitAllScratchSpaces() const;
|
void ValidateFieldBindings() const;
|
||||||
|
[[nodiscard]] bool InvalidateForChangedSpaces();
|
||||||
|
void LoadElement(int element_id);
|
||||||
|
|
||||||
void ApplyKelvinMapping(
|
const DomainMapper &m_mapper;
|
||||||
const mfem::Vector &x_ref,
|
const mfem::GridFunction &m_displacement;
|
||||||
mfem::Vector &x_phys
|
const mfem::GridFunction &m_compactification_coordinate;
|
||||||
) const;
|
const mfem::FiniteElementSpace *m_displacement_space;
|
||||||
|
const mfem::FiniteElementSpace *m_compactification_space;
|
||||||
|
long m_displacement_space_sequence;
|
||||||
|
long m_compactification_space_sequence;
|
||||||
|
DomainMapper::Workspace m_workspace;
|
||||||
|
|
||||||
void ComputeKelvinJacobian(
|
mfem::Array<int> m_displacement_dofs;
|
||||||
const mfem::Vector &x_ref,
|
mfem::Array<int> m_compactification_dofs;
|
||||||
const mfem::Vector &x_disp,
|
mfem::Vector m_element_displacement;
|
||||||
const mfem::DenseMatrix &J_D,
|
mfem::Vector m_element_compactification;
|
||||||
mfem::DenseMatrix &J
|
std::unique_ptr<ElementDisplacementData> m_displacement_data;
|
||||||
) const;
|
std::unique_ptr<ElementCompactificationData> m_compactification_data;
|
||||||
|
int m_cached_element_id{-1};
|
||||||
void InvalidateCache() const;
|
|
||||||
|
|
||||||
void UpdateElementCache(const mfem::ElementTransformation &T) const;
|
|
||||||
|
|
||||||
private:
|
|
||||||
const mfem::GridFunction *m_d;
|
|
||||||
std::unique_ptr<mfem::GridFunction> m_internal_d;
|
|
||||||
const int m_dim{3};
|
|
||||||
const int m_vacuum_attr{3};
|
|
||||||
const double m_r_star_ref{1.0};
|
|
||||||
const double m_r_inf_ref{2.0};
|
|
||||||
const double m_xi_clamp{0.9999};
|
|
||||||
|
|
||||||
mutable int m_cached_elem_id{-1};
|
|
||||||
mutable int m_cached_elem_type{mfem::ElementTransformation::ELEMENT};
|
|
||||||
mutable const mfem::FiniteElement *m_fe{nullptr};
|
|
||||||
|
|
||||||
mutable mfem::Vector m_elem_dofs;
|
|
||||||
mutable mfem::DenseMatrix m_dof_mat;
|
|
||||||
mutable mfem::DenseMatrix m_dshape;
|
|
||||||
mutable mfem::Vector m_shape;
|
|
||||||
|
|
||||||
mutable size_t m_cache_hits{0};
|
|
||||||
mutable size_t m_cache_misses{0};
|
|
||||||
|
|
||||||
mutable mfem::DenseMatrix m_J_D;
|
|
||||||
mutable mfem::DenseMatrix m_J_temp;
|
|
||||||
mutable mfem::DenseMatrix m_JInv_temp;
|
|
||||||
mutable mfem::Vector m_x_ref;
|
|
||||||
mutable mfem::Vector m_x_disp;
|
|
||||||
mutable mfem::Vector m_d_val;
|
|
||||||
|
|
||||||
bool m_displacement_is_identity{true};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace mean_field::mapping
|
} // namespace mean_field::mapping
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ export import :utils.user;
|
|||||||
export import :utils.domain;
|
export import :utils.domain;
|
||||||
export import :physics.gravity;
|
export import :physics.gravity;
|
||||||
export import :physics.solid_body;
|
export import :physics.solid_body;
|
||||||
export import :physics.barotrope;
|
|
||||||
export import :physics.contexts;
|
|
||||||
export import :boundary.contexts;
|
export import :boundary.contexts;
|
||||||
export import :analysis.integral;
|
export import :analysis.integral;
|
||||||
export import :mapping.domain_mapper;
|
export import :mapping.domain_mapper;
|
||||||
|
|||||||
@@ -74,7 +74,7 @@ export namespace mean_field::operators::context::barotropic {
|
|||||||
public:
|
public:
|
||||||
BarotropicClosureLinearizationContext(
|
BarotropicClosureLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const field::FieldDofMap &densityMap,
|
const field::FieldDofMap &densityMap,
|
||||||
const field::FieldDofMap &enthalpyMap,
|
const field::FieldDofMap &enthalpyMap,
|
||||||
const field::FieldDofMap &displacementMap
|
const field::FieldDofMap &displacementMap
|
||||||
@@ -103,7 +103,7 @@ export namespace mean_field::operators::context::barotropic {
|
|||||||
void VerifyPrepared() const;
|
void VerifyPrepared() const;
|
||||||
|
|
||||||
const fem::FEM &m_f;
|
const fem::FEM &m_f;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
|
|
||||||
int m_densitySize{0};
|
int m_densitySize{0};
|
||||||
int m_enthalpySize{0};
|
int m_enthalpySize{0};
|
||||||
|
|||||||
@@ -49,11 +49,12 @@ export namespace mean_field::operators::context::gravity_field {
|
|||||||
bool reconstructed_operators{false};
|
bool reconstructed_operators{false};
|
||||||
bool rebuilt_mass_operator{false};
|
bool rebuilt_mass_operator{false};
|
||||||
bool rebuilt_source_operator{false};
|
bool rebuilt_source_operator{false};
|
||||||
|
bool rebuilt_divergence_operator{false};
|
||||||
bool refreshed_variation_state{false};
|
bool refreshed_variation_state{false};
|
||||||
|
|
||||||
[[nodiscard]] bool DidAnyWork() const noexcept {
|
[[nodiscard]] bool DidAnyWork() const noexcept {
|
||||||
return reconstructed_operators || rebuilt_mass_operator || rebuilt_source_operator ||
|
return reconstructed_operators || rebuilt_mass_operator || rebuilt_source_operator ||
|
||||||
refreshed_variation_state;
|
rebuilt_divergence_operator || refreshed_variation_state;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -61,7 +62,7 @@ export namespace mean_field::operators::context::gravity_field {
|
|||||||
public:
|
public:
|
||||||
GravityFieldGeometryContext(
|
GravityFieldGeometryContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
const mapping::DomainMapper &domain_mapper
|
||||||
);
|
);
|
||||||
|
|
||||||
GravityFieldGeometryContext(const GravityFieldGeometryContext &) = delete;
|
GravityFieldGeometryContext(const GravityFieldGeometryContext &) = delete;
|
||||||
@@ -77,6 +78,8 @@ export namespace mean_field::operators::context::gravity_field {
|
|||||||
|
|
||||||
[[nodiscard]] const PreparedMappedHDivMassOperator &GetMassOperator() const;
|
[[nodiscard]] const PreparedMappedHDivMassOperator &GetMassOperator() const;
|
||||||
[[nodiscard]] const PreparedMappedGravitySourceOperator &GetSourceOperator() const;
|
[[nodiscard]] const PreparedMappedGravitySourceOperator &GetSourceOperator() const;
|
||||||
|
[[nodiscard]] const mfem::Operator &GetDivergenceOperator() const;
|
||||||
|
[[nodiscard]] const mfem::Operator &GetTransposeDivergenceOperator() const;
|
||||||
[[nodiscard]] const mfem::Vector &GetDisplacementTrue() const;
|
[[nodiscard]] const mfem::Vector &GetDisplacementTrue() const;
|
||||||
[[nodiscard]] const field::FieldDofMap &GetDisplacementMap() const noexcept;
|
[[nodiscard]] const field::FieldDofMap &GetDisplacementMap() const noexcept;
|
||||||
[[nodiscard]] DiscretizationRevision GetDiscretizationRevision() const noexcept;
|
[[nodiscard]] DiscretizationRevision GetDiscretizationRevision() const noexcept;
|
||||||
@@ -85,10 +88,12 @@ export namespace mean_field::operators::context::gravity_field {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
const mapping::DomainMapper &m_domain_mapper;
|
||||||
|
|
||||||
std::unique_ptr<PreparedMappedHDivMassOperator> m_mass_operator;
|
std::unique_ptr<PreparedMappedHDivMassOperator> m_mass_operator;
|
||||||
std::unique_ptr<PreparedMappedGravitySourceOperator> m_source_operator;
|
std::unique_ptr<PreparedMappedGravitySourceOperator> m_source_operator;
|
||||||
|
std::unique_ptr<mfem::ParMixedBilinearForm> m_divergence_operator;
|
||||||
|
std::unique_ptr<mfem::TransposeOperator> m_transpose_divergence_operator;
|
||||||
|
|
||||||
field::FieldDofMap m_displacement_map;
|
field::FieldDofMap m_displacement_map;
|
||||||
mfem::Vector m_displacement_true;
|
mfem::Vector m_displacement_true;
|
||||||
@@ -113,7 +118,7 @@ export namespace mean_field::operators::context::gravity_field {
|
|||||||
public:
|
public:
|
||||||
GravityFieldLinearizationContext(
|
GravityFieldLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
const mapping::DomainMapper &domain_mapper
|
||||||
);
|
);
|
||||||
|
|
||||||
GravityFieldLinearizationContext(const GravityFieldLinearizationContext &) = delete;
|
GravityFieldLinearizationContext(const GravityFieldLinearizationContext &) = delete;
|
||||||
|
|||||||
@@ -96,7 +96,7 @@ export namespace mean_field::operators::context::hydrostatic {
|
|||||||
public:
|
public:
|
||||||
HydrostaticEquilibriumContext(
|
HydrostaticEquilibriumContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper
|
const mapping::DomainMapper &domainMapper
|
||||||
);
|
);
|
||||||
|
|
||||||
HydrostaticEquilibriumContext(const HydrostaticEquilibriumContext &) = delete;
|
HydrostaticEquilibriumContext(const HydrostaticEquilibriumContext &) = delete;
|
||||||
@@ -138,7 +138,7 @@ export namespace mean_field::operators::context::hydrostatic {
|
|||||||
void VerifyPrepared() const;
|
void VerifyPrepared() const;
|
||||||
|
|
||||||
const fem::FEM &m_f;
|
const fem::FEM &m_f;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
|
|
||||||
field::FieldDofMap m_enthalpyMap;
|
field::FieldDofMap m_enthalpyMap;
|
||||||
field::FieldDofMap m_gravityPotentialMap;
|
field::FieldDofMap m_gravityPotentialMap;
|
||||||
|
|||||||
@@ -81,7 +81,7 @@ export namespace mean_field::operators::context::pressure_force {
|
|||||||
public:
|
public:
|
||||||
PressureForceLinearizationContext(
|
PressureForceLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const field::FieldDofMap &enthalpyMap,
|
const field::FieldDofMap &enthalpyMap,
|
||||||
const field::FieldDofMap &displacementMap
|
const field::FieldDofMap &displacementMap
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -78,7 +78,7 @@ export namespace mean_field::operators::context::rotational_displacement_force {
|
|||||||
public:
|
public:
|
||||||
RotationalDisplacementForceLinearizationContext(
|
RotationalDisplacementForceLinearizationContext(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper
|
const mapping::DomainMapper &domainMapper
|
||||||
);
|
);
|
||||||
|
|
||||||
RotationalDisplacementForceLinearizationContext(const RotationalDisplacementForceLinearizationContext &) =
|
RotationalDisplacementForceLinearizationContext(const RotationalDisplacementForceLinearizationContext &) =
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
GravityFieldOperator(
|
GravityFieldOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper,
|
const mapping::DomainMapper &domain_mapper,
|
||||||
context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
||||||
const mfem::Array<int> &state_offsets,
|
const mfem::Array<int> &state_offsets,
|
||||||
GravityFieldJacobianOperator &jacobian
|
GravityFieldJacobianOperator &jacobian
|
||||||
@@ -55,7 +55,7 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
fem::FEM &m_fem;
|
fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
const mapping::DomainMapper &m_domain_mapper;
|
||||||
context::gravity_field::GravityFieldLinearizationContext &m_linearization_context;
|
context::gravity_field::GravityFieldLinearizationContext &m_linearization_context;
|
||||||
mfem::Array<int> m_state_offsets;
|
mfem::Array<int> m_state_offsets;
|
||||||
mfem::Array<int> m_residual_offsets;
|
mfem::Array<int> m_residual_offsets;
|
||||||
@@ -112,4 +112,39 @@ export namespace mean_field::operators {
|
|||||||
context::gravity_field::GravityFieldGeometryContext &m_gravity_field_geometry_context;
|
context::gravity_field::GravityFieldGeometryContext &m_gravity_field_geometry_context;
|
||||||
mfem::Vector m_displacement;
|
mfem::Vector m_displacement;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class ReducedGravityFieldPreconditioner final : public mfem::Solver {
|
||||||
|
public:
|
||||||
|
ReducedGravityFieldPreconditioner(
|
||||||
|
const fem::FEM &f,
|
||||||
|
const context::gravity_field::GravityFieldGeometryContext &geometry_context
|
||||||
|
);
|
||||||
|
|
||||||
|
ReducedGravityFieldPreconditioner(const ReducedGravityFieldPreconditioner &) = delete;
|
||||||
|
ReducedGravityFieldPreconditioner &operator=(const ReducedGravityFieldPreconditioner &) = delete;
|
||||||
|
ReducedGravityFieldPreconditioner(ReducedGravityFieldPreconditioner &&) = delete;
|
||||||
|
ReducedGravityFieldPreconditioner &operator=(ReducedGravityFieldPreconditioner &&) = delete;
|
||||||
|
|
||||||
|
void SetOperator(const mfem::Operator &gravity_operator) override;
|
||||||
|
|
||||||
|
void Mult(
|
||||||
|
const mfem::Vector &right_hand_side,
|
||||||
|
mfem::Vector &action
|
||||||
|
) const override;
|
||||||
|
|
||||||
|
[[nodiscard]] const mfem::Array<int> &GetOffsets() const noexcept;
|
||||||
|
|
||||||
|
private:
|
||||||
|
field::FieldDofMap m_flux_map;
|
||||||
|
field::FieldDofMap m_potential_map;
|
||||||
|
mfem::Array<int> m_offsets;
|
||||||
|
mfem::Array<int> m_empty_tdofs;
|
||||||
|
|
||||||
|
std::unique_ptr<mfem::OperatorJacobiSmoother> m_mass_preconditioner;
|
||||||
|
std::unique_ptr<mfem::HypreParMatrix> m_schur;
|
||||||
|
std::unique_ptr<mfem::HypreBoomerAMG> m_potential_preconditioner;
|
||||||
|
|
||||||
|
mutable mfem::Vector m_potential_rhs_true;
|
||||||
|
mutable mfem::Vector m_potential_action_true;
|
||||||
|
};
|
||||||
} // namespace mean_field::operators
|
} // namespace mean_field::operators
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
GravityFieldJacobianOperator(
|
GravityFieldJacobianOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper,
|
const mapping::DomainMapper &domain_mapper,
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
const context::gravity_field::GravityFieldLinearizationContext &linearization_context,
|
||||||
const mfem::Array<int> &state_offsets,
|
const mfem::Array<int> &state_offsets,
|
||||||
const mfem::Array<int> &residual_offsets
|
const mfem::Array<int> &residual_offsets
|
||||||
@@ -27,7 +27,7 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
fem::FEM &m_fem;
|
fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
const mapping::DomainMapper &m_domain_mapper;
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &m_linearization_context;
|
const context::gravity_field::GravityFieldLinearizationContext &m_linearization_context;
|
||||||
mfem::Array<int> m_state_offsets;
|
mfem::Array<int> m_state_offsets;
|
||||||
mfem::Array<int> m_residual_offsets;
|
mfem::Array<int> m_residual_offsets;
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
*/
|
*/
|
||||||
void apply_barotropic_closure(
|
void apply_barotropic_closure(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const mfem::Vector &densityTrue,
|
const mfem::Vector &densityTrue,
|
||||||
const mfem::Vector &enthalpyTrue,
|
const mfem::Vector &enthalpyTrue,
|
||||||
@@ -32,7 +32,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_barotropic_closure_density_action(
|
void apply_barotropic_closure_density_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -41,7 +41,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_barotropic_closure_enthalpy_action(
|
void apply_barotropic_closure_enthalpy_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
const mfem::Vector &enthalpyVariationTrue,
|
const mfem::Vector &enthalpyVariationTrue,
|
||||||
@@ -51,7 +51,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_barotropic_closure_displacement_action(
|
void apply_barotropic_closure_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export import :mapping.domain_mapper;
|
|||||||
export namespace mean_field::operators::kernels {
|
export namespace mean_field::operators::kernels {
|
||||||
void apply_gravity_displacement_force_residual(
|
void apply_gravity_displacement_force_residual(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &densityTrue,
|
const mfem::Vector &densityTrue,
|
||||||
const mfem::Vector &gravityGradientTrue,
|
const mfem::Vector &gravityGradientTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -19,7 +19,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_gravity_displacement_force_density_action(
|
void apply_gravity_displacement_force_density_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &baseGravityGradientTrue,
|
const mfem::Vector &baseGravityGradientTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -28,7 +28,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_gravity_displacement_force_gradient_action(
|
void apply_gravity_displacement_force_gradient_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &gravityGradientVariationTrue,
|
const mfem::Vector &gravityGradientVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -37,7 +37,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_gravity_displacement_force_displacement_action(
|
void apply_gravity_displacement_force_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &baseGravityGradientTrue,
|
const mfem::Vector &baseGravityGradientTrue,
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
@@ -47,7 +47,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_gravity_displacement_force_complete_action(
|
void apply_gravity_displacement_force_complete_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &baseGravityGradientTrue,
|
const mfem::Vector &baseGravityGradientTrue,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_mapped_hdiv_mass(
|
void apply_mapped_hdiv_mass(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper,
|
const mapping::DomainMapper &domain_mapper,
|
||||||
const mfem::Vector &gravity_gradient_true,
|
const mfem::Vector &gravity_gradient_true,
|
||||||
const mfem::Vector &displacement_true,
|
const mfem::Vector &displacement_true,
|
||||||
mfem::Vector &action
|
mfem::Vector &action
|
||||||
@@ -23,7 +23,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_mapped_source(
|
void apply_mapped_source(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper,
|
const mapping::DomainMapper &domain_mapper,
|
||||||
const mfem::Vector &density_true,
|
const mfem::Vector &density_true,
|
||||||
const mfem::Vector &displacement_true,
|
const mfem::Vector &displacement_true,
|
||||||
mfem::Vector &action
|
mfem::Vector &action
|
||||||
@@ -31,7 +31,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_mapped_hdiv_mass_variation(
|
void apply_mapped_hdiv_mass_variation(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper,
|
const mapping::DomainMapper &domain_mapper,
|
||||||
const mfem::Vector &gravity_gradient_true,
|
const mfem::Vector &gravity_gradient_true,
|
||||||
const mfem::Vector &displacement_true,
|
const mfem::Vector &displacement_true,
|
||||||
const mfem::Vector &displacement_variation_true,
|
const mfem::Vector &displacement_variation_true,
|
||||||
@@ -40,7 +40,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_mapped_source_variation(
|
void apply_mapped_source_variation(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper,
|
const mapping::DomainMapper &domain_mapper,
|
||||||
const mfem::Vector &density_true,
|
const mfem::Vector &density_true,
|
||||||
const mfem::Vector &displacement_true,
|
const mfem::Vector &displacement_true,
|
||||||
const mfem::Vector &displacement_variation_true,
|
const mfem::Vector &displacement_variation_true,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export import :physics.rigid_rotation;
|
|||||||
export namespace mean_field::operators::kernels {
|
export namespace mean_field::operators::kernels {
|
||||||
void apply_hydrostatic_equilibrium(
|
void apply_hydrostatic_equilibrium(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &enthalpyTrue,
|
const mfem::Vector &enthalpyTrue,
|
||||||
const mfem::Vector &potentialTrue,
|
const mfem::Vector &potentialTrue,
|
||||||
@@ -22,7 +22,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_hydrostatic_equilibrium_enthalpy_action(
|
void apply_hydrostatic_equilibrium_enthalpy_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &enthalpyVariationTrue,
|
const mfem::Vector &enthalpyVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
mfem::Vector &action
|
mfem::Vector &action
|
||||||
@@ -30,7 +30,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_hydrostatic_equilibrium_potential_action(
|
void apply_hydrostatic_equilibrium_potential_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &potentialVariationTrue,
|
const mfem::Vector &potentialVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
mfem::Vector &action
|
mfem::Vector &action
|
||||||
@@ -38,7 +38,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_hydrostatic_equilibrium_constant_action(
|
void apply_hydrostatic_equilibrium_constant_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
double constantVariation,
|
double constantVariation,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
mfem::Vector &action
|
mfem::Vector &action
|
||||||
@@ -46,7 +46,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_hydrostatic_equilibrium_displacement_action(
|
void apply_hydrostatic_equilibrium_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
const mfem::Vector &basePotentialTrue,
|
const mfem::Vector &basePotentialTrue,
|
||||||
@@ -58,7 +58,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_hydrostatic_equilibrium_action(
|
void apply_hydrostatic_equilibrium_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
const mfem::Vector &basePotentialTrue,
|
const mfem::Vector &basePotentialTrue,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ export import :eos.polytrope;
|
|||||||
export namespace mean_field::operators::kernels {
|
export namespace mean_field::operators::kernels {
|
||||||
void apply_pressure_force_residual(
|
void apply_pressure_force_residual(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &enthalpyTrue,
|
const mfem::Vector &enthalpyTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -20,7 +20,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_pressure_force_enthalpy_action(
|
void apply_pressure_force_enthalpy_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
const mfem::Vector &enthalpyVariationTrue,
|
const mfem::Vector &enthalpyVariationTrue,
|
||||||
@@ -30,7 +30,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_pressure_force_displacement_action(
|
void apply_pressure_force_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &baseEnthalpyTrue,
|
const mfem::Vector &baseEnthalpyTrue,
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
*/
|
*/
|
||||||
void apply_rotational_displacement_force_residual(
|
void apply_rotational_displacement_force_residual(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &densityTrue,
|
const mfem::Vector &densityTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -34,7 +34,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_rotational_displacement_force_density_action(
|
void apply_rotational_displacement_force_density_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
const mfem::Vector &displacementTrue,
|
const mfem::Vector &displacementTrue,
|
||||||
@@ -43,7 +43,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_rotational_displacement_force_displacement_action(
|
void apply_rotational_displacement_force_displacement_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &displacementVariationTrue,
|
const mfem::Vector &displacementVariationTrue,
|
||||||
@@ -53,7 +53,7 @@ export namespace mean_field::operators::kernels {
|
|||||||
|
|
||||||
void apply_rotational_displacement_force_complete_action(
|
void apply_rotational_displacement_force_complete_action(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const physics::RigidRotation &rotation,
|
const physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &baseDensityTrue,
|
const mfem::Vector &baseDensityTrue,
|
||||||
const mfem::Vector &densityVariationTrue,
|
const mfem::Vector &densityVariationTrue,
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedBarotropicClosureOperator(
|
PreparedBarotropicClosureOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState
|
const eos::Polytrope &equationOfState
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -71,7 +71,7 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedBarotropicClosureOperator(
|
PreparedBarotropicClosureOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
ConstructionData constructionData
|
ConstructionData constructionData
|
||||||
);
|
);
|
||||||
@@ -100,7 +100,7 @@ export namespace mean_field::operators {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
const eos::Polytrope &m_equationOfState;
|
const eos::Polytrope &m_equationOfState;
|
||||||
|
|
||||||
field::FieldDofMap m_densityMap;
|
field::FieldDofMap m_densityMap;
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedDisplacementResidualOperator(
|
PreparedDisplacementResidualOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &barotrope,
|
const eos::Polytrope &barotrope,
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||||
);
|
);
|
||||||
@@ -158,7 +158,7 @@ export namespace mean_field::operators {
|
|||||||
void VerifyPrepared() const;
|
void VerifyPrepared() const;
|
||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &m_gravityContext;
|
const context::gravity_field::GravityFieldLinearizationContext &m_gravityContext;
|
||||||
|
|
||||||
PreparedPressureForceOperator m_pressureOperator;
|
PreparedPressureForceOperator m_pressureOperator;
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedGravityDisplacementForceOperator(
|
PreparedGravityDisplacementForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -107,7 +107,7 @@ export namespace mean_field::operators {
|
|||||||
void VerifyPrepared() const;
|
void VerifyPrepared() const;
|
||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &m_gravityContext;
|
const context::gravity_field::GravityFieldLinearizationContext &m_gravityContext;
|
||||||
|
|
||||||
context::gravity_field::GravityFieldRevisions m_preparedRevisions;
|
context::gravity_field::GravityFieldRevisions m_preparedRevisions;
|
||||||
|
|||||||
@@ -14,7 +14,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedMappedGravitySourceOperator(
|
PreparedMappedGravitySourceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
const mapping::DomainMapper &domain_mapper
|
||||||
);
|
);
|
||||||
|
|
||||||
void Prepare(const mfem::Vector &displacement);
|
void Prepare(const mfem::Vector &displacement);
|
||||||
@@ -55,7 +55,7 @@ export namespace mean_field::operators {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
const mapping::DomainMapper &m_domain_mapper;
|
||||||
|
|
||||||
field::FieldDofMap m_density_map;
|
field::FieldDofMap m_density_map;
|
||||||
field::FieldDofMap m_potential_map;
|
field::FieldDofMap m_potential_map;
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedMappedHDivMassOperator(
|
PreparedMappedHDivMassOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domain_mapper
|
const mapping::DomainMapper &domain_mapper
|
||||||
);
|
);
|
||||||
|
|
||||||
void Prepare(const mfem::Vector &displacement);
|
void Prepare(const mfem::Vector &displacement);
|
||||||
@@ -21,6 +21,8 @@ export namespace mean_field::operators {
|
|||||||
const mfem::Vector &gravity_gradient,
|
const mfem::Vector &gravity_gradient,
|
||||||
mfem::Vector &action
|
mfem::Vector &action
|
||||||
) const override;
|
) const override;
|
||||||
|
void AssembleDiagonal(mfem::Vector &diagonal) const override;
|
||||||
|
void AssembleTrueDiagonal(mfem::Vector &diagonal) const;
|
||||||
|
|
||||||
[[nodiscard]] bool IsPrepared() const noexcept;
|
[[nodiscard]] bool IsPrepared() const noexcept;
|
||||||
[[nodiscard]] std::uint64_t GetPreparationCount() const noexcept;
|
[[nodiscard]] std::uint64_t GetPreparationCount() const noexcept;
|
||||||
@@ -30,7 +32,7 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domain_mapper;
|
const mapping::DomainMapper &m_domain_mapper;
|
||||||
|
|
||||||
field::FieldDofMap m_flux_map;
|
field::FieldDofMap m_flux_map;
|
||||||
field::FieldDofMap m_displacement_map;
|
field::FieldDofMap m_displacement_map;
|
||||||
@@ -40,9 +42,11 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
std::unique_ptr<mfem::MatrixCoefficient> m_stellar_mass_coefficient;
|
std::unique_ptr<mfem::MatrixCoefficient> m_stellar_mass_coefficient;
|
||||||
std::unique_ptr<mfem::MatrixCoefficient> m_vacuum_mass_coefficient;
|
std::unique_ptr<mfem::MatrixCoefficient> m_vacuum_mass_coefficient;
|
||||||
std::unique_ptr<mfem::ParBilinearForm> m_mass_form;
|
std::unique_ptr<mfem::ParBilinearForm> m_stellar_mass_form;
|
||||||
|
std::unique_ptr<mfem::ParBilinearForm> m_vacuum_mass_form;
|
||||||
mutable mfem::Vector m_flux_true;
|
mutable mfem::Vector m_flux_true;
|
||||||
mutable mfem::Vector m_action_true;
|
mutable mfem::Vector m_action_true;
|
||||||
|
mutable mfem::Vector m_domain_action_true;
|
||||||
mfem::Vector m_displacement_true;
|
mfem::Vector m_displacement_true;
|
||||||
std::uint64_t m_preparation_count{0};
|
std::uint64_t m_preparation_count{0};
|
||||||
bool m_is_prepared{false};
|
bool m_is_prepared{false};
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedHydrostaticEquilibriumOperator(
|
PreparedHydrostaticEquilibriumOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper
|
const mapping::DomainMapper &domainMapper
|
||||||
);
|
);
|
||||||
|
|
||||||
PreparedHydrostaticEquilibriumOperator(const PreparedHydrostaticEquilibriumOperator &) = delete;
|
PreparedHydrostaticEquilibriumOperator(const PreparedHydrostaticEquilibriumOperator &) = delete;
|
||||||
@@ -217,7 +217,7 @@ export namespace mean_field::operators {
|
|||||||
void VerifyPrepared() const;
|
void VerifyPrepared() const;
|
||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
|
|
||||||
context::hydrostatic::HydrostaticEquilibriumContext m_context;
|
context::hydrostatic::HydrostaticEquilibriumContext m_context;
|
||||||
|
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedMassNormalizationOperator(
|
PreparedMassNormalizationOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
const context::gravity_field::GravityFieldLinearizationContext &gravityContext
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -148,7 +148,7 @@ export namespace mean_field::operators {
|
|||||||
[[nodiscard]] double GlobalSum(double localValue) const;
|
[[nodiscard]] double GlobalSum(double localValue) const;
|
||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
const context::gravity_field::GravityFieldLinearizationContext &m_gravityContext;
|
const context::gravity_field::GravityFieldLinearizationContext &m_gravityContext;
|
||||||
|
|
||||||
std::vector<ElementPAData> m_elements;
|
std::vector<ElementPAData> m_elements;
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedPressureForceOperator(
|
PreparedPressureForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState
|
const eos::Polytrope &equationOfState
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -155,7 +155,7 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedPressureForceOperator(
|
PreparedPressureForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
ConstructionData constructionData
|
ConstructionData constructionData
|
||||||
);
|
);
|
||||||
@@ -217,7 +217,7 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
|
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
|
|
||||||
const eos::Polytrope &m_equationOfState;
|
const eos::Polytrope &m_equationOfState;
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedRotationalDisplacementForceOperator(
|
PreparedRotationalDisplacementForceOperator(
|
||||||
const fem::FEM &f,
|
const fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper
|
const mapping::DomainMapper &domainMapper
|
||||||
);
|
);
|
||||||
|
|
||||||
PreparedRotationalDisplacementForceOperator(const PreparedRotationalDisplacementForceOperator &) = delete;
|
PreparedRotationalDisplacementForceOperator(const PreparedRotationalDisplacementForceOperator &) = delete;
|
||||||
@@ -105,7 +105,7 @@ export namespace mean_field::operators {
|
|||||||
void VerifyPrepared() const;
|
void VerifyPrepared() const;
|
||||||
|
|
||||||
const fem::FEM &m_fem;
|
const fem::FEM &m_fem;
|
||||||
const mapping::DomainMapperStateless &m_domainMapper;
|
const mapping::DomainMapper &m_domainMapper;
|
||||||
|
|
||||||
context::rotational_displacement_force::RotationalDisplacementForceLinearizationContext m_context;
|
context::rotational_displacement_force::RotationalDisplacementForceLinearizationContext m_context;
|
||||||
|
|
||||||
|
|||||||
@@ -76,14 +76,14 @@ export namespace mean_field::operators {
|
|||||||
public:
|
public:
|
||||||
PreparedStellarEquilibriumOperator(
|
PreparedStellarEquilibriumOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
double targetMass
|
double targetMass
|
||||||
);
|
);
|
||||||
|
|
||||||
PreparedStellarEquilibriumOperator(
|
PreparedStellarEquilibriumOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
const models::StellarModel &stellarModel
|
const models::StellarModel &stellarModel
|
||||||
);
|
);
|
||||||
@@ -130,7 +130,7 @@ export namespace mean_field::operators {
|
|||||||
|
|
||||||
PreparedStellarEquilibriumOperator(
|
PreparedStellarEquilibriumOperator(
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const mapping::DomainMapperStateless &domainMapper,
|
const mapping::DomainMapper &domainMapper,
|
||||||
const eos::Polytrope &equationOfState,
|
const eos::Polytrope &equationOfState,
|
||||||
double targetMass,
|
double targetMass,
|
||||||
ConstructionData constructionData
|
ConstructionData constructionData
|
||||||
|
|||||||
@@ -1,162 +0,0 @@
|
|||||||
module;
|
|
||||||
|
|
||||||
#include <cmath>
|
|
||||||
#include <format>
|
|
||||||
#include <stdexcept>
|
|
||||||
|
|
||||||
export module mean_field:physics.barotrope;
|
|
||||||
|
|
||||||
export namespace mean_field::physics {
|
|
||||||
class PolytropicBarotrope final {
|
|
||||||
public:
|
|
||||||
PolytropicBarotrope(
|
|
||||||
const double polytropic_index,
|
|
||||||
const double polytropic_constant
|
|
||||||
)
|
|
||||||
: m_polytropic_index(polytropic_index),
|
|
||||||
m_polytropic_constant(polytropic_constant),
|
|
||||||
m_enthalpy_scale((polytropic_index + 1.0) * polytropic_constant) {
|
|
||||||
if (!std::isfinite(polytropic_index) || polytropic_index < 1.0) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
std::format(
|
|
||||||
"The differentiable polytropic closure requires a "
|
|
||||||
"finite polytropic index greater than or equal to one. "
|
|
||||||
"Instead a value of {} has been provided",
|
|
||||||
polytropic_index
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!std::isfinite(polytropic_constant) || polytropic_constant <= 0.0) {
|
|
||||||
throw std::invalid_argument(
|
|
||||||
std::format(
|
|
||||||
"The polytropic constant must be finite and positive. "
|
|
||||||
"Instead a value of {} has been provided",
|
|
||||||
polytropic_constant
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
[[nodiscard]] double polytropic_index() const noexcept {
|
|
||||||
return m_polytropic_index;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double polytropic_constant() const noexcept {
|
|
||||||
return m_polytropic_constant;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double enthalpy_scale() const noexcept {
|
|
||||||
return m_enthalpy_scale;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double pressure_from_density(const double density) const {
|
|
||||||
validate_nonnegativity(density, "density");
|
|
||||||
if (density == 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_polytropic_constant * std::pow(density, 1.0 + 1.0 / m_polytropic_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double enthalpy_from_density(const double density) const {
|
|
||||||
validate_nonnegativity(density, "density");
|
|
||||||
if (density == 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_enthalpy_scale * std::pow(density, 1.0 / m_polytropic_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double density_from_enthalpy(const double enthalpy) const {
|
|
||||||
validate_finite(enthalpy, "enthalpy");
|
|
||||||
|
|
||||||
if (enthalpy <= 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return std::pow(enthalpy / m_enthalpy_scale, m_polytropic_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double pressure_from_enthalpy(const double enthalpy) const {
|
|
||||||
validate_finite(enthalpy, "enthalpy");
|
|
||||||
|
|
||||||
if (enthalpy <= 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return density_from_enthalpy(enthalpy) * enthalpy / (m_polytropic_index + 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double density_derivative_from_enthalpy(const double enthalpy) const {
|
|
||||||
validate_finite(enthalpy, "enthalpy");
|
|
||||||
if (enthalpy < 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (enthalpy == 0.0) {
|
|
||||||
return m_polytropic_index == 1.0 ? 1.0 / m_enthalpy_scale : 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_polytropic_index / m_enthalpy_scale *
|
|
||||||
std::pow(enthalpy / m_enthalpy_scale, m_polytropic_index - 1.0);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double pressure_derivative_from_enthalpy(const double enthalpy) const {
|
|
||||||
validate_finite(enthalpy, "enthalpy");
|
|
||||||
|
|
||||||
if (enthalpy <= 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return density_from_enthalpy(enthalpy);
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] double pressure_derivative_from_density(const double density) const {
|
|
||||||
validate_nonnegativity(density, "density");
|
|
||||||
if (density == 0.0) {
|
|
||||||
return 0.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return m_polytropic_constant * (1.0 + 1.0 / m_polytropic_index) *
|
|
||||||
std::pow(density, 1.0 / m_polytropic_index);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
static void validate_finite(
|
|
||||||
const double value,
|
|
||||||
const char *quantity
|
|
||||||
) {
|
|
||||||
if (!std::isfinite(value)) {
|
|
||||||
throw std::domain_error(
|
|
||||||
std::format(
|
|
||||||
"The {} must be finite. Instead a value of {} has been "
|
|
||||||
"provided",
|
|
||||||
quantity, value
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void validate_nonnegativity(
|
|
||||||
const double value,
|
|
||||||
const char *quantity
|
|
||||||
) {
|
|
||||||
validate_finite(value, quantity);
|
|
||||||
if (value < 0.0) {
|
|
||||||
throw std::domain_error(
|
|
||||||
std::format(
|
|
||||||
"The {} must be non-negative. Instead a value of {} "
|
|
||||||
"has been "
|
|
||||||
"provided",
|
|
||||||
quantity, value
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
double m_polytropic_index;
|
|
||||||
double m_polytropic_constant;
|
|
||||||
double m_enthalpy_scale;
|
|
||||||
};
|
|
||||||
} // namespace mean_field::physics
|
|
||||||
@@ -1,29 +0,0 @@
|
|||||||
module;
|
|
||||||
#include <memory>
|
|
||||||
#include <mfem.hpp>
|
|
||||||
|
|
||||||
export module mean_field:physics.contexts;
|
|
||||||
export import :mapping.coefficients;
|
|
||||||
|
|
||||||
export namespace mean_field::physics {
|
|
||||||
struct GravityContext {
|
|
||||||
std::unique_ptr<mfem::ParBilinearForm> m_form;
|
|
||||||
std::unique_ptr<mfem::ParMixedBilinearForm> b_form;
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::BlockOperator> block_A;
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::Solver> prec_M;
|
|
||||||
std::unique_ptr<mfem::HypreBoomerAMG> prec_Phi;
|
|
||||||
std::unique_ptr<mfem::BlockDiagonalPreconditioner> block_prec;
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::MINRESSolver> minres;
|
|
||||||
|
|
||||||
mfem::Array<int> stellar_mask;
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::TransposeOperator> BT;
|
|
||||||
std::unique_ptr<mfem::HypreParMatrix> Schur;
|
|
||||||
|
|
||||||
std::unique_ptr<mfem::MatrixCoefficient> mapped_hdiv_mass_coeff;
|
|
||||||
std::unique_ptr<mfem::Operator> source_form;
|
|
||||||
};
|
|
||||||
} // namespace mean_field::physics
|
|
||||||
@@ -16,27 +16,13 @@ export namespace mean_field::physics {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
GravitySolution grav_potential(
|
GravitySolution solve_gravity_field(
|
||||||
fem::FEM &f,
|
|
||||||
const utils::Args &args,
|
|
||||||
const mfem::GridFunction &rho,
|
|
||||||
bool phi_warm = false
|
|
||||||
);
|
|
||||||
|
|
||||||
GravitySolution grav_potential_new(
|
|
||||||
fem::FEM &f,
|
fem::FEM &f,
|
||||||
const utils::Args &args,
|
const utils::Args &args,
|
||||||
const mfem::GridFunction &rho,
|
const mfem::GridFunction &rho,
|
||||||
const mfem::GridFunction &displacement
|
const mfem::GridFunction &displacement
|
||||||
);
|
);
|
||||||
|
|
||||||
mfem::GridFunction get_potential(
|
|
||||||
fem::FEM &fem,
|
|
||||||
const utils::Args &args,
|
|
||||||
const mfem::GridFunction &rho,
|
|
||||||
bool warm = false
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::DenseMatrix compute_quadrupole_moment_tensor(
|
mfem::DenseMatrix compute_quadrupole_moment_tensor(
|
||||||
const fem::FEM &fem,
|
const fem::FEM &fem,
|
||||||
const mfem::GridFunction &rho,
|
const mfem::GridFunction &rho,
|
||||||
@@ -49,5 +35,4 @@ export namespace mean_field::physics {
|
|||||||
const mfem::Vector &phys_x
|
const mfem::Vector &phys_x
|
||||||
);
|
);
|
||||||
|
|
||||||
void update_stiffness_matrix(fem::FEM &fem);
|
|
||||||
} // namespace mean_field::physics
|
} // namespace mean_field::physics
|
||||||
|
|||||||
@@ -45,7 +45,8 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
template <typename T> constexpr bool is_domain_set_v = false;
|
template <typename T> constexpr bool is_domain_set_v = false;
|
||||||
|
|
||||||
template <IsDomain... DomainTs> constexpr bool is_domain_set_v<DomainSet<DomainTs...>> = true;
|
template <IsDomain... DomainTs>
|
||||||
|
constexpr bool is_domain_set_v<DomainSet<DomainTs...>> = true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsDomainSet = is_domain_set_v<T>;
|
concept IsDomainSet = is_domain_set_v<T>;
|
||||||
@@ -58,7 +59,8 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
struct DomainRelation {};
|
struct DomainRelation {};
|
||||||
|
|
||||||
template <IsDomainOrSet A, IsDomainOrSet B> struct Inscribed final : public DomainRelation {
|
template <IsDomainOrSet A, IsDomainOrSet B>
|
||||||
|
struct Inscribed final : public DomainRelation {
|
||||||
using inner_type = A;
|
using inner_type = A;
|
||||||
using outer_type = B;
|
using outer_type = B;
|
||||||
|
|
||||||
@@ -88,14 +90,16 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
template <typename T> constexpr bool is_material_v = false;
|
template <typename T> constexpr bool is_material_v = false;
|
||||||
|
|
||||||
template <IsDomain D, int Id> constexpr bool is_material_v<Material<D, Id>> = true;
|
template <IsDomain D, int Id>
|
||||||
|
constexpr bool is_material_v<Material<D, Id>> = true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsMaterial = is_material_v<T>;
|
concept IsMaterial = is_material_v<T>;
|
||||||
|
|
||||||
template <typename T> constexpr bool is_boundary_attr_v = false;
|
template <typename T> constexpr bool is_boundary_attr_v = false;
|
||||||
|
|
||||||
template <IsBoundary B, int Id> constexpr bool is_boundary_attr_v<BoundaryAttribute<B, Id>> = true;
|
template <IsBoundary B, int Id>
|
||||||
|
constexpr bool is_boundary_attr_v<BoundaryAttribute<B, Id>> = true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsBoundaryAttr = is_boundary_attr_v<T>;
|
concept IsBoundaryAttr = is_boundary_attr_v<T>;
|
||||||
@@ -113,10 +117,13 @@ export namespace mean_field::utils::domain {
|
|||||||
template <IsMaterial... MaterialTs>
|
template <IsMaterial... MaterialTs>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
consteval bool material_ids_are_unique() noexcept {
|
consteval bool material_ids_are_unique() noexcept {
|
||||||
constexpr std::array<int, sizeof...(MaterialTs)> materialIds{MaterialTs::id...};
|
constexpr std::array<int, sizeof...(MaterialTs)> materialIds{
|
||||||
|
MaterialTs::id...};
|
||||||
|
|
||||||
for (std::size_t firstIndex = 0; firstIndex < materialIds.size(); ++firstIndex) {
|
for (std::size_t firstIndex = 0; firstIndex < materialIds.size();
|
||||||
for (std::size_t secondIndex = firstIndex + 1; secondIndex < materialIds.size(); ++secondIndex) {
|
++firstIndex) {
|
||||||
|
for (std::size_t secondIndex = firstIndex + 1;
|
||||||
|
secondIndex < materialIds.size(); ++secondIndex) {
|
||||||
if (materialIds[firstIndex] == materialIds[secondIndex]) {
|
if (materialIds[firstIndex] == materialIds[secondIndex]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -129,10 +136,13 @@ export namespace mean_field::utils::domain {
|
|||||||
template <IsBoundaryAttr... BoundaryTs>
|
template <IsBoundaryAttr... BoundaryTs>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
consteval bool boundary_ids_are_unique() noexcept {
|
consteval bool boundary_ids_are_unique() noexcept {
|
||||||
constexpr std::array<int, sizeof...(BoundaryTs)> boundaryIds{BoundaryTs::id...};
|
constexpr std::array<int, sizeof...(BoundaryTs)> boundaryIds{
|
||||||
|
BoundaryTs::id...};
|
||||||
|
|
||||||
for (std::size_t firstIndex = 0; firstIndex < boundaryIds.size(); ++firstIndex) {
|
for (std::size_t firstIndex = 0; firstIndex < boundaryIds.size();
|
||||||
for (std::size_t secondIndex = firstIndex + 1; secondIndex < boundaryIds.size(); ++secondIndex) {
|
++firstIndex) {
|
||||||
|
for (std::size_t secondIndex = firstIndex + 1;
|
||||||
|
secondIndex < boundaryIds.size(); ++secondIndex) {
|
||||||
if (boundaryIds[firstIndex] == boundaryIds[secondIndex]) {
|
if (boundaryIds[firstIndex] == boundaryIds[secondIndex]) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -146,12 +156,14 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
template <> struct MaterialDomainsAreUnique<> : std::true_type {};
|
template <> struct MaterialDomainsAreUnique<> : std::true_type {};
|
||||||
|
|
||||||
template <typename MaterialT> struct MaterialDomainsAreUnique<MaterialT> : std::true_type { };
|
template <typename MaterialT>
|
||||||
|
struct MaterialDomainsAreUnique<MaterialT> : std::true_type {};
|
||||||
|
|
||||||
template <typename FirstMaterialT, typename... RemainingMaterialTs>
|
template <typename FirstMaterialT, typename... RemainingMaterialTs>
|
||||||
struct MaterialDomainsAreUnique<FirstMaterialT, RemainingMaterialTs...>
|
struct MaterialDomainsAreUnique<FirstMaterialT, RemainingMaterialTs...>
|
||||||
: std::bool_constant<
|
: std::bool_constant<
|
||||||
(!std::is_same_v<typename FirstMaterialT::domain_type, typename RemainingMaterialTs::domain_type> &&
|
(!std::is_same_v<typename FirstMaterialT::domain_type,
|
||||||
|
typename RemainingMaterialTs::domain_type> &&
|
||||||
...) &&
|
...) &&
|
||||||
MaterialDomainsAreUnique<RemainingMaterialTs...>::value> {};
|
MaterialDomainsAreUnique<RemainingMaterialTs...>::value> {};
|
||||||
|
|
||||||
@@ -159,12 +171,14 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
template <> struct BoundaryTypesAreUnique<> : std::true_type {};
|
template <> struct BoundaryTypesAreUnique<> : std::true_type {};
|
||||||
|
|
||||||
template <typename BoundaryT> struct BoundaryTypesAreUnique<BoundaryT> : std::true_type { };
|
template <typename BoundaryT>
|
||||||
|
struct BoundaryTypesAreUnique<BoundaryT> : std::true_type {};
|
||||||
|
|
||||||
template <typename FirstBoundaryT, typename... RemainingBoundaryTs>
|
template <typename FirstBoundaryT, typename... RemainingBoundaryTs>
|
||||||
struct BoundaryTypesAreUnique<FirstBoundaryT, RemainingBoundaryTs...>
|
struct BoundaryTypesAreUnique<FirstBoundaryT, RemainingBoundaryTs...>
|
||||||
: std::bool_constant<
|
: std::bool_constant<
|
||||||
(!std::is_same_v<typename FirstBoundaryT::boundary_type, typename RemainingBoundaryTs::boundary_type> &&
|
(!std::is_same_v<typename FirstBoundaryT::boundary_type,
|
||||||
|
typename RemainingBoundaryTs::boundary_type> &&
|
||||||
...) &&
|
...) &&
|
||||||
BoundaryTypesAreUnique<RemainingBoundaryTs...>::value> {};
|
BoundaryTypesAreUnique<RemainingBoundaryTs...>::value> {};
|
||||||
|
|
||||||
@@ -172,7 +186,8 @@ export namespace mean_field::utils::domain {
|
|||||||
concept HaveUniqueMaterialIds = material_ids_are_unique<MaterialTs...>();
|
concept HaveUniqueMaterialIds = material_ids_are_unique<MaterialTs...>();
|
||||||
|
|
||||||
template <typename... MaterialTs>
|
template <typename... MaterialTs>
|
||||||
concept HaveUniqueMaterialDomains = MaterialDomainsAreUnique<MaterialTs...>::value;
|
concept HaveUniqueMaterialDomains =
|
||||||
|
MaterialDomainsAreUnique<MaterialTs...>::value;
|
||||||
|
|
||||||
template <typename... BoundaryTs>
|
template <typename... BoundaryTs>
|
||||||
concept HaveUniqueBoundaryIds = boundary_ids_are_unique<BoundaryTs...>();
|
concept HaveUniqueBoundaryIds = boundary_ids_are_unique<BoundaryTs...>();
|
||||||
@@ -181,79 +196,104 @@ export namespace mean_field::utils::domain {
|
|||||||
concept HaveUniqueBoundaryTypes = BoundaryTypesAreUnique<BoundaryTs...>::value;
|
concept HaveUniqueBoundaryTypes = BoundaryTypesAreUnique<BoundaryTs...>::value;
|
||||||
|
|
||||||
template <IsMaterial... MaterialTs>
|
template <IsMaterial... MaterialTs>
|
||||||
requires(HaveUniqueMaterialIds<MaterialTs...> && HaveUniqueMaterialDomains<MaterialTs...>)
|
requires(HaveUniqueMaterialIds<MaterialTs...> &&
|
||||||
|
HaveUniqueMaterialDomains<MaterialTs...>)
|
||||||
struct MaterialList {
|
struct MaterialList {
|
||||||
static constexpr std::size_t count = sizeof...(MaterialTs);
|
static constexpr std::size_t count = sizeof...(MaterialTs);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr std::array<
|
static constexpr std::array<MaterialDescriptor, count>
|
||||||
MaterialDescriptor,
|
descriptors() noexcept {
|
||||||
count> descriptors() noexcept {
|
return {MaterialDescriptor{.name = MaterialTs::domain_type::name,
|
||||||
return {MaterialDescriptor{.name = MaterialTs::domain_type::name, .id = MaterialTs::id}...};
|
.id = MaterialTs::id}...};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <IsBoundaryAttr... BoundaryTs>
|
template <IsBoundaryAttr... BoundaryTs>
|
||||||
requires(HaveUniqueBoundaryIds<BoundaryTs...> && HaveUniqueBoundaryTypes<BoundaryTs...>)
|
requires(HaveUniqueBoundaryIds<BoundaryTs...> &&
|
||||||
|
HaveUniqueBoundaryTypes<BoundaryTs...>)
|
||||||
struct BoundaryList {
|
struct BoundaryList {
|
||||||
static constexpr std::size_t count = sizeof...(BoundaryTs);
|
static constexpr std::size_t count = sizeof...(BoundaryTs);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr std::array<
|
static constexpr std::array<BoundaryDescriptor, count>
|
||||||
BoundaryDescriptor,
|
descriptors() noexcept {
|
||||||
count> descriptors() noexcept {
|
return {BoundaryDescriptor{.name = BoundaryTs::boundary_type::name,
|
||||||
return {BoundaryDescriptor{.name = BoundaryTs::boundary_type::name, .id = BoundaryTs::id}...};
|
.id = BoundaryTs::id}...};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename DomainT, typename MaterialListT> struct DomainMaterialResolver;
|
template <typename DomainT, typename MaterialListT>
|
||||||
|
struct DomainMaterialResolver;
|
||||||
|
|
||||||
template <IsDomain DomainT, IsMaterial... MaterialTs>
|
template <IsDomain DomainT, IsMaterial... MaterialTs>
|
||||||
struct DomainMaterialResolver<DomainT, MaterialList<MaterialTs...>> {
|
struct DomainMaterialResolver<DomainT, MaterialList<MaterialTs...>> {
|
||||||
static constexpr bool registered = (std::is_same_v<DomainT, typename MaterialTs::domain_type> || ...);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static constexpr bool contains_attribute(int materialId) noexcept {
|
|
||||||
return ((std::is_same_v<DomainT, typename MaterialTs::domain_type> && MaterialTs::id == materialId) || ...);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <IsDomain... DomainTs, IsMaterial... MaterialTs>
|
|
||||||
struct DomainMaterialResolver<DomainSet<DomainTs...>, MaterialList<MaterialTs...>> {
|
|
||||||
static constexpr bool registered =
|
static constexpr bool registered =
|
||||||
(DomainMaterialResolver<DomainTs, MaterialList<MaterialTs...>>::registered && ...);
|
(std::is_same_v<DomainT, typename MaterialTs::domain_type> || ...);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr bool contains_attribute(int materialId) noexcept {
|
static constexpr bool contains_attribute(int materialId) noexcept {
|
||||||
return (
|
return ((std::is_same_v<DomainT, typename MaterialTs::domain_type> &&
|
||||||
DomainMaterialResolver<DomainTs, MaterialList<MaterialTs...>>::contains_attribute(materialId) || ...
|
MaterialTs::id == materialId) ||
|
||||||
);
|
...);
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename BoundaryT, typename BoundaryListT> struct BoundaryAttributeResolver;
|
|
||||||
|
|
||||||
template <IsBoundary BoundaryT, IsBoundaryAttr... BoundaryTs>
|
|
||||||
struct BoundaryAttributeResolver<BoundaryT, BoundaryList<BoundaryTs...>> {
|
|
||||||
static constexpr bool registered = (std::is_same_v<BoundaryT, typename BoundaryTs::boundary_type> || ...);
|
|
||||||
|
|
||||||
[[nodiscard]]
|
|
||||||
static constexpr bool matches_attribute(int boundaryId) noexcept {
|
|
||||||
return (
|
|
||||||
(std::is_same_v<BoundaryT, typename BoundaryTs::boundary_type> && BoundaryTs::id == boundaryId) || ...
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static consteval int attribute() {
|
static consteval int attribute() {
|
||||||
static_assert(
|
static_assert(registered,
|
||||||
registered, "Requested boundary is not registered "
|
"Requested domain is not registered in this schema.");
|
||||||
"in this schema."
|
|
||||||
);
|
int result = 0;
|
||||||
|
((std::is_same_v<DomainT, typename MaterialTs::domain_type>
|
||||||
|
? result = MaterialTs::id
|
||||||
|
: result),
|
||||||
|
...);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <IsDomain... DomainTs, IsMaterial... MaterialTs>
|
||||||
|
struct DomainMaterialResolver<DomainSet<DomainTs...>,
|
||||||
|
MaterialList<MaterialTs...>> {
|
||||||
|
static constexpr bool registered =
|
||||||
|
(DomainMaterialResolver<DomainTs,
|
||||||
|
MaterialList<MaterialTs...>>::registered &&
|
||||||
|
...);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static constexpr bool contains_attribute(int materialId) noexcept {
|
||||||
|
return (DomainMaterialResolver<DomainTs, MaterialList<MaterialTs...>>::
|
||||||
|
contains_attribute(materialId) ||
|
||||||
|
...);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
template <typename BoundaryT, typename BoundaryListT>
|
||||||
|
struct BoundaryAttributeResolver;
|
||||||
|
|
||||||
|
template <IsBoundary BoundaryT, IsBoundaryAttr... BoundaryTs>
|
||||||
|
struct BoundaryAttributeResolver<BoundaryT, BoundaryList<BoundaryTs...>> {
|
||||||
|
static constexpr bool registered =
|
||||||
|
(std::is_same_v<BoundaryT, typename BoundaryTs::boundary_type> || ...);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static constexpr bool matches_attribute(int boundaryId) noexcept {
|
||||||
|
return ((std::is_same_v<BoundaryT, typename BoundaryTs::boundary_type> &&
|
||||||
|
BoundaryTs::id == boundaryId) ||
|
||||||
|
...);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
static consteval int attribute() {
|
||||||
|
static_assert(registered, "Requested boundary is not registered "
|
||||||
|
"in this schema.");
|
||||||
|
|
||||||
int result = 0;
|
int result = 0;
|
||||||
|
|
||||||
((std::is_same_v<BoundaryT, typename BoundaryTs::boundary_type> ? result = BoundaryTs::id : result), ...);
|
((std::is_same_v<BoundaryT, typename BoundaryTs::boundary_type>
|
||||||
|
? result = BoundaryTs::id
|
||||||
|
: result),
|
||||||
|
...);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -261,14 +301,16 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
template <typename T> constexpr bool is_material_list_v = false;
|
template <typename T> constexpr bool is_material_list_v = false;
|
||||||
|
|
||||||
template <IsMaterial... MaterialTs> constexpr bool is_material_list_v<MaterialList<MaterialTs...>> = true;
|
template <IsMaterial... MaterialTs>
|
||||||
|
constexpr bool is_material_list_v<MaterialList<MaterialTs...>> = true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsMaterialList = is_material_list_v<T>;
|
concept IsMaterialList = is_material_list_v<T>;
|
||||||
|
|
||||||
template <typename T> constexpr bool is_boundary_list_v = false;
|
template <typename T> constexpr bool is_boundary_list_v = false;
|
||||||
|
|
||||||
template <IsBoundaryAttr... BoundaryTs> constexpr bool is_boundary_list_v<BoundaryList<BoundaryTs...>> = true;
|
template <IsBoundaryAttr... BoundaryTs>
|
||||||
|
constexpr bool is_boundary_list_v<BoundaryList<BoundaryTs...>> = true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsBoundaryList = is_boundary_list_v<T>;
|
concept IsBoundaryList = is_boundary_list_v<T>;
|
||||||
@@ -295,7 +337,8 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
template <typename T> constexpr bool is_relation_list_v = false;
|
template <typename T> constexpr bool is_relation_list_v = false;
|
||||||
|
|
||||||
template <IsRelation... RelationTs> constexpr bool is_relation_list_v<RelationList<RelationTs...>> = true;
|
template <IsRelation... RelationTs>
|
||||||
|
constexpr bool is_relation_list_v<RelationList<RelationTs...>> = true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsRelationList = is_relation_list_v<T>;
|
concept IsRelationList = is_relation_list_v<T>;
|
||||||
@@ -308,36 +351,51 @@ export namespace mean_field::utils::domain {
|
|||||||
* DomainBoundary references both a boundary and one or
|
* DomainBoundary references both a boundary and one or
|
||||||
* two domains.
|
* two domains.
|
||||||
*/
|
*/
|
||||||
template <IsRelation RelationT, IsMaterialList MaterialsT, IsBoundaryList BoundariesT>
|
template <IsRelation RelationT, IsMaterialList MaterialsT,
|
||||||
|
IsBoundaryList BoundariesT>
|
||||||
struct RelationUsesRegisteredEntities;
|
struct RelationUsesRegisteredEntities;
|
||||||
|
|
||||||
template <IsDomainOrSet DomainT, IsMaterialList MaterialsT, IsBoundaryList BoundariesT>
|
template <IsDomainOrSet DomainT, IsMaterialList MaterialsT,
|
||||||
struct RelationUsesRegisteredEntities<Connected<DomainT>, MaterialsT, BoundariesT>
|
IsBoundaryList BoundariesT>
|
||||||
: std::bool_constant<DomainMaterialResolver<DomainT, MaterialsT>::registered> { };
|
struct RelationUsesRegisteredEntities<Connected<DomainT>, MaterialsT,
|
||||||
|
BoundariesT>
|
||||||
|
: std::bool_constant<
|
||||||
|
DomainMaterialResolver<DomainT, MaterialsT>::registered> {};
|
||||||
|
|
||||||
template <IsDomainOrSet InnerT, IsDomainOrSet OuterT, IsMaterialList MaterialsT, IsBoundaryList BoundariesT>
|
template <IsDomainOrSet InnerT, IsDomainOrSet OuterT, IsMaterialList MaterialsT,
|
||||||
struct RelationUsesRegisteredEntities<Inscribed<InnerT, OuterT>, MaterialsT, BoundariesT>
|
IsBoundaryList BoundariesT>
|
||||||
|
struct RelationUsesRegisteredEntities<Inscribed<InnerT, OuterT>, MaterialsT,
|
||||||
|
BoundariesT>
|
||||||
: std::bool_constant<
|
: std::bool_constant<
|
||||||
DomainMaterialResolver<InnerT, MaterialsT>::registered &&
|
DomainMaterialResolver<InnerT, MaterialsT>::registered &&
|
||||||
DomainMaterialResolver<OuterT, MaterialsT>::registered> {};
|
DomainMaterialResolver<OuterT, MaterialsT>::registered> {};
|
||||||
|
|
||||||
template <IsBoundary BoundaryT, IsDomainOrSet... DomainTs, IsMaterialList MaterialsT, IsBoundaryList BoundariesT>
|
template <IsBoundary BoundaryT, IsDomainOrSet... DomainTs,
|
||||||
struct RelationUsesRegisteredEntities<DomainBoundary<BoundaryT, DomainTs...>, MaterialsT, BoundariesT>
|
IsMaterialList MaterialsT, IsBoundaryList BoundariesT>
|
||||||
|
struct RelationUsesRegisteredEntities<DomainBoundary<BoundaryT, DomainTs...>,
|
||||||
|
MaterialsT, BoundariesT>
|
||||||
: std::bool_constant<
|
: std::bool_constant<
|
||||||
BoundaryAttributeResolver<BoundaryT, BoundariesT>::registered &&
|
BoundaryAttributeResolver<BoundaryT, BoundariesT>::registered &&
|
||||||
(DomainMaterialResolver<DomainTs, MaterialsT>::registered && ...)> {};
|
(DomainMaterialResolver<DomainTs, MaterialsT>::registered && ...)> {};
|
||||||
|
|
||||||
template <IsMaterialList MaterialsT, IsBoundaryList BoundariesT, IsRelationList RelationsT>
|
template <IsMaterialList MaterialsT, IsBoundaryList BoundariesT,
|
||||||
|
IsRelationList RelationsT>
|
||||||
struct RelationsUseRegisteredEntities;
|
struct RelationsUseRegisteredEntities;
|
||||||
|
|
||||||
template <IsMaterialList MaterialsT, IsBoundaryList BoundariesT, IsRelation... RelationTs>
|
template <IsMaterialList MaterialsT, IsBoundaryList BoundariesT,
|
||||||
struct RelationsUseRegisteredEntities<MaterialsT, BoundariesT, RelationList<RelationTs...>>
|
IsRelation... RelationTs>
|
||||||
: std::bool_constant<(RelationUsesRegisteredEntities<RelationTs, MaterialsT, BoundariesT>::value && ...)> { };
|
struct RelationsUseRegisteredEntities<MaterialsT, BoundariesT,
|
||||||
|
RelationList<RelationTs...>>
|
||||||
|
: std::bool_constant<(RelationUsesRegisteredEntities<RelationTs, MaterialsT,
|
||||||
|
BoundariesT>::value &&
|
||||||
|
...)> {};
|
||||||
|
|
||||||
template <typename MaterialsT, typename BoundariesT, typename RelationsT>
|
template <typename MaterialsT, typename BoundariesT, typename RelationsT>
|
||||||
concept HaveValidRelationEntities = RelationsUseRegisteredEntities<MaterialsT, BoundariesT, RelationsT>::value;
|
concept HaveValidRelationEntities =
|
||||||
|
RelationsUseRegisteredEntities<MaterialsT, BoundariesT, RelationsT>::value;
|
||||||
|
|
||||||
template <IsMaterialList Materials, IsBoundaryList Boundaries, IsRelationList Relations>
|
template <IsMaterialList Materials, IsBoundaryList Boundaries,
|
||||||
|
IsRelationList Relations>
|
||||||
requires HaveValidRelationEntities<Materials, Boundaries, Relations>
|
requires HaveValidRelationEntities<Materials, Boundaries, Relations>
|
||||||
struct DomainSchema {
|
struct DomainSchema {
|
||||||
using materials_type = Materials;
|
using materials_type = Materials;
|
||||||
@@ -369,12 +427,20 @@ export namespace mean_field::utils::domain {
|
|||||||
template <IsDomainOrSet DomainT>
|
template <IsDomainOrSet DomainT>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr bool attribute_belongs_to(int materialId) noexcept {
|
static constexpr bool attribute_belongs_to(int materialId) noexcept {
|
||||||
static_assert(
|
static_assert(contains_domain<DomainT>(),
|
||||||
contains_domain<DomainT>(), "Requested domain is not completely "
|
"Requested domain is not completely "
|
||||||
"registered in this schema."
|
"registered in this schema.");
|
||||||
);
|
|
||||||
|
|
||||||
return DomainMaterialResolver<DomainT, Materials>::contains_attribute(materialId);
|
return DomainMaterialResolver<DomainT, Materials>::contains_attribute(
|
||||||
|
materialId);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <IsDomain DomainT>
|
||||||
|
[[nodiscard]]
|
||||||
|
static consteval int material_attribute() noexcept {
|
||||||
|
static_assert(contains_domain<DomainT>(),
|
||||||
|
"Requested domain is not registered in this schema.");
|
||||||
|
return DomainMaterialResolver<DomainT, Materials>::attribute();
|
||||||
}
|
}
|
||||||
|
|
||||||
template <IsBoundary BoundaryT>
|
template <IsBoundary BoundaryT>
|
||||||
@@ -392,19 +458,21 @@ export namespace mean_field::utils::domain {
|
|||||||
template <IsBoundary BoundaryT>
|
template <IsBoundary BoundaryT>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static constexpr bool boundary_attribute_matches(int boundaryId) noexcept {
|
static constexpr bool boundary_attribute_matches(int boundaryId) noexcept {
|
||||||
static_assert(
|
static_assert(contains_boundary<BoundaryT>(),
|
||||||
contains_boundary<BoundaryT>(), "Requested boundary is not registered "
|
"Requested boundary is not registered "
|
||||||
"in this schema."
|
"in this schema.");
|
||||||
);
|
|
||||||
|
|
||||||
return BoundaryAttributeResolver<BoundaryT, Boundaries>::matches_attribute(boundaryId);
|
return BoundaryAttributeResolver<BoundaryT, Boundaries>::matches_attribute(
|
||||||
|
boundaryId);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename S> constexpr bool is_schema_v = false;
|
template <typename S> constexpr bool is_schema_v = false;
|
||||||
|
|
||||||
template <IsMaterialList Materials, IsBoundaryList Boundaries, IsRelationList Relations>
|
template <IsMaterialList Materials, IsBoundaryList Boundaries,
|
||||||
constexpr bool is_schema_v<DomainSchema<Materials, Boundaries, Relations>> = true;
|
IsRelationList Relations>
|
||||||
|
constexpr bool is_schema_v<DomainSchema<Materials, Boundaries, Relations>> =
|
||||||
|
true;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept IsSchema = is_schema_v<T>;
|
concept IsSchema = is_schema_v<T>;
|
||||||
@@ -465,7 +533,8 @@ export namespace mean_field::utils::domain {
|
|||||||
std::optional<int> secondMaterialId = std::nullopt;
|
std::optional<int> secondMaterialId = std::nullopt;
|
||||||
};
|
};
|
||||||
|
|
||||||
std::optional<DomainBoundaryDiagnostics> domainBoundaryDiagnostics = std::nullopt;
|
std::optional<DomainBoundaryDiagnostics> domainBoundaryDiagnostics =
|
||||||
|
std::nullopt;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
bool valid() const noexcept {
|
bool valid() const noexcept {
|
||||||
@@ -480,19 +549,18 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
template <IsRelation RelationT> struct RelationValidator;
|
template <IsRelation RelationT> struct RelationValidator;
|
||||||
|
|
||||||
template <IsDomainOrSet InnerT, IsDomainOrSet OuterT> struct RelationValidator<Inscribed<InnerT, OuterT>> {
|
template <IsDomainOrSet InnerT, IsDomainOrSet OuterT>
|
||||||
|
struct RelationValidator<Inscribed<InnerT, OuterT>> {
|
||||||
template <IsSchema SchemaT>
|
template <IsSchema SchemaT>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static RelationValidationResult validate(const mfem::Mesh &mesh) {
|
static RelationValidationResult validate(const mfem::Mesh &mesh) {
|
||||||
static_assert(
|
static_assert(SchemaT::template contains_domain<InnerT>(),
|
||||||
SchemaT::template contains_domain<InnerT>(), "The inner domain of Inscribed is not "
|
"The inner domain of Inscribed is not "
|
||||||
"registered in the supplied schema."
|
"registered in the supplied schema.");
|
||||||
);
|
|
||||||
|
|
||||||
static_assert(
|
static_assert(SchemaT::template contains_domain<OuterT>(),
|
||||||
SchemaT::template contains_domain<OuterT>(), "The outer domain of Inscribed is not "
|
"The outer domain of Inscribed is not "
|
||||||
"registered in the supplied schema."
|
"registered in the supplied schema.");
|
||||||
);
|
|
||||||
|
|
||||||
bool foundInnerElement = false;
|
bool foundInnerElement = false;
|
||||||
bool foundOuterElement = false;
|
bool foundOuterElement = false;
|
||||||
@@ -501,9 +569,13 @@ export namespace mean_field::utils::domain {
|
|||||||
for (int elementId = 0; elementId < mesh.GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < mesh.GetNE(); ++elementId) {
|
||||||
const int materialId = mesh.GetAttribute(elementId);
|
const int materialId = mesh.GetAttribute(elementId);
|
||||||
|
|
||||||
foundInnerElement = foundInnerElement || SchemaT::template attribute_belongs_to<InnerT>(materialId);
|
foundInnerElement =
|
||||||
|
foundInnerElement ||
|
||||||
|
SchemaT::template attribute_belongs_to<InnerT>(materialId);
|
||||||
|
|
||||||
foundOuterElement = foundOuterElement || SchemaT::template attribute_belongs_to<OuterT>(materialId);
|
foundOuterElement =
|
||||||
|
foundOuterElement ||
|
||||||
|
SchemaT::template attribute_belongs_to<OuterT>(materialId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!foundInnerElement) {
|
if (!foundInnerElement) {
|
||||||
@@ -521,12 +593,12 @@ export namespace mean_field::utils::domain {
|
|||||||
mesh.GetFaceElements(faceId, &firstElementId, &secondElementId);
|
mesh.GetFaceElements(faceId, &firstElementId, &secondElementId);
|
||||||
|
|
||||||
const bool firstIsInner =
|
const bool firstIsInner =
|
||||||
firstElementId >= 0 &&
|
firstElementId >= 0 && SchemaT::template attribute_belongs_to<InnerT>(
|
||||||
SchemaT::template attribute_belongs_to<InnerT>(mesh.GetAttribute(firstElementId));
|
mesh.GetAttribute(firstElementId));
|
||||||
|
|
||||||
const bool secondIsInner =
|
const bool secondIsInner = secondElementId >= 0 &&
|
||||||
secondElementId >= 0 &&
|
SchemaT::template attribute_belongs_to<InnerT>(
|
||||||
SchemaT::template attribute_belongs_to<InnerT>(mesh.GetAttribute(secondElementId));
|
mesh.GetAttribute(secondElementId));
|
||||||
|
|
||||||
if (firstIsInner == secondIsInner) {
|
if (firstIsInner == secondIsInner) {
|
||||||
continue;
|
continue;
|
||||||
@@ -534,31 +606,32 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
foundInnerBoundary = true;
|
foundInnerBoundary = true;
|
||||||
|
|
||||||
const int innerElementId = firstIsInner ? firstElementId : secondElementId;
|
const int innerElementId =
|
||||||
|
firstIsInner ? firstElementId : secondElementId;
|
||||||
|
|
||||||
const int adjacentElementId = firstIsInner ? secondElementId : firstElementId;
|
const int adjacentElementId =
|
||||||
|
firstIsInner ? secondElementId : firstElementId;
|
||||||
|
|
||||||
if (adjacentElementId < 0) {
|
if (adjacentElementId < 0) {
|
||||||
return {
|
return {.failure =
|
||||||
.failure = RelationValidationFailure::InnerDomainTouchesMeshBoundary,
|
RelationValidationFailure::InnerDomainTouchesMeshBoundary,
|
||||||
.inscribedDiagnostics = std::make_optional<RelationValidationResult::InscribedDiagnostics>(
|
.inscribedDiagnostics = std::make_optional<
|
||||||
{.faceId = faceId, .innerElementId = innerElementId}
|
RelationValidationResult::InscribedDiagnostics>(
|
||||||
)
|
{.faceId = faceId, .innerElementId = innerElementId})};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const int adjacentMaterialId = mesh.GetAttribute(adjacentElementId);
|
const int adjacentMaterialId = mesh.GetAttribute(adjacentElementId);
|
||||||
|
|
||||||
if (!SchemaT::template attribute_belongs_to<OuterT>(adjacentMaterialId)) {
|
if (!SchemaT::template attribute_belongs_to<OuterT>(adjacentMaterialId)) {
|
||||||
return {
|
return {
|
||||||
.failure = RelationValidationFailure::InnerDomainTouchesUnexpectedMaterial,
|
.failure =
|
||||||
.inscribedDiagnostics = std::make_optional<RelationValidationResult::InscribedDiagnostics>(
|
RelationValidationFailure::InnerDomainTouchesUnexpectedMaterial,
|
||||||
|
.inscribedDiagnostics = std::make_optional<
|
||||||
|
RelationValidationResult::InscribedDiagnostics>(
|
||||||
{.faceId = faceId,
|
{.faceId = faceId,
|
||||||
.innerElementId = innerElementId,
|
.innerElementId = innerElementId,
|
||||||
.adjacentElementId = adjacentElementId,
|
.adjacentElementId = adjacentElementId,
|
||||||
.adjacentMaterialId = adjacentMaterialId}
|
.adjacentMaterialId = adjacentMaterialId})};
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -574,13 +647,13 @@ export namespace mean_field::utils::domain {
|
|||||||
template <IsSchema SchemaT>
|
template <IsSchema SchemaT>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static RelationValidationResult validate(const mfem::Mesh &mesh) {
|
static RelationValidationResult validate(const mfem::Mesh &mesh) {
|
||||||
static_assert(
|
static_assert(SchemaT::template contains_domain<DomainT>(),
|
||||||
SchemaT::template contains_domain<DomainT>(), "Connected refers to a domain which is "
|
"Connected refers to a domain which is "
|
||||||
"not completely registered in the "
|
"not completely registered in the "
|
||||||
"supplied DomainSchema."
|
"supplied DomainSchema.");
|
||||||
);
|
|
||||||
|
|
||||||
std::vector<bool> belongsToDomain(static_cast<std::size_t>(mesh.GetNE()), false);
|
std::vector<bool> belongsToDomain(static_cast<std::size_t>(mesh.GetNE()),
|
||||||
|
false);
|
||||||
|
|
||||||
int domainElementCount = 0;
|
int domainElementCount = 0;
|
||||||
int firstDomainElement = -1;
|
int firstDomainElement = -1;
|
||||||
@@ -588,7 +661,8 @@ export namespace mean_field::utils::domain {
|
|||||||
for (int elementId = 0; elementId < mesh.GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < mesh.GetNE(); ++elementId) {
|
||||||
const int materialId = mesh.GetAttribute(elementId);
|
const int materialId = mesh.GetAttribute(elementId);
|
||||||
|
|
||||||
const bool belongs = SchemaT::template attribute_belongs_to<DomainT>(materialId);
|
const bool belongs =
|
||||||
|
SchemaT::template attribute_belongs_to<DomainT>(materialId);
|
||||||
|
|
||||||
belongsToDomain[static_cast<std::size_t>(elementId)] = belongs;
|
belongsToDomain[static_cast<std::size_t>(elementId)] = belongs;
|
||||||
|
|
||||||
@@ -604,15 +678,14 @@ export namespace mean_field::utils::domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (domainElementCount == 0) {
|
if (domainElementCount == 0) {
|
||||||
return {
|
return {.failure = RelationValidationFailure::DomainAbsent,
|
||||||
.failure = RelationValidationFailure::DomainAbsent,
|
.connectedDiagnostics = std::make_optional<
|
||||||
.connectedDiagnostics = std::make_optional<RelationValidationResult::ConnectedDiagnostics>(
|
RelationValidationResult::ConnectedDiagnostics>(
|
||||||
{.domainElementCount = 0, .visitedElementCount = 0}
|
{.domainElementCount = 0, .visitedElementCount = 0})};
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::vector<int>> adjacency(static_cast<std::size_t>(mesh.GetNE()));
|
std::vector<std::vector<int>> adjacency(
|
||||||
|
static_cast<std::size_t>(mesh.GetNE()));
|
||||||
|
|
||||||
for (int faceId = 0; faceId < mesh.GetNumFaces(); ++faceId) {
|
for (int faceId = 0; faceId < mesh.GetNumFaces(); ++faceId) {
|
||||||
int firstElementId = -1;
|
int firstElementId = -1;
|
||||||
@@ -624,17 +697,21 @@ export namespace mean_field::utils::domain {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool firstBelongs = belongsToDomain[static_cast<std::size_t>(firstElementId)];
|
const bool firstBelongs =
|
||||||
|
belongsToDomain[static_cast<std::size_t>(firstElementId)];
|
||||||
|
|
||||||
const bool secondBelongs = belongsToDomain[static_cast<std::size_t>(secondElementId)];
|
const bool secondBelongs =
|
||||||
|
belongsToDomain[static_cast<std::size_t>(secondElementId)];
|
||||||
|
|
||||||
if (!(firstBelongs && secondBelongs)) {
|
if (!(firstBelongs && secondBelongs)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
adjacency[static_cast<std::size_t>(firstElementId)].push_back(secondElementId);
|
adjacency[static_cast<std::size_t>(firstElementId)].push_back(
|
||||||
|
secondElementId);
|
||||||
|
|
||||||
adjacency[static_cast<std::size_t>(secondElementId)].push_back(firstElementId);
|
adjacency[static_cast<std::size_t>(secondElementId)].push_back(
|
||||||
|
firstElementId);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<bool> visited(static_cast<std::size_t>(mesh.GetNE()), false);
|
std::vector<bool> visited(static_cast<std::size_t>(mesh.GetNE()), false);
|
||||||
@@ -660,7 +737,8 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
++visitedElementCount;
|
++visitedElementCount;
|
||||||
|
|
||||||
for (const int neighborElementId : adjacency[static_cast<std::size_t>(elementId)]) {
|
for (const int neighborElementId :
|
||||||
|
adjacency[static_cast<std::size_t>(elementId)]) {
|
||||||
if (!visited[static_cast<std::size_t>(neighborElementId)]) {
|
if (!visited[static_cast<std::size_t>(neighborElementId)]) {
|
||||||
pending.push_back(neighborElementId);
|
pending.push_back(neighborElementId);
|
||||||
}
|
}
|
||||||
@@ -668,11 +746,10 @@ export namespace mean_field::utils::domain {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (visitedElementCount == domainElementCount) {
|
if (visitedElementCount == domainElementCount) {
|
||||||
return {
|
return {.connectedDiagnostics = std::make_optional<
|
||||||
.connectedDiagnostics = std::make_optional<RelationValidationResult::ConnectedDiagnostics>(
|
RelationValidationResult::ConnectedDiagnostics>(
|
||||||
{.domainElementCount = domainElementCount, .visitedElementCount = visitedElementCount}
|
{.domainElementCount = domainElementCount,
|
||||||
)
|
.visitedElementCount = visitedElementCount})};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int disconnectedElementId = -1;
|
int disconnectedElementId = -1;
|
||||||
@@ -689,12 +766,11 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
.failure = RelationValidationFailure::DomainDisconnected,
|
.failure = RelationValidationFailure::DomainDisconnected,
|
||||||
.connectedDiagnostics = std::make_optional<RelationValidationResult::ConnectedDiagnostics>(
|
.connectedDiagnostics =
|
||||||
|
std::make_optional<RelationValidationResult::ConnectedDiagnostics>(
|
||||||
{.elementId = disconnectedElementId,
|
{.elementId = disconnectedElementId,
|
||||||
.domainElementCount = domainElementCount,
|
.domainElementCount = domainElementCount,
|
||||||
.visitedElementCount = visitedElementCount}
|
.visitedElementCount = visitedElementCount})};
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -703,23 +779,19 @@ export namespace mean_field::utils::domain {
|
|||||||
template <IsSchema SchemaT>
|
template <IsSchema SchemaT>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static RelationValidationResult validate(const mfem::Mesh &mesh) {
|
static RelationValidationResult validate(const mfem::Mesh &mesh) {
|
||||||
static_assert(
|
static_assert(sizeof...(DomainTs) == 1 || sizeof...(DomainTs) == 2,
|
||||||
sizeof...(DomainTs) == 1 || sizeof...(DomainTs) == 2,
|
"DomainBoundary requires exactly one or two domains.");
|
||||||
"DomainBoundary requires exactly one or two domains."
|
|
||||||
);
|
|
||||||
|
|
||||||
static_assert(
|
static_assert(SchemaT::template contains_boundary<BoundaryT>(),
|
||||||
SchemaT::template contains_boundary<BoundaryT>(), "DomainBoundary refers to a boundary which is not "
|
"DomainBoundary refers to a boundary which is not "
|
||||||
"registered in the supplied DomainSchema."
|
"registered in the supplied DomainSchema.");
|
||||||
);
|
|
||||||
|
|
||||||
static_assert(
|
static_assert((SchemaT::template contains_domain<DomainTs>() && ...),
|
||||||
(SchemaT::template contains_domain<DomainTs>() && ...),
|
|
||||||
"DomainBoundary refers to a domain which is not "
|
"DomainBoundary refers to a domain which is not "
|
||||||
"completely registered in the supplied DomainSchema."
|
"completely registered in the supplied DomainSchema.");
|
||||||
);
|
|
||||||
|
|
||||||
constexpr int expectedBoundaryAttribute = SchemaT::template boundary_attribute<BoundaryT>();
|
constexpr int expectedBoundaryAttribute =
|
||||||
|
SchemaT::template boundary_attribute<BoundaryT>();
|
||||||
|
|
||||||
using DomainsTuple = std::tuple<DomainTs...>;
|
using DomainsTuple = std::tuple<DomainTs...>;
|
||||||
|
|
||||||
@@ -732,42 +804,47 @@ export namespace mean_field::utils::domain {
|
|||||||
* one here; instead, every boundary element on an expected
|
* one here; instead, every boundary element on an expected
|
||||||
* face must carry the expected semantic boundary attribute.
|
* face must carry the expected semantic boundary attribute.
|
||||||
*/
|
*/
|
||||||
std::vector<std::vector<int>> boundaryElementsByFace(static_cast<std::size_t>(mesh.GetNumFaces()));
|
std::vector<std::vector<int>> boundaryElementsByFace(
|
||||||
|
static_cast<std::size_t>(mesh.GetNumFaces()));
|
||||||
|
|
||||||
for (int boundaryElementId = 0; boundaryElementId < mesh.GetNBE(); ++boundaryElementId) {
|
for (int boundaryElementId = 0; boundaryElementId < mesh.GetNBE();
|
||||||
|
++boundaryElementId) {
|
||||||
const int faceId = mesh.GetBdrElementFaceIndex(boundaryElementId);
|
const int faceId = mesh.GetBdrElementFaceIndex(boundaryElementId);
|
||||||
|
|
||||||
if (faceId >= 0 && faceId < mesh.GetNumFaces()) {
|
if (faceId >= 0 && faceId < mesh.GetNumFaces()) {
|
||||||
boundaryElementsByFace[static_cast<std::size_t>(faceId)].push_back(boundaryElementId);
|
boundaryElementsByFace[static_cast<std::size_t>(faceId)].push_back(
|
||||||
|
boundaryElementId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Build detailed diagnostics for one face.
|
* Build detailed diagnostics for one face.
|
||||||
*/
|
*/
|
||||||
const auto make_diagnostics = [&mesh, expectedBoundaryAttribute](
|
const auto make_diagnostics =
|
||||||
|
[&mesh, expectedBoundaryAttribute](
|
||||||
int faceId, int boundaryElementId,
|
int faceId, int boundaryElementId,
|
||||||
std::optional<int> actualBoundaryAttribute
|
std::optional<int> actualBoundaryAttribute) {
|
||||||
) {
|
|
||||||
RelationValidationResult::DomainBoundaryDiagnostics diagnostics{
|
RelationValidationResult::DomainBoundaryDiagnostics diagnostics{
|
||||||
.faceId = faceId,
|
.faceId = faceId,
|
||||||
.boundaryElementId = boundaryElementId,
|
.boundaryElementId = boundaryElementId,
|
||||||
.expectedBoundaryAttribute = expectedBoundaryAttribute,
|
.expectedBoundaryAttribute = expectedBoundaryAttribute,
|
||||||
.actualBoundaryAttribute = actualBoundaryAttribute
|
.actualBoundaryAttribute = actualBoundaryAttribute};
|
||||||
};
|
|
||||||
|
|
||||||
if (faceId < 0 || faceId >= mesh.GetNumFaces()) {
|
if (faceId < 0 || faceId >= mesh.GetNumFaces()) {
|
||||||
return diagnostics;
|
return diagnostics;
|
||||||
}
|
}
|
||||||
|
|
||||||
mesh.GetFaceElements(faceId, &diagnostics.firstElementId, &diagnostics.secondElementId);
|
mesh.GetFaceElements(faceId, &diagnostics.firstElementId,
|
||||||
|
&diagnostics.secondElementId);
|
||||||
|
|
||||||
if (diagnostics.firstElementId >= 0) {
|
if (diagnostics.firstElementId >= 0) {
|
||||||
diagnostics.firstMaterialId = mesh.GetAttribute(diagnostics.firstElementId);
|
diagnostics.firstMaterialId =
|
||||||
|
mesh.GetAttribute(diagnostics.firstElementId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (diagnostics.secondElementId >= 0) {
|
if (diagnostics.secondElementId >= 0) {
|
||||||
diagnostics.secondMaterialId = mesh.GetAttribute(diagnostics.secondElementId);
|
diagnostics.secondMaterialId =
|
||||||
|
mesh.GetAttribute(diagnostics.secondElementId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return diagnostics;
|
return diagnostics;
|
||||||
@@ -789,7 +866,8 @@ export namespace mean_field::utils::domain {
|
|||||||
*
|
*
|
||||||
* Both adjacent volume elements must exist.
|
* Both adjacent volume elements must exist.
|
||||||
*/
|
*/
|
||||||
const auto has_required_topology = [](int firstElementId, int secondElementId) {
|
const auto has_required_topology = [](int firstElementId,
|
||||||
|
int secondElementId) {
|
||||||
if constexpr (sizeof...(DomainTs) == 1) {
|
if constexpr (sizeof...(DomainTs) == 1) {
|
||||||
const bool firstExists = firstElementId >= 0;
|
const bool firstExists = firstElementId >= 0;
|
||||||
|
|
||||||
@@ -807,7 +885,8 @@ export namespace mean_field::utils::domain {
|
|||||||
*
|
*
|
||||||
* For two domains, ordering is intentionally irrelevant.
|
* For two domains, ordering is intentionally irrelevant.
|
||||||
*/
|
*/
|
||||||
const auto face_matches_domains = [&mesh](int firstElementId, int secondElementId) {
|
const auto face_matches_domains = [&mesh](int firstElementId,
|
||||||
|
int secondElementId) {
|
||||||
if constexpr (sizeof...(DomainTs) == 1) {
|
if constexpr (sizeof...(DomainTs) == 1) {
|
||||||
using DomainT = std::tuple_element_t<0, DomainsTuple>;
|
using DomainT = std::tuple_element_t<0, DomainsTuple>;
|
||||||
|
|
||||||
@@ -837,11 +916,17 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
const int secondMaterialId = mesh.GetAttribute(secondElementId);
|
const int secondMaterialId = mesh.GetAttribute(secondElementId);
|
||||||
|
|
||||||
const bool forwardMatch = SchemaT::template attribute_belongs_to<FirstDomainT>(firstMaterialId) &&
|
const bool forwardMatch =
|
||||||
SchemaT::template attribute_belongs_to<SecondDomainT>(secondMaterialId);
|
SchemaT::template attribute_belongs_to<FirstDomainT>(
|
||||||
|
firstMaterialId) &&
|
||||||
|
SchemaT::template attribute_belongs_to<SecondDomainT>(
|
||||||
|
secondMaterialId);
|
||||||
|
|
||||||
const bool reverseMatch = SchemaT::template attribute_belongs_to<SecondDomainT>(firstMaterialId) &&
|
const bool reverseMatch =
|
||||||
SchemaT::template attribute_belongs_to<FirstDomainT>(secondMaterialId);
|
SchemaT::template attribute_belongs_to<SecondDomainT>(
|
||||||
|
firstMaterialId) &&
|
||||||
|
SchemaT::template attribute_belongs_to<FirstDomainT>(
|
||||||
|
secondMaterialId);
|
||||||
|
|
||||||
return forwardMatch || reverseMatch;
|
return forwardMatch || reverseMatch;
|
||||||
}
|
}
|
||||||
@@ -856,7 +941,8 @@ export namespace mean_field::utils::domain {
|
|||||||
* exactly the topology/material interface declared by
|
* exactly the topology/material interface declared by
|
||||||
* DomainBoundary.
|
* DomainBoundary.
|
||||||
*/
|
*/
|
||||||
for (int boundaryElementId = 0; boundaryElementId < mesh.GetNBE(); ++boundaryElementId) {
|
for (int boundaryElementId = 0; boundaryElementId < mesh.GetNBE();
|
||||||
|
++boundaryElementId) {
|
||||||
const int boundaryAttribute = mesh.GetBdrAttribute(boundaryElementId);
|
const int boundaryAttribute = mesh.GetBdrAttribute(boundaryElementId);
|
||||||
|
|
||||||
if (boundaryAttribute != expectedBoundaryAttribute) {
|
if (boundaryAttribute != expectedBoundaryAttribute) {
|
||||||
@@ -873,23 +959,21 @@ export namespace mean_field::utils::domain {
|
|||||||
mesh.GetFaceElements(faceId, &firstElementId, &secondElementId);
|
mesh.GetFaceElements(faceId, &firstElementId, &secondElementId);
|
||||||
|
|
||||||
if (!has_required_topology(firstElementId, secondElementId)) {
|
if (!has_required_topology(firstElementId, secondElementId)) {
|
||||||
return {
|
return {.failure = RelationValidationFailure::
|
||||||
.failure = RelationValidationFailure::DomainBoundaryTaggedFaceHasWrongTopology,
|
DomainBoundaryTaggedFaceHasWrongTopology,
|
||||||
.domainBoundaryDiagnostics =
|
.domainBoundaryDiagnostics = std::make_optional<
|
||||||
std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>(
|
RelationValidationResult::DomainBoundaryDiagnostics>(
|
||||||
make_diagnostics(faceId, boundaryElementId, boundaryAttribute)
|
make_diagnostics(faceId, boundaryElementId,
|
||||||
)
|
boundaryAttribute))};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!face_matches_domains(firstElementId, secondElementId)) {
|
if (!face_matches_domains(firstElementId, secondElementId)) {
|
||||||
return {
|
return {.failure = RelationValidationFailure::
|
||||||
.failure = RelationValidationFailure::DomainBoundaryTaggedFaceTouchesUnexpectedMaterial,
|
DomainBoundaryTaggedFaceTouchesUnexpectedMaterial,
|
||||||
.domainBoundaryDiagnostics =
|
.domainBoundaryDiagnostics = std::make_optional<
|
||||||
std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>(
|
RelationValidationResult::DomainBoundaryDiagnostics>(
|
||||||
make_diagnostics(faceId, boundaryElementId, boundaryAttribute)
|
make_diagnostics(faceId, boundaryElementId,
|
||||||
)
|
boundaryAttribute))};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -917,32 +1001,32 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
foundExpectedFace = true;
|
foundExpectedFace = true;
|
||||||
|
|
||||||
const auto &boundaryElementIds = boundaryElementsByFace[static_cast<std::size_t>(faceId)];
|
const auto &boundaryElementIds =
|
||||||
|
boundaryElementsByFace[static_cast<std::size_t>(faceId)];
|
||||||
|
|
||||||
if (boundaryElementIds.empty()) {
|
if (boundaryElementIds.empty()) {
|
||||||
return {
|
return {
|
||||||
.failure = RelationValidationFailure::DomainBoundaryExpectedFaceIsUntagged,
|
.failure =
|
||||||
.domainBoundaryDiagnostics =
|
RelationValidationFailure::DomainBoundaryExpectedFaceIsUntagged,
|
||||||
std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>(
|
.domainBoundaryDiagnostics = std::make_optional<
|
||||||
make_diagnostics(faceId, -1, std::nullopt)
|
RelationValidationResult::DomainBoundaryDiagnostics>(
|
||||||
)
|
make_diagnostics(faceId, -1, std::nullopt))};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const int boundaryElementId : boundaryElementIds) {
|
for (const int boundaryElementId : boundaryElementIds) {
|
||||||
const int actualBoundaryAttribute = mesh.GetBdrAttribute(boundaryElementId);
|
const int actualBoundaryAttribute =
|
||||||
|
mesh.GetBdrAttribute(boundaryElementId);
|
||||||
|
|
||||||
if (actualBoundaryAttribute == expectedBoundaryAttribute) {
|
if (actualBoundaryAttribute == expectedBoundaryAttribute) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return {.failure = RelationValidationFailure::
|
||||||
.failure = RelationValidationFailure::DomainBoundaryExpectedFaceHasWrongAttribute,
|
DomainBoundaryExpectedFaceHasWrongAttribute,
|
||||||
.domainBoundaryDiagnostics =
|
.domainBoundaryDiagnostics = std::make_optional<
|
||||||
std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>(
|
RelationValidationResult::DomainBoundaryDiagnostics>(
|
||||||
make_diagnostics(faceId, boundaryElementId, actualBoundaryAttribute)
|
make_diagnostics(faceId, boundaryElementId,
|
||||||
)
|
actualBoundaryAttribute))};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -955,13 +1039,10 @@ export namespace mean_field::utils::domain {
|
|||||||
* have returned a more specific diagnostic.
|
* have returned a more specific diagnostic.
|
||||||
*/
|
*/
|
||||||
if (!foundTaggedBoundary || !foundExpectedFace) {
|
if (!foundTaggedBoundary || !foundExpectedFace) {
|
||||||
return {
|
return {.failure = RelationValidationFailure::DomainBoundaryAbsent,
|
||||||
.failure = RelationValidationFailure::DomainBoundaryAbsent,
|
.domainBoundaryDiagnostics = std::make_optional<
|
||||||
.domainBoundaryDiagnostics =
|
RelationValidationResult::DomainBoundaryDiagnostics>(
|
||||||
std::make_optional<RelationValidationResult::DomainBoundaryDiagnostics>(
|
make_diagnostics(-1, -1, std::nullopt))};
|
||||||
make_diagnostics(-1, -1, std::nullopt)
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
@@ -1028,7 +1109,8 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
std::optional<std::size_t> first_failed_relation_index() const noexcept {
|
std::optional<std::size_t> first_failed_relation_index() const noexcept {
|
||||||
for (std::size_t relationIndex = 0; relationIndex < relationResults.size(); ++relationIndex) {
|
for (std::size_t relationIndex = 0; relationIndex < relationResults.size();
|
||||||
|
++relationIndex) {
|
||||||
if (!relationResults[relationIndex].valid()) {
|
if (!relationResults[relationIndex].valid()) {
|
||||||
return relationIndex;
|
return relationIndex;
|
||||||
}
|
}
|
||||||
@@ -1038,7 +1120,8 @@ export namespace mean_field::utils::domain {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <IsSchema SchemaT, typename RelationListT> struct SchemaRelationValidator;
|
template <IsSchema SchemaT, typename RelationListT>
|
||||||
|
struct SchemaRelationValidator;
|
||||||
|
|
||||||
template <IsSchema SchemaT, IsRelation... RelationTs>
|
template <IsSchema SchemaT, IsRelation... RelationTs>
|
||||||
struct SchemaRelationValidator<SchemaT, RelationList<RelationTs...>> {
|
struct SchemaRelationValidator<SchemaT, RelationList<RelationTs...>> {
|
||||||
@@ -1050,13 +1133,11 @@ export namespace mean_field::utils::domain {
|
|||||||
|
|
||||||
std::size_t relationIndex = 0;
|
std::size_t relationIndex = 0;
|
||||||
|
|
||||||
(schemaResult.relationResults.push_back(
|
(schemaResult.relationResults.push_back(SchemaRelationValidationResult{
|
||||||
SchemaRelationValidationResult{
|
|
||||||
.relationIndex = relationIndex++,
|
.relationIndex = relationIndex++,
|
||||||
.relationName = RelationTs::name,
|
.relationName = RelationTs::name,
|
||||||
.result = RelationValidator<RelationTs>::template validate<SchemaT>(mesh)
|
.result =
|
||||||
}
|
RelationValidator<RelationTs>::template validate<SchemaT>(mesh)}),
|
||||||
),
|
|
||||||
...);
|
...);
|
||||||
|
|
||||||
return schemaResult;
|
return schemaResult;
|
||||||
@@ -1071,22 +1152,38 @@ export namespace mean_field::utils::domain {
|
|||||||
return SchemaRelationValidator<SchemaT, RelationsT>::validate(mesh);
|
return SchemaRelationValidator<SchemaT, RelationsT>::validate(mesh);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <IsDomainOrSet DomainT, IsSchema SchemaT>
|
||||||
|
[[nodiscard]]
|
||||||
|
mfem::Array<int> make_attribute_marker(const mfem::Mesh &mesh) {
|
||||||
|
static_assert(SchemaT::template contains_domain<DomainT>(),
|
||||||
|
"Requested marker domain is not completely registered in the "
|
||||||
|
"supplied DomainSchema.");
|
||||||
|
|
||||||
|
mfem::Array<int> marker(mesh.attributes.Max());
|
||||||
|
|
||||||
|
for (int attribute = 1; attribute <= marker.Size(); ++attribute) {
|
||||||
|
marker[attribute - 1] =
|
||||||
|
SchemaT::template attribute_belongs_to<DomainT>(attribute) ? 1 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return marker;
|
||||||
|
}
|
||||||
|
|
||||||
using CoreEnvelopeVacuumDomainSchema = DomainSchema<
|
using CoreEnvelopeVacuumDomainSchema = DomainSchema<
|
||||||
MaterialList<Material<Core, 1>, Material<Envelope, 2>, Material<Vacuum, 3>>,
|
MaterialList<Material<Core, 1>, Material<Envelope, 2>, Material<Vacuum, 3>>,
|
||||||
BoundaryList<BoundaryAttribute<StellarSurface, 1>, BoundaryAttribute<InfinitySurface, 2>>,
|
BoundaryList<BoundaryAttribute<StellarSurface, 1>,
|
||||||
|
BoundaryAttribute<InfinitySurface, 2>>,
|
||||||
RelationList<
|
RelationList<
|
||||||
// All Domains must be fully connected
|
// All Domains must be fully connected
|
||||||
Connected<Core>,
|
Connected<Core>, Connected<Envelope>, Connected<Vacuum>,
|
||||||
Connected<Envelope>,
|
|
||||||
Connected<Vacuum>,
|
|
||||||
|
|
||||||
// Describe the topology of the mesh (core must be within envelope and the stellar domain (core + envelope)
|
// Describe the topology of the mesh (core must be within envelope and
|
||||||
// must be inscribed within vacuum region
|
// the stellar domain (core + envelope) must be inscribed within vacuum
|
||||||
Inscribed<Core, Envelope>,
|
// region
|
||||||
Inscribed<Stellar, Vacuum>,
|
Inscribed<Core, Envelope>, Inscribed<Stellar, Vacuum>,
|
||||||
|
|
||||||
// The stellar surface sits between the stellar and vacuum domain and the infinity surface sits at the
|
// The stellar surface sits between the stellar and vacuum domain and
|
||||||
// outside of the vacuum domain
|
// the infinity surface sits at the outside of the vacuum domain
|
||||||
DomainBoundary<StellarSurface, Stellar, Vacuum>,
|
DomainBoundary<StellarSurface, Stellar, Vacuum>,
|
||||||
DomainBoundary<InfinitySurface, Vacuum>>>;
|
DomainBoundary<InfinitySurface, Vacuum>>>;
|
||||||
} // namespace mean_field::utils::domain
|
} // namespace mean_field::utils::domain
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
module;
|
module;
|
||||||
#include <expected>
|
|
||||||
#include <functional>
|
#include <functional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
|
|
||||||
@@ -9,16 +8,16 @@ module;
|
|||||||
#include <XAD/XAD.hpp>
|
#include <XAD/XAD.hpp>
|
||||||
|
|
||||||
export module mean_field:utils.misc;
|
export module mean_field:utils.misc;
|
||||||
import :boundary.contexts;
|
import :utils.domain;
|
||||||
|
|
||||||
export namespace mean_field::utils {
|
export namespace mean_field::utils {
|
||||||
constexpr double APPROX_MAX_ACCEPTABLE_POTENTIAL_ERROR_SI_BURNING = 1e-4;
|
constexpr double APPROX_MAX_ACCEPTABLE_POTENTIAL_ERROR_SI_BURNING = 1e-4;
|
||||||
|
|
||||||
bool is_vacuum(
|
bool is_vacuum(const mfem::ElementTransformation &Tr,
|
||||||
const mfem::ElementTransformation &Tr,
|
mfem::Array<mfem::Vector *> elvec) {
|
||||||
mfem::Array<mfem::Vector *> elvec
|
using Schema = domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
) {
|
|
||||||
if (Tr.Attribute == 3) {
|
if (Schema::template attribute_belongs_to<domain::Vacuum>(Tr.Attribute)) {
|
||||||
const int size_elvec = elvec.Size();
|
const int size_elvec = elvec.Size();
|
||||||
for (int i = 0; i < size_elvec; i++) {
|
for (int i = 0; i < size_elvec; i++) {
|
||||||
if (elvec[i]) {
|
if (elvec[i]) {
|
||||||
@@ -30,11 +29,11 @@ export namespace mean_field::utils {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_vacuum(
|
bool is_vacuum(const mfem::ElementTransformation &Tr,
|
||||||
const mfem::ElementTransformation &Tr,
|
const mfem::Array2D<mfem::DenseMatrix *> &elmats) {
|
||||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
using Schema = domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
) {
|
|
||||||
if (Tr.Attribute == 3) {
|
if (Schema::template attribute_belongs_to<domain::Vacuum>(Tr.Attribute)) {
|
||||||
const int cols = elmats.NumCols();
|
const int cols = elmats.NumCols();
|
||||||
const int rows = elmats.NumRows();
|
const int rows = elmats.NumRows();
|
||||||
for (int rowID = 0; rowID < rows; rowID++) {
|
for (int rowID = 0; rowID < rows; rowID++) {
|
||||||
@@ -66,13 +65,15 @@ export namespace mean_field::utils {
|
|||||||
[[maybe_unused]] constexpr int PORT = 19916;
|
[[maybe_unused]] constexpr int PORT = 19916;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept is_xad = std::is_same_v<T, xad::AReal<long double>> || std::is_same_v<T, xad::AReal<double>> ||
|
concept is_xad = std::is_same_v<T, xad::AReal<long double>> ||
|
||||||
|
std::is_same_v<T, xad::AReal<double>> ||
|
||||||
std::is_same_v<T, xad::AReal<float>>;
|
std::is_same_v<T, xad::AReal<float>>;
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
concept is_real = std::is_floating_point_v<T> || is_xad<T>;
|
concept is_real = std::is_floating_point_v<T> || is_xad<T>;
|
||||||
|
|
||||||
template <is_real T> using EOS_P = std::function<T(const T &rho, const T &temp)>;
|
template <is_real T>
|
||||||
|
using EOS_P = std::function<T(const T &rho, const T &temp)>;
|
||||||
|
|
||||||
enum class DOMAINS : uint8_t {
|
enum class DOMAINS : uint8_t {
|
||||||
CORE = 1 << 0,
|
CORE = 1 << 0,
|
||||||
@@ -82,35 +83,9 @@ export namespace mean_field::utils {
|
|||||||
ALL = CORE | ENVELOPE | VACUUM
|
ALL = CORE | ENVELOPE | VACUUM
|
||||||
};
|
};
|
||||||
|
|
||||||
DOMAINS operator|(
|
DOMAINS operator|(DOMAINS lhs, DOMAINS rhs);
|
||||||
DOMAINS lhs,
|
|
||||||
DOMAINS rhs
|
|
||||||
);
|
|
||||||
|
|
||||||
DOMAINS operator&(
|
DOMAINS operator&(DOMAINS lhs, DOMAINS rhs);
|
||||||
DOMAINS lhs,
|
|
||||||
DOMAINS rhs
|
|
||||||
);
|
|
||||||
|
|
||||||
void populate_element_mask(
|
|
||||||
const mfem::Mesh *mesh,
|
|
||||||
DOMAINS domain,
|
|
||||||
mfem::Array<int> &mask
|
|
||||||
);
|
|
||||||
|
|
||||||
void populate_domain_tdofs(
|
|
||||||
const mfem::ParFiniteElementSpace *fes,
|
|
||||||
const mfem::Array<int> &element_mask,
|
|
||||||
mfem::Array<int> &ess_tdof
|
|
||||||
);
|
|
||||||
|
|
||||||
std::expected<
|
|
||||||
boundary::Bounds,
|
|
||||||
boundary::BoundsError>
|
|
||||||
discover_bounds(
|
|
||||||
const mfem::Mesh *mesh,
|
|
||||||
int vacuum_attr
|
|
||||||
);
|
|
||||||
|
|
||||||
int get_mesh_order(const mfem::Mesh &mesh);
|
int get_mesh_order(const mfem::Mesh &mesh);
|
||||||
|
|
||||||
|
|||||||
@@ -7,9 +7,9 @@ export import :mapping.compactification.options;
|
|||||||
|
|
||||||
export namespace mean_field::utils {
|
export namespace mean_field::utils {
|
||||||
struct potential {
|
struct potential {
|
||||||
double rtol;
|
double rtol{1.0e-12};
|
||||||
double atol;
|
double atol{1.0e-12};
|
||||||
int max_iters;
|
int max_iters{1000};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct rot {
|
struct rot {
|
||||||
@@ -18,7 +18,7 @@ export namespace mean_field::utils {
|
|||||||
double L;
|
double L;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct DomainMapperStatelessOptions {
|
struct DomainMapperOptions {
|
||||||
int dimension{3};
|
int dimension{3};
|
||||||
int vacuum_element_attribute{3};
|
int vacuum_element_attribute{3};
|
||||||
};
|
};
|
||||||
@@ -31,7 +31,7 @@ export namespace mean_field::utils {
|
|||||||
double index{};
|
double index{};
|
||||||
double mass{};
|
double mass{};
|
||||||
double c{};
|
double c{};
|
||||||
DomainMapperStatelessOptions domain_mapper_options{};
|
DomainMapperOptions domain_mapper_options{};
|
||||||
mapping::compactification::options::KelvinCompactificationOptions kelvin_options{};
|
mapping::compactification::options::KelvinCompactificationOptions kelvin_options{};
|
||||||
int max_iters{};
|
int max_iters{};
|
||||||
double tol{};
|
double tol{};
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
#include <cmath>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <mfem.hpp>
|
#include <mfem.hpp>
|
||||||
#include <mpi.h>
|
#include <mpi.h>
|
||||||
@@ -79,6 +80,11 @@ namespace field_dof_map_test_utils {
|
|||||||
concept CanMakeFieldDofMap =
|
concept CanMakeFieldDofMap =
|
||||||
requires(const mfem::ParFiniteElementSpace &space) { field::make_field_dof_map<FieldT, Schema>(space); };
|
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<
|
using AlternateSchema = domain::DomainSchema<
|
||||||
domain::MaterialList<
|
domain::MaterialList<
|
||||||
domain::Material<domain::Core, 11>,
|
domain::Material<domain::Core, 11>,
|
||||||
@@ -90,7 +96,7 @@ namespace field_dof_map_test_utils {
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Preserves Canonical Bidirectional Indexing",
|
"Field DOF Map Preserves Canonical Bidirectional Indexing",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -166,7 +172,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Rejects Invalid Canonical Mappings",
|
"Field DOF Map Rejects Invalid Canonical Mappings",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -191,7 +197,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Rejects Out Of Range Index Queries",
|
"Field DOF Map Rejects Out Of Range Index Queries",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -212,7 +218,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Gather Selects Exactly The Active True DOFs",
|
"Field DOF Map Gather Selects Exactly The Active True DOFs",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -247,7 +253,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Scatter Produces The Canonical Supported Projection",
|
"Field DOF Map Scatter Produces The Canonical Supported Projection",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -281,7 +287,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Gather Scatter Projects A Full Vector Onto Field Support",
|
"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;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -310,7 +316,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Scatter Into Preserves Unsupported True DOFs",
|
"Field DOF Map Scatter Into Preserves Unsupported True DOFs",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -337,7 +343,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Scatter Add Accumulates Only Onto Active True DOFs",
|
"Field DOF Map Scatter Add Accumulates Only Onto Active True DOFs",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -364,7 +370,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Operations Support MFEM Vector Views Without Resizing",
|
"Field DOF Map Operations Support MFEM Vector Views Without Resizing",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -406,7 +412,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Operations Reject Incompatible Vector Sizes",
|
"Field DOF Map Operations Reject Incompatible Vector Sizes",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -433,7 +439,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Identity Mapping Is An Exact Vector Identity",
|
"Field DOF Map Identity Mapping Is An Exact Vector Identity",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -463,7 +469,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Validates Field DOF Support Consistency",
|
"Field DOF Map Validates Field DOF Support Consistency",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -495,7 +501,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Factory Is Available Only For Spatial Registered Fields",
|
"Field DOF Map Factory Is Available Only For Spatial Registered Fields",
|
||||||
tags::unit &tags::field
|
tags::field_dof_unit
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -509,12 +515,24 @@ TEST_CASE(
|
|||||||
|
|
||||||
STATIC_REQUIRE_FALSE(field_dof_map_test_utils::CanMakeFieldDofMap<field::BarotropicConstant>);
|
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);
|
CHECK(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Factory Exactly Preserves Density Support",
|
"Field DOF Map Factory Exactly Preserves Density Support",
|
||||||
tags::integration &tags::field
|
tags::field_dof_integration
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -567,7 +585,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Factory Exactly Preserves H1 Enthalpy Support",
|
"Field DOF Map Factory Exactly Preserves H1 Enthalpy Support",
|
||||||
tags::integration &tags::field
|
tags::field_dof_integration
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -614,7 +632,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Factory Produces Identity Maps For All Supported Fields",
|
"Field DOF Map Factory Produces Identity Maps For All Supported Fields",
|
||||||
tags::integration &tags::field
|
tags::field_dof_integration
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -648,7 +666,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Factory Uses Schema Material Bindings Rather Than Numeric Conventions",
|
"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;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -681,7 +699,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Field DOF Map Reduced Vectors Round Trip Through Real Field Support",
|
"Field DOF Map Reduced Vectors Round Trip Through Real Field Support",
|
||||||
tags::integration &tags::field
|
tags::field_dof_integration
|
||||||
) {
|
) {
|
||||||
namespace field = mean_field::field;
|
namespace field = mean_field::field;
|
||||||
|
|
||||||
@@ -722,3 +740,245 @@ TEST_CASE(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|||||||
@@ -9,6 +9,20 @@ import test_helpers;
|
|||||||
using namespace mean_field;
|
using namespace mean_field;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
struct SerialMappingData {
|
||||||
|
explicit SerialMappingData(mfem::Mesh &mesh)
|
||||||
|
: compactification_fes(&mesh, &compactification_fec),
|
||||||
|
compactification_coordinate(&compactification_fes),
|
||||||
|
mapper(field_dof_test_utils::make_domain_mapper()) {
|
||||||
|
compactification_coordinate = 0.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
mfem::H1_FECollection compactification_fec{1, 3};
|
||||||
|
mfem::FiniteElementSpace compactification_fes;
|
||||||
|
mfem::GridFunction compactification_coordinate;
|
||||||
|
mapping::DomainMapper mapper;
|
||||||
|
};
|
||||||
|
|
||||||
double compute_roche_surface_scale(
|
double compute_roche_surface_scale(
|
||||||
const double rotation_fraction,
|
const double rotation_fraction,
|
||||||
const double sine_theta_squared
|
const double sine_theta_squared
|
||||||
@@ -29,7 +43,7 @@ namespace {
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Centrifugal Integrator Matches Manufactured Cartesian Load",
|
"Centrifugal Integrator Matches Manufactured Cartesian Load",
|
||||||
tags::unit &tags::solver &tags::integrator &tags::centrifugal
|
tags::rotation_integrator_unit
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double density = 1.7;
|
constexpr double density = 1.7;
|
||||||
@@ -49,13 +63,15 @@ TEST_CASE(
|
|||||||
mfem::GridFunction displacement(&displacement_fes);
|
mfem::GridFunction displacement(&displacement_fes);
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
|
|
||||||
mapping::DomainMapper domain_mapper(displacement, 1.0, 2.0);
|
SerialMappingData mapping_data(mesh);
|
||||||
|
|
||||||
mfem::Vector omega(dim);
|
mfem::Vector omega(dim);
|
||||||
omega = 0.0;
|
omega = 0.0;
|
||||||
omega(2) = omega_value;
|
omega(2) = omega_value;
|
||||||
|
|
||||||
integrators::CentrifugalForceIntegrator integrator(domain_mapper, omega);
|
integrators::CentrifugalForceIntegrator integrator(
|
||||||
|
mapping_data.mapper, displacement, mapping_data.compactification_coordinate, omega
|
||||||
|
);
|
||||||
|
|
||||||
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
|
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
|
||||||
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
||||||
@@ -66,8 +82,7 @@ TEST_CASE(
|
|||||||
quadrature::Policy policy(std::move(rule_set));
|
quadrature::Policy policy(std::move(rule_set));
|
||||||
quadrature::RuleFactory quadrature_factory(std::move(policy));
|
quadrature::RuleFactory quadrature_factory(std::move(policy));
|
||||||
|
|
||||||
const quadrature::MappingKind mapping_kind =
|
const quadrature::MappingKind mapping_kind = quadrature::MappingKind::general;
|
||||||
!domain_mapper.HasDisplacementField() ? quadrature::MappingKind::none : quadrature::MappingKind::general;
|
|
||||||
const int position_order = displacement_element->GetOrder();
|
const int position_order = displacement_element->GetOrder();
|
||||||
|
|
||||||
quadrature_factory.configure_centrifugal(
|
quadrature_factory.configure_centrifugal(
|
||||||
@@ -127,7 +142,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Centrifugal Integrator Jacobian Matches Residual Linearization",
|
"Centrifugal Integrator Jacobian Matches Residual Linearization",
|
||||||
tags::unit &tags::solver &tags::integrator &tags::centrifugal
|
tags::rotation_integrator_unit
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double step = 1.0e-6;
|
constexpr double step = 1.0e-6;
|
||||||
@@ -147,14 +162,16 @@ TEST_CASE(
|
|||||||
mfem::GridFunction displacement(&displacement_fes);
|
mfem::GridFunction displacement(&displacement_fes);
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
|
|
||||||
mapping::DomainMapper domain_mapper(displacement, 1.0, 2.0);
|
SerialMappingData mapping_data(mesh);
|
||||||
|
|
||||||
mfem::Vector omega(dim);
|
mfem::Vector omega(dim);
|
||||||
omega(0) = 0.7;
|
omega(0) = 0.7;
|
||||||
omega(1) = -1.1;
|
omega(1) = -1.1;
|
||||||
omega(2) = 1.6;
|
omega(2) = 1.6;
|
||||||
|
|
||||||
integrators::CentrifugalForceIntegrator integrator(domain_mapper, omega);
|
integrators::CentrifugalForceIntegrator integrator(
|
||||||
|
mapping_data.mapper, displacement, mapping_data.compactification_coordinate, omega
|
||||||
|
);
|
||||||
|
|
||||||
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
|
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
|
||||||
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
||||||
@@ -165,8 +182,7 @@ TEST_CASE(
|
|||||||
quadrature::Policy policy(std::move(rule_set));
|
quadrature::Policy policy(std::move(rule_set));
|
||||||
quadrature::RuleFactory quadrature_factory(std::move(policy));
|
quadrature::RuleFactory quadrature_factory(std::move(policy));
|
||||||
|
|
||||||
const quadrature::MappingKind mapping_kind =
|
const quadrature::MappingKind mapping_kind = quadrature::MappingKind::general;
|
||||||
!domain_mapper.HasDisplacementField() ? quadrature::MappingKind::none : quadrature::MappingKind::general;
|
|
||||||
const int position_order = displacement_element->GetOrder();
|
const int position_order = displacement_element->GetOrder();
|
||||||
|
|
||||||
quadrature_factory.configure_centrifugal(
|
quadrature_factory.configure_centrifugal(
|
||||||
@@ -287,7 +303,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Centrifugal Integrator Preserves Rotation Identities",
|
"Centrifugal Integrator Preserves Rotation Identities",
|
||||||
tags::unit &tags::solver &tags::integrator &tags::centrifugal
|
tags::rotation_integrator_unit
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double density = 1.4;
|
constexpr double density = 1.4;
|
||||||
@@ -307,14 +323,16 @@ TEST_CASE(
|
|||||||
mfem::GridFunction displacement(&displacement_fes);
|
mfem::GridFunction displacement(&displacement_fes);
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
|
|
||||||
mapping::DomainMapper domain_mapper(displacement, 1.0, 2.0);
|
SerialMappingData mapping_data(mesh);
|
||||||
|
|
||||||
mfem::Vector omega(dim);
|
mfem::Vector omega(dim);
|
||||||
omega(0) = 0.7;
|
omega(0) = 0.7;
|
||||||
omega(1) = -1.1;
|
omega(1) = -1.1;
|
||||||
omega(2) = 1.6;
|
omega(2) = 1.6;
|
||||||
|
|
||||||
integrators::CentrifugalForceIntegrator integrator(domain_mapper, omega);
|
integrators::CentrifugalForceIntegrator integrator(
|
||||||
|
mapping_data.mapper, displacement, mapping_data.compactification_coordinate, omega
|
||||||
|
);
|
||||||
|
|
||||||
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
|
const mfem::FiniteElement *velocity_element = velocity_fes.GetFE(0);
|
||||||
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
||||||
@@ -325,8 +343,7 @@ TEST_CASE(
|
|||||||
quadrature::Policy policy(std::move(rule_set));
|
quadrature::Policy policy(std::move(rule_set));
|
||||||
quadrature::RuleFactory quadrature_factory(std::move(policy));
|
quadrature::RuleFactory quadrature_factory(std::move(policy));
|
||||||
|
|
||||||
const quadrature::MappingKind mapping_kind =
|
const quadrature::MappingKind mapping_kind = quadrature::MappingKind::general;
|
||||||
!domain_mapper.HasDisplacementField() ? quadrature::MappingKind::none : quadrature::MappingKind::general;
|
|
||||||
const int position_order = displacement_element->GetOrder();
|
const int position_order = displacement_element->GetOrder();
|
||||||
|
|
||||||
quadrature_factory.configure_centrifugal(
|
quadrature_factory.configure_centrifugal(
|
||||||
@@ -424,7 +441,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Centrifugal Integrator Matches Rotational Virial On Roche Mappings",
|
"Centrifugal Integrator Matches Rotational Virial On Roche Mappings",
|
||||||
tags::integration &tags::solver &tags::integrator &tags::centrifugal
|
tags::rotation_integrator_integration
|
||||||
) {
|
) {
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -486,16 +503,20 @@ TEST_CASE(
|
|||||||
|
|
||||||
mfem::VectorFunctionCoefficient displacement_coefficient(dim, rotation_displacement);
|
mfem::VectorFunctionCoefficient displacement_coefficient(dim, rotation_displacement);
|
||||||
displacement.ProjectCoefficient(displacement_coefficient);
|
displacement.ProjectCoefficient(displacement_coefficient);
|
||||||
f.mapping->SetDisplacement(displacement);
|
*f.displacement = displacement;
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*f.domainMapperStateless, *f.displacement, *f.compactificationCoordinate
|
||||||
|
);
|
||||||
|
|
||||||
mfem::Vector omega(dim);
|
mfem::Vector omega(dim);
|
||||||
omega = 0.0;
|
omega = 0.0;
|
||||||
omega(2) = rotation_fraction;
|
omega(2) = rotation_fraction;
|
||||||
|
|
||||||
integrators::CentrifugalForceIntegrator integrator(*f.mapping, omega);
|
integrators::CentrifugalForceIntegrator integrator(
|
||||||
|
*f.domainMapperStateless, *f.displacement, *f.compactificationCoordinate, omega
|
||||||
|
);
|
||||||
|
|
||||||
const quadrature::MappingKind mapping_kind =
|
const quadrature::MappingKind mapping_kind = quadrature::MappingKind::general;
|
||||||
!f.mapping->HasDisplacementField() ? quadrature::MappingKind::none : quadrature::MappingKind::general;
|
|
||||||
f.quadratureFactory->configure_centrifugal(
|
f.quadratureFactory->configure_centrifugal(
|
||||||
integrator, quadrature::QuadratureRole::discretization, representative_density_element,
|
integrator, quadrature::QuadratureRole::discretization, representative_density_element,
|
||||||
representative_velocity_element, representative_transformation, position_order, utils::DOMAINS::STELLAR,
|
representative_velocity_element, representative_transformation, position_order, utils::DOMAINS::STELLAR,
|
||||||
@@ -560,7 +581,7 @@ TEST_CASE(
|
|||||||
for (int i = 0; i < velocity_dofs_count; ++i) {
|
for (int i = 0; i < velocity_dofs_count; ++i) {
|
||||||
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
||||||
transformation->SetIntPoint(&node);
|
transformation->SetIntPoint(&node);
|
||||||
f.mapping->GetPhysicalPoint(*transformation, node, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, node, x_physical);
|
||||||
|
|
||||||
for (int d = 0; d < dim; ++d) {
|
for (int d = 0; d < dim; ++d) {
|
||||||
position_test_dofs(i + d * velocity_dofs_count) = x_physical(d);
|
position_test_dofs(i + d * velocity_dofs_count) = x_physical(d);
|
||||||
@@ -581,14 +602,14 @@ TEST_CASE(
|
|||||||
const mfem::IntegrationPoint &integration_point = reference_rule.IntPoint(q);
|
const mfem::IntegrationPoint &integration_point = reference_rule.IntPoint(q);
|
||||||
transformation->SetIntPoint(&integration_point);
|
transformation->SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const double signed_map_determinant = f.mapping->ComputeDetJ(*transformation, integration_point);
|
|
||||||
const mapping::VolumeQuadratureContext context =
|
const mapping::VolumeQuadratureContext context =
|
||||||
f.mapping->GetQuadratureContext(*transformation, integration_point);
|
mapping_evaluator.GetQuadratureContext(*transformation, integration_point);
|
||||||
|
const double signed_map_determinant = context.detJ;
|
||||||
|
|
||||||
local_minimum_map_determinant = std::min(local_minimum_map_determinant, signed_map_determinant);
|
local_minimum_map_determinant = std::min(local_minimum_map_determinant, signed_map_determinant);
|
||||||
local_maximum_map_determinant = std::max(local_maximum_map_determinant, signed_map_determinant);
|
local_maximum_map_determinant = std::max(local_maximum_map_determinant, signed_map_determinant);
|
||||||
|
|
||||||
f.mapping->GetPhysicalPoint(*transformation, integration_point, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, integration_point, x_physical);
|
||||||
velocity_element->CalcShape(integration_point, velocity_shape);
|
velocity_element->CalcShape(integration_point, velocity_shape);
|
||||||
|
|
||||||
position_test_value = 0.0;
|
position_test_value = 0.0;
|
||||||
@@ -661,13 +682,13 @@ TEST_CASE(
|
|||||||
CHECK_THAT(relative_position_error, Catch::Matchers::WithinAbs(0.0, position_tolerance));
|
CHECK_THAT(relative_position_error, Catch::Matchers::WithinAbs(0.0, position_tolerance));
|
||||||
}
|
}
|
||||||
|
|
||||||
f.mapping->ResetDisplacement();
|
*f.displacement = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Centrifugal Virial Position Representation Is Consistent At The "
|
"Centrifugal Virial Position Representation Is Consistent At The "
|
||||||
"Registered Order",
|
"Registered Order",
|
||||||
tags::integration &tags::solver &tags::integrator &tags::centrifugal
|
tags::rotation_integrator_integration
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double concentration = 4.0;
|
constexpr double concentration = 4.0;
|
||||||
@@ -728,7 +749,10 @@ TEST_CASE(
|
|||||||
|
|
||||||
mfem::VectorFunctionCoefficient displacement_coefficient(dim, rotation_displacement);
|
mfem::VectorFunctionCoefficient displacement_coefficient(dim, rotation_displacement);
|
||||||
displacement.ProjectCoefficient(displacement_coefficient);
|
displacement.ProjectCoefficient(displacement_coefficient);
|
||||||
f.mapping->SetDisplacement(displacement);
|
*f.displacement = displacement;
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*f.domainMapperStateless, *f.displacement, *f.compactificationCoordinate
|
||||||
|
);
|
||||||
|
|
||||||
mfem::Vector omega(dim);
|
mfem::Vector omega(dim);
|
||||||
omega = 0.0;
|
omega = 0.0;
|
||||||
@@ -761,7 +785,7 @@ TEST_CASE(
|
|||||||
for (int i = 0; i < velocity_dofs_count; ++i) {
|
for (int i = 0; i < velocity_dofs_count; ++i) {
|
||||||
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
||||||
transformation->SetIntPoint(&node);
|
transformation->SetIntPoint(&node);
|
||||||
f.mapping->GetPhysicalPoint(*transformation, node, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, node, x_physical);
|
||||||
|
|
||||||
for (int d = 0; d < dim; ++d) {
|
for (int d = 0; d < dim; ++d) {
|
||||||
position_test_dofs(i + d * velocity_dofs_count) = x_physical(d);
|
position_test_dofs(i + d * velocity_dofs_count) = x_physical(d);
|
||||||
@@ -780,13 +804,13 @@ TEST_CASE(
|
|||||||
const mfem::IntegrationPoint &integration_point = reference_rule.IntPoint(q);
|
const mfem::IntegrationPoint &integration_point = reference_rule.IntPoint(q);
|
||||||
transformation->SetIntPoint(&integration_point);
|
transformation->SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const double signed_map_determinant = f.mapping->ComputeDetJ(*transformation, integration_point);
|
|
||||||
const mapping::VolumeQuadratureContext context =
|
const mapping::VolumeQuadratureContext context =
|
||||||
f.mapping->GetQuadratureContext(*transformation, integration_point);
|
mapping_evaluator.GetQuadratureContext(*transformation, integration_point);
|
||||||
|
const double signed_map_determinant = context.detJ;
|
||||||
|
|
||||||
local_minimum_determinant = std::min(local_minimum_determinant, signed_map_determinant);
|
local_minimum_determinant = std::min(local_minimum_determinant, signed_map_determinant);
|
||||||
|
|
||||||
f.mapping->GetPhysicalPoint(*transformation, integration_point, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, integration_point, x_physical);
|
||||||
velocity_element->CalcShape(integration_point, velocity_shape);
|
velocity_element->CalcShape(integration_point, velocity_shape);
|
||||||
|
|
||||||
position_test_value = 0.0;
|
position_test_value = 0.0;
|
||||||
@@ -833,7 +857,7 @@ TEST_CASE(
|
|||||||
minimum_determinants[rotation_index][order_index] = global_minimum_determinant;
|
minimum_determinants[rotation_index][order_index] = global_minimum_determinant;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.mapping->ResetDisplacement();
|
*f.displacement = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t rotation_index = 0; rotation_index < rotation_fractions.size(); ++rotation_index) {
|
for (std::size_t rotation_index = 0; rotation_index < rotation_fractions.size(); ++rotation_index) {
|
||||||
@@ -853,7 +877,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Centrifugal Virial Position Representation Converges Under H Refinement",
|
"Centrifugal Virial Position Representation Converges Under H Refinement",
|
||||||
tags::integration &tags::solver &tags::integrator &tags::convergence &tags::h_refinement &tags::centrifugal
|
tags::rotation_integrator_convergence
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double concentration = 4.0;
|
constexpr double concentration = 4.0;
|
||||||
@@ -916,7 +940,10 @@ TEST_CASE(
|
|||||||
|
|
||||||
mfem::VectorFunctionCoefficient displacement_coefficient(dim, rotation_displacement);
|
mfem::VectorFunctionCoefficient displacement_coefficient(dim, rotation_displacement);
|
||||||
displacement.ProjectCoefficient(displacement_coefficient);
|
displacement.ProjectCoefficient(displacement_coefficient);
|
||||||
f.mapping->SetDisplacement(displacement);
|
*f.displacement = displacement;
|
||||||
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
*f.domainMapperStateless, *f.displacement, *f.compactificationCoordinate
|
||||||
|
);
|
||||||
|
|
||||||
mfem::Vector omega(dim);
|
mfem::Vector omega(dim);
|
||||||
omega = 0.0;
|
omega = 0.0;
|
||||||
@@ -949,7 +976,7 @@ TEST_CASE(
|
|||||||
for (int i = 0; i < velocity_dofs_count; ++i) {
|
for (int i = 0; i < velocity_dofs_count; ++i) {
|
||||||
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
||||||
transformation->SetIntPoint(&node);
|
transformation->SetIntPoint(&node);
|
||||||
f.mapping->GetPhysicalPoint(*transformation, node, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, node, x_physical);
|
||||||
|
|
||||||
for (int d = 0; d < dim; ++d) {
|
for (int d = 0; d < dim; ++d) {
|
||||||
position_test_dofs(i + d * velocity_dofs_count) = x_physical(d);
|
position_test_dofs(i + d * velocity_dofs_count) = x_physical(d);
|
||||||
@@ -968,13 +995,13 @@ TEST_CASE(
|
|||||||
const mfem::IntegrationPoint &integration_point = reference_rule.IntPoint(q);
|
const mfem::IntegrationPoint &integration_point = reference_rule.IntPoint(q);
|
||||||
transformation->SetIntPoint(&integration_point);
|
transformation->SetIntPoint(&integration_point);
|
||||||
|
|
||||||
const double signed_map_determinant = f.mapping->ComputeDetJ(*transformation, integration_point);
|
|
||||||
const mapping::VolumeQuadratureContext context =
|
const mapping::VolumeQuadratureContext context =
|
||||||
f.mapping->GetQuadratureContext(*transformation, integration_point);
|
mapping_evaluator.GetQuadratureContext(*transformation, integration_point);
|
||||||
|
const double signed_map_determinant = context.detJ;
|
||||||
|
|
||||||
local_minimum_determinant = std::min(local_minimum_determinant, signed_map_determinant);
|
local_minimum_determinant = std::min(local_minimum_determinant, signed_map_determinant);
|
||||||
|
|
||||||
f.mapping->GetPhysicalPoint(*transformation, integration_point, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, integration_point, x_physical);
|
||||||
velocity_element->CalcShape(integration_point, velocity_shape);
|
velocity_element->CalcShape(integration_point, velocity_shape);
|
||||||
|
|
||||||
position_test_value = 0.0;
|
position_test_value = 0.0;
|
||||||
@@ -1021,7 +1048,7 @@ TEST_CASE(
|
|||||||
minimum_determinants[rotation_index][refinement_index] = global_minimum_determinant;
|
minimum_determinants[rotation_index][refinement_index] = global_minimum_determinant;
|
||||||
}
|
}
|
||||||
|
|
||||||
f.mapping->ResetDisplacement();
|
*f.displacement = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::size_t rotation_index = 0; rotation_index < rotation_fractions.size(); ++rotation_index) {
|
for (std::size_t rotation_index = 0; rotation_index < rotation_fractions.size(); ++rotation_index) {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ using namespace mean_field;
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Gravity Force Integrator Jacobian Matches Residual Linearization",
|
"Gravity Force Integrator Jacobian Matches Residual Linearization",
|
||||||
tags::unit &tags::solver &tags::integrator &tags::gravity
|
tags::gravity_integrator_unit
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double finite_difference_step = 1.0e-3;
|
constexpr double finite_difference_step = 1.0e-3;
|
||||||
@@ -31,21 +31,20 @@ TEST_CASE(
|
|||||||
mfem::RT_FECollection gravity_gradient_fec(1, dim);
|
mfem::RT_FECollection gravity_gradient_fec(1, dim);
|
||||||
mfem::L2_FECollection gravity_potential_fec(1, dim);
|
mfem::L2_FECollection gravity_potential_fec(1, dim);
|
||||||
mfem::H1_FECollection displacement_fec(2, dim);
|
mfem::H1_FECollection displacement_fec(2, dim);
|
||||||
|
mfem::H1_FECollection compactification_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 density_fes(&mesh, &density_fec);
|
||||||
mfem::FiniteElementSpace gravity_gradient_fes(&mesh, &gravity_gradient_fec);
|
mfem::FiniteElementSpace gravity_gradient_fes(&mesh, &gravity_gradient_fec);
|
||||||
mfem::FiniteElementSpace gravity_potential_fes(&mesh, &gravity_potential_fec);
|
mfem::FiniteElementSpace gravity_potential_fes(&mesh, &gravity_potential_fec);
|
||||||
mfem::FiniteElementSpace displacement_fes(&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM);
|
mfem::FiniteElementSpace displacement_fes(&mesh, &displacement_fec, dim, mfem::Ordering::byVDIM);
|
||||||
|
mfem::FiniteElementSpace compactification_fes(&mesh, &compactification_fec);
|
||||||
|
|
||||||
mfem::GridFunction displacement(&displacement_fes);
|
mfem::GridFunction displacement(&displacement_fes);
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
|
mfem::GridFunction compactification_coordinate(&compactification_fes);
|
||||||
mapping::DomainMapper domain_mapper(displacement, 1.0, 2.0);
|
compactification_coordinate = 0.0;
|
||||||
INFO(std::format("Domain mapping is has displacement field: {}", domain_mapper.HasDisplacementField()));
|
mapping::DomainMapper domain_mapper = field_dof_test_utils::make_domain_mapper();
|
||||||
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 *velocity_element = velocity_fes.GetFE(0);
|
||||||
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
const mfem::FiniteElement *density_element = density_fes.GetFE(0);
|
||||||
@@ -130,7 +129,8 @@ TEST_CASE(
|
|||||||
element_residual[displacement_block] = &displacement_residual;
|
element_residual[displacement_block] = &displacement_residual;
|
||||||
|
|
||||||
integrators::GravityMomentumIntegrator integrator(
|
integrators::GravityMomentumIntegrator integrator(
|
||||||
domain_mapper, integrators::GravityForceJacobianMode::field_coupled
|
domain_mapper, displacement, compactification_coordinate,
|
||||||
|
integrators::GravityForceJacobianMode::field_coupled
|
||||||
);
|
);
|
||||||
|
|
||||||
const int maximum_order = std::max(
|
const int maximum_order = std::max(
|
||||||
@@ -268,7 +268,7 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Gravity Force Integrator Matches Manufactured Cartesian Load",
|
"Gravity Force Integrator Matches Manufactured Cartesian Load",
|
||||||
tags::unit &tags::solver &tags::integrator &tags::gravity
|
tags::gravity_integrator_unit
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double tolerance = 1.0e-12;
|
constexpr double tolerance = 1.0e-12;
|
||||||
@@ -286,18 +286,23 @@ TEST_CASE(
|
|||||||
mfem::L2_FECollection density_fec(1, dim);
|
mfem::L2_FECollection density_fec(1, dim);
|
||||||
mfem::RT_FECollection gravity_gradient_fec(0, dim);
|
mfem::RT_FECollection gravity_gradient_fec(0, dim);
|
||||||
mfem::H1_FECollection displacement_fec(1, dim);
|
mfem::H1_FECollection displacement_fec(1, dim);
|
||||||
|
mfem::H1_FECollection compactification_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 density_fes(&mesh, &density_fec);
|
||||||
mfem::FiniteElementSpace gravity_gradient_fes(&mesh, &gravity_gradient_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::FiniteElementSpace compactification_fes(&mesh, &compactification_fec);
|
||||||
|
|
||||||
mfem::GridFunction displacement(&displacement_fes);
|
mfem::GridFunction displacement(&displacement_fes);
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
|
mfem::GridFunction compactification_coordinate(&compactification_fes);
|
||||||
|
compactification_coordinate = 0.0;
|
||||||
|
mapping::DomainMapper domain_mapper = field_dof_test_utils::make_domain_mapper();
|
||||||
|
|
||||||
mapping::DomainMapper domain_mapper(displacement, 1.0, 2.0);
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
domain_mapper, displacement, compactification_coordinate
|
||||||
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); };
|
||||||
|
|
||||||
@@ -376,7 +381,8 @@ TEST_CASE(
|
|||||||
element_residual[displacement_block] = &displacement_residual;
|
element_residual[displacement_block] = &displacement_residual;
|
||||||
|
|
||||||
integrators::GravityMomentumIntegrator integrator(
|
integrators::GravityMomentumIntegrator integrator(
|
||||||
domain_mapper, integrators::GravityForceJacobianMode::field_coupled
|
domain_mapper, displacement, compactification_coordinate,
|
||||||
|
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);
|
||||||
@@ -395,7 +401,7 @@ TEST_CASE(
|
|||||||
for (int i = 0; i < velocity_dofs_count; ++i) {
|
for (int i = 0; i < velocity_dofs_count; ++i) {
|
||||||
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
||||||
transformation->SetIntPoint(&node);
|
transformation->SetIntPoint(&node);
|
||||||
domain_mapper.GetPhysicalPoint(*transformation, node, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, node, x_physical);
|
||||||
test_dofs(i + component * velocity_dofs_count) =
|
test_dofs(i + component * velocity_dofs_count) =
|
||||||
coordinate_weight < 0 ? 1.0 : x_physical(coordinate_weight);
|
coordinate_weight < 0 ? 1.0 : x_physical(coordinate_weight);
|
||||||
}
|
}
|
||||||
@@ -433,7 +439,7 @@ TEST_CASE(
|
|||||||
}
|
}
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Gravity Force Integrator Preserves Gravity Identities",
|
"Gravity Force Integrator Preserves Gravity Identities",
|
||||||
tags::unit &tags::solver &tags::integrator &tags::gravity
|
tags::gravity_integrator_unit
|
||||||
) {
|
) {
|
||||||
constexpr int dim = 3;
|
constexpr int dim = 3;
|
||||||
constexpr double density_value = 1.7;
|
constexpr double density_value = 1.7;
|
||||||
@@ -454,18 +460,22 @@ TEST_CASE(
|
|||||||
mfem::L2_FECollection density_fec(0, dim);
|
mfem::L2_FECollection density_fec(0, dim);
|
||||||
mfem::RT_FECollection gravity_gradient_fec(0, dim);
|
mfem::RT_FECollection gravity_gradient_fec(0, dim);
|
||||||
mfem::H1_FECollection displacement_fec(1, dim);
|
mfem::H1_FECollection displacement_fec(1, dim);
|
||||||
|
mfem::H1_FECollection compactification_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 density_fes(&mesh, &density_fec);
|
||||||
mfem::FiniteElementSpace gravity_gradient_fes(&mesh, &gravity_gradient_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::FiniteElementSpace compactification_fes(&mesh, &compactification_fec);
|
||||||
|
|
||||||
mfem::GridFunction displacement(&displacement_fes);
|
mfem::GridFunction displacement(&displacement_fes);
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
|
mfem::GridFunction compactification_coordinate(&compactification_fes);
|
||||||
mapping::DomainMapper domain_mapper(displacement, 1.0, 2.0);
|
compactification_coordinate = 0.0;
|
||||||
|
mapping::DomainMapper domain_mapper = field_dof_test_utils::make_domain_mapper();
|
||||||
REQUIRE(domain_mapper.HasDisplacementField());
|
mapping::GridFunctionMappingEvaluator mapping_evaluator(
|
||||||
|
domain_mapper, displacement, compactification_coordinate
|
||||||
|
);
|
||||||
|
|
||||||
auto radial_gravity = [](const mfem::Vector &x, mfem::Vector &gravity) {
|
auto radial_gravity = [](const mfem::Vector &x, mfem::Vector &gravity) {
|
||||||
gravity.SetSize(3);
|
gravity.SetSize(3);
|
||||||
@@ -543,7 +553,8 @@ TEST_CASE(
|
|||||||
element_residual[displacement_block] = &displacement_residual;
|
element_residual[displacement_block] = &displacement_residual;
|
||||||
|
|
||||||
integrators::GravityMomentumIntegrator integrator(
|
integrators::GravityMomentumIntegrator integrator(
|
||||||
domain_mapper, integrators::GravityForceJacobianMode::field_coupled
|
domain_mapper, displacement, compactification_coordinate,
|
||||||
|
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);
|
||||||
@@ -609,7 +620,7 @@ TEST_CASE(
|
|||||||
for (int i = 0; i < velocity_dofs_count; ++i) {
|
for (int i = 0; i < velocity_dofs_count; ++i) {
|
||||||
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
const mfem::IntegrationPoint &node = velocity_nodes.IntPoint(i);
|
||||||
transformation->SetIntPoint(&node);
|
transformation->SetIntPoint(&node);
|
||||||
domain_mapper.GetPhysicalPoint(*transformation, node, x_physical);
|
mapping_evaluator.GetPhysicalPoint(*transformation, node, x_physical);
|
||||||
|
|
||||||
for (int component = 0; component < dim; ++component) {
|
for (int component = 0; component < dim; ++component) {
|
||||||
centered_position(component) = x_physical(component) - 0.5;
|
centered_position(component) = x_physical(component) - 0.5;
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -43,11 +43,18 @@ TEST_CASE(
|
|||||||
CHECK(initial_report.geometry.reconstructed_operators);
|
CHECK(initial_report.geometry.reconstructed_operators);
|
||||||
CHECK(initial_report.geometry.rebuilt_mass_operator);
|
CHECK(initial_report.geometry.rebuilt_mass_operator);
|
||||||
CHECK(initial_report.geometry.rebuilt_source_operator);
|
CHECK(initial_report.geometry.rebuilt_source_operator);
|
||||||
|
CHECK(initial_report.geometry.rebuilt_divergence_operator);
|
||||||
CHECK(initial_report.geometry.refreshed_variation_state);
|
CHECK(initial_report.geometry.refreshed_variation_state);
|
||||||
CHECK(initial_report.updated_density);
|
CHECK(initial_report.updated_density);
|
||||||
CHECK(initial_report.updated_gravity_gradient);
|
CHECK(initial_report.updated_gravity_gradient);
|
||||||
CHECK(initial_report.DidAnyWork());
|
CHECK(initial_report.DidAnyWork());
|
||||||
|
|
||||||
|
const auto &geometry_context = context.GetGeometryContext();
|
||||||
|
CHECK(geometry_context.GetDivergenceOperator().Width() == f.gravityFluxFes->GetTrueVSize());
|
||||||
|
CHECK(geometry_context.GetDivergenceOperator().Height() == f.gravityPotentialFes->GetTrueVSize());
|
||||||
|
CHECK(geometry_context.GetTransposeDivergenceOperator().Width() == f.gravityPotentialFes->GetTrueVSize());
|
||||||
|
CHECK(geometry_context.GetTransposeDivergenceOperator().Height() == f.gravityFluxFes->GetTrueVSize());
|
||||||
|
|
||||||
const auto initial_mass_preparations = context.GetGeometryContext().GetMassOperator().GetPreparationCount();
|
const auto initial_mass_preparations = context.GetGeometryContext().GetMassOperator().GetPreparationCount();
|
||||||
const auto initial_source_preparations = context.GetGeometryContext().GetSourceOperator().GetPreparationCount();
|
const auto initial_source_preparations = context.GetGeometryContext().GetSourceOperator().GetPreparationCount();
|
||||||
|
|
||||||
@@ -93,6 +100,7 @@ TEST_CASE(
|
|||||||
CHECK_FALSE(displacement_report.geometry.reconstructed_operators);
|
CHECK_FALSE(displacement_report.geometry.reconstructed_operators);
|
||||||
CHECK(displacement_report.geometry.rebuilt_mass_operator);
|
CHECK(displacement_report.geometry.rebuilt_mass_operator);
|
||||||
CHECK(displacement_report.geometry.rebuilt_source_operator);
|
CHECK(displacement_report.geometry.rebuilt_source_operator);
|
||||||
|
CHECK_FALSE(displacement_report.geometry.rebuilt_divergence_operator);
|
||||||
CHECK(displacement_report.geometry.refreshed_variation_state);
|
CHECK(displacement_report.geometry.refreshed_variation_state);
|
||||||
CHECK_FALSE(displacement_report.updated_density);
|
CHECK_FALSE(displacement_report.updated_density);
|
||||||
CHECK_FALSE(displacement_report.updated_gravity_gradient);
|
CHECK_FALSE(displacement_report.updated_gravity_gradient);
|
||||||
@@ -107,6 +115,7 @@ TEST_CASE(
|
|||||||
CHECK(discretization_report.geometry.reconstructed_operators);
|
CHECK(discretization_report.geometry.reconstructed_operators);
|
||||||
CHECK(discretization_report.geometry.rebuilt_mass_operator);
|
CHECK(discretization_report.geometry.rebuilt_mass_operator);
|
||||||
CHECK(discretization_report.geometry.rebuilt_source_operator);
|
CHECK(discretization_report.geometry.rebuilt_source_operator);
|
||||||
|
CHECK(discretization_report.geometry.rebuilt_divergence_operator);
|
||||||
CHECK(discretization_report.updated_density);
|
CHECK(discretization_report.updated_density);
|
||||||
CHECK(discretization_report.updated_gravity_gradient);
|
CHECK(discretization_report.updated_gravity_gradient);
|
||||||
CHECK(context.GetGeometryContext().GetMassOperator().GetPreparationCount() == 1);
|
CHECK(context.GetGeometryContext().GetMassOperator().GetPreparationCount() == 1);
|
||||||
|
|||||||
@@ -14,83 +14,95 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
using CoupledForm = mean_field::utils::blocks::barotropic_equilibrium_form;
|
using CoupledForm = mean_field::utils::blocks::barotropic_equilibrium_form;
|
||||||
|
|
||||||
constexpr auto densityValue =
|
constexpr auto densityValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::density_field.mass_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::density_field.mass_term);
|
||||||
|
|
||||||
constexpr auto displacementValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto displacementValue =
|
||||||
mean_field::utils::blocks::displacement_field.geometry_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::displacement_field.geometry_term);
|
||||||
|
|
||||||
constexpr auto gravityGradientValue =
|
constexpr auto gravityGradientValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::gravity_field.gradient_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::gravity_field.gradient_term);
|
||||||
|
|
||||||
constexpr auto gravityPotentialValue =
|
constexpr auto gravityPotentialValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::gravity_field.poisson_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
constexpr auto enthalpyValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto enthalpyValue =
|
||||||
mean_field::utils::blocks::enthalpy_field.specific_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::enthalpy_field.specific_term);
|
||||||
|
|
||||||
constexpr auto barotropicConstantValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto barotropicConstantValue =
|
||||||
mean_field::utils::blocks::barotropic_constant_field.mass_normalization_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::barotropic_constant_field
|
||||||
|
.mass_normalization_term);
|
||||||
|
|
||||||
constexpr auto gravityGradientResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto gravityGradientResidual =
|
||||||
mean_field::utils::blocks::gravity_field.gradient_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.gradient_term);
|
||||||
|
|
||||||
constexpr auto gravityPotentialResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto gravityPotentialResidual =
|
||||||
mean_field::utils::blocks::gravity_field.poisson_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
constexpr auto densityResidual =
|
constexpr auto densityResidual =
|
||||||
mean_field::utils::blocks::get_residual_block<CoupledForm>(mean_field::utils::blocks::density_field.mass_term);
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::density_field.mass_term);
|
||||||
|
|
||||||
constexpr auto displacementResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto displacementResidual =
|
||||||
mean_field::utils::blocks::displacement_field.geometry_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::displacement_field.geometry_term);
|
||||||
|
|
||||||
constexpr auto enthalpyResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto enthalpyResidual =
|
||||||
mean_field::utils::blocks::enthalpy_field.specific_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::enthalpy_field.specific_term);
|
||||||
|
|
||||||
constexpr auto massResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto massResidual =
|
||||||
mean_field::utils::blocks::barotropic_constant_field.mass_normalization_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::barotropic_constant_field
|
||||||
|
.mass_normalization_term);
|
||||||
|
|
||||||
[[nodiscard]] mean_field::operators::GravityDisplacementForceLayout make_layout(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mean_field::operators::GravityDisplacementForceLayout
|
||||||
|
make_layout(const mean_field::fem::FEM &f) {
|
||||||
using DomainSchema = gravity_prepared_test_utils::DomainSchema;
|
using DomainSchema = gravity_prepared_test_utils::DomainSchema;
|
||||||
|
|
||||||
const auto densityMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Density>(f);
|
const auto densityMap =
|
||||||
const auto displacementMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Displacement>(f);
|
gravity_prepared_test_utils::make_field_map<mean_field::field::Density>(
|
||||||
|
f);
|
||||||
|
const auto displacementMap = gravity_prepared_test_utils::make_field_map<
|
||||||
|
mean_field::field::Displacement>(f);
|
||||||
const auto gravityFluxMap =
|
const auto gravityFluxMap =
|
||||||
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityFluxFes);
|
mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
const auto gravityPotentialMap =
|
DomainSchema>(*f.gravityFluxFes);
|
||||||
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes);
|
const auto gravityPotentialMap = mean_field::field::make_field_dof_map<
|
||||||
|
mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes);
|
||||||
const auto enthalpyMap =
|
const auto enthalpyMap =
|
||||||
mean_field::field::make_field_dof_map<mean_field::field::Enthalpy, DomainSchema>(*f.enthalpyFes);
|
mean_field::field::make_field_dof_map<mean_field::field::Enthalpy,
|
||||||
|
DomainSchema>(*f.enthalpyFes);
|
||||||
|
|
||||||
const std::array<int, CoupledForm::value_block_count> valueSizes{
|
const std::array<int, CoupledForm::value_block_count> valueSizes{
|
||||||
densityMap.reduced_size(), displacementMap.reduced_size(), gravityFluxMap.reduced_size(),
|
densityMap.reduced_size(), displacementMap.reduced_size(),
|
||||||
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1
|
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(),
|
||||||
};
|
enthalpyMap.reduced_size(), 1};
|
||||||
|
|
||||||
const std::array<int, CoupledForm::residual_block_count> residualSizes{
|
const std::array<int, CoupledForm::residual_block_count> residualSizes{
|
||||||
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
|
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(),
|
||||||
displacementMap.reduced_size(), enthalpyMap.reduced_size(), 1
|
densityMap.reduced_size(), displacementMap.reduced_size(),
|
||||||
};
|
enthalpyMap.reduced_size(), 1};
|
||||||
|
|
||||||
return {valueSizes, residualSizes};
|
return {valueSizes, residualSizes};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_density(
|
[[nodiscard]] mfem::Vector make_density(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
|
|
||||||
mfem::FunctionCoefficient densityCoefficient([phase](const mfem::Vector &position) {
|
mfem::FunctionCoefficient densityCoefficient(
|
||||||
|
[phase](const mfem::Vector &position) {
|
||||||
return 0.82 + 0.07 * std::sin(0.8 * position(0) + phase) +
|
return 0.82 + 0.07 * std::sin(0.8 * position(0) + phase) +
|
||||||
0.05 * std::cos(0.6 * position(1) - 0.3 * phase) + 0.03 * position(2) * position(2);
|
0.05 * std::cos(0.6 * position(1) - 0.3 * phase) +
|
||||||
|
0.03 * position(2) * position(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
densityField.ProjectCoefficient(densityCoefficient);
|
densityField.ProjectCoefficient(densityCoefficient);
|
||||||
@@ -100,15 +112,14 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
return densityTrue;
|
return densityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_density_direction(
|
[[nodiscard]] mfem::Vector make_density_direction(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
|
|
||||||
mfem::FunctionCoefficient densityCoefficient([phase](const mfem::Vector &position) {
|
mfem::FunctionCoefficient densityCoefficient(
|
||||||
return 0.19 * std::sin(0.9 * position(0) + phase) - 0.13 * std::cos(0.7 * position(1) - phase) +
|
[phase](const mfem::Vector &position) {
|
||||||
0.08 * position(2);
|
return 0.19 * std::sin(0.9 * position(0) + phase) -
|
||||||
|
0.13 * std::cos(0.7 * position(1) - phase) + 0.08 * position(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
densityField.ProjectCoefficient(densityCoefficient);
|
densityField.ProjectCoefficient(densityCoefficient);
|
||||||
@@ -118,13 +129,12 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
return densityTrue;
|
return densityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_gravity_gradient(
|
[[nodiscard]] mfem::Vector make_gravity_gradient(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
||||||
|
|
||||||
auto gravityFunction = [phase](const mfem::Vector &position, mfem::Vector &value) {
|
auto gravityFunction = [phase](const mfem::Vector &position,
|
||||||
|
mfem::Vector &value) {
|
||||||
value.SetSize(3);
|
value.SetSize(3);
|
||||||
|
|
||||||
value(0) = 0.31 + 0.08 * position(0) + 0.03 * phase * position(1);
|
value(0) = 0.31 + 0.08 * position(0) + 0.03 * phase * position(1);
|
||||||
@@ -143,13 +153,13 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
return gravityTrue;
|
return gravityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_gravity_gradient_direction(
|
[[nodiscard]] mfem::Vector
|
||||||
const mean_field::fem::FEM &f,
|
make_gravity_gradient_direction(const mean_field::fem::FEM &f,
|
||||||
const double phase
|
const double phase) {
|
||||||
) {
|
|
||||||
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
||||||
|
|
||||||
auto gravityFunction = [phase](const mfem::Vector &position, mfem::Vector &value) {
|
auto gravityFunction = [phase](const mfem::Vector &position,
|
||||||
|
mfem::Vector &value) {
|
||||||
value.SetSize(3);
|
value.SetSize(3);
|
||||||
|
|
||||||
value(0) = 0.14 * std::sin(position(0) + phase) + 0.03 * position(1);
|
value(0) = 0.14 * std::sin(position(0) + phase) + 0.03 * position(1);
|
||||||
@@ -168,26 +178,31 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
return gravityTrue;
|
return gravityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_displacement_direction(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
mfem::Vector direction = gravity_prepared_test_utils::make_displacement(f, 0.83);
|
make_displacement_direction(const mean_field::fem::FEM &f) {
|
||||||
|
mfem::Vector direction =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.83);
|
||||||
|
|
||||||
const mfem::Vector second = gravity_prepared_test_utils::make_displacement(f, 0.29);
|
const mfem::Vector second =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.29);
|
||||||
|
|
||||||
direction -= second;
|
direction -= second;
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_vacuum_only_density(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
|
make_vacuum_only_density(const mean_field::fem::FEM &f) {
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
densityField = 0.0;
|
densityField = 0.0;
|
||||||
|
|
||||||
const int vacuumAttribute = f.domainMapperStateless->GetVacuumElementAttribute();
|
const int vacuumAttribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
|
|
||||||
mfem::Array<int> densityDofs;
|
mfem::Array<int> densityDofs;
|
||||||
int localVacuumElements = 0;
|
int localVacuumElements = 0;
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
f.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
REQUIRE(transformation != nullptr);
|
REQUIRE(transformation != nullptr);
|
||||||
|
|
||||||
@@ -204,7 +219,8 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int globalVacuumElements = 0;
|
int globalVacuumElements = 0;
|
||||||
MPI_Allreduce(&localVacuumElements, &globalVacuumElements, 1, MPI_INT, MPI_SUM, f.mesh->GetComm());
|
MPI_Allreduce(&localVacuumElements, &globalVacuumElements, 1, MPI_INT,
|
||||||
|
MPI_SUM, f.mesh->GetComm());
|
||||||
|
|
||||||
REQUIRE(globalVacuumElements > 0);
|
REQUIRE(globalVacuumElements > 0);
|
||||||
|
|
||||||
@@ -213,65 +229,59 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
return densityTrue;
|
return densityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mean_field::operators::context::gravity_field::GravityFieldRevisions make_revisions() {
|
[[nodiscard]] mean_field::operators::context::gravity_field::
|
||||||
return {
|
GravityFieldRevisions
|
||||||
.discretization = {.value = 3},
|
make_revisions() {
|
||||||
|
return {.discretization = {.value = 3},
|
||||||
.displacement = {.value = 5},
|
.displacement = {.value = 5},
|
||||||
.density = {.value = 7},
|
.density = {.value = 7},
|
||||||
.gravity_gradient = {.value = 11},
|
.gravity_gradient = {.value = 11},
|
||||||
.gravity_potential = {.value = 13}
|
.gravity_potential = {.value = 13}};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare_gravity_context(
|
void prepare_gravity_context(
|
||||||
mean_field::operators::context::gravity_field::GravityFieldLinearizationContext &context,
|
mean_field::operators::context::gravity_field::
|
||||||
const mfem::Vector &density,
|
GravityFieldLinearizationContext &context,
|
||||||
const mfem::Vector &displacement,
|
const mfem::Vector &density, const mfem::Vector &displacement,
|
||||||
const mfem::Vector &gravityGradient,
|
const mfem::Vector &gravityGradient, const mfem::Vector &gravityPotential,
|
||||||
const mfem::Vector &gravityPotential,
|
const mean_field::operators::context::gravity_field::GravityFieldRevisions
|
||||||
const mean_field::operators::context::gravity_field::GravityFieldRevisions &revisions
|
&revisions) {
|
||||||
) {
|
|
||||||
context.Prepare(
|
context.Prepare(
|
||||||
{.density = context.GetDensityMap().gather(density),
|
{.density = context.GetDensityMap().gather(density),
|
||||||
.displacement = context.GetDisplacementMap().gather(displacement),
|
.displacement = context.GetDisplacementMap().gather(displacement),
|
||||||
.gravity_gradient = context.GetGravityGradientMap().gather(gravityGradient),
|
.gravity_gradient =
|
||||||
.gravity_potential = context.GetGravityPotentialMap().gather(gravityPotential)},
|
context.GetGravityGradientMap().gather(gravityGradient),
|
||||||
revisions
|
.gravity_potential =
|
||||||
);
|
context.GetGravityPotentialMap().gather(gravityPotential)},
|
||||||
|
revisions);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double relative_difference(
|
[[nodiscard]] double relative_difference(const mfem::Vector &left,
|
||||||
const mfem::Vector &left,
|
|
||||||
const mfem::Vector &right,
|
const mfem::Vector &right,
|
||||||
const MPI_Comm communicator
|
const MPI_Comm communicator) {
|
||||||
) {
|
MFEM_VERIFY(left.Size() == right.Size(),
|
||||||
MFEM_VERIFY(
|
"Cannot compare gravity-displacement-force vectors with "
|
||||||
left.Size() == right.Size(), "Cannot compare gravity-displacement-force vectors with "
|
"different sizes.");
|
||||||
"different sizes."
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector difference(left);
|
mfem::Vector difference(left);
|
||||||
difference -= right;
|
difference -= right;
|
||||||
|
|
||||||
const double scale = std::max(
|
const double scale =
|
||||||
{gravity_prepared_test_utils::global_norm(left, communicator),
|
std::max({gravity_prepared_test_utils::global_norm(left, communicator),
|
||||||
gravity_prepared_test_utils::global_norm(right, communicator),
|
gravity_prepared_test_utils::global_norm(right, communicator),
|
||||||
100.0 * std::numeric_limits<double>::epsilon()}
|
100.0 * std::numeric_limits<double>::epsilon()});
|
||||||
);
|
|
||||||
|
|
||||||
return gravity_prepared_test_utils::global_norm(difference, communicator) / scale;
|
return gravity_prepared_test_utils::global_norm(difference, communicator) /
|
||||||
|
scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector centered_difference(
|
[[nodiscard]] mfem::Vector centered_difference(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f, const mfem::Vector &baseDensity,
|
||||||
const mfem::Vector &baseDensity,
|
|
||||||
const mfem::Vector &densityDirection,
|
const mfem::Vector &densityDirection,
|
||||||
const mfem::Vector &baseGravityGradient,
|
const mfem::Vector &baseGravityGradient,
|
||||||
const mfem::Vector &gravityGradientDirection,
|
const mfem::Vector &gravityGradientDirection,
|
||||||
const mfem::Vector &baseDisplacement,
|
const mfem::Vector &baseDisplacement,
|
||||||
const mfem::Vector &displacementDirection,
|
const mfem::Vector &displacementDirection, const double step) {
|
||||||
const double step
|
|
||||||
) {
|
|
||||||
mfem::Vector plusDensity(baseDensity);
|
mfem::Vector plusDensity(baseDensity);
|
||||||
plusDensity.Add(step, densityDirection);
|
plusDensity.Add(step, densityDirection);
|
||||||
|
|
||||||
@@ -294,12 +304,12 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
mfem::Vector minusResidual;
|
mfem::Vector minusResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, plusDensity, plusGravity, plusDisplacement, plusResidual
|
f, *f.domainMapperStateless, plusDensity, plusGravity, plusDisplacement,
|
||||||
);
|
plusResidual);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, minusDensity, minusGravity, minusDisplacement, minusResidual
|
f, *f.domainMapperStateless, minusDensity, minusGravity,
|
||||||
);
|
minusDisplacement, minusResidual);
|
||||||
|
|
||||||
plusResidual -= minusResidual;
|
plusResidual -= minusResidual;
|
||||||
plusResidual /= 2.0 * step;
|
plusResidual /= 2.0 * step;
|
||||||
@@ -310,8 +320,7 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
[[nodiscard]] mfem::Vector copy_residual_block(
|
[[nodiscard]] mfem::Vector copy_residual_block(
|
||||||
const mfem::Vector &action,
|
const mfem::Vector &action,
|
||||||
const mean_field::operators::GravityDisplacementForceLayout &layout,
|
const mean_field::operators::GravityDisplacementForceLayout &layout,
|
||||||
const mean_field::utils::blocks::residual_block<index> block
|
const mean_field::utils::blocks::residual_block<index> block) {
|
||||||
) {
|
|
||||||
mfem::Vector result(layout.size(block));
|
mfem::Vector result(layout.size(block));
|
||||||
const int offset = layout.offset(block);
|
const int offset = layout.offset(block);
|
||||||
|
|
||||||
@@ -323,19 +332,18 @@ namespace gravity_displacement_force_test_utils {
|
|||||||
}
|
}
|
||||||
} // namespace gravity_displacement_force_test_utils
|
} // namespace gravity_displacement_force_test_utils
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Gravity Displacement Force Query Includes Every Registered Operand",
|
||||||
"Gravity Displacement Force Query Includes Every Registered Operand",
|
tags::gravity_unit) {
|
||||||
tags::gravity_unit
|
using DisplacementField =
|
||||||
) {
|
mean_field::field::Field<mean_field::field::Displacement>;
|
||||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
|
||||||
|
|
||||||
constexpr int geometryWeightOrder = 4;
|
constexpr int geometryWeightOrder = 4;
|
||||||
|
|
||||||
constexpr mean_field::quadrature::Query query =
|
constexpr mean_field::quadrature::Query query = DisplacementField::make_query<
|
||||||
DisplacementField::make_query<mean_field::field::Displacement::Form::GravityForce>(
|
mean_field::field::Displacement::Form::GravityForce>(
|
||||||
mean_field::quadrature::QuadratureRole::discretization, geometryWeightOrder, {},
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
geometryWeightOrder, {}, mean_field::utils::DOMAINS::STELLAR,
|
||||||
);
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* rho: 2
|
* rho: 2
|
||||||
@@ -348,7 +356,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
STATIC_REQUIRE(query.term == mean_field::quadrature::Term::gravity_force);
|
STATIC_REQUIRE(query.term == mean_field::quadrature::Term::gravity_force);
|
||||||
|
|
||||||
STATIC_REQUIRE(query.role == mean_field::quadrature::QuadratureRole::discretization);
|
STATIC_REQUIRE(query.role ==
|
||||||
|
mean_field::quadrature::QuadratureRole::discretization);
|
||||||
|
|
||||||
STATIC_REQUIRE(query.domain == mean_field::utils::DOMAINS::STELLAR);
|
STATIC_REQUIRE(query.domain == mean_field::utils::DOMAINS::STELLAR);
|
||||||
|
|
||||||
@@ -358,11 +367,9 @@ TEST_CASE(
|
|||||||
STATIC_REQUIRE(*query.base_order == expectedBaseOrder);
|
STATIC_REQUIRE(*query.base_order == expectedBaseOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Gravity Displacement Force Uses Positive Grad-Phi Sign And Excludes "
|
||||||
"Gravity Displacement Force Uses Positive Grad-Phi Sign And Excludes "
|
|
||||||
"Vacuum",
|
"Vacuum",
|
||||||
tags::gravity_kernel_accuracy
|
tags::gravity_kernel_accuracy) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -384,7 +391,8 @@ TEST_CASE(
|
|||||||
value(0) = 1.0;
|
value(0) = 1.0;
|
||||||
};
|
};
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient gravityCoefficient(3, constantGravityFunction);
|
mfem::VectorFunctionCoefficient gravityCoefficient(3,
|
||||||
|
constantGravityFunction);
|
||||||
|
|
||||||
gravityField.ProjectCoefficient(gravityCoefficient);
|
gravityField.ProjectCoefficient(gravityCoefficient);
|
||||||
|
|
||||||
@@ -397,8 +405,8 @@ TEST_CASE(
|
|||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, residual
|
f, *f.domainMapperStateless, density, gravityGradient, displacement,
|
||||||
);
|
residual);
|
||||||
|
|
||||||
mfem::ParGridFunction testField(f.displacementFes.get());
|
mfem::ParGridFunction testField(f.displacementFes.get());
|
||||||
testField.ProjectCoefficient(gravityCoefficient);
|
testField.ProjectCoefficient(gravityCoefficient);
|
||||||
@@ -406,54 +414,57 @@ TEST_CASE(
|
|||||||
mfem::Vector testDirection;
|
mfem::Vector testDirection;
|
||||||
testField.GetTrueDofs(testDirection);
|
testField.GetTrueDofs(testDirection);
|
||||||
|
|
||||||
const double signedWork = gravity_prepared_test_utils::global_dot(residual, testDirection, f.mesh->GetComm());
|
const double signedWork = gravity_prepared_test_utils::global_dot(
|
||||||
|
residual, testDirection, f.mesh->GetComm());
|
||||||
|
|
||||||
INFO("Constant +x gravity-force work = " << signedWork);
|
INFO("Constant +x gravity-force work = " << signedWork);
|
||||||
CHECK(signedWork > 0.0);
|
CHECK(signedWork > 0.0);
|
||||||
|
|
||||||
const mfem::Vector vacuumDensity = gravity_displacement_force_test_utils::make_vacuum_only_density(f);
|
const mfem::Vector vacuumDensity =
|
||||||
|
gravity_displacement_force_test_utils::make_vacuum_only_density(f);
|
||||||
|
|
||||||
mfem::Vector vacuumResidual;
|
mfem::Vector vacuumResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, vacuumDensity, gravityGradient, displacement, vacuumResidual
|
f, *f.domainMapperStateless, vacuumDensity, gravityGradient, displacement,
|
||||||
);
|
vacuumResidual);
|
||||||
|
|
||||||
CHECK(gravity_prepared_test_utils::global_norm(vacuumResidual, f.mesh->GetComm()) == 0.0);
|
CHECK(gravity_prepared_test_utils::global_norm(vacuumResidual,
|
||||||
|
f.mesh->GetComm()) == 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Gravity Displacement Force Reuses Shared Gravity Revisions",
|
||||||
"Prepared Gravity Displacement Force Reuses Shared Gravity Revisions",
|
tags::gravity_prepared) {
|
||||||
tags::gravity_prepared
|
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
|
|
||||||
mfem::Vector density = gravity_displacement_force_test_utils::make_density(f, 0.31);
|
mfem::Vector density =
|
||||||
|
gravity_displacement_force_test_utils::make_density(f, 0.31);
|
||||||
|
|
||||||
const mfem::Vector gravityGradient = gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.47);
|
const mfem::Vector gravityGradient =
|
||||||
|
gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.47);
|
||||||
|
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.61);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.61);
|
||||||
|
|
||||||
mfem::Vector gravityPotential(f.gravityPotentialFes->GetTrueVSize());
|
mfem::Vector gravityPotential(f.gravityPotentialFes->GetTrueVSize());
|
||||||
gravityPotential = 0.0;
|
gravityPotential = 0.0;
|
||||||
|
|
||||||
auto revisions = gravity_displacement_force_test_utils::make_revisions();
|
auto revisions = gravity_displacement_force_test_utils::make_revisions();
|
||||||
|
|
||||||
mean_field::operators::context::gravity_field::GravityFieldLinearizationContext gravityContext(
|
mean_field::operators::context::gravity_field::
|
||||||
f, *f.domainMapperStateless
|
GravityFieldLinearizationContext gravityContext(f,
|
||||||
);
|
*f.domainMapperStateless);
|
||||||
|
|
||||||
gravity_displacement_force_test_utils::prepare_gravity_context(
|
gravity_displacement_force_test_utils::prepare_gravity_context(
|
||||||
gravityContext, density, displacement, gravityGradient, gravityPotential, revisions
|
gravityContext, density, displacement, gravityGradient, gravityPotential,
|
||||||
);
|
revisions);
|
||||||
|
|
||||||
mean_field::operators::PreparedGravityDisplacementForceOperator preparedOperator(
|
mean_field::operators::PreparedGravityDisplacementForceOperator
|
||||||
f, *f.domainMapperStateless, gravityContext
|
preparedOperator(f, *f.domainMapperStateless, gravityContext);
|
||||||
);
|
|
||||||
|
|
||||||
const auto initialReport = preparedOperator.Prepare();
|
const auto initialReport = preparedOperator.Prepare();
|
||||||
REQUIRE(initialReport.DidAnyWork());
|
REQUIRE(initialReport.DidAnyWork());
|
||||||
@@ -465,24 +476,23 @@ TEST_CASE(
|
|||||||
preparedOperator.BuildResidual(preparedResidual);
|
preparedOperator.BuildResidual(preparedResidual);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, kernelResidual
|
f, *f.domainMapperStateless, density, gravityGradient, displacement,
|
||||||
);
|
kernelResidual);
|
||||||
|
|
||||||
const mfem::Vector kernelResidualReduced = gravityContext.GetDisplacementMap().gather(kernelResidual);
|
const mfem::Vector kernelResidualReduced =
|
||||||
|
gravityContext.GetDisplacementMap().gather(kernelResidual);
|
||||||
|
|
||||||
CHECK(
|
CHECK(gravity_displacement_force_test_utils::relative_difference(
|
||||||
gravity_displacement_force_test_utils::relative_difference(
|
preparedResidual, kernelResidualReduced, f.mesh->GetComm()) <
|
||||||
preparedResidual, kernelResidualReduced, f.mesh->GetComm()
|
2.0e-12);
|
||||||
) < 2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
CHECK_FALSE(preparedOperator.Prepare().DidAnyWork());
|
CHECK_FALSE(preparedOperator.Prepare().DidAnyWork());
|
||||||
|
|
||||||
++revisions.gravity_potential.value;
|
++revisions.gravity_potential.value;
|
||||||
|
|
||||||
gravity_displacement_force_test_utils::prepare_gravity_context(
|
gravity_displacement_force_test_utils::prepare_gravity_context(
|
||||||
gravityContext, density, displacement, gravityGradient, gravityPotential, revisions
|
gravityContext, density, displacement, gravityGradient, gravityPotential,
|
||||||
);
|
revisions);
|
||||||
|
|
||||||
CHECK(preparedOperator.IsPrepared());
|
CHECK(preparedOperator.IsPrepared());
|
||||||
CHECK_FALSE(preparedOperator.Prepare().DidAnyWork());
|
CHECK_FALSE(preparedOperator.Prepare().DidAnyWork());
|
||||||
@@ -491,8 +501,8 @@ TEST_CASE(
|
|||||||
++revisions.density.value;
|
++revisions.density.value;
|
||||||
|
|
||||||
gravity_displacement_force_test_utils::prepare_gravity_context(
|
gravity_displacement_force_test_utils::prepare_gravity_context(
|
||||||
gravityContext, density, displacement, gravityGradient, gravityPotential, revisions
|
gravityContext, density, displacement, gravityGradient, gravityPotential,
|
||||||
);
|
revisions);
|
||||||
|
|
||||||
CHECK_FALSE(preparedOperator.IsPrepared());
|
CHECK_FALSE(preparedOperator.IsPrepared());
|
||||||
|
|
||||||
@@ -506,73 +516,79 @@ TEST_CASE(
|
|||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Gravity Displacement Force Jacobian Matches All Columns And Centered "
|
"Gravity Displacement Force Jacobian Matches All Columns And Centered "
|
||||||
"Differences",
|
"Differences",
|
||||||
tags::gravity_prepared_jacobian_accuracy
|
tags::gravity_prepared_jacobian_accuracy) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
|
|
||||||
const mfem::Vector density = gravity_displacement_force_test_utils::make_density(f, 0.37);
|
const mfem::Vector density =
|
||||||
|
gravity_displacement_force_test_utils::make_density(f, 0.37);
|
||||||
|
|
||||||
const mfem::Vector densityDirection = gravity_displacement_force_test_utils::make_density_direction(f, 0.53);
|
const mfem::Vector densityDirection =
|
||||||
|
gravity_displacement_force_test_utils::make_density_direction(f, 0.53);
|
||||||
|
|
||||||
const mfem::Vector gravityGradient = gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.67);
|
const mfem::Vector gravityGradient =
|
||||||
|
gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.67);
|
||||||
|
|
||||||
const mfem::Vector gravityGradientDirection =
|
const mfem::Vector gravityGradientDirection =
|
||||||
gravity_displacement_force_test_utils::make_gravity_gradient_direction(f, 0.71);
|
gravity_displacement_force_test_utils::make_gravity_gradient_direction(
|
||||||
|
f, 0.71);
|
||||||
|
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.59);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.59);
|
||||||
|
|
||||||
const mfem::Vector displacementDirection = gravity_displacement_force_test_utils::make_displacement_direction(f);
|
const mfem::Vector displacementDirection =
|
||||||
|
gravity_displacement_force_test_utils::make_displacement_direction(f);
|
||||||
|
|
||||||
mfem::Vector gravityPotential(f.gravityPotentialFes->GetTrueVSize());
|
mfem::Vector gravityPotential(f.gravityPotentialFes->GetTrueVSize());
|
||||||
gravityPotential = 0.0;
|
gravityPotential = 0.0;
|
||||||
|
|
||||||
mean_field::operators::context::gravity_field::GravityFieldLinearizationContext gravityContext(
|
mean_field::operators::context::gravity_field::
|
||||||
f, *f.domainMapperStateless
|
GravityFieldLinearizationContext gravityContext(f,
|
||||||
);
|
*f.domainMapperStateless);
|
||||||
|
|
||||||
gravity_displacement_force_test_utils::prepare_gravity_context(
|
gravity_displacement_force_test_utils::prepare_gravity_context(
|
||||||
gravityContext, density, displacement, gravityGradient, gravityPotential,
|
gravityContext, density, displacement, gravityGradient, gravityPotential,
|
||||||
gravity_displacement_force_test_utils::make_revisions()
|
gravity_displacement_force_test_utils::make_revisions());
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::PreparedGravityDisplacementForceOperator preparedOperator(
|
mean_field::operators::PreparedGravityDisplacementForceOperator
|
||||||
f, *f.domainMapperStateless, gravityContext
|
preparedOperator(f, *f.domainMapperStateless, gravityContext);
|
||||||
);
|
|
||||||
|
|
||||||
preparedOperator.Prepare();
|
preparedOperator.Prepare();
|
||||||
|
|
||||||
const mfem::Vector densityDirectionReduced = gravityContext.GetDensityMap().gather(densityDirection);
|
const mfem::Vector densityDirectionReduced =
|
||||||
|
gravityContext.GetDensityMap().gather(densityDirection);
|
||||||
const mfem::Vector gravityGradientDirectionReduced =
|
const mfem::Vector gravityGradientDirectionReduced =
|
||||||
gravityContext.GetGravityGradientMap().gather(gravityGradientDirection);
|
gravityContext.GetGravityGradientMap().gather(gravityGradientDirection);
|
||||||
const mfem::Vector displacementDirectionReduced = gravityContext.GetDisplacementMap().gather(displacementDirection);
|
const mfem::Vector displacementDirectionReduced =
|
||||||
|
gravityContext.GetDisplacementMap().gather(displacementDirection);
|
||||||
|
|
||||||
mfem::Vector densityAction;
|
mfem::Vector densityAction;
|
||||||
mfem::Vector gravityAction;
|
mfem::Vector gravityAction;
|
||||||
mfem::Vector displacementAction;
|
mfem::Vector displacementAction;
|
||||||
mfem::Vector completeAction;
|
mfem::Vector completeAction;
|
||||||
|
|
||||||
preparedOperator.ApplyDensityJacobianAction(densityDirectionReduced, densityAction);
|
preparedOperator.ApplyDensityJacobianAction(densityDirectionReduced,
|
||||||
|
densityAction);
|
||||||
|
|
||||||
preparedOperator.ApplyGravityGradientJacobianAction(gravityGradientDirectionReduced, gravityAction);
|
preparedOperator.ApplyGravityGradientJacobianAction(
|
||||||
|
gravityGradientDirectionReduced, gravityAction);
|
||||||
|
|
||||||
preparedOperator.ApplyDisplacementJacobianAction(displacementDirectionReduced, displacementAction);
|
preparedOperator.ApplyDisplacementJacobianAction(displacementDirectionReduced,
|
||||||
|
displacementAction);
|
||||||
|
|
||||||
preparedOperator.ApplyCompleteJacobianAction(
|
preparedOperator.ApplyCompleteJacobianAction(
|
||||||
densityDirectionReduced, displacementDirectionReduced, gravityGradientDirectionReduced, completeAction
|
densityDirectionReduced, displacementDirectionReduced,
|
||||||
);
|
gravityGradientDirectionReduced, completeAction);
|
||||||
|
|
||||||
mfem::Vector summedColumns(densityAction);
|
mfem::Vector summedColumns(densityAction);
|
||||||
summedColumns += gravityAction;
|
summedColumns += gravityAction;
|
||||||
summedColumns += displacementAction;
|
summedColumns += displacementAction;
|
||||||
|
|
||||||
CHECK(
|
CHECK(gravity_displacement_force_test_utils::relative_difference(
|
||||||
gravity_displacement_force_test_utils::relative_difference(completeAction, summedColumns, f.mesh->GetComm()) <
|
completeAction, summedColumns, f.mesh->GetComm()) < 2.0e-12);
|
||||||
2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector zeroDensity(densityDirection.Size());
|
mfem::Vector zeroDensity(densityDirection.Size());
|
||||||
mfem::Vector zeroGravity(gravityGradientDirection.Size());
|
mfem::Vector zeroGravity(gravityGradientDirection.Size());
|
||||||
@@ -583,41 +599,50 @@ TEST_CASE(
|
|||||||
|
|
||||||
constexpr double step = 1.0e-5;
|
constexpr double step = 1.0e-5;
|
||||||
|
|
||||||
const mfem::Vector densityDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
|
const mfem::Vector densityDifferenceTrue =
|
||||||
f, density, densityDirection, gravityGradient, zeroGravity, displacement, zeroDisplacement, step
|
gravity_displacement_force_test_utils::centered_difference(
|
||||||
);
|
f, density, densityDirection, gravityGradient, zeroGravity,
|
||||||
|
displacement, zeroDisplacement, step);
|
||||||
|
|
||||||
const mfem::Vector gravityDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
|
const mfem::Vector gravityDifferenceTrue =
|
||||||
f, density, zeroDensity, gravityGradient, gravityGradientDirection, displacement, zeroDisplacement, step
|
gravity_displacement_force_test_utils::centered_difference(
|
||||||
);
|
f, density, zeroDensity, gravityGradient, gravityGradientDirection,
|
||||||
|
displacement, zeroDisplacement, step);
|
||||||
|
|
||||||
const mfem::Vector displacementDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
|
const mfem::Vector displacementDifferenceTrue =
|
||||||
f, density, zeroDensity, gravityGradient, zeroGravity, displacement, displacementDirection, step
|
gravity_displacement_force_test_utils::centered_difference(
|
||||||
);
|
f, density, zeroDensity, gravityGradient, zeroGravity, displacement,
|
||||||
|
displacementDirection, step);
|
||||||
|
|
||||||
const mfem::Vector completeDifferenceTrue = gravity_displacement_force_test_utils::centered_difference(
|
const mfem::Vector completeDifferenceTrue =
|
||||||
f, density, densityDirection, gravityGradient, gravityGradientDirection, displacement, displacementDirection,
|
gravity_displacement_force_test_utils::centered_difference(
|
||||||
step
|
f, density, densityDirection, gravityGradient,
|
||||||
);
|
gravityGradientDirection, displacement, displacementDirection, step);
|
||||||
|
|
||||||
const mfem::Vector densityDifference = gravityContext.GetDisplacementMap().gather(densityDifferenceTrue);
|
const mfem::Vector densityDifference =
|
||||||
const mfem::Vector gravityDifference = gravityContext.GetDisplacementMap().gather(gravityDifferenceTrue);
|
gravityContext.GetDisplacementMap().gather(densityDifferenceTrue);
|
||||||
const mfem::Vector displacementDifference = gravityContext.GetDisplacementMap().gather(displacementDifferenceTrue);
|
const mfem::Vector gravityDifference =
|
||||||
const mfem::Vector completeDifference = gravityContext.GetDisplacementMap().gather(completeDifferenceTrue);
|
gravityContext.GetDisplacementMap().gather(gravityDifferenceTrue);
|
||||||
|
const mfem::Vector displacementDifference =
|
||||||
|
gravityContext.GetDisplacementMap().gather(displacementDifferenceTrue);
|
||||||
|
const mfem::Vector completeDifference =
|
||||||
|
gravityContext.GetDisplacementMap().gather(completeDifferenceTrue);
|
||||||
|
|
||||||
const double densityError =
|
const double densityError =
|
||||||
gravity_displacement_force_test_utils::relative_difference(densityAction, densityDifference, f.mesh->GetComm());
|
gravity_displacement_force_test_utils::relative_difference(
|
||||||
|
densityAction, densityDifference, f.mesh->GetComm());
|
||||||
|
|
||||||
const double gravityError =
|
const double gravityError =
|
||||||
gravity_displacement_force_test_utils::relative_difference(gravityAction, gravityDifference, f.mesh->GetComm());
|
gravity_displacement_force_test_utils::relative_difference(
|
||||||
|
gravityAction, gravityDifference, f.mesh->GetComm());
|
||||||
|
|
||||||
const double displacementError = gravity_displacement_force_test_utils::relative_difference(
|
const double displacementError =
|
||||||
displacementAction, displacementDifference, f.mesh->GetComm()
|
gravity_displacement_force_test_utils::relative_difference(
|
||||||
);
|
displacementAction, displacementDifference, f.mesh->GetComm());
|
||||||
|
|
||||||
const double completeError = gravity_displacement_force_test_utils::relative_difference(
|
const double completeError =
|
||||||
completeAction, completeDifference, f.mesh->GetComm()
|
gravity_displacement_force_test_utils::relative_difference(
|
||||||
);
|
completeAction, completeDifference, f.mesh->GetComm());
|
||||||
|
|
||||||
INFO("Density-column centered-difference error = " << densityError);
|
INFO("Density-column centered-difference error = " << densityError);
|
||||||
INFO("Gravity-column centered-difference error = " << gravityError);
|
INFO("Gravity-column centered-difference error = " << gravityError);
|
||||||
@@ -630,70 +655,82 @@ TEST_CASE(
|
|||||||
CHECK(completeError < 3.0e-8);
|
CHECK(completeError < 3.0e-8);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Gravity Displacement Force MFEM Adapter Routes Only R-d",
|
||||||
"Prepared Gravity Displacement Force MFEM Adapter Routes Only R-d",
|
tags::gravity_prepared_unit) {
|
||||||
tags::gravity_prepared_unit
|
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
|
|
||||||
const mfem::Vector density = gravity_displacement_force_test_utils::make_density(f, 0.41);
|
const mfem::Vector density =
|
||||||
|
gravity_displacement_force_test_utils::make_density(f, 0.41);
|
||||||
|
|
||||||
const mfem::Vector densityDirection = gravity_displacement_force_test_utils::make_density_direction(f, 0.57);
|
const mfem::Vector densityDirection =
|
||||||
|
gravity_displacement_force_test_utils::make_density_direction(f, 0.57);
|
||||||
|
|
||||||
const mfem::Vector gravityGradient = gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.63);
|
const mfem::Vector gravityGradient =
|
||||||
|
gravity_displacement_force_test_utils::make_gravity_gradient(f, 0.63);
|
||||||
|
|
||||||
const mfem::Vector gravityGradientDirection =
|
const mfem::Vector gravityGradientDirection =
|
||||||
gravity_displacement_force_test_utils::make_gravity_gradient_direction(f, 0.77);
|
gravity_displacement_force_test_utils::make_gravity_gradient_direction(
|
||||||
|
f, 0.77);
|
||||||
|
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.51);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.51);
|
||||||
|
|
||||||
const mfem::Vector displacementDirection = gravity_displacement_force_test_utils::make_displacement_direction(f);
|
const mfem::Vector displacementDirection =
|
||||||
|
gravity_displacement_force_test_utils::make_displacement_direction(f);
|
||||||
|
|
||||||
mfem::Vector gravityPotential(f.gravityPotentialFes->GetTrueVSize());
|
mfem::Vector gravityPotential(f.gravityPotentialFes->GetTrueVSize());
|
||||||
gravityPotential = 0.0;
|
gravityPotential = 0.0;
|
||||||
|
|
||||||
mean_field::operators::context::gravity_field::GravityFieldLinearizationContext gravityContext(
|
mean_field::operators::context::gravity_field::
|
||||||
f, *f.domainMapperStateless
|
GravityFieldLinearizationContext gravityContext(f,
|
||||||
);
|
*f.domainMapperStateless);
|
||||||
|
|
||||||
gravity_displacement_force_test_utils::prepare_gravity_context(
|
gravity_displacement_force_test_utils::prepare_gravity_context(
|
||||||
gravityContext, density, displacement, gravityGradient, gravityPotential,
|
gravityContext, density, displacement, gravityGradient, gravityPotential,
|
||||||
gravity_displacement_force_test_utils::make_revisions()
|
gravity_displacement_force_test_utils::make_revisions());
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::PreparedGravityDisplacementForceOperator preparedOperator(
|
mean_field::operators::PreparedGravityDisplacementForceOperator
|
||||||
f, *f.domainMapperStateless, gravityContext
|
preparedOperator(f, *f.domainMapperStateless, gravityContext);
|
||||||
);
|
|
||||||
|
|
||||||
preparedOperator.Prepare();
|
preparedOperator.Prepare();
|
||||||
|
|
||||||
const mfem::Vector densityDirectionReduced = gravityContext.GetDensityMap().gather(densityDirection);
|
const mfem::Vector densityDirectionReduced =
|
||||||
|
gravityContext.GetDensityMap().gather(densityDirection);
|
||||||
const mfem::Vector gravityGradientDirectionReduced =
|
const mfem::Vector gravityGradientDirectionReduced =
|
||||||
gravityContext.GetGravityGradientMap().gather(gravityGradientDirection);
|
gravityContext.GetGravityGradientMap().gather(gravityGradientDirection);
|
||||||
const mfem::Vector displacementDirectionReduced = gravityContext.GetDisplacementMap().gather(displacementDirection);
|
const mfem::Vector displacementDirectionReduced =
|
||||||
|
gravityContext.GetDisplacementMap().gather(displacementDirection);
|
||||||
|
|
||||||
const auto layout = gravity_displacement_force_test_utils::make_layout(f);
|
const auto layout = gravity_displacement_force_test_utils::make_layout(f);
|
||||||
|
|
||||||
mean_field::operators::PreparedGravityDisplacementForceJacobianOperator adapter(layout, preparedOperator);
|
mean_field::operators::PreparedGravityDisplacementForceJacobianOperator
|
||||||
|
adapter(layout, preparedOperator);
|
||||||
|
|
||||||
mfem::BlockVector direction(layout.value_offsets());
|
mfem::BlockVector direction(layout.value_offsets());
|
||||||
direction = 0.0;
|
direction = 0.0;
|
||||||
|
|
||||||
direction.GetBlock(gravity_displacement_force_test_utils::densityValue) = densityDirectionReduced;
|
direction.GetBlock(gravity_displacement_force_test_utils::densityValue) =
|
||||||
|
densityDirectionReduced;
|
||||||
|
|
||||||
direction.GetBlock(gravity_displacement_force_test_utils::displacementValue) = displacementDirectionReduced;
|
direction.GetBlock(gravity_displacement_force_test_utils::displacementValue) =
|
||||||
|
displacementDirectionReduced;
|
||||||
|
|
||||||
direction.GetBlock(gravity_displacement_force_test_utils::gravityGradientValue) = gravityGradientDirectionReduced;
|
direction.GetBlock(
|
||||||
|
gravity_displacement_force_test_utils::gravityGradientValue) =
|
||||||
|
gravityGradientDirectionReduced;
|
||||||
|
|
||||||
direction.GetBlock(gravity_displacement_force_test_utils::gravityPotentialValue) = 0.29;
|
direction.GetBlock(
|
||||||
|
gravity_displacement_force_test_utils::gravityPotentialValue) = 0.29;
|
||||||
|
|
||||||
direction.GetBlock(gravity_displacement_force_test_utils::enthalpyValue) = -0.37;
|
direction.GetBlock(gravity_displacement_force_test_utils::enthalpyValue) =
|
||||||
|
-0.37;
|
||||||
|
|
||||||
direction.GetBlock(gravity_displacement_force_test_utils::barotropicConstantValue) = 0.43;
|
direction.GetBlock(
|
||||||
|
gravity_displacement_force_test_utils::barotropicConstantValue) = 0.43;
|
||||||
|
|
||||||
mfem::Vector action;
|
mfem::Vector action;
|
||||||
adapter.Mult(direction, action);
|
adapter.Mult(direction, action);
|
||||||
@@ -701,39 +738,36 @@ TEST_CASE(
|
|||||||
mfem::Vector expectedDisplacementAction;
|
mfem::Vector expectedDisplacementAction;
|
||||||
|
|
||||||
preparedOperator.ApplyCompleteJacobianAction(
|
preparedOperator.ApplyCompleteJacobianAction(
|
||||||
densityDirectionReduced, displacementDirectionReduced, gravityGradientDirectionReduced,
|
densityDirectionReduced, displacementDirectionReduced,
|
||||||
expectedDisplacementAction
|
gravityGradientDirectionReduced, expectedDisplacementAction);
|
||||||
);
|
|
||||||
|
|
||||||
const mfem::Vector actualDisplacementAction = gravity_displacement_force_test_utils::copy_residual_block(
|
const mfem::Vector actualDisplacementAction =
|
||||||
action, layout, gravity_displacement_force_test_utils::displacementResidual
|
gravity_displacement_force_test_utils::copy_residual_block(
|
||||||
);
|
action, layout,
|
||||||
|
gravity_displacement_force_test_utils::displacementResidual);
|
||||||
|
|
||||||
CHECK(
|
CHECK(gravity_displacement_force_test_utils::relative_difference(
|
||||||
gravity_displacement_force_test_utils::relative_difference(
|
actualDisplacementAction, expectedDisplacementAction,
|
||||||
actualDisplacementAction, expectedDisplacementAction, f.mesh->GetComm()
|
f.mesh->GetComm()) < 2.0e-12);
|
||||||
) < 2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
const std::array<mfem::Vector, 5> zeroRows{
|
const std::array<mfem::Vector, 5> zeroRows{
|
||||||
gravity_displacement_force_test_utils::copy_residual_block(
|
gravity_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, gravity_displacement_force_test_utils::gravityGradientResidual
|
action, layout,
|
||||||
),
|
gravity_displacement_force_test_utils::gravityGradientResidual),
|
||||||
gravity_displacement_force_test_utils::copy_residual_block(
|
gravity_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, gravity_displacement_force_test_utils::gravityPotentialResidual
|
action, layout,
|
||||||
),
|
gravity_displacement_force_test_utils::gravityPotentialResidual),
|
||||||
gravity_displacement_force_test_utils::copy_residual_block(
|
gravity_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, gravity_displacement_force_test_utils::densityResidual
|
action, layout,
|
||||||
),
|
gravity_displacement_force_test_utils::densityResidual),
|
||||||
gravity_displacement_force_test_utils::copy_residual_block(
|
gravity_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, gravity_displacement_force_test_utils::enthalpyResidual
|
action, layout,
|
||||||
),
|
gravity_displacement_force_test_utils::enthalpyResidual),
|
||||||
gravity_displacement_force_test_utils::copy_residual_block(
|
gravity_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, gravity_displacement_force_test_utils::massResidual
|
action, layout, gravity_displacement_force_test_utils::massResidual)};
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const mfem::Vector &row : zeroRows) {
|
for (const mfem::Vector &row : zeroRows) {
|
||||||
CHECK(gravity_prepared_test_utils::global_norm(row, f.mesh->GetComm()) == 0.0);
|
CHECK(gravity_prepared_test_utils::global_norm(row, f.mesh->GetComm()) ==
|
||||||
|
0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,25 +20,17 @@ namespace gravity_displacement_force_analytic_test_utils {
|
|||||||
return (4.0 / 3.0) * std::numbers::pi * radius * radius * radius;
|
return (4.0 / 3.0) * std::numbers::pi * radius * radius * radius;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double determinant(
|
[[nodiscard]] double determinant(const std::array<double, 3> &scales) {
|
||||||
const std::array<
|
|
||||||
double,
|
|
||||||
3> &scales
|
|
||||||
) {
|
|
||||||
return scales[0] * scales[1] * scales[2];
|
return scales[0] * scales[1] * scales[2];
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double relative_scalar_error(
|
[[nodiscard]] double relative_scalar_error(const double computed,
|
||||||
const double computed,
|
const double expected) {
|
||||||
const double expected
|
|
||||||
) {
|
|
||||||
return std::abs(computed - expected) / std::max(std::abs(expected), 1.0e-30);
|
return std::abs(computed - expected) / std::max(std::abs(expected), 1.0e-30);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_constant_density(
|
[[nodiscard]] mfem::Vector make_constant_density(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double densityValue) {
|
||||||
const double densityValue
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
mfem::ConstantCoefficient densityCoefficient(densityValue);
|
mfem::ConstantCoefficient densityCoefficient(densityValue);
|
||||||
densityField.ProjectCoefficient(densityCoefficient);
|
densityField.ProjectCoefficient(densityCoefficient);
|
||||||
@@ -48,23 +40,21 @@ namespace gravity_displacement_force_analytic_test_utils {
|
|||||||
return densityTrue;
|
return densityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_reference_gravity(
|
[[nodiscard]] mfem::Vector
|
||||||
const mean_field::fem::FEM &f,
|
make_reference_gravity(const mean_field::fem::FEM &f,
|
||||||
const std::array<
|
const std::array<double, 3> &referenceGravity) {
|
||||||
double,
|
|
||||||
3> &referenceGravity
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient gravityCoefficient(
|
mfem::VectorFunctionCoefficient gravityCoefficient(
|
||||||
f.mesh->Dimension(), [referenceGravity](const mfem::Vector &, mfem::Vector &value) {
|
f.mesh->Dimension(),
|
||||||
|
[referenceGravity](const mfem::Vector &, mfem::Vector &value) {
|
||||||
value.SetSize(3);
|
value.SetSize(3);
|
||||||
|
|
||||||
for (int component = 0; component < 3; ++component) {
|
for (int component = 0; component < 3; ++component) {
|
||||||
value(component) = referenceGravity[static_cast<std::size_t>(component)];
|
value(component) =
|
||||||
|
referenceGravity[static_cast<std::size_t>(component)];
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
gravityField.ProjectCoefficient(gravityCoefficient);
|
gravityField.ProjectCoefficient(gravityCoefficient);
|
||||||
|
|
||||||
@@ -73,21 +63,19 @@ namespace gravity_displacement_force_analytic_test_utils {
|
|||||||
return gravityTrue;
|
return gravityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_radial_gravity(
|
[[nodiscard]] mfem::Vector make_radial_gravity(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double radialCoefficient) {
|
||||||
const double radialCoefficient
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
mfem::ParGridFunction gravityField(f.gravityFluxFes.get());
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient gravityCoefficient(
|
mfem::VectorFunctionCoefficient gravityCoefficient(
|
||||||
f.mesh->Dimension(), [radialCoefficient](const mfem::Vector &position, mfem::Vector &value) {
|
f.mesh->Dimension(),
|
||||||
|
[radialCoefficient](const mfem::Vector &position, mfem::Vector &value) {
|
||||||
value.SetSize(position.Size());
|
value.SetSize(position.Size());
|
||||||
|
|
||||||
for (int component = 0; component < position.Size(); ++component) {
|
for (int component = 0; component < position.Size(); ++component) {
|
||||||
value(component) = radialCoefficient * position(component);
|
value(component) = radialCoefficient * position(component);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
gravityField.ProjectCoefficient(gravityCoefficient);
|
gravityField.ProjectCoefficient(gravityCoefficient);
|
||||||
|
|
||||||
@@ -96,23 +84,22 @@ namespace gravity_displacement_force_analytic_test_utils {
|
|||||||
return gravityTrue;
|
return gravityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_affine_displacement(
|
[[nodiscard]] mfem::Vector
|
||||||
const mean_field::fem::FEM &f,
|
make_affine_displacement(const mean_field::fem::FEM &f,
|
||||||
const std::array<
|
const std::array<double, 3> &scales) {
|
||||||
double,
|
|
||||||
3> &scales
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction displacementField(f.displacementFes.get());
|
mfem::ParGridFunction displacementField(f.displacementFes.get());
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient displacementCoefficient(
|
mfem::VectorFunctionCoefficient displacementCoefficient(
|
||||||
f.mesh->Dimension(), [scales](const mfem::Vector &position, mfem::Vector &value) {
|
f.mesh->Dimension(),
|
||||||
|
[scales](const mfem::Vector &position, mfem::Vector &value) {
|
||||||
value.SetSize(position.Size());
|
value.SetSize(position.Size());
|
||||||
|
|
||||||
for (int component = 0; component < position.Size(); ++component) {
|
for (int component = 0; component < position.Size(); ++component) {
|
||||||
value(component) = (scales[static_cast<std::size_t>(component)] - 1.0) * position(component);
|
value(component) =
|
||||||
|
(scales[static_cast<std::size_t>(component)] - 1.0) *
|
||||||
|
position(component);
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
displacementField.ProjectCoefficient(displacementCoefficient);
|
displacementField.ProjectCoefficient(displacementCoefficient);
|
||||||
|
|
||||||
@@ -121,19 +108,18 @@ namespace gravity_displacement_force_analytic_test_utils {
|
|||||||
return displacementTrue;
|
return displacementTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_constant_test_direction(
|
[[nodiscard]] mfem::Vector
|
||||||
const mean_field::fem::FEM &f,
|
make_constant_test_direction(const mean_field::fem::FEM &f,
|
||||||
const int selectedComponent
|
const int selectedComponent) {
|
||||||
) {
|
|
||||||
mfem::ParGridFunction testField(f.displacementFes.get());
|
mfem::ParGridFunction testField(f.displacementFes.get());
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient testCoefficient(
|
mfem::VectorFunctionCoefficient testCoefficient(
|
||||||
f.mesh->Dimension(), [selectedComponent](const mfem::Vector &position, mfem::Vector &value) {
|
f.mesh->Dimension(),
|
||||||
|
[selectedComponent](const mfem::Vector &position, mfem::Vector &value) {
|
||||||
value.SetSize(position.Size());
|
value.SetSize(position.Size());
|
||||||
value = 0.0;
|
value = 0.0;
|
||||||
value(selectedComponent) = 1.0;
|
value(selectedComponent) = 1.0;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
testField.ProjectCoefficient(testCoefficient);
|
testField.ProjectCoefficient(testCoefficient);
|
||||||
|
|
||||||
@@ -142,12 +128,13 @@ namespace gravity_displacement_force_analytic_test_utils {
|
|||||||
return testTrue;
|
return testTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_dilation_test_direction(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
|
make_dilation_test_direction(const mean_field::fem::FEM &f) {
|
||||||
mfem::ParGridFunction testField(f.displacementFes.get());
|
mfem::ParGridFunction testField(f.displacementFes.get());
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient testCoefficient(
|
mfem::VectorFunctionCoefficient testCoefficient(
|
||||||
f.mesh->Dimension(), [](const mfem::Vector &position, mfem::Vector &value) { value = position; }
|
f.mesh->Dimension(), [](const mfem::Vector &position,
|
||||||
);
|
mfem::Vector &value) { value = position; });
|
||||||
|
|
||||||
testField.ProjectCoefficient(testCoefficient);
|
testField.ProjectCoefficient(testCoefficient);
|
||||||
|
|
||||||
@@ -156,57 +143,64 @@ namespace gravity_displacement_force_analytic_test_utils {
|
|||||||
return testTrue;
|
return testTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_mass_normalized_density(
|
void set_mass_normalized_density(mean_field::fem::FEM &f,
|
||||||
mean_field::fem::FEM &f,
|
|
||||||
const double targetMass,
|
const double targetMass,
|
||||||
mfem::ParGridFunction &densityField
|
mfem::ParGridFunction &densityField) {
|
||||||
) {
|
const mfem::Vector stellarDensityTrue =
|
||||||
const mfem::Vector stellarDensityTrue = gravity_prepared_test_utils::make_domain_supported_density(f, true);
|
gravity_prepared_test_utils::make_domain_supported_density(f, true);
|
||||||
|
|
||||||
densityField.SetFromTrueDofs(stellarDensityTrue);
|
densityField.SetFromTrueDofs(stellarDensityTrue);
|
||||||
|
|
||||||
const double unnormalizedMass =
|
const double unnormalizedMass =
|
||||||
mean_field::analysis::domain_integrate_grid_function(f, densityField, mean_field::utils::DOMAINS::STELLAR);
|
mean_field::analysis::domain_integrate_grid_function(
|
||||||
|
f, densityField, mean_field::utils::DOMAINS::STELLAR);
|
||||||
|
|
||||||
MFEM_VERIFY(unnormalizedMass > 0.0, "The analytic gravity-force test obtained non-positive mass.");
|
MFEM_VERIFY(unnormalizedMass > 0.0,
|
||||||
|
"The analytic gravity-force test obtained non-positive mass.");
|
||||||
|
|
||||||
densityField *= targetMass / unnormalizedMass;
|
densityField *= targetMass / unnormalizedMass;
|
||||||
}
|
}
|
||||||
} // namespace gravity_displacement_force_analytic_test_utils
|
} // namespace gravity_displacement_force_analytic_test_utils
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Gravity Displacement Force Matches Analytic Affine Resultants",
|
||||||
"Gravity Displacement Force Matches Analytic Affine Resultants",
|
tags::gravity &tags::accuracy &tags::analytic_comparison
|
||||||
tags::gravity &tags::accuracy &tags::analytic_comparison &tags::integration
|
&tags::integration) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
REQUIRE(f.domainMapperStateless != nullptr);
|
REQUIRE(f.domainMapperStateless != nullptr);
|
||||||
REQUIRE(f.mapping != nullptr);
|
REQUIRE(f.domainMapperStateless != nullptr);
|
||||||
|
|
||||||
constexpr double densityValue = 1.37;
|
constexpr double densityValue = 1.37;
|
||||||
|
|
||||||
constexpr std::array<double, 3> physicalGravity{0.31, -0.47, 0.22};
|
constexpr std::array<double, 3> physicalGravity{0.31, -0.47, 0.22};
|
||||||
|
|
||||||
constexpr std::array<gravity_displacement_force_analytic_test_utils::AffineCase, 3> affineCases{
|
constexpr std::array<
|
||||||
{{.name = "identity geometry", .scales = {1.0, 1.0, 1.0}},
|
gravity_displacement_force_analytic_test_utils::AffineCase, 3>
|
||||||
{.name = "volume-preserving affine geometry", .scales = {1.14, 0.93, 1.0 / (1.14 * 0.93)}},
|
affineCases{{{.name = "identity geometry", .scales = {1.0, 1.0, 1.0}},
|
||||||
{.name = "volume-changing affine geometry", .scales = {1.11, 0.96, 1.07}}}
|
{.name = "volume-preserving affine geometry",
|
||||||
};
|
.scales = {1.14, 0.93, 1.0 / (1.14 * 0.93)}},
|
||||||
|
{.name = "volume-changing affine geometry",
|
||||||
|
.scales = {1.11, 0.96, 1.07}}}};
|
||||||
|
|
||||||
const mfem::Vector density = gravity_displacement_force_analytic_test_utils::make_constant_density(f, densityValue);
|
const mfem::Vector density =
|
||||||
|
gravity_displacement_force_analytic_test_utils::make_constant_density(
|
||||||
|
f, densityValue);
|
||||||
|
|
||||||
const double referenceVolume =
|
const double referenceVolume =
|
||||||
gravity_displacement_force_analytic_test_utils::analytic_sphere_volume(mean_field::utils::RADIUS);
|
gravity_displacement_force_analytic_test_utils::analytic_sphere_volume(
|
||||||
|
mean_field::utils::RADIUS);
|
||||||
|
|
||||||
constexpr double relativeTolerance = 5.0e-6;
|
constexpr double relativeTolerance = 5.0e-6;
|
||||||
|
|
||||||
for (const gravity_displacement_force_analytic_test_utils::AffineCase &affineCase : affineCases) {
|
for (const gravity_displacement_force_analytic_test_utils::AffineCase
|
||||||
|
&affineCase : affineCases) {
|
||||||
DYNAMIC_SECTION(affineCase.name) {
|
DYNAMIC_SECTION(affineCase.name) {
|
||||||
const double mapDeterminant =
|
const double mapDeterminant =
|
||||||
gravity_displacement_force_analytic_test_utils::determinant(affineCase.scales);
|
gravity_displacement_force_analytic_test_utils::determinant(
|
||||||
|
affineCase.scales);
|
||||||
|
|
||||||
REQUIRE(mapDeterminant > 0.0);
|
REQUIRE(mapDeterminant > 0.0);
|
||||||
|
|
||||||
@@ -222,35 +216,42 @@ TEST_CASE(
|
|||||||
*/
|
*/
|
||||||
for (int component = 0; component < 3; ++component) {
|
for (int component = 0; component < 3; ++component) {
|
||||||
referenceGravity[static_cast<std::size_t>(component)] =
|
referenceGravity[static_cast<std::size_t>(component)] =
|
||||||
mapDeterminant * physicalGravity[static_cast<std::size_t>(component)] /
|
mapDeterminant *
|
||||||
|
physicalGravity[static_cast<std::size_t>(component)] /
|
||||||
affineCase.scales[static_cast<std::size_t>(component)];
|
affineCase.scales[static_cast<std::size_t>(component)];
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::Vector gravityGradient =
|
const mfem::Vector gravityGradient =
|
||||||
gravity_displacement_force_analytic_test_utils::make_reference_gravity(f, referenceGravity);
|
gravity_displacement_force_analytic_test_utils::
|
||||||
|
make_reference_gravity(f, referenceGravity);
|
||||||
|
|
||||||
const mfem::Vector displacement =
|
const mfem::Vector displacement =
|
||||||
gravity_displacement_force_analytic_test_utils::make_affine_displacement(f, affineCase.scales);
|
gravity_displacement_force_analytic_test_utils::
|
||||||
|
make_affine_displacement(f, affineCase.scales);
|
||||||
|
|
||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, residual
|
f, *f.domainMapperStateless, density, gravityGradient, displacement,
|
||||||
);
|
residual);
|
||||||
|
|
||||||
for (int component = 0; component < 3; ++component) {
|
for (int component = 0; component < 3; ++component) {
|
||||||
const mfem::Vector testDirection =
|
const mfem::Vector testDirection =
|
||||||
gravity_displacement_force_analytic_test_utils::make_constant_test_direction(f, component);
|
gravity_displacement_force_analytic_test_utils::
|
||||||
|
make_constant_test_direction(f, component);
|
||||||
|
|
||||||
const double computedResultant =
|
const double computedResultant =
|
||||||
gravity_prepared_test_utils::global_dot(residual, testDirection, f.mesh->GetComm());
|
gravity_prepared_test_utils::global_dot(residual, testDirection,
|
||||||
|
f.mesh->GetComm());
|
||||||
|
|
||||||
const double expectedResultant = densityValue * physicalGravity[static_cast<std::size_t>(component)] *
|
const double expectedResultant =
|
||||||
|
densityValue *
|
||||||
|
physicalGravity[static_cast<std::size_t>(component)] *
|
||||||
mapDeterminant * referenceVolume;
|
mapDeterminant * referenceVolume;
|
||||||
|
|
||||||
const double relativeError = gravity_displacement_force_analytic_test_utils::relative_scalar_error(
|
const double relativeError =
|
||||||
computedResultant, expectedResultant
|
gravity_displacement_force_analytic_test_utils::
|
||||||
);
|
relative_scalar_error(computedResultant, expectedResultant);
|
||||||
|
|
||||||
CAPTURE(component);
|
CAPTURE(component);
|
||||||
INFO("Map determinant = " << mapDeterminant);
|
INFO("Map determinant = " << mapDeterminant);
|
||||||
@@ -266,8 +267,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Gravity Displacement Force Reproduces Analytic Homogeneous Sphere Work",
|
"Gravity Displacement Force Reproduces Analytic Homogeneous Sphere Work",
|
||||||
tags::gravity &tags::accuracy &tags::analytic_comparison &tags::integration
|
tags::gravity &tags::accuracy &tags::analytic_comparison
|
||||||
) {
|
&tags::integration) {
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -277,15 +278,21 @@ TEST_CASE(
|
|||||||
|
|
||||||
const double radius = mean_field::utils::RADIUS;
|
const double radius = mean_field::utils::RADIUS;
|
||||||
const double mass = mean_field::utils::MASS;
|
const double mass = mean_field::utils::MASS;
|
||||||
const double volume = gravity_displacement_force_analytic_test_utils::analytic_sphere_volume(radius);
|
const double volume =
|
||||||
|
gravity_displacement_force_analytic_test_utils::analytic_sphere_volume(
|
||||||
|
radius);
|
||||||
|
|
||||||
const double densityValue = mass / volume;
|
const double densityValue = mass / volume;
|
||||||
const double radialGravityCoefficient = mean_field::utils::G * mass / (radius * radius * radius);
|
const double radialGravityCoefficient =
|
||||||
|
mean_field::utils::G * mass / (radius * radius * radius);
|
||||||
|
|
||||||
const mfem::Vector density = gravity_displacement_force_analytic_test_utils::make_constant_density(f, densityValue);
|
const mfem::Vector density =
|
||||||
|
gravity_displacement_force_analytic_test_utils::make_constant_density(
|
||||||
|
f, densityValue);
|
||||||
|
|
||||||
const mfem::Vector gravityGradient =
|
const mfem::Vector gravityGradient =
|
||||||
gravity_displacement_force_analytic_test_utils::make_radial_gravity(f, radialGravityCoefficient);
|
gravity_displacement_force_analytic_test_utils::make_radial_gravity(
|
||||||
|
f, radialGravityCoefficient);
|
||||||
|
|
||||||
mfem::Vector displacement(f.displacementFes->GetTrueVSize());
|
mfem::Vector displacement(f.displacementFes->GetTrueVSize());
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
@@ -293,18 +300,22 @@ TEST_CASE(
|
|||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, density, gravityGradient, displacement, residual
|
f, *f.domainMapperStateless, density, gravityGradient, displacement,
|
||||||
);
|
residual);
|
||||||
|
|
||||||
const mfem::Vector dilationDirection =
|
const mfem::Vector dilationDirection =
|
||||||
gravity_displacement_force_analytic_test_utils::make_dilation_test_direction(f);
|
gravity_displacement_force_analytic_test_utils::
|
||||||
|
make_dilation_test_direction(f);
|
||||||
|
|
||||||
const double computedWork = gravity_prepared_test_utils::global_dot(residual, dilationDirection, f.mesh->GetComm());
|
const double computedWork = gravity_prepared_test_utils::global_dot(
|
||||||
|
residual, dilationDirection, f.mesh->GetComm());
|
||||||
|
|
||||||
const double analyticWork = (3.0 / 5.0) * mean_field::utils::G * mass * mass / radius;
|
const double analyticWork =
|
||||||
|
(3.0 / 5.0) * mean_field::utils::G * mass * mass / radius;
|
||||||
|
|
||||||
const double relativeError =
|
const double relativeError =
|
||||||
gravity_displacement_force_analytic_test_utils::relative_scalar_error(computedWork, analyticWork);
|
gravity_displacement_force_analytic_test_utils::relative_scalar_error(
|
||||||
|
computedWork, analyticWork);
|
||||||
|
|
||||||
INFO("Computed positive gravity work = " << computedWork);
|
INFO("Computed positive gravity work = " << computedWork);
|
||||||
INFO("Analytic positive gravity work = " << analyticWork);
|
INFO("Analytic positive gravity work = " << analyticWork);
|
||||||
@@ -316,10 +327,9 @@ TEST_CASE(
|
|||||||
CHECK(relativeError < 1.0e-5);
|
CHECK(relativeError < 1.0e-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Solved Homogeneous Sphere Gravity Force Matches Analytic Virial",
|
||||||
"Solved Homogeneous Sphere Gravity Force Matches Analytic Virial",
|
tags::gravity &tags::accuracy &tags::analytic_comparison
|
||||||
tags::gravity &tags::accuracy &tags::analytic_comparison &tags::integration &tags::initialization
|
&tags::integration &tags::initialization) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
args.p.rtol = 1.0e-13;
|
args.p.rtol = 1.0e-13;
|
||||||
args.p.max_iters = std::max(args.p.max_iters, 1000);
|
args.p.max_iters = std::max(args.p.max_iters, 1000);
|
||||||
@@ -332,19 +342,20 @@ TEST_CASE(
|
|||||||
mfem::ParGridFunction displacementField(f.displacementFes.get());
|
mfem::ParGridFunction displacementField(f.displacementFes.get());
|
||||||
displacementField = 0.0;
|
displacementField = 0.0;
|
||||||
|
|
||||||
REQUIRE(f.mapping != nullptr);
|
REQUIRE(f.domainMapperStateless != nullptr);
|
||||||
f.mapping->ResetDisplacement();
|
*f.displacement = 0.0;
|
||||||
mean_field::physics::update_stiffness_matrix(f);
|
|
||||||
|
|
||||||
const double radius = mean_field::utils::RADIUS;
|
const double radius = mean_field::utils::RADIUS;
|
||||||
const double mass = mean_field::utils::MASS;
|
const double mass = mean_field::utils::MASS;
|
||||||
|
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
|
|
||||||
gravity_displacement_force_analytic_test_utils::set_mass_normalized_density(f, mass, densityField);
|
gravity_displacement_force_analytic_test_utils::set_mass_normalized_density(
|
||||||
|
f, mass, densityField);
|
||||||
|
|
||||||
const mean_field::physics::GravitySolution gravitySolution =
|
const mean_field::physics::GravitySolution gravitySolution =
|
||||||
mean_field::physics::grav_potential_new(f, args, densityField, displacementField);
|
mean_field::physics::solve_gravity_field(f, args, densityField,
|
||||||
|
displacementField);
|
||||||
|
|
||||||
mfem::Vector densityTrue;
|
mfem::Vector densityTrue;
|
||||||
mfem::Vector gravityGradientTrue;
|
mfem::Vector gravityGradientTrue;
|
||||||
@@ -357,18 +368,22 @@ TEST_CASE(
|
|||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
mean_field::operators::kernels::apply_gravity_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, densityTrue, gravityGradientTrue, displacementTrue, residual
|
f, *f.domainMapperStateless, densityTrue, gravityGradientTrue,
|
||||||
);
|
displacementTrue, residual);
|
||||||
|
|
||||||
const mfem::Vector dilationDirection =
|
const mfem::Vector dilationDirection =
|
||||||
gravity_displacement_force_analytic_test_utils::make_dilation_test_direction(f);
|
gravity_displacement_force_analytic_test_utils::
|
||||||
|
make_dilation_test_direction(f);
|
||||||
|
|
||||||
const double computedWork = gravity_prepared_test_utils::global_dot(residual, dilationDirection, f.mesh->GetComm());
|
const double computedWork = gravity_prepared_test_utils::global_dot(
|
||||||
|
residual, dilationDirection, f.mesh->GetComm());
|
||||||
|
|
||||||
const double analyticWork = (3.0 / 5.0) * mean_field::utils::G * mass * mass / radius;
|
const double analyticWork =
|
||||||
|
(3.0 / 5.0) * mean_field::utils::G * mass * mass / radius;
|
||||||
|
|
||||||
const double relativeError =
|
const double relativeError =
|
||||||
gravity_displacement_force_analytic_test_utils::relative_scalar_error(computedWork, analyticWork);
|
gravity_displacement_force_analytic_test_utils::relative_scalar_error(
|
||||||
|
computedWork, analyticWork);
|
||||||
|
|
||||||
INFO("Solved-field positive gravity work = " << computedWork);
|
INFO("Solved-field positive gravity work = " << computedWork);
|
||||||
INFO("Analytic positive gravity work = " << analyticWork);
|
INFO("Analytic positive gravity work = " << analyticWork);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -9,10 +9,8 @@ import mean_field;
|
|||||||
import test_helpers;
|
import test_helpers;
|
||||||
|
|
||||||
namespace hydrostatic_kernel_test_utils {
|
namespace hydrostatic_kernel_test_utils {
|
||||||
mfem::Vector project_scalar(
|
mfem::Vector project_scalar(mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
mfem::ParFiniteElementSpace &finiteElementSpace,
|
mfem::Coefficient &coefficient) {
|
||||||
mfem::Coefficient &coefficient
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction field(&finiteElementSpace);
|
mfem::ParGridFunction field(&finiteElementSpace);
|
||||||
|
|
||||||
field.ProjectCoefficient(coefficient);
|
field.ProjectCoefficient(coefficient);
|
||||||
@@ -23,10 +21,9 @@ namespace hydrostatic_kernel_test_utils {
|
|||||||
return trueVector;
|
return trueVector;
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector make_constant_field(
|
mfem::Vector
|
||||||
mfem::ParFiniteElementSpace &finiteElementSpace,
|
make_constant_field(mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||||
const double value
|
const double value) {
|
||||||
) {
|
|
||||||
mfem::ConstantCoefficient coefficient(value);
|
mfem::ConstantCoefficient coefficient(value);
|
||||||
|
|
||||||
return project_scalar(finiteElementSpace, coefficient);
|
return project_scalar(finiteElementSpace, coefficient);
|
||||||
@@ -34,7 +31,8 @@ namespace hydrostatic_kernel_test_utils {
|
|||||||
|
|
||||||
mfem::Vector make_enthalpy(const mean_field::fem::FEM &f) {
|
mfem::Vector make_enthalpy(const mean_field::fem::FEM &f) {
|
||||||
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
||||||
return 1.10 + 0.035 * position(0) - 0.021 * position(1) + 0.014 * position(2);
|
return 1.10 + 0.035 * position(0) - 0.021 * position(1) +
|
||||||
|
0.014 * position(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
return project_scalar(*f.enthalpyFes, coefficient);
|
return project_scalar(*f.enthalpyFes, coefficient);
|
||||||
@@ -42,7 +40,8 @@ namespace hydrostatic_kernel_test_utils {
|
|||||||
|
|
||||||
mfem::Vector make_potential(const mean_field::fem::FEM &f) {
|
mfem::Vector make_potential(const mean_field::fem::FEM &f) {
|
||||||
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
||||||
return -0.72 + 0.018 * position(0) + 0.011 * position(1) - 0.025 * position(2);
|
return -0.72 + 0.018 * position(0) + 0.011 * position(1) -
|
||||||
|
0.025 * position(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
return project_scalar(*f.gravityPotentialFes, coefficient);
|
return project_scalar(*f.gravityPotentialFes, coefficient);
|
||||||
@@ -74,11 +73,9 @@ namespace hydrostatic_kernel_test_utils {
|
|||||||
return mean_field::physics::RigidRotation(angularVelocity, center);
|
return mean_field::physics::RigidRotation(angularVelocity, center);
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector centered_difference(
|
mfem::Vector centered_difference(const mfem::Vector &plusResidual,
|
||||||
const mfem::Vector &plusResidual,
|
|
||||||
const mfem::Vector &minusResidual,
|
const mfem::Vector &minusResidual,
|
||||||
const double epsilon
|
const double epsilon) {
|
||||||
) {
|
|
||||||
mfem::Vector difference(plusResidual);
|
mfem::Vector difference(plusResidual);
|
||||||
|
|
||||||
difference -= minusResidual;
|
difference -= minusResidual;
|
||||||
@@ -87,12 +84,10 @@ namespace hydrostatic_kernel_test_utils {
|
|||||||
return difference;
|
return difference;
|
||||||
}
|
}
|
||||||
|
|
||||||
double sum_normalized_error(
|
double sum_normalized_error(const mfem::Vector &computed,
|
||||||
const mfem::Vector &computed,
|
|
||||||
const mfem::Vector &reference,
|
const mfem::Vector &reference,
|
||||||
const double normalization,
|
const double normalization,
|
||||||
const MPI_Comm communicator
|
const MPI_Comm communicator) {
|
||||||
) {
|
|
||||||
mfem::Vector difference(computed);
|
mfem::Vector difference(computed);
|
||||||
difference -= reference;
|
difference -= reference;
|
||||||
|
|
||||||
@@ -105,9 +100,10 @@ namespace hydrostatic_kernel_test_utils {
|
|||||||
|
|
||||||
attributeValues = 0.0;
|
attributeValues = 0.0;
|
||||||
|
|
||||||
const int vacuumAttribute = f.domainMapperStateless->GetVacuumElementAttribute();
|
const int vacuumAttribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
|
|
||||||
for (int attributeIndex = 0; attributeIndex < f.mesh->attributes.Size(); ++attributeIndex) {
|
for (int attributeIndex = 0; attributeIndex < f.mesh->attributes.Size();
|
||||||
|
++attributeIndex) {
|
||||||
const int attribute = f.mesh->attributes[attributeIndex];
|
const int attribute = f.mesh->attributes[attributeIndex];
|
||||||
|
|
||||||
if (attribute == vacuumAttribute) {
|
if (attribute == vacuumAttribute) {
|
||||||
@@ -124,38 +120,31 @@ namespace hydrostatic_kernel_test_utils {
|
|||||||
public:
|
public:
|
||||||
HydrostaticEnthalpyMassOperator(
|
HydrostaticEnthalpyMassOperator(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mfem::Vector &displacementTrue
|
const mfem::Vector &displacementTrue)
|
||||||
)
|
: mfem::Operator(f.enthalpyFes->GetTrueVSize()), f_(f),
|
||||||
: mfem::Operator(f.enthalpyFes->GetTrueVSize()),
|
domainMapper_(domainMapper), displacementTrue_(displacementTrue) {}
|
||||||
f_(f),
|
|
||||||
domainMapper_(domainMapper),
|
|
||||||
displacementTrue_(displacementTrue) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mult(
|
void Mult(const mfem::Vector &input, mfem::Vector &output) const override {
|
||||||
const mfem::Vector &input,
|
mean_field::operators::kernels::
|
||||||
mfem::Vector &output
|
apply_hydrostatic_equilibrium_enthalpy_action(
|
||||||
) const override {
|
f_, domainMapper_, input, displacementTrue_, output);
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_enthalpy_action(
|
|
||||||
f_, domainMapper_, input, displacementTrue_, output
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mean_field::fem::FEM &f_;
|
const mean_field::fem::FEM &f_;
|
||||||
|
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper_;
|
const mean_field::mapping::DomainMapper &domainMapper_;
|
||||||
|
|
||||||
const mfem::Vector &displacementTrue_;
|
const mfem::Vector &displacementTrue_;
|
||||||
};
|
};
|
||||||
} // namespace hydrostatic_kernel_test_utils
|
} // namespace hydrostatic_kernel_test_utils
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Rigid Rotation Potential Derivative Matches Centered Differences",
|
||||||
"Rigid Rotation Potential Derivative Matches Centered Differences",
|
tags::barotrope &tags::hydro &tags::jacobian &tags::physics
|
||||||
tags::barotrope &tags::hydro &tags::jacobian &tags::physics &tags::unit &tags::kernels
|
&tags::unit &tags::kernels) {
|
||||||
) {
|
const mean_field::physics::RigidRotation rotation =
|
||||||
const mean_field::physics::RigidRotation rotation = hydrostatic_kernel_test_utils::make_rotation();
|
hydrostatic_kernel_test_utils::make_rotation();
|
||||||
|
|
||||||
mfem::Vector position(3);
|
mfem::Vector position(3);
|
||||||
mfem::Vector direction(3);
|
mfem::Vector direction(3);
|
||||||
@@ -177,43 +166,52 @@ TEST_CASE(
|
|||||||
minusPosition.Add(-epsilon, direction);
|
minusPosition.Add(-epsilon, direction);
|
||||||
|
|
||||||
const double centeredDerivative =
|
const double centeredDerivative =
|
||||||
(rotation.potential(plusPosition) - rotation.potential(minusPosition)) / (2.0 * epsilon);
|
(rotation.potential(plusPosition) - rotation.potential(minusPosition)) /
|
||||||
|
(2.0 * epsilon);
|
||||||
|
|
||||||
const double analyticDerivative = rotation.potential_directional_derivative(position, direction);
|
const double analyticDerivative =
|
||||||
|
rotation.potential_directional_derivative(position, direction);
|
||||||
|
|
||||||
const double relativeError = std::abs(centeredDerivative - analyticDerivative) /
|
const double relativeError =
|
||||||
std::max(std::abs(analyticDerivative), std::numeric_limits<double>::epsilon());
|
std::abs(centeredDerivative - analyticDerivative) /
|
||||||
|
std::max(std::abs(analyticDerivative),
|
||||||
|
std::numeric_limits<double>::epsilon());
|
||||||
|
|
||||||
INFO("Rigid-rotation derivative error = " << relativeError);
|
INFO("Rigid-rotation derivative error = " << relativeError);
|
||||||
|
|
||||||
CHECK(relativeError < 2.0e-9);
|
CHECK(relativeError < 2.0e-9);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Hydrostatic Residual Vanishes For A Manufactured Rotating State",
|
||||||
"Hydrostatic Residual Vanishes For A Manufactured Rotating State",
|
tags::barotrope &tags::hydro &tags::integration &tags::kernels
|
||||||
tags::barotrope &tags::hydro &tags::integration &tags::kernels &tags::physics &tags::residuals
|
&tags::physics &tags::residuals) {
|
||||||
) {
|
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = hydrostatic_kernel_test_utils::make_rotation();
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
hydrostatic_kernel_test_utils::make_rotation();
|
||||||
|
|
||||||
constexpr double bernoulliConstant = 0.73;
|
constexpr double bernoulliConstant = 0.73;
|
||||||
constexpr double potentialValue = -0.21;
|
constexpr double potentialValue = -0.21;
|
||||||
constexpr double constantOffset = 0.40;
|
constexpr double constantOffset = 0.40;
|
||||||
|
|
||||||
mfem::FunctionCoefficient enthalpyCoefficient([&rotation](const mfem::Vector &position) {
|
mfem::FunctionCoefficient enthalpyCoefficient(
|
||||||
return bernoulliConstant - potentialValue + rotation.potential(position);
|
[&rotation](const mfem::Vector &position) {
|
||||||
|
return bernoulliConstant - potentialValue +
|
||||||
|
rotation.potential(position);
|
||||||
});
|
});
|
||||||
|
|
||||||
const mfem::Vector interpolatedEnthalpy =
|
const mfem::Vector interpolatedEnthalpy =
|
||||||
hydrostatic_kernel_test_utils::project_scalar(*f.enthalpyFes, enthalpyCoefficient);
|
hydrostatic_kernel_test_utils::project_scalar(*f.enthalpyFes,
|
||||||
|
enthalpyCoefficient);
|
||||||
|
|
||||||
const mfem::Vector potential =
|
const mfem::Vector potential =
|
||||||
hydrostatic_kernel_test_utils::make_constant_field(*f.gravityPotentialFes, potentialValue);
|
hydrostatic_kernel_test_utils::make_constant_field(*f.gravityPotentialFes,
|
||||||
|
potentialValue);
|
||||||
|
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 0.0);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.0);
|
||||||
|
|
||||||
const MPI_Comm communicator = f.mesh->GetComm();
|
const MPI_Comm communicator = f.mesh->GetComm();
|
||||||
|
|
||||||
@@ -228,32 +226,33 @@ TEST_CASE(
|
|||||||
mfem::Vector interpolatedReferenceResidual;
|
mfem::Vector interpolatedReferenceResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, interpolatedEnthalpy, potential, displacement, bernoulliConstant,
|
f, *f.domainMapperStateless, rotation, interpolatedEnthalpy, potential,
|
||||||
interpolatedResidual
|
displacement, bernoulliConstant, interpolatedResidual);
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, interpolatedEnthalpy, potential, displacement,
|
f, *f.domainMapperStateless, rotation, interpolatedEnthalpy, potential,
|
||||||
bernoulliConstant + constantOffset, interpolatedReferenceResidual
|
displacement, bernoulliConstant + constantOffset,
|
||||||
);
|
interpolatedReferenceResidual);
|
||||||
|
|
||||||
const double interpolatedResidualNorm =
|
const double interpolatedResidualNorm =
|
||||||
gravity_prepared_test_utils::global_norm(interpolatedResidual, communicator);
|
gravity_prepared_test_utils::global_norm(interpolatedResidual,
|
||||||
|
communicator);
|
||||||
|
|
||||||
const double interpolatedReferenceNorm =
|
const double interpolatedReferenceNorm =
|
||||||
gravity_prepared_test_utils::global_norm(interpolatedReferenceResidual, communicator);
|
gravity_prepared_test_utils::global_norm(interpolatedReferenceResidual,
|
||||||
|
communicator);
|
||||||
|
|
||||||
REQUIRE(interpolatedReferenceNorm > 1.0e-12);
|
REQUIRE(interpolatedReferenceNorm > 1.0e-12);
|
||||||
|
|
||||||
const double representationFloor = interpolatedResidualNorm / interpolatedReferenceNorm;
|
const double representationFloor =
|
||||||
|
interpolatedResidualNorm / interpolatedReferenceNorm;
|
||||||
|
|
||||||
INFO("Interpolated rotating-state residual norm = " << interpolatedResidualNorm);
|
INFO("Interpolated rotating-state residual norm = "
|
||||||
|
<< interpolatedResidualNorm);
|
||||||
|
|
||||||
INFO(
|
INFO("Interpolated rotating-state relative "
|
||||||
"Interpolated rotating-state relative "
|
|
||||||
"representation floor = "
|
"representation floor = "
|
||||||
<< representationFloor
|
<< representationFloor);
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This remains an independent physical/sign check. A wrong
|
* This remains an independent physical/sign check. A wrong
|
||||||
@@ -276,9 +275,8 @@ TEST_CASE(
|
|||||||
* side is in the range of M_h. Starting CG from zero keeps the
|
* side is in the range of M_h. Starting CG from zero keeps the
|
||||||
* iteration in the active stellar subspace.
|
* iteration in the active stellar subspace.
|
||||||
*/
|
*/
|
||||||
hydrostatic_kernel_test_utils::HydrostaticEnthalpyMassOperator enthalpyMassOperator(
|
hydrostatic_kernel_test_utils::HydrostaticEnthalpyMassOperator
|
||||||
f, *f.domainMapperStateless, displacement
|
enthalpyMassOperator(f, *f.domainMapperStateless, displacement);
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector correctionRightHandSide(interpolatedResidual);
|
mfem::Vector correctionRightHandSide(interpolatedResidual);
|
||||||
|
|
||||||
@@ -299,11 +297,14 @@ TEST_CASE(
|
|||||||
|
|
||||||
projectionSolver.Mult(correctionRightHandSide, enthalpyCorrection);
|
projectionSolver.Mult(correctionRightHandSide, enthalpyCorrection);
|
||||||
|
|
||||||
INFO("Discrete-equilibrium projection converged = " << projectionSolver.GetConverged());
|
INFO("Discrete-equilibrium projection converged = "
|
||||||
|
<< projectionSolver.GetConverged());
|
||||||
|
|
||||||
INFO("Discrete-equilibrium projection iterations = " << projectionSolver.GetNumIterations());
|
INFO("Discrete-equilibrium projection iterations = "
|
||||||
|
<< projectionSolver.GetNumIterations());
|
||||||
|
|
||||||
INFO("Discrete-equilibrium projection final norm = " << projectionSolver.GetFinalNorm());
|
INFO("Discrete-equilibrium projection final norm = "
|
||||||
|
<< projectionSolver.GetFinalNorm());
|
||||||
|
|
||||||
REQUIRE(projectionSolver.GetConverged());
|
REQUIRE(projectionSolver.GetConverged());
|
||||||
|
|
||||||
@@ -314,15 +315,15 @@ TEST_CASE(
|
|||||||
correctionEquationResidual -= correctionRightHandSide;
|
correctionEquationResidual -= correctionRightHandSide;
|
||||||
|
|
||||||
const double correctionEquationNorm =
|
const double correctionEquationNorm =
|
||||||
gravity_prepared_test_utils::global_norm(correctionEquationResidual, communicator);
|
gravity_prepared_test_utils::global_norm(correctionEquationResidual,
|
||||||
|
communicator);
|
||||||
|
|
||||||
INFO(
|
INFO("Discrete-equilibrium correction-equation "
|
||||||
"Discrete-equilibrium correction-equation "
|
|
||||||
"residual norm = "
|
"residual norm = "
|
||||||
<< correctionEquationNorm
|
<< correctionEquationNorm);
|
||||||
);
|
|
||||||
|
|
||||||
CHECK(correctionEquationNorm <= std::max(5.0e-12 * interpolatedResidualNorm, 5.0e-15));
|
CHECK(correctionEquationNorm <=
|
||||||
|
std::max(5.0e-12 * interpolatedResidualNorm, 5.0e-15));
|
||||||
|
|
||||||
mfem::Vector discreteEnthalpy(interpolatedEnthalpy);
|
mfem::Vector discreteEnthalpy(interpolatedEnthalpy);
|
||||||
|
|
||||||
@@ -332,20 +333,21 @@ TEST_CASE(
|
|||||||
mfem::Vector referenceResidual;
|
mfem::Vector referenceResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, discreteEnthalpy, potential, displacement, bernoulliConstant,
|
f, *f.domainMapperStateless, rotation, discreteEnthalpy, potential,
|
||||||
exactResidual
|
displacement, bernoulliConstant, exactResidual);
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, discreteEnthalpy, potential, displacement,
|
f, *f.domainMapperStateless, rotation, discreteEnthalpy, potential,
|
||||||
bernoulliConstant + constantOffset, referenceResidual
|
displacement, bernoulliConstant + constantOffset, referenceResidual);
|
||||||
);
|
|
||||||
|
|
||||||
const double exactNorm = gravity_prepared_test_utils::global_norm(exactResidual, communicator);
|
const double exactNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(exactResidual, communicator);
|
||||||
|
|
||||||
const double referenceNorm = gravity_prepared_test_utils::global_norm(referenceResidual, communicator);
|
const double referenceNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(referenceResidual, communicator);
|
||||||
|
|
||||||
const double correctionNorm = gravity_prepared_test_utils::global_norm(enthalpyCorrection, communicator);
|
const double correctionNorm = gravity_prepared_test_utils::global_norm(
|
||||||
|
enthalpyCorrection, communicator);
|
||||||
|
|
||||||
INFO("Enthalpy representation correction norm = " << correctionNorm);
|
INFO("Enthalpy representation correction norm = " << correctionNorm);
|
||||||
|
|
||||||
@@ -360,31 +362,37 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Exact Constant Hydrostatic Equilibrium Remains Zero Under Deformation",
|
"Exact Constant Hydrostatic Equilibrium Remains Zero Under Deformation",
|
||||||
tags::barotrope &tags::hydro &tags::integration &tags::jacobian &tags::kernels &tags::mapping &tags::physics
|
tags::barotrope &tags::hydro &tags::integration &tags::jacobian
|
||||||
) {
|
&tags::kernels &tags::mapping &tags::physics) {
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = hydrostatic_kernel_test_utils::make_zero_rotation();
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
hydrostatic_kernel_test_utils::make_zero_rotation();
|
||||||
|
|
||||||
constexpr double enthalpyValue = 1.20;
|
constexpr double enthalpyValue = 1.20;
|
||||||
constexpr double potentialValue = -0.35;
|
constexpr double potentialValue = -0.35;
|
||||||
|
|
||||||
constexpr double bernoulliConstant = enthalpyValue + potentialValue;
|
constexpr double bernoulliConstant = enthalpyValue + potentialValue;
|
||||||
|
|
||||||
const mfem::Vector enthalpy = hydrostatic_kernel_test_utils::make_constant_field(*f.enthalpyFes, enthalpyValue);
|
const mfem::Vector enthalpy =
|
||||||
|
hydrostatic_kernel_test_utils::make_constant_field(*f.enthalpyFes,
|
||||||
|
enthalpyValue);
|
||||||
|
|
||||||
const mfem::Vector potential =
|
const mfem::Vector potential =
|
||||||
hydrostatic_kernel_test_utils::make_constant_field(*f.gravityPotentialFes, potentialValue);
|
hydrostatic_kernel_test_utils::make_constant_field(*f.gravityPotentialFes,
|
||||||
|
potentialValue);
|
||||||
|
|
||||||
const mfem::Vector displacementVariation = gravity_prepared_test_utils::make_displacement(f, 0.67);
|
const mfem::Vector displacementVariation =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.67);
|
||||||
|
|
||||||
const MPI_Comm communicator = f.mesh->GetComm();
|
const MPI_Comm communicator = f.mesh->GetComm();
|
||||||
|
|
||||||
for (const double deformationScale : {0.0, 0.5, 1.0}) {
|
for (const double deformationScale : {0.0, 0.5, 1.0}) {
|
||||||
DYNAMIC_SECTION("Deformation scale = " << deformationScale) {
|
DYNAMIC_SECTION("Deformation scale = " << deformationScale) {
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, deformationScale);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, deformationScale);
|
||||||
|
|
||||||
mfem::Vector exactResidual;
|
mfem::Vector exactResidual;
|
||||||
mfem::Vector referenceResidual;
|
mfem::Vector referenceResidual;
|
||||||
@@ -392,35 +400,38 @@ TEST_CASE(
|
|||||||
mfem::Vector referenceGeometryAction;
|
mfem::Vector referenceGeometryAction;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant,
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
exactResidual
|
displacement, bernoulliConstant, exactResidual);
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant + 0.50,
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
referenceResidual
|
displacement, bernoulliConstant + 0.50, referenceResidual);
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_displacement_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant,
|
apply_hydrostatic_equilibrium_displacement_action(
|
||||||
displacementVariation, exactGeometryAction
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
);
|
displacement, bernoulliConstant, displacementVariation,
|
||||||
|
exactGeometryAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_displacement_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant + 0.50,
|
apply_hydrostatic_equilibrium_displacement_action(
|
||||||
displacementVariation, referenceGeometryAction
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
);
|
displacement, bernoulliConstant + 0.50, displacementVariation,
|
||||||
|
referenceGeometryAction);
|
||||||
|
|
||||||
const double exactResidualNorm = gravity_prepared_test_utils::global_norm(exactResidual, communicator);
|
const double exactResidualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(exactResidual, communicator);
|
||||||
|
|
||||||
const double referenceResidualNorm =
|
const double referenceResidualNorm =
|
||||||
gravity_prepared_test_utils::global_norm(referenceResidual, communicator);
|
gravity_prepared_test_utils::global_norm(referenceResidual,
|
||||||
|
communicator);
|
||||||
|
|
||||||
const double exactGeometryNorm =
|
const double exactGeometryNorm = gravity_prepared_test_utils::global_norm(
|
||||||
gravity_prepared_test_utils::global_norm(exactGeometryAction, communicator);
|
exactGeometryAction, communicator);
|
||||||
|
|
||||||
const double referenceGeometryNorm =
|
const double referenceGeometryNorm =
|
||||||
gravity_prepared_test_utils::global_norm(referenceGeometryAction, communicator);
|
gravity_prepared_test_utils::global_norm(referenceGeometryAction,
|
||||||
|
communicator);
|
||||||
|
|
||||||
REQUIRE(referenceResidualNorm > 1.0e-12);
|
REQUIRE(referenceResidualNorm > 1.0e-12);
|
||||||
|
|
||||||
@@ -433,51 +444,59 @@ TEST_CASE(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Hydrostatic Equilibrium Excludes Vacuum Elements",
|
||||||
"Hydrostatic Equilibrium Excludes Vacuum Elements",
|
tags::barotrope &tags::hydro &tags::kernels &tags::mapping
|
||||||
tags::barotrope &tags::hydro &tags::kernels &tags::mapping &tags::physics &tags::unit
|
&tags::physics &tags::unit) {
|
||||||
) {
|
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = hydrostatic_kernel_test_utils::make_zero_rotation();
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
hydrostatic_kernel_test_utils::make_zero_rotation();
|
||||||
|
|
||||||
const mfem::Vector zeroEnthalpy(f.enthalpyFes->GetTrueVSize());
|
const mfem::Vector zeroEnthalpy(f.enthalpyFes->GetTrueVSize());
|
||||||
|
|
||||||
mfem::Vector enthalpy(zeroEnthalpy);
|
mfem::Vector enthalpy(zeroEnthalpy);
|
||||||
enthalpy = 0.0;
|
enthalpy = 0.0;
|
||||||
|
|
||||||
const mfem::Vector vacuumPotential = hydrostatic_kernel_test_utils::make_vacuum_supported_potential(f);
|
const mfem::Vector vacuumPotential =
|
||||||
|
hydrostatic_kernel_test_utils::make_vacuum_supported_potential(f);
|
||||||
|
|
||||||
const mfem::Vector stellarPotential =
|
const mfem::Vector stellarPotential =
|
||||||
hydrostatic_kernel_test_utils::make_constant_field(*f.gravityPotentialFes, 1.0);
|
hydrostatic_kernel_test_utils::make_constant_field(*f.gravityPotentialFes,
|
||||||
|
1.0);
|
||||||
|
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 1.0);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||||
|
|
||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
mfem::Vector vacuumAction;
|
mfem::Vector vacuumAction;
|
||||||
mfem::Vector stellarAction;
|
mfem::Vector stellarAction;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, vacuumPotential, displacement, 0.0, residual
|
f, *f.domainMapperStateless, rotation, enthalpy, vacuumPotential,
|
||||||
);
|
displacement, 0.0, residual);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_potential_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, vacuumPotential, displacement, vacuumAction
|
apply_hydrostatic_equilibrium_potential_action(
|
||||||
);
|
f, *f.domainMapperStateless, vacuumPotential, displacement,
|
||||||
|
vacuumAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_potential_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, stellarPotential, displacement, stellarAction
|
apply_hydrostatic_equilibrium_potential_action(
|
||||||
);
|
f, *f.domainMapperStateless, stellarPotential, displacement,
|
||||||
|
stellarAction);
|
||||||
|
|
||||||
const MPI_Comm communicator = f.mesh->GetComm();
|
const MPI_Comm communicator = f.mesh->GetComm();
|
||||||
|
|
||||||
const double residualNorm = gravity_prepared_test_utils::global_norm(residual, communicator);
|
const double residualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(residual, communicator);
|
||||||
|
|
||||||
const double vacuumActionNorm = gravity_prepared_test_utils::global_norm(vacuumAction, communicator);
|
const double vacuumActionNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(vacuumAction, communicator);
|
||||||
|
|
||||||
const double stellarActionNorm = gravity_prepared_test_utils::global_norm(stellarAction, communicator);
|
const double stellarActionNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(stellarAction, communicator);
|
||||||
|
|
||||||
REQUIRE(stellarActionNorm > 1.0e-12);
|
REQUIRE(stellarActionNorm > 1.0e-12);
|
||||||
|
|
||||||
@@ -486,30 +505,35 @@ TEST_CASE(
|
|||||||
CHECK(vacuumActionNorm <= 5.0e-13 * stellarActionNorm);
|
CHECK(vacuumActionNorm <= 5.0e-13 * stellarActionNorm);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Hydrostatic Jacobian Matches Blocks And Centered Differences",
|
||||||
"Hydrostatic Jacobian Matches Blocks And Centered Differences",
|
tags::barotrope &tags::hydro &tags::integration &tags::jacobian
|
||||||
tags::barotrope &tags::hydro &tags::integration &tags::jacobian &tags::kernels &tags::mapping &tags::physics
|
&tags::kernels &tags::mapping &tags::physics) {
|
||||||
) {
|
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = hydrostatic_kernel_test_utils::make_rotation();
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
hydrostatic_kernel_test_utils::make_rotation();
|
||||||
|
|
||||||
const mfem::Vector enthalpy = hydrostatic_kernel_test_utils::make_enthalpy(f);
|
const mfem::Vector enthalpy = hydrostatic_kernel_test_utils::make_enthalpy(f);
|
||||||
|
|
||||||
const mfem::Vector potential = hydrostatic_kernel_test_utils::make_potential(f);
|
const mfem::Vector potential =
|
||||||
|
hydrostatic_kernel_test_utils::make_potential(f);
|
||||||
|
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 1.0);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||||
|
|
||||||
const mfem::Vector enthalpyVariation =
|
const mfem::Vector enthalpyVariation =
|
||||||
gravity_prepared_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.23);
|
gravity_prepared_test_utils::make_deterministic_vector(
|
||||||
|
f.enthalpyFes->GetTrueVSize(), 0.23);
|
||||||
|
|
||||||
const mfem::Vector potentialVariation =
|
const mfem::Vector potentialVariation =
|
||||||
gravity_prepared_test_utils::make_deterministic_vector(f.gravityPotentialFes->GetTrueVSize(), 0.47);
|
gravity_prepared_test_utils::make_deterministic_vector(
|
||||||
|
f.gravityPotentialFes->GetTrueVSize(), 0.47);
|
||||||
|
|
||||||
const mfem::Vector displacementVariation =
|
const mfem::Vector displacementVariation =
|
||||||
gravity_prepared_test_utils::make_deterministic_vector(f.displacementFes->GetTrueVSize(), 0.71);
|
gravity_prepared_test_utils::make_deterministic_vector(
|
||||||
|
f.displacementFes->GetTrueVSize(), 0.71);
|
||||||
|
|
||||||
constexpr double bernoulliConstant = 0.41;
|
constexpr double bernoulliConstant = 0.41;
|
||||||
constexpr double constantVariation = -0.37;
|
constexpr double constantVariation = -0.37;
|
||||||
@@ -522,26 +546,28 @@ TEST_CASE(
|
|||||||
mfem::Vector completeAction;
|
mfem::Vector completeAction;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_enthalpy_action(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium_enthalpy_action(
|
||||||
f, *f.domainMapperStateless, enthalpyVariation, displacement, enthalpyAction
|
f, *f.domainMapperStateless, enthalpyVariation, displacement,
|
||||||
);
|
enthalpyAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_potential_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, potentialVariation, displacement, potentialAction
|
apply_hydrostatic_equilibrium_potential_action(
|
||||||
);
|
f, *f.domainMapperStateless, potentialVariation, displacement,
|
||||||
|
potentialAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_constant_action(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium_constant_action(
|
||||||
f, *f.domainMapperStateless, constantVariation, displacement, constantAction
|
f, *f.domainMapperStateless, constantVariation, displacement,
|
||||||
);
|
constantAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_displacement_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant,
|
apply_hydrostatic_equilibrium_displacement_action(
|
||||||
displacementVariation, displacementAction
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
);
|
displacement, bernoulliConstant, displacementVariation,
|
||||||
|
displacementAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_action(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium_action(
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant, enthalpyVariation,
|
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement,
|
||||||
potentialVariation, constantVariation, displacementVariation, completeAction
|
bernoulliConstant, enthalpyVariation, potentialVariation,
|
||||||
);
|
constantVariation, displacementVariation, completeAction);
|
||||||
|
|
||||||
mfem::Vector blockAction(enthalpyAction);
|
mfem::Vector blockAction(enthalpyAction);
|
||||||
blockAction += potentialAction;
|
blockAction += potentialAction;
|
||||||
@@ -550,22 +576,23 @@ TEST_CASE(
|
|||||||
|
|
||||||
const MPI_Comm communicator = f.mesh->GetComm();
|
const MPI_Comm communicator = f.mesh->GetComm();
|
||||||
|
|
||||||
const double blockError = gravity_prepared_test_utils::relative_error(completeAction, blockAction, communicator);
|
const double blockError = gravity_prepared_test_utils::relative_error(
|
||||||
|
completeAction, blockAction, communicator);
|
||||||
|
|
||||||
INFO("Hydrostatic block reconstruction error = " << blockError);
|
INFO("Hydrostatic block reconstruction error = " << blockError);
|
||||||
|
|
||||||
CHECK(blockError < 5.0e-13);
|
CHECK(blockError < 5.0e-13);
|
||||||
|
|
||||||
auto evaluate_residual = [&f, &rotation](
|
auto evaluate_residual = [&f,
|
||||||
const mfem::Vector &trialEnthalpy, const mfem::Vector &trialPotential,
|
&rotation](const mfem::Vector &trialEnthalpy,
|
||||||
const mfem::Vector &trialDisplacement, const double trialConstant
|
const mfem::Vector &trialPotential,
|
||||||
) {
|
const mfem::Vector &trialDisplacement,
|
||||||
|
const double trialConstant) {
|
||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, rotation, trialEnthalpy, trialPotential, trialDisplacement, trialConstant,
|
f, *f.domainMapperStateless, rotation, trialEnthalpy, trialPotential,
|
||||||
residual
|
trialDisplacement, trialConstant, residual);
|
||||||
);
|
|
||||||
|
|
||||||
return residual;
|
return residual;
|
||||||
};
|
};
|
||||||
@@ -577,10 +604,13 @@ TEST_CASE(
|
|||||||
|
|
||||||
minusEnthalpy.Add(-epsilon, enthalpyVariation);
|
minusEnthalpy.Add(-epsilon, enthalpyVariation);
|
||||||
|
|
||||||
const mfem::Vector enthalpyDifference = hydrostatic_kernel_test_utils::centered_difference(
|
const mfem::Vector enthalpyDifference =
|
||||||
evaluate_residual(plusEnthalpy, potential, displacement, bernoulliConstant),
|
hydrostatic_kernel_test_utils::centered_difference(
|
||||||
evaluate_residual(minusEnthalpy, potential, displacement, bernoulliConstant), epsilon
|
evaluate_residual(plusEnthalpy, potential, displacement,
|
||||||
);
|
bernoulliConstant),
|
||||||
|
evaluate_residual(minusEnthalpy, potential, displacement,
|
||||||
|
bernoulliConstant),
|
||||||
|
epsilon);
|
||||||
|
|
||||||
mfem::Vector plusPotential(potential);
|
mfem::Vector plusPotential(potential);
|
||||||
mfem::Vector minusPotential(potential);
|
mfem::Vector minusPotential(potential);
|
||||||
@@ -589,15 +619,21 @@ TEST_CASE(
|
|||||||
|
|
||||||
minusPotential.Add(-epsilon, potentialVariation);
|
minusPotential.Add(-epsilon, potentialVariation);
|
||||||
|
|
||||||
const mfem::Vector potentialDifference = hydrostatic_kernel_test_utils::centered_difference(
|
const mfem::Vector potentialDifference =
|
||||||
evaluate_residual(enthalpy, plusPotential, displacement, bernoulliConstant),
|
hydrostatic_kernel_test_utils::centered_difference(
|
||||||
evaluate_residual(enthalpy, minusPotential, displacement, bernoulliConstant), epsilon
|
evaluate_residual(enthalpy, plusPotential, displacement,
|
||||||
);
|
bernoulliConstant),
|
||||||
|
evaluate_residual(enthalpy, minusPotential, displacement,
|
||||||
|
bernoulliConstant),
|
||||||
|
epsilon);
|
||||||
|
|
||||||
const mfem::Vector constantDifference = hydrostatic_kernel_test_utils::centered_difference(
|
const mfem::Vector constantDifference =
|
||||||
evaluate_residual(enthalpy, potential, displacement, bernoulliConstant + epsilon * constantVariation),
|
hydrostatic_kernel_test_utils::centered_difference(
|
||||||
evaluate_residual(enthalpy, potential, displacement, bernoulliConstant - epsilon * constantVariation), epsilon
|
evaluate_residual(enthalpy, potential, displacement,
|
||||||
);
|
bernoulliConstant + epsilon * constantVariation),
|
||||||
|
evaluate_residual(enthalpy, potential, displacement,
|
||||||
|
bernoulliConstant - epsilon * constantVariation),
|
||||||
|
epsilon);
|
||||||
|
|
||||||
mfem::Vector plusDisplacement(displacement);
|
mfem::Vector plusDisplacement(displacement);
|
||||||
mfem::Vector minusDisplacement(displacement);
|
mfem::Vector minusDisplacement(displacement);
|
||||||
@@ -606,22 +642,25 @@ TEST_CASE(
|
|||||||
|
|
||||||
minusDisplacement.Add(-epsilon, displacementVariation);
|
minusDisplacement.Add(-epsilon, displacementVariation);
|
||||||
|
|
||||||
const mfem::Vector displacementDifference = hydrostatic_kernel_test_utils::centered_difference(
|
const mfem::Vector displacementDifference =
|
||||||
evaluate_residual(enthalpy, potential, plusDisplacement, bernoulliConstant),
|
hydrostatic_kernel_test_utils::centered_difference(
|
||||||
evaluate_residual(enthalpy, potential, minusDisplacement, bernoulliConstant), epsilon
|
evaluate_residual(enthalpy, potential, plusDisplacement,
|
||||||
);
|
bernoulliConstant),
|
||||||
|
evaluate_residual(enthalpy, potential, minusDisplacement,
|
||||||
|
bernoulliConstant),
|
||||||
|
epsilon);
|
||||||
|
|
||||||
const double enthalpyError =
|
const double enthalpyError = gravity_prepared_test_utils::relative_error(
|
||||||
gravity_prepared_test_utils::relative_error(enthalpyAction, enthalpyDifference, communicator);
|
enthalpyAction, enthalpyDifference, communicator);
|
||||||
|
|
||||||
const double potentialError =
|
const double potentialError = gravity_prepared_test_utils::relative_error(
|
||||||
gravity_prepared_test_utils::relative_error(potentialAction, potentialDifference, communicator);
|
potentialAction, potentialDifference, communicator);
|
||||||
|
|
||||||
const double constantError =
|
const double constantError = gravity_prepared_test_utils::relative_error(
|
||||||
gravity_prepared_test_utils::relative_error(constantAction, constantDifference, communicator);
|
constantAction, constantDifference, communicator);
|
||||||
|
|
||||||
const double displacementError =
|
const double displacementError = gravity_prepared_test_utils::relative_error(
|
||||||
gravity_prepared_test_utils::relative_error(displacementAction, displacementDifference, communicator);
|
displacementAction, displacementDifference, communicator);
|
||||||
|
|
||||||
INFO("Hydrostatic enthalpy-block error = " << enthalpyError);
|
INFO("Hydrostatic enthalpy-block error = " << enthalpyError);
|
||||||
|
|
||||||
@@ -655,86 +694,91 @@ TEST_CASE(
|
|||||||
|
|
||||||
combinedMinusDisplacement.Add(-epsilon, displacementVariation);
|
combinedMinusDisplacement.Add(-epsilon, displacementVariation);
|
||||||
|
|
||||||
const mfem::Vector combinedDifference = hydrostatic_kernel_test_utils::centered_difference(
|
const mfem::Vector combinedDifference =
|
||||||
evaluate_residual(
|
hydrostatic_kernel_test_utils::centered_difference(
|
||||||
combinedPlusEnthalpy, combinedPlusPotential, combinedPlusDisplacement,
|
evaluate_residual(combinedPlusEnthalpy, combinedPlusPotential,
|
||||||
bernoulliConstant + epsilon * constantVariation
|
combinedPlusDisplacement,
|
||||||
),
|
bernoulliConstant + epsilon * constantVariation),
|
||||||
evaluate_residual(
|
evaluate_residual(combinedMinusEnthalpy, combinedMinusPotential,
|
||||||
combinedMinusEnthalpy, combinedMinusPotential, combinedMinusDisplacement,
|
combinedMinusDisplacement,
|
||||||
bernoulliConstant - epsilon * constantVariation
|
bernoulliConstant - epsilon * constantVariation),
|
||||||
),
|
epsilon);
|
||||||
epsilon
|
|
||||||
);
|
|
||||||
|
|
||||||
const double blockNormSum = gravity_prepared_test_utils::global_norm(enthalpyAction, communicator) +
|
const double blockNormSum =
|
||||||
|
gravity_prepared_test_utils::global_norm(enthalpyAction, communicator) +
|
||||||
gravity_prepared_test_utils::global_norm(potentialAction, communicator) +
|
gravity_prepared_test_utils::global_norm(potentialAction, communicator) +
|
||||||
gravity_prepared_test_utils::global_norm(constantAction, communicator) +
|
gravity_prepared_test_utils::global_norm(constantAction, communicator) +
|
||||||
gravity_prepared_test_utils::global_norm(displacementAction, communicator);
|
gravity_prepared_test_utils::global_norm(displacementAction,
|
||||||
|
communicator);
|
||||||
|
|
||||||
const double simultaneousError = hydrostatic_kernel_test_utils::sum_normalized_error(
|
const double simultaneousError =
|
||||||
completeAction, combinedDifference, blockNormSum, communicator
|
hydrostatic_kernel_test_utils::sum_normalized_error(
|
||||||
);
|
completeAction, combinedDifference, blockNormSum, communicator);
|
||||||
|
|
||||||
INFO("Hydrostatic simultaneous Jacobian error = " << simultaneousError);
|
INFO("Hydrostatic simultaneous Jacobian error = " << simultaneousError);
|
||||||
|
|
||||||
CHECK(simultaneousError < 2.0e-7);
|
CHECK(simultaneousError < 2.0e-7);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Hydrostatic Displacement Action Is Linear In Its Direction",
|
||||||
"Hydrostatic Displacement Action Is Linear In Its Direction",
|
tags::barotrope &tags::hydro &tags::integration &tags::jacobian
|
||||||
tags::barotrope &tags::hydro &tags::integration &tags::jacobian &tags::mapping &tags::physics &tags::unit
|
&tags::mapping &tags::physics &tags::unit &tags::kernels) {
|
||||||
&tags::kernels
|
|
||||||
) {
|
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = hydrostatic_kernel_test_utils::make_rotation();
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
hydrostatic_kernel_test_utils::make_rotation();
|
||||||
|
|
||||||
const mfem::Vector enthalpy = hydrostatic_kernel_test_utils::make_enthalpy(f);
|
const mfem::Vector enthalpy = hydrostatic_kernel_test_utils::make_enthalpy(f);
|
||||||
|
|
||||||
const mfem::Vector potential = hydrostatic_kernel_test_utils::make_potential(f);
|
const mfem::Vector potential =
|
||||||
|
hydrostatic_kernel_test_utils::make_potential(f);
|
||||||
|
|
||||||
const mfem::Vector displacement = gravity_prepared_test_utils::make_displacement(f, 1.0);
|
const mfem::Vector displacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||||
|
|
||||||
const mfem::Vector firstDirection =
|
const mfem::Vector firstDirection =
|
||||||
gravity_prepared_test_utils::make_deterministic_vector(f.displacementFes->GetTrueVSize(), 0.31);
|
gravity_prepared_test_utils::make_deterministic_vector(
|
||||||
|
f.displacementFes->GetTrueVSize(), 0.31);
|
||||||
|
|
||||||
const mfem::Vector secondDirection =
|
const mfem::Vector secondDirection =
|
||||||
gravity_prepared_test_utils::make_deterministic_vector(f.displacementFes->GetTrueVSize(), 0.83);
|
gravity_prepared_test_utils::make_deterministic_vector(
|
||||||
|
f.displacementFes->GetTrueVSize(), 0.83);
|
||||||
|
|
||||||
constexpr double firstScale = 0.43;
|
constexpr double firstScale = 0.43;
|
||||||
constexpr double secondScale = -0.29;
|
constexpr double secondScale = -0.29;
|
||||||
constexpr double bernoulliConstant = 0.41;
|
constexpr double bernoulliConstant = 0.41;
|
||||||
|
|
||||||
const mfem::Vector combinedDirection =
|
const mfem::Vector combinedDirection =
|
||||||
gravity_prepared_test_utils::linear_combination(firstDirection, firstScale, secondDirection, secondScale);
|
gravity_prepared_test_utils::linear_combination(
|
||||||
|
firstDirection, firstScale, secondDirection, secondScale);
|
||||||
|
|
||||||
mfem::Vector firstAction;
|
mfem::Vector firstAction;
|
||||||
mfem::Vector secondAction;
|
mfem::Vector secondAction;
|
||||||
mfem::Vector combinedAction;
|
mfem::Vector combinedAction;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_displacement_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant, firstDirection,
|
apply_hydrostatic_equilibrium_displacement_action(
|
||||||
firstAction
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
);
|
displacement, bernoulliConstant, firstDirection, firstAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_displacement_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant, secondDirection,
|
apply_hydrostatic_equilibrium_displacement_action(
|
||||||
secondAction
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
);
|
displacement, bernoulliConstant, secondDirection, secondAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium_displacement_action(
|
mean_field::operators::kernels::
|
||||||
f, *f.domainMapperStateless, rotation, enthalpy, potential, displacement, bernoulliConstant, combinedDirection,
|
apply_hydrostatic_equilibrium_displacement_action(
|
||||||
combinedAction
|
f, *f.domainMapperStateless, rotation, enthalpy, potential,
|
||||||
);
|
displacement, bernoulliConstant, combinedDirection, combinedAction);
|
||||||
|
|
||||||
const mfem::Vector expectedAction =
|
const mfem::Vector expectedAction =
|
||||||
gravity_prepared_test_utils::linear_combination(firstAction, firstScale, secondAction, secondScale);
|
gravity_prepared_test_utils::linear_combination(
|
||||||
|
firstAction, firstScale, secondAction, secondScale);
|
||||||
|
|
||||||
const double linearityError =
|
const double linearityError = gravity_prepared_test_utils::relative_error(
|
||||||
gravity_prepared_test_utils::relative_error(combinedAction, expectedAction, f.mesh->GetComm());
|
combinedAction, expectedAction, f.mesh->GetComm());
|
||||||
|
|
||||||
INFO("Hydrostatic displacement-linearity error = " << linearityError);
|
INFO("Hydrostatic displacement-linearity error = " << linearityError);
|
||||||
|
|
||||||
@@ -743,8 +787,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Hydrostatic Residual Is Translationally Invariant On Deformed Geometry",
|
"Hydrostatic Residual Is Translationally Invariant On Deformed Geometry",
|
||||||
tags::barotrope &tags::hydro &tags::integration &tags::kernels &tags::mapping &tags::physics &tags::residuals
|
tags::barotrope &tags::hydro &tags::integration &tags::kernels
|
||||||
) {
|
&tags::mapping &tags::physics &tags::residuals) {
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -770,29 +814,33 @@ TEST_CASE(
|
|||||||
mfem::Vector translatedCenter(center);
|
mfem::Vector translatedCenter(center);
|
||||||
translatedCenter += translation;
|
translatedCenter += translation;
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation baseRotation(angularVelocity, center);
|
const mean_field::physics::RigidRotation baseRotation(angularVelocity,
|
||||||
|
center);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation translatedRotation(angularVelocity, translatedCenter);
|
const mean_field::physics::RigidRotation translatedRotation(angularVelocity,
|
||||||
|
translatedCenter);
|
||||||
|
|
||||||
const mfem::Vector enthalpy = hydrostatic_kernel_test_utils::make_enthalpy(f);
|
const mfem::Vector enthalpy = hydrostatic_kernel_test_utils::make_enthalpy(f);
|
||||||
|
|
||||||
const mfem::Vector potential = hydrostatic_kernel_test_utils::make_potential(f);
|
const mfem::Vector potential =
|
||||||
|
hydrostatic_kernel_test_utils::make_potential(f);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Use a nontrivially deformed base state so this checks rotation
|
* Use a nontrivially deformed base state so this checks rotation
|
||||||
* and mapped geometry simultaneously. The comparison state adds
|
* and mapped geometry simultaneously. The comparison state adds
|
||||||
* an exactly representable rigid translation to that deformation.
|
* an exactly representable rigid translation to that deformation.
|
||||||
*/
|
*/
|
||||||
const mfem::Vector baseDisplacement = gravity_prepared_test_utils::make_displacement(f, 0.73);
|
const mfem::Vector baseDisplacement =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.73);
|
||||||
|
|
||||||
mfem::ParGridFunction translationField(f.displacementFes.get());
|
mfem::ParGridFunction translationField(f.displacementFes.get());
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient translationCoefficient(
|
mfem::VectorFunctionCoefficient translationCoefficient(
|
||||||
f.mesh->Dimension(), [&translation](const mfem::Vector &, mfem::Vector &value) {
|
f.mesh->Dimension(),
|
||||||
|
[&translation](const mfem::Vector &, mfem::Vector &value) {
|
||||||
value.SetSize(translation.Size());
|
value.SetSize(translation.Size());
|
||||||
value = translation;
|
value = translation;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
translationField.ProjectCoefficient(translationCoefficient);
|
translationField.ProjectCoefficient(translationCoefficient);
|
||||||
|
|
||||||
@@ -810,43 +858,47 @@ TEST_CASE(
|
|||||||
mfem::Vector untranslatedCenterResidual;
|
mfem::Vector untranslatedCenterResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, baseRotation, enthalpy, potential, baseDisplacement, bernoulliConstant,
|
f, *f.domainMapperStateless, baseRotation, enthalpy, potential,
|
||||||
baseResidual
|
baseDisplacement, bernoulliConstant, baseResidual);
|
||||||
);
|
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, translatedRotation, enthalpy, potential, translatedDisplacement, bernoulliConstant,
|
f, *f.domainMapperStateless, translatedRotation, enthalpy, potential,
|
||||||
translatedResidual
|
translatedDisplacement, bernoulliConstant, translatedResidual);
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Negative control: translate the geometry but leave the rotation
|
* Negative control: translate the geometry but leave the rotation
|
||||||
* center fixed. This must not agree with the covariant result.
|
* center fixed. This must not agree with the covariant result.
|
||||||
*/
|
*/
|
||||||
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
mean_field::operators::kernels::apply_hydrostatic_equilibrium(
|
||||||
f, *f.domainMapperStateless, baseRotation, enthalpy, potential, translatedDisplacement, bernoulliConstant,
|
f, *f.domainMapperStateless, baseRotation, enthalpy, potential,
|
||||||
untranslatedCenterResidual
|
translatedDisplacement, bernoulliConstant, untranslatedCenterResidual);
|
||||||
);
|
|
||||||
|
|
||||||
const MPI_Comm communicator = f.mesh->GetComm();
|
const MPI_Comm communicator = f.mesh->GetComm();
|
||||||
|
|
||||||
const double baseResidualNorm = gravity_prepared_test_utils::global_norm(baseResidual, communicator);
|
const double baseResidualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(baseResidual, communicator);
|
||||||
|
|
||||||
const double translatedResidualNorm = gravity_prepared_test_utils::global_norm(translatedResidual, communicator);
|
const double translatedResidualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(translatedResidual,
|
||||||
|
communicator);
|
||||||
|
|
||||||
const double translationInvarianceError =
|
const double translationInvarianceError =
|
||||||
gravity_prepared_test_utils::relative_error(translatedResidual, baseResidual, communicator);
|
gravity_prepared_test_utils::relative_error(translatedResidual,
|
||||||
|
baseResidual, communicator);
|
||||||
|
|
||||||
const double fixedCenterDifference =
|
const double fixedCenterDifference =
|
||||||
gravity_prepared_test_utils::relative_error(untranslatedCenterResidual, translatedResidual, communicator);
|
gravity_prepared_test_utils::relative_error(
|
||||||
|
untranslatedCenterResidual, translatedResidual, communicator);
|
||||||
|
|
||||||
INFO("Base deformed hydrostatic residual norm = " << baseResidualNorm);
|
INFO("Base deformed hydrostatic residual norm = " << baseResidualNorm);
|
||||||
|
|
||||||
INFO("Translated hydrostatic residual norm = " << translatedResidualNorm);
|
INFO("Translated hydrostatic residual norm = " << translatedResidualNorm);
|
||||||
|
|
||||||
INFO("Mapped-rotation translation invariance error = " << translationInvarianceError);
|
INFO("Mapped-rotation translation invariance error = "
|
||||||
|
<< translationInvarianceError);
|
||||||
|
|
||||||
INFO("Relative change with untranslated rotation center = " << fixedCenterDifference);
|
INFO("Relative change with untranslated rotation center = "
|
||||||
|
<< fixedCenterDifference);
|
||||||
|
|
||||||
REQUIRE(baseResidualNorm > 1.0e-12);
|
REQUIRE(baseResidualNorm > 1.0e-12);
|
||||||
REQUIRE(translatedResidualNorm > 1.0e-12);
|
REQUIRE(translatedResidualNorm > 1.0e-12);
|
||||||
|
|||||||
@@ -10,52 +10,48 @@ import mean_field;
|
|||||||
import test_helpers;
|
import test_helpers;
|
||||||
|
|
||||||
namespace pressure_force_kernel_test_utils {
|
namespace pressure_force_kernel_test_utils {
|
||||||
[[nodiscard]] mfem::Vector make_deterministic_vector(
|
[[nodiscard]] mfem::Vector make_deterministic_vector(const int size,
|
||||||
const int size,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::Vector vector(size);
|
mfem::Vector vector(size);
|
||||||
|
|
||||||
for (int index = 0; index < size; ++index) {
|
for (int index = 0; index < size; ++index) {
|
||||||
const double position = static_cast<double>(index + 1);
|
const double position = static_cast<double>(index + 1);
|
||||||
|
|
||||||
vector(index) =
|
vector(index) = 0.71 + 0.19 * std::sin(0.31 * position + phase) +
|
||||||
0.71 + 0.19 * std::sin(0.31 * position + phase) + 0.08 * std::cos(0.17 * position - 0.5 * phase);
|
0.08 * std::cos(0.17 * position - 0.5 * phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_zero_displacement(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
|
make_zero_displacement(const mean_field::fem::FEM &f) {
|
||||||
mfem::Vector displacementTrue(f.displacementFes->GetTrueVSize());
|
mfem::Vector displacementTrue(f.displacementFes->GetTrueVSize());
|
||||||
displacementTrue = 0.0;
|
displacementTrue = 0.0;
|
||||||
return displacementTrue;
|
return displacementTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_vacuum_only_enthalpy(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
mfem::Vector enthalpyTrue = make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.43);
|
make_vacuum_only_enthalpy(const mean_field::fem::FEM &f) {
|
||||||
|
mfem::Vector enthalpyTrue =
|
||||||
|
make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.43);
|
||||||
|
|
||||||
mfem::Array<int> stellarElementMask;
|
using DomainSchema =
|
||||||
mean_field::utils::populate_element_mask(f.mesh.get(), mean_field::utils::DOMAINS::STELLAR, stellarElementMask);
|
mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||||
|
const mean_field::field::FieldDofMap enthalpyMap =
|
||||||
|
mean_field::field::make_field_dof_map<mean_field::field::Enthalpy,
|
||||||
|
DomainSchema>(*f.enthalpyFes);
|
||||||
|
|
||||||
mfem::Array<int> stellarEnthalpyTrueDofs;
|
for (int reducedDof = 0; reducedDof < enthalpyMap.reduced_size();
|
||||||
mean_field::utils::populate_domain_tdofs(f.enthalpyFes.get(), stellarElementMask, stellarEnthalpyTrueDofs);
|
++reducedDof) {
|
||||||
|
enthalpyTrue(enthalpyMap.true_dof(reducedDof)) = 0.0;
|
||||||
for (int listIndex = 0; listIndex < stellarEnthalpyTrueDofs.Size(); ++listIndex) {
|
|
||||||
const int trueDof = stellarEnthalpyTrueDofs[listIndex];
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
|
||||||
trueDof >= 0 && trueDof < enthalpyTrue.Size(), "The stellar enthalpy true-DOF mask contains an "
|
|
||||||
"invalid index."
|
|
||||||
);
|
|
||||||
|
|
||||||
enthalpyTrue(trueDof) = 0.0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return enthalpyTrue;
|
return enthalpyTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_positive_asymmetric_enthalpy(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
|
make_positive_asymmetric_enthalpy(const mean_field::fem::FEM &f) {
|
||||||
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
mfem::FunctionCoefficient coefficient([](const mfem::Vector &position) {
|
||||||
return 1.10 + 0.07 * position(0) - 0.04 * position(1) + 0.03 * position(2);
|
return 1.10 + 0.07 * position(0) - 0.04 * position(1) + 0.03 * position(2);
|
||||||
});
|
});
|
||||||
@@ -70,16 +66,16 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
return enthalpyTrue;
|
return enthalpyTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_component_test_field(
|
[[nodiscard]] mfem::Vector
|
||||||
const mean_field::fem::FEM &f,
|
make_component_test_field(const mean_field::fem::FEM &f, const int component,
|
||||||
const int component,
|
const int coordinate) {
|
||||||
const int coordinate
|
|
||||||
) {
|
|
||||||
const int dimension = f.mesh->Dimension();
|
const int dimension = f.mesh->Dimension();
|
||||||
|
|
||||||
MFEM_VERIFY(component >= 0 && component < dimension, "The requested vector component is invalid.");
|
MFEM_VERIFY(component >= 0 && component < dimension,
|
||||||
|
"The requested vector component is invalid.");
|
||||||
|
|
||||||
MFEM_VERIFY(coordinate >= -1 && coordinate < dimension, "The requested coordinate is invalid.");
|
MFEM_VERIFY(coordinate >= -1 && coordinate < dimension,
|
||||||
|
"The requested coordinate is invalid.");
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* coordinate == -1 gives the rigid translation e_component.
|
* coordinate == -1 gives the rigid translation e_component.
|
||||||
@@ -89,13 +85,13 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
* w = x_coordinate e_component.
|
* w = x_coordinate e_component.
|
||||||
*/
|
*/
|
||||||
mfem::VectorFunctionCoefficient coefficient(
|
mfem::VectorFunctionCoefficient coefficient(
|
||||||
dimension, [component, coordinate, dimension](const mfem::Vector &position, mfem::Vector &value) {
|
dimension, [component, coordinate, dimension](
|
||||||
|
const mfem::Vector &position, mfem::Vector &value) {
|
||||||
value.SetSize(dimension);
|
value.SetSize(dimension);
|
||||||
value = 0.0;
|
value = 0.0;
|
||||||
|
|
||||||
value(component) = coordinate < 0 ? 1.0 : position(coordinate);
|
value(component) = coordinate < 0 ? 1.0 : position(coordinate);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
mfem::ParGridFunction field(f.displacementFes.get());
|
mfem::ParGridFunction field(f.displacementFes.get());
|
||||||
|
|
||||||
@@ -107,12 +103,11 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
return fieldTrue;
|
return fieldTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double global_dot(
|
[[nodiscard]] double global_dot(const mfem::Vector &left,
|
||||||
const mfem::Vector &left,
|
|
||||||
const mfem::Vector &right,
|
const mfem::Vector &right,
|
||||||
MPI_Comm communicator
|
MPI_Comm communicator) {
|
||||||
) {
|
MFEM_VERIFY(left.Size() == right.Size(),
|
||||||
MFEM_VERIFY(left.Size() == right.Size(), "The global dot-product vectors have different sizes.");
|
"The global dot-product vectors have different sizes.");
|
||||||
|
|
||||||
const double localDot = left * right;
|
const double localDot = left * right;
|
||||||
double globalDot = 0.0;
|
double globalDot = 0.0;
|
||||||
@@ -124,24 +119,19 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
|
|
||||||
[[nodiscard]] double integrate_pressure(
|
[[nodiscard]] double integrate_pressure(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
const mean_field::mapping::DomainMapper &domainMapper,
|
||||||
const mean_field::eos::Polytrope &barotrope,
|
const mean_field::eos::Polytrope &barotrope,
|
||||||
const mfem::Vector &enthalpyTrue,
|
const mfem::Vector &enthalpyTrue, const mfem::Vector &displacementTrue) {
|
||||||
const mfem::Vector &displacementTrue
|
MFEM_VERIFY(enthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(),
|
||||||
) {
|
"The pressure-integral enthalpy vector has the wrong size.");
|
||||||
MFEM_VERIFY(
|
|
||||||
enthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(),
|
|
||||||
"The pressure-integral enthalpy vector has the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
"The pressure-integral displacement vector has the wrong size.");
|
||||||
"The pressure-integral displacement vector has the wrong size."
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector enthalpyLocal(f.enthalpyFes->GetVSize());
|
mfem::Vector enthalpyLocal(f.enthalpyFes->GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *enthalpyProlongation = f.enthalpyFes->GetProlongationMatrix();
|
const mfem::Operator *enthalpyProlongation =
|
||||||
|
f.enthalpyFes->GetProlongationMatrix();
|
||||||
|
|
||||||
if (enthalpyProlongation != nullptr) {
|
if (enthalpyProlongation != nullptr) {
|
||||||
enthalpyProlongation->Mult(enthalpyTrue, enthalpyLocal);
|
enthalpyProlongation->Mult(enthalpyTrue, enthalpyLocal);
|
||||||
@@ -151,7 +141,8 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
|
|
||||||
mfem::Vector displacementLocal(f.displacementFes->GetVSize());
|
mfem::Vector displacementLocal(f.displacementFes->GetVSize());
|
||||||
|
|
||||||
const mfem::Operator *displacementProlongation = f.displacementFes->GetProlongationMatrix();
|
const mfem::Operator *displacementProlongation =
|
||||||
|
f.displacementFes->GetProlongationMatrix();
|
||||||
|
|
||||||
if (displacementProlongation != nullptr) {
|
if (displacementProlongation != nullptr) {
|
||||||
displacementProlongation->Mult(displacementTrue, displacementLocal);
|
displacementProlongation->Mult(displacementTrue, displacementLocal);
|
||||||
@@ -160,19 +151,22 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const double pressureExtraOrderValue =
|
const double pressureExtraOrderValue =
|
||||||
barotrope.polytropic_index() * static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
barotrope.polytropic_index() *
|
||||||
|
static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(pressureExtraOrderValue) &&
|
||||||
std::isfinite(pressureExtraOrderValue) && pressureExtraOrderValue >= 0.0 &&
|
pressureExtraOrderValue >= 0.0 &&
|
||||||
pressureExtraOrderValue <= static_cast<double>(std::numeric_limits<int>::max()),
|
pressureExtraOrderValue <=
|
||||||
"The pressure-integral EOS order is invalid."
|
static_cast<double>(std::numeric_limits<int>::max()),
|
||||||
);
|
"The pressure-integral EOS order is invalid.");
|
||||||
|
|
||||||
const int pressureExtraOrder = static_cast<int>(std::ceil(pressureExtraOrderValue));
|
const int pressureExtraOrder =
|
||||||
|
static_cast<int>(std::ceil(pressureExtraOrderValue));
|
||||||
|
|
||||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||||
|
|
||||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
mean_field::mapping::DomainMapper::Workspace workspace(
|
||||||
|
f.mesh->Dimension());
|
||||||
|
|
||||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||||
|
|
||||||
@@ -187,27 +181,31 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
|
|
||||||
double localPressureIntegral = 0.0;
|
double localPressureIntegral = 0.0;
|
||||||
|
|
||||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
const int vacuumAttribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
f.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(transformation != nullptr,
|
||||||
transformation != nullptr, "The pressure-integral reference received a null "
|
"The pressure-integral reference received a null "
|
||||||
"element transformation."
|
"element transformation.");
|
||||||
);
|
|
||||||
|
|
||||||
if (transformation->Attribute == vacuumAttribute) {
|
if (transformation->Attribute == vacuumAttribute) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
const mfem::FiniteElement &enthalpyElement =
|
||||||
|
*f.enthalpyFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
const mfem::FiniteElement &displacementElement =
|
||||||
|
*f.displacementFes->GetFE(elementId);
|
||||||
|
|
||||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
const mfem::FiniteElement &compactificationElement =
|
||||||
|
*f.compactificationFes->GetFE(elementId);
|
||||||
|
|
||||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
mfem::DofTransformation *enthalpyDofTransformation =
|
||||||
|
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||||
|
|
||||||
mfem::DofTransformation *displacementDofTransformation =
|
mfem::DofTransformation *displacementDofTransformation =
|
||||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||||
@@ -219,7 +217,8 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
|
|
||||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||||
|
|
||||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
f.compactificationCoordinate->GetSubVector(compactificationDofs,
|
||||||
|
elementCompactification);
|
||||||
|
|
||||||
if (enthalpyDofTransformation != nullptr) {
|
if (enthalpyDofTransformation != nullptr) {
|
||||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpy);
|
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpy);
|
||||||
@@ -230,63 +229,70 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (compactificationDofTransformation != nullptr) {
|
if (compactificationDofTransformation != nullptr) {
|
||||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
compactificationDofTransformation->InvTransformPrimal(
|
||||||
|
elementCompactification);
|
||||||
}
|
}
|
||||||
|
|
||||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||||
|
displacementElement, elementDisplacement);
|
||||||
|
|
||||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||||
compactificationElement, elementCompactification
|
compactificationElement, elementCompactification);
|
||||||
);
|
|
||||||
|
|
||||||
const mean_field::mapping::ElementMappingData mappingData{
|
const mean_field::mapping::ElementMappingData mappingData{
|
||||||
.displacement = displacementData, .compactification = compactificationData
|
.displacement = displacementData,
|
||||||
};
|
.compactification = compactificationData};
|
||||||
|
|
||||||
const mean_field::quadrature::Query query =
|
const mean_field::quadrature::Query query = EnthalpyField::make_query<
|
||||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureIntegral>(
|
mean_field::field::Enthalpy::Form::PressureIntegral>(
|
||||||
mean_field::quadrature::QuadratureRole::diagnostic, transformation->OrderW(),
|
mean_field::quadrature::QuadratureRole::diagnostic,
|
||||||
std::array<int, 1>{pressureExtraOrder}, mean_field::utils::DOMAINS::STELLAR,
|
transformation->OrderW(), std::array<int, 1>{pressureExtraOrder},
|
||||||
mean_field::quadrature::MappingKind::general
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
);
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
const mean_field::quadrature::MfemRule rule =
|
const mean_field::quadrature::MfemRule rule =
|
||||||
f.quadratureFactory->get(query, transformation->GetGeometryType());
|
f.quadratureFactory->get(query, transformation->GetGeometryType());
|
||||||
|
|
||||||
MFEM_VERIFY(rule.integration_rule != nullptr, "The pressure-integral quadrature rule is null.");
|
MFEM_VERIFY(rule.integration_rule != nullptr,
|
||||||
|
"The pressure-integral quadrature rule is null.");
|
||||||
|
|
||||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||||
|
|
||||||
for (int quadratureIndex = 0; quadratureIndex < rule.integration_rule->GetNPoints(); ++quadratureIndex) {
|
for (int quadratureIndex = 0;
|
||||||
const mfem::IntegrationPoint &integrationPoint = rule.integration_rule->IntPoint(quadratureIndex);
|
quadratureIndex < rule.integration_rule->GetNPoints();
|
||||||
|
++quadratureIndex) {
|
||||||
|
const mfem::IntegrationPoint &integrationPoint =
|
||||||
|
rule.integration_rule->IntPoint(quadratureIndex);
|
||||||
|
|
||||||
transformation->SetIntPoint(&integrationPoint);
|
transformation->SetIntPoint(&integrationPoint);
|
||||||
|
|
||||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
const mean_field::mapping::MappingStatus mappingStatus =
|
||||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
domainMapper.EvaluateVolume(mappingData, *transformation,
|
||||||
);
|
integrationPoint, workspace,
|
||||||
|
mappingContext);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
|
||||||
"Stateless mapping failed in the "
|
"Stateless mapping failed in the "
|
||||||
"independent pressure integral. Element: "
|
"independent pressure integral. Element: "
|
||||||
<< elementId << ", attribute: " << transformation->Attribute
|
<< elementId
|
||||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
<< ", attribute: " << transformation->Attribute
|
||||||
);
|
<< ", quadrature point: " << quadratureIndex
|
||||||
|
<< ", status: " << static_cast<int>(mappingStatus));
|
||||||
|
|
||||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||||
|
|
||||||
const double enthalpyValue = elementEnthalpy * enthalpyShape;
|
const double enthalpyValue = elementEnthalpy * enthalpyShape;
|
||||||
|
|
||||||
const double pressureValue = barotrope.pressure_from_enthalpy(enthalpyValue);
|
const double pressureValue =
|
||||||
|
barotrope.pressure_from_enthalpy(enthalpyValue);
|
||||||
|
|
||||||
const double contribution = pressureValue * mappingContext.quadrature.weight;
|
const double contribution =
|
||||||
|
pressureValue * mappingContext.quadrature.weight;
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(std::isfinite(pressureValue) && std::isfinite(contribution),
|
||||||
std::isfinite(pressureValue) && std::isfinite(contribution), "The independent pressure integral "
|
"The independent pressure integral "
|
||||||
"encountered a non-finite value."
|
"encountered a non-finite value.");
|
||||||
);
|
|
||||||
|
|
||||||
localPressureIntegral += contribution;
|
localPressureIntegral += contribution;
|
||||||
}
|
}
|
||||||
@@ -294,16 +300,15 @@ namespace pressure_force_kernel_test_utils {
|
|||||||
|
|
||||||
double globalPressureIntegral = 0.0;
|
double globalPressureIntegral = 0.0;
|
||||||
|
|
||||||
MPI_Allreduce(&localPressureIntegral, &globalPressureIntegral, 1, MPI_DOUBLE, MPI_SUM, f.mesh->GetComm());
|
MPI_Allreduce(&localPressureIntegral, &globalPressureIntegral, 1, MPI_DOUBLE,
|
||||||
|
MPI_SUM, f.mesh->GetComm());
|
||||||
|
|
||||||
return globalPressureIntegral;
|
return globalPressureIntegral;
|
||||||
}
|
}
|
||||||
} // namespace pressure_force_kernel_test_utils
|
} // namespace pressure_force_kernel_test_utils
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force Residual Vanishes For Zero Enthalpy",
|
||||||
"Pressure Force Residual Vanishes For Zero Enthalpy",
|
tags::barotrope &tags::pressure &tags::kernels &tags::integration) {
|
||||||
tags::barotrope &tags::pressure &tags::kernels &tags::integration
|
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -315,25 +320,25 @@ TEST_CASE(
|
|||||||
mfem::Vector enthalpyTrue(f.enthalpyFes->GetTrueVSize());
|
mfem::Vector enthalpyTrue(f.enthalpyFes->GetTrueVSize());
|
||||||
enthalpyTrue = 0.0;
|
enthalpyTrue = 0.0;
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = pressure_force_kernel_test_utils::make_zero_displacement(f);
|
const mfem::Vector displacementTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_zero_displacement(f);
|
||||||
|
|
||||||
mfem::Vector residualTrue;
|
mfem::Vector residualTrue;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_residual(
|
mean_field::operators::kernels::apply_pressure_force_residual(
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue, residualTrue
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue,
|
||||||
);
|
residualTrue);
|
||||||
|
|
||||||
REQUIRE(residualTrue.Size() == f.displacementFes->GetTrueVSize());
|
REQUIRE(residualTrue.Size() == f.displacementFes->GetTrueVSize());
|
||||||
|
|
||||||
const double residualNorm = gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
const double residualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
CHECK(residualNorm == 0.0);
|
CHECK(residualNorm == 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force Residual Excludes Vacuum Enthalpy Exactly",
|
||||||
"Pressure Force Residual Excludes Vacuum Enthalpy Exactly",
|
tags::barotrope &tags::pressure &tags::kernels &tags::integration) {
|
||||||
tags::barotrope &tags::pressure &tags::kernels &tags::integration
|
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -342,9 +347,11 @@ TEST_CASE(
|
|||||||
|
|
||||||
const mean_field::eos::Polytrope barotrope(3.0, 0.25);
|
const mean_field::eos::Polytrope barotrope(3.0, 0.25);
|
||||||
|
|
||||||
const mfem::Vector enthalpyTrue = pressure_force_kernel_test_utils::make_vacuum_only_enthalpy(f);
|
const mfem::Vector enthalpyTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_vacuum_only_enthalpy(f);
|
||||||
|
|
||||||
const double enthalpyNorm = gravity_prepared_test_utils::global_norm(enthalpyTrue, f.mesh->GetComm());
|
const double enthalpyNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(enthalpyTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensure this is a real exclusion test rather than another
|
* Ensure this is a real exclusion test rather than another
|
||||||
@@ -352,25 +359,25 @@ TEST_CASE(
|
|||||||
*/
|
*/
|
||||||
REQUIRE(enthalpyNorm > 0.0);
|
REQUIRE(enthalpyNorm > 0.0);
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = pressure_force_kernel_test_utils::make_zero_displacement(f);
|
const mfem::Vector displacementTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_zero_displacement(f);
|
||||||
|
|
||||||
mfem::Vector residualTrue;
|
mfem::Vector residualTrue;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_residual(
|
mean_field::operators::kernels::apply_pressure_force_residual(
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue, residualTrue
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue,
|
||||||
);
|
residualTrue);
|
||||||
|
|
||||||
REQUIRE(residualTrue.Size() == f.displacementFes->GetTrueVSize());
|
REQUIRE(residualTrue.Size() == f.displacementFes->GetTrueVSize());
|
||||||
|
|
||||||
const double residualNorm = gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
const double residualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
CHECK(residualNorm == 0.0);
|
CHECK(residualNorm == 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force Residual Is Nonzero For Positive Stellar Pressure",
|
||||||
"Pressure Force Residual Is Nonzero For Positive Stellar Pressure",
|
tags::barotrope &tags::pressure &tags::kernels &tags::integration) {
|
||||||
tags::barotrope &tags::pressure &tags::kernels &tags::integration
|
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -387,15 +394,17 @@ TEST_CASE(
|
|||||||
mfem::Vector enthalpyTrue(f.enthalpyFes->GetTrueVSize());
|
mfem::Vector enthalpyTrue(f.enthalpyFes->GetTrueVSize());
|
||||||
enthalpyTrue = 1.0;
|
enthalpyTrue = 1.0;
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = pressure_force_kernel_test_utils::make_zero_displacement(f);
|
const mfem::Vector displacementTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_zero_displacement(f);
|
||||||
|
|
||||||
mfem::Vector residualTrue;
|
mfem::Vector residualTrue;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_residual(
|
mean_field::operators::kernels::apply_pressure_force_residual(
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue, residualTrue
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue,
|
||||||
);
|
residualTrue);
|
||||||
|
|
||||||
const double residualNorm = gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
const double residualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
INFO("Positive-pressure residual norm = " << residualNorm);
|
INFO("Positive-pressure residual norm = " << residualNorm);
|
||||||
|
|
||||||
@@ -404,10 +413,9 @@ TEST_CASE(
|
|||||||
CHECK(residualNorm > 100.0 * std::numeric_limits<double>::epsilon());
|
CHECK(residualNorm > 100.0 * std::numeric_limits<double>::epsilon());
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force Residual Does No Work Against Rigid Translations",
|
||||||
"Pressure Force Residual Does No Work Against Rigid Translations",
|
tags::barotrope &tags::pressure &tags::kernels &tags::integration
|
||||||
tags::barotrope &tags::pressure &tags::kernels &tags::integration &tags::accuracy
|
&tags::accuracy) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -418,17 +426,20 @@ TEST_CASE(
|
|||||||
|
|
||||||
const mean_field::eos::Polytrope barotrope(3.0, 0.25);
|
const mean_field::eos::Polytrope barotrope(3.0, 0.25);
|
||||||
|
|
||||||
const mfem::Vector enthalpyTrue = pressure_force_kernel_test_utils::make_positive_asymmetric_enthalpy(f);
|
const mfem::Vector enthalpyTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_positive_asymmetric_enthalpy(f);
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = pressure_force_kernel_test_utils::make_zero_displacement(f);
|
const mfem::Vector displacementTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_zero_displacement(f);
|
||||||
|
|
||||||
mfem::Vector residualTrue;
|
mfem::Vector residualTrue;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_residual(
|
mean_field::operators::kernels::apply_pressure_force_residual(
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue, residualTrue
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue,
|
||||||
);
|
residualTrue);
|
||||||
|
|
||||||
const double residualNorm = gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
const double residualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(residualTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
REQUIRE(residualNorm > 0.0);
|
REQUIRE(residualNorm > 0.0);
|
||||||
|
|
||||||
@@ -436,14 +447,17 @@ TEST_CASE(
|
|||||||
|
|
||||||
for (int component = 0; component < dimension; ++component) {
|
for (int component = 0; component < dimension; ++component) {
|
||||||
const mfem::Vector translationTrue =
|
const mfem::Vector translationTrue =
|
||||||
pressure_force_kernel_test_utils::make_component_test_field(f, component, -1);
|
pressure_force_kernel_test_utils::make_component_test_field(
|
||||||
|
f, component, -1);
|
||||||
|
|
||||||
const double translationNorm = gravity_prepared_test_utils::global_norm(translationTrue, f.mesh->GetComm());
|
const double translationNorm = gravity_prepared_test_utils::global_norm(
|
||||||
|
translationTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
const double translationWork =
|
const double translationWork = pressure_force_kernel_test_utils::global_dot(
|
||||||
pressure_force_kernel_test_utils::global_dot(translationTrue, residualTrue, f.mesh->GetComm());
|
translationTrue, residualTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
const double dotProductScale = std::fmax(residualNorm * translationNorm, 1.0);
|
const double dotProductScale =
|
||||||
|
std::fmax(residualNorm * translationNorm, 1.0);
|
||||||
|
|
||||||
CAPTURE(component, translationWork, dotProductScale);
|
CAPTURE(component, translationWork, dotProductScale);
|
||||||
|
|
||||||
@@ -451,10 +465,9 @@ TEST_CASE(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force Residual Matches Independent Pressure Integral",
|
||||||
"Pressure Force Residual Matches Independent Pressure Integral",
|
tags::barotrope &tags::pressure &tags::kernels &tags::integration
|
||||||
tags::barotrope &tags::pressure &tags::kernels &tags::integration &tags::accuracy
|
&tags::accuracy) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -465,15 +478,17 @@ TEST_CASE(
|
|||||||
|
|
||||||
const mean_field::eos::Polytrope barotrope(3.0, 0.25);
|
const mean_field::eos::Polytrope barotrope(3.0, 0.25);
|
||||||
|
|
||||||
const mfem::Vector enthalpyTrue = pressure_force_kernel_test_utils::make_positive_asymmetric_enthalpy(f);
|
const mfem::Vector enthalpyTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_positive_asymmetric_enthalpy(f);
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = pressure_force_kernel_test_utils::make_zero_displacement(f);
|
const mfem::Vector displacementTrue =
|
||||||
|
pressure_force_kernel_test_utils::make_zero_displacement(f);
|
||||||
|
|
||||||
mfem::Vector residualTrue;
|
mfem::Vector residualTrue;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_residual(
|
mean_field::operators::kernels::apply_pressure_force_residual(
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue, residualTrue
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue,
|
||||||
);
|
residualTrue);
|
||||||
|
|
||||||
const int dimension = f.mesh->Dimension();
|
const int dimension = f.mesh->Dimension();
|
||||||
|
|
||||||
@@ -484,16 +499,19 @@ TEST_CASE(
|
|||||||
for (int component = 0; component < dimension; ++component) {
|
for (int component = 0; component < dimension; ++component) {
|
||||||
for (int coordinate = 0; coordinate < dimension; ++coordinate) {
|
for (int coordinate = 0; coordinate < dimension; ++coordinate) {
|
||||||
const mfem::Vector affineTestTrue =
|
const mfem::Vector affineTestTrue =
|
||||||
pressure_force_kernel_test_utils::make_component_test_field(f, component, coordinate);
|
pressure_force_kernel_test_utils::make_component_test_field(
|
||||||
|
f, component, coordinate);
|
||||||
|
|
||||||
virtualWork(component, coordinate) =
|
virtualWork(component, coordinate) =
|
||||||
pressure_force_kernel_test_utils::global_dot(affineTestTrue, residualTrue, f.mesh->GetComm());
|
pressure_force_kernel_test_utils::global_dot(
|
||||||
|
affineTestTrue, residualTrue, f.mesh->GetComm());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const double pressureIntegral = pressure_force_kernel_test_utils::integrate_pressure(
|
const double pressureIntegral =
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementTrue
|
pressure_force_kernel_test_utils::integrate_pressure(
|
||||||
);
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue,
|
||||||
|
displacementTrue);
|
||||||
|
|
||||||
REQUIRE(std::isfinite(pressureIntegral));
|
REQUIRE(std::isfinite(pressureIntegral));
|
||||||
|
|
||||||
@@ -527,25 +545,28 @@ TEST_CASE(
|
|||||||
for (int coordinate = 0; coordinate < dimension; ++coordinate) {
|
for (int coordinate = 0; coordinate < dimension; ++coordinate) {
|
||||||
const double computedWork = virtualWork(component, coordinate);
|
const double computedWork = virtualWork(component, coordinate);
|
||||||
|
|
||||||
const double expectedWork = component == coordinate ? -pressureIntegral : 0.0;
|
const double expectedWork =
|
||||||
|
component == coordinate ? -pressureIntegral : 0.0;
|
||||||
|
|
||||||
CAPTURE(component, coordinate, computedWork, expectedWork, pressureIntegral, comparisonTolerance);
|
CAPTURE(component, coordinate, computedWork, expectedWork,
|
||||||
|
pressureIntegral, comparisonTolerance);
|
||||||
|
|
||||||
CHECK(std::abs(computedWork - expectedWork) <= comparisonTolerance);
|
CHECK(std::abs(computedWork - expectedWork) <= comparisonTolerance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const double relativeMeanError = std::abs(meanDiagonalWork + pressureIntegral) / std::abs(pressureIntegral);
|
const double relativeMeanError =
|
||||||
|
std::abs(meanDiagonalWork + pressureIntegral) /
|
||||||
|
std::abs(pressureIntegral);
|
||||||
|
|
||||||
INFO("Relative mean diagonal error = " << relativeMeanError);
|
INFO("Relative mean diagonal error = " << relativeMeanError);
|
||||||
|
|
||||||
CHECK(relativeMeanError <= 1.0e-6);
|
CHECK(relativeMeanError <= 1.0e-6);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force Residual Matches Deformed Pressure Volume Variation",
|
||||||
"Pressure Force Residual Matches Deformed Pressure Volume Variation",
|
tags::barotrope &tags::pressure &tags::kernels &tags::integration
|
||||||
tags::barotrope &tags::pressure &tags::kernels &tags::integration &tags::accuracy
|
&tags::accuracy) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -559,14 +580,16 @@ TEST_CASE(
|
|||||||
* exercises a genuinely nonuniform pressure distribution.
|
* exercises a genuinely nonuniform pressure distribution.
|
||||||
*/
|
*/
|
||||||
const mfem::Vector enthalpyTrue =
|
const mfem::Vector enthalpyTrue =
|
||||||
pressure_force_kernel_test_utils::make_deterministic_vector(f.enthalpyFes->GetTrueVSize(), 0.37);
|
pressure_force_kernel_test_utils::make_deterministic_vector(
|
||||||
|
f.enthalpyFes->GetTrueVSize(), 0.37);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* make_displacement() contains anisotropic diagonal terms and
|
* make_displacement() contains anisotropic diagonal terms and
|
||||||
* quadratic cross terms. A scale of 0.67 therefore provides a
|
* quadratic cross terms. A scale of 0.67 therefore provides a
|
||||||
* nonzero, nonspherical, valid base geometry.
|
* nonzero, nonspherical, valid base geometry.
|
||||||
*/
|
*/
|
||||||
const mfem::Vector baseDisplacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.67);
|
const mfem::Vector baseDisplacementTrue =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.67);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Differentiate along the same smooth deformation family. Thus
|
* Differentiate along the same smooth deformation family. Thus
|
||||||
@@ -576,38 +599,43 @@ TEST_CASE(
|
|||||||
* This gives a controlled geometry path while still evaluating
|
* This gives a controlled geometry path while still evaluating
|
||||||
* the derivative at a genuinely deformed base state.
|
* the derivative at a genuinely deformed base state.
|
||||||
*/
|
*/
|
||||||
const mfem::Vector displacementVariationTrue = gravity_prepared_test_utils::make_displacement(f, 1.0);
|
const mfem::Vector displacementVariationTrue =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 1.0);
|
||||||
|
|
||||||
const double baseDisplacementNorm =
|
const double baseDisplacementNorm = gravity_prepared_test_utils::global_norm(
|
||||||
gravity_prepared_test_utils::global_norm(baseDisplacementTrue, f.mesh->GetComm());
|
baseDisplacementTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
const double variationNorm = gravity_prepared_test_utils::global_norm(displacementVariationTrue, f.mesh->GetComm());
|
const double variationNorm = gravity_prepared_test_utils::global_norm(
|
||||||
|
displacementVariationTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
REQUIRE(baseDisplacementNorm > 100.0 * std::numeric_limits<double>::epsilon());
|
REQUIRE(baseDisplacementNorm >
|
||||||
|
100.0 * std::numeric_limits<double>::epsilon());
|
||||||
|
|
||||||
REQUIRE(variationNorm > 100.0 * std::numeric_limits<double>::epsilon());
|
REQUIRE(variationNorm > 100.0 * std::numeric_limits<double>::epsilon());
|
||||||
|
|
||||||
mfem::Vector residualTrue;
|
mfem::Vector residualTrue;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_residual(
|
mean_field::operators::kernels::apply_pressure_force_residual(
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, baseDisplacementTrue, residualTrue
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue,
|
||||||
);
|
baseDisplacementTrue, residualTrue);
|
||||||
|
|
||||||
REQUIRE(residualTrue.Size() == f.displacementFes->GetTrueVSize());
|
REQUIRE(residualTrue.Size() == f.displacementFes->GetTrueVSize());
|
||||||
|
|
||||||
const double residualWork =
|
const double residualWork = pressure_force_kernel_test_utils::global_dot(
|
||||||
pressure_force_kernel_test_utils::global_dot(displacementVariationTrue, residualTrue, f.mesh->GetComm());
|
displacementVariationTrue, residualTrue, f.mesh->GetComm());
|
||||||
|
|
||||||
REQUIRE(std::isfinite(residualWork));
|
REQUIRE(std::isfinite(residualWork));
|
||||||
|
|
||||||
REQUIRE(std::abs(residualWork) > 100.0 * std::numeric_limits<double>::epsilon());
|
REQUIRE(std::abs(residualWork) >
|
||||||
|
100.0 * std::numeric_limits<double>::epsilon());
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The relatively broad initial sweep lets us see the expected
|
* The relatively broad initial sweep lets us see the expected
|
||||||
* centered-difference convergence before reaching the quadrature
|
* centered-difference convergence before reaching the quadrature
|
||||||
* and representation plateau.
|
* and representation plateau.
|
||||||
*/
|
*/
|
||||||
constexpr std::array<double, 4> differenceSteps{1.0e-2, 5.0e-3, 2.5e-3, 1.25e-3};
|
constexpr std::array<double, 4> differenceSteps{1.0e-2, 5.0e-3, 2.5e-3,
|
||||||
|
1.25e-3};
|
||||||
|
|
||||||
double bestRelativeDiscrepancy = std::numeric_limits<double>::infinity();
|
double bestRelativeDiscrepancy = std::numeric_limits<double>::infinity();
|
||||||
|
|
||||||
@@ -620,18 +648,21 @@ TEST_CASE(
|
|||||||
|
|
||||||
displacementMinus.Add(-differenceStep, displacementVariationTrue);
|
displacementMinus.Add(-differenceStep, displacementVariationTrue);
|
||||||
|
|
||||||
const double pressureIntegralPlus = pressure_force_kernel_test_utils::integrate_pressure(
|
const double pressureIntegralPlus =
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementPlus
|
pressure_force_kernel_test_utils::integrate_pressure(
|
||||||
);
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue,
|
||||||
|
displacementPlus);
|
||||||
|
|
||||||
const double pressureIntegralMinus = pressure_force_kernel_test_utils::integrate_pressure(
|
const double pressureIntegralMinus =
|
||||||
f, *f.domainMapperStateless, barotrope, enthalpyTrue, displacementMinus
|
pressure_force_kernel_test_utils::integrate_pressure(
|
||||||
);
|
f, *f.domainMapperStateless, barotrope, enthalpyTrue,
|
||||||
|
displacementMinus);
|
||||||
|
|
||||||
REQUIRE(std::isfinite(pressureIntegralPlus));
|
REQUIRE(std::isfinite(pressureIntegralPlus));
|
||||||
REQUIRE(std::isfinite(pressureIntegralMinus));
|
REQUIRE(std::isfinite(pressureIntegralMinus));
|
||||||
|
|
||||||
const double pressureVolumeDerivative = (pressureIntegralPlus - pressureIntegralMinus) / (2.0 * differenceStep);
|
const double pressureVolumeDerivative =
|
||||||
|
(pressureIntegralPlus - pressureIntegralMinus) / (2.0 * differenceStep);
|
||||||
|
|
||||||
REQUIRE(std::isfinite(pressureVolumeDerivative));
|
REQUIRE(std::isfinite(pressureVolumeDerivative));
|
||||||
|
|
||||||
@@ -643,7 +674,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
REQUIRE(comparisonScale > 100.0 * std::numeric_limits<double>::epsilon());
|
REQUIRE(comparisonScale > 100.0 * std::numeric_limits<double>::epsilon());
|
||||||
|
|
||||||
const double absoluteDiscrepancy = std::abs(residualWork + pressureVolumeDerivative);
|
const double absoluteDiscrepancy =
|
||||||
|
std::abs(residualWork + pressureVolumeDerivative);
|
||||||
|
|
||||||
const double relativeDiscrepancy = absoluteDiscrepancy / comparisonScale;
|
const double relativeDiscrepancy = absoluteDiscrepancy / comparisonScale;
|
||||||
|
|
||||||
@@ -657,7 +689,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
INFO("Pressure-volume derivative = " << pressureVolumeDerivative);
|
INFO("Pressure-volume derivative = " << pressureVolumeDerivative);
|
||||||
|
|
||||||
INFO("Residual work plus derivative = " << residualWork + pressureVolumeDerivative);
|
INFO("Residual work plus derivative = " << residualWork +
|
||||||
|
pressureVolumeDerivative);
|
||||||
|
|
||||||
INFO("Relative discrepancy = " << relativeDiscrepancy);
|
INFO("Relative discrepancy = " << relativeDiscrepancy);
|
||||||
|
|
||||||
@@ -669,7 +702,8 @@ TEST_CASE(
|
|||||||
CHECK(residualWork * pressureVolumeDerivative < 0.0);
|
CHECK(residualWork * pressureVolumeDerivative < 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO("Best pressure-volume relative discrepancy = " << bestRelativeDiscrepancy);
|
INFO("Best pressure-volume relative discrepancy = "
|
||||||
|
<< bestRelativeDiscrepancy);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This is intentionally a provisional but meaningful threshold.
|
* This is intentionally a provisional but meaningful threshold.
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include <catch2/catch_test_macros.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
#include <catch2/matchers/catch_matchers_floating_point.hpp>
|
||||||
|
#include <cmath>
|
||||||
#include <mfem.hpp>
|
#include <mfem.hpp>
|
||||||
|
|
||||||
import mean_field;
|
import mean_field;
|
||||||
@@ -9,28 +10,33 @@ using namespace mean_field;
|
|||||||
using Catch::Matchers::WithinAbs;
|
using Catch::Matchers::WithinAbs;
|
||||||
namespace prepared_test = gravity_prepared_test_utils;
|
namespace prepared_test = gravity_prepared_test_utils;
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Mapped Hdiv Mass Matches Stateless Kernel",
|
||||||
"Prepared Mapped Hdiv Mass Matches Stateless Kernel",
|
tags::gravity_prepared) {
|
||||||
tags::gravity_prepared
|
|
||||||
) {
|
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
operators::PreparedMappedHDivMassOperator prepared_operator(f, *f.domainMapperStateless);
|
operators::PreparedMappedHDivMassOperator prepared_operator(
|
||||||
REQUIRE(prepared_operator.Width() == prepared_operator.GetFluxMap().reduced_size());
|
f, *f.domainMapperStateless);
|
||||||
REQUIRE(prepared_operator.Height() == prepared_operator.GetFluxMap().reduced_size());
|
REQUIRE(prepared_operator.Width() ==
|
||||||
|
prepared_operator.GetFluxMap().reduced_size());
|
||||||
|
REQUIRE(prepared_operator.Height() ==
|
||||||
|
prepared_operator.GetFluxMap().reduced_size());
|
||||||
|
|
||||||
const mfem::Vector gravity_gradient_true =
|
const mfem::Vector gravity_gradient_true =
|
||||||
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.21);
|
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(),
|
||||||
const mfem::Vector gravity_gradient = prepared_operator.GetFluxMap().gather(gravity_gradient_true);
|
0.21);
|
||||||
|
const mfem::Vector gravity_gradient =
|
||||||
|
prepared_operator.GetFluxMap().gather(gravity_gradient_true);
|
||||||
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
|
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
|
||||||
|
|
||||||
mfem::Vector identity_action;
|
mfem::Vector identity_action;
|
||||||
mfem::Vector deformed_action;
|
mfem::Vector deformed_action;
|
||||||
|
|
||||||
for (const double deformation_scale : {0.0, 1.0}) {
|
for (const double deformation_scale : {0.0, 1.0}) {
|
||||||
const mfem::Vector displacement_true = prepared_test::make_displacement(f, deformation_scale);
|
const mfem::Vector displacement_true =
|
||||||
const mfem::Vector displacement = prepared_operator.GetDisplacementMap().gather(displacement_true);
|
prepared_test::make_displacement(f, deformation_scale);
|
||||||
|
const mfem::Vector displacement =
|
||||||
|
prepared_operator.GetDisplacementMap().gather(displacement_true);
|
||||||
|
|
||||||
prepared_operator.Prepare(displacement);
|
prepared_operator.Prepare(displacement);
|
||||||
|
|
||||||
@@ -39,15 +45,19 @@ TEST_CASE(
|
|||||||
prepared_operator.Mult(gravity_gradient, prepared_action);
|
prepared_operator.Mult(gravity_gradient, prepared_action);
|
||||||
mfem::Vector reference_action_true;
|
mfem::Vector reference_action_true;
|
||||||
operators::kernels::apply_mapped_hdiv_mass(
|
operators::kernels::apply_mapped_hdiv_mass(
|
||||||
f, *f.domainMapperStateless, gravity_gradient_true, displacement_true, reference_action_true
|
f, *f.domainMapperStateless, gravity_gradient_true, displacement_true,
|
||||||
);
|
reference_action_true);
|
||||||
const mfem::Vector reference_action = prepared_operator.GetFluxMap().gather(reference_action_true);
|
const mfem::Vector reference_action =
|
||||||
|
prepared_operator.GetFluxMap().gather(reference_action_true);
|
||||||
|
|
||||||
const double relative_error = prepared_test::relative_error(prepared_action, reference_action, communicator);
|
const double relative_error = prepared_test::relative_error(
|
||||||
|
prepared_action, reference_action, communicator);
|
||||||
|
|
||||||
INFO("Deformation scale = " << deformation_scale);
|
INFO("Deformation scale = " << deformation_scale);
|
||||||
INFO("Prepared action norm = " << prepared_test::global_norm(prepared_action, communicator));
|
INFO("Prepared action norm = "
|
||||||
INFO("Reference action norm = " << prepared_test::global_norm(reference_action, communicator));
|
<< prepared_test::global_norm(prepared_action, communicator));
|
||||||
|
INFO("Reference action norm = "
|
||||||
|
<< prepared_test::global_norm(reference_action, communicator));
|
||||||
INFO("Relative prepared-operator error = " << relative_error);
|
INFO("Relative prepared-operator error = " << relative_error);
|
||||||
|
|
||||||
REQUIRE(prepared_operator.IsPrepared());
|
REQUIRE(prepared_operator.IsPrepared());
|
||||||
@@ -60,7 +70,8 @@ TEST_CASE(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const double geometry_change = prepared_test::relative_error(deformed_action, identity_action, communicator);
|
const double geometry_change = prepared_test::relative_error(
|
||||||
|
deformed_action, identity_action, communicator);
|
||||||
|
|
||||||
INFO("Relative action change under deformation = " << geometry_change);
|
INFO("Relative action change under deformation = " << geometry_change);
|
||||||
|
|
||||||
@@ -68,27 +79,30 @@ TEST_CASE(
|
|||||||
CHECK(geometry_change > 1.0e-5);
|
CHECK(geometry_change > 1.0e-5);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Mapped Hdiv Mass Preserves Operator Identities",
|
||||||
"Prepared Mapped Hdiv Mass Preserves Operator Identities",
|
tags::gravity_prepared) {
|
||||||
tags::gravity_prepared
|
|
||||||
) {
|
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
operators::PreparedMappedHDivMassOperator prepared_operator(f, *f.domainMapperStateless);
|
operators::PreparedMappedHDivMassOperator prepared_operator(
|
||||||
REQUIRE(prepared_operator.Width() == prepared_operator.GetFluxMap().reduced_size());
|
f, *f.domainMapperStateless);
|
||||||
REQUIRE(prepared_operator.Height() == prepared_operator.GetFluxMap().reduced_size());
|
REQUIRE(prepared_operator.Width() ==
|
||||||
|
prepared_operator.GetFluxMap().reduced_size());
|
||||||
|
REQUIRE(prepared_operator.Height() ==
|
||||||
|
prepared_operator.GetFluxMap().reduced_size());
|
||||||
const mfem::Vector displacement =
|
const mfem::Vector displacement =
|
||||||
prepared_operator.GetDisplacementMap().gather(prepared_test::make_displacement(f, 1.0));
|
prepared_operator.GetDisplacementMap().gather(
|
||||||
|
prepared_test::make_displacement(f, 1.0));
|
||||||
prepared_operator.Prepare(displacement);
|
prepared_operator.Prepare(displacement);
|
||||||
|
|
||||||
const mfem::Vector first = prepared_operator.GetFluxMap().gather(
|
const mfem::Vector first = prepared_operator.GetFluxMap().gather(
|
||||||
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.17)
|
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(),
|
||||||
);
|
0.17));
|
||||||
const mfem::Vector second = prepared_operator.GetFluxMap().gather(
|
const mfem::Vector second = prepared_operator.GetFluxMap().gather(
|
||||||
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(), 0.83)
|
prepared_test::make_deterministic_vector(f.gravityFluxFes->GetTrueVSize(),
|
||||||
);
|
0.83));
|
||||||
const mfem::Vector combination = prepared_test::linear_combination(first, 1.7, second, -0.4);
|
const mfem::Vector combination =
|
||||||
|
prepared_test::linear_combination(first, 1.7, second, -0.4);
|
||||||
|
|
||||||
mfem::Vector first_action;
|
mfem::Vector first_action;
|
||||||
mfem::Vector second_action;
|
mfem::Vector second_action;
|
||||||
@@ -99,7 +113,8 @@ TEST_CASE(
|
|||||||
prepared_operator.Mult(second, second_action);
|
prepared_operator.Mult(second, second_action);
|
||||||
prepared_operator.Mult(combination, combination_action);
|
prepared_operator.Mult(combination, combination_action);
|
||||||
|
|
||||||
mfem::Vector expected_combination = prepared_test::linear_combination(first_action, 1.7, second_action, -0.4);
|
mfem::Vector expected_combination =
|
||||||
|
prepared_test::linear_combination(first_action, 1.7, second_action, -0.4);
|
||||||
|
|
||||||
mfem::Vector zero(first.Size());
|
mfem::Vector zero(first.Size());
|
||||||
zero = 0.0;
|
zero = 0.0;
|
||||||
@@ -107,14 +122,20 @@ TEST_CASE(
|
|||||||
|
|
||||||
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
|
const MPI_Comm communicator = f.gravityFluxFes->GetComm();
|
||||||
|
|
||||||
const double first_second_product = prepared_test::global_dot(first, second_action, communicator);
|
const double first_second_product =
|
||||||
const double second_first_product = prepared_test::global_dot(second, first_action, communicator);
|
prepared_test::global_dot(first, second_action, communicator);
|
||||||
const double symmetry_error = prepared_test::relative_scalar_error(first_second_product, second_first_product);
|
const double second_first_product =
|
||||||
const double linearity_error =
|
prepared_test::global_dot(second, first_action, communicator);
|
||||||
prepared_test::relative_error(combination_action, expected_combination, communicator);
|
const double symmetry_error = prepared_test::relative_scalar_error(
|
||||||
const double first_energy = prepared_test::global_dot(first, first_action, communicator);
|
first_second_product, second_first_product);
|
||||||
const double second_energy = prepared_test::global_dot(second, second_action, communicator);
|
const double linearity_error = prepared_test::relative_error(
|
||||||
const std::uint64_t preparation_count = prepared_operator.GetPreparationCount();
|
combination_action, expected_combination, communicator);
|
||||||
|
const double first_energy =
|
||||||
|
prepared_test::global_dot(first, first_action, communicator);
|
||||||
|
const double second_energy =
|
||||||
|
prepared_test::global_dot(second, second_action, communicator);
|
||||||
|
const std::uint64_t preparation_count =
|
||||||
|
prepared_operator.GetPreparationCount();
|
||||||
|
|
||||||
mfem::Vector repeated_action;
|
mfem::Vector repeated_action;
|
||||||
prepared_operator.Mult(first, repeated_action);
|
prepared_operator.Mult(first, repeated_action);
|
||||||
@@ -128,9 +149,42 @@ TEST_CASE(
|
|||||||
|
|
||||||
CHECK_THAT(symmetry_error, WithinAbs(0.0, 2.0e-12));
|
CHECK_THAT(symmetry_error, WithinAbs(0.0, 2.0e-12));
|
||||||
CHECK_THAT(linearity_error, WithinAbs(0.0, 2.0e-12));
|
CHECK_THAT(linearity_error, WithinAbs(0.0, 2.0e-12));
|
||||||
CHECK_THAT(prepared_test::global_norm(zero_action, communicator), WithinAbs(0.0, 1.0e-14));
|
CHECK_THAT(prepared_test::global_norm(zero_action, communicator),
|
||||||
|
WithinAbs(0.0, 1.0e-14));
|
||||||
CHECK(first_energy > 0.0);
|
CHECK(first_energy > 0.0);
|
||||||
CHECK(second_energy > 0.0);
|
CHECK(second_energy > 0.0);
|
||||||
CHECK(prepared_test::relative_error(repeated_action, first_action, communicator) < 2.0e-14);
|
CHECK(prepared_test::relative_error(repeated_action, first_action,
|
||||||
|
communicator) < 2.0e-14);
|
||||||
CHECK(prepared_operator.GetPreparationCount() == preparation_count);
|
CHECK(prepared_operator.GetPreparationCount() == preparation_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("Prepared Mapped Hdiv Mass Diagonal Is Positive Across Both Domains",
|
||||||
|
tags::gravity_prepared) {
|
||||||
|
auto args = test_utils::setup_args();
|
||||||
|
fem::FEM f = fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
|
operators::PreparedMappedHDivMassOperator prepared_operator(
|
||||||
|
f, *f.domainMapperStateless);
|
||||||
|
const mfem::Vector displacement =
|
||||||
|
prepared_operator.GetDisplacementMap().gather(
|
||||||
|
prepared_test::make_displacement(f, 1.0));
|
||||||
|
prepared_operator.Prepare(displacement);
|
||||||
|
|
||||||
|
mfem::Vector diagonal;
|
||||||
|
mfem::Vector true_diagonal;
|
||||||
|
prepared_operator.AssembleDiagonal(diagonal);
|
||||||
|
prepared_operator.AssembleTrueDiagonal(true_diagonal);
|
||||||
|
|
||||||
|
REQUIRE(diagonal.Size() == prepared_operator.Height());
|
||||||
|
REQUIRE(true_diagonal.Size() == prepared_operator.GetFluxMap().full_size());
|
||||||
|
|
||||||
|
const mfem::Vector gathered_true_diagonal =
|
||||||
|
prepared_operator.GetFluxMap().gather(true_diagonal);
|
||||||
|
|
||||||
|
for (int i = 0; i < diagonal.Size(); ++i) {
|
||||||
|
REQUIRE(std::isfinite(diagonal(i)));
|
||||||
|
CHECK(diagonal(i) > 0.0);
|
||||||
|
CHECK_THAT(diagonal(i), WithinAbs(gathered_true_diagonal(i),
|
||||||
|
1.0e-14 * std::abs(diagonal(i))));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -24,52 +24,40 @@ namespace prepared_hydrostatic_analytic_solve_test_utils {
|
|||||||
public:
|
public:
|
||||||
EnthalpyJacobianOperator(
|
EnthalpyJacobianOperator(
|
||||||
const int enthalpySize,
|
const int enthalpySize,
|
||||||
const mean_field::operators::PreparedHydrostaticEquilibriumOperator &preparedOperator
|
const mean_field::operators::PreparedHydrostaticEquilibriumOperator
|
||||||
)
|
&preparedOperator)
|
||||||
: mfem::Operator(enthalpySize),
|
: mfem::Operator(enthalpySize), m_preparedOperator(preparedOperator) {}
|
||||||
m_preparedOperator(preparedOperator) {
|
|
||||||
}
|
|
||||||
|
|
||||||
void Mult(
|
void Mult(const mfem::Vector &direction,
|
||||||
const mfem::Vector &direction,
|
mfem::Vector &action) const override {
|
||||||
mfem::Vector &action
|
|
||||||
) const override {
|
|
||||||
m_preparedOperator.ApplyEnthalpyJacobianAction(direction, action);
|
m_preparedOperator.ApplyEnthalpyJacobianAction(direction, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const mean_field::operators::PreparedHydrostaticEquilibriumOperator &m_preparedOperator;
|
const mean_field::operators::PreparedHydrostaticEquilibriumOperator
|
||||||
|
&m_preparedOperator;
|
||||||
};
|
};
|
||||||
|
|
||||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumDependencies make_dependencies() {
|
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumDependencies
|
||||||
return {
|
make_dependencies() {
|
||||||
.discretization = {.identity = 701, .revision = 2},
|
return {.discretization = {.identity = 701, .revision = 2},
|
||||||
.enthalpy = {.identity = 709, .revision = 3},
|
.enthalpy = {.identity = 709, .revision = 3},
|
||||||
.gravityPotential = {.identity = 719, .revision = 5},
|
.gravityPotential = {.identity = 719, .revision = 5},
|
||||||
.displacement = {.identity = 727, .revision = 7},
|
.displacement = {.identity = 727, .revision = 7},
|
||||||
.rotation = {.identity = 733, .revision = 11},
|
.rotation = {.identity = 733, .revision = 11},
|
||||||
.bernoulliConstant = {.identity = 739, .revision = 13}
|
.bernoulliConstant = {.identity = 739, .revision = 13}};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumStateView make_state(
|
mean_field::operators::context::hydrostatic::HydrostaticEquilibriumStateView
|
||||||
const mfem::Vector &enthalpy,
|
make_state(const mfem::Vector &enthalpy, const mfem::Vector &gravityPotential,
|
||||||
const mfem::Vector &gravityPotential,
|
const mfem::Vector &displacement) {
|
||||||
const mfem::Vector &displacement
|
return {.enthalpy = enthalpy,
|
||||||
) {
|
|
||||||
return {
|
|
||||||
.enthalpy = enthalpy,
|
|
||||||
.gravityPotential = gravityPotential,
|
.gravityPotential = gravityPotential,
|
||||||
.displacement = displacement,
|
.displacement = displacement,
|
||||||
.bernoulliConstant = bernoulliConstant
|
.bernoulliConstant = bernoulliConstant};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Vector make_vector(
|
mfem::Vector make_vector(const std::array<double, 3> &values) {
|
||||||
const std::array<
|
|
||||||
double,
|
|
||||||
3> &values
|
|
||||||
) {
|
|
||||||
mfem::Vector vector(3);
|
mfem::Vector vector(3);
|
||||||
|
|
||||||
for (int component = 0; component < 3; ++component) {
|
for (int component = 0; component < 3; ++component) {
|
||||||
@@ -79,22 +67,22 @@ namespace prepared_hydrostatic_analytic_solve_test_utils {
|
|||||||
return vector;
|
return vector;
|
||||||
}
|
}
|
||||||
|
|
||||||
mean_field::physics::RigidRotation make_rotation(const AnalyticCase &analyticCase) {
|
mean_field::physics::RigidRotation
|
||||||
|
make_rotation(const AnalyticCase &analyticCase) {
|
||||||
return mean_field::physics::RigidRotation(
|
return mean_field::physics::RigidRotation(
|
||||||
make_vector(analyticCase.angularVelocity), make_vector(analyticCase.rotationCenter)
|
make_vector(analyticCase.angularVelocity),
|
||||||
);
|
make_vector(analyticCase.rotationCenter));
|
||||||
}
|
}
|
||||||
|
|
||||||
void map_to_physical(
|
void map_to_physical(const mfem::Vector &referencePosition,
|
||||||
const mfem::Vector &referencePosition,
|
|
||||||
const AnalyticCase &analyticCase,
|
const AnalyticCase &analyticCase,
|
||||||
mfem::Vector &physicalPosition
|
mfem::Vector &physicalPosition) {
|
||||||
) {
|
|
||||||
physicalPosition.SetSize(3);
|
physicalPosition.SetSize(3);
|
||||||
|
|
||||||
for (int component = 0; component < 3; ++component) {
|
for (int component = 0; component < 3; ++component) {
|
||||||
physicalPosition(component) =
|
physicalPosition(component) =
|
||||||
analyticCase.deformationScale[static_cast<std::size_t>(component)] * referencePosition(component);
|
analyticCase.deformationScale[static_cast<std::size_t>(component)] *
|
||||||
|
referencePosition(component);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,7 +90,8 @@ namespace prepared_hydrostatic_analytic_solve_test_utils {
|
|||||||
double normalizedRadiusSquared = 0.0;
|
double normalizedRadiusSquared = 0.0;
|
||||||
|
|
||||||
for (int component = 0; component < 3; ++component) {
|
for (int component = 0; component < 3; ++component) {
|
||||||
const double normalizedCoordinate = referencePosition(component) / mean_field::utils::RADIUS;
|
const double normalizedCoordinate =
|
||||||
|
referencePosition(component) / mean_field::utils::RADIUS;
|
||||||
|
|
||||||
normalizedRadiusSquared += normalizedCoordinate * normalizedCoordinate;
|
normalizedRadiusSquared += normalizedCoordinate * normalizedCoordinate;
|
||||||
}
|
}
|
||||||
@@ -110,11 +99,10 @@ namespace prepared_hydrostatic_analytic_solve_test_utils {
|
|||||||
return enthalpyAmplitude * std::max(0.0, 1.0 - normalizedRadiusSquared);
|
return enthalpyAmplitude * std::max(0.0, 1.0 - normalizedRadiusSquared);
|
||||||
}
|
}
|
||||||
|
|
||||||
double exact_potential_value(
|
double
|
||||||
const mfem::Vector &referencePosition,
|
exact_potential_value(const mfem::Vector &referencePosition,
|
||||||
const AnalyticCase &analyticCase,
|
const AnalyticCase &analyticCase,
|
||||||
const mean_field::physics::RigidRotation &rotation
|
const mean_field::physics::RigidRotation &rotation) {
|
||||||
) {
|
|
||||||
mfem::Vector physicalPosition;
|
mfem::Vector physicalPosition;
|
||||||
|
|
||||||
map_to_physical(referencePosition, analyticCase, physicalPosition);
|
map_to_physical(referencePosition, analyticCase, physicalPosition);
|
||||||
@@ -126,26 +114,27 @@ namespace prepared_hydrostatic_analytic_solve_test_utils {
|
|||||||
*
|
*
|
||||||
* analytically.
|
* analytically.
|
||||||
*/
|
*/
|
||||||
return bernoulliConstant + rotation.potential(physicalPosition) - exact_enthalpy_value(referencePosition);
|
return bernoulliConstant + rotation.potential(physicalPosition) -
|
||||||
|
exact_enthalpy_value(referencePosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
mfem::Array<int> make_stellar_element_marker(const mean_field::fem::FEM &f) {
|
mfem::Array<int> make_stellar_element_marker(const mean_field::fem::FEM &f) {
|
||||||
mfem::Array<int> stellarElementMarker(f.mesh->GetNE());
|
mfem::Array<int> stellarElementMarker(f.mesh->GetNE());
|
||||||
|
|
||||||
const int vacuumAttribute = f.domainMapperStateless->GetVacuumElementAttribute();
|
const int vacuumAttribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
stellarElementMarker[elementId] = f.mesh->GetAttribute(elementId) != vacuumAttribute;
|
stellarElementMarker[elementId] =
|
||||||
|
f.mesh->GetAttribute(elementId) != vacuumAttribute;
|
||||||
}
|
}
|
||||||
|
|
||||||
return stellarElementMarker;
|
return stellarElementMarker;
|
||||||
}
|
}
|
||||||
} // namespace prepared_hydrostatic_analytic_solve_test_utils
|
} // namespace prepared_hydrostatic_analytic_solve_test_utils
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Hydrostatic Operator Solves Analytic Bernoulli Equilibria",
|
||||||
"Prepared Hydrostatic Operator Solves Analytic Bernoulli Equilibria",
|
tags::barotrope_hydrostatic_prepared_analytic &tags::convergence
|
||||||
tags::barotrope_hydrostatic_prepared_analytic &tags::convergence &tags::accuracy
|
&tags::accuracy) {
|
||||||
) {
|
|
||||||
using prepared_hydrostatic_analytic_solve_test_utils::AnalyticCase;
|
using prepared_hydrostatic_analytic_solve_test_utils::AnalyticCase;
|
||||||
|
|
||||||
constexpr double deformationX = 1.08;
|
constexpr double deformationX = 1.08;
|
||||||
@@ -171,8 +160,7 @@ TEST_CASE(
|
|||||||
{.name = "volume-preserving deformed rotating equilibrium",
|
{.name = "volume-preserving deformed rotating equilibrium",
|
||||||
.deformationScale = {deformationX, deformationY, deformationZ},
|
.deformationScale = {deformationX, deformationY, deformationZ},
|
||||||
.angularVelocity = {0.17, -0.12, 0.43},
|
.angularVelocity = {0.17, -0.12, 0.43},
|
||||||
.rotationCenter = {0.031, -0.024, 0.018}}}
|
.rotationCenter = {0.031, -0.024, 0.018}}}};
|
||||||
};
|
|
||||||
|
|
||||||
auto args = test_utils::setup_args();
|
auto args = test_utils::setup_args();
|
||||||
|
|
||||||
@@ -181,51 +169,59 @@ TEST_CASE(
|
|||||||
const MPI_Comm communicator = f.mesh->GetComm();
|
const MPI_Comm communicator = f.mesh->GetComm();
|
||||||
|
|
||||||
const mean_field::field::FieldDofMap enthalpyMap =
|
const mean_field::field::FieldDofMap enthalpyMap =
|
||||||
field_dof_test_utils::make_map<mean_field::field::Enthalpy>(*f.enthalpyFes);
|
field_dof_test_utils::make_map<mean_field::field::Enthalpy>(
|
||||||
|
*f.enthalpyFes);
|
||||||
|
|
||||||
const mean_field::field::FieldDofMap gravityPotentialMap =
|
const mean_field::field::FieldDofMap gravityPotentialMap =
|
||||||
field_dof_test_utils::make_map<mean_field::field::Gravity>(*f.gravityPotentialFes);
|
field_dof_test_utils::make_map<mean_field::field::Gravity>(
|
||||||
|
*f.gravityPotentialFes);
|
||||||
|
|
||||||
const mean_field::field::FieldDofMap displacementMap =
|
const mean_field::field::FieldDofMap displacementMap =
|
||||||
field_dof_test_utils::make_map<mean_field::field::Displacement>(*f.displacementFes);
|
field_dof_test_utils::make_map<mean_field::field::Displacement>(
|
||||||
|
*f.displacementFes);
|
||||||
|
|
||||||
const mfem::Array<int> stellarElementMarker =
|
const mfem::Array<int> stellarElementMarker =
|
||||||
prepared_hydrostatic_analytic_solve_test_utils::make_stellar_element_marker(f);
|
prepared_hydrostatic_analytic_solve_test_utils::
|
||||||
|
make_stellar_element_marker(f);
|
||||||
|
|
||||||
for (const AnalyticCase &analyticCase : analyticCases) {
|
for (const AnalyticCase &analyticCase : analyticCases) {
|
||||||
DYNAMIC_SECTION(analyticCase.name) {
|
DYNAMIC_SECTION(analyticCase.name) {
|
||||||
const double deformationDeterminant =
|
const double deformationDeterminant = analyticCase.deformationScale[0] *
|
||||||
analyticCase.deformationScale[0] * analyticCase.deformationScale[1] * analyticCase.deformationScale[2];
|
analyticCase.deformationScale[1] *
|
||||||
|
analyticCase.deformationScale[2];
|
||||||
|
|
||||||
REQUIRE(std::abs(deformationDeterminant - 1.0) < 2.0e-14);
|
REQUIRE(std::abs(deformationDeterminant - 1.0) < 2.0e-14);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation =
|
const mean_field::physics::RigidRotation rotation =
|
||||||
prepared_hydrostatic_analytic_solve_test_utils::make_rotation(analyticCase);
|
prepared_hydrostatic_analytic_solve_test_utils::make_rotation(
|
||||||
|
analyticCase);
|
||||||
|
|
||||||
auto displacementFunction =
|
auto displacementFunction =
|
||||||
[&analyticCase](const mfem::Vector &referencePosition, mfem::Vector &displacementValue) {
|
[&analyticCase](const mfem::Vector &referencePosition,
|
||||||
|
mfem::Vector &displacementValue) {
|
||||||
mfem::Vector physicalPosition;
|
mfem::Vector physicalPosition;
|
||||||
|
|
||||||
prepared_hydrostatic_analytic_solve_test_utils::map_to_physical(
|
prepared_hydrostatic_analytic_solve_test_utils::map_to_physical(
|
||||||
referencePosition, analyticCase, physicalPosition
|
referencePosition, analyticCase, physicalPosition);
|
||||||
);
|
|
||||||
|
|
||||||
displacementValue.SetSize(3);
|
displacementValue.SetSize(3);
|
||||||
displacementValue = physicalPosition;
|
displacementValue = physicalPosition;
|
||||||
displacementValue -= referencePosition;
|
displacementValue -= referencePosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
auto potentialFunction = [&analyticCase, &rotation](const mfem::Vector &referencePosition) {
|
auto potentialFunction = [&analyticCase, &rotation](
|
||||||
return prepared_hydrostatic_analytic_solve_test_utils::exact_potential_value(
|
const mfem::Vector &referencePosition) {
|
||||||
referencePosition, analyticCase, rotation
|
return prepared_hydrostatic_analytic_solve_test_utils::
|
||||||
);
|
exact_potential_value(referencePosition, analyticCase, rotation);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto enthalpyFunction = [](const mfem::Vector &referencePosition) {
|
auto enthalpyFunction = [](const mfem::Vector &referencePosition) {
|
||||||
return prepared_hydrostatic_analytic_solve_test_utils::exact_enthalpy_value(referencePosition);
|
return prepared_hydrostatic_analytic_solve_test_utils::
|
||||||
|
exact_enthalpy_value(referencePosition);
|
||||||
};
|
};
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient displacementCoefficient(f.mesh->Dimension(), displacementFunction);
|
mfem::VectorFunctionCoefficient displacementCoefficient(
|
||||||
|
f.mesh->Dimension(), displacementFunction);
|
||||||
|
|
||||||
mfem::FunctionCoefficient potentialCoefficient(potentialFunction);
|
mfem::FunctionCoefficient potentialCoefficient(potentialFunction);
|
||||||
|
|
||||||
@@ -248,8 +244,10 @@ TEST_CASE(
|
|||||||
displacementField.GetTrueDofs(displacementTrue);
|
displacementField.GetTrueDofs(displacementTrue);
|
||||||
potentialField.GetTrueDofs(gravityPotentialTrue);
|
potentialField.GetTrueDofs(gravityPotentialTrue);
|
||||||
|
|
||||||
const mfem::Vector displacement = displacementMap.gather(displacementTrue);
|
const mfem::Vector displacement =
|
||||||
const mfem::Vector gravityPotential = gravityPotentialMap.gather(gravityPotentialTrue);
|
displacementMap.gather(displacementTrue);
|
||||||
|
const mfem::Vector gravityPotential =
|
||||||
|
gravityPotentialMap.gather(gravityPotentialTrue);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This projection is not used as the solution. It gives
|
* This projection is not used as the solution. It gives
|
||||||
@@ -264,15 +262,16 @@ TEST_CASE(
|
|||||||
|
|
||||||
zeroEnthalpyField = 0.0;
|
zeroEnthalpyField = 0.0;
|
||||||
|
|
||||||
const double exactEnthalpyNorm =
|
const double exactEnthalpyNorm = zeroEnthalpyField.ComputeL2Error(
|
||||||
zeroEnthalpyField.ComputeL2Error(exactEnthalpyCoefficient, nullptr, &stellarElementMarker);
|
exactEnthalpyCoefficient, nullptr, &stellarElementMarker);
|
||||||
|
|
||||||
const double projectionError =
|
const double projectionError = projectedEnthalpyField.ComputeL2Error(
|
||||||
projectedEnthalpyField.ComputeL2Error(exactEnthalpyCoefficient, nullptr, &stellarElementMarker);
|
exactEnthalpyCoefficient, nullptr, &stellarElementMarker);
|
||||||
|
|
||||||
REQUIRE(exactEnthalpyNorm > 0.0);
|
REQUIRE(exactEnthalpyNorm > 0.0);
|
||||||
|
|
||||||
const double relativeProjectionError = projectionError / exactEnthalpyNorm;
|
const double relativeProjectionError =
|
||||||
|
projectionError / exactEnthalpyNorm;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Begin deliberately far from equilibrium.
|
* Begin deliberately far from equilibrium.
|
||||||
@@ -281,14 +280,16 @@ TEST_CASE(
|
|||||||
|
|
||||||
enthalpy = 0.0;
|
enthalpy = 0.0;
|
||||||
|
|
||||||
auto dependencies = prepared_hydrostatic_analytic_solve_test_utils::make_dependencies();
|
auto dependencies =
|
||||||
|
prepared_hydrostatic_analytic_solve_test_utils::make_dependencies();
|
||||||
|
|
||||||
mean_field::operators::PreparedHydrostaticEquilibriumOperator preparedOperator(f, *f.domainMapperStateless);
|
mean_field::operators::PreparedHydrostaticEquilibriumOperator
|
||||||
|
preparedOperator(f, *f.domainMapperStateless);
|
||||||
|
|
||||||
const auto initialReport = preparedOperator.Prepare(
|
const auto initialReport = preparedOperator.Prepare(
|
||||||
prepared_hydrostatic_analytic_solve_test_utils::make_state(enthalpy, gravityPotential, displacement),
|
prepared_hydrostatic_analytic_solve_test_utils::make_state(
|
||||||
dependencies, rotation
|
enthalpy, gravityPotential, displacement),
|
||||||
);
|
dependencies, rotation);
|
||||||
|
|
||||||
REQUIRE(initialReport.preparedResidual);
|
REQUIRE(initialReport.preparedResidual);
|
||||||
REQUIRE(initialReport.preparedAlgebraicJacobianBlocks);
|
REQUIRE(initialReport.preparedAlgebraicJacobianBlocks);
|
||||||
@@ -297,7 +298,9 @@ TEST_CASE(
|
|||||||
|
|
||||||
preparedOperator.BuildResidual(initialResidual);
|
preparedOperator.BuildResidual(initialResidual);
|
||||||
|
|
||||||
const double initialResidualNorm = gravity_prepared_test_utils::global_norm(initialResidual, communicator);
|
const double initialResidualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(initialResidual,
|
||||||
|
communicator);
|
||||||
|
|
||||||
REQUIRE(initialResidualNorm > 1.0e-12);
|
REQUIRE(initialResidualNorm > 1.0e-12);
|
||||||
|
|
||||||
@@ -311,9 +314,8 @@ TEST_CASE(
|
|||||||
* rotation, and displacement makes this a well-defined
|
* rotation, and displacement makes this a well-defined
|
||||||
* enthalpy solve.
|
* enthalpy solve.
|
||||||
*/
|
*/
|
||||||
prepared_hydrostatic_analytic_solve_test_utils::EnthalpyJacobianOperator enthalpyJacobian(
|
prepared_hydrostatic_analytic_solve_test_utils::EnthalpyJacobianOperator
|
||||||
enthalpyMap.reduced_size(), preparedOperator
|
enthalpyJacobian(enthalpyMap.reduced_size(), preparedOperator);
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector rightHandSide(initialResidual);
|
mfem::Vector rightHandSide(initialResidual);
|
||||||
rightHandSide *= -1.0;
|
rightHandSide *= -1.0;
|
||||||
@@ -355,9 +357,9 @@ TEST_CASE(
|
|||||||
++dependencies.enthalpy.revision;
|
++dependencies.enthalpy.revision;
|
||||||
|
|
||||||
const auto solvedReport = preparedOperator.Prepare(
|
const auto solvedReport = preparedOperator.Prepare(
|
||||||
prepared_hydrostatic_analytic_solve_test_utils::make_state(enthalpy, gravityPotential, displacement),
|
prepared_hydrostatic_analytic_solve_test_utils::make_state(
|
||||||
dependencies, rotation
|
enthalpy, gravityPotential, displacement),
|
||||||
);
|
dependencies, rotation);
|
||||||
|
|
||||||
CHECK(solvedReport.contextReport.updatedEnthalpy);
|
CHECK(solvedReport.contextReport.updatedEnthalpy);
|
||||||
|
|
||||||
@@ -371,7 +373,9 @@ TEST_CASE(
|
|||||||
|
|
||||||
preparedOperator.BuildResidual(solvedResidual);
|
preparedOperator.BuildResidual(solvedResidual);
|
||||||
|
|
||||||
const double solvedResidualNorm = gravity_prepared_test_utils::global_norm(solvedResidual, communicator);
|
const double solvedResidualNorm =
|
||||||
|
gravity_prepared_test_utils::global_norm(solvedResidual,
|
||||||
|
communicator);
|
||||||
|
|
||||||
const double residualReduction = solvedResidualNorm / initialResidualNorm;
|
const double residualReduction = solvedResidualNorm / initialResidualNorm;
|
||||||
|
|
||||||
@@ -389,10 +393,11 @@ TEST_CASE(
|
|||||||
enthalpyMap.scatter(enthalpy, enthalpyTrue);
|
enthalpyMap.scatter(enthalpy, enthalpyTrue);
|
||||||
solvedEnthalpyField.SetFromTrueDofs(enthalpyTrue);
|
solvedEnthalpyField.SetFromTrueDofs(enthalpyTrue);
|
||||||
|
|
||||||
const double solvedAnalyticError =
|
const double solvedAnalyticError = solvedEnthalpyField.ComputeL2Error(
|
||||||
solvedEnthalpyField.ComputeL2Error(exactEnthalpyCoefficient, nullptr, &stellarElementMarker);
|
exactEnthalpyCoefficient, nullptr, &stellarElementMarker);
|
||||||
|
|
||||||
const double relativeSolvedAnalyticError = solvedAnalyticError / exactEnthalpyNorm;
|
const double relativeSolvedAnalyticError =
|
||||||
|
solvedAnalyticError / exactEnthalpyNorm;
|
||||||
|
|
||||||
INFO("Deformation determinant = " << deformationDeterminant);
|
INFO("Deformation determinant = " << deformationDeterminant);
|
||||||
|
|
||||||
@@ -404,7 +409,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
INFO("Relative analytic projection floor = " << relativeProjectionError);
|
INFO("Relative analytic projection floor = " << relativeProjectionError);
|
||||||
|
|
||||||
INFO("Relative solved analytic L2 error = " << relativeSolvedAnalyticError);
|
INFO("Relative solved analytic L2 error = "
|
||||||
|
<< relativeSolvedAnalyticError);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The discrete Bernoulli equation must be solved essentially
|
* The discrete Bernoulli equation must be solved essentially
|
||||||
@@ -419,7 +425,8 @@ TEST_CASE(
|
|||||||
* also contains potential-projection and mapped-space
|
* also contains potential-projection and mapped-space
|
||||||
* compatibility errors.
|
* compatibility errors.
|
||||||
*/
|
*/
|
||||||
CHECK(relativeSolvedAnalyticError < std::max(5.0 * relativeProjectionError, 1.25e-4));
|
CHECK(relativeSolvedAnalyticError <
|
||||||
|
std::max(5.0 * relativeProjectionError, 1.25e-4));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Record that the analytic error remains within one order of
|
* Record that the analytic error remains within one order of
|
||||||
|
|||||||
@@ -24,76 +24,59 @@ namespace prepared_pressure_force_test_utils {
|
|||||||
|
|
||||||
explicit Maps(const mean_field::fem::FEM &f)
|
explicit Maps(const mean_field::fem::FEM &f)
|
||||||
: density(
|
: density(
|
||||||
mean_field::field::make_field_dof_map<
|
mean_field::field::make_field_dof_map<mean_field::field::Density,
|
||||||
mean_field::field::Density,
|
DomainSchema>(*f.densityFes)),
|
||||||
DomainSchema>(*f.densityFes)
|
displacement(mean_field::field::make_field_dof_map<
|
||||||
),
|
mean_field::field::Displacement, DomainSchema>(
|
||||||
displacement(
|
*f.displacementFes)),
|
||||||
mean_field::field::make_field_dof_map<
|
|
||||||
mean_field::field::Displacement,
|
|
||||||
DomainSchema>(*f.displacementFes)
|
|
||||||
),
|
|
||||||
gravityFlux(
|
gravityFlux(
|
||||||
mean_field::field::make_field_dof_map<
|
mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
mean_field::field::Gravity,
|
DomainSchema>(
|
||||||
DomainSchema>(*f.gravityFluxFes)
|
*f.gravityFluxFes)),
|
||||||
),
|
|
||||||
gravityPotential(
|
gravityPotential(
|
||||||
mean_field::field::make_field_dof_map<
|
mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
mean_field::field::Gravity,
|
DomainSchema>(
|
||||||
DomainSchema>(*f.gravityPotentialFes)
|
*f.gravityPotentialFes)),
|
||||||
),
|
enthalpy(mean_field::field::make_field_dof_map<
|
||||||
enthalpy(
|
mean_field::field::Enthalpy, DomainSchema>(*f.enthalpyFes)) {}
|
||||||
mean_field::field::make_field_dof_map<
|
|
||||||
mean_field::field::Enthalpy,
|
|
||||||
DomainSchema>(*f.enthalpyFes)
|
|
||||||
) {
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
mfem::Vector make_positive_enthalpy_true(
|
mfem::Vector make_positive_enthalpy_true(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::Vector enthalpy(f.enthalpyFes->GetTrueVSize());
|
mfem::Vector enthalpy(f.enthalpyFes->GetTrueVSize());
|
||||||
|
|
||||||
for (int index = 0; index < enthalpy.Size(); ++index) {
|
for (int index = 0; index < enthalpy.Size(); ++index) {
|
||||||
const double position = static_cast<double>(index + 1);
|
const double position = static_cast<double>(index + 1);
|
||||||
|
|
||||||
enthalpy(index) =
|
enthalpy(index) = 0.93 + 0.09 * std::sin(0.23 * position + phase) +
|
||||||
0.93 + 0.09 * std::sin(0.23 * position + phase) + 0.04 * std::cos(0.17 * position - 0.5 * phase);
|
0.04 * std::cos(0.17 * position - 0.5 * phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
return enthalpy;
|
return enthalpy;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
mfem::Vector make_enthalpy_direction_true(
|
mfem::Vector make_enthalpy_direction_true(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::Vector direction(f.enthalpyFes->GetTrueVSize());
|
mfem::Vector direction(f.enthalpyFes->GetTrueVSize());
|
||||||
|
|
||||||
for (int index = 0; index < direction.Size(); ++index) {
|
for (int index = 0; index < direction.Size(); ++index) {
|
||||||
const double position = static_cast<double>(index + 1);
|
const double position = static_cast<double>(index + 1);
|
||||||
|
|
||||||
direction(index) =
|
direction(index) = 0.27 * std::sin(0.19 * position + phase) +
|
||||||
0.27 * std::sin(0.19 * position + phase) + 0.14 * std::cos(0.13 * position - 0.5 * phase);
|
0.14 * std::cos(0.13 * position - 0.5 * phase);
|
||||||
}
|
}
|
||||||
|
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
mfem::Vector make_displacement_direction_true(
|
mfem::Vector make_displacement_direction_true(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
MFEM_VERIFY(f.mesh->Dimension() == 3,
|
||||||
) {
|
"The prepared pressure-force test requires a "
|
||||||
MFEM_VERIFY(
|
"three-dimensional mesh.");
|
||||||
f.mesh->Dimension() == 3, "The prepared pressure-force test requires a "
|
|
||||||
"three-dimensional mesh."
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::ParGridFunction directionField(f.displacementFes.get());
|
mfem::ParGridFunction directionField(f.displacementFes.get());
|
||||||
|
|
||||||
@@ -107,13 +90,15 @@ namespace prepared_pressure_force_test_utils {
|
|||||||
|
|
||||||
value.SetSize(3);
|
value.SetSize(3);
|
||||||
|
|
||||||
value(0) = 0.019 * x + 0.011 * y * z - 0.006 * z * z + 0.004 * phase * y;
|
value(0) =
|
||||||
|
0.019 * x + 0.011 * y * z - 0.006 * z * z + 0.004 * phase * y;
|
||||||
|
|
||||||
value(1) = -0.016 * y + 0.008 * x * z + 0.005 * x * x - 0.003 * phase * z;
|
value(1) =
|
||||||
|
-0.016 * y + 0.008 * x * z + 0.005 * x * x - 0.003 * phase * z;
|
||||||
|
|
||||||
value(2) = 0.013 * z - 0.010 * x * y + 0.006 * y * y + 0.004 * phase * x;
|
value(2) =
|
||||||
}
|
0.013 * z - 0.010 * x * y + 0.006 * y * y + 0.004 * phase * x;
|
||||||
);
|
});
|
||||||
|
|
||||||
directionField.ProjectCoefficient(directionCoefficient);
|
directionField.ProjectCoefficient(directionCoefficient);
|
||||||
|
|
||||||
@@ -125,93 +110,95 @@ namespace prepared_pressure_force_test_utils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
double relative_difference(
|
double relative_difference(const mfem::Vector &left, const mfem::Vector &right,
|
||||||
const mfem::Vector &left,
|
const MPI_Comm communicator) {
|
||||||
const mfem::Vector &right,
|
MFEM_VERIFY(left.Size() == right.Size(),
|
||||||
const MPI_Comm communicator
|
"Cannot compare prepared pressure-force vectors with "
|
||||||
) {
|
"different sizes.");
|
||||||
MFEM_VERIFY(
|
|
||||||
left.Size() == right.Size(), "Cannot compare prepared pressure-force vectors with "
|
|
||||||
"different sizes."
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector difference(left);
|
mfem::Vector difference(left);
|
||||||
|
|
||||||
difference -= right;
|
difference -= right;
|
||||||
|
|
||||||
const double scale = std::max(
|
const double scale =
|
||||||
{gravity_prepared_test_utils::global_norm(left, communicator),
|
std::max({gravity_prepared_test_utils::global_norm(left, communicator),
|
||||||
gravity_prepared_test_utils::global_norm(right, communicator),
|
gravity_prepared_test_utils::global_norm(right, communicator),
|
||||||
100.0 * std::numeric_limits<double>::epsilon()}
|
100.0 * std::numeric_limits<double>::epsilon()});
|
||||||
);
|
|
||||||
|
|
||||||
return gravity_prepared_test_utils::global_norm(difference, communicator) / scale;
|
return gravity_prepared_test_utils::global_norm(difference, communicator) /
|
||||||
|
scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
mean_field::operators::context::pressure_force::PressureForceDependencies make_dependencies() {
|
mean_field::operators::context::pressure_force::PressureForceDependencies
|
||||||
return {
|
make_dependencies() {
|
||||||
.discretization = {.identity = 1201, .revision = 3},
|
return {.discretization = {.identity = 1201, .revision = 3},
|
||||||
.enthalpy = {.identity = 1213, .revision = 5},
|
.enthalpy = {.identity = 1213, .revision = 5},
|
||||||
.displacement = {.identity = 1217, .revision = 7}
|
.displacement = {.identity = 1217, .revision = 7}};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto densityValue =
|
constexpr auto densityValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::density_field.mass_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::density_field.mass_term);
|
||||||
|
|
||||||
constexpr auto displacementValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto displacementValue =
|
||||||
mean_field::utils::blocks::displacement_field.geometry_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::displacement_field.geometry_term);
|
||||||
|
|
||||||
constexpr auto gravityGradientValue =
|
constexpr auto gravityGradientValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::gravity_field.gradient_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::gravity_field.gradient_term);
|
||||||
|
|
||||||
constexpr auto gravityPotentialValue =
|
constexpr auto gravityPotentialValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::gravity_field.poisson_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
constexpr auto enthalpyValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto enthalpyValue =
|
||||||
mean_field::utils::blocks::enthalpy_field.specific_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::enthalpy_field.specific_term);
|
||||||
|
|
||||||
constexpr auto barotropicConstantValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto barotropicConstantValue =
|
||||||
mean_field::utils::blocks::barotropic_constant_field.mass_normalization_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::barotropic_constant_field
|
||||||
|
.mass_normalization_term);
|
||||||
|
|
||||||
constexpr auto gravityGradientResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto gravityGradientResidual =
|
||||||
mean_field::utils::blocks::gravity_field.gradient_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.gradient_term);
|
||||||
|
|
||||||
constexpr auto gravityPotentialResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto gravityPotentialResidual =
|
||||||
mean_field::utils::blocks::gravity_field.poisson_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
constexpr auto densityResidual =
|
constexpr auto densityResidual =
|
||||||
mean_field::utils::blocks::get_residual_block<CoupledForm>(mean_field::utils::blocks::density_field.mass_term);
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::density_field.mass_term);
|
||||||
|
|
||||||
constexpr auto displacementResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto displacementResidual =
|
||||||
mean_field::utils::blocks::displacement_field.geometry_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::displacement_field.geometry_term);
|
||||||
|
|
||||||
constexpr auto enthalpyResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto enthalpyResidual =
|
||||||
mean_field::utils::blocks::enthalpy_field.specific_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::enthalpy_field.specific_term);
|
||||||
|
|
||||||
constexpr auto massResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto massResidual =
|
||||||
mean_field::utils::blocks::barotropic_constant_field.mass_normalization_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::barotropic_constant_field
|
||||||
|
.mass_normalization_term);
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
mean_field::operators::BarotropicEquilibriumLayout make_coupled_layout(const Maps &maps) {
|
mean_field::operators::BarotropicEquilibriumLayout
|
||||||
|
make_coupled_layout(const Maps &maps) {
|
||||||
const std::array<int, CoupledForm::value_block_count> valueSizes{
|
const std::array<int, CoupledForm::value_block_count> valueSizes{
|
||||||
maps.density.reduced_size(), maps.displacement.reduced_size(), maps.gravityFlux.reduced_size(),
|
maps.density.reduced_size(), maps.displacement.reduced_size(),
|
||||||
maps.gravityPotential.reduced_size(), maps.enthalpy.reduced_size(), 1
|
maps.gravityFlux.reduced_size(), maps.gravityPotential.reduced_size(),
|
||||||
};
|
maps.enthalpy.reduced_size(), 1};
|
||||||
|
|
||||||
const std::array<int, CoupledForm::residual_block_count> residualSizes{
|
const std::array<int, CoupledForm::residual_block_count> residualSizes{
|
||||||
maps.gravityFlux.reduced_size(), maps.gravityPotential.reduced_size(), maps.density.reduced_size(),
|
maps.gravityFlux.reduced_size(), maps.gravityPotential.reduced_size(),
|
||||||
maps.displacement.reduced_size(), maps.enthalpy.reduced_size(), 1
|
maps.density.reduced_size(), maps.displacement.reduced_size(),
|
||||||
};
|
maps.enthalpy.reduced_size(), 1};
|
||||||
|
|
||||||
return {valueSizes, residualSizes};
|
return {valueSizes, residualSizes};
|
||||||
}
|
}
|
||||||
@@ -221,8 +208,7 @@ namespace prepared_pressure_force_test_utils {
|
|||||||
mfem::Vector copy_residual_block(
|
mfem::Vector copy_residual_block(
|
||||||
const mfem::Vector &action,
|
const mfem::Vector &action,
|
||||||
const mean_field::operators::BarotropicEquilibriumLayout &layout,
|
const mean_field::operators::BarotropicEquilibriumLayout &layout,
|
||||||
const mean_field::utils::blocks::residual_block<index> block
|
const mean_field::utils::blocks::residual_block<index> block) {
|
||||||
) {
|
|
||||||
mfem::Vector result(layout.size(block));
|
mfem::Vector result(layout.size(block));
|
||||||
|
|
||||||
const int offset = layout.offset(block);
|
const int offset = layout.offset(block);
|
||||||
@@ -236,9 +222,9 @@ namespace prepared_pressure_force_test_utils {
|
|||||||
} // namespace prepared_pressure_force_test_utils
|
} // namespace prepared_pressure_force_test_utils
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Prepared Pressure Force Uses FieldDof Supported Dimensions And Owns Its Context",
|
"Prepared Pressure Force Uses FieldDof Supported Dimensions And Owns Its "
|
||||||
tags::barotrope &tags::pressure &tags::prepared &tags::field &tags::unit
|
"Context",
|
||||||
) {
|
tags::barotrope &tags::pressure &tags::prepared &tags::field &tags::unit) {
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -249,7 +235,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
const mean_field::eos::Polytrope equationOfState(3.0, 0.25);
|
const mean_field::eos::Polytrope equationOfState(3.0, 0.25);
|
||||||
|
|
||||||
mean_field::operators::PreparedPressureForceOperator preparedOperator(f, *f.domainMapperStateless, equationOfState);
|
mean_field::operators::PreparedPressureForceOperator preparedOperator(
|
||||||
|
f, *f.domainMapperStateless, equationOfState);
|
||||||
|
|
||||||
REQUIRE(maps.enthalpy.reduced_size() < maps.enthalpy.full_size());
|
REQUIRE(maps.enthalpy.reduced_size() < maps.enthalpy.full_size());
|
||||||
|
|
||||||
@@ -257,17 +244,17 @@ TEST_CASE(
|
|||||||
|
|
||||||
CHECK(preparedOperator.GetEnthalpySize() == maps.enthalpy.reduced_size());
|
CHECK(preparedOperator.GetEnthalpySize() == maps.enthalpy.reduced_size());
|
||||||
|
|
||||||
CHECK(preparedOperator.GetDisplacementSize() == maps.displacement.reduced_size());
|
CHECK(preparedOperator.GetDisplacementSize() ==
|
||||||
|
maps.displacement.reduced_size());
|
||||||
|
|
||||||
CHECK(
|
CHECK(&preparedOperator.GetContext().GetPreparationStatistics() ==
|
||||||
&preparedOperator.GetContext().GetPreparationStatistics() == &preparedOperator.GetContextPreparationStatistics()
|
&preparedOperator.GetContextPreparationStatistics());
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Pressure Force Jacobian Matches Full Stateless Columns "
|
||||||
"Prepared Pressure Force Jacobian Matches Full Stateless Columns Through FieldDof Restriction",
|
"Through FieldDof Restriction",
|
||||||
tags::barotrope &tags::pressure &tags::prepared &tags::field &tags::integration &tags::accuracy
|
tags::barotrope &tags::pressure &tags::prepared &tags::field
|
||||||
) {
|
&tags::integration &tags::accuracy) {
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -278,86 +265,90 @@ TEST_CASE(
|
|||||||
|
|
||||||
const mean_field::eos::Polytrope equationOfState(3.0, 0.25);
|
const mean_field::eos::Polytrope equationOfState(3.0, 0.25);
|
||||||
|
|
||||||
const mfem::Vector enthalpy =
|
const mfem::Vector enthalpy = maps.enthalpy.gather(
|
||||||
maps.enthalpy.gather(prepared_pressure_force_test_utils::make_positive_enthalpy_true(f, 0.47));
|
prepared_pressure_force_test_utils::make_positive_enthalpy_true(f, 0.47));
|
||||||
|
|
||||||
const mfem::Vector displacement = maps.displacement.gather(gravity_prepared_test_utils::make_displacement(f, 0.69));
|
const mfem::Vector displacement = maps.displacement.gather(
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.69));
|
||||||
|
|
||||||
const mfem::Vector enthalpyDirection =
|
const mfem::Vector enthalpyDirection = maps.enthalpy.gather(
|
||||||
maps.enthalpy.gather(prepared_pressure_force_test_utils::make_enthalpy_direction_true(f, 0.73));
|
prepared_pressure_force_test_utils::make_enthalpy_direction_true(f,
|
||||||
|
0.73));
|
||||||
|
|
||||||
const mfem::Vector displacementDirection =
|
const mfem::Vector displacementDirection = maps.displacement.gather(
|
||||||
maps.displacement.gather(prepared_pressure_force_test_utils::make_displacement_direction_true(f, 0.83));
|
prepared_pressure_force_test_utils::make_displacement_direction_true(
|
||||||
|
f, 0.83));
|
||||||
|
|
||||||
mean_field::operators::PreparedPressureForceOperator preparedOperator(f, *f.domainMapperStateless, equationOfState);
|
mean_field::operators::PreparedPressureForceOperator preparedOperator(
|
||||||
|
f, *f.domainMapperStateless, equationOfState);
|
||||||
|
|
||||||
preparedOperator.Prepare(
|
preparedOperator.Prepare(
|
||||||
{.enthalpy = enthalpy, .displacement = displacement}, prepared_pressure_force_test_utils::make_dependencies()
|
{.enthalpy = enthalpy, .displacement = displacement},
|
||||||
);
|
prepared_pressure_force_test_utils::make_dependencies());
|
||||||
|
|
||||||
const mfem::Vector enthalpyTrue = maps.enthalpy.scatter(enthalpy);
|
const mfem::Vector enthalpyTrue = maps.enthalpy.scatter(enthalpy);
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = maps.displacement.scatter(displacement);
|
const mfem::Vector displacementTrue = maps.displacement.scatter(displacement);
|
||||||
|
|
||||||
const mfem::Vector enthalpyDirectionTrue = maps.enthalpy.scatter(enthalpyDirection);
|
const mfem::Vector enthalpyDirectionTrue =
|
||||||
|
maps.enthalpy.scatter(enthalpyDirection);
|
||||||
|
|
||||||
const mfem::Vector displacementDirectionTrue = maps.displacement.scatter(displacementDirection);
|
const mfem::Vector displacementDirectionTrue =
|
||||||
|
maps.displacement.scatter(displacementDirection);
|
||||||
|
|
||||||
mfem::Vector preparedEnthalpyAction;
|
mfem::Vector preparedEnthalpyAction;
|
||||||
mfem::Vector kernelEnthalpyActionTrue;
|
mfem::Vector kernelEnthalpyActionTrue;
|
||||||
|
|
||||||
preparedOperator.ApplyEnthalpyJacobianAction(enthalpyDirection, preparedEnthalpyAction);
|
preparedOperator.ApplyEnthalpyJacobianAction(enthalpyDirection,
|
||||||
|
preparedEnthalpyAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_enthalpy_action(
|
mean_field::operators::kernels::apply_pressure_force_enthalpy_action(
|
||||||
f, *f.domainMapperStateless, equationOfState, enthalpyTrue, enthalpyDirectionTrue, displacementTrue,
|
f, *f.domainMapperStateless, equationOfState, enthalpyTrue,
|
||||||
kernelEnthalpyActionTrue
|
enthalpyDirectionTrue, displacementTrue, kernelEnthalpyActionTrue);
|
||||||
);
|
|
||||||
|
|
||||||
const mfem::Vector kernelEnthalpyAction = maps.displacement.gather(kernelEnthalpyActionTrue);
|
const mfem::Vector kernelEnthalpyAction =
|
||||||
|
maps.displacement.gather(kernelEnthalpyActionTrue);
|
||||||
|
|
||||||
CHECK(
|
CHECK(prepared_pressure_force_test_utils::relative_difference(
|
||||||
prepared_pressure_force_test_utils::relative_difference(
|
preparedEnthalpyAction, kernelEnthalpyAction, f.mesh->GetComm()) <
|
||||||
preparedEnthalpyAction, kernelEnthalpyAction, f.mesh->GetComm()
|
2.0e-12);
|
||||||
) < 2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector preparedDisplacementAction;
|
mfem::Vector preparedDisplacementAction;
|
||||||
mfem::Vector kernelDisplacementActionTrue;
|
mfem::Vector kernelDisplacementActionTrue;
|
||||||
|
|
||||||
preparedOperator.ApplyDisplacementJacobianAction(displacementDirection, preparedDisplacementAction);
|
preparedOperator.ApplyDisplacementJacobianAction(displacementDirection,
|
||||||
|
preparedDisplacementAction);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_displacement_action(
|
mean_field::operators::kernels::apply_pressure_force_displacement_action(
|
||||||
f, *f.domainMapperStateless, equationOfState, enthalpyTrue, displacementDirectionTrue, displacementTrue,
|
f, *f.domainMapperStateless, equationOfState, enthalpyTrue,
|
||||||
kernelDisplacementActionTrue
|
displacementDirectionTrue, displacementTrue,
|
||||||
);
|
kernelDisplacementActionTrue);
|
||||||
|
|
||||||
const mfem::Vector kernelDisplacementAction = maps.displacement.gather(kernelDisplacementActionTrue);
|
const mfem::Vector kernelDisplacementAction =
|
||||||
|
maps.displacement.gather(kernelDisplacementActionTrue);
|
||||||
|
|
||||||
CHECK(
|
CHECK(prepared_pressure_force_test_utils::relative_difference(
|
||||||
prepared_pressure_force_test_utils::relative_difference(
|
preparedDisplacementAction, kernelDisplacementAction,
|
||||||
preparedDisplacementAction, kernelDisplacementAction, f.mesh->GetComm()
|
f.mesh->GetComm()) < 2.0e-12);
|
||||||
) < 2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector fusedAction;
|
mfem::Vector fusedAction;
|
||||||
|
|
||||||
preparedOperator.ApplyCompleteJacobianAction(enthalpyDirection, displacementDirection, fusedAction);
|
preparedOperator.ApplyCompleteJacobianAction(
|
||||||
|
enthalpyDirection, displacementDirection, fusedAction);
|
||||||
|
|
||||||
mfem::Vector expectedFusedAction(kernelEnthalpyAction);
|
mfem::Vector expectedFusedAction(kernelEnthalpyAction);
|
||||||
|
|
||||||
expectedFusedAction += kernelDisplacementAction;
|
expectedFusedAction += kernelDisplacementAction;
|
||||||
|
|
||||||
CHECK(
|
CHECK(prepared_pressure_force_test_utils::relative_difference(
|
||||||
prepared_pressure_force_test_utils::relative_difference(fusedAction, expectedFusedAction, f.mesh->GetComm()) <
|
fusedAction, expectedFusedAction, f.mesh->GetComm()) < 2.0e-12);
|
||||||
2.0e-12
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Prepared Pressure Force MFEM Adapter Routes Reduced Coupled FieldDof Blocks",
|
"Prepared Pressure Force MFEM Adapter Routes Reduced Coupled FieldDof "
|
||||||
tags::barotrope &tags::pressure &tags::prepared &tags::field &tags::integration &tags::jacobian
|
"Blocks",
|
||||||
&tags::mfem_operators &tags::unit
|
tags::barotrope &tags::pressure &tags::prepared &tags::field
|
||||||
) {
|
&tags::integration &tags::jacobian &tags::mfem_operators &tags::unit) {
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
@@ -368,31 +359,38 @@ TEST_CASE(
|
|||||||
|
|
||||||
const mean_field::eos::Polytrope equationOfState(3.0, 0.25);
|
const mean_field::eos::Polytrope equationOfState(3.0, 0.25);
|
||||||
|
|
||||||
const mfem::Vector enthalpy =
|
const mfem::Vector enthalpy = maps.enthalpy.gather(
|
||||||
maps.enthalpy.gather(prepared_pressure_force_test_utils::make_positive_enthalpy_true(f, 0.53));
|
prepared_pressure_force_test_utils::make_positive_enthalpy_true(f, 0.53));
|
||||||
|
|
||||||
const mfem::Vector displacement = maps.displacement.gather(gravity_prepared_test_utils::make_displacement(f, 0.71));
|
const mfem::Vector displacement = maps.displacement.gather(
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.71));
|
||||||
|
|
||||||
const mfem::Vector enthalpyDirection =
|
const mfem::Vector enthalpyDirection = maps.enthalpy.gather(
|
||||||
maps.enthalpy.gather(prepared_pressure_force_test_utils::make_enthalpy_direction_true(f, 0.89));
|
prepared_pressure_force_test_utils::make_enthalpy_direction_true(f,
|
||||||
|
0.89));
|
||||||
|
|
||||||
const mfem::Vector displacementDirection =
|
const mfem::Vector displacementDirection = maps.displacement.gather(
|
||||||
maps.displacement.gather(prepared_pressure_force_test_utils::make_displacement_direction_true(f, 0.97));
|
prepared_pressure_force_test_utils::make_displacement_direction_true(
|
||||||
|
f, 0.97));
|
||||||
|
|
||||||
mean_field::operators::PreparedPressureForceOperator preparedOperator(f, *f.domainMapperStateless, equationOfState);
|
mean_field::operators::PreparedPressureForceOperator preparedOperator(
|
||||||
|
f, *f.domainMapperStateless, equationOfState);
|
||||||
|
|
||||||
preparedOperator.Prepare(
|
preparedOperator.Prepare(
|
||||||
{.enthalpy = enthalpy, .displacement = displacement}, prepared_pressure_force_test_utils::make_dependencies()
|
{.enthalpy = enthalpy, .displacement = displacement},
|
||||||
);
|
prepared_pressure_force_test_utils::make_dependencies());
|
||||||
|
|
||||||
const mean_field::operators::BarotropicEquilibriumLayout layout =
|
const mean_field::operators::BarotropicEquilibriumLayout layout =
|
||||||
prepared_pressure_force_test_utils::make_coupled_layout(maps);
|
prepared_pressure_force_test_utils::make_coupled_layout(maps);
|
||||||
|
|
||||||
mean_field::operators::PreparedPressureForceJacobianOperator adapter(layout, preparedOperator);
|
mean_field::operators::PreparedPressureForceJacobianOperator adapter(
|
||||||
|
layout, preparedOperator);
|
||||||
|
|
||||||
CHECK(layout.size(prepared_pressure_force_test_utils::enthalpyValue) == maps.enthalpy.reduced_size());
|
CHECK(layout.size(prepared_pressure_force_test_utils::enthalpyValue) ==
|
||||||
|
maps.enthalpy.reduced_size());
|
||||||
|
|
||||||
CHECK(layout.size(prepared_pressure_force_test_utils::densityValue) == maps.density.reduced_size());
|
CHECK(layout.size(prepared_pressure_force_test_utils::densityValue) ==
|
||||||
|
maps.density.reduced_size());
|
||||||
|
|
||||||
mfem::BlockVector direction(layout.value_offsets());
|
mfem::BlockVector direction(layout.value_offsets());
|
||||||
|
|
||||||
@@ -403,74 +401,66 @@ TEST_CASE(
|
|||||||
*/
|
*/
|
||||||
direction.GetBlock(prepared_pressure_force_test_utils::densityValue) = 0.37;
|
direction.GetBlock(prepared_pressure_force_test_utils::densityValue) = 0.37;
|
||||||
|
|
||||||
direction.GetBlock(prepared_pressure_force_test_utils::gravityGradientValue) = -0.41;
|
direction.GetBlock(prepared_pressure_force_test_utils::gravityGradientValue) =
|
||||||
|
-0.41;
|
||||||
|
|
||||||
direction.GetBlock(prepared_pressure_force_test_utils::gravityPotentialValue) = 0.59;
|
direction.GetBlock(
|
||||||
|
prepared_pressure_force_test_utils::gravityPotentialValue) = 0.59;
|
||||||
|
|
||||||
direction.GetBlock(prepared_pressure_force_test_utils::barotropicConstantValue) = -0.73;
|
direction.GetBlock(
|
||||||
|
prepared_pressure_force_test_utils::barotropicConstantValue) = -0.73;
|
||||||
|
|
||||||
direction.GetBlock(prepared_pressure_force_test_utils::displacementValue) = displacementDirection;
|
direction.GetBlock(prepared_pressure_force_test_utils::displacementValue) =
|
||||||
|
displacementDirection;
|
||||||
|
|
||||||
direction.GetBlock(prepared_pressure_force_test_utils::enthalpyValue) = enthalpyDirection;
|
direction.GetBlock(prepared_pressure_force_test_utils::enthalpyValue) =
|
||||||
|
enthalpyDirection;
|
||||||
|
|
||||||
mfem::Vector expectedDisplacementAction;
|
mfem::Vector expectedDisplacementAction;
|
||||||
|
|
||||||
preparedOperator.ApplyCompleteJacobianAction(enthalpyDirection, displacementDirection, expectedDisplacementAction);
|
preparedOperator.ApplyCompleteJacobianAction(
|
||||||
|
enthalpyDirection, displacementDirection, expectedDisplacementAction);
|
||||||
|
|
||||||
mfem::Vector action;
|
mfem::Vector action;
|
||||||
|
|
||||||
adapter.Mult(direction, action);
|
adapter.Mult(direction, action);
|
||||||
|
|
||||||
const mfem::Vector displacementResidualAction = prepared_pressure_force_test_utils::copy_residual_block(
|
const mfem::Vector displacementResidualAction =
|
||||||
action, layout, prepared_pressure_force_test_utils::displacementResidual
|
prepared_pressure_force_test_utils::copy_residual_block(
|
||||||
);
|
action, layout,
|
||||||
|
prepared_pressure_force_test_utils::displacementResidual);
|
||||||
|
|
||||||
CHECK(
|
CHECK(prepared_pressure_force_test_utils::relative_difference(
|
||||||
prepared_pressure_force_test_utils::relative_difference(
|
displacementResidualAction, expectedDisplacementAction,
|
||||||
displacementResidualAction, expectedDisplacementAction, f.mesh->GetComm()
|
f.mesh->GetComm()) < 2.0e-14);
|
||||||
) < 2.0e-14
|
|
||||||
);
|
CHECK(prepared_pressure_force_test_utils::copy_residual_block(
|
||||||
|
action, layout,
|
||||||
|
prepared_pressure_force_test_utils::gravityGradientResidual)
|
||||||
|
.Norml2() == 0.0);
|
||||||
|
|
||||||
|
CHECK(prepared_pressure_force_test_utils::copy_residual_block(
|
||||||
|
action, layout,
|
||||||
|
prepared_pressure_force_test_utils::gravityPotentialResidual)
|
||||||
|
.Norml2() == 0.0);
|
||||||
|
|
||||||
|
CHECK(prepared_pressure_force_test_utils::copy_residual_block(
|
||||||
|
action, layout, prepared_pressure_force_test_utils::densityResidual)
|
||||||
|
.Norml2() == 0.0);
|
||||||
|
|
||||||
CHECK(
|
CHECK(
|
||||||
prepared_pressure_force_test_utils::copy_residual_block(
|
prepared_pressure_force_test_utils::copy_residual_block(
|
||||||
action, layout, prepared_pressure_force_test_utils::gravityGradientResidual
|
action, layout, prepared_pressure_force_test_utils::enthalpyResidual)
|
||||||
)
|
.Norml2() == 0.0);
|
||||||
.Norml2() == 0.0
|
|
||||||
);
|
|
||||||
|
|
||||||
CHECK(
|
CHECK(prepared_pressure_force_test_utils::copy_residual_block(
|
||||||
prepared_pressure_force_test_utils::copy_residual_block(
|
action, layout, prepared_pressure_force_test_utils::massResidual)
|
||||||
action, layout, prepared_pressure_force_test_utils::gravityPotentialResidual
|
.Norml2() == 0.0);
|
||||||
)
|
|
||||||
.Norml2() == 0.0
|
|
||||||
);
|
|
||||||
|
|
||||||
CHECK(
|
|
||||||
prepared_pressure_force_test_utils::copy_residual_block(
|
|
||||||
action, layout, prepared_pressure_force_test_utils::densityResidual
|
|
||||||
)
|
|
||||||
.Norml2() == 0.0
|
|
||||||
);
|
|
||||||
|
|
||||||
CHECK(
|
|
||||||
prepared_pressure_force_test_utils::copy_residual_block(
|
|
||||||
action, layout, prepared_pressure_force_test_utils::enthalpyResidual
|
|
||||||
)
|
|
||||||
.Norml2() == 0.0
|
|
||||||
);
|
|
||||||
|
|
||||||
CHECK(
|
|
||||||
prepared_pressure_force_test_utils::copy_residual_block(
|
|
||||||
action, layout, prepared_pressure_force_test_utils::massResidual
|
|
||||||
)
|
|
||||||
.Norml2() == 0.0
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force Residual Converges To A Manufactured Analytic Force",
|
||||||
"Pressure Force Residual Converges To A Manufactured Analytic Force",
|
tags::barotrope &tags::pressure &tags::kernels &tags::integration
|
||||||
tags::barotrope &tags::pressure &tags::kernels &tags::integration &tags::convergence &tags::h_refinement
|
&tags::convergence &tags::h_refinement &tags::analytic_comparison
|
||||||
&tags::analytic_comparison &tags::accuracy
|
&tags::accuracy) {
|
||||||
) {
|
|
||||||
constexpr int dimension = 3;
|
constexpr int dimension = 3;
|
||||||
|
|
||||||
constexpr std::array<int, 2> refinementLevels{0, 1};
|
constexpr std::array<int, 2> refinementLevels{0, 1};
|
||||||
@@ -484,10 +474,12 @@ TEST_CASE(
|
|||||||
|
|
||||||
std::array<double, refinementLevels.size()> relativeErrors{};
|
std::array<double, refinementLevels.size()> relativeErrors{};
|
||||||
|
|
||||||
for (std::size_t levelIndex = 0; levelIndex < refinementLevels.size(); ++levelIndex) {
|
for (std::size_t levelIndex = 0; levelIndex < refinementLevels.size();
|
||||||
|
++levelIndex) {
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, refinementLevels[levelIndex]);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(
|
||||||
|
args.mesh_file, args, refinementLevels[levelIndex]);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
REQUIRE(f.mesh->Dimension() == dimension);
|
REQUIRE(f.mesh->Dimension() == dimension);
|
||||||
@@ -495,12 +487,15 @@ TEST_CASE(
|
|||||||
|
|
||||||
const MPI_Comm communicator = f.mesh->GetComm();
|
const MPI_Comm communicator = f.mesh->GetComm();
|
||||||
|
|
||||||
constexpr double supportRadius = supportRadiusFraction * mean_field::utils::RADIUS;
|
constexpr double supportRadius =
|
||||||
|
supportRadiusFraction * mean_field::utils::RADIUS;
|
||||||
|
|
||||||
constexpr double supportRadiusSquared = supportRadius * supportRadius;
|
constexpr double supportRadiusSquared = supportRadius * supportRadius;
|
||||||
|
|
||||||
auto analyticEnthalpyFunction = [supportRadiusSquared](const mfem::Vector &position) {
|
auto analyticEnthalpyFunction = [supportRadiusSquared](
|
||||||
const double normalizedRadiusSquared = (position * position) / supportRadiusSquared;
|
const mfem::Vector &position) {
|
||||||
|
const double normalizedRadiusSquared =
|
||||||
|
(position * position) / supportRadiusSquared;
|
||||||
|
|
||||||
if (normalizedRadiusSquared >= 1.0) {
|
if (normalizedRadiusSquared >= 1.0) {
|
||||||
return 0.0;
|
return 0.0;
|
||||||
@@ -508,14 +503,18 @@ TEST_CASE(
|
|||||||
|
|
||||||
const double distanceToSupportBoundary = 1.0 - normalizedRadiusSquared;
|
const double distanceToSupportBoundary = 1.0 - normalizedRadiusSquared;
|
||||||
|
|
||||||
return amplitude * std::exp(-bumpSharpness * normalizedRadiusSquared / distanceToSupportBoundary);
|
return amplitude * std::exp(-bumpSharpness * normalizedRadiusSquared /
|
||||||
|
distanceToSupportBoundary);
|
||||||
};
|
};
|
||||||
|
|
||||||
auto analyticPressureForceFunction = [supportRadiusSquared](const mfem::Vector &position, mfem::Vector &force) {
|
auto analyticPressureForceFunction = [supportRadiusSquared](
|
||||||
|
const mfem::Vector &position,
|
||||||
|
mfem::Vector &force) {
|
||||||
force.SetSize(dimension);
|
force.SetSize(dimension);
|
||||||
force = 0.0;
|
force = 0.0;
|
||||||
|
|
||||||
const double normalizedRadiusSquared = (position * position) / supportRadiusSquared;
|
const double normalizedRadiusSquared =
|
||||||
|
(position * position) / supportRadiusSquared;
|
||||||
|
|
||||||
if (normalizedRadiusSquared >= 1.0) {
|
if (normalizedRadiusSquared >= 1.0) {
|
||||||
return;
|
return;
|
||||||
@@ -524,20 +523,24 @@ TEST_CASE(
|
|||||||
const double distanceToSupportBoundary = 1.0 - normalizedRadiusSquared;
|
const double distanceToSupportBoundary = 1.0 - normalizedRadiusSquared;
|
||||||
|
|
||||||
const double enthalpy =
|
const double enthalpy =
|
||||||
amplitude * std::exp(-bumpSharpness * normalizedRadiusSquared / distanceToSupportBoundary);
|
amplitude * std::exp(-bumpSharpness * normalizedRadiusSquared /
|
||||||
|
distanceToSupportBoundary);
|
||||||
|
|
||||||
const double pressureGradientScale =
|
const double pressureGradientScale =
|
||||||
-2.0 * bumpSharpness * std::pow(enthalpy, 4.0) /
|
-2.0 * bumpSharpness * std::pow(enthalpy, 4.0) /
|
||||||
(supportRadiusSquared * distanceToSupportBoundary * distanceToSupportBoundary);
|
(supportRadiusSquared * distanceToSupportBoundary *
|
||||||
|
distanceToSupportBoundary);
|
||||||
|
|
||||||
for (int component = 0; component < dimension; ++component) {
|
for (int component = 0; component < dimension; ++component) {
|
||||||
force(component) = pressureGradientScale * position(component);
|
force(component) = pressureGradientScale * position(component);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mfem::FunctionCoefficient analyticEnthalpyCoefficient(analyticEnthalpyFunction);
|
mfem::FunctionCoefficient analyticEnthalpyCoefficient(
|
||||||
|
analyticEnthalpyFunction);
|
||||||
|
|
||||||
mfem::VectorFunctionCoefficient analyticPressureForceCoefficient(dimension, analyticPressureForceFunction);
|
mfem::VectorFunctionCoefficient analyticPressureForceCoefficient(
|
||||||
|
dimension, analyticPressureForceFunction);
|
||||||
|
|
||||||
mfem::ParGridFunction discreteEnthalpyField(f.enthalpyFes.get());
|
mfem::ParGridFunction discreteEnthalpyField(f.enthalpyFes.get());
|
||||||
|
|
||||||
@@ -555,8 +558,8 @@ TEST_CASE(
|
|||||||
mfem::Vector discreteResidual;
|
mfem::Vector discreteResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_pressure_force_residual(
|
mean_field::operators::kernels::apply_pressure_force_residual(
|
||||||
f, *f.domainMapperStateless, barotrope, discreteEnthalpyTrue, zeroDisplacement, discreteResidual
|
f, *f.domainMapperStateless, barotrope, discreteEnthalpyTrue,
|
||||||
);
|
zeroDisplacement, discreteResidual);
|
||||||
|
|
||||||
REQUIRE(discreteResidual.Size() == f.displacementFes->GetTrueVSize());
|
REQUIRE(discreteResidual.Size() == f.displacementFes->GetTrueVSize());
|
||||||
|
|
||||||
@@ -564,9 +567,10 @@ TEST_CASE(
|
|||||||
|
|
||||||
stellarMarker = 0;
|
stellarMarker = 0;
|
||||||
|
|
||||||
const int vacuumAttribute = f.domainMapperStateless->GetVacuumElementAttribute();
|
const int vacuumAttribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
|
|
||||||
for (int attributeIndex = 0; attributeIndex < f.mesh->attributes.Size(); ++attributeIndex) {
|
for (int attributeIndex = 0; attributeIndex < f.mesh->attributes.Size();
|
||||||
|
++attributeIndex) {
|
||||||
const int attribute = f.mesh->attributes[attributeIndex];
|
const int attribute = f.mesh->attributes[attributeIndex];
|
||||||
|
|
||||||
if (attribute != vacuumAttribute) {
|
if (attribute != vacuumAttribute) {
|
||||||
@@ -574,28 +578,34 @@ TEST_CASE(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const mfem::Geometry::Type elementGeometry = f.displacementFes->GetFE(0)->GetGeomType();
|
const mfem::Geometry::Type elementGeometry =
|
||||||
|
f.displacementFes->GetFE(0)->GetGeomType();
|
||||||
|
|
||||||
for (int element = 1; element < f.mesh->GetNE(); ++element) {
|
for (int element = 1; element < f.mesh->GetNE(); ++element) {
|
||||||
REQUIRE(f.displacementFes->GetFE(element)->GetGeomType() == elementGeometry);
|
REQUIRE(f.displacementFes->GetFE(element)->GetGeomType() ==
|
||||||
|
elementGeometry);
|
||||||
}
|
}
|
||||||
|
|
||||||
const int referenceQuadratureOrder = 2 * f.displacementFes->GetMaxElementOrder() + 16;
|
const int referenceQuadratureOrder =
|
||||||
|
2 * f.displacementFes->GetMaxElementOrder() + 16;
|
||||||
|
|
||||||
const mfem::IntegrationRule &referenceQuadrature =
|
const mfem::IntegrationRule &referenceQuadrature =
|
||||||
mfem::IntRules.Get(elementGeometry, referenceQuadratureOrder);
|
mfem::IntRules.Get(elementGeometry, referenceQuadratureOrder);
|
||||||
|
|
||||||
auto *analyticForceIntegrator = new mfem::VectorDomainLFIntegrator(analyticPressureForceCoefficient);
|
auto *analyticForceIntegrator =
|
||||||
|
new mfem::VectorDomainLFIntegrator(analyticPressureForceCoefficient);
|
||||||
|
|
||||||
analyticForceIntegrator->SetIntRule(&referenceQuadrature);
|
analyticForceIntegrator->SetIntRule(&referenceQuadrature);
|
||||||
|
|
||||||
mfem::ParLinearForm analyticForceLoad(f.displacementFes.get());
|
mfem::ParLinearForm analyticForceLoad(f.displacementFes.get());
|
||||||
|
|
||||||
analyticForceLoad.AddDomainIntegrator(analyticForceIntegrator, stellarMarker);
|
analyticForceLoad.AddDomainIntegrator(analyticForceIntegrator,
|
||||||
|
stellarMarker);
|
||||||
|
|
||||||
analyticForceLoad.Assemble();
|
analyticForceLoad.Assemble();
|
||||||
|
|
||||||
std::unique_ptr<mfem::HypreParVector> analyticForceHypreVector(analyticForceLoad.ParallelAssemble());
|
std::unique_ptr<mfem::HypreParVector> analyticForceHypreVector(
|
||||||
|
analyticForceLoad.ParallelAssemble());
|
||||||
|
|
||||||
REQUIRE(analyticForceHypreVector != nullptr);
|
REQUIRE(analyticForceHypreVector != nullptr);
|
||||||
|
|
||||||
@@ -603,7 +613,8 @@ TEST_CASE(
|
|||||||
|
|
||||||
REQUIRE(analyticForceTrue.Size() == discreteResidual.Size());
|
REQUIRE(analyticForceTrue.Size() == discreteResidual.Size());
|
||||||
|
|
||||||
const double analyticForceNorm = gravity_prepared_test_utils::global_norm(analyticForceTrue, communicator);
|
const double analyticForceNorm = gravity_prepared_test_utils::global_norm(
|
||||||
|
analyticForceTrue, communicator);
|
||||||
|
|
||||||
REQUIRE(std::isfinite(analyticForceNorm));
|
REQUIRE(std::isfinite(analyticForceNorm));
|
||||||
REQUIRE(analyticForceNorm > 0.0);
|
REQUIRE(analyticForceNorm > 0.0);
|
||||||
@@ -620,7 +631,8 @@ TEST_CASE(
|
|||||||
rieszForm.Assemble();
|
rieszForm.Assemble();
|
||||||
rieszForm.Finalize();
|
rieszForm.Finalize();
|
||||||
|
|
||||||
std::unique_ptr<mfem::HypreParMatrix> rieszMatrix(rieszForm.ParallelAssemble());
|
std::unique_ptr<mfem::HypreParMatrix> rieszMatrix(
|
||||||
|
rieszForm.ParallelAssemble());
|
||||||
|
|
||||||
REQUIRE(rieszMatrix != nullptr);
|
REQUIRE(rieszMatrix != nullptr);
|
||||||
REQUIRE(rieszMatrix->Height() == discreteResidual.Size());
|
REQUIRE(rieszMatrix->Height() == discreteResidual.Size());
|
||||||
@@ -637,30 +649,30 @@ TEST_CASE(
|
|||||||
rieszSolver.SetRelTol(1.0e-13);
|
rieszSolver.SetRelTol(1.0e-13);
|
||||||
rieszSolver.SetAbsTol(1.0e-15);
|
rieszSolver.SetAbsTol(1.0e-15);
|
||||||
rieszSolver.SetMaxIter(5000);
|
rieszSolver.SetMaxIter(5000);
|
||||||
rieszSolver.SetPrintLevel(1);
|
rieszSolver.SetPrintLevel(0);
|
||||||
|
|
||||||
auto calculateDualNorm = [&rieszSolver, communicator](const mfem::Vector &functional) {
|
auto calculateDualNorm = [&rieszSolver,
|
||||||
|
communicator](const mfem::Vector &functional) {
|
||||||
mfem::Vector rieszRepresentative(functional.Size());
|
mfem::Vector rieszRepresentative(functional.Size());
|
||||||
|
|
||||||
rieszRepresentative = 0.0;
|
rieszRepresentative = 0.0;
|
||||||
|
|
||||||
rieszSolver.Mult(functional, rieszRepresentative);
|
rieszSolver.Mult(functional, rieszRepresentative);
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(rieszSolver.GetConverged(),
|
||||||
rieszSolver.GetConverged(), "The pressure-force convergence-test Riesz solve "
|
"The pressure-force convergence-test Riesz solve "
|
||||||
"did not converge."
|
"did not converge.");
|
||||||
);
|
|
||||||
|
|
||||||
const double dualNormSquared =
|
const double dualNormSquared = gravity_prepared_test_utils::global_dot(
|
||||||
gravity_prepared_test_utils::global_dot(functional, rieszRepresentative, communicator);
|
functional, rieszRepresentative, communicator);
|
||||||
|
|
||||||
MFEM_VERIFY(std::isfinite(dualNormSquared), "The pressure-force dual norm is not finite.");
|
MFEM_VERIFY(std::isfinite(dualNormSquared),
|
||||||
|
"The pressure-force dual norm is not finite.");
|
||||||
|
|
||||||
MFEM_VERIFY(
|
MFEM_VERIFY(dualNormSquared >=
|
||||||
dualNormSquared >= -100.0 * std::numeric_limits<double>::epsilon(),
|
-100.0 * std::numeric_limits<double>::epsilon(),
|
||||||
"The pressure-force Riesz operator produced a "
|
"The pressure-force Riesz operator produced a "
|
||||||
"negative dual norm."
|
"negative dual norm.");
|
||||||
);
|
|
||||||
|
|
||||||
return std::sqrt(std::max(dualNormSquared, 0.0));
|
return std::sqrt(std::max(dualNormSquared, 0.0));
|
||||||
};
|
};
|
||||||
@@ -688,9 +700,12 @@ TEST_CASE(
|
|||||||
REQUIRE(relativeError > 0.0);
|
REQUIRE(relativeError > 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static_assert(refinementLevels.size() == 2, "This reduced convergence test expects exactly two refinement levels.");
|
static_assert(
|
||||||
|
refinementLevels.size() == 2,
|
||||||
|
"This reduced convergence test expects exactly two refinement levels.");
|
||||||
|
|
||||||
const double observedRate = std::log(relativeErrors[0] / relativeErrors[1]) / std::log(2.0);
|
const double observedRate =
|
||||||
|
std::log(relativeErrors[0] / relativeErrors[1]) / std::log(2.0);
|
||||||
|
|
||||||
INFO("Level 0 pressure-force relative dual error = " << relativeErrors[0]);
|
INFO("Level 0 pressure-force relative dual error = " << relativeErrors[0]);
|
||||||
|
|
||||||
|
|||||||
@@ -14,82 +14,94 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
using CoupledForm = mean_field::utils::blocks::barotropic_equilibrium_form;
|
using CoupledForm = mean_field::utils::blocks::barotropic_equilibrium_form;
|
||||||
|
|
||||||
constexpr auto densityValue =
|
constexpr auto densityValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::density_field.mass_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::density_field.mass_term);
|
||||||
|
|
||||||
constexpr auto displacementValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto displacementValue =
|
||||||
mean_field::utils::blocks::displacement_field.geometry_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::displacement_field.geometry_term);
|
||||||
|
|
||||||
constexpr auto gravityGradientValue =
|
constexpr auto gravityGradientValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::gravity_field.gradient_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::gravity_field.gradient_term);
|
||||||
|
|
||||||
constexpr auto gravityPotentialValue =
|
constexpr auto gravityPotentialValue =
|
||||||
mean_field::utils::blocks::get_value_block<CoupledForm>(mean_field::utils::blocks::gravity_field.poisson_term);
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
constexpr auto enthalpyValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto enthalpyValue =
|
||||||
mean_field::utils::blocks::enthalpy_field.specific_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::enthalpy_field.specific_term);
|
||||||
|
|
||||||
constexpr auto barotropicConstantValue = mean_field::utils::blocks::get_value_block<CoupledForm>(
|
constexpr auto barotropicConstantValue =
|
||||||
mean_field::utils::blocks::barotropic_constant_field.mass_normalization_term
|
mean_field::utils::blocks::get_value_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::barotropic_constant_field
|
||||||
|
.mass_normalization_term);
|
||||||
|
|
||||||
constexpr auto gravityGradientResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto gravityGradientResidual =
|
||||||
mean_field::utils::blocks::gravity_field.gradient_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.gradient_term);
|
||||||
|
|
||||||
constexpr auto gravityPotentialResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto gravityPotentialResidual =
|
||||||
mean_field::utils::blocks::gravity_field.poisson_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::gravity_field.poisson_term);
|
||||||
|
|
||||||
constexpr auto densityResidual =
|
constexpr auto densityResidual =
|
||||||
mean_field::utils::blocks::get_residual_block<CoupledForm>(mean_field::utils::blocks::density_field.mass_term);
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
|
mean_field::utils::blocks::density_field.mass_term);
|
||||||
|
|
||||||
constexpr auto displacementResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto displacementResidual =
|
||||||
mean_field::utils::blocks::displacement_field.geometry_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::displacement_field.geometry_term);
|
||||||
|
|
||||||
constexpr auto enthalpyResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto enthalpyResidual =
|
||||||
mean_field::utils::blocks::enthalpy_field.specific_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::enthalpy_field.specific_term);
|
||||||
|
|
||||||
constexpr auto massResidual = mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
constexpr auto massResidual =
|
||||||
mean_field::utils::blocks::barotropic_constant_field.mass_normalization_term
|
mean_field::utils::blocks::get_residual_block<CoupledForm>(
|
||||||
);
|
mean_field::utils::blocks::barotropic_constant_field
|
||||||
|
.mass_normalization_term);
|
||||||
|
|
||||||
[[nodiscard]] mean_field::operators::RotationalDisplacementForceLayout make_layout(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mean_field::operators::RotationalDisplacementForceLayout
|
||||||
|
make_layout(const mean_field::fem::FEM &f) {
|
||||||
using DomainSchema = gravity_prepared_test_utils::DomainSchema;
|
using DomainSchema = gravity_prepared_test_utils::DomainSchema;
|
||||||
|
|
||||||
const auto densityMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Density>(f);
|
const auto densityMap =
|
||||||
const auto displacementMap = gravity_prepared_test_utils::make_field_map<mean_field::field::Displacement>(f);
|
gravity_prepared_test_utils::make_field_map<mean_field::field::Density>(
|
||||||
|
f);
|
||||||
|
const auto displacementMap = gravity_prepared_test_utils::make_field_map<
|
||||||
|
mean_field::field::Displacement>(f);
|
||||||
const auto gravityFluxMap =
|
const auto gravityFluxMap =
|
||||||
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityFluxFes);
|
mean_field::field::make_field_dof_map<mean_field::field::Gravity,
|
||||||
const auto gravityPotentialMap =
|
DomainSchema>(*f.gravityFluxFes);
|
||||||
mean_field::field::make_field_dof_map<mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes);
|
const auto gravityPotentialMap = mean_field::field::make_field_dof_map<
|
||||||
|
mean_field::field::Gravity, DomainSchema>(*f.gravityPotentialFes);
|
||||||
const auto enthalpyMap =
|
const auto enthalpyMap =
|
||||||
mean_field::field::make_field_dof_map<mean_field::field::Enthalpy, DomainSchema>(*f.enthalpyFes);
|
mean_field::field::make_field_dof_map<mean_field::field::Enthalpy,
|
||||||
|
DomainSchema>(*f.enthalpyFes);
|
||||||
|
|
||||||
const std::array<int, CoupledForm::value_block_count> valueSizes{
|
const std::array<int, CoupledForm::value_block_count> valueSizes{
|
||||||
densityMap.reduced_size(), displacementMap.reduced_size(), gravityFluxMap.reduced_size(),
|
densityMap.reduced_size(), displacementMap.reduced_size(),
|
||||||
gravityPotentialMap.reduced_size(), enthalpyMap.reduced_size(), 1
|
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(),
|
||||||
};
|
enthalpyMap.reduced_size(), 1};
|
||||||
|
|
||||||
const std::array<int, CoupledForm::residual_block_count> residualSizes{
|
const std::array<int, CoupledForm::residual_block_count> residualSizes{
|
||||||
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(), densityMap.reduced_size(),
|
gravityFluxMap.reduced_size(), gravityPotentialMap.reduced_size(),
|
||||||
displacementMap.reduced_size(), enthalpyMap.reduced_size(), 1
|
densityMap.reduced_size(), displacementMap.reduced_size(),
|
||||||
};
|
enthalpyMap.reduced_size(), 1};
|
||||||
|
|
||||||
return {valueSizes, residualSizes};
|
return {valueSizes, residualSizes};
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_density(
|
[[nodiscard]] mfem::Vector make_density(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
|
|
||||||
mfem::FunctionCoefficient densityCoefficient([phase](const mfem::Vector &position) {
|
mfem::FunctionCoefficient densityCoefficient(
|
||||||
return 0.88 + 0.06 * std::sin(0.7 * position(0) + phase) + 0.04 * std::cos(0.6 * position(1) - phase) +
|
[phase](const mfem::Vector &position) {
|
||||||
|
return 0.88 + 0.06 * std::sin(0.7 * position(0) + phase) +
|
||||||
|
0.04 * std::cos(0.6 * position(1) - phase) +
|
||||||
0.025 * position(2) * position(2);
|
0.025 * position(2) * position(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -100,15 +112,14 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
return densityTrue;
|
return densityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_density_direction(
|
[[nodiscard]] mfem::Vector make_density_direction(const mean_field::fem::FEM &f,
|
||||||
const mean_field::fem::FEM &f,
|
const double phase) {
|
||||||
const double phase
|
|
||||||
) {
|
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
|
|
||||||
mfem::FunctionCoefficient densityCoefficient([phase](const mfem::Vector &position) {
|
mfem::FunctionCoefficient densityCoefficient(
|
||||||
return 0.17 * std::sin(0.9 * position(0) + phase) - 0.12 * std::cos(0.8 * position(1) - phase) +
|
[phase](const mfem::Vector &position) {
|
||||||
0.07 * position(2);
|
return 0.17 * std::sin(0.9 * position(0) + phase) -
|
||||||
|
0.12 * std::cos(0.8 * position(1) - phase) + 0.07 * position(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
densityField.ProjectCoefficient(densityCoefficient);
|
densityField.ProjectCoefficient(densityCoefficient);
|
||||||
@@ -118,16 +129,20 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
return densityTrue;
|
return densityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_displacement_direction(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
mfem::Vector direction = gravity_prepared_test_utils::make_displacement(f, 0.91);
|
make_displacement_direction(const mean_field::fem::FEM &f) {
|
||||||
|
mfem::Vector direction =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.91);
|
||||||
|
|
||||||
const mfem::Vector second = gravity_prepared_test_utils::make_displacement(f, 0.27);
|
const mfem::Vector second =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.27);
|
||||||
|
|
||||||
direction -= second;
|
direction -= second;
|
||||||
return direction;
|
return direction;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mean_field::physics::RigidRotation make_rotation(const double scale = 1.0) {
|
[[nodiscard]] mean_field::physics::RigidRotation
|
||||||
|
make_rotation(const double scale = 1.0) {
|
||||||
mfem::Vector angularVelocity(3);
|
mfem::Vector angularVelocity(3);
|
||||||
angularVelocity(0) = scale * 0.17;
|
angularVelocity(0) = scale * 0.17;
|
||||||
angularVelocity(1) = scale * -0.09;
|
angularVelocity(1) = scale * -0.09;
|
||||||
@@ -141,27 +156,28 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
return mean_field::physics::RigidRotation(angularVelocity, center);
|
return mean_field::physics::RigidRotation(angularVelocity, center);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mean_field::operators::context::rotational_displacement_force::RotationalDisplacementForceDependencies
|
[[nodiscard]] mean_field::operators::context::rotational_displacement_force::
|
||||||
|
RotationalDisplacementForceDependencies
|
||||||
make_dependencies() {
|
make_dependencies() {
|
||||||
return {
|
return {.discretization = {.identity = 211, .revision = 3},
|
||||||
.discretization = {.identity = 211, .revision = 3},
|
|
||||||
.density = {.identity = 223, .revision = 5},
|
.density = {.identity = 223, .revision = 5},
|
||||||
.displacement = {.identity = 227, .revision = 7},
|
.displacement = {.identity = 227, .revision = 7},
|
||||||
.rotation = {.identity = 229, .revision = 11}
|
.rotation = {.identity = 229, .revision = 11}};
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector make_vacuum_only_density(const mean_field::fem::FEM &f) {
|
[[nodiscard]] mfem::Vector
|
||||||
|
make_vacuum_only_density(const mean_field::fem::FEM &f) {
|
||||||
mfem::ParGridFunction densityField(f.densityFes.get());
|
mfem::ParGridFunction densityField(f.densityFes.get());
|
||||||
densityField = 0.0;
|
densityField = 0.0;
|
||||||
|
|
||||||
const int vacuumAttribute = f.domainMapperStateless->GetVacuumElementAttribute();
|
const int vacuumAttribute = field_dof_test_utils::vacuum_material_attribute;
|
||||||
|
|
||||||
mfem::Array<int> densityDofs;
|
mfem::Array<int> densityDofs;
|
||||||
int localVacuumElements = 0;
|
int localVacuumElements = 0;
|
||||||
|
|
||||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
mfem::ElementTransformation *transformation =
|
||||||
|
f.mesh->GetElementTransformation(elementId);
|
||||||
|
|
||||||
REQUIRE(transformation != nullptr);
|
REQUIRE(transformation != nullptr);
|
||||||
|
|
||||||
@@ -179,7 +195,8 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
|
|
||||||
int globalVacuumElements = 0;
|
int globalVacuumElements = 0;
|
||||||
|
|
||||||
MPI_Allreduce(&localVacuumElements, &globalVacuumElements, 1, MPI_INT, MPI_SUM, f.mesh->GetComm());
|
MPI_Allreduce(&localVacuumElements, &globalVacuumElements, 1, MPI_INT,
|
||||||
|
MPI_SUM, f.mesh->GetComm());
|
||||||
|
|
||||||
REQUIRE(globalVacuumElements > 0);
|
REQUIRE(globalVacuumElements > 0);
|
||||||
|
|
||||||
@@ -188,23 +205,20 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
return densityTrue;
|
return densityTrue;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double global_norm(
|
[[nodiscard]] double global_norm(const mfem::Vector &vector,
|
||||||
const mfem::Vector &vector,
|
MPI_Comm communicator) {
|
||||||
MPI_Comm communicator
|
|
||||||
) {
|
|
||||||
const double localSquaredNorm = vector * vector;
|
const double localSquaredNorm = vector * vector;
|
||||||
double globalSquaredNorm = 0.0;
|
double globalSquaredNorm = 0.0;
|
||||||
|
|
||||||
MPI_Allreduce(&localSquaredNorm, &globalSquaredNorm, 1, MPI_DOUBLE, MPI_SUM, communicator);
|
MPI_Allreduce(&localSquaredNorm, &globalSquaredNorm, 1, MPI_DOUBLE, MPI_SUM,
|
||||||
|
communicator);
|
||||||
|
|
||||||
return std::sqrt(globalSquaredNorm);
|
return std::sqrt(globalSquaredNorm);
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double global_dot(
|
[[nodiscard]] double global_dot(const mfem::Vector &left,
|
||||||
const mfem::Vector &left,
|
|
||||||
const mfem::Vector &right,
|
const mfem::Vector &right,
|
||||||
MPI_Comm communicator
|
MPI_Comm communicator) {
|
||||||
) {
|
|
||||||
REQUIRE(left.Size() == right.Size());
|
REQUIRE(left.Size() == right.Size());
|
||||||
|
|
||||||
const double localDot = left * right;
|
const double localDot = left * right;
|
||||||
@@ -215,29 +229,25 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
return globalDot;
|
return globalDot;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] double relative_difference(
|
[[nodiscard]] double relative_difference(const mfem::Vector &computed,
|
||||||
const mfem::Vector &computed,
|
|
||||||
const mfem::Vector &reference,
|
const mfem::Vector &reference,
|
||||||
MPI_Comm communicator
|
MPI_Comm communicator) {
|
||||||
) {
|
|
||||||
REQUIRE(computed.Size() == reference.Size());
|
REQUIRE(computed.Size() == reference.Size());
|
||||||
|
|
||||||
mfem::Vector difference(computed);
|
mfem::Vector difference(computed);
|
||||||
difference -= reference;
|
difference -= reference;
|
||||||
|
|
||||||
return global_norm(difference, communicator) /
|
return global_norm(difference, communicator) /
|
||||||
std::max(global_norm(reference, communicator), std::numeric_limits<double>::epsilon());
|
std::max(global_norm(reference, communicator),
|
||||||
|
std::numeric_limits<double>::epsilon());
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] mfem::Vector centered_difference(
|
[[nodiscard]] mfem::Vector centered_difference(
|
||||||
const mean_field::fem::FEM &f,
|
const mean_field::fem::FEM &f,
|
||||||
const mean_field::physics::RigidRotation &rotation,
|
const mean_field::physics::RigidRotation &rotation,
|
||||||
const mfem::Vector &baseDensity,
|
const mfem::Vector &baseDensity, const mfem::Vector &densityDirection,
|
||||||
const mfem::Vector &densityDirection,
|
|
||||||
const mfem::Vector &baseDisplacement,
|
const mfem::Vector &baseDisplacement,
|
||||||
const mfem::Vector &displacementDirection,
|
const mfem::Vector &displacementDirection, const double step) {
|
||||||
const double step
|
|
||||||
) {
|
|
||||||
mfem::Vector plusDensity(baseDensity);
|
mfem::Vector plusDensity(baseDensity);
|
||||||
plusDensity.Add(step, densityDirection);
|
plusDensity.Add(step, densityDirection);
|
||||||
|
|
||||||
@@ -254,12 +264,12 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
mfem::Vector minusResidual;
|
mfem::Vector minusResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, rotation, plusDensity, plusDisplacement, plusResidual
|
f, *f.domainMapperStateless, rotation, plusDensity, plusDisplacement,
|
||||||
);
|
plusResidual);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, rotation, minusDensity, minusDisplacement, minusResidual
|
f, *f.domainMapperStateless, rotation, minusDensity, minusDisplacement,
|
||||||
);
|
minusResidual);
|
||||||
|
|
||||||
plusResidual -= minusResidual;
|
plusResidual -= minusResidual;
|
||||||
plusResidual /= 2.0 * step;
|
plusResidual /= 2.0 * step;
|
||||||
@@ -270,8 +280,7 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
[[nodiscard]] mfem::Vector copy_residual_block(
|
[[nodiscard]] mfem::Vector copy_residual_block(
|
||||||
const mfem::Vector &action,
|
const mfem::Vector &action,
|
||||||
const mean_field::operators::RotationalDisplacementForceLayout &layout,
|
const mean_field::operators::RotationalDisplacementForceLayout &layout,
|
||||||
const mean_field::utils::blocks::residual_block<index> block
|
const mean_field::utils::blocks::residual_block<index> block) {
|
||||||
) {
|
|
||||||
mfem::Vector result(layout.size(block));
|
mfem::Vector result(layout.size(block));
|
||||||
const int offset = layout.offset(block);
|
const int offset = layout.offset(block);
|
||||||
|
|
||||||
@@ -286,17 +295,18 @@ namespace rotational_displacement_force_test_utils {
|
|||||||
TEST_CASE(
|
TEST_CASE(
|
||||||
"Rotational Displacement Force Query Includes Density Test And Linear "
|
"Rotational Displacement Force Query Includes Density Test And Linear "
|
||||||
"Position",
|
"Position",
|
||||||
tags::rotation_prepared_unit
|
tags::rotation_prepared_unit) {
|
||||||
) {
|
using DisplacementField =
|
||||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
mean_field::field::Field<mean_field::field::Displacement>;
|
||||||
|
|
||||||
constexpr int geometryWeightOrder = 4;
|
constexpr int geometryWeightOrder = 4;
|
||||||
|
|
||||||
constexpr mean_field::quadrature::Query query =
|
constexpr mean_field::quadrature::Query query = DisplacementField::make_query<
|
||||||
DisplacementField::make_query<mean_field::field::Displacement::Form::CentrifugalForce>(
|
mean_field::field::Displacement::Form::CentrifugalForce>(
|
||||||
mean_field::quadrature::QuadratureRole::discretization, geometryWeightOrder, std::array<int, 1>{1},
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
geometryWeightOrder, std::array<int, 1>{1},
|
||||||
);
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
/* density: 2, displacement test: 3, position: 1, geometry: 4 */
|
/* density: 2, displacement test: 3, position: 1, geometry: 4 */
|
||||||
constexpr int expectedBaseOrder = 2 + 3 + 1 + 4;
|
constexpr int expectedBaseOrder = 2 + 3 + 1 + 4;
|
||||||
@@ -308,33 +318,33 @@ TEST_CASE(
|
|||||||
STATIC_REQUIRE(*query.base_order == expectedBaseOrder);
|
STATIC_REQUIRE(*query.base_order == expectedBaseOrder);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Rotational Displacement Force Uses Negative Rotation-Potential "
|
||||||
"Rotational Displacement Force Uses Negative Rotation-Potential "
|
|
||||||
"Gradient And Excludes Vacuum",
|
"Gradient And Excludes Vacuum",
|
||||||
tags::rotation_kernel_accuracy
|
tags::rotation_kernel_accuracy) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
|
|
||||||
const mfem::Vector density = rotational_displacement_force_test_utils::make_density(f, 0.31);
|
const mfem::Vector density =
|
||||||
|
rotational_displacement_force_test_utils::make_density(f, 0.31);
|
||||||
|
|
||||||
mfem::Vector displacement(f.displacementFes->GetTrueVSize());
|
mfem::Vector displacement(f.displacementFes->GetTrueVSize());
|
||||||
displacement = 0.0;
|
displacement = 0.0;
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = rotational_displacement_force_test_utils::make_rotation();
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
rotational_displacement_force_test_utils::make_rotation();
|
||||||
|
|
||||||
mfem::Vector residual;
|
mfem::Vector residual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, rotation, density, displacement, residual
|
f, *f.domainMapperStateless, rotation, density, displacement, residual);
|
||||||
);
|
|
||||||
|
|
||||||
mfem::ParGridFunction gradientTestField(f.displacementFes.get());
|
mfem::ParGridFunction gradientTestField(f.displacementFes.get());
|
||||||
|
|
||||||
auto gradientFunction = [&rotation](const mfem::Vector &position, mfem::Vector &value) {
|
auto gradientFunction = [&rotation](const mfem::Vector &position,
|
||||||
|
mfem::Vector &value) {
|
||||||
rotation.potential_gradient(position, value);
|
rotation.potential_gradient(position, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -346,63 +356,73 @@ TEST_CASE(
|
|||||||
gradientTestField.GetTrueDofs(gradientTestDirection);
|
gradientTestField.GetTrueDofs(gradientTestDirection);
|
||||||
|
|
||||||
const double signedWork =
|
const double signedWork =
|
||||||
rotational_displacement_force_test_utils::global_dot(residual, gradientTestDirection, f.mesh->GetComm());
|
rotational_displacement_force_test_utils::global_dot(
|
||||||
|
residual, gradientTestDirection, f.mesh->GetComm());
|
||||||
|
|
||||||
INFO("Rotation-force work against grad(Psi) = " << signedWork);
|
INFO("Rotation-force work against grad(Psi) = " << signedWork);
|
||||||
CHECK(signedWork < 0.0);
|
CHECK(signedWork < 0.0);
|
||||||
|
|
||||||
const mfem::Vector vacuumDensity = rotational_displacement_force_test_utils::make_vacuum_only_density(f);
|
const mfem::Vector vacuumDensity =
|
||||||
|
rotational_displacement_force_test_utils::make_vacuum_only_density(f);
|
||||||
|
|
||||||
mfem::Vector vacuumResidual;
|
mfem::Vector vacuumResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, rotation, vacuumDensity, displacement, vacuumResidual
|
f, *f.domainMapperStateless, rotation, vacuumDensity, displacement,
|
||||||
);
|
vacuumResidual);
|
||||||
|
|
||||||
CHECK(rotational_displacement_force_test_utils::global_norm(vacuumResidual, f.mesh->GetComm()) == 0.0);
|
CHECK(rotational_displacement_force_test_utils::global_norm(
|
||||||
|
vacuumResidual, f.mesh->GetComm()) == 0.0);
|
||||||
|
|
||||||
mfem::Vector zeroAngularVelocity(3);
|
mfem::Vector zeroAngularVelocity(3);
|
||||||
mfem::Vector zeroCenter(3);
|
mfem::Vector zeroCenter(3);
|
||||||
zeroAngularVelocity = 0.0;
|
zeroAngularVelocity = 0.0;
|
||||||
zeroCenter = 0.0;
|
zeroCenter = 0.0;
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation zeroRotation(zeroAngularVelocity, zeroCenter);
|
const mean_field::physics::RigidRotation zeroRotation(zeroAngularVelocity,
|
||||||
|
zeroCenter);
|
||||||
|
|
||||||
mfem::Vector zeroRotationResidual;
|
mfem::Vector zeroRotationResidual;
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, zeroRotation, density, displacement, zeroRotationResidual
|
f, *f.domainMapperStateless, zeroRotation, density, displacement,
|
||||||
);
|
zeroRotationResidual);
|
||||||
|
|
||||||
CHECK(rotational_displacement_force_test_utils::global_norm(zeroRotationResidual, f.mesh->GetComm()) == 0.0);
|
CHECK(rotational_displacement_force_test_utils::global_norm(
|
||||||
|
zeroRotationResidual, f.mesh->GetComm()) == 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Rotational Displacement Force Reprepares Selectively",
|
||||||
"Prepared Rotational Displacement Force Reprepares Selectively",
|
tags::rotation_prepared) {
|
||||||
tags::rotation_prepared
|
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
|
|
||||||
mfem::Vector densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.37);
|
mfem::Vector densityTrue =
|
||||||
|
rotational_displacement_force_test_utils::make_density(f, 0.37);
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.53);
|
const mfem::Vector displacementTrue =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.53);
|
||||||
|
|
||||||
mean_field::physics::RigidRotation rotation = rotational_displacement_force_test_utils::make_rotation(0.81);
|
mean_field::physics::RigidRotation rotation =
|
||||||
|
rotational_displacement_force_test_utils::make_rotation(0.81);
|
||||||
|
|
||||||
auto dependencies = rotational_displacement_force_test_utils::make_dependencies();
|
auto dependencies =
|
||||||
|
rotational_displacement_force_test_utils::make_dependencies();
|
||||||
|
|
||||||
mean_field::operators::PreparedRotationalDisplacementForceOperator preparedOperator(f, *f.domainMapperStateless);
|
mean_field::operators::PreparedRotationalDisplacementForceOperator
|
||||||
|
preparedOperator(f, *f.domainMapperStateless);
|
||||||
|
|
||||||
const auto &context = preparedOperator.GetContext();
|
const auto &context = preparedOperator.GetContext();
|
||||||
mfem::Vector density = context.GetDensityMap().gather(densityTrue);
|
mfem::Vector density = context.GetDensityMap().gather(densityTrue);
|
||||||
const mfem::Vector displacement = context.GetDisplacementMap().gather(displacementTrue);
|
const mfem::Vector displacement =
|
||||||
|
context.GetDisplacementMap().gather(displacementTrue);
|
||||||
|
|
||||||
const auto initialReport =
|
const auto initialReport = preparedOperator.Prepare(
|
||||||
preparedOperator.Prepare({.density = density, .displacement = displacement}, dependencies, rotation);
|
{.density = density, .displacement = displacement}, dependencies,
|
||||||
|
rotation);
|
||||||
|
|
||||||
REQUIRE(initialReport.DidAnyWork());
|
REQUIRE(initialReport.DidAnyWork());
|
||||||
REQUIRE(initialReport.updatedRotation);
|
REQUIRE(initialReport.updatedRotation);
|
||||||
@@ -415,18 +435,19 @@ TEST_CASE(
|
|||||||
preparedOperator.BuildResidual(preparedResidual);
|
preparedOperator.BuildResidual(preparedResidual);
|
||||||
|
|
||||||
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
mean_field::operators::kernels::apply_rotational_displacement_force_residual(
|
||||||
f, *f.domainMapperStateless, rotation, densityTrue, displacementTrue, kernelResidual
|
f, *f.domainMapperStateless, rotation, densityTrue, displacementTrue,
|
||||||
);
|
kernelResidual);
|
||||||
|
|
||||||
const mfem::Vector kernelResidualReduced = context.GetDisplacementMap().gather(kernelResidual);
|
const mfem::Vector kernelResidualReduced =
|
||||||
|
context.GetDisplacementMap().gather(kernelResidual);
|
||||||
|
|
||||||
CHECK(
|
CHECK(rotational_displacement_force_test_utils::relative_difference(
|
||||||
rotational_displacement_force_test_utils::relative_difference(
|
preparedResidual, kernelResidualReduced, f.mesh->GetComm()) <
|
||||||
preparedResidual, kernelResidualReduced, f.mesh->GetComm()
|
2.0e-12);
|
||||||
) < 2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
CHECK_FALSE(preparedOperator.Prepare({.density = density, .displacement = displacement}, dependencies, rotation)
|
CHECK_FALSE(preparedOperator
|
||||||
|
.Prepare({.density = density, .displacement = displacement},
|
||||||
|
dependencies, rotation)
|
||||||
.DidAnyWork());
|
.DidAnyWork());
|
||||||
|
|
||||||
densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.79);
|
densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.79);
|
||||||
@@ -434,8 +455,9 @@ TEST_CASE(
|
|||||||
|
|
||||||
++dependencies.density.revision;
|
++dependencies.density.revision;
|
||||||
|
|
||||||
const auto densityReport =
|
const auto densityReport = preparedOperator.Prepare(
|
||||||
preparedOperator.Prepare({.density = density, .displacement = displacement}, dependencies, rotation);
|
{.density = density, .displacement = displacement}, dependencies,
|
||||||
|
rotation);
|
||||||
|
|
||||||
CHECK(densityReport.preparedResidual);
|
CHECK(densityReport.preparedResidual);
|
||||||
CHECK_FALSE(densityReport.updatedRotation);
|
CHECK_FALSE(densityReport.updatedRotation);
|
||||||
@@ -444,8 +466,9 @@ TEST_CASE(
|
|||||||
|
|
||||||
++dependencies.rotation.revision;
|
++dependencies.rotation.revision;
|
||||||
|
|
||||||
const auto rotationReport =
|
const auto rotationReport = preparedOperator.Prepare(
|
||||||
preparedOperator.Prepare({.density = density, .displacement = displacement}, dependencies, rotation);
|
{.density = density, .displacement = displacement}, dependencies,
|
||||||
|
rotation);
|
||||||
|
|
||||||
CHECK(rotationReport.updatedRotation);
|
CHECK(rotationReport.updatedRotation);
|
||||||
CHECK(rotationReport.preparedResidual);
|
CHECK(rotationReport.preparedResidual);
|
||||||
@@ -453,40 +476,45 @@ TEST_CASE(
|
|||||||
CHECK(preparedOperator.GetResidualApplicationCount() == 1);
|
CHECK(preparedOperator.GetResidualApplicationCount() == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Rotational Displacement Force Jacobian Matches Both Columns And "
|
||||||
"Rotational Displacement Force Jacobian Matches Both Columns And "
|
|
||||||
"Centered Differences",
|
"Centered Differences",
|
||||||
tags::rotation_prepared_jacobian_accuracy
|
tags::rotation_prepared_jacobian_accuracy) {
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
|
|
||||||
const mfem::Vector densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.43);
|
const mfem::Vector densityTrue =
|
||||||
|
rotational_displacement_force_test_utils::make_density(f, 0.43);
|
||||||
|
|
||||||
const mfem::Vector densityDirectionTrue = rotational_displacement_force_test_utils::make_density_direction(f, 0.59);
|
const mfem::Vector densityDirectionTrue =
|
||||||
|
rotational_displacement_force_test_utils::make_density_direction(f, 0.59);
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.61);
|
const mfem::Vector displacementTrue =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.61);
|
||||||
|
|
||||||
const mfem::Vector displacementDirectionTrue =
|
const mfem::Vector displacementDirectionTrue =
|
||||||
rotational_displacement_force_test_utils::make_displacement_direction(f);
|
rotational_displacement_force_test_utils::make_displacement_direction(f);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = rotational_displacement_force_test_utils::make_rotation(0.93);
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
rotational_displacement_force_test_utils::make_rotation(0.93);
|
||||||
|
|
||||||
mean_field::operators::PreparedRotationalDisplacementForceOperator preparedOperator(f, *f.domainMapperStateless);
|
mean_field::operators::PreparedRotationalDisplacementForceOperator
|
||||||
|
preparedOperator(f, *f.domainMapperStateless);
|
||||||
|
|
||||||
const auto &context = preparedOperator.GetContext();
|
const auto &context = preparedOperator.GetContext();
|
||||||
const mfem::Vector density = context.GetDensityMap().gather(densityTrue);
|
const mfem::Vector density = context.GetDensityMap().gather(densityTrue);
|
||||||
const mfem::Vector densityDirection = context.GetDensityMap().gather(densityDirectionTrue);
|
const mfem::Vector densityDirection =
|
||||||
const mfem::Vector displacement = context.GetDisplacementMap().gather(displacementTrue);
|
context.GetDensityMap().gather(densityDirectionTrue);
|
||||||
const mfem::Vector displacementDirection = context.GetDisplacementMap().gather(displacementDirectionTrue);
|
const mfem::Vector displacement =
|
||||||
|
context.GetDisplacementMap().gather(displacementTrue);
|
||||||
|
const mfem::Vector displacementDirection =
|
||||||
|
context.GetDisplacementMap().gather(displacementDirectionTrue);
|
||||||
|
|
||||||
preparedOperator.Prepare(
|
preparedOperator.Prepare(
|
||||||
{.density = density, .displacement = displacement},
|
{.density = density, .displacement = displacement},
|
||||||
rotational_displacement_force_test_utils::make_dependencies(), rotation
|
rotational_displacement_force_test_utils::make_dependencies(), rotation);
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector densityAction;
|
mfem::Vector densityAction;
|
||||||
mfem::Vector displacementAction;
|
mfem::Vector displacementAction;
|
||||||
@@ -494,18 +522,17 @@ TEST_CASE(
|
|||||||
|
|
||||||
preparedOperator.ApplyDensityJacobianAction(densityDirection, densityAction);
|
preparedOperator.ApplyDensityJacobianAction(densityDirection, densityAction);
|
||||||
|
|
||||||
preparedOperator.ApplyDisplacementJacobianAction(displacementDirection, displacementAction);
|
preparedOperator.ApplyDisplacementJacobianAction(displacementDirection,
|
||||||
|
displacementAction);
|
||||||
|
|
||||||
preparedOperator.ApplyCompleteJacobianAction(densityDirection, displacementDirection, completeAction);
|
preparedOperator.ApplyCompleteJacobianAction(
|
||||||
|
densityDirection, displacementDirection, completeAction);
|
||||||
|
|
||||||
mfem::Vector summedColumns(densityAction);
|
mfem::Vector summedColumns(densityAction);
|
||||||
summedColumns += displacementAction;
|
summedColumns += displacementAction;
|
||||||
|
|
||||||
CHECK(
|
CHECK(rotational_displacement_force_test_utils::relative_difference(
|
||||||
rotational_displacement_force_test_utils::relative_difference(
|
completeAction, summedColumns, f.mesh->GetComm()) < 2.0e-12);
|
||||||
completeAction, summedColumns, f.mesh->GetComm()
|
|
||||||
) < 2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
mfem::Vector zeroDensityTrue(densityDirectionTrue.Size());
|
mfem::Vector zeroDensityTrue(densityDirectionTrue.Size());
|
||||||
mfem::Vector zeroDisplacementTrue(displacementDirectionTrue.Size());
|
mfem::Vector zeroDisplacementTrue(displacementDirectionTrue.Size());
|
||||||
@@ -514,33 +541,39 @@ TEST_CASE(
|
|||||||
|
|
||||||
constexpr double step = 1.0e-5;
|
constexpr double step = 1.0e-5;
|
||||||
|
|
||||||
const mfem::Vector densityDifferenceTrue = rotational_displacement_force_test_utils::centered_difference(
|
const mfem::Vector densityDifferenceTrue =
|
||||||
f, rotation, densityTrue, densityDirectionTrue, displacementTrue, zeroDisplacementTrue, step
|
rotational_displacement_force_test_utils::centered_difference(
|
||||||
);
|
f, rotation, densityTrue, densityDirectionTrue, displacementTrue,
|
||||||
|
zeroDisplacementTrue, step);
|
||||||
|
|
||||||
const mfem::Vector displacementDifferenceTrue = rotational_displacement_force_test_utils::centered_difference(
|
const mfem::Vector displacementDifferenceTrue =
|
||||||
f, rotation, densityTrue, zeroDensityTrue, displacementTrue, displacementDirectionTrue, step
|
rotational_displacement_force_test_utils::centered_difference(
|
||||||
);
|
f, rotation, densityTrue, zeroDensityTrue, displacementTrue,
|
||||||
|
displacementDirectionTrue, step);
|
||||||
|
|
||||||
const mfem::Vector completeDifferenceTrue = rotational_displacement_force_test_utils::centered_difference(
|
const mfem::Vector completeDifferenceTrue =
|
||||||
f, rotation, densityTrue, densityDirectionTrue, displacementTrue, displacementDirectionTrue, step
|
rotational_displacement_force_test_utils::centered_difference(
|
||||||
);
|
f, rotation, densityTrue, densityDirectionTrue, displacementTrue,
|
||||||
|
displacementDirectionTrue, step);
|
||||||
|
|
||||||
const mfem::Vector densityDifference = context.GetDisplacementMap().gather(densityDifferenceTrue);
|
const mfem::Vector densityDifference =
|
||||||
const mfem::Vector displacementDifference = context.GetDisplacementMap().gather(displacementDifferenceTrue);
|
context.GetDisplacementMap().gather(densityDifferenceTrue);
|
||||||
const mfem::Vector completeDifference = context.GetDisplacementMap().gather(completeDifferenceTrue);
|
const mfem::Vector displacementDifference =
|
||||||
|
context.GetDisplacementMap().gather(displacementDifferenceTrue);
|
||||||
|
const mfem::Vector completeDifference =
|
||||||
|
context.GetDisplacementMap().gather(completeDifferenceTrue);
|
||||||
|
|
||||||
const double densityError = rotational_displacement_force_test_utils::relative_difference(
|
const double densityError =
|
||||||
densityAction, densityDifference, f.mesh->GetComm()
|
rotational_displacement_force_test_utils::relative_difference(
|
||||||
);
|
densityAction, densityDifference, f.mesh->GetComm());
|
||||||
|
|
||||||
const double displacementError = rotational_displacement_force_test_utils::relative_difference(
|
const double displacementError =
|
||||||
displacementAction, displacementDifference, f.mesh->GetComm()
|
rotational_displacement_force_test_utils::relative_difference(
|
||||||
);
|
displacementAction, displacementDifference, f.mesh->GetComm());
|
||||||
|
|
||||||
const double completeError = rotational_displacement_force_test_utils::relative_difference(
|
const double completeError =
|
||||||
completeAction, completeDifference, f.mesh->GetComm()
|
rotational_displacement_force_test_utils::relative_difference(
|
||||||
);
|
completeAction, completeDifference, f.mesh->GetComm());
|
||||||
|
|
||||||
INFO("Density-column centered-difference error = " << densityError);
|
INFO("Density-column centered-difference error = " << densityError);
|
||||||
INFO("Displacement-column centered-difference error = " << displacementError);
|
INFO("Displacement-column centered-difference error = " << displacementError);
|
||||||
@@ -551,95 +584,109 @@ TEST_CASE(
|
|||||||
CHECK(completeError < 4.0e-8);
|
CHECK(completeError < 4.0e-8);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Prepared Rotational Displacement Force MFEM Adapter Routes Only R-d",
|
||||||
"Prepared Rotational Displacement Force MFEM Adapter Routes Only R-d",
|
tags::rotation_prepared_unit) {
|
||||||
tags::rotation_prepared_unit
|
|
||||||
) {
|
|
||||||
mean_field::utils::Args args = test_utils::setup_args();
|
mean_field::utils::Args args = test_utils::setup_args();
|
||||||
|
|
||||||
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
mean_field::fem::FEM f = mean_field::fem::setup_fem(args.mesh_file, args, 0);
|
||||||
|
|
||||||
REQUIRE(f.okay());
|
REQUIRE(f.okay());
|
||||||
|
|
||||||
const mfem::Vector densityTrue = rotational_displacement_force_test_utils::make_density(f, 0.47);
|
const mfem::Vector densityTrue =
|
||||||
|
rotational_displacement_force_test_utils::make_density(f, 0.47);
|
||||||
|
|
||||||
const mfem::Vector densityDirectionTrue = rotational_displacement_force_test_utils::make_density_direction(f, 0.63);
|
const mfem::Vector densityDirectionTrue =
|
||||||
|
rotational_displacement_force_test_utils::make_density_direction(f, 0.63);
|
||||||
|
|
||||||
const mfem::Vector displacementTrue = gravity_prepared_test_utils::make_displacement(f, 0.57);
|
const mfem::Vector displacementTrue =
|
||||||
|
gravity_prepared_test_utils::make_displacement(f, 0.57);
|
||||||
|
|
||||||
const mfem::Vector displacementDirectionTrue =
|
const mfem::Vector displacementDirectionTrue =
|
||||||
rotational_displacement_force_test_utils::make_displacement_direction(f);
|
rotational_displacement_force_test_utils::make_displacement_direction(f);
|
||||||
|
|
||||||
const mean_field::physics::RigidRotation rotation = rotational_displacement_force_test_utils::make_rotation(0.87);
|
const mean_field::physics::RigidRotation rotation =
|
||||||
|
rotational_displacement_force_test_utils::make_rotation(0.87);
|
||||||
|
|
||||||
mean_field::operators::PreparedRotationalDisplacementForceOperator preparedOperator(f, *f.domainMapperStateless);
|
mean_field::operators::PreparedRotationalDisplacementForceOperator
|
||||||
|
preparedOperator(f, *f.domainMapperStateless);
|
||||||
|
|
||||||
const auto &context = preparedOperator.GetContext();
|
const auto &context = preparedOperator.GetContext();
|
||||||
const mfem::Vector density = context.GetDensityMap().gather(densityTrue);
|
const mfem::Vector density = context.GetDensityMap().gather(densityTrue);
|
||||||
const mfem::Vector densityDirection = context.GetDensityMap().gather(densityDirectionTrue);
|
const mfem::Vector densityDirection =
|
||||||
const mfem::Vector displacement = context.GetDisplacementMap().gather(displacementTrue);
|
context.GetDensityMap().gather(densityDirectionTrue);
|
||||||
const mfem::Vector displacementDirection = context.GetDisplacementMap().gather(displacementDirectionTrue);
|
const mfem::Vector displacement =
|
||||||
|
context.GetDisplacementMap().gather(displacementTrue);
|
||||||
|
const mfem::Vector displacementDirection =
|
||||||
|
context.GetDisplacementMap().gather(displacementDirectionTrue);
|
||||||
|
|
||||||
preparedOperator.Prepare(
|
preparedOperator.Prepare(
|
||||||
{.density = density, .displacement = displacement},
|
{.density = density, .displacement = displacement},
|
||||||
rotational_displacement_force_test_utils::make_dependencies(), rotation
|
rotational_displacement_force_test_utils::make_dependencies(), rotation);
|
||||||
);
|
|
||||||
|
|
||||||
const auto layout = rotational_displacement_force_test_utils::make_layout(f);
|
const auto layout = rotational_displacement_force_test_utils::make_layout(f);
|
||||||
|
|
||||||
mean_field::operators::PreparedRotationalDisplacementForceJacobianOperator adapter(layout, preparedOperator);
|
mean_field::operators::PreparedRotationalDisplacementForceJacobianOperator
|
||||||
|
adapter(layout, preparedOperator);
|
||||||
|
|
||||||
mfem::BlockVector direction(layout.value_offsets());
|
mfem::BlockVector direction(layout.value_offsets());
|
||||||
direction = 0.0;
|
direction = 0.0;
|
||||||
|
|
||||||
direction.GetBlock(rotational_displacement_force_test_utils::densityValue) = densityDirection;
|
direction.GetBlock(rotational_displacement_force_test_utils::densityValue) =
|
||||||
|
densityDirection;
|
||||||
|
|
||||||
direction.GetBlock(rotational_displacement_force_test_utils::displacementValue) = displacementDirection;
|
direction.GetBlock(
|
||||||
|
rotational_displacement_force_test_utils::displacementValue) =
|
||||||
|
displacementDirection;
|
||||||
|
|
||||||
direction.GetBlock(rotational_displacement_force_test_utils::gravityGradientValue) = 0.23;
|
direction.GetBlock(
|
||||||
|
rotational_displacement_force_test_utils::gravityGradientValue) = 0.23;
|
||||||
|
|
||||||
direction.GetBlock(rotational_displacement_force_test_utils::gravityPotentialValue) = -0.31;
|
direction.GetBlock(
|
||||||
|
rotational_displacement_force_test_utils::gravityPotentialValue) = -0.31;
|
||||||
|
|
||||||
direction.GetBlock(rotational_displacement_force_test_utils::enthalpyValue) = 0.37;
|
direction.GetBlock(rotational_displacement_force_test_utils::enthalpyValue) =
|
||||||
|
0.37;
|
||||||
|
|
||||||
direction.GetBlock(rotational_displacement_force_test_utils::barotropicConstantValue) = -0.41;
|
direction.GetBlock(
|
||||||
|
rotational_displacement_force_test_utils::barotropicConstantValue) =
|
||||||
|
-0.41;
|
||||||
|
|
||||||
mfem::Vector action;
|
mfem::Vector action;
|
||||||
adapter.Mult(direction, action);
|
adapter.Mult(direction, action);
|
||||||
|
|
||||||
mfem::Vector expectedDisplacementAction;
|
mfem::Vector expectedDisplacementAction;
|
||||||
|
|
||||||
preparedOperator.ApplyCompleteJacobianAction(densityDirection, displacementDirection, expectedDisplacementAction);
|
preparedOperator.ApplyCompleteJacobianAction(
|
||||||
|
densityDirection, displacementDirection, expectedDisplacementAction);
|
||||||
|
|
||||||
const mfem::Vector actualDisplacementAction = rotational_displacement_force_test_utils::copy_residual_block(
|
const mfem::Vector actualDisplacementAction =
|
||||||
action, layout, rotational_displacement_force_test_utils::displacementResidual
|
rotational_displacement_force_test_utils::copy_residual_block(
|
||||||
);
|
action, layout,
|
||||||
|
rotational_displacement_force_test_utils::displacementResidual);
|
||||||
|
|
||||||
CHECK(
|
CHECK(rotational_displacement_force_test_utils::relative_difference(
|
||||||
rotational_displacement_force_test_utils::relative_difference(
|
actualDisplacementAction, expectedDisplacementAction,
|
||||||
actualDisplacementAction, expectedDisplacementAction, f.mesh->GetComm()
|
f.mesh->GetComm()) < 2.0e-12);
|
||||||
) < 2.0e-12
|
|
||||||
);
|
|
||||||
|
|
||||||
const std::array<mfem::Vector, 5> zeroRows{
|
const std::array<mfem::Vector, 5> zeroRows{
|
||||||
rotational_displacement_force_test_utils::copy_residual_block(
|
rotational_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, rotational_displacement_force_test_utils::gravityGradientResidual
|
action, layout,
|
||||||
),
|
rotational_displacement_force_test_utils::gravityGradientResidual),
|
||||||
rotational_displacement_force_test_utils::copy_residual_block(
|
rotational_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, rotational_displacement_force_test_utils::gravityPotentialResidual
|
action, layout,
|
||||||
),
|
rotational_displacement_force_test_utils::gravityPotentialResidual),
|
||||||
rotational_displacement_force_test_utils::copy_residual_block(
|
rotational_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, rotational_displacement_force_test_utils::densityResidual
|
action, layout,
|
||||||
),
|
rotational_displacement_force_test_utils::densityResidual),
|
||||||
rotational_displacement_force_test_utils::copy_residual_block(
|
rotational_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, rotational_displacement_force_test_utils::enthalpyResidual
|
action, layout,
|
||||||
),
|
rotational_displacement_force_test_utils::enthalpyResidual),
|
||||||
rotational_displacement_force_test_utils::copy_residual_block(
|
rotational_displacement_force_test_utils::copy_residual_block(
|
||||||
action, layout, rotational_displacement_force_test_utils::massResidual
|
action, layout,
|
||||||
)
|
rotational_displacement_force_test_utils::massResidual)};
|
||||||
};
|
|
||||||
|
|
||||||
for (const mfem::Vector &row : zeroRows) {
|
for (const mfem::Vector &row : zeroRows) {
|
||||||
CHECK(rotational_displacement_force_test_utils::global_norm(row, f.mesh->GetComm()) == 0.0);
|
CHECK(rotational_displacement_force_test_utils::global_norm(
|
||||||
|
row, f.mesh->GetComm()) == 0.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -8,14 +8,13 @@
|
|||||||
import mean_field;
|
import mean_field;
|
||||||
import test_helpers;
|
import test_helpers;
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Satisfies Its Analytic Identities",
|
||||||
"Polytropic Barotrope Satisfies Its Analytic Identities",
|
tags::barotrope_eos_unit) {
|
||||||
tags::hydro &tags::unit &tags::barotrope
|
|
||||||
) {
|
|
||||||
constexpr double polytropic_index = 3.0;
|
constexpr double polytropic_index = 3.0;
|
||||||
constexpr double polytropic_constant = 1.5;
|
constexpr double polytropic_constant = 1.5;
|
||||||
|
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(polytropic_index, polytropic_constant);
|
const mean_field::eos::Polytrope barotrope(polytropic_index,
|
||||||
|
polytropic_constant);
|
||||||
|
|
||||||
const std::array<double, 5> densities{1.0e-6, 1.0e-3, 0.1, 0.7, 2.0};
|
const std::array<double, 5> densities{1.0e-6, 1.0e-3, 0.1, 0.7, 2.0};
|
||||||
|
|
||||||
@@ -24,30 +23,40 @@ TEST_CASE(
|
|||||||
|
|
||||||
const double enthalpy = barotrope.enthalpy_from_density(density);
|
const double enthalpy = barotrope.enthalpy_from_density(density);
|
||||||
|
|
||||||
const double reconstructed_density = barotrope.density_from_enthalpy(enthalpy);
|
const double reconstructed_density =
|
||||||
|
barotrope.density_from_enthalpy(enthalpy);
|
||||||
|
|
||||||
const double reconstructed_pressure = barotrope.pressure_from_enthalpy(enthalpy);
|
const double reconstructed_pressure =
|
||||||
|
barotrope.pressure_from_enthalpy(enthalpy);
|
||||||
|
|
||||||
CHECK_THAT(reconstructed_density, Catch::Matchers::WithinRel(density, 2.0e-14));
|
const double reconstructed_enthalpy =
|
||||||
|
barotrope.enthalpy_from_pressure(pressure);
|
||||||
|
|
||||||
CHECK_THAT(reconstructed_pressure, Catch::Matchers::WithinRel(pressure, 2.0e-14));
|
CHECK_THAT(reconstructed_density,
|
||||||
|
Catch::Matchers::WithinRel(density, 2.0e-14));
|
||||||
|
|
||||||
CHECK_THAT(pressure, Catch::Matchers::WithinRel(density * enthalpy / (polytropic_index + 1.0), 2.0e-14));
|
CHECK_THAT(reconstructed_pressure,
|
||||||
|
Catch::Matchers::WithinRel(pressure, 2.0e-14));
|
||||||
|
|
||||||
CHECK_THAT(barotrope.pressure_derivative_from_enthalpy(enthalpy), Catch::Matchers::WithinRel(density, 2.0e-14));
|
CHECK_THAT(reconstructed_enthalpy,
|
||||||
|
Catch::Matchers::WithinRel(enthalpy, 2.0e-14));
|
||||||
|
|
||||||
|
CHECK_THAT(pressure,
|
||||||
|
Catch::Matchers::WithinRel(
|
||||||
|
density * enthalpy / (polytropic_index + 1.0), 2.0e-14));
|
||||||
|
|
||||||
|
CHECK_THAT(barotrope.pressure_derivative_from_enthalpy(enthalpy),
|
||||||
|
Catch::Matchers::WithinRel(density, 2.0e-14));
|
||||||
|
|
||||||
CHECK_THAT(
|
CHECK_THAT(
|
||||||
barotrope.pressure_derivative_from_density(density),
|
barotrope.pressure_derivative_from_density(density),
|
||||||
Catch::Matchers::WithinRel(enthalpy / polytropic_index, 2.0e-14)
|
Catch::Matchers::WithinRel(enthalpy / polytropic_index, 2.0e-14));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Derivatives Match Centered Differences",
|
||||||
"Polytropic Barotrope Derivatives Match Centered Differences",
|
tags::barotrope_eos_jacobian) {
|
||||||
tags::hydro &tags::jacobian &tags::unit &tags::barotrope
|
const mean_field::eos::Polytrope barotrope(3.0, 1.5);
|
||||||
) {
|
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 1.5);
|
|
||||||
|
|
||||||
const std::array<double, 4> enthalpies{0.05, 0.2, 0.7, 1.4};
|
const std::array<double, 4> enthalpies{0.05, 0.2, 0.7, 1.4};
|
||||||
|
|
||||||
@@ -55,30 +64,30 @@ TEST_CASE(
|
|||||||
const double step = 1.0e-6 * std::max(1.0, enthalpy);
|
const double step = 1.0e-6 * std::max(1.0, enthalpy);
|
||||||
|
|
||||||
const double density_difference =
|
const double density_difference =
|
||||||
(barotrope.density_from_enthalpy(enthalpy + step) - barotrope.density_from_enthalpy(enthalpy - step)) /
|
(barotrope.density_from_enthalpy(enthalpy + step) -
|
||||||
|
barotrope.density_from_enthalpy(enthalpy - step)) /
|
||||||
(2.0 * step);
|
(2.0 * step);
|
||||||
|
|
||||||
const double pressure_difference =
|
const double pressure_difference =
|
||||||
(barotrope.pressure_from_enthalpy(enthalpy + step) - barotrope.pressure_from_enthalpy(enthalpy - step)) /
|
(barotrope.pressure_from_enthalpy(enthalpy + step) -
|
||||||
|
barotrope.pressure_from_enthalpy(enthalpy - step)) /
|
||||||
(2.0 * step);
|
(2.0 * step);
|
||||||
|
|
||||||
CHECK_THAT(
|
CHECK_THAT(
|
||||||
density_difference,
|
density_difference,
|
||||||
Catch::Matchers::WithinRel(barotrope.density_derivative_from_enthalpy(enthalpy), 5.0e-10)
|
Catch::Matchers::WithinRel(
|
||||||
);
|
barotrope.density_derivative_from_enthalpy(enthalpy), 5.0e-10));
|
||||||
|
|
||||||
CHECK_THAT(
|
CHECK_THAT(
|
||||||
pressure_difference,
|
pressure_difference,
|
||||||
Catch::Matchers::WithinRel(barotrope.pressure_derivative_from_enthalpy(enthalpy), 5.0e-10)
|
Catch::Matchers::WithinRel(
|
||||||
);
|
barotrope.pressure_derivative_from_enthalpy(enthalpy), 5.0e-10));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Has An Exact Zero Density Surface",
|
||||||
"Polytropic Barotrope Has An Exact Zero Density Surface",
|
tags::barotrope_eos_unit) {
|
||||||
tags::hydro &tags::unit &tags::barotrope
|
const mean_field::eos::Polytrope barotrope(3.0, 1.5);
|
||||||
) {
|
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 1.5);
|
|
||||||
|
|
||||||
CHECK(barotrope.density_from_enthalpy(-1.0) == 0.0);
|
CHECK(barotrope.density_from_enthalpy(-1.0) == 0.0);
|
||||||
CHECK(barotrope.density_from_enthalpy(0.0) == 0.0);
|
CHECK(barotrope.density_from_enthalpy(0.0) == 0.0);
|
||||||
@@ -93,21 +102,21 @@ TEST_CASE(
|
|||||||
CHECK(barotrope.pressure_derivative_from_enthalpy(0.0) == 0.0);
|
CHECK(barotrope.pressure_derivative_from_enthalpy(0.0) == 0.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Rejects Invalid Material Parameters",
|
||||||
"Polytropic Barotrope Rejects Invalid Material Parameters",
|
tags::barotrope_eos_unit) {
|
||||||
tags::hydro &tags::unit
|
CHECK_THROWS_AS(mean_field::eos::Polytrope(0.5, 1.0), std::invalid_argument);
|
||||||
) {
|
|
||||||
CHECK_THROWS_AS(mean_field::physics::PolytropicBarotrope(0.5, 1.0), std::invalid_argument);
|
|
||||||
|
|
||||||
CHECK_THROWS_AS(mean_field::physics::PolytropicBarotrope(3.0, 0.0), std::invalid_argument);
|
CHECK_THROWS_AS(mean_field::eos::Polytrope(3.0, 0.0), std::invalid_argument);
|
||||||
|
|
||||||
CHECK_THROWS_AS(
|
CHECK_THROWS_AS(
|
||||||
mean_field::physics::PolytropicBarotrope(std::numeric_limits<double>::infinity(), 1.0), std::invalid_argument
|
mean_field::eos::Polytrope(std::numeric_limits<double>::infinity(), 1.0),
|
||||||
);
|
std::invalid_argument);
|
||||||
|
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 1.0);
|
const mean_field::eos::Polytrope barotrope(3.0, 1.0);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.pressure_from_density(-1.0), std::domain_error);
|
CHECK_THROWS_AS(barotrope.pressure_from_density(-1.0), std::domain_error);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.enthalpy_from_density(-1.0), std::domain_error);
|
CHECK_THROWS_AS(barotrope.enthalpy_from_density(-1.0), std::domain_error);
|
||||||
|
|
||||||
|
CHECK_THROWS_AS(barotrope.enthalpy_from_pressure(-1.0), std::domain_error);
|
||||||
}
|
}
|
||||||
@@ -13,37 +13,32 @@
|
|||||||
import mean_field;
|
import mean_field;
|
||||||
import test_helpers;
|
import test_helpers;
|
||||||
|
|
||||||
namespace polytropic_barotrope_test_utils {
|
namespace polytropic_eos_test_utils {
|
||||||
template <typename Function>
|
template <typename Function>
|
||||||
double centered_derivative(
|
double centered_derivative(Function &&function, const double position,
|
||||||
Function &&function,
|
const double step) {
|
||||||
const double position,
|
|
||||||
const double step
|
|
||||||
) {
|
|
||||||
return (function(position + step) - function(position - step)) / (2.0 * step);
|
return (function(position + step) - function(position - step)) / (2.0 * step);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Integrand>
|
template <typename Integrand>
|
||||||
double integrate_cube(
|
double integrate_cube(const mfem::IntegrationRule &integrationRule,
|
||||||
const mfem::IntegrationRule &integrationRule,
|
Integrand &&integrand) {
|
||||||
Integrand &&integrand
|
|
||||||
) {
|
|
||||||
double integral = 0.0;
|
double integral = 0.0;
|
||||||
|
|
||||||
for (int pointIndex = 0; pointIndex < integrationRule.GetNPoints(); ++pointIndex) {
|
for (int pointIndex = 0; pointIndex < integrationRule.GetNPoints();
|
||||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(pointIndex);
|
++pointIndex) {
|
||||||
|
const mfem::IntegrationPoint &integrationPoint =
|
||||||
|
integrationRule.IntPoint(pointIndex);
|
||||||
|
|
||||||
integral += integrationPoint.weight * integrand(integrationPoint);
|
integral += integrationPoint.weight * integrand(integrationPoint);
|
||||||
}
|
}
|
||||||
|
|
||||||
return integral;
|
return integral;
|
||||||
}
|
}
|
||||||
} // namespace polytropic_barotrope_test_utils
|
} // namespace polytropic_eos_test_utils
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Satisfies Its Thermodynamic Identities",
|
||||||
"Polytropic Barotrope Satisfies Its Thermodynamic Identities",
|
tags::barotrope_eos_unit) {
|
||||||
tags::barotrope &tags::physics &tags::unit
|
|
||||||
) {
|
|
||||||
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
||||||
|
|
||||||
constexpr std::array<double, 4> densities{1.0e-4, 0.02, 0.37, 2.4};
|
constexpr std::array<double, 4> densities{1.0e-4, 0.02, 0.37, 2.4};
|
||||||
@@ -52,9 +47,11 @@ TEST_CASE(
|
|||||||
|
|
||||||
for (const double polytropicIndex : polytropicIndices) {
|
for (const double polytropicIndex : polytropicIndices) {
|
||||||
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(polytropicIndex, polytropicConstant);
|
const mean_field::eos::Polytrope barotrope(polytropicIndex,
|
||||||
|
polytropicConstant);
|
||||||
|
|
||||||
const double expectedEnthalpyScale = (polytropicIndex + 1.0) * polytropicConstant;
|
const double expectedEnthalpyScale =
|
||||||
|
(polytropicIndex + 1.0) * polytropicConstant;
|
||||||
|
|
||||||
CHECK(barotrope.polytropic_index() == polytropicIndex);
|
CHECK(barotrope.polytropic_index() == polytropicIndex);
|
||||||
|
|
||||||
@@ -65,35 +62,45 @@ TEST_CASE(
|
|||||||
for (const double density : densities) {
|
for (const double density : densities) {
|
||||||
CAPTURE(polytropicIndex, polytropicConstant, density);
|
CAPTURE(polytropicIndex, polytropicConstant, density);
|
||||||
|
|
||||||
const double expectedPressure = polytropicConstant * std::pow(density, 1.0 + 1.0 / polytropicIndex);
|
const double expectedPressure =
|
||||||
|
polytropicConstant * std::pow(density, 1.0 + 1.0 / polytropicIndex);
|
||||||
|
|
||||||
const double expectedEnthalpy = expectedEnthalpyScale * std::pow(density, 1.0 / polytropicIndex);
|
const double expectedEnthalpy =
|
||||||
|
expectedEnthalpyScale * std::pow(density, 1.0 / polytropicIndex);
|
||||||
|
|
||||||
const double pressureFromDensity = barotrope.pressure_from_density(density);
|
const double pressureFromDensity =
|
||||||
|
barotrope.pressure_from_density(density);
|
||||||
|
|
||||||
const double enthalpyFromDensity = barotrope.enthalpy_from_density(density);
|
const double enthalpyFromDensity =
|
||||||
|
barotrope.enthalpy_from_density(density);
|
||||||
|
|
||||||
const double recoveredDensity = barotrope.density_from_enthalpy(enthalpyFromDensity);
|
const double recoveredDensity =
|
||||||
|
barotrope.density_from_enthalpy(enthalpyFromDensity);
|
||||||
|
|
||||||
const double pressureFromEnthalpy = barotrope.pressure_from_enthalpy(enthalpyFromDensity);
|
const double pressureFromEnthalpy =
|
||||||
|
barotrope.pressure_from_enthalpy(enthalpyFromDensity);
|
||||||
|
|
||||||
CHECK_THAT(pressureFromDensity, Catch::Matchers::WithinRel(expectedPressure, 2.0e-13));
|
CHECK_THAT(pressureFromDensity,
|
||||||
|
Catch::Matchers::WithinRel(expectedPressure, 2.0e-13));
|
||||||
|
|
||||||
CHECK_THAT(enthalpyFromDensity, Catch::Matchers::WithinRel(expectedEnthalpy, 2.0e-13));
|
CHECK_THAT(enthalpyFromDensity,
|
||||||
|
Catch::Matchers::WithinRel(expectedEnthalpy, 2.0e-13));
|
||||||
|
|
||||||
CHECK_THAT(recoveredDensity, Catch::Matchers::WithinRel(density, 5.0e-13));
|
CHECK_THAT(recoveredDensity,
|
||||||
|
Catch::Matchers::WithinRel(density, 5.0e-13));
|
||||||
|
|
||||||
CHECK_THAT(pressureFromEnthalpy, Catch::Matchers::WithinRel(expectedPressure, 5.0e-13));
|
CHECK_THAT(pressureFromEnthalpy,
|
||||||
|
Catch::Matchers::WithinRel(expectedPressure, 5.0e-13));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Polytropic identity:
|
* Polytropic identity:
|
||||||
*
|
*
|
||||||
* P = rho h / (n + 1).
|
* P = rho h / (n + 1).
|
||||||
*/
|
*/
|
||||||
CHECK_THAT(
|
CHECK_THAT(pressureFromEnthalpy,
|
||||||
pressureFromEnthalpy,
|
Catch::Matchers::WithinRel(density * enthalpyFromDensity /
|
||||||
Catch::Matchers::WithinRel(density * enthalpyFromDensity / (polytropicIndex + 1.0), 5.0e-13)
|
(polytropicIndex + 1.0),
|
||||||
);
|
5.0e-13));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Polytropic identity:
|
* Polytropic identity:
|
||||||
@@ -105,8 +112,7 @@ TEST_CASE(
|
|||||||
*/
|
*/
|
||||||
CHECK(
|
CHECK(
|
||||||
barotrope.pressure_derivative_from_enthalpy(enthalpyFromDensity) ==
|
barotrope.pressure_derivative_from_enthalpy(enthalpyFromDensity) ==
|
||||||
barotrope.density_from_enthalpy(enthalpyFromDensity)
|
barotrope.density_from_enthalpy(enthalpyFromDensity));
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Since
|
* Since
|
||||||
@@ -117,19 +123,16 @@ TEST_CASE(
|
|||||||
*
|
*
|
||||||
* dP / d rho = h / n.
|
* dP / d rho = h / n.
|
||||||
*/
|
*/
|
||||||
CHECK_THAT(
|
CHECK_THAT(barotrope.pressure_derivative_from_density(density),
|
||||||
barotrope.pressure_derivative_from_density(density),
|
Catch::Matchers::WithinRel(
|
||||||
Catch::Matchers::WithinRel(enthalpyFromDensity / polytropicIndex, 5.0e-13)
|
enthalpyFromDensity / polytropicIndex, 5.0e-13));
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Pressure Derivatives Match Centered Differences",
|
||||||
"Polytropic Barotrope Pressure Derivatives Match Centered Differences",
|
tags::barotrope_eos_jacobian) {
|
||||||
tags::barotrope &tags::physics &tags::unit &tags::jacobian &tags::pressure
|
|
||||||
) {
|
|
||||||
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
||||||
|
|
||||||
constexpr std::array<double, 3> positiveValues{0.2, 0.73, 1.8};
|
constexpr std::array<double, 3> positiveValues{0.2, 0.73, 1.8};
|
||||||
@@ -137,50 +140,55 @@ TEST_CASE(
|
|||||||
constexpr double polytropicConstant = 0.61;
|
constexpr double polytropicConstant = 0.61;
|
||||||
|
|
||||||
for (const double polytropicIndex : polytropicIndices) {
|
for (const double polytropicIndex : polytropicIndices) {
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(polytropicIndex, polytropicConstant);
|
const mean_field::eos::Polytrope barotrope(polytropicIndex,
|
||||||
|
polytropicConstant);
|
||||||
|
|
||||||
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
||||||
for (const double enthalpy : positiveValues) {
|
for (const double enthalpy : positiveValues) {
|
||||||
const double step = 2.0e-6 * std::max(1.0, std::abs(enthalpy));
|
const double step = 2.0e-6 * std::max(1.0, std::abs(enthalpy));
|
||||||
|
|
||||||
const double numericalDerivative = polytropic_barotrope_test_utils::centered_derivative(
|
const double numericalDerivative =
|
||||||
|
polytropic_eos_test_utils::centered_derivative(
|
||||||
[&barotrope](const double perturbedEnthalpy) {
|
[&barotrope](const double perturbedEnthalpy) {
|
||||||
return barotrope.pressure_from_enthalpy(perturbedEnthalpy);
|
return barotrope.pressure_from_enthalpy(perturbedEnthalpy);
|
||||||
},
|
},
|
||||||
enthalpy, step
|
enthalpy, step);
|
||||||
);
|
|
||||||
|
|
||||||
const double analyticDerivative = barotrope.pressure_derivative_from_enthalpy(enthalpy);
|
const double analyticDerivative =
|
||||||
|
barotrope.pressure_derivative_from_enthalpy(enthalpy);
|
||||||
|
|
||||||
CAPTURE(polytropicIndex, enthalpy, step, numericalDerivative, analyticDerivative);
|
CAPTURE(polytropicIndex, enthalpy, step, numericalDerivative,
|
||||||
|
analyticDerivative);
|
||||||
|
|
||||||
CHECK_THAT(numericalDerivative, Catch::Matchers::WithinRel(analyticDerivative, 5.0e-8));
|
CHECK_THAT(numericalDerivative,
|
||||||
|
Catch::Matchers::WithinRel(analyticDerivative, 5.0e-8));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const double density : positiveValues) {
|
for (const double density : positiveValues) {
|
||||||
const double step = 2.0e-6 * std::max(1.0, std::abs(density));
|
const double step = 2.0e-6 * std::max(1.0, std::abs(density));
|
||||||
|
|
||||||
const double numericalDerivative = polytropic_barotrope_test_utils::centered_derivative(
|
const double numericalDerivative =
|
||||||
|
polytropic_eos_test_utils::centered_derivative(
|
||||||
[&barotrope](const double perturbedDensity) {
|
[&barotrope](const double perturbedDensity) {
|
||||||
return barotrope.pressure_from_density(perturbedDensity);
|
return barotrope.pressure_from_density(perturbedDensity);
|
||||||
},
|
},
|
||||||
density, step
|
density, step);
|
||||||
);
|
|
||||||
|
|
||||||
const double analyticDerivative = barotrope.pressure_derivative_from_density(density);
|
const double analyticDerivative =
|
||||||
|
barotrope.pressure_derivative_from_density(density);
|
||||||
|
|
||||||
CAPTURE(polytropicIndex, density, step, numericalDerivative, analyticDerivative);
|
CAPTURE(polytropicIndex, density, step, numericalDerivative,
|
||||||
|
analyticDerivative);
|
||||||
|
|
||||||
CHECK_THAT(numericalDerivative, Catch::Matchers::WithinRel(analyticDerivative, 5.0e-8));
|
CHECK_THAT(numericalDerivative,
|
||||||
|
Catch::Matchers::WithinRel(analyticDerivative, 5.0e-8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Density Derivative Matches Centered Differences",
|
||||||
"Polytropic Barotrope Density Derivative Matches Centered Differences",
|
tags::barotrope_eos_jacobian) {
|
||||||
tags::barotrope &tags::physics &tags::unit &tags::jacobian &tags::pressure
|
|
||||||
) {
|
|
||||||
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
||||||
|
|
||||||
constexpr std::array<double, 3> enthalpies{0.2, 0.73, 1.8};
|
constexpr std::array<double, 3> enthalpies{0.2, 0.73, 1.8};
|
||||||
@@ -188,40 +196,43 @@ TEST_CASE(
|
|||||||
constexpr double polytropicConstant = 0.61;
|
constexpr double polytropicConstant = 0.61;
|
||||||
|
|
||||||
for (const double polytropicIndex : polytropicIndices) {
|
for (const double polytropicIndex : polytropicIndices) {
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(polytropicIndex, polytropicConstant);
|
const mean_field::eos::Polytrope barotrope(polytropicIndex,
|
||||||
|
polytropicConstant);
|
||||||
|
|
||||||
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
||||||
for (const double enthalpy : enthalpies) {
|
for (const double enthalpy : enthalpies) {
|
||||||
const double step = 2.0e-6 * std::max(1.0, std::abs(enthalpy));
|
const double step = 2.0e-6 * std::max(1.0, std::abs(enthalpy));
|
||||||
|
|
||||||
const double numericalDerivative = polytropic_barotrope_test_utils::centered_derivative(
|
const double numericalDerivative =
|
||||||
|
polytropic_eos_test_utils::centered_derivative(
|
||||||
[&barotrope](const double perturbedEnthalpy) {
|
[&barotrope](const double perturbedEnthalpy) {
|
||||||
return barotrope.density_from_enthalpy(perturbedEnthalpy);
|
return barotrope.density_from_enthalpy(perturbedEnthalpy);
|
||||||
},
|
},
|
||||||
enthalpy, step
|
enthalpy, step);
|
||||||
);
|
|
||||||
|
|
||||||
const double analyticDerivative = barotrope.density_derivative_from_enthalpy(enthalpy);
|
const double analyticDerivative =
|
||||||
|
barotrope.density_derivative_from_enthalpy(enthalpy);
|
||||||
|
|
||||||
CAPTURE(polytropicIndex, enthalpy, step, numericalDerivative, analyticDerivative);
|
CAPTURE(polytropicIndex, enthalpy, step, numericalDerivative,
|
||||||
|
analyticDerivative);
|
||||||
|
|
||||||
CHECK_THAT(numericalDerivative, Catch::Matchers::WithinRel(analyticDerivative, 5.0e-8));
|
CHECK_THAT(numericalDerivative,
|
||||||
|
Catch::Matchers::WithinRel(analyticDerivative, 5.0e-8));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Defines Consistent Surface And Exterior Behavior",
|
||||||
"Polytropic Barotrope Defines Consistent Surface And Exterior Behavior",
|
tags::barotrope_eos_unit) {
|
||||||
tags::barotrope &tags::physics &tags::unit &tags::pressure
|
|
||||||
) {
|
|
||||||
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
constexpr std::array<double, 3> polytropicIndices{1.0, 1.5, 3.0};
|
||||||
|
|
||||||
constexpr double polytropicConstant = 0.47;
|
constexpr double polytropicConstant = 0.47;
|
||||||
constexpr double exteriorEnthalpy = -0.3;
|
constexpr double exteriorEnthalpy = -0.3;
|
||||||
|
|
||||||
for (const double polytropicIndex : polytropicIndices) {
|
for (const double polytropicIndex : polytropicIndices) {
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(polytropicIndex, polytropicConstant);
|
const mean_field::eos::Polytrope barotrope(polytropicIndex,
|
||||||
|
polytropicConstant);
|
||||||
|
|
||||||
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
DYNAMIC_SECTION("polytropic index n = " << polytropicIndex) {
|
||||||
/*
|
/*
|
||||||
@@ -246,9 +257,11 @@ TEST_CASE(
|
|||||||
|
|
||||||
CHECK(barotrope.pressure_from_enthalpy(exteriorEnthalpy) == 0.0);
|
CHECK(barotrope.pressure_from_enthalpy(exteriorEnthalpy) == 0.0);
|
||||||
|
|
||||||
CHECK(barotrope.density_derivative_from_enthalpy(exteriorEnthalpy) == 0.0);
|
CHECK(barotrope.density_derivative_from_enthalpy(exteriorEnthalpy) ==
|
||||||
|
0.0);
|
||||||
|
|
||||||
CHECK(barotrope.pressure_derivative_from_enthalpy(exteriorEnthalpy) == 0.0);
|
CHECK(barotrope.pressure_derivative_from_enthalpy(exteriorEnthalpy) ==
|
||||||
|
0.0);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* At h = 0, rho(h) has a nonzero right
|
* At h = 0, rho(h) has a nonzero right
|
||||||
@@ -257,55 +270,58 @@ TEST_CASE(
|
|||||||
const double expectedSurfaceDensityDerivative =
|
const double expectedSurfaceDensityDerivative =
|
||||||
polytropicIndex == 1.0 ? 1.0 / barotrope.enthalpy_scale() : 0.0;
|
polytropicIndex == 1.0 ? 1.0 / barotrope.enthalpy_scale() : 0.0;
|
||||||
|
|
||||||
CHECK(barotrope.density_derivative_from_enthalpy(0.0) == expectedSurfaceDensityDerivative);
|
CHECK(barotrope.density_derivative_from_enthalpy(0.0) ==
|
||||||
|
expectedSurfaceDensityDerivative);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Polytropic EOS Rejects Invalid Physical Inputs",
|
||||||
"Polytropic Barotrope Rejects Invalid Physical Inputs",
|
tags::barotrope_eos_unit) {
|
||||||
tags::barotrope &tags::physics &tags::unit &tags::pressure
|
CHECK_THROWS_AS(mean_field::eos::Polytrope(0.999, 1.0),
|
||||||
) {
|
std::invalid_argument);
|
||||||
CHECK_THROWS_AS(mean_field::physics::PolytropicBarotrope(0.999, 1.0), std::invalid_argument);
|
|
||||||
|
|
||||||
CHECK_THROWS_AS(
|
CHECK_THROWS_AS(
|
||||||
mean_field::physics::PolytropicBarotrope(std::numeric_limits<double>::infinity(), 1.0), std::invalid_argument
|
mean_field::eos::Polytrope(std::numeric_limits<double>::infinity(), 1.0),
|
||||||
);
|
std::invalid_argument);
|
||||||
|
|
||||||
CHECK_THROWS_AS(mean_field::physics::PolytropicBarotrope(3.0, 0.0), std::invalid_argument);
|
CHECK_THROWS_AS(mean_field::eos::Polytrope(3.0, 0.0), std::invalid_argument);
|
||||||
|
|
||||||
CHECK_THROWS_AS(mean_field::physics::PolytropicBarotrope(3.0, -1.0), std::invalid_argument);
|
CHECK_THROWS_AS(mean_field::eos::Polytrope(3.0, -1.0), std::invalid_argument);
|
||||||
|
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 0.75);
|
const mean_field::eos::Polytrope barotrope(3.0, 0.75);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.pressure_from_density(-0.1), std::domain_error);
|
CHECK_THROWS_AS(barotrope.pressure_from_density(-0.1), std::domain_error);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.enthalpy_from_density(-0.1), std::domain_error);
|
CHECK_THROWS_AS(barotrope.enthalpy_from_density(-0.1), std::domain_error);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.pressure_derivative_from_density(-0.1), std::domain_error);
|
CHECK_THROWS_AS(barotrope.pressure_derivative_from_density(-0.1),
|
||||||
|
std::domain_error);
|
||||||
|
|
||||||
constexpr std::array<double, 3> nonfiniteValues{
|
constexpr std::array<double, 3> nonfiniteValues{
|
||||||
std::numeric_limits<double>::infinity(), -std::numeric_limits<double>::infinity(),
|
std::numeric_limits<double>::infinity(),
|
||||||
std::numeric_limits<double>::quiet_NaN()
|
-std::numeric_limits<double>::infinity(),
|
||||||
};
|
std::numeric_limits<double>::quiet_NaN()};
|
||||||
|
|
||||||
for (const double nonfiniteValue : nonfiniteValues) {
|
for (const double nonfiniteValue : nonfiniteValues) {
|
||||||
CAPTURE(nonfiniteValue);
|
CAPTURE(nonfiniteValue);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.density_from_enthalpy(nonfiniteValue), std::domain_error);
|
CHECK_THROWS_AS(barotrope.density_from_enthalpy(nonfiniteValue),
|
||||||
|
std::domain_error);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.pressure_from_enthalpy(nonfiniteValue), std::domain_error);
|
CHECK_THROWS_AS(barotrope.pressure_from_enthalpy(nonfiniteValue),
|
||||||
|
std::domain_error);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.density_derivative_from_enthalpy(nonfiniteValue), std::domain_error);
|
CHECK_THROWS_AS(barotrope.density_derivative_from_enthalpy(nonfiniteValue),
|
||||||
|
std::domain_error);
|
||||||
|
|
||||||
CHECK_THROWS_AS(barotrope.pressure_derivative_from_enthalpy(nonfiniteValue), std::domain_error);
|
CHECK_THROWS_AS(barotrope.pressure_derivative_from_enthalpy(nonfiniteValue),
|
||||||
|
std::domain_error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Force And Pressure Integral Have Distinct Registered Forms",
|
||||||
"Pressure Force And Pressure Integral Have Distinct Registered Forms",
|
tags::barotrope_pressure_quadrature_unit) {
|
||||||
tags::barotrope &tags::pressure &tags::pressure_gradient &tags::quadrature &tags::unit
|
|
||||||
) {
|
|
||||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -320,34 +336,38 @@ TEST_CASE(
|
|||||||
*
|
*
|
||||||
* beyond the registered enthalpy operand.
|
* beyond the registered enthalpy operand.
|
||||||
*/
|
*/
|
||||||
constexpr int enthalpyOrder = mean_field::field::Enthalpy::Scalar::familyOrder;
|
constexpr int enthalpyOrder =
|
||||||
|
mean_field::field::Enthalpy::Scalar::familyOrder;
|
||||||
|
|
||||||
constexpr int pressureExtraOrder = 3 * enthalpyOrder;
|
constexpr int pressureExtraOrder = 3 * enthalpyOrder;
|
||||||
|
|
||||||
constexpr int geometryWeightOrder = 2;
|
constexpr int geometryWeightOrder = 2;
|
||||||
|
|
||||||
constexpr mean_field::quadrature::Query pressureIntegralQuery =
|
constexpr mean_field::quadrature::Query pressureIntegralQuery =
|
||||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureIntegral>(
|
EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::diagnostic, geometryWeightOrder,
|
mean_field::field::Enthalpy::Form::PressureIntegral>(
|
||||||
std::array<int, 1>{pressureExtraOrder}, mean_field::utils::DOMAINS::STELLAR,
|
mean_field::quadrature::QuadratureRole::diagnostic,
|
||||||
mean_field::quadrature::MappingKind::general
|
geometryWeightOrder, std::array<int, 1>{pressureExtraOrder},
|
||||||
);
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
|
|
||||||
constexpr mean_field::quadrature::Query pressureForceQuery =
|
constexpr mean_field::quadrature::Query pressureForceQuery =
|
||||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureForce>(
|
EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::discretization, geometryWeightOrder,
|
mean_field::field::Enthalpy::Form::PressureForce>(
|
||||||
std::array<int, 1>{pressureExtraOrder}, mean_field::utils::DOMAINS::STELLAR,
|
mean_field::quadrature::QuadratureRole::discretization,
|
||||||
mean_field::quadrature::MappingKind::general
|
geometryWeightOrder, std::array<int, 1>{pressureExtraOrder},
|
||||||
);
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::general);
|
||||||
STATIC_CHECK(mean_field::field::Enthalpy::Form::PressureIntegral::dynamicOrderCount == 1);
|
|
||||||
|
|
||||||
STATIC_CHECK(mean_field::field::Enthalpy::Form::PressureForce::dynamicOrderCount == 1);
|
|
||||||
|
|
||||||
STATIC_CHECK(
|
STATIC_CHECK(
|
||||||
mean_field::field::Enthalpy::Form::PressureIntegral::policyKey !=
|
mean_field::field::Enthalpy::Form::PressureIntegral::dynamicOrderCount ==
|
||||||
mean_field::field::Enthalpy::Form::PressureForce::policyKey
|
1);
|
||||||
);
|
|
||||||
|
STATIC_CHECK(
|
||||||
|
mean_field::field::Enthalpy::Form::PressureForce::dynamicOrderCount == 1);
|
||||||
|
|
||||||
|
STATIC_CHECK(mean_field::field::Enthalpy::Form::PressureIntegral::policyKey !=
|
||||||
|
mean_field::field::Enthalpy::Form::PressureForce::policyKey);
|
||||||
|
|
||||||
REQUIRE(pressureIntegralQuery.base_order.has_value());
|
REQUIRE(pressureIntegralQuery.base_order.has_value());
|
||||||
|
|
||||||
@@ -374,13 +394,17 @@ TEST_CASE(
|
|||||||
*/
|
*/
|
||||||
CHECK(*pressureForceQuery.base_order == 16);
|
CHECK(*pressureForceQuery.base_order == 16);
|
||||||
|
|
||||||
CHECK(pressureIntegralQuery.term == mean_field::quadrature::Term::pressure_integral);
|
CHECK(pressureIntegralQuery.term ==
|
||||||
|
mean_field::quadrature::Term::pressure_integral);
|
||||||
|
|
||||||
CHECK(pressureForceQuery.term == mean_field::quadrature::Term::pressure_force);
|
CHECK(pressureForceQuery.term ==
|
||||||
|
mean_field::quadrature::Term::pressure_force);
|
||||||
|
|
||||||
CHECK(pressureIntegralQuery.role == mean_field::quadrature::QuadratureRole::diagnostic);
|
CHECK(pressureIntegralQuery.role ==
|
||||||
|
mean_field::quadrature::QuadratureRole::diagnostic);
|
||||||
|
|
||||||
CHECK(pressureForceQuery.role == mean_field::quadrature::QuadratureRole::discretization);
|
CHECK(pressureForceQuery.role ==
|
||||||
|
mean_field::quadrature::QuadratureRole::discretization);
|
||||||
|
|
||||||
CHECK(pressureIntegralQuery.domain == mean_field::utils::DOMAINS::STELLAR);
|
CHECK(pressureIntegralQuery.domain == mean_field::utils::DOMAINS::STELLAR);
|
||||||
|
|
||||||
@@ -391,16 +415,19 @@ TEST_CASE(
|
|||||||
* controls.
|
* controls.
|
||||||
*/
|
*/
|
||||||
mean_field::quadrature::RuleSet ruleSet =
|
mean_field::quadrature::RuleSet ruleSet =
|
||||||
mean_field::quadrature::make_rule_set(mean_field::quadrature::Mode::production);
|
mean_field::quadrature::make_rule_set(
|
||||||
|
mean_field::quadrature::Mode::production);
|
||||||
|
|
||||||
ruleSet.pressure_integral.boost = 3;
|
ruleSet.pressure_integral.boost = 3;
|
||||||
ruleSet.pressure_force.boost = 5;
|
ruleSet.pressure_force.boost = 5;
|
||||||
|
|
||||||
const mean_field::quadrature::Policy policy(std::move(ruleSet));
|
const mean_field::quadrature::Policy policy(std::move(ruleSet));
|
||||||
|
|
||||||
const mean_field::quadrature::Resolution pressureIntegralResolution = policy.resolve(pressureIntegralQuery);
|
const mean_field::quadrature::Resolution pressureIntegralResolution =
|
||||||
|
policy.resolve(pressureIntegralQuery);
|
||||||
|
|
||||||
const mean_field::quadrature::Resolution pressureForceResolution = policy.resolve(pressureForceQuery);
|
const mean_field::quadrature::Resolution pressureForceResolution =
|
||||||
|
policy.resolve(pressureForceQuery);
|
||||||
|
|
||||||
CHECK(pressureIntegralResolution.base_order == 14);
|
CHECK(pressureIntegralResolution.base_order == 14);
|
||||||
|
|
||||||
@@ -415,13 +442,12 @@ TEST_CASE(
|
|||||||
CHECK(pressureForceResolution.order == 21);
|
CHECK(pressureForceResolution.order == 21);
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE(
|
TEST_CASE("Pressure Quadrature Exactly Integrates An N Three Polynomial",
|
||||||
"Pressure Quadrature Exactly Integrates An N Three Polynomial",
|
tags::barotrope_pressure_quadrature_accuracy) {
|
||||||
tags::barotrope &tags::pressure &tags::pressure_gradient &tags::quadrature &tags::accuracy
|
|
||||||
) {
|
|
||||||
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
using EnthalpyField = mean_field::field::Field<mean_field::field::Enthalpy>;
|
||||||
|
|
||||||
constexpr int enthalpyOrder = mean_field::field::Enthalpy::Scalar::familyOrder;
|
constexpr int enthalpyOrder =
|
||||||
|
mean_field::field::Enthalpy::Scalar::familyOrder;
|
||||||
|
|
||||||
constexpr int pressureExtraOrder = 3 * enthalpyOrder;
|
constexpr int pressureExtraOrder = 3 * enthalpyOrder;
|
||||||
|
|
||||||
@@ -432,23 +458,27 @@ TEST_CASE(
|
|||||||
* rho(h) = h^3,
|
* rho(h) = h^3,
|
||||||
* P(h) = h^4 / 4.
|
* P(h) = h^4 / 4.
|
||||||
*/
|
*/
|
||||||
const mean_field::physics::PolytropicBarotrope barotrope(3.0, 0.25);
|
const mean_field::eos::Polytrope barotrope(3.0, 0.25);
|
||||||
|
|
||||||
constexpr mean_field::quadrature::Query pressureIntegralQuery =
|
constexpr mean_field::quadrature::Query pressureIntegralQuery =
|
||||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureIntegral>(
|
EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::diagnostic, 0, std::array<int, 1>{pressureExtraOrder},
|
mean_field::field::Enthalpy::Form::PressureIntegral>(
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::affine
|
mean_field::quadrature::QuadratureRole::diagnostic, 0,
|
||||||
);
|
std::array<int, 1>{pressureExtraOrder},
|
||||||
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::affine);
|
||||||
|
|
||||||
constexpr mean_field::quadrature::Query pressureForceQuery =
|
constexpr mean_field::quadrature::Query pressureForceQuery =
|
||||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureForce>(
|
EnthalpyField::make_query<
|
||||||
mean_field::quadrature::QuadratureRole::discretization, 0, std::array<int, 1>{pressureExtraOrder},
|
mean_field::field::Enthalpy::Form::PressureForce>(
|
||||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::affine
|
mean_field::quadrature::QuadratureRole::discretization, 0,
|
||||||
);
|
std::array<int, 1>{pressureExtraOrder},
|
||||||
|
mean_field::utils::DOMAINS::STELLAR,
|
||||||
|
mean_field::quadrature::MappingKind::affine);
|
||||||
|
|
||||||
const mean_field::quadrature::RuleFactory ruleFactory{
|
const mean_field::quadrature::RuleFactory ruleFactory{
|
||||||
mean_field::quadrature::Policy(mean_field::quadrature::make_rule_set(mean_field::quadrature::Mode::production))
|
mean_field::quadrature::Policy(mean_field::quadrature::make_rule_set(
|
||||||
};
|
mean_field::quadrature::Mode::production))};
|
||||||
|
|
||||||
const mean_field::quadrature::MfemRule pressureIntegralRule =
|
const mean_field::quadrature::MfemRule pressureIntegralRule =
|
||||||
ruleFactory.get(pressureIntegralQuery, mfem::Geometry::CUBE);
|
ruleFactory.get(pressureIntegralQuery, mfem::Geometry::CUBE);
|
||||||
@@ -466,15 +496,17 @@ TEST_CASE(
|
|||||||
*
|
*
|
||||||
* P = x^12 y^12 z^12 / 4.
|
* P = x^12 y^12 z^12 / 4.
|
||||||
*/
|
*/
|
||||||
const double numericalPressureIntegral = polytropic_barotrope_test_utils::integrate_cube(
|
const double numericalPressureIntegral =
|
||||||
*pressureIntegralRule.integration_rule, [&barotrope](const mfem::IntegrationPoint &integrationPoint) {
|
polytropic_eos_test_utils::integrate_cube(
|
||||||
const double coordinateProduct = integrationPoint.x * integrationPoint.y * integrationPoint.z;
|
*pressureIntegralRule.integration_rule,
|
||||||
|
[&barotrope](const mfem::IntegrationPoint &integrationPoint) {
|
||||||
|
const double coordinateProduct =
|
||||||
|
integrationPoint.x * integrationPoint.y * integrationPoint.z;
|
||||||
|
|
||||||
const double enthalpy = std::pow(coordinateProduct, 3.0);
|
const double enthalpy = std::pow(coordinateProduct, 3.0);
|
||||||
|
|
||||||
return barotrope.pressure_from_enthalpy(enthalpy);
|
return barotrope.pressure_from_enthalpy(enthalpy);
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const double analyticPressureIntegral = 0.25 / std::pow(13.0, 3.0);
|
const double analyticPressureIntegral = 0.25 / std::pow(13.0, 3.0);
|
||||||
|
|
||||||
@@ -489,32 +521,38 @@ TEST_CASE(
|
|||||||
* -P div(w)
|
* -P div(w)
|
||||||
* = -x^14 y^14 z^14 / 4.
|
* = -x^14 y^14 z^14 / 4.
|
||||||
*/
|
*/
|
||||||
const double numericalPressureForceIntegral = polytropic_barotrope_test_utils::integrate_cube(
|
const double numericalPressureForceIntegral =
|
||||||
*pressureForceRule.integration_rule, [&barotrope](const mfem::IntegrationPoint &integrationPoint) {
|
polytropic_eos_test_utils::integrate_cube(
|
||||||
const double coordinateProduct = integrationPoint.x * integrationPoint.y * integrationPoint.z;
|
*pressureForceRule.integration_rule,
|
||||||
|
[&barotrope](const mfem::IntegrationPoint &integrationPoint) {
|
||||||
|
const double coordinateProduct =
|
||||||
|
integrationPoint.x * integrationPoint.y * integrationPoint.z;
|
||||||
|
|
||||||
const double enthalpy = std::pow(coordinateProduct, 3.0);
|
const double enthalpy = std::pow(coordinateProduct, 3.0);
|
||||||
|
|
||||||
const double pressure = barotrope.pressure_from_enthalpy(enthalpy);
|
const double pressure = barotrope.pressure_from_enthalpy(enthalpy);
|
||||||
|
|
||||||
const double testDivergence = integrationPoint.x * integrationPoint.x * integrationPoint.y *
|
const double testDivergence =
|
||||||
|
integrationPoint.x * integrationPoint.x * integrationPoint.y *
|
||||||
integrationPoint.y * integrationPoint.z * integrationPoint.z;
|
integrationPoint.y * integrationPoint.z * integrationPoint.z;
|
||||||
|
|
||||||
return -pressure * testDivergence;
|
return -pressure * testDivergence;
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
const double analyticPressureForceIntegral = -0.25 / std::pow(15.0, 3.0);
|
const double analyticPressureForceIntegral = -0.25 / std::pow(15.0, 3.0);
|
||||||
|
|
||||||
INFO("Pressure-integral quadrature order = " << pressureIntegralRule.resolution.order);
|
INFO("Pressure-integral quadrature order = "
|
||||||
|
<< pressureIntegralRule.resolution.order);
|
||||||
|
|
||||||
INFO("Pressure-force quadrature order = " << pressureForceRule.resolution.order);
|
INFO("Pressure-force quadrature order = "
|
||||||
|
<< pressureForceRule.resolution.order);
|
||||||
|
|
||||||
INFO("Numerical pressure integral = " << numericalPressureIntegral);
|
INFO("Numerical pressure integral = " << numericalPressureIntegral);
|
||||||
|
|
||||||
INFO("Analytic pressure integral = " << analyticPressureIntegral);
|
INFO("Analytic pressure integral = " << analyticPressureIntegral);
|
||||||
|
|
||||||
INFO("Numerical pressure-force integral = " << numericalPressureForceIntegral);
|
INFO(
|
||||||
|
"Numerical pressure-force integral = " << numericalPressureForceIntegral);
|
||||||
|
|
||||||
INFO("Analytic pressure-force integral = " << analyticPressureForceIntegral);
|
INFO("Analytic pressure-force integral = " << analyticPressureForceIntegral);
|
||||||
|
|
||||||
@@ -526,7 +564,10 @@ TEST_CASE(
|
|||||||
|
|
||||||
CHECK(pressureForceRule.resolution.order == 14);
|
CHECK(pressureForceRule.resolution.order == 14);
|
||||||
|
|
||||||
CHECK_THAT(numericalPressureIntegral, Catch::Matchers::WithinAbs(analyticPressureIntegral, 5.0e-14));
|
CHECK_THAT(numericalPressureIntegral,
|
||||||
|
Catch::Matchers::WithinAbs(analyticPressureIntegral, 5.0e-14));
|
||||||
|
|
||||||
CHECK_THAT(numericalPressureForceIntegral, Catch::Matchers::WithinAbs(analyticPressureForceIntegral, 5.0e-14));
|
CHECK_THAT(
|
||||||
|
numericalPressureForceIntegral,
|
||||||
|
Catch::Matchers::WithinAbs(analyticPressureForceIntegral, 5.0e-14));
|
||||||
}
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user