perf(jacobian-action): major updates to jacobian action application by removing redudant quadrature work. ~5x increase in speed
This commit is contained in:
@@ -8,6 +8,8 @@ import :operators.kernels.gravity_displacement_force;
|
||||
import :operators.prepared_gravity_displacement_force;
|
||||
|
||||
namespace {
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
|
||||
[[nodiscard]] bool relevant_revisions_match(
|
||||
const mean_field::operators::context::gravity_field::GravityFieldRevisions &left,
|
||||
const mean_field::operators::context::gravity_field::GravityFieldRevisions &right
|
||||
@@ -15,6 +17,71 @@ namespace {
|
||||
return left.discretization == right.discretization && left.displacement == right.displacement &&
|
||||
left.density == right.density && left.gravity_gradient == right.gravity_gradient;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool is_vacuum_attribute(const int attribute) {
|
||||
return DomainSchema::template attribute_belongs_to<mean_field::utils::domain::Vacuum>(attribute);
|
||||
}
|
||||
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finiteElementSpace,
|
||||
const mfem::Vector &trueVector,
|
||||
mfem::Vector &localVector
|
||||
) {
|
||||
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
|
||||
) {
|
||||
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;
|
||||
}
|
||||
MFEM_VERIFY(ordering == mfem::Ordering::byVDIM, "Unsupported displacement ordering.");
|
||||
return scalarDof * dimension + component;
|
||||
}
|
||||
|
||||
[[nodiscard]] const mfem::IntegrationRule &get_gravity_force_rule(
|
||||
const mean_field::fem::FEM &f,
|
||||
const mfem::ElementTransformation &transformation
|
||||
) {
|
||||
using DisplacementField = mean_field::field::Field<mean_field::field::Displacement>;
|
||||
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;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace mean_field::operators {
|
||||
@@ -41,6 +108,122 @@ namespace mean_field::operators {
|
||||
);
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::PrepareElementData() {
|
||||
m_elements.clear();
|
||||
m_elements.reserve(m_fem.mesh->GetNE());
|
||||
|
||||
mfem::Vector baseDensityLocal;
|
||||
mfem::Vector baseGravityGradientLocal;
|
||||
mfem::Vector baseDisplacementLocal;
|
||||
true_to_local(*m_fem.densityFes, m_gravityContext.GetDensityTrue(), baseDensityLocal);
|
||||
true_to_local(*m_fem.gravityFluxFes, m_gravityContext.GetGravityGradientTrue(), baseGravityGradientLocal);
|
||||
true_to_local(
|
||||
*m_fem.displacementFes, m_gravityContext.GetGeometryContext().GetDisplacementTrue(), baseDisplacementLocal
|
||||
);
|
||||
|
||||
mapping::DomainMapper::Workspace workspace(m_domainMapper.GetDimension());
|
||||
mapping::VolumeMappingContext mappingContext;
|
||||
mfem::Array<int> compactificationDofs;
|
||||
mfem::Vector elementBaseDensity;
|
||||
mfem::Vector elementBaseGravityGradient;
|
||||
mfem::Vector elementBaseDisplacement;
|
||||
mfem::Vector elementCompactification;
|
||||
mfem::Vector densityShape;
|
||||
mfem::Vector baseGravityReferenceValue;
|
||||
mfem::DenseMatrix gravityGradientShape;
|
||||
|
||||
const int dimension = m_domainMapper.GetDimension();
|
||||
|
||||
for (int elementId = 0; elementId < m_fem.mesh->GetNE(); ++elementId) {
|
||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(elementId);
|
||||
MFEM_VERIFY(transformation != nullptr, "Prepared gravity force received a null transformation.");
|
||||
if (is_vacuum_attribute(transformation->Attribute)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
m_elements.emplace_back();
|
||||
ElementPAData &data = m_elements.back();
|
||||
data.elementId = elementId;
|
||||
data.densityDofTransformation = m_fem.densityFes->GetElementDofs(elementId, data.densityDofs);
|
||||
data.gravityGradientDofTransformation =
|
||||
m_fem.gravityFluxFes->GetElementVDofs(elementId, data.gravityGradientDofs);
|
||||
data.displacementDofTransformation =
|
||||
m_fem.displacementFes->GetElementVDofs(elementId, data.displacementDofs);
|
||||
mfem::DofTransformation *compactificationDofTransformation =
|
||||
m_fem.compactificationFes->GetElementDofs(elementId, compactificationDofs);
|
||||
|
||||
baseDensityLocal.GetSubVector(data.densityDofs, elementBaseDensity);
|
||||
baseGravityGradientLocal.GetSubVector(data.gravityGradientDofs, elementBaseGravityGradient);
|
||||
baseDisplacementLocal.GetSubVector(data.displacementDofs, elementBaseDisplacement);
|
||||
m_fem.compactificationCoordinate->GetSubVector(compactificationDofs, elementCompactification);
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
data.densityDofTransformation->InvTransformPrimal(elementBaseDensity);
|
||||
}
|
||||
if (data.gravityGradientDofTransformation != nullptr) {
|
||||
data.gravityGradientDofTransformation->InvTransformPrimal(elementBaseGravityGradient);
|
||||
}
|
||||
if (data.displacementDofTransformation != nullptr) {
|
||||
data.displacementDofTransformation->InvTransformPrimal(elementBaseDisplacement);
|
||||
}
|
||||
if (compactificationDofTransformation != nullptr) {
|
||||
compactificationDofTransformation->InvTransformPrimal(elementCompactification);
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement = *m_fem.densityFes->GetFE(elementId);
|
||||
const mfem::FiniteElement &gravityGradientElement = *m_fem.gravityFluxFes->GetFE(elementId);
|
||||
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);
|
||||
|
||||
const mapping::ElementDisplacementData displacementData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, elementBaseDisplacement);
|
||||
const mapping::ElementCompactificationData compactificationData(
|
||||
compactificationElement, elementCompactification
|
||||
);
|
||||
const mapping::ElementMappingData mappingData{
|
||||
.displacement = displacementData, .compactification = compactificationData
|
||||
};
|
||||
|
||||
const int quadraturePointCount = data.integrationRule->GetNPoints();
|
||||
data.mappingJacobians.SetSize(quadraturePointCount, dimension * dimension);
|
||||
data.inverseMeshJacobians.SetSize(quadraturePointCount, dimension * dimension);
|
||||
data.baseGravityReferenceValues.SetSize(quadraturePointCount, dimension);
|
||||
data.baseDensityValues.SetSize(quadraturePointCount);
|
||||
data.referenceWeights.SetSize(quadraturePointCount);
|
||||
densityShape.SetSize(densityElement.GetDof());
|
||||
gravityGradientShape.SetSize(gravityGradientElement.GetDof(), dimension);
|
||||
baseGravityReferenceValue.SetSize(dimension);
|
||||
|
||||
for (int quadraturePoint = 0; quadraturePoint < quadraturePointCount; ++quadraturePoint) {
|
||||
const mfem::IntegrationPoint &integrationPoint = data.integrationRule->IntPoint(quadraturePoint);
|
||||
const mapping::MappingStatus status = m_domainMapper.EvaluateVolume(
|
||||
mappingData, *transformation, integrationPoint, workspace, mappingContext
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
status == mapping::MappingStatus::valid && !mappingContext.mapping.compactified,
|
||||
"Prepared gravity force encountered an invalid stellar mapping."
|
||||
);
|
||||
|
||||
densityElement.CalcShape(integrationPoint, densityShape);
|
||||
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();
|
||||
for (int row = 0; row < dimension; ++row) {
|
||||
data.baseGravityReferenceValues(quadraturePoint, row) = baseGravityReferenceValue(row);
|
||||
for (int column = 0; column < dimension; ++column) {
|
||||
const int entry = row * dimension + column;
|
||||
data.mappingJacobians(quadraturePoint, entry) =
|
||||
mappingContext.mapping.mapping_jacobian(row, column);
|
||||
data.inverseMeshJacobians(quadraturePoint, entry) = inverseMeshJacobian(row, column);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PreparedGravityDisplacementForceReport PreparedGravityDisplacementForceOperator::Prepare() {
|
||||
MFEM_VERIFY(
|
||||
m_gravityContext.IsPrepared(), "PreparedGravityDisplacementForceOperator requires the shared "
|
||||
@@ -59,6 +242,7 @@ namespace mean_field::operators {
|
||||
);
|
||||
m_cachedResidual.SetSize(m_gravityContext.GetDisplacementMap().reduced_size());
|
||||
m_gravityContext.GetDisplacementMap().gather(m_actionTrue, m_cachedResidual);
|
||||
PrepareElementData();
|
||||
|
||||
m_preparedRevisions = requestedRevisions;
|
||||
++m_residualPreparationCount;
|
||||
@@ -130,6 +314,117 @@ namespace mean_field::operators {
|
||||
++m_displacementJacobianStatistics.applications;
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::ApplyPreparedCompleteJacobianActionTrue(
|
||||
const mfem::Vector &densityVariationTrue,
|
||||
const mfem::Vector &displacementVariationTrue,
|
||||
const mfem::Vector &gravityGradientVariationTrue,
|
||||
mfem::Vector &actionTrue
|
||||
) const {
|
||||
true_to_local(*m_fem.densityFes, densityVariationTrue, m_densityVariationLocal);
|
||||
true_to_local(*m_fem.gravityFluxFes, gravityGradientVariationTrue, m_gravityGradientVariationLocal);
|
||||
true_to_local(*m_fem.displacementFes, displacementVariationTrue, m_displacementVariationLocal);
|
||||
m_localAction.SetSize(m_fem.displacementFes->GetVSize());
|
||||
m_localAction = 0.0;
|
||||
|
||||
const int dimension = m_domainMapper.GetDimension();
|
||||
const mfem::Ordering::Type ordering = m_fem.displacementFes->GetOrdering();
|
||||
|
||||
for (const ElementPAData &data : m_elements) {
|
||||
MFEM_VERIFY(data.integrationRule != nullptr, "Prepared gravity force has no integration rule.");
|
||||
|
||||
m_densityVariationLocal.GetSubVector(data.densityDofs, m_elementDensityVariation);
|
||||
m_gravityGradientVariationLocal.GetSubVector(data.gravityGradientDofs, m_elementGravityGradientVariation);
|
||||
m_displacementVariationLocal.GetSubVector(data.displacementDofs, m_elementDisplacementVariation);
|
||||
if (data.densityDofTransformation != nullptr) {
|
||||
data.densityDofTransformation->InvTransformPrimal(m_elementDensityVariation);
|
||||
}
|
||||
if (data.gravityGradientDofTransformation != nullptr) {
|
||||
data.gravityGradientDofTransformation->InvTransformPrimal(m_elementGravityGradientVariation);
|
||||
}
|
||||
if (data.displacementDofTransformation != nullptr) {
|
||||
data.displacementDofTransformation->InvTransformPrimal(m_elementDisplacementVariation);
|
||||
}
|
||||
|
||||
const mfem::FiniteElement &densityElement = *m_fem.densityFes->GetFE(data.elementId);
|
||||
const mfem::FiniteElement &gravityGradientElement = *m_fem.gravityFluxFes->GetFE(data.elementId);
|
||||
const mfem::FiniteElement &displacementElement = *m_fem.displacementFes->GetFE(data.elementId);
|
||||
mfem::ElementTransformation *transformation = m_fem.mesh->GetElementTransformation(data.elementId);
|
||||
MFEM_VERIFY(transformation != nullptr, "Prepared gravity force received a null transformation.");
|
||||
|
||||
const mapping::ElementDisplacementData directionData =
|
||||
mapping::ElementDisplacementDataFromElementVDofs(displacementElement, m_elementDisplacementVariation);
|
||||
const mfem::DenseMatrix &directionDofs = directionData.GetDofMatrix();
|
||||
const int scalarDisplacementDofCount = displacementElement.GetDof();
|
||||
|
||||
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_baseGravityReferenceValue.SetSize(dimension);
|
||||
m_gravityVariationReferenceValue.SetSize(dimension);
|
||||
m_mappedBaseGravity.SetSize(dimension);
|
||||
m_mappedGravityVariation.SetSize(dimension);
|
||||
m_mappedGeometryVariation.SetSize(dimension);
|
||||
m_forceValue.SetSize(dimension);
|
||||
m_elementAction.SetSize(data.displacementDofs.Size());
|
||||
m_elementAction = 0.0;
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
for (int column = 0; column < dimension; ++column) {
|
||||
const int entry = row * dimension + column;
|
||||
m_mappingJacobian(row, column) = data.mappingJacobians(quadraturePoint, entry);
|
||||
m_inverseMeshJacobian(row, column) = data.inverseMeshJacobians(quadraturePoint, entry);
|
||||
}
|
||||
}
|
||||
mfem::Mult(m_referenceDisplacementJacobian, m_inverseMeshJacobian, m_displacementJacobianVariation);
|
||||
m_mappingJacobian.Mult(m_baseGravityReferenceValue, m_mappedBaseGravity);
|
||||
m_mappingJacobian.Mult(m_gravityVariationReferenceValue, m_mappedGravityVariation);
|
||||
m_displacementJacobianVariation.Mult(m_baseGravityReferenceValue, m_mappedGeometryVariation);
|
||||
|
||||
const double densityVariationValue = m_elementDensityVariation * m_densityShape;
|
||||
const double baseDensityValue = data.baseDensityValues(quadraturePoint);
|
||||
m_forceValue = 0.0;
|
||||
m_forceValue.Add(densityVariationValue, m_mappedBaseGravity);
|
||||
m_forceValue.Add(baseDensityValue, m_mappedGravityVariation);
|
||||
m_forceValue.Add(baseDensityValue, m_mappedGeometryVariation);
|
||||
m_forceValue *= data.referenceWeights(quadraturePoint);
|
||||
|
||||
for (int scalarDof = 0; scalarDof < scalarDisplacementDofCount; ++scalarDof) {
|
||||
for (int component = 0; component < dimension; ++component) {
|
||||
const int vectorDof =
|
||||
vector_dof_index(ordering, scalarDof, component, scalarDisplacementDofCount, dimension);
|
||||
m_elementAction(vectorDof) += m_displacementShape(scalarDof) * m_forceValue(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (data.displacementDofTransformation != nullptr) {
|
||||
data.displacementDofTransformation->TransformDual(m_elementAction);
|
||||
}
|
||||
m_localAction.AddElementVector(data.displacementDofs, m_elementAction);
|
||||
}
|
||||
|
||||
local_to_true(*m_fem.displacementFes, m_localAction, actionTrue);
|
||||
}
|
||||
|
||||
void PreparedGravityDisplacementForceOperator::ApplyCompleteJacobianAction(
|
||||
const mfem::Vector &densityVariation,
|
||||
const mfem::Vector &displacementVariation,
|
||||
@@ -145,10 +440,8 @@ namespace mean_field::operators {
|
||||
m_gravityContext.GetGravityGradientMap().scatter(gravityGradientVariation, m_gravityGradientVariationTrue);
|
||||
m_gravityContext.GetDisplacementMap().scatter(displacementVariation, m_displacementVariationTrue);
|
||||
|
||||
kernels::apply_gravity_displacement_force_complete_action(
|
||||
m_fem, m_domainMapper, m_gravityContext.GetDensityTrue(), m_densityVariationTrue,
|
||||
m_gravityContext.GetGravityGradientTrue(), m_gravityGradientVariationTrue, m_displacementVariationTrue,
|
||||
m_gravityContext.GetGeometryContext().GetDisplacementTrue(), m_actionTrue
|
||||
ApplyPreparedCompleteJacobianActionTrue(
|
||||
m_densityVariationTrue, m_displacementVariationTrue, m_gravityGradientVariationTrue, m_actionTrue
|
||||
);
|
||||
action.SetSize(m_gravityContext.GetDisplacementMap().reduced_size());
|
||||
m_gravityContext.GetDisplacementMap().gather(m_actionTrue, action);
|
||||
|
||||
Reference in New Issue
Block a user