feat(field-support): added field support system, mid migration
currently the barotope and the pressure force operator are migrated to the new support system
This commit is contained in:
@@ -8,24 +8,29 @@ module;
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.barotropic_closure;
|
||||
import :field.registry;
|
||||
import :utils.domain;
|
||||
|
||||
namespace {
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
using ClosureDomain = mean_field::field::FieldDomainT<mean_field::field::Density>;
|
||||
|
||||
enum class ClosureAction { residual, density, enthalpy };
|
||||
|
||||
[[nodiscard]] bool element_is_in_closure_support(const int attribute) {
|
||||
return DomainSchema::template attribute_belongs_to<ClosureDomain>(attribute);
|
||||
}
|
||||
|
||||
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."
|
||||
);
|
||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
@@ -39,16 +44,12 @@ namespace {
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"Local vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(), "Local vector has the wrong size.");
|
||||
|
||||
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) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
@@ -57,19 +58,13 @@ namespace {
|
||||
}
|
||||
}
|
||||
|
||||
int get_eos_extra_order(
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope
|
||||
) {
|
||||
const double extraOrder =
|
||||
(barotrope.polytropic_index() - 1.0) *
|
||||
static_cast<double>(
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder
|
||||
);
|
||||
int get_eos_extra_order(const mean_field::eos::Polytrope &barotrope) {
|
||||
const double extraOrder = (barotrope.polytropic_index() - 1.0) *
|
||||
static_cast<double>(mean_field::field::Enthalpy::Scalar::familyOrder);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(extraOrder) && extraOrder >= 0.0 &&
|
||||
extraOrder <=
|
||||
static_cast<double>(std::numeric_limits<int>::max()),
|
||||
extraOrder <= static_cast<double>(std::numeric_limits<int>::max()),
|
||||
"The EOS effective polynomial order is invalid."
|
||||
);
|
||||
|
||||
@@ -78,44 +73,37 @@ namespace {
|
||||
|
||||
const mfem::IntegrationRule &get_eos_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::FiniteElement &enthalpyElement,
|
||||
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(
|
||||
densityElement.GetOrder() ==
|
||||
mean_field::field::Density::Scalar::familyOrder,
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The EOS test element does not match the "
|
||||
"registered density field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
enthalpyElement.GetOrder() ==
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The EOS trial element does not match the "
|
||||
"registered enthalpy field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EosClosureSource>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(),
|
||||
std::array<int, 1>{get_eos_extra_order(barotrope)},
|
||||
mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
const mean_field::quadrature::Query query =
|
||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EosClosureSource>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(),
|
||||
std::array<int, 1>{get_eos_extra_order(barotrope)}, 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(
|
||||
resolution.integration_rule != nullptr,
|
||||
"The quadrature policy did not return an "
|
||||
"EOS-closure integration rule."
|
||||
resolution.integration_rule != nullptr, "The quadrature policy did not return an "
|
||||
"EOS-closure integration rule."
|
||||
);
|
||||
|
||||
return *resolution.integration_rule;
|
||||
@@ -126,54 +114,44 @@ namespace {
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
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."
|
||||
f.densityFes != nullptr, "The EOS closure kernel requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"The EOS closure kernel requires the density "
|
||||
"finite-element space."
|
||||
f.enthalpyFes != nullptr, "The EOS closure kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"The EOS closure kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
f.displacementFes != nullptr, "The EOS closure kernel requires the displacement "
|
||||
"finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"The EOS closure kernel requires the displacement "
|
||||
"finite-element space."
|
||||
f.compactificationFes != nullptr, "The EOS closure kernel requires the "
|
||||
"compactification finite-element space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The EOS closure kernel requires the "
|
||||
"compactification finite-element space."
|
||||
f.compactificationCoordinate != nullptr, "The EOS closure kernel requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The EOS closure kernel requires the "
|
||||
"compactification coordinate."
|
||||
f.quadratureFactory != nullptr, "The EOS closure kernel requires the quadrature "
|
||||
"rule factory."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The EOS closure kernel requires the quadrature "
|
||||
"rule factory."
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(), "The displacement vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
);
|
||||
}
|
||||
|
||||
void apply_closure_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const ClosureAction closureAction,
|
||||
const mfem::Vector *densityInputTrue,
|
||||
const mfem::Vector *baseEnthalpyTrue,
|
||||
@@ -183,29 +161,23 @@ namespace {
|
||||
) {
|
||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||
|
||||
if (closureAction == ClosureAction::residual ||
|
||||
closureAction == ClosureAction::density) {
|
||||
if (closureAction == ClosureAction::residual || closureAction == ClosureAction::density) {
|
||||
MFEM_VERIFY(
|
||||
densityInputTrue != nullptr &&
|
||||
densityInputTrue->Size() == f.densityFes->GetTrueVSize(),
|
||||
densityInputTrue != nullptr && densityInputTrue->Size() == f.densityFes->GetTrueVSize(),
|
||||
"The density input has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (closureAction == ClosureAction::residual ||
|
||||
closureAction == ClosureAction::enthalpy) {
|
||||
if (closureAction == ClosureAction::residual || closureAction == ClosureAction::enthalpy) {
|
||||
MFEM_VERIFY(
|
||||
baseEnthalpyTrue != nullptr &&
|
||||
baseEnthalpyTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
baseEnthalpyTrue != nullptr && baseEnthalpyTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The base enthalpy has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (closureAction == ClosureAction::enthalpy) {
|
||||
MFEM_VERIFY(
|
||||
enthalpyVariationTrue != nullptr &&
|
||||
enthalpyVariationTrue->Size() ==
|
||||
f.enthalpyFes->GetTrueVSize(),
|
||||
enthalpyVariationTrue != nullptr && enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The enthalpy variation has the wrong size."
|
||||
);
|
||||
}
|
||||
@@ -224,9 +196,7 @@ namespace {
|
||||
}
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.enthalpyFes, *enthalpyVariationTrue, enthalpyVariationLocal
|
||||
);
|
||||
true_to_local(*f.enthalpyFes, *enthalpyVariationTrue, enthalpyVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
@@ -234,9 +204,7 @@ namespace {
|
||||
mfem::Vector localAction(f.densityFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
@@ -253,150 +221,105 @@ namespace {
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector enthalpyShape;
|
||||
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
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(
|
||||
transformation != nullptr,
|
||||
"The EOS closure kernel received a null "
|
||||
"element transformation."
|
||||
transformation != nullptr, "The EOS closure kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
if (!element_is_in_closure_support(transformation->Attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement =
|
||||
*f.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement =
|
||||
*f.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement =
|
||||
*f.displacementFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &compactificationElement =
|
||||
*f.compactificationFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &enthalpyElement = *f.enthalpyFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->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 *enthalpyDofTransformation =
|
||||
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
if (densityInputTrue != nullptr) {
|
||||
densityInputLocal.GetSubVector(
|
||||
densityDofs, elementDensityInput
|
||||
);
|
||||
densityInputLocal.GetSubVector(densityDofs, elementDensityInput);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
densityDofTransformation->InvTransformPrimal(
|
||||
elementDensityInput
|
||||
);
|
||||
densityDofTransformation->InvTransformPrimal(elementDensityInput);
|
||||
}
|
||||
}
|
||||
|
||||
if (baseEnthalpyTrue != nullptr) {
|
||||
baseEnthalpyLocal.GetSubVector(
|
||||
enthalpyDofs, elementBaseEnthalpy
|
||||
);
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementBaseEnthalpy
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
}
|
||||
}
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
enthalpyVariationLocal.GetSubVector(
|
||||
enthalpyDofs, elementEnthalpyVariation
|
||||
);
|
||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementEnthalpyVariation
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpyVariation);
|
||||
}
|
||||
}
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData
|
||||
displacementData = mean_field::mapping::
|
||||
ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData
|
||||
compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||
elementAction.SetSize(densityElement.GetDof());
|
||||
elementAction = 0.0;
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule = get_eos_rule(
|
||||
f, barotrope, densityElement, enthalpyElement, *transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_eos_rule(f, barotrope, densityElement, enthalpyElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0;
|
||||
quadratureIndex < integrationRule.GetNPoints();
|
||||
++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadratureIndex);
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the EOS "
|
||||
"closure kernel. Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
@@ -408,34 +331,23 @@ namespace {
|
||||
} else {
|
||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||
|
||||
const double baseEnthalpy =
|
||||
elementBaseEnthalpy * enthalpyShape;
|
||||
const double baseEnthalpy = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
if (closureAction == ClosureAction::residual) {
|
||||
const double density =
|
||||
elementDensityInput * densityShape;
|
||||
const double density = elementDensityInput * densityShape;
|
||||
|
||||
integrand =
|
||||
density -
|
||||
barotrope.density_from_enthalpy(baseEnthalpy);
|
||||
integrand = density - barotrope.density_from_enthalpy(baseEnthalpy);
|
||||
} else {
|
||||
const double enthalpyVariation =
|
||||
elementEnthalpyVariation * enthalpyShape;
|
||||
const double enthalpyVariation = elementEnthalpyVariation * enthalpyShape;
|
||||
|
||||
integrand = -barotrope.density_derivative_from_enthalpy(
|
||||
baseEnthalpy
|
||||
) *
|
||||
enthalpyVariation;
|
||||
integrand = -barotrope.density_derivative_from_enthalpy(baseEnthalpy) * enthalpyVariation;
|
||||
}
|
||||
}
|
||||
|
||||
const double weightedIntegrand =
|
||||
mappingContext.quadrature.weight * integrand;
|
||||
const double weightedIntegrand = mappingContext.quadrature.weight * integrand;
|
||||
|
||||
for (int densityDof = 0; densityDof < densityElement.GetDof();
|
||||
++densityDof) {
|
||||
elementAction(densityDof) +=
|
||||
weightedIntegrand * densityShape(densityDof);
|
||||
for (int densityDof = 0; densityDof < densityElement.GetDof(); ++densityDof) {
|
||||
elementAction(densityDof) += weightedIntegrand * densityShape(densityDof);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -454,51 +366,51 @@ namespace mean_field::operators::kernels {
|
||||
void apply_barotropic_closure(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &densityTrue,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residual
|
||||
) {
|
||||
apply_closure_action(
|
||||
f, domainMapper, barotrope, ClosureAction::residual, &densityTrue,
|
||||
&enthalpyTrue, nullptr, displacementTrue, residual
|
||||
f, domainMapper, barotrope, ClosureAction::residual, &densityTrue, &enthalpyTrue, nullptr, displacementTrue,
|
||||
residual
|
||||
);
|
||||
}
|
||||
|
||||
void apply_barotropic_closure_density_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
) {
|
||||
apply_closure_action(
|
||||
f, domainMapper, barotrope, ClosureAction::density,
|
||||
&densityVariationTrue, nullptr, nullptr, displacementTrue, action
|
||||
f, domainMapper, barotrope, ClosureAction::density, &densityVariationTrue, nullptr, nullptr,
|
||||
displacementTrue, action
|
||||
);
|
||||
}
|
||||
|
||||
void apply_barotropic_closure_enthalpy_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &action
|
||||
) {
|
||||
apply_closure_action(
|
||||
f, domainMapper, barotrope, ClosureAction::enthalpy, nullptr,
|
||||
&baseEnthalpyTrue, &enthalpyVariationTrue, displacementTrue, action
|
||||
f, domainMapper, barotrope, ClosureAction::enthalpy, nullptr, &baseEnthalpyTrue, &enthalpyVariationTrue,
|
||||
displacementTrue, action
|
||||
);
|
||||
}
|
||||
|
||||
void apply_barotropic_closure_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
@@ -511,66 +423,55 @@ namespace mean_field::operators::kernels {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the density finite-element space."
|
||||
f.densityFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the density finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the enthalpy finite-element space."
|
||||
f.enthalpyFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the enthalpy finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the displacement finite-element space."
|
||||
f.displacementFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the displacement finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the compactification finite-element space."
|
||||
f.compactificationFes != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the compactification finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the compactification coordinate."
|
||||
f.compactificationCoordinate != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"requires the quadrature-rule factory."
|
||||
f.quadratureFactory != nullptr, "The barotropic-closure displacement action "
|
||||
"requires the quadrature-rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue.Size() == f.densityFes->GetTrueVSize(),
|
||||
"The base-density vector has the wrong size."
|
||||
baseDensityTrue.Size() == f.densityFes->GetTrueVSize(), "The base-density vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
baseEnthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The base-enthalpy vector has the wrong size."
|
||||
baseEnthalpyTrue.Size() == f.enthalpyFes->GetTrueVSize(), "The base-enthalpy vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement vector has the wrong size."
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(), "The displacement vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue.Size() ==
|
||||
f.displacementFes->GetTrueVSize(),
|
||||
displacementVariationTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement-variation vector has the wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The domain-mapper dimension does not match the "
|
||||
"mesh dimension."
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The domain-mapper dimension does not match the "
|
||||
"mesh dimension."
|
||||
);
|
||||
|
||||
mfem::Vector baseDensityLocal;
|
||||
@@ -584,17 +485,12 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
true_to_local(
|
||||
*f.displacementFes, displacementVariationTrue,
|
||||
displacementVariationLocal
|
||||
);
|
||||
true_to_local(*f.displacementFes, displacementVariationTrue, displacementVariationLocal);
|
||||
|
||||
mfem::Vector localAction(f.densityFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
@@ -614,109 +510,76 @@ namespace mean_field::operators::kernels {
|
||||
mapping::VolumeMappingContext mappingContext;
|
||||
mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
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(
|
||||
transformation != nullptr,
|
||||
"The barotropic-closure displacement action "
|
||||
"received a null element transformation."
|
||||
transformation != nullptr, "The barotropic-closure displacement action "
|
||||
"received a null element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
if (!element_is_in_closure_support(transformation->Attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement =
|
||||
*f.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
|
||||
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 *densityDofTransformation =
|
||||
f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
|
||||
mfem::DofTransformation *enthalpyDofTransformation =
|
||||
f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
mfem::DofTransformation *enthalpyDofTransformation = f.enthalpyFes->GetElementDofs(elementId, enthalpyDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
baseDensityLocal.GetSubVector(densityDofs, elementBaseDensity);
|
||||
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
displacementVariationLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacementVariation
|
||||
);
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
densityDofTransformation->InvTransformPrimal(
|
||||
elementBaseDensity
|
||||
);
|
||||
densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementBaseEnthalpy
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacementVariation
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mapping::ElementDisplacementData displacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mapping::ElementDisplacementData displacementVariationData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
);
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacementVariation);
|
||||
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
@@ -724,74 +587,57 @@ namespace mean_field::operators::kernels {
|
||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||
|
||||
elementAction.SetSize(densityElement.GetDof());
|
||||
elementAction = 0.0;
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule = get_eos_rule(
|
||||
f, barotrope, densityElement, enthalpyElement, *transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_eos_rule(f, barotrope, densityElement, enthalpyElement, *transformation);
|
||||
|
||||
for (int quadraturePoint = 0;
|
||||
quadraturePoint < integrationRule.GetNPoints();
|
||||
++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadraturePoint);
|
||||
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mapping::MappingStatus::valid,
|
||||
"The base mapping is invalid while applying "
|
||||
"the barotropic-closure displacement action. "
|
||||
"Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
const mapping::MappingStatus variationStatus =
|
||||
domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, displacementVariationData, *transformation,
|
||||
integrationPoint, mappingContext, workspace,
|
||||
mappingVariation
|
||||
);
|
||||
const mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mapping::MappingStatus::valid,
|
||||
"The mapping variation is invalid while "
|
||||
"applying the barotropic-closure "
|
||||
"displacement action. Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadraturePoint
|
||||
<< ", status: " << static_cast<int>(variationStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadraturePoint << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
|
||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||
|
||||
const double densityValue = elementBaseDensity * densityShape;
|
||||
const double densityValue = elementBaseDensity * densityShape;
|
||||
|
||||
const double enthalpyValue =
|
||||
elementBaseEnthalpy * enthalpyShape;
|
||||
const double enthalpyValue = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
const double closureValue =
|
||||
densityValue -
|
||||
barotrope.density_from_enthalpy(enthalpyValue);
|
||||
const double closureValue = densityValue - barotrope.density_from_enthalpy(enthalpyValue);
|
||||
|
||||
const double geometryActionValue =
|
||||
closureValue * mappingVariation.weight_variation;
|
||||
const double geometryActionValue = closureValue * mappingVariation.weight_variation;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(closureValue) &&
|
||||
std::isfinite(geometryActionValue),
|
||||
std::isfinite(closureValue) && std::isfinite(geometryActionValue),
|
||||
"The barotropic-closure displacement action "
|
||||
"encountered a non-finite quadrature value."
|
||||
);
|
||||
@@ -808,4 +654,4 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
local_to_true(*f.densityFes, localAction, action);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
} // namespace mean_field::operators::kernels
|
||||
|
||||
@@ -0,0 +1,718 @@
|
||||
module;
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.gravity_displacement_force;
|
||||
|
||||
namespace {
|
||||
enum class GravityDisplacementForceAction { residual, 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());
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
} else {
|
||||
localVector = trueVector;
|
||||
}
|
||||
}
|
||||
|
||||
void local_to_true(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"The gravity-displacement-force local vector has the wrong size."
|
||||
);
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
} else {
|
||||
trueVector = localVector;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] int vector_dof_index(
|
||||
const mfem::Ordering::Type ordering,
|
||||
const int scalarDof,
|
||||
const int component,
|
||||
const int scalarDofCount,
|
||||
const int dimension
|
||||
) {
|
||||
if (ordering == mfem::Ordering::byNODES) {
|
||||
return scalarDof + component * scalarDofCount;
|
||||
}
|
||||
|
||||
if (ordering == mfem::Ordering::byVDIM) {
|
||||
return scalarDof * dimension + component;
|
||||
}
|
||||
|
||||
MFEM_ABORT(
|
||||
"The gravity-displacement-force test space uses an unsupported "
|
||||
"ordering."
|
||||
);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_gravity_force_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::FiniteElement &gravityGradientElement,
|
||||
const mfem::FiniteElement &displacementElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The gravity-displacement-force density element does not match "
|
||||
"the registered density field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
gravityGradientElement.GetOrder() == mean_field::field::Gravity::Flux::familyOrder + 1,
|
||||
"The gravity-displacement-force RT element does not match the "
|
||||
"registered gravity-gradient field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
||||
"The gravity-displacement-force test element does not match the "
|
||||
"registered displacement field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query =
|
||||
DisplacementField::make_query<mean_field::field::Displacement::Form::GravityForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
const mean_field::quadrature::MfemRule rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return a gravity-displacement-"
|
||||
"force integration rule."
|
||||
);
|
||||
|
||||
return *rule.integration_rule;
|
||||
}
|
||||
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
void validate_common_inputs(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &displacementTrue
|
||||
) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "The gravity-displacement-force kernel requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr, "The gravity-displacement-force kernel requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.gravityFluxFes != nullptr, "The gravity-displacement-force kernel requires the gravity-"
|
||||
"gradient finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr, "The gravity-displacement-force kernel requires the displacement "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr && f.compactificationCoordinate != nullptr,
|
||||
"The gravity-displacement-force kernel requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr, "The gravity-displacement-force kernel requires the quadrature "
|
||||
"rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The gravity-displacement-force displacement vector has the "
|
||||
"wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The gravity-displacement-force mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||
"The gravity-displacement-force displacement dimension does not "
|
||||
"match the mesh dimension."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
displacementTrue, "The gravity-displacement-force displacement contains a "
|
||||
"non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_density(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::Vector &density,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
||||
validate_finite_vector(density, message);
|
||||
}
|
||||
|
||||
void validate_gravity_gradient(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::Vector &gravityGradient,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(gravityGradient.Size() == f.gravityFluxFes->GetTrueVSize(), message);
|
||||
|
||||
validate_finite_vector(gravityGradient, message);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const GravityDisplacementForceAction requestedAction,
|
||||
const mfem::Vector *baseDensityTrue,
|
||||
const mfem::Vector *densityVariationTrue,
|
||||
const mfem::Vector *baseGravityGradientTrue,
|
||||
const mfem::Vector *gravityGradientVariationTrue,
|
||||
const mfem::Vector *displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||
|
||||
const bool needsBaseDensity = requestedAction == GravityDisplacementForceAction::residual ||
|
||||
requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
||||
requestedAction == GravityDisplacementForceAction::displacement ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDensityVariation = requestedAction == GravityDisplacementForceAction::density ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsBaseGravityGradient = requestedAction == GravityDisplacementForceAction::residual ||
|
||||
requestedAction == GravityDisplacementForceAction::density ||
|
||||
requestedAction == GravityDisplacementForceAction::displacement ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsGravityGradientVariation = requestedAction == GravityDisplacementForceAction::gravityGradient ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDisplacementVariation = requestedAction == GravityDisplacementForceAction::displacement ||
|
||||
requestedAction == GravityDisplacementForceAction::complete;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue != nullptr, "The gravity-displacement-force action requires a base "
|
||||
"density."
|
||||
);
|
||||
|
||||
validate_density(f, *baseDensityTrue, "The gravity-displacement-force base density is invalid.");
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
MFEM_VERIFY(
|
||||
densityVariationTrue != nullptr, "The gravity-displacement-force action requires a density "
|
||||
"variation."
|
||||
);
|
||||
|
||||
validate_density(
|
||||
f, *densityVariationTrue,
|
||||
"The gravity-displacement-force density variation is "
|
||||
"invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
MFEM_VERIFY(
|
||||
baseGravityGradientTrue != nullptr, "The gravity-displacement-force action requires a base "
|
||||
"gravity gradient."
|
||||
);
|
||||
|
||||
validate_gravity_gradient(
|
||||
f, *baseGravityGradientTrue,
|
||||
"The gravity-displacement-force base gravity gradient is "
|
||||
"invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
MFEM_VERIFY(
|
||||
gravityGradientVariationTrue != nullptr, "The gravity-displacement-force action requires a gravity-"
|
||||
"gradient variation."
|
||||
);
|
||||
|
||||
validate_gravity_gradient(
|
||||
f, *gravityGradientVariationTrue,
|
||||
"The gravity-displacement-force gravity-gradient variation "
|
||||
"is invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue != nullptr &&
|
||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The gravity-displacement-force displacement variation is "
|
||||
"invalid."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
*displacementVariationTrue, "The gravity-displacement-force displacement variation "
|
||||
"contains a non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
mfem::Vector baseDensityLocal;
|
||||
mfem::Vector densityVariationLocal;
|
||||
mfem::Vector baseGravityGradientLocal;
|
||||
mfem::Vector gravityGradientVariationLocal;
|
||||
mfem::Vector displacementLocal;
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
true_to_local(*f.densityFes, *baseDensityTrue, baseDensityLocal);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
true_to_local(*f.densityFes, *densityVariationTrue, densityVariationLocal);
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
true_to_local(*f.gravityFluxFes, *baseGravityGradientTrue, baseGravityGradientLocal);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
true_to_local(*f.gravityFluxFes, *gravityGradientVariationTrue, gravityGradientVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
||||
}
|
||||
|
||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> gravityGradientDofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
|
||||
mfem::Vector elementBaseDensity;
|
||||
mfem::Vector elementDensityVariation;
|
||||
mfem::Vector elementBaseGravityGradient;
|
||||
mfem::Vector elementGravityGradientVariation;
|
||||
mfem::Vector elementDisplacement;
|
||||
mfem::Vector elementDisplacementVariation;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector elementAction;
|
||||
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector displacementShape;
|
||||
mfem::DenseMatrix gravityGradientShape;
|
||||
|
||||
mfem::Vector baseGravityReferenceValue;
|
||||
mfem::Vector gravityVariationReferenceValue;
|
||||
mfem::Vector mappedBaseGravity;
|
||||
mfem::Vector mappedGravityVariation;
|
||||
mfem::Vector mappedGeometryVariation;
|
||||
mfem::Vector forceValue;
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const int dimension = f.mesh->Dimension();
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr, "The gravity-displacement-force kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &gravityGradientElement = *f.gravityFluxFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
|
||||
mfem::DofTransformation *gravityGradientDofTransformation =
|
||||
f.gravityFluxFes->GetElementVDofs(elementId, gravityGradientDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityLocal.GetSubVector(densityDofs, elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationLocal.GetSubVector(densityDofs, elementDensityVariation);
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
baseGravityGradientLocal.GetSubVector(gravityGradientDofs, elementBaseGravityGradient);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
gravityGradientVariationLocal.GetSubVector(gravityGradientDofs, elementGravityGradientVariation);
|
||||
}
|
||||
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
if (needsBaseDensity) {
|
||||
densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityDofTransformation->InvTransformPrimal(elementDensityVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (gravityGradientDofTransformation != nullptr) {
|
||||
if (needsBaseGravityGradient) {
|
||||
gravityGradientDofTransformation->InvTransformPrimal(elementBaseGravityGradient);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
gravityGradientDofTransformation->InvTransformPrimal(elementGravityGradientVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
||||
"The gravity-displacement-force element displacement vector "
|
||||
"has the wrong size."
|
||||
);
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
displacementShape.SetSize(scalarDisplacementDofCount);
|
||||
gravityGradientShape.SetSize(gravityGradientElement.GetDof(), dimension);
|
||||
|
||||
baseGravityReferenceValue.SetSize(dimension);
|
||||
gravityVariationReferenceValue.SetSize(dimension);
|
||||
mappedBaseGravity.SetSize(dimension);
|
||||
mappedGravityVariation.SetSize(dimension);
|
||||
mappedGeometryVariation.SetSize(dimension);
|
||||
forceValue.SetSize(dimension);
|
||||
|
||||
elementAction.SetSize(displacementDofs.Size());
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_gravity_force_rule(f, densityElement, gravityGradientElement, displacementElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the gravity-displacement-"
|
||||
"force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping variation failed in the gravity-"
|
||||
"displacement-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
}
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
|
||||
displacementElement.CalcShape(integrationPoint, displacementShape);
|
||||
|
||||
gravityGradientElement.CalcVShape(*transformation, gravityGradientShape);
|
||||
|
||||
double baseDensityValue = 0.0;
|
||||
double densityVariationValue = 0.0;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityValue = elementBaseDensity * densityShape;
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationValue = elementDensityVariation * densityShape;
|
||||
}
|
||||
|
||||
if (needsBaseGravityGradient) {
|
||||
gravityGradientShape.MultTranspose(elementBaseGravityGradient, baseGravityReferenceValue);
|
||||
|
||||
mappingContext.mapping.mapping_jacobian.Mult(baseGravityReferenceValue, mappedBaseGravity);
|
||||
} else {
|
||||
mappedBaseGravity = 0.0;
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
gravityGradientShape.MultTranspose(elementGravityGradientVariation, gravityVariationReferenceValue);
|
||||
|
||||
mappingContext.mapping.mapping_jacobian.Mult(
|
||||
gravityVariationReferenceValue, mappedGravityVariation
|
||||
);
|
||||
} else {
|
||||
mappedGravityVariation = 0.0;
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
mappingVariation.mapping.mapping_jacobian_variation.Mult(
|
||||
baseGravityReferenceValue, mappedGeometryVariation
|
||||
);
|
||||
} else {
|
||||
mappedGeometryVariation = 0.0;
|
||||
}
|
||||
|
||||
forceValue = 0.0;
|
||||
|
||||
if (requestedAction == GravityDisplacementForceAction::residual) {
|
||||
forceValue.Add(baseDensityValue, mappedBaseGravity);
|
||||
} else {
|
||||
if (needsDensityVariation) {
|
||||
forceValue.Add(densityVariationValue, mappedBaseGravity);
|
||||
}
|
||||
|
||||
if (needsGravityGradientVariation) {
|
||||
forceValue.Add(baseDensityValue, mappedGravityVariation);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
forceValue.Add(baseDensityValue, mappedGeometryVariation);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* If g_ref is the RT pullback, then
|
||||
*
|
||||
* g_phys = J_map g_ref / det(J_map),
|
||||
* dV_phys = det(J_map) dV_ref.
|
||||
*
|
||||
* The determinant cancels exactly. Consequently the base
|
||||
* integrand uses J_map g_ref and its geometry derivative uses
|
||||
* delta(J_map) g_ref. This is algebraically identical to
|
||||
* differentiating the Piola map and physical volume weight,
|
||||
* but avoids a numerically pointless cancellation.
|
||||
*/
|
||||
const double referenceWeight = integrationPoint.weight * transformation->Weight();
|
||||
|
||||
forceValue *= referenceWeight;
|
||||
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
||||
for (int component = 0; component < dimension; ++component) {
|
||||
const int vectorDof = vector_dof_index(
|
||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
||||
);
|
||||
|
||||
const double contribution = displacementShape(scalarDof) * forceValue(component);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(contribution), "The gravity-displacement-force kernel "
|
||||
"encountered a non-finite contribution."
|
||||
);
|
||||
|
||||
elementAction(vectorDof) += contribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->TransformDual(elementAction);
|
||||
}
|
||||
|
||||
localAction.AddElementVector(displacementDofs, elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*f.displacementFes, localAction, actionTrue);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_gravity_displacement_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &densityTrue,
|
||||
const mfem::Vector &gravityGradientTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::residual, &densityTrue, nullptr, &gravityGradientTrue,
|
||||
nullptr, nullptr, displacementTrue, residualTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_density_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &baseGravityGradientTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::density, nullptr, &densityVariationTrue,
|
||||
&baseGravityGradientTrue, nullptr, nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_gradient_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &gravityGradientVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::gravityGradient, &baseDensityTrue, nullptr, nullptr,
|
||||
&gravityGradientVariationTrue, nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &baseGravityGradientTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::displacement, &baseDensityTrue, nullptr,
|
||||
&baseGravityGradientTrue, nullptr, &displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_gravity_displacement_force_complete_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &baseGravityGradientTrue,
|
||||
const mfem::Vector &gravityGradientVariationTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_gravity_displacement_force_action(
|
||||
f, domainMapper, GravityDisplacementForceAction::complete, &baseDensityTrue, &densityVariationTrue,
|
||||
&baseGravityGradientTrue, &gravityGradientVariationTrue, &displacementVariationTrue, displacementTrue,
|
||||
actionTrue
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
File diff suppressed because it is too large
Load Diff
@@ -16,15 +16,11 @@ namespace {
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"True vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(trueVector.Size() == finiteElementSpace.GetTrueVSize(), "True vector has the wrong size.");
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
@@ -38,17 +34,13 @@ namespace {
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"Local vector has the wrong size."
|
||||
);
|
||||
MFEM_VERIFY(localVector.Size() == finiteElementSpace.GetVSize(), "Local vector has the wrong size.");
|
||||
|
||||
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) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
@@ -61,9 +53,7 @@ namespace {
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &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(
|
||||
f.enthalpyFes != nullptr, "The hydrostatic kernel requires the "
|
||||
@@ -71,9 +61,8 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.gravityPotentialFes != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"gravity-potential finite-element space."
|
||||
f.gravityPotentialFes != nullptr, "The hydrostatic kernel requires the "
|
||||
"gravity-potential finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
@@ -82,33 +71,28 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"compactification finite-element space."
|
||||
f.compactificationFes != nullptr, "The hydrostatic kernel requires the "
|
||||
"compactification finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"compactification coordinate."
|
||||
f.compactificationCoordinate != nullptr, "The hydrostatic kernel requires the "
|
||||
"compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The hydrostatic kernel requires the "
|
||||
"quadrature-rule factory."
|
||||
f.quadratureFactory != nullptr, "The hydrostatic kernel requires the "
|
||||
"quadrature-rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.mesh->Dimension() == 3,
|
||||
"The rigid-rotation hydrostatic kernel "
|
||||
"currently requires a three-dimensional mesh."
|
||||
f.mesh->Dimension() == 3, "The rigid-rotation hydrostatic kernel "
|
||||
"currently requires a three-dimensional mesh."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(), "The domain-mapper dimension does not match "
|
||||
"the mesh dimension."
|
||||
);
|
||||
}
|
||||
|
||||
@@ -118,69 +102,51 @@ namespace {
|
||||
const mfem::FiniteElement &potentialElement,
|
||||
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(
|
||||
enthalpyElement.GetOrder() ==
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The hydrostatic test element does not match "
|
||||
"the registered enthalpy field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
potentialElement.GetOrder() ==
|
||||
mean_field::field::Gravity::Potential::familyOrder,
|
||||
potentialElement.GetOrder() == mean_field::field::Gravity::Potential::familyOrder,
|
||||
"The hydrostatic potential element does not "
|
||||
"match the registered gravity-potential field."
|
||||
);
|
||||
|
||||
const auto enthalpyQuery = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::EquilibriumEnthalpy>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
const auto enthalpyQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumEnthalpy>(
|
||||
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>(
|
||||
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>(
|
||||
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>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), std::array<int, 1>{2},
|
||||
mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
const auto rotationQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumRotation>(
|
||||
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>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(), {}, mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
const auto constantQuery = EnthalpyField::make_query<mean_field::field::Enthalpy::Form::EquilibriumConstant>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(), {},
|
||||
mean_field::utils::DOMAINS::STELLAR, mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
|
||||
int integrationOrder = 0;
|
||||
|
||||
const auto update_order = [&f, &transformation, &integrationOrder](
|
||||
const mean_field::quadrature::Query &query
|
||||
) {
|
||||
const auto rule = f.quadratureFactory->get(
|
||||
query, transformation.GetGeometryType()
|
||||
);
|
||||
const auto update_order = [&f, &transformation, &integrationOrder](const mean_field::quadrature::Query &query) {
|
||||
const auto rule = f.quadratureFactory->get(query, transformation.GetGeometryType());
|
||||
|
||||
MFEM_VERIFY(
|
||||
rule.integration_rule != nullptr,
|
||||
"The quadrature policy did not return "
|
||||
"a hydrostatic-equilibrium rule."
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return "
|
||||
"a hydrostatic-equilibrium rule."
|
||||
);
|
||||
|
||||
integrationOrder =
|
||||
std::max(integrationOrder, rule.resolution.order);
|
||||
integrationOrder = std::max(integrationOrder, rule.resolution.order);
|
||||
};
|
||||
|
||||
update_order(enthalpyQuery);
|
||||
@@ -188,9 +154,7 @@ namespace {
|
||||
update_order(rotationQuery);
|
||||
update_order(constantQuery);
|
||||
|
||||
return mfem::IntRules.Get(
|
||||
transformation.GetGeometryType(), integrationOrder
|
||||
);
|
||||
return mfem::IntRules.Get(transformation.GetGeometryType(), integrationOrder);
|
||||
}
|
||||
|
||||
struct HydrostaticAssemblyRequest {
|
||||
@@ -219,81 +183,64 @@ namespace {
|
||||
validate_fem(f, domainMapper);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The hydrostatic displacement vector has "
|
||||
"the wrong size."
|
||||
displacementTrue.Size() == f.displacementFes->GetTrueVSize(), "The hydrostatic displacement vector has "
|
||||
"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) {
|
||||
MFEM_VERIFY(
|
||||
request.rotation != nullptr,
|
||||
"The hydrostatic residual or geometry "
|
||||
"action requires the rotation model."
|
||||
request.rotation != nullptr, "The hydrostatic residual or geometry "
|
||||
"action requires the rotation model."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
request.baseEnthalpyTrue != nullptr,
|
||||
"The hydrostatic residual or geometry "
|
||||
"action requires the base enthalpy."
|
||||
request.baseEnthalpyTrue != nullptr, "The hydrostatic residual or geometry "
|
||||
"action requires the base enthalpy."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
request.basePotentialTrue != nullptr,
|
||||
"The hydrostatic residual or geometry "
|
||||
"action requires the base potential."
|
||||
request.basePotentialTrue != nullptr, "The hydrostatic residual or geometry "
|
||||
"action requires the base potential."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.baseEnthalpyTrue->Size() ==
|
||||
f.enthalpyFes->GetTrueVSize(),
|
||||
request.baseEnthalpyTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The base enthalpy vector has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.basePotentialTrue->Size() ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
request.basePotentialTrue->Size() == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"The base potential vector has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.enthalpyVariationTrue->Size() ==
|
||||
f.enthalpyFes->GetTrueVSize(),
|
||||
request.enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The enthalpy variation has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.potentialVariationTrue->Size() ==
|
||||
f.gravityPotentialFes->GetTrueVSize(),
|
||||
request.potentialVariationTrue->Size() == f.gravityPotentialFes->GetTrueVSize(),
|
||||
"The potential variation has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
MFEM_VERIFY(
|
||||
request.displacementVariationTrue->Size() ==
|
||||
f.displacementFes->GetTrueVSize(),
|
||||
request.displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The displacement variation has the wrong size."
|
||||
);
|
||||
}
|
||||
@@ -308,46 +255,30 @@ namespace {
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.enthalpyFes, *request.baseEnthalpyTrue, baseEnthalpyLocal
|
||||
);
|
||||
true_to_local(*f.enthalpyFes, *request.baseEnthalpyTrue, baseEnthalpyLocal);
|
||||
}
|
||||
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.gravityPotentialFes, *request.basePotentialTrue,
|
||||
basePotentialLocal
|
||||
);
|
||||
true_to_local(*f.gravityPotentialFes, *request.basePotentialTrue, basePotentialLocal);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.enthalpyFes, *request.enthalpyVariationTrue,
|
||||
enthalpyVariationLocal
|
||||
);
|
||||
true_to_local(*f.enthalpyFes, *request.enthalpyVariationTrue, enthalpyVariationLocal);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
true_to_local(
|
||||
*f.gravityPotentialFes, *request.potentialVariationTrue,
|
||||
potentialVariationLocal
|
||||
);
|
||||
true_to_local(*f.gravityPotentialFes, *request.potentialVariationTrue, potentialVariationLocal);
|
||||
}
|
||||
|
||||
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());
|
||||
|
||||
localResult = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
mfem::Array<int> potentialDofs;
|
||||
@@ -369,33 +300,26 @@ namespace {
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
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(
|
||||
transformation != nullptr,
|
||||
"The hydrostatic kernel received a null "
|
||||
"element transformation."
|
||||
transformation != nullptr, "The hydrostatic kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
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 =
|
||||
f.gravityPotentialFes->GetElementDofs(elementId, potentialDofs);
|
||||
@@ -404,119 +328,82 @@ namespace {
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
baseEnthalpyLocal.GetSubVector(
|
||||
enthalpyDofs, elementBaseEnthalpy
|
||||
);
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
}
|
||||
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
basePotentialLocal.GetSubVector(
|
||||
potentialDofs, elementBasePotential
|
||||
);
|
||||
basePotentialLocal.GetSubVector(potentialDofs, elementBasePotential);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
enthalpyVariationLocal.GetSubVector(
|
||||
enthalpyDofs, elementEnthalpyVariation
|
||||
);
|
||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
potentialVariationLocal.GetSubVector(
|
||||
potentialDofs, elementPotentialVariation
|
||||
);
|
||||
potentialVariationLocal.GetSubVector(potentialDofs, elementPotentialVariation);
|
||||
}
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
displacementVariationLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacementVariation
|
||||
);
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
if (request.baseEnthalpyTrue != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementBaseEnthalpy
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
}
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(
|
||||
elementEnthalpyVariation
|
||||
);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpyVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (potentialDofTransformation != nullptr) {
|
||||
if (request.basePotentialTrue != nullptr) {
|
||||
potentialDofTransformation->InvTransformPrimal(
|
||||
elementBasePotential
|
||||
);
|
||||
potentialDofTransformation->InvTransformPrimal(elementBasePotential);
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
potentialDofTransformation->InvTransformPrimal(
|
||||
elementPotentialVariation
|
||||
);
|
||||
potentialDofTransformation->InvTransformPrimal(elementPotentialVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacementVariation
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData
|
||||
displacementData = mean_field::mapping::
|
||||
ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData
|
||||
compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
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) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::
|
||||
ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -528,32 +415,25 @@ namespace {
|
||||
|
||||
potentialShape.SetSize(potentialElement.GetDof());
|
||||
|
||||
const mfem::IntegrationRule &integrationRule = get_hydrostatic_rule(
|
||||
f, enthalpyElement, potentialElement, *transformation
|
||||
);
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_hydrostatic_rule(f, enthalpyElement, potentialElement, *transformation);
|
||||
|
||||
for (int quadraturePoint = 0;
|
||||
quadraturePoint < integrationRule.GetNPoints();
|
||||
++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadraturePoint);
|
||||
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadraturePoint);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"The base mapping is invalid in the "
|
||||
"hydrostatic kernel. Element: "
|
||||
<< elementId
|
||||
<< ", quadrature point: " << quadraturePoint
|
||||
<< elementId << ", quadrature point: " << quadraturePoint
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
@@ -564,27 +444,18 @@ namespace {
|
||||
double baseIntegrand = 0.0;
|
||||
|
||||
if (requiresBaseState) {
|
||||
const double enthalpyValue =
|
||||
elementBaseEnthalpy * enthalpyShape;
|
||||
const double enthalpyValue = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
const double potentialValue =
|
||||
elementBasePotential * potentialShape;
|
||||
const double potentialValue = elementBasePotential * potentialShape;
|
||||
|
||||
const double rotationPotential =
|
||||
request.rotation->potential(
|
||||
mappingContext.mapping.physical_position
|
||||
);
|
||||
request.rotation->potential(mappingContext.mapping.physical_position);
|
||||
|
||||
baseIntegrand = enthalpyValue + potentialValue -
|
||||
rotationPotential -
|
||||
request.bernoulliConstant;
|
||||
baseIntegrand = enthalpyValue + potentialValue - rotationPotential - request.bernoulliConstant;
|
||||
}
|
||||
|
||||
if (request.buildResidual) {
|
||||
elementResult.Add(
|
||||
mappingContext.quadrature.weight * baseIntegrand,
|
||||
enthalpyShape
|
||||
);
|
||||
elementResult.Add(mappingContext.quadrature.weight * baseIntegrand, enthalpyShape);
|
||||
|
||||
continue;
|
||||
}
|
||||
@@ -592,45 +463,35 @@ namespace {
|
||||
double materialVariation = -request.constantVariation;
|
||||
|
||||
if (request.enthalpyVariationTrue != nullptr) {
|
||||
materialVariation +=
|
||||
elementEnthalpyVariation * enthalpyShape;
|
||||
materialVariation += elementEnthalpyVariation * enthalpyShape;
|
||||
}
|
||||
|
||||
if (request.potentialVariationTrue != nullptr) {
|
||||
materialVariation +=
|
||||
elementPotentialVariation * potentialShape;
|
||||
materialVariation += elementPotentialVariation * potentialShape;
|
||||
}
|
||||
|
||||
double weightedVariation =
|
||||
mappingContext.quadrature.weight * materialVariation;
|
||||
double weightedVariation = mappingContext.quadrature.weight * materialVariation;
|
||||
|
||||
if (request.displacementVariationTrue != nullptr) {
|
||||
mean_field::mapping::VolumeMappingVariation
|
||||
mappingVariation;
|
||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const mean_field::mapping::MappingStatus variationStatus =
|
||||
domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData,
|
||||
*transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus ==
|
||||
mean_field::mapping::MappingStatus::valid,
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"The mapping variation is invalid "
|
||||
"in the hydrostatic kernel."
|
||||
);
|
||||
|
||||
const double rotationVariation =
|
||||
request.rotation->potential_directional_derivative(
|
||||
mappingContext.mapping.physical_position,
|
||||
mappingVariation.mapping.physical_position_variation
|
||||
);
|
||||
const double rotationVariation = request.rotation->potential_directional_derivative(
|
||||
mappingContext.mapping.physical_position, mappingVariation.mapping.physical_position_variation
|
||||
);
|
||||
|
||||
weightedVariation +=
|
||||
baseIntegrand * mappingVariation.weight_variation -
|
||||
rotationVariation * mappingContext.quadrature.weight;
|
||||
weightedVariation += baseIntegrand * mappingVariation.weight_variation -
|
||||
rotationVariation * mappingContext.quadrature.weight;
|
||||
}
|
||||
|
||||
elementResult.Add(weightedVariation, enthalpyShape);
|
||||
@@ -666,9 +527,7 @@ namespace mean_field::operators::kernels {
|
||||
request.bernoulliConstant = bernoulliConstant;
|
||||
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(
|
||||
@@ -682,9 +541,7 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
request.enthalpyVariationTrue = &enthalpyVariationTrue;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, displacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_potential_action(
|
||||
@@ -698,9 +555,7 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
request.potentialVariationTrue = &potentialVariationTrue;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, displacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_constant_action(
|
||||
@@ -714,9 +569,7 @@ namespace mean_field::operators::kernels {
|
||||
|
||||
request.constantVariation = constantVariation;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, displacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, displacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_displacement_action(
|
||||
@@ -738,9 +591,7 @@ namespace mean_field::operators::kernels {
|
||||
request.displacementVariationTrue = &displacementVariationTrue;
|
||||
request.bernoulliConstant = baseBernoulliConstant;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, baseDisplacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request, action);
|
||||
}
|
||||
|
||||
void apply_hydrostatic_equilibrium_action(
|
||||
@@ -768,8 +619,6 @@ namespace mean_field::operators::kernels {
|
||||
request.bernoulliConstant = baseBernoulliConstant;
|
||||
request.constantVariation = constantVariation;
|
||||
|
||||
assemble_hydrostatic_form(
|
||||
f, domainMapper, baseDisplacementTrue, request, action
|
||||
);
|
||||
assemble_hydrostatic_form(f, domainMapper, baseDisplacementTrue, request, action);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
@@ -3,6 +3,7 @@ module;
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <limits>
|
||||
#include <optional>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
@@ -11,20 +12,20 @@ module mean_field;
|
||||
import :operators.kernels.pressure_force;
|
||||
|
||||
namespace {
|
||||
enum class PressureForceAction { residual, enthalpy, displacement };
|
||||
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(),
|
||||
"The pressure-force true vector has the wrong size."
|
||||
trueVector.Size() == finiteElementSpace.GetTrueVSize(), "The pressure-force true vector has the wrong size."
|
||||
);
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation =
|
||||
finiteElementSpace.GetProlongationMatrix();
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
@@ -39,15 +40,13 @@ namespace {
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"The pressure-force local vector has the wrong size."
|
||||
localVector.Size() == finiteElementSpace.GetVSize(), "The pressure-force local vector has the wrong size."
|
||||
);
|
||||
|
||||
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) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
@@ -68,15 +67,14 @@ namespace {
|
||||
}
|
||||
|
||||
if (ordering == mfem::Ordering::byVDIM) {
|
||||
return component + scalarDof * dimension;
|
||||
return scalarDof * dimension + component;
|
||||
}
|
||||
|
||||
MFEM_ABORT("The displacement space uses an unsupported ordering.");
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] int get_pressure_extra_order(
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope
|
||||
) {
|
||||
[[nodiscard]] int get_pressure_extra_order(const mean_field::eos::Polytrope &barotrope) {
|
||||
/*
|
||||
* Pressure has the enthalpy dependence
|
||||
*
|
||||
@@ -87,15 +85,11 @@ namespace {
|
||||
* contribution is therefore n times that order.
|
||||
*/
|
||||
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(
|
||||
std::isfinite(extraOrder) && extraOrder >= 0.0 &&
|
||||
extraOrder <=
|
||||
static_cast<double>(std::numeric_limits<int>::max()),
|
||||
extraOrder <= static_cast<double>(std::numeric_limits<int>::max()),
|
||||
"The pressure EOS effective polynomial order is invalid."
|
||||
);
|
||||
|
||||
@@ -104,44 +98,37 @@ namespace {
|
||||
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_pressure_force_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::physics::PolytropicBarotrope &barotrope,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const mfem::FiniteElement &enthalpyElement,
|
||||
const mfem::FiniteElement &displacementElement,
|
||||
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(
|
||||
enthalpyElement.GetOrder() ==
|
||||
mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
enthalpyElement.GetOrder() == mean_field::field::Enthalpy::Scalar::familyOrder,
|
||||
"The pressure-force enthalpy element does not match the "
|
||||
"registered enthalpy field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementElement.GetOrder() ==
|
||||
mean_field::field::Displacement::Vector::familyOrder,
|
||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
||||
"The pressure-force test element does not match the "
|
||||
"registered displacement field."
|
||||
);
|
||||
|
||||
const mean_field::quadrature::Query query = EnthalpyField::make_query<
|
||||
mean_field::field::Enthalpy::Form::PressureForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization,
|
||||
transformation.OrderW(),
|
||||
std::array<int, 1>{get_pressure_extra_order(barotrope)},
|
||||
mean_field::utils::DOMAINS::STELLAR,
|
||||
mean_field::quadrature::MappingKind::general
|
||||
);
|
||||
const mean_field::quadrature::Query query =
|
||||
EnthalpyField::make_query<mean_field::field::Enthalpy::Form::PressureForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, transformation.OrderW(),
|
||||
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(
|
||||
rule.integration_rule != nullptr,
|
||||
"The quadrature policy did not return a pressure-force "
|
||||
"integration rule."
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return a pressure-force "
|
||||
"integration rule."
|
||||
);
|
||||
|
||||
return *rule.integration_rule;
|
||||
@@ -153,38 +140,31 @@ namespace {
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
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."
|
||||
f.enthalpyFes != nullptr, "The pressure-force kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.enthalpyFes != nullptr,
|
||||
"The pressure-force kernel requires the enthalpy "
|
||||
"finite-element space."
|
||||
f.displacementFes != nullptr, "The pressure-force kernel requires the displacement "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes != nullptr,
|
||||
"The pressure-force kernel requires the displacement "
|
||||
"finite-element space."
|
||||
f.compactificationFes != nullptr, "The pressure-force kernel requires the compactification "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationFes != nullptr,
|
||||
"The pressure-force kernel requires the compactification "
|
||||
"finite-element space."
|
||||
f.compactificationCoordinate != nullptr, "The pressure-force kernel requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.compactificationCoordinate != nullptr,
|
||||
"The pressure-force kernel requires the compactification "
|
||||
"coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr,
|
||||
"The pressure-force kernel requires the quadrature "
|
||||
"rule factory."
|
||||
f.quadratureFactory != nullptr, "The pressure-force kernel requires the quadrature "
|
||||
"rule factory."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
@@ -204,73 +184,105 @@ namespace {
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||
"The displacement vector dimension does not match the "
|
||||
"mesh dimension."
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(), "The displacement vector dimension does not match the "
|
||||
"mesh dimension."
|
||||
);
|
||||
|
||||
/*
|
||||
* ElementDisplacementDataFromElementVDofs currently consumes the
|
||||
* registered byNODES layout. Keep this explicit so a future
|
||||
* registry change fails immediately rather than silently
|
||||
* corrupting the geometry.
|
||||
*/
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetOrdering() == mfem::Ordering::byNODES,
|
||||
"The pressure-force kernel requires the registered byNODES "
|
||||
"displacement ordering."
|
||||
);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_pressure_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::PolytropicBarotrope &barotrope,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
void apply_pressure_force_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mean_field::eos::Polytrope &barotrope,
|
||||
const PressureForceAction pressureForceAction,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector *enthalpyVariationTrue,
|
||||
const mfem::Vector *displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
validate_inputs(f, domainMapper, enthalpyTrue, displacementTrue);
|
||||
validate_inputs(f, domainMapper, baseEnthalpyTrue, displacementTrue);
|
||||
|
||||
mfem::Vector enthalpyLocal;
|
||||
if (pressureForceAction == PressureForceAction::enthalpy) {
|
||||
MFEM_VERIFY(
|
||||
enthalpyVariationTrue != nullptr && enthalpyVariationTrue->Size() == f.enthalpyFes->GetTrueVSize(),
|
||||
"The pressure-force enthalpy variation has the wrong size."
|
||||
);
|
||||
}
|
||||
|
||||
if (pressureForceAction == PressureForceAction::displacement) {
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue != nullptr &&
|
||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The pressure-force displacement variation has the wrong "
|
||||
"size."
|
||||
);
|
||||
}
|
||||
|
||||
mfem::Vector baseEnthalpyLocal;
|
||||
mfem::Vector enthalpyVariationLocal;
|
||||
mfem::Vector displacementLocal;
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
true_to_local(*f.enthalpyFes, enthalpyTrue, enthalpyLocal);
|
||||
true_to_local(*f.enthalpyFes, baseEnthalpyTrue, baseEnthalpyLocal);
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
true_to_local(*f.enthalpyFes, *enthalpyVariationTrue, enthalpyVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
mfem::Vector localResidual(f.displacementFes->GetVSize());
|
||||
localResidual = 0.0;
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
||||
}
|
||||
|
||||
mapping::DomainMapperStateless::Workspace workspace(
|
||||
f.mesh->Dimension()
|
||||
);
|
||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> enthalpyDofsofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
|
||||
mfem::Vector elementEnthalpy;
|
||||
mfem::Vector elementBaseEnthalpy;
|
||||
mfem::Vector elementEnthalpyVariation;
|
||||
mfem::Vector elementDisplacement;
|
||||
mfem::Vector elementDisplacementVariation;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector elementResidual;
|
||||
mfem::Vector elementAction;
|
||||
mfem::Vector enthalpyShape;
|
||||
|
||||
mfem::Array<int> enthalpyDofs;
|
||||
|
||||
mfem::DenseMatrix displacementDShapeReference;
|
||||
mfem::DenseMatrix displacementDShapePhysical;
|
||||
mfem::DenseMatrix displacementDShapePhysicalVariation;
|
||||
|
||||
mapping::VolumeMappingContext mappingContext;
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
|
||||
const int dimension = f.mesh->Dimension();
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
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) {
|
||||
mfem::ElementTransformation *transformation =
|
||||
f.mesh->GetElementTransformation(elementId);
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr,
|
||||
"The pressure-force kernel received a null element "
|
||||
"transformation."
|
||||
transformation != nullptr, "The pressure-force kernel received a null element "
|
||||
"transformation."
|
||||
);
|
||||
|
||||
/*
|
||||
@@ -281,128 +293,131 @@ namespace mean_field::operators::kernels {
|
||||
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 =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(
|
||||
elementId, compactificationDofs
|
||||
);
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
enthalpyLocal.GetSubVector(enthalpyDofs, elementEnthalpy);
|
||||
baseEnthalpyLocal.GetSubVector(enthalpyDofs, elementBaseEnthalpy);
|
||||
|
||||
displacementLocal.GetSubVector(
|
||||
displacementDofs, elementDisplacement
|
||||
);
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
enthalpyVariationLocal.GetSubVector(enthalpyDofs, elementEnthalpyVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(
|
||||
compactificationDofs, elementCompactification
|
||||
);
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (enthalpyDofTransformation != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpy);
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementBaseEnthalpy);
|
||||
|
||||
if (enthalpyVariationTrue != nullptr) {
|
||||
enthalpyDofTransformation->InvTransformPrimal(elementEnthalpyVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(
|
||||
elementDisplacement
|
||||
);
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(
|
||||
elementCompactification
|
||||
);
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mapping::ElementDisplacementData displacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacement
|
||||
);
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData,
|
||||
.compactification = compactificationData
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
||||
|
||||
if (displacementVariationTrue != nullptr) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementDofs.Size() ==
|
||||
scalarDisplacementDofCount * dimension,
|
||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
||||
"The pressure-force element displacement vector has "
|
||||
"the wrong size."
|
||||
);
|
||||
|
||||
enthalpyShape.SetSize(enthalpyElement.GetDof());
|
||||
|
||||
displacementDShapeReference.SetSize(
|
||||
scalarDisplacementDofCount, dimension
|
||||
);
|
||||
displacementDShapeReference.SetSize(scalarDisplacementDofCount, dimension);
|
||||
|
||||
displacementDShapePhysical.SetSize(
|
||||
scalarDisplacementDofCount, dimension
|
||||
);
|
||||
displacementDShapePhysical.SetSize(scalarDisplacementDofCount, dimension);
|
||||
|
||||
elementResidual.SetSize(displacementDofs.Size());
|
||||
elementResidual = 0.0;
|
||||
displacementDShapePhysicalVariation.SetSize(scalarDisplacementDofCount, dimension);
|
||||
|
||||
elementAction.SetSize(displacementDofs.Size());
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_pressure_force_rule(
|
||||
f, barotrope, enthalpyElement, displacementElement,
|
||||
*transformation
|
||||
);
|
||||
get_pressure_force_rule(f, barotrope, enthalpyElement, displacementElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0;
|
||||
quadratureIndex < integrationRule.GetNPoints();
|
||||
++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint =
|
||||
integrationRule.IntPoint(quadratureIndex);
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mapping::MappingStatus mappingStatus =
|
||||
domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint,
|
||||
workspace, mappingContext
|
||||
);
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mapping::MappingStatus::valid,
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the pressure-force "
|
||||
"kernel. Element: "
|
||||
<< elementId
|
||||
<< ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex
|
||||
<< ", status: " << static_cast<int>(mappingStatus)
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
|
||||
|
||||
const double enthalpyValue = elementEnthalpy * enthalpyShape;
|
||||
const double enthalpyValue = elementBaseEnthalpy * enthalpyShape;
|
||||
|
||||
const double pressureValue =
|
||||
barotrope.pressure_from_enthalpy(enthalpyValue);
|
||||
double pressureFactor = 0.0;
|
||||
|
||||
displacementElement.CalcDShape(
|
||||
integrationPoint, displacementDShapeReference
|
||||
);
|
||||
if (pressureForceAction == PressureForceAction::residual ||
|
||||
pressureForceAction == PressureForceAction::displacement) {
|
||||
pressureFactor = barotrope.pressure_from_enthalpy(enthalpyValue);
|
||||
} else {
|
||||
const double enthalpyVariationValue = elementEnthalpyVariation * enthalpyShape;
|
||||
|
||||
pressureFactor =
|
||||
barotrope.pressure_derivative_from_enthalpy(enthalpyValue) * enthalpyVariationValue;
|
||||
}
|
||||
|
||||
displacementElement.CalcDShape(integrationPoint, displacementDShapeReference);
|
||||
|
||||
/*
|
||||
* Row i of DShape is grad_reference(N_i). Multiplication
|
||||
@@ -411,17 +426,45 @@ namespace mean_field::operators::kernels {
|
||||
* grad_physical(N_i)
|
||||
* = grad_reference(N_i) J^{-1}.
|
||||
*/
|
||||
mfem::Mult(
|
||||
displacementDShapeReference,
|
||||
mappingContext.quadrature.J_inv, displacementDShapePhysical
|
||||
);
|
||||
mfem::Mult(displacementDShapeReference, mappingContext.quadrature.J_inv, displacementDShapePhysical);
|
||||
|
||||
const double weightedPressure =
|
||||
pressureValue * mappingContext.quadrature.weight;
|
||||
std::optional<mean_field::mapping::VolumeMappingVariation> mappingVariation;
|
||||
|
||||
if (pressureForceAction == PressureForceAction::displacement) {
|
||||
mappingVariation.emplace();
|
||||
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, *mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping variation failed in the "
|
||||
"pressure-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
|
||||
/*
|
||||
* Differentiating
|
||||
*
|
||||
* grad_x(N_i) = grad_reference(N_i) J^{-1}
|
||||
*
|
||||
* at the frozen base geometry gives the physical
|
||||
* test-gradient variation used by the geometric
|
||||
* pressure block.
|
||||
*/
|
||||
mfem::Mult(
|
||||
displacementDShapeReference, mappingVariation->inverse_element_jacobian_variation,
|
||||
displacementDShapePhysicalVariation
|
||||
);
|
||||
}
|
||||
|
||||
const double weightedPressureFactor = pressureFactor * mappingContext.quadrature.weight;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(pressureValue) &&
|
||||
std::isfinite(weightedPressure),
|
||||
std::isfinite(pressureFactor) && std::isfinite(weightedPressureFactor),
|
||||
"The pressure-force kernel encountered a non-finite "
|
||||
"quadrature value."
|
||||
);
|
||||
@@ -436,29 +479,96 @@ namespace mean_field::operators::kernels {
|
||||
* R_(i,c)
|
||||
* = -integral P partial_c N_i dV.
|
||||
*/
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount;
|
||||
++scalarDof) {
|
||||
for (int component = 0; component < dimension;
|
||||
++component) {
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
||||
for (int component = 0; component < dimension; ++component) {
|
||||
const int vectorDof = vector_dof_index(
|
||||
displacementOrdering, scalarDof, component,
|
||||
scalarDisplacementDofCount, dimension
|
||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
||||
);
|
||||
|
||||
elementResidual(vectorDof) -=
|
||||
weightedPressure *
|
||||
displacementDShapePhysical(scalarDof, component);
|
||||
if (pressureForceAction == PressureForceAction::displacement) {
|
||||
/*
|
||||
* Differentiate the complete discrete factor
|
||||
*
|
||||
* grad_x(N_i) dV_x.
|
||||
*
|
||||
* The enthalpy DOFs, and therefore P(h), are
|
||||
* frozen in this Jacobian column.
|
||||
*/
|
||||
const double gradientWeightVariation =
|
||||
mappingContext.quadrature.weight *
|
||||
displacementDShapePhysicalVariation(scalarDof, component) +
|
||||
mappingVariation->weight_variation * displacementDShapePhysical(scalarDof, component);
|
||||
|
||||
const double contribution = pressureFactor * gradientWeightVariation;
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(gradientWeightVariation) && std::isfinite(contribution),
|
||||
"The pressure-force geometry action "
|
||||
"encountered a non-finite contribution."
|
||||
);
|
||||
|
||||
elementAction(vectorDof) -= contribution;
|
||||
} else {
|
||||
elementAction(vectorDof) -=
|
||||
weightedPressureFactor * displacementDShapePhysical(scalarDof, component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->TransformDual(elementResidual);
|
||||
displacementDofTransformation->TransformDual(elementAction);
|
||||
}
|
||||
|
||||
localResidual.AddElementVector(displacementDofs, elementResidual);
|
||||
localAction.AddElementVector(displacementDofs, elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*f.displacementFes, localResidual, residualTrue);
|
||||
local_to_true(*f.displacementFes, localAction, actionTrue);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_pressure_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &enthalpyTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
) {
|
||||
apply_pressure_force_action(
|
||||
f, domainMapper, barotrope, PressureForceAction::residual, enthalpyTrue, nullptr, nullptr, displacementTrue,
|
||||
residualTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_pressure_force_enthalpy_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &enthalpyVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_pressure_force_action(
|
||||
f, domainMapper, barotrope, PressureForceAction::enthalpy, baseEnthalpyTrue, &enthalpyVariationTrue,
|
||||
nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_pressure_force_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const eos::Polytrope &barotrope,
|
||||
const mfem::Vector &baseEnthalpyTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_pressure_force_action(
|
||||
f, domainMapper, barotrope, PressureForceAction::displacement, baseEnthalpyTrue, nullptr,
|
||||
&displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
|
||||
@@ -0,0 +1,590 @@
|
||||
module;
|
||||
|
||||
#include <array>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
module mean_field;
|
||||
|
||||
import :operators.kernels.rotational_displacement_force;
|
||||
|
||||
namespace {
|
||||
enum class RotationalDisplacementForceAction { 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 "
|
||||
"size."
|
||||
);
|
||||
|
||||
localVector.SetSize(finiteElementSpace.GetVSize());
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(trueVector, localVector);
|
||||
} else {
|
||||
localVector = trueVector;
|
||||
}
|
||||
}
|
||||
|
||||
void local_to_true(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &localVector,
|
||||
mfem::Vector &trueVector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
localVector.Size() == finiteElementSpace.GetVSize(),
|
||||
"The rotational-displacement-force local vector has the wrong "
|
||||
"size."
|
||||
);
|
||||
|
||||
trueVector.SetSize(finiteElementSpace.GetTrueVSize());
|
||||
trueVector = 0.0;
|
||||
|
||||
const mfem::Operator *prolongation = finiteElementSpace.GetProlongationMatrix();
|
||||
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(localVector, trueVector);
|
||||
} else {
|
||||
trueVector = localVector;
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] int vector_dof_index(
|
||||
const mfem::Ordering::Type ordering,
|
||||
const int scalarDof,
|
||||
const int component,
|
||||
const int scalarDofCount,
|
||||
const int dimension
|
||||
) {
|
||||
if (ordering == mfem::Ordering::byNODES) {
|
||||
return scalarDof + component * scalarDofCount;
|
||||
}
|
||||
|
||||
if (ordering == mfem::Ordering::byVDIM) {
|
||||
return scalarDof * dimension + component;
|
||||
}
|
||||
|
||||
MFEM_ABORT(
|
||||
"The rotational-displacement-force test space uses an "
|
||||
"unsupported ordering."
|
||||
);
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_rotation_force_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::FiniteElement &densityElement,
|
||||
const mfem::FiniteElement &displacementElement,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
||||
|
||||
MFEM_VERIFY(
|
||||
densityElement.GetOrder() == mean_field::field::Density::Scalar::familyOrder,
|
||||
"The rotational-displacement-force density element does not "
|
||||
"match the registered density field."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementElement.GetOrder() == mean_field::field::Displacement::Vector::familyOrder,
|
||||
"The rotational-displacement-force test element does not match "
|
||||
"the registered displacement field."
|
||||
);
|
||||
|
||||
/*
|
||||
* grad(Psi_rotation) is linear in physical position, so it adds one
|
||||
* dynamic polynomial-order contribution.
|
||||
*/
|
||||
const mean_field::quadrature::Query query =
|
||||
DisplacementField::make_query<mean_field::field::Displacement::Form::CentrifugalForce>(
|
||||
mean_field::quadrature::QuadratureRole::discretization, 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());
|
||||
|
||||
MFEM_VERIFY(
|
||||
rule.integration_rule != nullptr, "The quadrature policy did not return a rotational-"
|
||||
"displacement-force integration rule."
|
||||
);
|
||||
|
||||
return *rule.integration_rule;
|
||||
}
|
||||
|
||||
void validate_finite_vector(
|
||||
const mfem::Vector &vector,
|
||||
const char *message
|
||||
) {
|
||||
for (int index = 0; index < vector.Size(); ++index) {
|
||||
MFEM_VERIFY(std::isfinite(vector(index)), message);
|
||||
}
|
||||
}
|
||||
|
||||
void validate_common_inputs(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mfem::Vector &displacementTrue
|
||||
) {
|
||||
MFEM_VERIFY(f.mesh != nullptr, "The rotational-displacement-force kernel requires a mesh.");
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.mesh->Dimension() == 3, "The rotational-displacement-force kernel requires a "
|
||||
"three-dimensional mesh."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.densityFes != nullptr, "The rotational-displacement-force kernel requires the density "
|
||||
"finite-element space."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
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 "
|
||||
"compactification coordinate."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.quadratureFactory != nullptr, "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 "
|
||||
"wrong size."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
domainMapper.GetDimension() == f.mesh->Dimension(),
|
||||
"The rotational-displacement-force mapper dimension does not "
|
||||
"match the mesh dimension."
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
f.displacementFes->GetVDim() == f.mesh->Dimension(),
|
||||
"The rotational-displacement-force displacement dimension does "
|
||||
"not match the mesh dimension."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
displacementTrue, "The rotational-displacement-force displacement contains a "
|
||||
"non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
void validate_density(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::Vector &density,
|
||||
const char *message
|
||||
) {
|
||||
MFEM_VERIFY(density.Size() == f.densityFes->GetTrueVSize(), message);
|
||||
validate_finite_vector(density, message);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_action(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mean_field::mapping::DomainMapperStateless &domainMapper,
|
||||
const mean_field::physics::RigidRotation &rotation,
|
||||
const RotationalDisplacementForceAction requestedAction,
|
||||
const mfem::Vector *baseDensityTrue,
|
||||
const mfem::Vector *densityVariationTrue,
|
||||
const mfem::Vector *displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
validate_common_inputs(f, domainMapper, displacementTrue);
|
||||
|
||||
const bool needsBaseDensity = requestedAction == RotationalDisplacementForceAction::residual ||
|
||||
requestedAction == RotationalDisplacementForceAction::displacement ||
|
||||
requestedAction == RotationalDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDensityVariation = requestedAction == RotationalDisplacementForceAction::density ||
|
||||
requestedAction == RotationalDisplacementForceAction::complete;
|
||||
|
||||
const bool needsDisplacementVariation = requestedAction == RotationalDisplacementForceAction::displacement ||
|
||||
requestedAction == RotationalDisplacementForceAction::complete;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
MFEM_VERIFY(
|
||||
baseDensityTrue != nullptr, "The rotational-displacement-force action requires a base "
|
||||
"density."
|
||||
);
|
||||
|
||||
validate_density(f, *baseDensityTrue, "The rotational-displacement-force base density is invalid.");
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
MFEM_VERIFY(
|
||||
densityVariationTrue != nullptr, "The rotational-displacement-force action requires a "
|
||||
"density variation."
|
||||
);
|
||||
|
||||
validate_density(
|
||||
f, *densityVariationTrue,
|
||||
"The rotational-displacement-force density variation is "
|
||||
"invalid."
|
||||
);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
MFEM_VERIFY(
|
||||
displacementVariationTrue != nullptr &&
|
||||
displacementVariationTrue->Size() == f.displacementFes->GetTrueVSize(),
|
||||
"The rotational-displacement-force displacement variation "
|
||||
"is invalid."
|
||||
);
|
||||
|
||||
validate_finite_vector(
|
||||
*displacementVariationTrue, "The rotational-displacement-force displacement variation "
|
||||
"contains a non-finite value."
|
||||
);
|
||||
}
|
||||
|
||||
mfem::Vector baseDensityLocal;
|
||||
mfem::Vector densityVariationLocal;
|
||||
mfem::Vector displacementLocal;
|
||||
mfem::Vector displacementVariationLocal;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
true_to_local(*f.densityFes, *baseDensityTrue, baseDensityLocal);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
true_to_local(*f.densityFes, *densityVariationTrue, densityVariationLocal);
|
||||
}
|
||||
|
||||
true_to_local(*f.displacementFes, displacementTrue, displacementLocal);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
true_to_local(*f.displacementFes, *displacementVariationTrue, displacementVariationLocal);
|
||||
}
|
||||
|
||||
mfem::Vector localAction(f.displacementFes->GetVSize());
|
||||
localAction = 0.0;
|
||||
|
||||
mean_field::mapping::DomainMapperStateless::Workspace workspace(f.mesh->Dimension());
|
||||
|
||||
mfem::Array<int> densityDofs;
|
||||
mfem::Array<int> displacementDofs;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
|
||||
mfem::Vector elementBaseDensity;
|
||||
mfem::Vector elementDensityVariation;
|
||||
mfem::Vector elementDisplacement;
|
||||
mfem::Vector elementDisplacementVariation;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector elementAction;
|
||||
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector displacementShape;
|
||||
mfem::Vector potentialGradient;
|
||||
mfem::Vector potentialGradientVariation;
|
||||
mfem::Vector centrifugalAcceleration;
|
||||
mfem::Vector centrifugalAccelerationVariation;
|
||||
mfem::Vector weightedForce;
|
||||
|
||||
mean_field::mapping::VolumeMappingContext mappingContext;
|
||||
mean_field::mapping::VolumeMappingVariation mappingVariation;
|
||||
|
||||
const int dimension = f.mesh->Dimension();
|
||||
const int vacuumAttribute = domainMapper.GetVacuumElementAttribute();
|
||||
|
||||
const mfem::Ordering::Type displacementOrdering = f.displacementFes->GetOrdering();
|
||||
|
||||
for (int elementId = 0; elementId < f.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation = f.mesh->GetElementTransformation(elementId);
|
||||
|
||||
MFEM_VERIFY(
|
||||
transformation != nullptr, "The rotational-displacement-force kernel received a null "
|
||||
"element transformation."
|
||||
);
|
||||
|
||||
if (transformation->Attribute == vacuumAttribute) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement = *f.densityFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &displacementElement = *f.displacementFes->GetFE(elementId);
|
||||
|
||||
const mfem::FiniteElement &compactificationElement = *f.compactificationFes->GetFE(elementId);
|
||||
|
||||
mfem::DofTransformation *densityDofTransformation = f.densityFes->GetElementDofs(elementId, densityDofs);
|
||||
|
||||
mfem::DofTransformation *displacementDofTransformation =
|
||||
f.displacementFes->GetElementVDofs(elementId, displacementDofs);
|
||||
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
f.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityLocal.GetSubVector(densityDofs, elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationLocal.GetSubVector(densityDofs, elementDensityVariation);
|
||||
}
|
||||
|
||||
displacementLocal.GetSubVector(displacementDofs, elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationLocal.GetSubVector(displacementDofs, elementDisplacementVariation);
|
||||
}
|
||||
|
||||
f.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
|
||||
if (densityDofTransformation != nullptr) {
|
||||
if (needsBaseDensity) {
|
||||
densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityDofTransformation->InvTransformPrimal(elementDensityVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacement);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementDofTransformation->InvTransformPrimal(elementDisplacementVariation);
|
||||
}
|
||||
}
|
||||
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mean_field::mapping::ElementDisplacementData displacementData =
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementDisplacement);
|
||||
|
||||
const mean_field::mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
|
||||
const mean_field::mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
std::optional<mean_field::mapping::ElementDisplacementData> displacementVariationData;
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
displacementVariationData.emplace(
|
||||
mean_field::mapping::ElementDisplacementDataFromElementVDofs(
|
||||
displacementElement, elementDisplacementVariation
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||
|
||||
MFEM_VERIFY(
|
||||
displacementDofs.Size() == scalarDisplacementDofCount * dimension,
|
||||
"The rotational-displacement-force element displacement "
|
||||
"vector has the wrong size."
|
||||
);
|
||||
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
displacementShape.SetSize(scalarDisplacementDofCount);
|
||||
potentialGradient.SetSize(dimension);
|
||||
potentialGradientVariation.SetSize(dimension);
|
||||
centrifugalAcceleration.SetSize(dimension);
|
||||
centrifugalAccelerationVariation.SetSize(dimension);
|
||||
weightedForce.SetSize(dimension);
|
||||
|
||||
elementAction.SetSize(displacementDofs.Size());
|
||||
elementAction = 0.0;
|
||||
|
||||
const mfem::IntegrationRule &integrationRule =
|
||||
get_rotation_force_rule(f, densityElement, displacementElement, *transformation);
|
||||
|
||||
for (int quadratureIndex = 0; quadratureIndex < integrationRule.GetNPoints(); ++quadratureIndex) {
|
||||
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadratureIndex);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
const mean_field::mapping::MappingStatus mappingStatus = domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
mappingStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping failed in the rotational-"
|
||||
"displacement-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute
|
||||
<< ", quadrature point: " << quadratureIndex << ", status: " << static_cast<int>(mappingStatus)
|
||||
);
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
const mean_field::mapping::MappingStatus variationStatus = domainMapper.EvaluateVolumeVariation(
|
||||
mappingData, *displacementVariationData, *transformation, integrationPoint, mappingContext,
|
||||
workspace, mappingVariation
|
||||
);
|
||||
|
||||
MFEM_VERIFY(
|
||||
variationStatus == mean_field::mapping::MappingStatus::valid,
|
||||
"Stateless mapping variation failed in the "
|
||||
"rotational-displacement-force kernel. Element: "
|
||||
<< elementId << ", attribute: " << transformation->Attribute << ", quadrature point: "
|
||||
<< quadratureIndex << ", status: " << static_cast<int>(variationStatus)
|
||||
);
|
||||
}
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
|
||||
displacementElement.CalcShape(integrationPoint, displacementShape);
|
||||
|
||||
double baseDensityValue = 0.0;
|
||||
double densityVariationValue = 0.0;
|
||||
|
||||
if (needsBaseDensity) {
|
||||
baseDensityValue = elementBaseDensity * densityShape;
|
||||
}
|
||||
|
||||
if (needsDensityVariation) {
|
||||
densityVariationValue = elementDensityVariation * densityShape;
|
||||
}
|
||||
|
||||
rotation.potential_gradient(mappingContext.mapping.physical_position, potentialGradient);
|
||||
|
||||
centrifugalAcceleration = potentialGradient;
|
||||
centrifugalAcceleration *= -1.0;
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
rotation.potential_gradient_directional_derivative(
|
||||
mappingVariation.mapping.physical_position_variation, potentialGradientVariation
|
||||
);
|
||||
|
||||
centrifugalAccelerationVariation = potentialGradientVariation;
|
||||
|
||||
centrifugalAccelerationVariation *= -1.0;
|
||||
} else {
|
||||
centrifugalAccelerationVariation = 0.0;
|
||||
}
|
||||
|
||||
weightedForce = 0.0;
|
||||
|
||||
if (requestedAction == RotationalDisplacementForceAction::residual) {
|
||||
weightedForce.Add(baseDensityValue * mappingContext.quadrature.weight, centrifugalAcceleration);
|
||||
} else {
|
||||
if (needsDensityVariation) {
|
||||
weightedForce.Add(
|
||||
densityVariationValue * mappingContext.quadrature.weight, centrifugalAcceleration
|
||||
);
|
||||
}
|
||||
|
||||
if (needsDisplacementVariation) {
|
||||
weightedForce.Add(
|
||||
baseDensityValue * mappingContext.quadrature.weight, centrifugalAccelerationVariation
|
||||
);
|
||||
|
||||
weightedForce.Add(
|
||||
baseDensityValue * mappingVariation.weight_variation, centrifugalAcceleration
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
||||
for (int component = 0; component < dimension; ++component) {
|
||||
const int vectorDof = vector_dof_index(
|
||||
displacementOrdering, scalarDof, component, scalarDisplacementDofCount, dimension
|
||||
);
|
||||
|
||||
const double contribution = displacementShape(scalarDof) * weightedForce(component);
|
||||
|
||||
MFEM_VERIFY(
|
||||
std::isfinite(contribution), "The rotational-displacement-force kernel "
|
||||
"encountered a non-finite contribution."
|
||||
);
|
||||
|
||||
elementAction(vectorDof) += contribution;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (displacementDofTransformation != nullptr) {
|
||||
displacementDofTransformation->TransformDual(elementAction);
|
||||
}
|
||||
|
||||
localAction.AddElementVector(displacementDofs, elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*f.displacementFes, localAction, actionTrue);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators::kernels {
|
||||
void apply_rotational_displacement_force_residual(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &densityTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &residualTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::residual, &densityTrue, nullptr, nullptr,
|
||||
displacementTrue, residualTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_density_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::density, nullptr, &densityVariationTrue,
|
||||
nullptr, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_displacement_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::displacement, &baseDensityTrue, nullptr,
|
||||
&displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
|
||||
void apply_rotational_displacement_force_complete_action(
|
||||
const fem::FEM &f,
|
||||
const mapping::DomainMapperStateless &domainMapper,
|
||||
const physics::RigidRotation &rotation,
|
||||
const mfem::Vector &baseDensityTrue,
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &displacementTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) {
|
||||
apply_rotational_displacement_force_action(
|
||||
f, domainMapper, rotation, RotationalDisplacementForceAction::complete, &baseDensityTrue,
|
||||
&densityVariationTrue, &displacementVariationTrue, displacementTrue, actionTrue
|
||||
);
|
||||
}
|
||||
} // namespace mean_field::operators::kernels
|
||||
Reference in New Issue
Block a user