module; #include #include #include #include module mean_field; import :preconditioning.gravity_field; namespace mean_field::preconditioning { std::unique_ptr assembleGravityDivergenceSurrogate(const fem::FEM &f) { if (f.mesh == nullptr || f.gravityFluxFes == nullptr || f.gravityPotentialFes == nullptr || f.quadratureFactory == nullptr) { throw std::invalid_argument( "The gravity divergence surrogate requires its mesh, gravity spaces, and quadrature policy." ); } mfem::ParMixedBilinearForm divergence(f.gravityFluxFes.get(), f.gravityPotentialFes.get()); auto integrator = std::make_unique(); const mfem::FiniteElement &trialElement = *f.gravityFluxFes->GetTypicalFE(); const mfem::FiniteElement &testElement = *f.gravityPotentialFes->GetTypicalFE(); const mfem::ElementTransformation &transformation = *f.mesh->GetElementTransformation(0); f.quadratureFactory->configure_gravity_divergence( *integrator, quadrature::QuadratureRole::preconditioner, trialElement, testElement, transformation, utils::DOMAINS::ALL, quadrature::MappingKind::none ); divergence.AddDomainIntegrator(integrator.release()); divergence.Assemble(); divergence.Finalize(); std::unique_ptr assembled(divergence.ParallelAssemble()); if (assembled == nullptr) { throw std::runtime_error("MFEM did not assemble the gravity divergence surrogate."); } return assembled; } std::unique_ptr assembleGravityPotentialSchurSurrogate( const fem::FEM &f, const mfem::Vector &trueMassDiagonal ) { if (f.gravityFluxFes == nullptr || trueMassDiagonal.Size() != f.gravityFluxFes->GetTrueVSize()) { throw std::invalid_argument( "The gravity Schur surrogate requires one mass-diagonal entry per true gravity-gradient DOF." ); } mfem::Vector inverseMassDiagonal(trueMassDiagonal); for (int index = 0; index < inverseMassDiagonal.Size(); ++index) { const double entry = inverseMassDiagonal(index); if (!std::isfinite(entry) || entry <= 0.0) { throw std::invalid_argument( "The gravity Schur surrogate encountered a non-positive or non-finite mass diagonal." ); } inverseMassDiagonal(index) = 1.0 / entry; } std::unique_ptr divergence = assembleGravityDivergenceSurrogate(f); std::unique_ptr inverseMassDivergenceTranspose(divergence->Transpose()); inverseMassDivergenceTranspose->ScaleRows(inverseMassDiagonal); std::unique_ptr schur( mfem::ParMult(divergence.get(), inverseMassDivergenceTranspose.get()) ); if (schur == nullptr) { throw std::runtime_error("MFEM did not assemble the gravity potential-Schur surrogate."); } return schur; } } // namespace mean_field::preconditioning