perf(jacobian-action): major updates to jacobian action application by removing redudant quadrature work. ~5x increase in speed
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user