feat(mean_field): added initial implementation

note this implementation lacks many tests
This commit is contained in:
2026-07-15 09:44:43 -04:00
commit 9bc4f2758a
49 changed files with 171811 additions and 0 deletions

View File

@@ -0,0 +1,198 @@
module;
#include <mfem.hpp>
#include <utility>
export module mean_field:quadrature.mfem;
export import :quadrature.policy;
export namespace mean_field::quadrature {
struct MfemRule {
Resolution resolution;
const mfem::IntegrationRule* integration_rule;
};
class RuleFactory {
public:
explicit RuleFactory(
Policy policy
);
MfemRule get(
const Query& query,
mfem::Geometry::Type geometry
) const;
MfemRule get(
Term term,
QuadratureRole role,
mfem::Geometry::Type geometry,
int base_order,
utils::DOMAINS domain = utils::DOMAINS::ALL,
MappingKind mapping = MappingKind::none
) const;
Resolution configure_gravity_hdiv_mass(
mfem::VectorFEMassIntegrator& integrator,
QuadratureRole role,
const mfem::FiniteElement& element,
const mfem::ElementTransformation& transformation,
utils::DOMAINS domain = utils::DOMAINS::ALL,
MappingKind mapping = MappingKind::none
) const;
Resolution configure_gravity_divergence(
mfem::VectorFEDivergenceIntegrator& integrator,
QuadratureRole role,
const mfem::FiniteElement& trial_element,
const mfem::FiniteElement& test_element,
const mfem::ElementTransformation& transformation,
utils::DOMAINS domain = utils::DOMAINS::ALL,
MappingKind mapping = MappingKind::none
) const;
Resolution configure_gravity_boundary(
mfem::VectorFEBoundaryFluxLFIntegrator& integrator,
QuadratureRole role,
const mfem::FiniteElement& boundary_element,
utils::DOMAINS domain = utils::DOMAINS::VACUUM,
MappingKind mapping = MappingKind::none
) const;
Resolution configure_gravity_source(
mfem::DomainLFIntegrator& integrator,
QuadratureRole role,
const mfem::FiniteElement& test_element,
const mfem::ElementTransformation& transformation,
int coefficient_order,
utils::DOMAINS domain = utils::DOMAINS::STELLAR,
MappingKind mapping = MappingKind::none
) const;
template<typename IntegratorType>
Resolution configure(
IntegratorType& integrator,
Term term,
QuadratureRole role,
mfem::Geometry::Type geometry,
int base_order,
utils::DOMAINS domain = utils::DOMAINS::ALL,
MappingKind mapping = MappingKind::none
) const;
private:
Policy policy;
};
RuleFactory::RuleFactory(Policy policy) : policy(std::move(policy)) {}
MfemRule RuleFactory::get(
const Query& query,
const mfem::Geometry::Type geometry
) const {
const Resolution resolution = policy.resolve(query);
const mfem::IntegrationRule& integration_rule = mfem::IntRules.Get(geometry, resolution.order);
return {.resolution = resolution, .integration_rule = &integration_rule};
}
MfemRule RuleFactory::get(
const Term term,
const QuadratureRole role,
const mfem::Geometry::Type geometry,
const int base_order,
const utils::DOMAINS domain,
const MappingKind mapping
) const {
Query query{.term = term};
query.domain = domain;
query.mapping = mapping;
query.role = role;
query.base_order = base_order;
return get(query, geometry);
}
Resolution RuleFactory::configure_gravity_hdiv_mass(
mfem::VectorFEMassIntegrator& integrator,
const QuadratureRole role,
const mfem::FiniteElement& element,
const mfem::ElementTransformation& transformation,
const utils::DOMAINS domain,
const MappingKind mapping
) const {
const int base_order = 2 * element.GetOrder() + transformation.OrderW();
return configure(integrator, Term::gravity_hdiv_mass, role, element.GetGeomType(), base_order, domain, mapping);
}
Resolution RuleFactory::configure_gravity_divergence(
mfem::VectorFEDivergenceIntegrator& integrator,
const QuadratureRole role,
const mfem::FiniteElement& trial_element,
const mfem::FiniteElement& test_element,
const mfem::ElementTransformation& transformation,
const utils::DOMAINS domain,
const MappingKind mapping
) const {
const Query query = {
.term = Term::gravity_divergence,
.role = role,
.domain = domain,
.mapping = mapping,
.trial_order = trial_element.GetOrder(),
.test_order = test_element.GetOrder(),
.geometry_weight_order = transformation.OrderW()
};
const auto [resolution, integration_rule] = get(query, trial_element.GetGeomType());
integrator.SetIntegrationRule(*integration_rule);
return resolution;
}
Resolution RuleFactory::configure_gravity_boundary(
mfem::VectorFEBoundaryFluxLFIntegrator& integrator,
const QuadratureRole role,
const mfem::FiniteElement& boundary_element,
const utils::DOMAINS domain,
const MappingKind mapping
) const {
const int base_order = 2 * boundary_element.GetOrder();
return configure(integrator, Term::gravity_boundary, role, boundary_element.GetGeomType(), base_order, domain, mapping);
}
Resolution RuleFactory::configure_gravity_source(
mfem::DomainLFIntegrator& integrator,
const QuadratureRole role,
const mfem::FiniteElement& test_element,
const mfem::ElementTransformation& transformation,
const int coefficient_order,
const utils::DOMAINS domain,
const MappingKind mapping
) const {
const Query query = {
.term = Term::gravity_source,
.role = role,
.domain = domain,
.mapping = mapping,
.test_order = test_element.GetOrder(),
.coefficient_order = coefficient_order,
.geometry_weight_order = transformation.OrderW()
};
const auto [resolution, integration_rule] = get(query, test_element.GetGeomType());
integrator.SetIntegrationRule(*integration_rule);
return resolution;
}
template<typename IntegratorType>
Resolution RuleFactory::configure(
IntegratorType& integrator,
const Term term,
const QuadratureRole role,
const mfem::Geometry::Type geometry,
const int base_order,
const utils::DOMAINS domain,
const MappingKind mapping
) const {
const auto [resolution, integration_rule] = get(term, role, geometry, base_order, domain, mapping);
integrator.SetIntegrationRule(*integration_rule);
return resolution;
}
}

View File

@@ -0,0 +1,256 @@
module;
#include <algorithm>
#include <optional>
#include <stdexcept>
#include <utility>
export module mean_field:quadrature.policy;
export import :utils.misc;
export namespace mean_field::quadrature {
enum class Term {
gravity_hdiv_mass,
gravity_divergence,
gravity_source,
gravity_boundary,
density_projection,
mass_conservation,
center_of_mass,
quadrupole,
gravitational_energy,
virial,
error_norm
};
enum class QuadratureRole {
discretization,
preconditioner,
diagnostic,
projection
};
enum class MappingKind {
none,
affine,
general,
kelvin
};
enum class Mode {
fast,
production,
reference,
convergence
};
struct RuleControl {
std::optional<int> fixed_order;
int boost = 0;
};
struct RoleControls {
RuleControl discretization;
RuleControl preconditioner;
RuleControl diagnostic;
RuleControl projection;
};
struct RuleSet {
RuleControl gravity_hdiv_mass;
RuleControl gravity_divergence;
RuleControl gravity_source;
RuleControl gravity_boundary;
RuleControl density_projection;
RuleControl mass_conservation;
RuleControl center_of_mass;
RuleControl quadrupole;
RuleControl gravitational_energy;
RuleControl virial;
RuleControl error_norm;
RoleControls roles;
RuleControl fallback;
};
struct Query {
Term term;
QuadratureRole role = QuadratureRole::discretization;
utils::DOMAINS domain = utils::DOMAINS::ALL;
MappingKind mapping = MappingKind::none;
int trial_order = 0;
int test_order = 0;
int coefficient_order = 0;
int geometry_weight_order = 0;
std::optional<int> base_order;
};
struct Resolution {
int base_order;
int boost;
int order;
bool used_fixed_order;
};
struct QuadratureTermOptions {
std::optional<int> fixed_order;
int additional_boost = 0;
};
struct QuadratureManifestOptions {
bool enabled = false;
bool include_repeated_queries = false;
std::optional<std::string> output_file;
};
struct QuadratureValidationOptions {
bool require_explicit_base_order = false;
bool require_explicit_mfem_rule = false;
bool reject_negative_boosts = true;
bool report_unused_overrides = true;
};
struct QuadratureRoleOptions {
QuadratureTermOptions discretization;
QuadratureTermOptions preconditioner;
QuadratureTermOptions diagnostic;
QuadratureTermOptions projection;
};
struct QuadratureOptions {
Mode mode = Mode::production;
int global_boost = 0;
std::optional<int> fallback_fixed_order;
QuadratureTermOptions gravity_hdiv_mass;
QuadratureTermOptions gravity_divergence;
QuadratureTermOptions gravity_source;
QuadratureTermOptions gravity_boundary;
QuadratureTermOptions density_projection;
QuadratureTermOptions mass_conservation;
QuadratureTermOptions center_of_mass;
QuadratureTermOptions quadrupole;
QuadratureTermOptions gravitational_energy;
QuadratureTermOptions virial;
QuadratureTermOptions error_norm;
QuadratureRoleOptions roles;
std::vector<int> convergence_boosts = {0, 2, 4};
QuadratureManifestOptions manifest;
QuadratureValidationOptions validation;
};
RuleSet make_rule_set(Mode mode, int global_boost = 0);
class Policy {
public:
explicit Policy(RuleSet rule_set);
Resolution resolve(const Query& query) const;
private:
const RuleControl& get_control(Term term) const;
static int compute_base_order(const Query& query) ;
const RuleControl& get_role_control(QuadratureRole role) const;
RuleSet rule_set;
};
RuleSet make_rule_set(const Mode mode, const int global_boost) {
RuleSet rule_set;
switch (mode) {
case Mode::fast:
case Mode::production:
case Mode::convergence:
rule_set.fallback.boost = global_boost;
break;
case Mode::reference:
rule_set.fallback.boost = global_boost + 8;
break;
}
return rule_set;
}
Policy::Policy(RuleSet rule_set) : rule_set(std::move(rule_set)) {}
Resolution Policy::resolve(const Query& query) const {
const int base_order = compute_base_order(query);
const RuleControl& term_control = get_control(query.term);
const RuleControl& role_control = get_role_control(query.role);
std::optional<int> fixed_order;
if (term_control.fixed_order.has_value()) {
fixed_order = term_control.fixed_order;
} else if (role_control.fixed_order.has_value()) {
fixed_order = role_control.fixed_order;
} else {
fixed_order = rule_set.fallback.fixed_order;
}
if (fixed_order.has_value()) {
if (*fixed_order < 0) {
throw std::invalid_argument("Quadrature fixed order cannot be negative.");
}
return {.base_order = base_order, .boost = 0, .order = *fixed_order, .used_fixed_order = true};
}
const int boost = rule_set.fallback.boost + role_control.boost + term_control.boost;
const int order = base_order + boost;
if (order < 0) {
throw std::invalid_argument("Resolved quadrature order cannot be negative.");
}
return {.base_order = base_order, .boost = boost, .order = order, .used_fixed_order = false};
}
const RuleControl& Policy::get_control(const Term term) const {
switch (term) {
case Term::gravity_hdiv_mass: return rule_set.gravity_hdiv_mass;
case Term::gravity_divergence: return rule_set.gravity_divergence;
case Term::gravity_source: return rule_set.gravity_source;
case Term::gravity_boundary: return rule_set.gravity_boundary;
case Term::density_projection: return rule_set.density_projection;
case Term::mass_conservation: return rule_set.mass_conservation;
case Term::center_of_mass: return rule_set.center_of_mass;
case Term::quadrupole: return rule_set.quadrupole;
case Term::gravitational_energy: return rule_set.gravitational_energy;
case Term::virial: return rule_set.virial;
case Term::error_norm: return rule_set.error_norm;
}
throw std::logic_error("Unknown quadrature term.");
}
int Policy::compute_base_order(const Query& query) {
if (query.base_order.has_value()) {
if (*query.base_order < 0) {
throw std::invalid_argument("Quadrature base order cannot be negative.");
}
return *query.base_order;
}
if (query.trial_order < 0 || query.test_order < 0 || query.coefficient_order < 0 || query.geometry_weight_order < 0) {
throw std::invalid_argument("Quadrature query orders cannot be negative.");
}
int trial_order = query.trial_order;
if (query.term == Term::gravity_divergence) {
trial_order = std::max(0, trial_order - 1);
}
return trial_order + query.test_order + query.coefficient_order + query.geometry_weight_order;
}
const RuleControl& Policy::get_role_control(const QuadratureRole role) const {
switch (role) {
case QuadratureRole::discretization: return rule_set.roles.discretization;
case QuadratureRole::preconditioner: return rule_set.roles.preconditioner;
case QuadratureRole::diagnostic: return rule_set.roles.diagnostic;
case QuadratureRole::projection: return rule_set.roles.projection;
}
throw std::logic_error("Unknown quadrature role.");
}
}