Snapshot optimized solver and audit diagnostics before numerical experiments
This commit is contained in:
@@ -11,6 +11,7 @@ module;
|
||||
#include <utility>
|
||||
|
||||
#include <mfem.hpp>
|
||||
#include "interior_displacement_contractions.hpp"
|
||||
|
||||
module mean_field;
|
||||
|
||||
@@ -384,7 +385,30 @@ namespace mean_field::operators {
|
||||
const context::hydrostatic::HydrostaticEquilibriumDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
) {
|
||||
const bool wasPrepared = m_isPrepared;
|
||||
return TryPrepareImpl(state, dependencies, rotation, true);
|
||||
}
|
||||
HydrostaticEquilibriumPreparationResult PreparedHydrostaticEquilibriumOperator::TryPrepareReference(
|
||||
const context::hydrostatic::HydrostaticEquilibriumStateView &state,
|
||||
const context::hydrostatic::HydrostaticEquilibriumDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
) {
|
||||
return TryPrepareImpl(state, dependencies, rotation, false);
|
||||
}
|
||||
PreparedHydrostaticEquilibriumReport PreparedHydrostaticEquilibriumOperator::PrepareReference(
|
||||
const context::hydrostatic::HydrostaticEquilibriumStateView &state,
|
||||
const context::hydrostatic::HydrostaticEquilibriumDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation
|
||||
) {
|
||||
auto result = TryPrepareReference(state, dependencies, rotation);
|
||||
if (!result.has_value()) throwHydrostaticEquilibriumPreparationRejection(result.error());
|
||||
return std::move(result).value();
|
||||
}
|
||||
HydrostaticEquilibriumPreparationResult PreparedHydrostaticEquilibriumOperator::TryPrepareImpl(
|
||||
const context::hydrostatic::HydrostaticEquilibriumStateView &state,
|
||||
const context::hydrostatic::HydrostaticEquilibriumDependencies &dependencies,
|
||||
const physics::RigidRotation &rotation, const bool useTensorPreparation
|
||||
) {
|
||||
const bool wasPrepared = m_isPrepared && m_preparedWithTensorPreparation == useTensorPreparation;
|
||||
const bool rotationObjectChanged =
|
||||
!wasPrepared || !m_context.IsPrepared() || dependencies.rotation != m_context.GetDependencies().rotation;
|
||||
|
||||
@@ -409,7 +433,7 @@ namespace mean_field::operators {
|
||||
}
|
||||
|
||||
if (report.contextReport.preparedGeometryState || !wasPrepared) {
|
||||
const auto mappingFailure = synchronize_mapping_failure(PrepareGeometry(), m_fem.mesh->GetComm());
|
||||
const auto mappingFailure = synchronize_mapping_failure(PrepareGeometry(useTensorPreparation), m_fem.mesh->GetComm());
|
||||
if (mappingFailure.has_value()) {
|
||||
const auto reason = *mappingFailure == mapping::MappingStatus::non_positive_determinant
|
||||
? HydrostaticEquilibriumPreparationRejectionReason::inverted_geometry
|
||||
@@ -419,7 +443,7 @@ namespace mean_field::operators {
|
||||
);
|
||||
}
|
||||
|
||||
if (synchronize_non_finite_failure(PrepareAlgebraicJacobianBlocks(), m_fem.mesh->GetComm())) {
|
||||
if (synchronize_non_finite_failure(PrepareAlgebraicJacobianBlocks(useTensorPreparation), m_fem.mesh->GetComm())) {
|
||||
return std::unexpected(
|
||||
HydrostaticEquilibriumPreparationRejection{
|
||||
.reason = HydrostaticEquilibriumPreparationRejectionReason::non_finite_geometry,
|
||||
@@ -441,7 +465,7 @@ namespace mean_field::operators {
|
||||
}
|
||||
|
||||
if (report.contextReport.preparedBaseState || !wasPrepared) {
|
||||
if (synchronize_non_finite_failure(PrepareBaseState(), m_fem.mesh->GetComm())) {
|
||||
if (synchronize_non_finite_failure(PrepareBaseState(useTensorPreparation), m_fem.mesh->GetComm())) {
|
||||
return std::unexpected(
|
||||
HydrostaticEquilibriumPreparationRejection{
|
||||
.reason = HydrostaticEquilibriumPreparationRejectionReason::non_finite_residual
|
||||
@@ -480,6 +504,7 @@ namespace mean_field::operators {
|
||||
++m_residualPreparationCount;
|
||||
}
|
||||
|
||||
m_preparedWithTensorPreparation = useTensorPreparation;
|
||||
m_isPrepared = true;
|
||||
return report;
|
||||
}
|
||||
@@ -529,10 +554,18 @@ namespace mean_field::operators {
|
||||
data.enthalpyReferenceTable = referenceTables.GetScalarTable(enthalpyElement, *data.integrationRule);
|
||||
data.gravityPotentialReferenceTable =
|
||||
referenceTables.GetScalarTable(gravityPotentialElement, *data.integrationRule);
|
||||
const auto &displacementElement = *m_fem.displacementFes->GetFE(elementId);
|
||||
if (m_fem.mesh->Dimension() == 3 &&
|
||||
displacementElement.GetMapType() == mfem::FiniteElement::VALUE &&
|
||||
displacementElement.GetDerivType() == mfem::FiniteElement::GRAD &&
|
||||
!m_domainMapper.IsCompactifiedElement(*transformation)) {
|
||||
data.displacementReferenceTable =
|
||||
referenceTables.GetScalarTable(displacementElement, *data.integrationRule);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::optional<mapping::MappingStatus> PreparedHydrostaticEquilibriumOperator::PrepareGeometry() {
|
||||
std::optional<mapping::MappingStatus> PreparedHydrostaticEquilibriumOperator::PrepareGeometry(const bool useTensorPreparation) {
|
||||
mfem::Vector displacementLocal;
|
||||
|
||||
true_to_local(*m_fem.displacementFes, m_context.GetDisplacementTrue(), displacementLocal);
|
||||
@@ -544,6 +577,8 @@ namespace mean_field::operators {
|
||||
|
||||
mfem::Vector elementDisplacement;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector sampleValue(3), tensorWorkspace;
|
||||
mfem::DenseMatrix sampleGradient(3), tensorSamples;
|
||||
|
||||
for (ElementPAData &data : m_elements) {
|
||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
|
||||
@@ -590,14 +625,27 @@ namespace mean_field::operators {
|
||||
data.quadratureWeights.SetSize(quadraturePointCount);
|
||||
|
||||
data.baseMappingContexts.SetSize(quadraturePointCount, m_fem.mesh->Dimension());
|
||||
if (data.displacementReferenceTable != nullptr)
|
||||
data.displacementInverseJacobians.SetSize(9, quadraturePointCount);
|
||||
|
||||
const bool tensor = useTensorPreparation && data.displacementReferenceTable &&
|
||||
data.displacementReferenceTable->HasTensorEvaluation3D();
|
||||
if (tensor) data.displacementReferenceTable->EvaluateTensor3D(
|
||||
data.baseDisplacementData->GetDofMatrix(), tensorSamples, tensorWorkspace);
|
||||
|
||||
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
|
||||
|
||||
transformation->SetIntPoint(&integrationPoint);
|
||||
|
||||
if (tensor) for (int c = 0; c < 3; ++c) {
|
||||
sampleValue(c) = tensorSamples(quadraturePoint, 4*c);
|
||||
for (int a = 0; a < 3; ++a)
|
||||
sampleGradient(c,a) = tensorSamples(quadraturePoint, 4*c+a+1);
|
||||
}
|
||||
const mapping::DomainMapper::ReferenceDisplacementSample sample{sampleValue, sampleGradient};
|
||||
const mapping::MappingStatus mappingStatus = m_domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext, tensor ? &sample : nullptr
|
||||
);
|
||||
|
||||
if (mappingStatus != mapping::MappingStatus::valid) {
|
||||
@@ -615,6 +663,16 @@ namespace mean_field::operators {
|
||||
|
||||
data.baseMappingContexts.Store(quadraturePoint, mappingContext);
|
||||
data.quadratureWeights(quadraturePoint) = quadratureWeight;
|
||||
if (data.displacementInverseJacobians.Width() != 0) {
|
||||
if (mappingContext.mapping.compactified) {
|
||||
data.displacementInverseJacobians.SetSize(0, 0);
|
||||
} else {
|
||||
double *inverse = data.displacementInverseJacobians.Data() + 9 * quadraturePoint;
|
||||
for (int c = 0; c < 3; ++c)
|
||||
for (int r = 0; r < 3; ++r)
|
||||
inverse[r + 3 * c] = mappingContext.quadrature.J_inv(r, c);
|
||||
}
|
||||
}
|
||||
|
||||
for (int component = 0; component < m_fem.mesh->Dimension(); ++component) {
|
||||
const double position = mappingContext.mapping.physical_position(component);
|
||||
@@ -631,7 +689,8 @@ namespace mean_field::operators {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool PreparedHydrostaticEquilibriumOperator::PrepareAlgebraicJacobianBlocks() {
|
||||
bool PreparedHydrostaticEquilibriumOperator::PrepareAlgebraicJacobianBlocks(const bool useTensorPreparation) {
|
||||
mfem::Vector dual, column, workspace;
|
||||
for (ElementPAData &data : m_elements) {
|
||||
const mfem::DenseMatrix &enthalpyBasis = data.GetEnthalpyBasis();
|
||||
const mfem::DenseMatrix &gravityPotentialBasis = data.GetGravityPotentialBasis();
|
||||
@@ -658,7 +717,21 @@ namespace mean_field::operators {
|
||||
data.gravityPotentialJacobian = 0.0;
|
||||
data.bernoulliConstantJacobian = 0.0;
|
||||
|
||||
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
|
||||
if (useTensorPreparation && data.enthalpyReferenceTable->HasTensorEvaluation3D()) {
|
||||
dual.SetSize(quadraturePointCount);
|
||||
auto assemble = [&](const mfem::DenseMatrix &basis, mfem::DenseMatrix &matrix) {
|
||||
for (int j = 0; j < basis.Width(); ++j) {
|
||||
for (int q = 0; q < quadraturePointCount; ++q)
|
||||
dual(q) = data.quadratureWeights(q)*basis(q,j);
|
||||
data.enthalpyReferenceTable->ApplyTransposeTensor3D(dual, column, workspace);
|
||||
for (int i = 0; i < enthalpyDofCount; ++i) matrix(i,j) = column(i);
|
||||
}
|
||||
};
|
||||
assemble(enthalpyBasis, data.enthalpyJacobian);
|
||||
assemble(gravityPotentialBasis, data.gravityPotentialJacobian);
|
||||
for (int q = 0; q < quadraturePointCount; ++q) dual(q) = -data.quadratureWeights(q);
|
||||
data.enthalpyReferenceTable->ApplyTransposeTensor3D(dual, data.bernoulliConstantJacobian, workspace);
|
||||
} else for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
|
||||
const double quadratureWeight = data.quadratureWeights(quadraturePoint);
|
||||
|
||||
for (int testDof = 0; testDof < enthalpyDofCount; ++testDof) {
|
||||
@@ -738,7 +811,7 @@ namespace mean_field::operators {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool PreparedHydrostaticEquilibriumOperator::PrepareBaseState() {
|
||||
bool PreparedHydrostaticEquilibriumOperator::PrepareBaseState(const bool useTensorPreparation) {
|
||||
mfem::Vector enthalpyLocal;
|
||||
mfem::Vector gravityPotentialLocal;
|
||||
|
||||
@@ -750,6 +823,7 @@ namespace mean_field::operators {
|
||||
mfem::Vector elementGravityPotential;
|
||||
mfem::Vector quadratureEnthalpy;
|
||||
mfem::Vector quadratureGravityPotential;
|
||||
mfem::Vector workspace;
|
||||
|
||||
for (ElementPAData &data : m_elements) {
|
||||
enthalpyLocal.GetSubVector(data.enthalpyDofs, elementEnthalpy);
|
||||
@@ -770,9 +844,12 @@ namespace mean_field::operators {
|
||||
|
||||
quadratureGravityPotential.SetSize(quadraturePointCount);
|
||||
|
||||
data.GetEnthalpyBasis().Mult(elementEnthalpy, quadratureEnthalpy);
|
||||
|
||||
data.GetGravityPotentialBasis().Mult(elementGravityPotential, quadratureGravityPotential);
|
||||
if (useTensorPreparation && data.enthalpyReferenceTable->HasTensorEvaluation3D())
|
||||
data.enthalpyReferenceTable->EvaluateValuesTensor3D(elementEnthalpy, quadratureEnthalpy, workspace);
|
||||
else data.GetEnthalpyBasis().Mult(elementEnthalpy, quadratureEnthalpy);
|
||||
if (useTensorPreparation && data.gravityPotentialReferenceTable->HasTensorEvaluation3D())
|
||||
data.gravityPotentialReferenceTable->EvaluateValuesTensor3D(elementGravityPotential, quadratureGravityPotential, workspace);
|
||||
else data.GetGravityPotentialBasis().Mult(elementGravityPotential, quadratureGravityPotential);
|
||||
|
||||
MFEM_VERIFY(
|
||||
data.rotationPotential.Size() == quadraturePointCount, "Prepared hydrostatic base state has stale "
|
||||
@@ -1156,6 +1233,38 @@ namespace mean_field::operators {
|
||||
void PreparedHydrostaticEquilibriumOperator::ApplyDisplacementJacobianAction(
|
||||
const mfem::Vector &displacementVariation,
|
||||
mfem::Vector &action
|
||||
) const {
|
||||
ApplyDisplacementJacobianActionImpl(displacementVariation, action, true, true);
|
||||
}
|
||||
|
||||
void PreparedHydrostaticEquilibriumOperator::ApplyDisplacementJacobianActionReference(
|
||||
const mfem::Vector &displacementVariation, mfem::Vector &action
|
||||
) const {
|
||||
ApplyDisplacementJacobianActionImpl(displacementVariation, action, false, false);
|
||||
}
|
||||
|
||||
void PreparedHydrostaticEquilibriumOperator::ApplyDisplacementJacobianActionCachedReference(
|
||||
const mfem::Vector &displacementVariation, mfem::Vector &action
|
||||
) const {
|
||||
ApplyDisplacementJacobianActionImpl(displacementVariation, action, true, false);
|
||||
}
|
||||
|
||||
int PreparedHydrostaticEquilibriumOperator::GetTensorDisplacementElementCount() const noexcept {
|
||||
int count = 0;
|
||||
for (const auto &data : m_elements)
|
||||
count += data.displacementInverseJacobians.Width() != 0 && data.displacementReferenceTable != nullptr &&
|
||||
data.displacementReferenceTable->HasTensorEvaluation3D();
|
||||
return count;
|
||||
}
|
||||
|
||||
int PreparedHydrostaticEquilibriumOperator::GetFastDisplacementElementCount() const noexcept {
|
||||
int count = 0;
|
||||
for (const auto &data : m_elements) count += data.displacementInverseJacobians.Width() != 0;
|
||||
return count;
|
||||
}
|
||||
|
||||
void PreparedHydrostaticEquilibriumOperator::ApplyDisplacementJacobianActionImpl(
|
||||
const mfem::Vector &displacementVariation, mfem::Vector &action, const bool useFastPath, const bool useTensorPath
|
||||
) const {
|
||||
VerifyPrepared();
|
||||
|
||||
@@ -1226,8 +1335,42 @@ namespace mean_field::operators {
|
||||
);
|
||||
|
||||
weightedQuadratureVariation.SetSize(quadraturePointCount);
|
||||
const bool tensor = useFastPath && useTensorPath && data.displacementInverseJacobians.Width() != 0 &&
|
||||
data.displacementReferenceTable->HasTensorEvaluation3D();
|
||||
if (tensor) data.displacementReferenceTable->EvaluateTensor3D(
|
||||
directionData.GetDofMatrix(), m_tensorDisplacementValuesAndGradients, m_tensorDisplacementWorkspace);
|
||||
|
||||
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
|
||||
if (tensor) {
|
||||
const double *inverse = data.displacementInverseJacobians.Data() + 9 * quadraturePoint;
|
||||
double trace = 0.0, position = 0.0;
|
||||
for (int c = 0; c < 3; ++c) {
|
||||
position += data.rotationGradient(quadraturePoint, c) *
|
||||
m_tensorDisplacementValuesAndGradients(quadraturePoint, 4 * c);
|
||||
for (int derivative = 0; derivative < 3; ++derivative)
|
||||
trace += inverse[derivative + 3 * c] *
|
||||
m_tensorDisplacementValuesAndGradients(quadraturePoint, 4 * c + 1 + derivative);
|
||||
}
|
||||
const double value = data.quadratureWeights(quadraturePoint) *
|
||||
(data.hydrostaticImbalance(quadraturePoint) * trace - position);
|
||||
MFEM_VERIFY(std::isfinite(value), "Prepared hydrostatic tensor action is non-finite.");
|
||||
weightedQuadratureVariation(quadraturePoint) = value;
|
||||
continue;
|
||||
}
|
||||
if (useFastPath && data.displacementInverseJacobians.Width() != 0) {
|
||||
const double weight = data.quadratureWeights(quadraturePoint);
|
||||
double positionCoefficient[3];
|
||||
for (int c = 0; c < 3; ++c)
|
||||
positionCoefficient[c] = -weight * data.rotationGradient(quadraturePoint, c);
|
||||
const double value = apply_interior_functional(
|
||||
directionData.GetDofMatrix(), data.displacementReferenceTable->GetGradients(quadraturePoint),
|
||||
data.displacementReferenceTable->GetValues(), quadraturePoint,
|
||||
data.displacementInverseJacobians.Data() + 9 * quadraturePoint,
|
||||
weight * data.hydrostaticImbalance(quadraturePoint), positionCoefficient);
|
||||
MFEM_VERIFY(std::isfinite(value), "Prepared hydrostatic displacement action is non-finite.");
|
||||
weightedQuadratureVariation(quadraturePoint) = value;
|
||||
continue;
|
||||
}
|
||||
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
|
||||
data.baseMappingContexts.Load(quadraturePoint, mappingContext);
|
||||
|
||||
@@ -1279,7 +1422,7 @@ namespace mean_field::operators {
|
||||
action.SetSize(m_context.GetEnthalpyMap().reduced_size());
|
||||
m_context.GetEnthalpyMap().gather(m_fullEnthalpyAction, action);
|
||||
|
||||
++m_displacementJacobianStatistics.applications;
|
||||
if (useFastPath && useTensorPath) ++m_displacementJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
void PreparedHydrostaticEquilibriumOperator::ApplyCompleteJacobianAction(
|
||||
|
||||
Reference in New Issue
Block a user