perf(jacobian-action): major updates to jacobian action application by removing redudant quadrature work. ~5x increase in speed

This commit is contained in:
2026-09-02 17:01:50 -04:00
parent 85500fef3b
commit 25510008dd
74 changed files with 8967 additions and 814 deletions

View File

@@ -174,9 +174,15 @@ namespace {
"non-finite mapping determinant."
);
m_inverse_element_jacobian = mapping_context.quadrature.J_inv;
return 4.0 * std::numbers::pi * mean_field::utils::G * mapping_determinant;
}
[[nodiscard]] const mfem::DenseMatrix &GetInverseElementJacobian() const noexcept {
return m_inverse_element_jacobian;
}
private:
void LoadElement(const int element_id) {
if (element_id == m_cached_element_id) {
@@ -230,6 +236,7 @@ namespace {
std::unique_ptr<mean_field::mapping::ElementCompactificationData> m_compactification_data;
mean_field::mapping::DomainMapper::Workspace m_workspace;
mfem::DenseMatrix m_inverse_element_jacobian;
int m_cached_element_id{-1};
};
} // namespace
@@ -336,6 +343,9 @@ namespace mean_field::operators {
data.potential_dof_transformation =
m_fem.gravityPotentialFes->GetElementDofs(element_id, data.potential_dofs);
data.displacement_dof_transformation =
m_fem.displacementFes->GetElementVDofs(element_id, data.displacement_dofs);
const mfem::FiniteElement &density_element = *m_fem.densityFes->GetFE(element_id);
const mfem::FiniteElement &potential_element = *m_fem.gravityPotentialFes->GetFE(element_id);
@@ -344,6 +354,7 @@ namespace mean_field::operators {
const mfem::IntegrationRule &integration_rule =
get_source_rule(m_fem, density_element, potential_element, transformation);
data.integration_rule = &integration_rule;
const int quadrature_point_count = integration_rule.GetNPoints();
@@ -355,6 +366,9 @@ namespace mean_field::operators {
data.potential_basis.SetSize(quadrature_point_count, potential_dof_count);
const int dimension = m_fem.mesh->Dimension();
data.inverse_element_jacobians.SetSize(quadrature_point_count, dimension * dimension);
data.quadrature_data.SetSize(quadrature_point_count);
mfem::Vector density_shape(density_dof_count);
@@ -381,6 +395,14 @@ namespace mean_field::operators {
const double coefficient_value = source_coefficient.Eval(transformation, integration_point);
const mfem::DenseMatrix &inverse_element_jacobian = source_coefficient.GetInverseElementJacobian();
for (int row = 0; row < dimension; ++row) {
for (int column = 0; column < dimension; ++column) {
data.inverse_element_jacobians(quadrature_point, row * dimension + column) =
inverse_element_jacobian(row, column);
}
}
transformation.SetIntPoint(&integration_point);
const double quadrature_value = integration_point.weight * transformation.Weight() * coefficient_value;
@@ -463,6 +485,98 @@ namespace mean_field::operators {
m_potential_map.gather(m_action_true, action);
}
void PreparedMappedGravitySourceOperator::MultDisplacementVariationTrue(
const mfem::Vector &densityTrue,
const mfem::Vector &displacementVariationTrue,
mfem::Vector &actionVariationTrue
) const {
MFEM_VERIFY(
m_is_prepared,
"PreparedMappedGravitySourceOperator must be prepared before applying a displacement variation."
);
MFEM_VERIFY(
densityTrue.Size() == m_fem.densityFes->GetTrueVSize(), "The full density vector has the wrong size."
);
MFEM_VERIFY(
displacementVariationTrue.Size() == m_fem.displacementFes->GetTrueVSize(),
"The full displacement variation has the wrong size."
);
true_to_local(*m_fem.densityFes, densityTrue, m_density_local);
true_to_local(*m_fem.displacementFes, displacementVariationTrue, m_displacement_variation_local);
m_local_variation_action.SetSize(m_fem.gravityPotentialFes->GetVSize());
m_local_variation_action = 0.0;
const int dimension = m_fem.mesh->Dimension();
for (const ElementPAData &data : m_elements) {
MFEM_VERIFY(
data.integration_rule != nullptr,
"Prepared gravity source displacement variation has no integration rule."
);
m_density_local.GetSubVector(data.density_dofs, m_element_density);
m_displacement_variation_local.GetSubVector(data.displacement_dofs, m_element_displacement_variation);
if (data.density_dof_transformation != nullptr) {
data.density_dof_transformation->InvTransformPrimal(m_element_density);
}
if (data.displacement_dof_transformation != nullptr) {
data.displacement_dof_transformation->InvTransformPrimal(m_element_displacement_variation);
}
const mfem::FiniteElement &displacement_element = *m_fem.displacementFes->GetFE(data.element_id);
const mapping::ElementDisplacementData direction_data = mapping::ElementDisplacementDataFromElementVDofs(
displacement_element, m_element_displacement_variation
);
const mfem::DenseMatrix &direction_dofs = direction_data.GetDofMatrix();
MFEM_VERIFY(
data.inverse_element_jacobians.Height() == data.integration_rule->GetNPoints() &&
data.inverse_element_jacobians.Width() == dimension * dimension,
"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);
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);
double logarithmic_jacobian_variation{0.0};
for (int row = 0; row < dimension; ++row) {
for (int column = 0; column < dimension; ++column) {
logarithmic_jacobian_variation +=
data.inverse_element_jacobians(quadrature_point, row * dimension + column) *
m_reference_displacement_jacobian(column, row);
}
}
m_quadrature_variation_action(quadrature_point) *=
data.quadrature_data(quadrature_point) * logarithmic_jacobian_variation;
MFEM_VERIFY(
std::isfinite(m_quadrature_variation_action(quadrature_point)),
"Prepared gravity source displacement variation encountered a non-finite quadrature value."
);
}
m_element_variation_action.SetSize(data.potential_dofs.Size());
data.potential_basis.MultTranspose(m_quadrature_variation_action, m_element_variation_action);
if (data.potential_dof_transformation != nullptr) {
data.potential_dof_transformation->TransformDual(m_element_variation_action);
}
m_local_variation_action.AddElementVector(data.potential_dofs, m_element_variation_action);
}
local_to_true(*m_fem.gravityPotentialFes, m_local_variation_action, actionVariationTrue);
}
void PreparedMappedGravitySourceOperator::MultTranspose(
const mfem::Vector &potential,
mfem::Vector &action