feat(preconditioner): major work on preconditioner system
first preconditioner MVP
This commit is contained in:
@@ -9,7 +9,132 @@ import :operators.context.gravity_field;
|
||||
namespace {
|
||||
using DomainSchema = mean_field::utils::domain::CoreEnvelopeVacuumDomainSchema;
|
||||
|
||||
[[nodiscard]] std::unique_ptr<mfem::ParMixedBilinearForm> make_divergence_operator(const mean_field::fem::FEM &f) {
|
||||
void true_to_local(
|
||||
const mfem::ParFiniteElementSpace &finite_element_space,
|
||||
const mfem::Vector &true_vector,
|
||||
mfem::Vector &local_vector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
true_vector.Size() == finite_element_space.GetTrueVSize(),
|
||||
"True-DOF operator received an input vector with the wrong size."
|
||||
);
|
||||
|
||||
local_vector.SetSize(finite_element_space.GetVSize());
|
||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->Mult(true_vector, local_vector);
|
||||
} else {
|
||||
local_vector = true_vector;
|
||||
}
|
||||
}
|
||||
|
||||
void local_to_true(
|
||||
const mfem::ParFiniteElementSpace &finite_element_space,
|
||||
const mfem::Vector &local_vector,
|
||||
mfem::Vector &true_vector
|
||||
) {
|
||||
MFEM_VERIFY(
|
||||
local_vector.Size() == finite_element_space.GetVSize(),
|
||||
"True-DOF operator produced a local vector with the wrong size."
|
||||
);
|
||||
|
||||
true_vector.SetSize(finite_element_space.GetTrueVSize());
|
||||
const mfem::Operator *prolongation = finite_element_space.GetProlongationMatrix();
|
||||
if (prolongation != nullptr) {
|
||||
prolongation->MultTranspose(local_vector, true_vector);
|
||||
} else {
|
||||
true_vector = local_vector;
|
||||
}
|
||||
}
|
||||
|
||||
bool communicator_has_single_rank(const MPI_Comm communicator) {
|
||||
int size = 0;
|
||||
MFEM_VERIFY(MPI_Comm_size(communicator, &size) == MPI_SUCCESS, "Failed to query the MPI communicator size.");
|
||||
MFEM_VERIFY(size > 0, "The MPI communicator must contain at least one rank.");
|
||||
return size == 1;
|
||||
}
|
||||
|
||||
class TrueDofParMixedBilinearFormOperator final : public mfem::Operator {
|
||||
public:
|
||||
TrueDofParMixedBilinearFormOperator(
|
||||
const mfem::ParFiniteElementSpace &trial_space,
|
||||
const mfem::ParFiniteElementSpace &test_space,
|
||||
std::unique_ptr<mfem::ParMixedBilinearForm> local_form
|
||||
)
|
||||
: Operator(
|
||||
test_space.GetTrueVSize(),
|
||||
trial_space.GetTrueVSize()
|
||||
),
|
||||
m_trial_space(trial_space),
|
||||
m_test_space(test_space),
|
||||
m_local_form(std::move(local_form)),
|
||||
m_single_rank(communicator_has_single_rank(trial_space.GetComm())) {
|
||||
int communicators_compare = MPI_UNEQUAL;
|
||||
MFEM_VERIFY(
|
||||
MPI_Comm_compare(trial_space.GetComm(), test_space.GetComm(), &communicators_compare) == MPI_SUCCESS,
|
||||
"Failed to compare mixed-operator MPI communicators."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
communicators_compare == MPI_IDENT || communicators_compare == MPI_CONGRUENT,
|
||||
"True-DOF mixed operator requires congruent trial and test communicators."
|
||||
);
|
||||
MFEM_VERIFY(m_local_form != nullptr, "True-DOF mixed operator requires a local bilinear form.");
|
||||
MFEM_VERIFY(
|
||||
m_local_form->Width() == m_trial_space.GetVSize(),
|
||||
"True-DOF mixed operator received an incompatible trial space."
|
||||
);
|
||||
MFEM_VERIFY(
|
||||
m_local_form->Height() == m_test_space.GetVSize(),
|
||||
"True-DOF mixed operator received an incompatible test space."
|
||||
);
|
||||
}
|
||||
|
||||
void Mult(
|
||||
const mfem::Vector &input,
|
||||
mfem::Vector &output
|
||||
) const override {
|
||||
MFEM_VERIFY(input.Size() == Width(), "True-DOF mixed operator received an input with the wrong size.");
|
||||
|
||||
if (m_single_rank) [[likely]] {
|
||||
output.SetSize(Height());
|
||||
m_local_form->Mult(input, output);
|
||||
return;
|
||||
}
|
||||
|
||||
true_to_local(m_trial_space, input, m_trial_local);
|
||||
m_test_local.SetSize(m_test_space.GetVSize());
|
||||
m_local_form->Mult(m_trial_local, m_test_local);
|
||||
local_to_true(m_test_space, m_test_local, output);
|
||||
}
|
||||
|
||||
void MultTranspose(
|
||||
const mfem::Vector &input,
|
||||
mfem::Vector &output
|
||||
) const override {
|
||||
MFEM_VERIFY(input.Size() == Height(), "True-DOF mixed transpose received an input with the wrong size.");
|
||||
|
||||
if (m_single_rank) [[likely]] {
|
||||
output.SetSize(Width());
|
||||
m_local_form->MultTranspose(input, output);
|
||||
return;
|
||||
}
|
||||
|
||||
true_to_local(m_test_space, input, m_test_local);
|
||||
m_trial_local.SetSize(m_trial_space.GetVSize());
|
||||
m_local_form->MultTranspose(m_test_local, m_trial_local);
|
||||
local_to_true(m_trial_space, m_trial_local, output);
|
||||
}
|
||||
|
||||
private:
|
||||
const mfem::ParFiniteElementSpace &m_trial_space;
|
||||
const mfem::ParFiniteElementSpace &m_test_space;
|
||||
std::unique_ptr<mfem::ParMixedBilinearForm> m_local_form;
|
||||
mutable mfem::Vector m_trial_local;
|
||||
mutable mfem::Vector m_test_local;
|
||||
bool m_single_rank;
|
||||
};
|
||||
|
||||
[[nodiscard]] std::unique_ptr<mfem::Operator> make_divergence_operator(const mean_field::fem::FEM &f) {
|
||||
auto divergence =
|
||||
std::make_unique<mfem::ParMixedBilinearForm>(f.gravityFluxFes.get(), f.gravityPotentialFes.get());
|
||||
|
||||
@@ -29,7 +154,9 @@ namespace {
|
||||
divergence->AddDomainIntegrator(integrator.release());
|
||||
divergence->Assemble();
|
||||
|
||||
return divergence;
|
||||
return std::make_unique<TrueDofParMixedBilinearFormOperator>(
|
||||
*f.gravityFluxFes, *f.gravityPotentialFes, std::move(divergence)
|
||||
);
|
||||
}
|
||||
|
||||
void validate_displacement(
|
||||
@@ -167,6 +294,25 @@ namespace mean_field::operators::context::gravity_field {
|
||||
const mfem::Vector &displacement,
|
||||
const DiscretizationRevision discretization_revision,
|
||||
const DisplacementRevision displacement_revision
|
||||
) {
|
||||
return PrepareImpl(
|
||||
displacement, discretization_revision, displacement_revision, PreparationMode::linearization
|
||||
);
|
||||
}
|
||||
|
||||
GravityFieldGeometryPreparation GravityFieldGeometryContext::PreparePrimal(
|
||||
const mfem::Vector &displacement,
|
||||
const DiscretizationRevision discretization_revision,
|
||||
const DisplacementRevision displacement_revision
|
||||
) {
|
||||
return PrepareImpl(displacement, discretization_revision, displacement_revision, PreparationMode::primal);
|
||||
}
|
||||
|
||||
GravityFieldGeometryPreparation GravityFieldGeometryContext::PrepareImpl(
|
||||
const mfem::Vector &displacement,
|
||||
const DiscretizationRevision discretization_revision,
|
||||
const DisplacementRevision displacement_revision,
|
||||
const PreparationMode mode
|
||||
) {
|
||||
validate_displacement(m_displacement_map, displacement);
|
||||
|
||||
@@ -185,21 +331,38 @@ namespace mean_field::operators::context::gravity_field {
|
||||
|
||||
const bool discretization_changed = !m_is_prepared || discretization_revision != m_discretization_revision;
|
||||
const bool displacement_changed = !m_is_prepared || displacement_revision != m_displacement_revision;
|
||||
const bool requires_variation = mode == PreparationMode::linearization;
|
||||
const bool variation_upgrade = requires_variation && !m_variation_state_prepared;
|
||||
|
||||
GravityFieldGeometryPreparation preparation;
|
||||
|
||||
if (!discretization_changed && !displacement_changed) {
|
||||
if (!discretization_changed && !displacement_changed && !variation_upgrade) {
|
||||
return preparation;
|
||||
}
|
||||
|
||||
const auto prepare_mass = [&](PreparedMappedHDivMassOperator &mass_operator) {
|
||||
if (requires_variation) {
|
||||
mass_operator.Prepare(displacement);
|
||||
} else {
|
||||
mass_operator.PreparePrimal(displacement);
|
||||
}
|
||||
};
|
||||
const auto prepare_source = [&](PreparedMappedGravitySourceOperator &source_operator) {
|
||||
if (requires_variation) {
|
||||
source_operator.Prepare(displacement);
|
||||
} else {
|
||||
source_operator.PreparePrimal(displacement);
|
||||
}
|
||||
};
|
||||
|
||||
if (discretization_changed) {
|
||||
auto mass_operator = std::make_unique<PreparedMappedHDivMassOperator>(m_fem, m_domain_mapper);
|
||||
auto source_operator = std::make_unique<PreparedMappedGravitySourceOperator>(m_fem, m_domain_mapper);
|
||||
auto divergence_operator = make_divergence_operator(m_fem);
|
||||
auto transpose_divergence_operator = std::make_unique<mfem::TransposeOperator>(divergence_operator.get());
|
||||
|
||||
mass_operator->Prepare(displacement);
|
||||
source_operator->Prepare(displacement);
|
||||
prepare_mass(*mass_operator);
|
||||
prepare_source(*source_operator);
|
||||
|
||||
m_mass_operator = std::move(mass_operator);
|
||||
m_source_operator = std::move(source_operator);
|
||||
@@ -220,8 +383,8 @@ namespace mean_field::operators::context::gravity_field {
|
||||
"operator."
|
||||
);
|
||||
|
||||
m_mass_operator->Prepare(displacement);
|
||||
m_source_operator->Prepare(displacement);
|
||||
prepare_mass(*m_mass_operator);
|
||||
prepare_source(*m_source_operator);
|
||||
|
||||
preparation.rebuilt_mass_operator = true;
|
||||
preparation.rebuilt_source_operator = true;
|
||||
@@ -232,8 +395,9 @@ namespace mean_field::operators::context::gravity_field {
|
||||
m_discretization_revision = discretization_revision;
|
||||
m_displacement_revision = displacement_revision;
|
||||
m_is_prepared = true;
|
||||
m_variation_state_prepared = requires_variation;
|
||||
|
||||
preparation.refreshed_variation_state = true;
|
||||
preparation.refreshed_variation_state = requires_variation;
|
||||
|
||||
return preparation;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user