perf(allocations): reduced overall allocations by 95%, increaseed jacobian applicatin by 2x

This commit uses global pre allocated work space to dramatically reduce memory usage and allocation time
This commit is contained in:
2026-09-10 06:50:56 -04:00
parent b3c04d507a
commit 75cc638739
66 changed files with 207183 additions and 99552 deletions

View File

@@ -311,13 +311,12 @@ namespace mean_field::operators {
const mfem::FiniteElement &densityElement = *m_fem.densityFes->GetFE(elementId);
const mfem::IntegrationRule &integrationRule =
get_moment_of_inertia_rule(m_fem, densityElement, *transformation);
data.quadraturePoints.resize(integrationRule.GetNPoints());
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
QuadraturePointData &point = data.quadraturePoints[quadraturePoint];
point.integrationPoint = integrationRule.IntPoint(quadraturePoint);
point.densityShape.SetSize(densityElement.GetDof());
densityElement.CalcShape(point.integrationPoint, point.densityShape);
}
data.integrationRule = &integrationRule;
data.densityBasis = m_fem.GetReferenceTables().GetScalarTable(densityElement, integrationRule);
data.mappingContexts.SetSize(integrationRule.GetNPoints(), m_fem.mesh->Dimension());
data.density.SetSize(integrationRule.GetNPoints());
data.quadratureWeights.SetSize(integrationRule.GetNPoints());
data.cylindricalRadiusSquared.SetSize(integrationRule.GetNPoints());
}
int globalStellarElementCount = 0;
MFEM_VERIFY(
@@ -344,6 +343,7 @@ namespace mean_field::operators {
return mapping::MappingStatus::non_finite_result;
}
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingContext mappingContext;
for (ElementPAData &data : m_elements) {
displacementLocal.GetSubVector(data.displacementDofs, data.baseDisplacement);
@@ -372,21 +372,24 @@ namespace mean_field::operators {
.displacement = displacementData, .compactification = compactificationData
};
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
for (QuadraturePointData &point : data.quadraturePoints) {
for (int quadraturePoint = 0; quadraturePoint < data.integrationRule->GetNPoints(); ++quadraturePoint) {
const mapping::MappingStatus status = m_domainMapper.EvaluateVolume(
mappingData, *transformation, point.integrationPoint, workspace, point.mappingContext
mappingData, *transformation, data.integrationRule->IntPoint(quadraturePoint), workspace,
mappingContext
);
if (status != mapping::MappingStatus::valid) {
return status;
}
if (point.mappingContext.mapping.compactified) {
if (mappingContext.mapping.compactified) {
return mapping::MappingStatus::at_compactified_infinity;
}
point.cylindricalRadiusSquared =
CylindricalRadiusSquared(point.mappingContext.mapping.physical_position);
if (!std::isfinite(point.cylindricalRadiusSquared)) {
data.cylindricalRadiusSquared(quadraturePoint) =
CylindricalRadiusSquared(mappingContext.mapping.physical_position);
if (!std::isfinite(data.cylindricalRadiusSquared(quadraturePoint))) {
return mapping::MappingStatus::non_finite_result;
}
data.mappingContexts.Store(quadraturePoint, mappingContext);
data.quadratureWeights(quadraturePoint) = mappingContext.quadrature.weight;
}
}
return std::nullopt;
@@ -411,11 +414,9 @@ namespace mean_field::operators {
if (!is_finite_vector(elementDensity)) {
return false;
}
for (QuadraturePointData &point : data.quadraturePoints) {
point.density = elementDensity * point.densityShape;
if (!std::isfinite(point.density)) {
return false;
}
data.densityBasis->GetValues().Mult(elementDensity, data.density);
if (!is_finite_vector(data.density)) {
return false;
}
}
return true;
@@ -424,9 +425,9 @@ namespace mean_field::operators {
std::optional<AngularMomentumPreparationRejection> PreparedAngularMomentumOperator::TryAssembleResidual() {
double localMomentOfInertia = 0.0;
for (const ElementPAData &data : m_elements) {
for (const QuadraturePointData &point : data.quadraturePoints) {
localMomentOfInertia +=
point.density * point.cylindricalRadiusSquared * point.mappingContext.quadrature.weight;
for (int quadraturePoint = 0; quadraturePoint < data.density.Size(); ++quadraturePoint) {
localMomentOfInertia += data.density(quadraturePoint) * data.cylindricalRadiusSquared(quadraturePoint) *
data.quadratureWeights(quadraturePoint);
}
}
m_momentOfInertia = GlobalSum(localMomentOfInertia);
@@ -472,15 +473,18 @@ namespace mean_field::operators {
"Angular-momentum density action has the wrong true-vector size."
);
true_to_local(*m_fem.densityFes, densityVariation, m_densityVariationLocal);
mfem::Vector quadratureDensityVariation;
double localAction = 0.0;
for (const ElementPAData &data : m_elements) {
m_densityVariationLocal.GetSubVector(data.densityDofs, m_elementDensityVariation);
if (data.densityDofTransformation != nullptr) {
data.densityDofTransformation->InvTransformPrimal(m_elementDensityVariation);
}
for (const QuadraturePointData &point : data.quadraturePoints) {
localAction += (m_elementDensityVariation * point.densityShape) * point.cylindricalRadiusSquared *
point.mappingContext.quadrature.weight;
quadratureDensityVariation.SetSize(data.integrationRule->GetNPoints());
data.densityBasis->GetValues().Mult(m_elementDensityVariation, quadratureDensityVariation);
for (int quadraturePoint = 0; quadraturePoint < quadratureDensityVariation.Size(); ++quadraturePoint) {
localAction += quadratureDensityVariation(quadraturePoint) *
data.cylindricalRadiusSquared(quadraturePoint) * data.quadratureWeights(quadraturePoint);
}
}
return localAction;
@@ -496,6 +500,7 @@ namespace mean_field::operators {
true_to_local(*m_fem.displacementFes, displacementVariation, m_displacementVariationLocal);
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingVariation variation;
mapping::VolumeMappingContext mappingContext;
double localAction = 0.0;
for (const ElementPAData &data : m_elements) {
m_displacementVariationLocal.GetSubVector(data.displacementDofs, m_elementDisplacementVariation);
@@ -515,20 +520,22 @@ namespace mean_field::operators {
.displacement = baseDisplacementData, .compactification = compactificationData
};
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
for (const QuadraturePointData &point : data.quadraturePoints) {
for (int quadraturePoint = 0; quadraturePoint < data.integrationRule->GetNPoints(); ++quadraturePoint) {
data.mappingContexts.Load(quadraturePoint, mappingContext);
const mapping::MappingStatus status = m_domainMapper.EvaluateVolumeVariation(
mappingData, directionData, *transformation, point.integrationPoint, point.mappingContext,
workspace, variation
mappingData, directionData, *transformation, data.integrationRule->IntPoint(quadraturePoint),
mappingContext, workspace, variation
);
MFEM_VERIFY(
status == mapping::MappingStatus::valid,
"Mapped angular-momentum variation is invalid. Element: " << data.elementId
);
const double radiusSquaredVariation = CylindricalRadiusSquaredVariation(
point.mappingContext.mapping.physical_position, variation.mapping.physical_position_variation
mappingContext.mapping.physical_position, variation.mapping.physical_position_variation
);
localAction += point.density * (radiusSquaredVariation * point.mappingContext.quadrature.weight +
point.cylindricalRadiusSquared * variation.weight_variation);
localAction += data.density(quadraturePoint) *
(radiusSquaredVariation * data.quadratureWeights(quadraturePoint) +
data.cylindricalRadiusSquared(quadraturePoint) * variation.weight_variation);
}
}
return localAction;

View File

@@ -450,8 +450,8 @@ namespace mean_field::operators {
m_displacementMap.scatter(m_context.GetDisplacement(), m_baseDisplacementTrue);
m_isPrepared = false;
m_elements.clear();
m_elements.reserve(m_fem.mesh->GetNE());
std::size_t preparedElementCount{0};
mfem::Vector baseDensityLocal;
mfem::Vector baseEnthalpyLocal;
@@ -462,6 +462,7 @@ namespace mean_field::operators {
true_to_local(*m_fem.displacementFes, m_baseDisplacementTrue, displacementLocal);
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingContext mappingContext;
mfem::Array<int> compactificationDofs;
@@ -485,8 +486,10 @@ namespace mean_field::operators {
continue;
}
m_elements.emplace_back();
ElementPAData &data = m_elements.back();
if (preparedElementCount == m_elements.size()) {
m_elements.emplace_back();
}
ElementPAData &data = m_elements[preparedElementCount++];
data.elementId = elementId;
data.densityDofTransformation = m_fem.densityFes->GetElementDofs(elementId, data.densityDofs);
@@ -533,13 +536,15 @@ namespace mean_field::operators {
const mfem::IntegrationRule &integrationRule =
get_eos_rule(m_fem, m_equationOfState, densityElement, enthalpyElement, *transformation);
data.integrationRule = &integrationRule;
const int quadraturePointCount = integrationRule.GetNPoints();
const int densityDofCount = densityElement.GetDof();
const int enthalpyDofCount = enthalpyElement.GetDof();
data.densityBasis.SetSize(quadraturePointCount, densityDofCount);
data.enthalpyBasis.SetSize(quadraturePointCount, enthalpyDofCount);
data.densityBasis = m_fem.GetReferenceTables().GetScalarTable(densityElement, integrationRule);
data.enthalpyBasis = m_fem.GetReferenceTables().GetScalarTable(enthalpyElement, integrationRule);
data.displacementBasis = m_fem.GetReferenceTables().GetScalarTable(displacementElement, integrationRule);
data.inverseElementJacobians.SetSize(
quadraturePointCount, m_fem.mesh->Dimension() * m_fem.mesh->Dimension()
);
@@ -555,8 +560,6 @@ namespace mean_field::operators {
transformation->SetIntPoint(&integrationPoint);
mapping::VolumeMappingContext mappingContext;
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolume(
mappingData, *transformation, integrationPoint, workspace, mappingContext
);
@@ -585,8 +588,8 @@ namespace mean_field::operators {
}
}
densityElement.CalcShape(integrationPoint, densityShape);
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
data.densityBasis->GetValues().GetRow(quadraturePoint, densityShape);
data.enthalpyBasis->GetValues().GetRow(quadraturePoint, enthalpyShape);
if (!vector_is_finite(densityShape) || !vector_is_finite(enthalpyShape)) {
retain_higher_priority_rejection(
@@ -595,13 +598,6 @@ namespace mean_field::operators {
continue;
}
for (int densityDof = 0; densityDof < densityDofCount; ++densityDof) {
data.densityBasis(quadraturePoint, densityDof) = densityShape(densityDof);
}
for (int enthalpyDof = 0; enthalpyDof < enthalpyDofCount; ++enthalpyDof) {
data.enthalpyBasis(quadraturePoint, enthalpyDof) = enthalpyShape(enthalpyDof);
}
const double density = elementBaseDensity * densityShape;
const double enthalpy = elementBaseEnthalpy * enthalpyShape;
const double quadratureWeight = mappingContext.quadrature.weight;
@@ -665,6 +661,7 @@ namespace mean_field::operators {
data.weightedEnthalpyDerivative(quadraturePoint) = weightedEnthalpyDerivative;
}
}
m_elements.resize(preparedElementCount);
if (auto globalRejection = synchronize_rejection(localRejection, m_fem.densityFes->GetComm());
globalRejection.has_value()) {
@@ -689,7 +686,7 @@ namespace mean_field::operators {
for (const ElementPAData &data : m_elements) {
elementResidual.SetSize(data.densityDofs.Size());
data.densityBasis.MultTranspose(data.weightedResidual, elementResidual);
data.densityBasis->GetValues().MultTranspose(data.weightedResidual, elementResidual);
if (data.densityDofTransformation != nullptr) {
data.densityDofTransformation->TransformDual(elementResidual);
@@ -719,7 +716,7 @@ namespace mean_field::operators {
elementDiagonal = 0.0;
for (int trialDof = 0; trialDof < data.densityDofs.Size(); ++trialDof) {
for (int quadraturePoint = 0; quadraturePoint < data.quadratureWeights.Size(); ++quadraturePoint) {
const double basis = data.densityBasis(quadraturePoint, trialDof);
const double basis = data.densityBasis->GetValues()(quadraturePoint, trialDof);
elementDiagonal(trialDof) += data.quadratureWeights(quadraturePoint) * basis * basis;
}
}
@@ -842,8 +839,8 @@ namespace mean_field::operators {
quadratureEnthalpyVariation.SetSize(data.quadratureWeights.Size());
quadratureAction.SetSize(data.quadratureWeights.Size());
data.densityBasis.Mult(elementDensityVariation, quadratureDensityVariation);
data.enthalpyBasis.Mult(elementEnthalpyVariation, quadratureEnthalpyVariation);
data.densityBasis->GetValues().Mult(elementDensityVariation, quadratureDensityVariation);
data.enthalpyBasis->GetValues().Mult(elementEnthalpyVariation, quadratureEnthalpyVariation);
for (int quadraturePoint = 0; quadraturePoint < quadratureAction.Size(); ++quadraturePoint) {
quadratureAction(quadraturePoint) =
@@ -852,7 +849,7 @@ namespace mean_field::operators {
}
elementAction.SetSize(data.densityDofs.Size());
data.densityBasis.MultTranspose(quadratureAction, elementAction);
data.densityBasis->GetValues().MultTranspose(quadratureAction, elementAction);
if (data.densityDofTransformation != nullptr) {
data.densityDofTransformation->TransformDual(elementAction);
@@ -906,14 +903,14 @@ namespace mean_field::operators {
"Prepared barotropic closure inverse-Jacobian data has an incompatible size."
);
m_referenceDShape.SetSize(displacementElement.GetDof(), dimension);
m_referenceDisplacementJacobian.SetSize(dimension, dimension);
m_quadratureDisplacementAction.SetSize(integrationRule.GetNPoints());
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
const mfem::IntegrationPoint &integrationPoint = integrationRule.IntPoint(quadraturePoint);
displacementElement.CalcDShape(integrationPoint, m_referenceDShape);
mfem::MultAtB(directionDofs, m_referenceDShape, m_referenceDisplacementJacobian);
mfem::MultAtB(
directionDofs, data.displacementBasis->GetGradients(quadraturePoint),
m_referenceDisplacementJacobian
);
double logarithmicJacobianVariation{0.0};
for (int row = 0; row < dimension; ++row) {
@@ -933,7 +930,7 @@ namespace mean_field::operators {
}
m_elementDisplacementAction.SetSize(data.densityDofs.Size());
data.densityBasis.MultTranspose(m_quadratureDisplacementAction, m_elementDisplacementAction);
data.densityBasis->GetValues().MultTranspose(m_quadratureDisplacementAction, m_elementDisplacementAction);
if (data.densityDofTransformation != nullptr) {
data.densityDofTransformation->TransformDual(m_elementDisplacementAction);

View File

@@ -13,6 +13,7 @@ module mean_field;
import :operators.kernels.gravity_displacement_force;
import :operators.prepared_gravity_displacement_force;
import :fem.reference_tables;
namespace {
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
@@ -249,6 +250,17 @@ namespace mean_field::operators {
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(elementId);
const mfem::FiniteElement &compactificationElement = *m_fem.compactificationFes->GetFE(elementId);
data.integrationRule = &get_gravity_force_rule(m_fem, *transformation);
data.densityReferenceTable =
m_fem.GetReferenceTables().GetScalarTable(densityElement, *data.integrationRule);
data.displacementReferenceTable =
m_fem.GetReferenceTables().GetScalarTable(displacementElement, *data.integrationRule);
if (gravityGradientElement.GetMapType() == mfem::FiniteElement::H_DIV &&
gravityGradientElement.GetDim() == dimension && gravityGradientElement.GetRangeDim() == dimension &&
transformation->GetSpaceDim() == dimension) {
data.gravityReferenceTable =
m_fem.GetReferenceTables().GetVectorTable(gravityGradientElement, *data.integrationRule);
data.meshPiolaJacobians.SetSize(data.integrationRule->GetNPoints(), dimension * dimension);
}
const mapping::ElementDisplacementData displacementData =
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementBaseDisplacement);
@@ -282,13 +294,17 @@ namespace mean_field::operators {
"Prepared gravity force encountered compactification on a stellar element."
);
densityElement.CalcShape(integrationPoint, densityShape);
for (int dof = 0; dof < densityElement.GetDof(); ++dof) {
densityShape(dof) = data.densityReferenceTable->GetValues()(quadraturePoint, dof);
}
gravityGradientElement.CalcVShape(*transformation, gravityGradientShape);
gravityGradientShape.MultTranspose(elementBaseGravityGradient, baseGravityReferenceValue);
data.baseDensityValues(quadraturePoint) = elementBaseDensity * densityShape;
data.referenceWeights(quadraturePoint) = integrationPoint.weight * transformation->Weight();
const mfem::DenseMatrix &inverseMeshJacobian = transformation->InverseJacobian();
const mfem::DenseMatrix &meshJacobian = transformation->Jacobian();
const double inverseMeshWeight = 1.0 / transformation->Weight();
for (int row = 0; row < dimension; ++row) {
data.baseGravityReferenceValues(quadraturePoint, row) = baseGravityReferenceValue(row);
for (int column = 0; column < dimension; ++column) {
@@ -296,6 +312,10 @@ namespace mean_field::operators {
data.mappingJacobians(quadraturePoint, entry) =
mappingContext.mapping.mapping_jacobian(row, column);
data.inverseMeshJacobians(quadraturePoint, entry) = inverseMeshJacobian(row, column);
if (data.gravityReferenceTable != nullptr) {
data.meshPiolaJacobians(quadraturePoint, entry) =
inverseMeshWeight * meshJacobian(row, column);
}
}
}
@@ -308,7 +328,9 @@ namespace mean_field::operators {
for (int column = 0; column < dimension; ++column) {
const int entry = row * dimension + column;
if (!std::isfinite(data.mappingJacobians(quadraturePoint, entry)) ||
!std::isfinite(data.inverseMeshJacobians(quadraturePoint, entry))) {
!std::isfinite(data.inverseMeshJacobians(quadraturePoint, entry)) ||
(data.gravityReferenceTable != nullptr &&
!std::isfinite(data.meshPiolaJacobians(quadraturePoint, entry)))) {
return std::unexpected(non_finite_rejection());
}
}
@@ -462,6 +484,10 @@ namespace mean_field::operators {
for (const ElementPAData &data : m_elements) {
MFEM_VERIFY(data.integrationRule != nullptr, "Prepared gravity force has no integration rule.");
MFEM_VERIFY(
data.densityReferenceTable != nullptr && data.displacementReferenceTable != nullptr,
"Prepared gravity force has no reference basis tables."
);
m_densityVariationLocal.GetSubVector(data.densityDofs, m_elementDensityVariation);
m_gravityGradientVariationLocal.GetSubVector(data.gravityGradientDofs, m_elementGravityGradientVariation);
@@ -490,13 +516,14 @@ namespace mean_field::operators {
m_densityShape.SetSize(densityElement.GetDof());
m_displacementShape.SetSize(scalarDisplacementDofCount);
m_gravityGradientShape.SetSize(gravityGradientElement.GetDof(), dimension);
m_referenceDisplacementDShape.SetSize(scalarDisplacementDofCount, dimension);
m_referenceDisplacementJacobian.SetSize(dimension, dimension);
m_displacementJacobianVariation.SetSize(dimension, dimension);
m_mappingJacobian.SetSize(dimension, dimension);
m_inverseMeshJacobian.SetSize(dimension, dimension);
m_meshPiolaJacobian.SetSize(dimension, dimension);
m_baseGravityReferenceValue.SetSize(dimension);
m_gravityVariationReferenceValue.SetSize(dimension);
m_gravityVariationReferenceCellValue.SetSize(dimension);
m_mappedBaseGravity.SetSize(dimension);
m_mappedGravityVariation.SetSize(dimension);
m_mappedGeometryVariation.SetSize(dimension);
@@ -506,16 +533,28 @@ namespace mean_field::operators {
for (int quadraturePoint = 0; quadraturePoint < data.integrationRule->GetNPoints(); ++quadraturePoint) {
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
densityElement.CalcShape(integrationPoint, m_densityShape);
displacementElement.CalcShape(integrationPoint, m_displacementShape);
displacementElement.CalcDShape(integrationPoint, m_referenceDisplacementDShape);
mfem::MultAtB(directionDofs, m_referenceDisplacementDShape, m_referenceDisplacementJacobian);
const mfem::DenseMatrix &referenceDisplacementDShape =
data.displacementReferenceTable->GetGradients(quadraturePoint);
mfem::MultAtB(directionDofs, referenceDisplacementDShape, m_referenceDisplacementJacobian);
const mfem::DenseMatrix &densityValues = data.densityReferenceTable->GetValues();
const mfem::DenseMatrix &displacementValues = data.displacementReferenceTable->GetValues();
for (int dof = 0; dof < densityElement.GetDof(); ++dof) {
m_densityShape(dof) = densityValues(quadraturePoint, dof);
}
for (int dof = 0; dof < scalarDisplacementDofCount; ++dof) {
m_displacementShape(dof) = displacementValues(quadraturePoint, dof);
}
transformation->SetIntPoint(&integrationPoint);
gravityGradientElement.CalcVShape(*transformation, m_gravityGradientShape);
m_gravityGradientShape.MultTranspose(
m_elementGravityGradientVariation, m_gravityVariationReferenceValue
);
if (data.gravityReferenceTable != nullptr) {
data.gravityReferenceTable->GetValues(quadraturePoint)
.MultTranspose(m_elementGravityGradientVariation, m_gravityVariationReferenceCellValue);
} else {
transformation->SetIntPoint(&integrationPoint);
gravityGradientElement.CalcVShape(*transformation, m_gravityGradientShape);
m_gravityGradientShape.MultTranspose(
m_elementGravityGradientVariation, m_gravityVariationReferenceValue
);
}
for (int row = 0; row < dimension; ++row) {
m_baseGravityReferenceValue(row) = data.baseGravityReferenceValues(quadraturePoint, row);
@@ -523,8 +562,14 @@ namespace mean_field::operators {
const int entry = row * dimension + column;
m_mappingJacobian(row, column) = data.mappingJacobians(quadraturePoint, entry);
m_inverseMeshJacobian(row, column) = data.inverseMeshJacobians(quadraturePoint, entry);
if (data.gravityReferenceTable != nullptr) {
m_meshPiolaJacobian(row, column) = data.meshPiolaJacobians(quadraturePoint, entry);
}
}
}
if (data.gravityReferenceTable != nullptr) {
m_meshPiolaJacobian.Mult(m_gravityVariationReferenceCellValue, m_gravityVariationReferenceValue);
}
mfem::Mult(m_referenceDisplacementJacobian, m_inverseMeshJacobian, m_displacementJacobianVariation);
m_mappingJacobian.Mult(m_baseGravityReferenceValue, m_mappedBaseGravity);
m_mappingJacobian.Mult(m_gravityVariationReferenceValue, m_mappedGravityVariation);

View File

@@ -182,19 +182,17 @@ namespace {
.displacement = *m_displacement_data, .compactification = *m_compactification_data
};
mean_field::mapping::VolumeMappingContext mapping_context;
const mean_field::mapping::MappingStatus status = m_domain_mapper.EvaluateVolume(
mapping_data, transformation, integration_point, m_workspace, mapping_context
mapping_data, transformation, integration_point, m_workspace, m_mapping_context
);
if (status != mean_field::mapping::MappingStatus::valid) {
m_mappingFailure = status;
return 0.0;
}
const double mapping_determinant = mapping_context.mapping.mapping_determinant;
const double mapping_determinant = m_mapping_context.mapping.mapping_determinant;
m_inverse_element_jacobian = mapping_context.quadrature.J_inv;
m_inverse_element_jacobian = m_mapping_context.quadrature.J_inv;
const double value = 4.0 * std::numbers::pi * mean_field::utils::G * mapping_determinant;
if (!std::isfinite(value)) {
@@ -269,6 +267,7 @@ namespace {
std::unique_ptr<mean_field::mapping::ElementCompactificationData> m_compactification_data;
mean_field::mapping::DomainMapper::Workspace m_workspace;
mean_field::mapping::VolumeMappingContext m_mapping_context;
mfem::DenseMatrix m_inverse_element_jacobian;
int m_cached_element_id{-1};
mean_field::mapping::MappingStatus m_mappingFailure{mean_field::mapping::MappingStatus::valid};
@@ -394,8 +393,8 @@ namespace mean_field::operators {
m_has_variation_data = false;
m_displacement_true.SetSize(m_displacement_map.full_size());
m_displacement_map.scatter(displacement, m_displacement_true);
m_elements.clear();
m_elements.reserve(m_fem.mesh->GetNE());
std::size_t prepared_element_count{0};
FrozenMappedGravitySourceCoefficient source_coefficient(m_fem, m_domain_mapper, m_displacement_true);
bool localNonFiniteQuadrature = false;
@@ -407,8 +406,10 @@ namespace mean_field::operators {
continue;
}
m_elements.emplace_back();
ElementPAData &data = m_elements.back();
if (prepared_element_count == m_elements.size()) {
m_elements.emplace_back();
}
ElementPAData &data = m_elements[prepared_element_count++];
data.element_id = element_id;
@@ -438,37 +439,59 @@ namespace mean_field::operators {
const int potential_dof_count = potential_element.GetDof();
data.density_basis.SetSize(quadrature_point_count, density_dof_count);
data.potential_basis.SetSize(quadrature_point_count, potential_dof_count);
if (density_element.GetMapType() == mfem::FiniteElement::VALUE) {
data.density_reference = m_fem.GetReferenceTables().GetScalarTable(density_element, integration_rule);
data.density_basis.SetSize(0, 0);
} else {
data.density_reference.reset();
data.density_basis.SetSize(quadrature_point_count, density_dof_count);
}
if (potential_element.GetMapType() == mfem::FiniteElement::VALUE) {
data.potential_reference =
m_fem.GetReferenceTables().GetScalarTable(potential_element, integration_rule);
data.potential_basis.SetSize(0, 0);
} else {
data.potential_reference.reset();
data.potential_basis.SetSize(quadrature_point_count, potential_dof_count);
}
const int dimension = m_fem.mesh->Dimension();
if (mode == PreparationMode::linearization) {
data.inverse_element_jacobians.SetSize(quadrature_point_count, dimension * dimension);
data.displacement_reference = m_fem.GetReferenceTables().GetScalarTable(
*m_fem.displacementFes->GetFE(element_id), integration_rule
);
}
data.quadrature_data.SetSize(quadrature_point_count);
mfem::Vector density_shape(density_dof_count);
mfem::Vector potential_shape(potential_dof_count);
mfem::Vector density_shape;
mfem::Vector potential_shape;
if (!data.density_reference) {
density_shape.SetSize(density_dof_count);
}
if (!data.potential_reference) {
potential_shape.SetSize(potential_dof_count);
}
for (int quadrature_point = 0; quadrature_point < quadrature_point_count; ++quadrature_point) {
const mfem::IntegrationPoint &integration_point = integration_rule.IntPoint(quadrature_point);
transformation.SetIntPoint(&integration_point);
// CalcPhysShape matches the scalar mixed-mass discretization,
// including the finite-element map type.
density_element.CalcPhysShape(transformation, density_shape);
potential_element.CalcPhysShape(transformation, potential_shape);
for (int i = 0; i < density_dof_count; ++i) {
data.density_basis(quadrature_point, i) = density_shape(i);
// VALUE maps use the shared reference basis. Preserve the
// physical-shape evaluation for every other scalar map type.
if (!data.density_reference) {
density_element.CalcPhysShape(transformation, density_shape);
for (int i = 0; i < density_dof_count; ++i) {
data.density_basis(quadrature_point, i) = density_shape(i);
}
}
for (int i = 0; i < potential_dof_count; ++i) {
data.potential_basis(quadrature_point, i) = potential_shape(i);
if (!data.potential_reference) {
potential_element.CalcPhysShape(transformation, potential_shape);
for (int i = 0; i < potential_dof_count; ++i) {
data.potential_basis(quadrature_point, i) = potential_shape(i);
}
}
const double coefficient_value = source_coefficient.Eval(transformation, integration_point);
@@ -505,6 +528,7 @@ namespace mean_field::operators {
break;
}
}
m_elements.resize(prepared_element_count);
const bool localNonFiniteArithmetic = source_coefficient.HasNonFiniteArithmetic() || localNonFiniteQuadrature;
auto preparationResult = synchronize_preparation_failure(
@@ -555,7 +579,7 @@ namespace mean_field::operators {
m_quadrature_action.SetSize(data.quadrature_data.Size());
// B_density * x_e
data.density_basis.Mult(m_element_input, m_quadrature_action);
data.GetDensityBasis().Mult(m_element_input, m_quadrature_action);
// D * B_density * x_e
for (int q = 0; q < m_quadrature_action.Size(); ++q) {
@@ -565,7 +589,7 @@ namespace mean_field::operators {
m_element_action.SetSize(data.potential_dofs.Size());
// B_potential^T * D * B_density * x_e
data.potential_basis.MultTranspose(m_quadrature_action, m_element_action);
data.GetPotentialBasis().MultTranspose(m_quadrature_action, m_element_action);
if (data.potential_dof_transformation != nullptr) {
data.potential_dof_transformation->TransformDual(m_element_action);
@@ -641,15 +665,15 @@ namespace mean_field::operators {
"Prepared gravity source inverse-Jacobian data has an incompatible size."
);
m_reference_displacement_dshape.SetSize(displacement_element.GetDof(), dimension);
m_reference_displacement_jacobian.SetSize(dimension, dimension);
m_quadrature_variation_action.SetSize(data.integration_rule->GetNPoints());
data.density_basis.Mult(m_element_density, m_quadrature_variation_action);
data.GetDensityBasis().Mult(m_element_density, m_quadrature_variation_action);
for (int quadrature_point = 0; quadrature_point < data.integration_rule->GetNPoints(); ++quadrature_point) {
const mfem::IntegrationPoint &integration_point = data.integration_rule->IntPoint(quadrature_point);
displacement_element.CalcDShape(integration_point, m_reference_displacement_dshape);
mfem::MultAtB(direction_dofs, m_reference_displacement_dshape, m_reference_displacement_jacobian);
mfem::MultAtB(
direction_dofs, data.displacement_reference->GetGradients(quadrature_point),
m_reference_displacement_jacobian
);
double logarithmic_jacobian_variation{0.0};
for (int row = 0; row < dimension; ++row) {
@@ -669,7 +693,7 @@ namespace mean_field::operators {
}
m_element_variation_action.SetSize(data.potential_dofs.Size());
data.potential_basis.MultTranspose(m_quadrature_variation_action, m_element_variation_action);
data.GetPotentialBasis().MultTranspose(m_quadrature_variation_action, m_element_variation_action);
if (data.potential_dof_transformation != nullptr) {
data.potential_dof_transformation->TransformDual(m_element_variation_action);
@@ -714,7 +738,7 @@ namespace mean_field::operators {
m_quadrature_action.SetSize(data.quadrature_data.Size());
data.potential_basis.Mult(m_element_input, m_quadrature_action);
data.GetPotentialBasis().Mult(m_element_input, m_quadrature_action);
for (int q = 0; q < m_quadrature_action.Size(); ++q) {
m_quadrature_action(q) *= data.quadrature_data(q);
@@ -722,7 +746,7 @@ namespace mean_field::operators {
m_element_action.SetSize(data.density_dofs.Size());
data.density_basis.MultTranspose(m_quadrature_action, m_element_action);
data.GetDensityBasis().MultTranspose(m_quadrature_action, m_element_action);
if (data.density_dof_transformation != nullptr) {
data.density_dof_transformation->TransformDual(m_element_action);

View File

@@ -13,6 +13,8 @@ module;
#include <mpi.h>
module mean_field;
import :fem.reference_tables;
import :operators.prepared_hdiv_mass;
namespace {
@@ -551,6 +553,15 @@ namespace mean_field::operators {
);
data.integrationRule = &get_hdiv_mass_rule(m_fem, m_domain_mapper, gravityGradientElement, *transformation);
const int dimension = m_domain_mapper.GetDimension();
if (gravityGradientElement.GetMapType() == mfem::FiniteElement::H_DIV &&
gravityGradientElement.GetDim() == dimension && gravityGradientElement.GetRangeDim() == dimension &&
transformation->GetSpaceDim() == dimension) {
data.gravityReferenceTable =
m_fem.GetReferenceTables().GetVectorTable(gravityGradientElement, *data.integrationRule);
data.meshPiolaJacobians.SetSize(data.integrationRule->GetNPoints(), dimension * dimension);
data.referenceWeights.SetSize(data.integrationRule->GetNPoints());
}
data.frozenMappingData.SetSize(
data.integrationRule->GetNPoints(), frozen_mapping_width(m_domain_mapper.GetDimension())
);
@@ -573,6 +584,25 @@ namespace mean_field::operators {
return status;
}
freeze_mapping_context(mappingContext, quadraturePoint, data.frozenMappingData);
if (data.gravityReferenceTable != nullptr) {
// CalcVShape_RT = reference_shape * J_mesh^T / Weight.
// Cache only this small factor, never the mapped basis.
const double meshWeight = transformation->Weight();
const mfem::DenseMatrix &meshJacobian = transformation->Jacobian();
const double inverseMeshWeight = 1.0 / meshWeight;
data.referenceWeights(quadraturePoint) = integrationPoint.weight * meshWeight;
for (int row = 0; row < dimension; ++row) {
for (int column = 0; column < dimension; ++column) {
const double entry = inverseMeshWeight * meshJacobian(row, column);
if (!std::isfinite(entry))
return mapping::MappingStatus::non_finite_result;
data.meshPiolaJacobians(quadraturePoint, row * dimension + column) = entry;
}
}
if (!std::isfinite(data.referenceWeights(quadraturePoint))) {
return mapping::MappingStatus::non_finite_result;
}
}
}
}
return mapping::MappingStatus::valid;
@@ -830,7 +860,10 @@ namespace mean_field::operators {
m_elementVariationAction.SetSize(gravityGradientElement.GetDof());
m_elementVariationAction = 0.0;
m_gravityGradientValue.SetSize(dimension);
m_gravityReferenceCellValue.SetSize(dimension);
m_referenceCellDual.SetSize(dimension);
m_massTensorVariationAction.SetSize(dimension);
m_meshPiolaJacobian.SetSize(dimension, dimension);
m_gravityGradientShape.SetSize(gravityGradientElement.GetDof(), dimension);
m_massTensorVariation.SetSize(dimension, dimension);
@@ -853,12 +886,33 @@ namespace mean_field::operators {
m_baseMappingContext.mapping, m_mappingVariation.mapping, m_massTensorVariation
);
transformation->SetIntPoint(&integrationPoint);
gravityGradientElement.CalcVShape(*transformation, m_gravityGradientShape);
m_gravityGradientShape.MultTranspose(m_elementGravityGradient, m_gravityGradientValue);
m_massTensorVariation.Mult(m_gravityGradientValue, m_massTensorVariationAction);
const double referenceWeight = integrationPoint.weight * transformation->Weight();
m_gravityGradientShape.AddMult(m_massTensorVariationAction, m_elementVariationAction, referenceWeight);
if (data.gravityReferenceTable != nullptr) {
const mfem::DenseMatrix &referenceShape = data.gravityReferenceTable->GetValues(quadraturePoint);
referenceShape.MultTranspose(m_elementGravityGradient, m_gravityReferenceCellValue);
for (int row = 0; row < dimension; ++row) {
for (int column = 0; column < dimension; ++column) {
m_meshPiolaJacobian(row, column) =
data.meshPiolaJacobians(quadraturePoint, row * dimension + column);
}
}
m_meshPiolaJacobian.Mult(m_gravityReferenceCellValue, m_gravityGradientValue);
m_massTensorVariation.Mult(m_gravityGradientValue, m_massTensorVariationAction);
// Move the test-side Piola transform onto the three-vector
// dual before applying the reference basis transpose.
m_meshPiolaJacobian.MultTranspose(m_massTensorVariationAction, m_referenceCellDual);
referenceShape.AddMult(
m_referenceCellDual, m_elementVariationAction, data.referenceWeights(quadraturePoint)
);
} else {
transformation->SetIntPoint(&integrationPoint);
gravityGradientElement.CalcVShape(*transformation, m_gravityGradientShape);
m_gravityGradientShape.MultTranspose(m_elementGravityGradient, m_gravityGradientValue);
m_massTensorVariation.Mult(m_gravityGradientValue, m_massTensorVariationAction);
const double referenceWeight = integrationPoint.weight * transformation->Weight();
m_gravityGradientShape.AddMult(
m_massTensorVariationAction, m_elementVariationAction, referenceWeight
);
}
}
if (data.gravityGradientDofTransformation != nullptr) {

View File

@@ -488,9 +488,6 @@ namespace mean_field::operators {
m_elements.clear();
m_elements.reserve(m_fem.mesh->GetNE());
mfem::Vector enthalpyShape;
mfem::Vector gravityPotentialShape;
for (int elementId = 0; elementId < m_fem.mesh->GetNE(); ++elementId) {
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(elementId);
@@ -528,34 +525,10 @@ namespace mean_field::operators {
data.integrationRule =
&get_hydrostatic_rule(m_fem, enthalpyElement, gravityPotentialElement, *transformation);
const int quadraturePointCount = data.integrationRule->GetNPoints();
const int enthalpyDofCount = enthalpyElement.GetDof();
const int gravityPotentialDofCount = gravityPotentialElement.GetDof();
data.enthalpyBasis.SetSize(quadraturePointCount, enthalpyDofCount);
data.gravityPotentialBasis.SetSize(quadraturePointCount, gravityPotentialDofCount);
enthalpyShape.SetSize(enthalpyDofCount);
gravityPotentialShape.SetSize(gravityPotentialDofCount);
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
gravityPotentialElement.CalcShape(integrationPoint, gravityPotentialShape);
for (int dof = 0; dof < enthalpyDofCount; ++dof) {
data.enthalpyBasis(quadraturePoint, dof) = enthalpyShape(dof);
}
for (int dof = 0; dof < gravityPotentialDofCount; ++dof) {
data.gravityPotentialBasis(quadraturePoint, dof) = gravityPotentialShape(dof);
}
}
const fem::ReferenceTableCache &referenceTables = m_fem.GetReferenceTables();
data.enthalpyReferenceTable = referenceTables.GetScalarTable(enthalpyElement, *data.integrationRule);
data.gravityPotentialReferenceTable =
referenceTables.GetScalarTable(gravityPotentialElement, *data.integrationRule);
}
}
@@ -565,6 +538,7 @@ namespace mean_field::operators {
true_to_local(*m_fem.displacementFes, m_context.GetDisplacementTrue(), displacementLocal);
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingContext mappingContext;
mfem::Array<int> compactificationDofs;
@@ -615,16 +589,14 @@ namespace mean_field::operators {
data.quadratureWeights.SetSize(quadraturePointCount);
data.baseMappingContexts.resize(quadraturePointCount);
data.baseMappingContexts.SetSize(quadraturePointCount, m_fem.mesh->Dimension());
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
transformation->SetIntPoint(&integrationPoint);
mapping::VolumeMappingContext &mappingContext = data.baseMappingContexts[quadraturePoint];
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolume(
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolume(
mappingData, *transformation, integrationPoint, workspace, mappingContext
);
@@ -641,6 +613,7 @@ namespace mean_field::operators {
return mapping::MappingStatus::non_positive_determinant;
}
data.baseMappingContexts.Store(quadraturePoint, mappingContext);
data.quadratureWeights(quadraturePoint) = quadratureWeight;
for (int component = 0; component < m_fem.mesh->Dimension(); ++component) {
@@ -660,15 +633,17 @@ namespace mean_field::operators {
bool PreparedHydrostaticEquilibriumOperator::PrepareAlgebraicJacobianBlocks() {
for (ElementPAData &data : m_elements) {
const int quadraturePointCount = data.quadratureWeights.Size();
const mfem::DenseMatrix &enthalpyBasis = data.GetEnthalpyBasis();
const mfem::DenseMatrix &gravityPotentialBasis = data.GetGravityPotentialBasis();
const int quadraturePointCount = data.quadratureWeights.Size();
const int enthalpyDofCount = data.enthalpyBasis.Width();
const int enthalpyDofCount = enthalpyBasis.Width();
const int gravityPotentialDofCount = data.gravityPotentialBasis.Width();
const int gravityPotentialDofCount = gravityPotentialBasis.Width();
MFEM_VERIFY(
data.enthalpyBasis.Height() == quadraturePointCount &&
data.gravityPotentialBasis.Height() == quadraturePointCount,
enthalpyBasis.Height() == quadraturePointCount &&
gravityPotentialBasis.Height() == quadraturePointCount,
"Prepared hydrostatic algebraic Jacobian has "
"inconsistent quadrature data."
);
@@ -687,18 +662,18 @@ namespace mean_field::operators {
const double quadratureWeight = data.quadratureWeights(quadraturePoint);
for (int testDof = 0; testDof < enthalpyDofCount; ++testDof) {
const double weightedTestBasis = quadratureWeight * data.enthalpyBasis(quadraturePoint, testDof);
const double weightedTestBasis = quadratureWeight * enthalpyBasis(quadraturePoint, testDof);
data.bernoulliConstantJacobian(testDof) -= weightedTestBasis;
for (int trialDof = 0; trialDof < enthalpyDofCount; ++trialDof) {
data.enthalpyJacobian(testDof, trialDof) +=
weightedTestBasis * data.enthalpyBasis(quadraturePoint, trialDof);
weightedTestBasis * enthalpyBasis(quadraturePoint, trialDof);
}
for (int trialDof = 0; trialDof < gravityPotentialDofCount; ++trialDof) {
data.gravityPotentialJacobian(testDof, trialDof) +=
weightedTestBasis * data.gravityPotentialBasis(quadraturePoint, trialDof);
weightedTestBasis * gravityPotentialBasis(quadraturePoint, trialDof);
}
}
}
@@ -795,9 +770,9 @@ namespace mean_field::operators {
quadratureGravityPotential.SetSize(quadraturePointCount);
data.enthalpyBasis.Mult(elementEnthalpy, quadratureEnthalpy);
data.GetEnthalpyBasis().Mult(elementEnthalpy, quadratureEnthalpy);
data.gravityPotentialBasis.Mult(elementGravityPotential, quadratureGravityPotential);
data.GetGravityPotentialBasis().Mult(elementGravityPotential, quadratureGravityPotential);
MFEM_VERIFY(
data.rotationPotential.Size() == quadraturePointCount, "Prepared hydrostatic base state has stale "
@@ -836,7 +811,8 @@ namespace mean_field::operators {
MFEM_VERIFY(
data.baseDisplacementData.has_value() && data.compactificationData.has_value() &&
static_cast<int>(data.baseMappingContexts.size()) == quadraturePointCount &&
data.baseMappingContexts.GetPointCount() == quadraturePointCount &&
data.baseMappingContexts.GetDimension() == dimension &&
data.rotationGradient.Height() == quadraturePointCount &&
data.rotationGradient.Width() == dimension &&
data.hydrostaticImbalance.Size() == quadraturePointCount,
@@ -855,7 +831,7 @@ namespace mean_field::operators {
for (const ElementPAData &data : m_elements) {
elementResidual.SetSize(data.enthalpyDofs.Size());
data.enthalpyBasis.MultTranspose(data.weightedResidual, elementResidual);
data.GetEnthalpyBasis().MultTranspose(data.weightedResidual, elementResidual);
if (data.enthalpyDofTransformation != nullptr) {
data.enthalpyDofTransformation->TransformDual(elementResidual);
@@ -1072,7 +1048,7 @@ namespace mean_field::operators {
data.rotationPotential(quadraturePoint);
}
elementAction.SetSize(data.enthalpyDofs.Size());
data.enthalpyBasis.MultTranspose(weightedVariation, elementAction);
data.GetEnthalpyBasis().MultTranspose(weightedVariation, elementAction);
if (data.enthalpyDofTransformation != nullptr) {
data.enthalpyDofTransformation->TransformDual(elementAction);
}
@@ -1204,6 +1180,7 @@ namespace mean_field::operators {
mfem::Vector elementDisplacementVariation;
mfem::Vector weightedQuadratureVariation;
mfem::Vector elementAction;
mapping::VolumeMappingContext mappingContext;
mapping::VolumeMappingVariation variation;
for (const ElementPAData &data : m_elements) {
@@ -1239,7 +1216,7 @@ namespace mean_field::operators {
const int quadraturePointCount = data.integrationRule->GetNPoints();
MFEM_VERIFY(
static_cast<int>(data.baseMappingContexts.size()) == quadraturePointCount &&
data.baseMappingContexts.GetPointCount() == quadraturePointCount &&
data.quadratureWeights.Size() == quadraturePointCount &&
data.hydrostaticImbalance.Size() == quadraturePointCount &&
data.rotationGradient.Height() == quadraturePointCount &&
@@ -1252,10 +1229,10 @@ namespace mean_field::operators {
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
data.baseMappingContexts.Load(quadraturePoint, mappingContext);
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolumeVariation(
mappingData, directionData, *transformation, integrationPoint,
data.baseMappingContexts[quadraturePoint], workspace, variation
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolumeVariation(
mappingData, directionData, *transformation, integrationPoint, mappingContext, workspace, variation
);
MFEM_VERIFY(
@@ -1288,7 +1265,7 @@ namespace mean_field::operators {
elementAction.SetSize(data.enthalpyDofs.Size());
data.enthalpyBasis.MultTranspose(weightedQuadratureVariation, elementAction);
data.GetEnthalpyBasis().MultTranspose(weightedQuadratureVariation, elementAction);
if (data.enthalpyDofTransformation != nullptr) {
data.enthalpyDofTransformation->TransformDual(elementAction);

View File

@@ -420,17 +420,12 @@ namespace mean_field::operators {
const mfem::IntegrationRule &integrationRule =
get_mass_normalization_rule(m_fem, densityElement, *transformation);
data.integrationRule = &integrationRule;
data.quadraturePoints.resize(integrationRule.GetNPoints());
for (int quadraturePoint = 0; quadraturePoint < integrationRule.GetNPoints(); ++quadraturePoint) {
QuadraturePointData &point = data.quadraturePoints[quadraturePoint];
point.integrationPoint = integrationRule.IntPoint(quadraturePoint);
point.densityShape.SetSize(densityElement.GetDof());
densityElement.CalcShape(point.integrationPoint, point.densityShape);
}
data.densityBasis = m_fem.GetReferenceTables().GetScalarTable(densityElement, integrationRule);
data.mappingContexts.SetSize(integrationRule.GetNPoints(), m_fem.mesh->Dimension());
data.density.SetSize(integrationRule.GetNPoints());
data.quadratureWeights.SetSize(integrationRule.GetNPoints());
}
int globalStellarElementCount = 0;
@@ -459,6 +454,7 @@ namespace mean_field::operators {
true_to_local(*m_fem.displacementFes, displacement, displacementLocal);
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingContext mappingContext;
std::optional<MassNormalizationPreparationRejection> rejection;
for (ElementPAData &data : m_elements) {
@@ -491,9 +487,10 @@ namespace mean_field::operators {
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
for (QuadraturePointData &point : data.quadraturePoints) {
for (int quadraturePoint = 0; quadraturePoint < data.integrationRule->GetNPoints(); ++quadraturePoint) {
const mapping::MappingStatus status = m_domainMapper.EvaluateVolume(
mappingData, *transformation, point.integrationPoint, workspace, point.mappingContext
mappingData, *transformation, data.integrationRule->IntPoint(quadraturePoint), workspace,
mappingContext
);
MFEM_VERIFY(
@@ -505,6 +502,9 @@ namespace mean_field::operators {
rejection, {.reason = MassNormalizationPreparationRejectionReason::mapping_failure,
.mappingStatus = status}
);
} else {
data.mappingContexts.Store(quadraturePoint, mappingContext);
data.quadratureWeights(quadraturePoint) = mappingContext.quadrature.weight;
}
}
}
@@ -537,9 +537,9 @@ namespace mean_field::operators {
data.densityDofTransformation->InvTransformPrimal(elementDensity);
}
for (QuadraturePointData &point : data.quadraturePoints) {
point.density = elementDensity * point.densityShape;
if (!std::isfinite(point.density)) {
data.densityBasis->GetValues().Mult(elementDensity, data.density);
for (int quadraturePoint = 0; quadraturePoint < data.density.Size(); ++quadraturePoint) {
if (!std::isfinite(data.density(quadraturePoint))) {
retain_higher_priority_rejection(
rejection,
{.reason = MassNormalizationPreparationRejectionReason::non_finite_density_interpolation}
@@ -556,8 +556,8 @@ namespace mean_field::operators {
std::optional<MassNormalizationPreparationRejection> localRejection;
for (const ElementPAData &data : m_elements) {
for (const QuadraturePointData &point : data.quadraturePoints) {
const double contribution = point.density * point.mappingContext.quadrature.weight;
for (int quadraturePoint = 0; quadraturePoint < data.density.Size(); ++quadraturePoint) {
const double contribution = data.density(quadraturePoint) * data.quadratureWeights(quadraturePoint);
if (!std::isfinite(contribution) || !std::isfinite(localMass + contribution)) {
localRejection = {.reason = MassNormalizationPreparationRejectionReason::non_finite_assembled_mass};
continue;
@@ -615,6 +615,7 @@ namespace mean_field::operators {
true_to_local(*m_fem.densityFes, densityVariation, densityVariationLocal);
mfem::Vector elementDensityVariation;
mfem::Vector quadratureDensityVariation;
double localAction = 0.0;
for (const ElementPAData &data : m_elements) {
@@ -624,8 +625,10 @@ namespace mean_field::operators {
data.densityDofTransformation->InvTransformPrimal(elementDensityVariation);
}
for (const QuadraturePointData &point : data.quadraturePoints) {
localAction += (elementDensityVariation * point.densityShape) * point.mappingContext.quadrature.weight;
quadratureDensityVariation.SetSize(data.integrationRule->GetNPoints());
data.densityBasis->GetValues().Mult(elementDensityVariation, quadratureDensityVariation);
for (int quadraturePoint = 0; quadraturePoint < quadratureDensityVariation.Size(); ++quadraturePoint) {
localAction += quadratureDensityVariation(quadraturePoint) * data.quadratureWeights(quadraturePoint);
}
}
@@ -650,6 +653,7 @@ namespace mean_field::operators {
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingVariation variation;
mapping::VolumeMappingContext mappingContext;
mfem::Vector elementDisplacementVariation;
double localAction = 0.0;
@@ -681,10 +685,11 @@ namespace mean_field::operators {
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
for (const QuadraturePointData &point : data.quadraturePoints) {
for (int quadraturePoint = 0; quadraturePoint < data.integrationRule->GetNPoints(); ++quadraturePoint) {
data.mappingContexts.Load(quadraturePoint, mappingContext);
const mapping::MappingStatus status = m_domainMapper.EvaluateVolumeVariation(
mappingData, directionData, *transformation, point.integrationPoint, point.mappingContext,
workspace, variation
mappingData, directionData, *transformation, data.integrationRule->IntPoint(quadraturePoint),
mappingContext, workspace, variation
);
MFEM_VERIFY(
@@ -694,7 +699,7 @@ namespace mean_field::operators {
<< ", status: " << static_cast<int>(status)
);
localAction += point.density * variation.weight_variation;
localAction += data.density(quadraturePoint) * variation.weight_variation;
}
}
@@ -789,14 +794,13 @@ namespace mean_field::operators {
localDual = 0.0;
mfem::Vector elementDual;
mfem::Vector weightedDual;
for (const ElementPAData &data : m_elements) {
elementDual.SetSize(data.densityDofs.Size());
elementDual = 0.0;
for (const QuadraturePointData &point : data.quadraturePoints) {
elementDual.Add(residualDual * point.mappingContext.quadrature.weight, point.densityShape);
}
weightedDual = data.quadratureWeights;
weightedDual *= residualDual;
data.densityBasis->GetValues().MultTranspose(weightedDual, elementDual);
if (data.densityDofTransformation != nullptr) {
data.densityDofTransformation->TransformDual(elementDual);
@@ -821,6 +825,7 @@ namespace mean_field::operators {
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingVariation variation;
mapping::VolumeMappingContext mappingContext;
mfem::Vector elementDirection;
mfem::Vector elementDual;
@@ -852,10 +857,11 @@ namespace mean_field::operators {
double elementDofAction = 0.0;
for (const QuadraturePointData &point : data.quadraturePoints) {
for (int quadraturePoint = 0; quadraturePoint < data.integrationRule->GetNPoints(); ++quadraturePoint) {
data.mappingContexts.Load(quadraturePoint, mappingContext);
const mapping::MappingStatus status = m_domainMapper.EvaluateVolumeVariation(
mappingData, directionData, *transformation, point.integrationPoint, point.mappingContext,
workspace, variation
mappingData, directionData, *transformation, data.integrationRule->IntPoint(quadraturePoint),
mappingContext, workspace, variation
);
MFEM_VERIFY(
@@ -864,7 +870,7 @@ namespace mean_field::operators {
<< data.elementId << ", status: " << static_cast<int>(status)
);
elementDofAction += point.density * variation.weight_variation;
elementDofAction += data.density(quadraturePoint) * variation.weight_variation;
}
elementDual(elementDof) = residualDual * elementDofAction;

View File

@@ -492,9 +492,6 @@ namespace mean_field::operators {
m_elements.reserve(m_fem.mesh->GetNE());
mfem::Vector enthalpyShape;
mfem::DenseMatrix displacementDShape;
for (int elementId = 0; elementId < m_fem.mesh->GetNE(); ++elementId) {
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(elementId);
@@ -559,29 +556,11 @@ namespace mean_field::operators {
"an unexpected vector DOF count."
);
data.enthalpyBasis.SetSize(quadraturePointCount, enthalpyDofCount);
data.referenceTestGradients.resize(quadraturePointCount);
const fem::ReferenceTableCache &referenceTables = m_fem.GetReferenceTables();
data.enthalpyReferenceTable = referenceTables.GetScalarTable(enthalpyElement, *data.integrationRule);
data.displacementReferenceTable =
referenceTables.GetScalarTable(displacementElement, *data.integrationRule);
data.physicalTestGradients.resize(quadraturePointCount);
enthalpyShape.SetSize(enthalpyDofCount);
displacementDShape.SetSize(scalarDisplacementDofCount, dimension);
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
enthalpyElement.CalcShape(integrationPoint, enthalpyShape);
displacementElement.CalcDShape(integrationPoint, displacementDShape);
for (int enthalpyDof = 0; enthalpyDof < enthalpyDofCount; ++enthalpyDof) {
data.enthalpyBasis(quadraturePoint, enthalpyDof) = enthalpyShape(enthalpyDof);
}
data.referenceTestGradients[quadraturePoint] = displacementDShape;
}
}
}
@@ -591,6 +570,7 @@ namespace mean_field::operators {
true_to_local(*m_fem.displacementFes, m_baseDisplacementTrue, displacementLocal);
mapping::DomainMapper::Workspace workspace(m_fem.mesh->Dimension());
mapping::VolumeMappingContext mappingContext;
mfem::Vector elementDisplacement;
mfem::Vector elementCompactification;
@@ -634,14 +614,15 @@ namespace mean_field::operators {
const int quadraturePointCount = data.integrationRule->GetNPoints();
MFEM_VERIFY(
static_cast<int>(data.referenceTestGradients.size()) == quadraturePointCount,
data.displacementReferenceTable != nullptr &&
data.displacementReferenceTable->GetPointCount() == quadraturePointCount,
"Prepared pressure-force geometry has inconsistent "
"static gradient data."
);
data.quadratureWeights.SetSize(quadraturePointCount);
data.baseMappingContexts.resize(quadraturePointCount);
data.baseMappingContexts.SetSize(quadraturePointCount, m_fem.mesh->Dimension());
data.physicalTestGradients.resize(quadraturePointCount);
@@ -650,9 +631,7 @@ namespace mean_field::operators {
transformation->SetIntPoint(&integrationPoint);
mapping::VolumeMappingContext &mappingContext = data.baseMappingContexts[quadraturePoint];
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolume(
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolume(
mappingData, *transformation, integrationPoint, workspace, mappingContext
);
@@ -669,11 +648,13 @@ namespace mean_field::operators {
return mapping_rejection(mapping::MappingStatus::non_positive_determinant);
}
data.quadratureWeights(quadraturePoint) = quadratureWeight;
data.baseMappingContexts.Store(quadraturePoint, mappingContext);
data.quadratureWeights(quadraturePoint) = quadratureWeight;
const mfem::DenseMatrix &referenceTestGradient = data.referenceTestGradients[quadraturePoint];
const mfem::DenseMatrix &referenceTestGradient =
data.displacementReferenceTable->GetGradients(quadraturePoint);
mfem::DenseMatrix &physicalTestGradient = data.physicalTestGradients[quadraturePoint];
mfem::DenseMatrix &physicalTestGradient = data.physicalTestGradients[quadraturePoint];
MFEM_VERIFY(
referenceTestGradient.Width() == mappingContext.quadrature.J_inv.Height() &&
@@ -714,9 +695,11 @@ namespace mean_field::operators {
data.enthalpyDofTransformation->InvTransformPrimal(elementEnthalpy);
}
const int quadraturePointCount = data.enthalpyBasis.Height();
const mfem::DenseMatrix &enthalpyBasis = data.GetEnthalpyBasis();
const int enthalpyDofCount = data.enthalpyBasis.Width();
const int quadraturePointCount = enthalpyBasis.Height();
const int enthalpyDofCount = enthalpyBasis.Width();
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(data.elementId);
@@ -734,7 +717,7 @@ namespace mean_field::operators {
quadratureEnthalpy.SetSize(quadraturePointCount);
data.enthalpyBasis.Mult(elementEnthalpy, quadratureEnthalpy);
enthalpyBasis.Mult(elementEnthalpy, quadratureEnthalpy);
data.pressure.SetSize(quadraturePointCount);
@@ -814,8 +797,8 @@ namespace mean_field::operators {
data.elementResidual(vectorDof) -= residualContribution;
for (int enthalpyDof = 0; enthalpyDof < enthalpyDofCount; ++enthalpyDof) {
const double jacobianContribution = pressureDerivative * weightedTestGradient *
data.enthalpyBasis(quadraturePoint, enthalpyDof);
const double jacobianContribution =
pressureDerivative * weightedTestGradient * enthalpyBasis(quadraturePoint, enthalpyDof);
if (!std::isfinite(jacobianContribution)) {
materialFailure = non_finite_rejection();
continue;
@@ -841,8 +824,10 @@ namespace mean_field::operators {
MFEM_VERIFY(
data.baseDisplacementData.has_value() && data.compactificationData.has_value() &&
static_cast<int>(data.baseMappingContexts.size()) == quadraturePointCount &&
static_cast<int>(data.referenceTestGradients.size()) == quadraturePointCount &&
data.baseMappingContexts.GetPointCount() == quadraturePointCount &&
data.baseMappingContexts.GetDimension() == dimension &&
data.displacementReferenceTable != nullptr &&
data.displacementReferenceTable->GetPointCount() == quadraturePointCount &&
static_cast<int>(data.physicalTestGradients.size()) == quadraturePointCount &&
data.quadratureWeights.Size() == quadraturePointCount &&
data.pressure.Size() == quadraturePointCount,
@@ -852,7 +837,7 @@ namespace mean_field::operators {
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
MFEM_VERIFY(
data.referenceTestGradients[quadraturePoint].Width() == dimension &&
data.displacementReferenceTable->GetGradients(quadraturePoint).Width() == dimension &&
data.physicalTestGradients[quadraturePoint].Width() == dimension,
"Prepared pressure-force displacement Jacobian has "
"a gradient with the wrong dimension."
@@ -978,6 +963,7 @@ namespace mean_field::operators {
mfem::Vector elementAction;
mfem::DenseMatrix referenceDisplacementJacobian;
mfem::DenseMatrix inverseElementJacobian;
mfem::DenseMatrix inverseElementJacobianVariation;
mfem::DenseMatrix matrixTemporary;
mfem::DenseMatrix physicalTestGradientVariation;
@@ -1016,7 +1002,7 @@ namespace mean_field::operators {
);
MFEM_VERIFY(
static_cast<int>(data.baseMappingContexts.size()) == quadraturePointCount &&
data.baseMappingContexts.GetPointCount() == quadraturePointCount &&
data.pressure.Size() == quadraturePointCount,
"Prepared pressure-force displacement Jacobian has "
"stale quadrature data."
@@ -1032,12 +1018,12 @@ namespace mean_field::operators {
physicalTestGradientVariation.SetSize(scalarDisplacementDofCount, dimension);
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
const mfem::DenseMatrix &referenceTestGradient = data.referenceTestGradients[quadraturePoint];
const mfem::DenseMatrix &referenceTestGradient =
data.displacementReferenceTable->GetGradients(quadraturePoint);
mfem::MultAtB(directionDofs, referenceTestGradient, referenceDisplacementJacobian);
const mfem::DenseMatrix &inverseElementJacobian =
data.baseMappingContexts[quadraturePoint].quadrature.J_inv;
data.baseMappingContexts.LoadInverseJacobian(quadraturePoint, inverseElementJacobian);
mfem::Mult(inverseElementJacobian, referenceDisplacementJacobian, matrixTemporary);
double logarithmicJacobianVariation{0.0};

View File

@@ -1068,6 +1068,29 @@ namespace mean_field::operators {
return m_generatedVolumeDisplacement;
}
void PreparedStellarEquilibriumOperator::BuildVolumeDisplacementDirection(
const mfem::Vector &surfaceDeformationDirection,
mfem::Vector &volumeDisplacementDirection
) const {
VerifyPrepared();
MFEM_VERIFY(
surfaceDeformationDirection.Size() == m_domainDeformation.parameterCount(),
"PreparedStellarEquilibriumOperator received a surface-deformation direction with the wrong size."
);
validate_finite_vector(
surfaceDeformationDirection,
"PreparedStellarEquilibriumOperator received a non-finite surface-deformation direction."
);
MFEM_VERIFY(
volumeDisplacementDirection.Size() == m_domainDeformation.volumeDisplacementSize(),
"PreparedStellarEquilibriumOperator received a volume-displacement workspace with the wrong size."
);
m_domainDeformation.applyJacobian(
m_surfaceDeformationParameters, surfaceDeformationDirection, volumeDisplacementDirection
);
}
const mfem::Vector &PreparedStellarEquilibriumOperator::GetFullMechanicalResidual() const {
VerifyPrepared();
return m_fullMechanicalResidual;