feat(mean_field): added initial implementation
note this implementation lacks many tests
This commit is contained in:
41
libmeanfield/interface/analysis/integral.cppm
Normal file
41
libmeanfield/interface/analysis/integral.cppm
Normal file
@@ -0,0 +1,41 @@
|
||||
module;
|
||||
#include "mean_field.h"
|
||||
|
||||
export module mean_field:analysis.integral;
|
||||
export import :fem;
|
||||
export import :utils.domain;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :mapping.types;
|
||||
|
||||
export namespace mean_field::analysis {
|
||||
double domain_integrate_grid_function(
|
||||
const fem::FEM &fem,
|
||||
const mfem::GridFunction &gf,
|
||||
utils::DOMAINS domain = utils::DOMAINS::ALL,
|
||||
mapping::COORDINATE_SPACE coord_space = mapping::COORDINATE_SPACE::PHYSICAL
|
||||
);
|
||||
|
||||
mfem::Vector get_com(
|
||||
const fem::FEM &fem,
|
||||
const mfem::GridFunction &rho
|
||||
);
|
||||
|
||||
void conserve_mass(
|
||||
const fem::FEM &fem,
|
||||
mfem::GridFunction &rho,
|
||||
double target_mass
|
||||
);
|
||||
|
||||
double get_moment_of_inertia(
|
||||
const fem::FEM &fem,
|
||||
const mfem::GridFunction &rho
|
||||
);
|
||||
|
||||
double get_mesh_volume(
|
||||
const fem::FEM& fem,
|
||||
mapping::COORDINATE_SPACE coordinate_space = mapping::COORDINATE_SPACE::PHYSICAL,
|
||||
utils::DOMAINS domain = utils::DOMAINS::STELLAR
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
34
libmeanfield/interface/boundary/context.cppm
Normal file
34
libmeanfield/interface/boundary/context.cppm
Normal file
@@ -0,0 +1,34 @@
|
||||
module;
|
||||
#include "mean_field.h"
|
||||
|
||||
export module mean_field:boundary.contexts;
|
||||
|
||||
export namespace mean_field::boundary {
|
||||
struct BoundaryContext {
|
||||
mfem::Array<int> inf_bounds;
|
||||
mfem::Array<int> stellar_bounds;
|
||||
};
|
||||
|
||||
enum class Boundaries : uint8_t {
|
||||
STELLAR_SURFACE = 1,
|
||||
INF_SURFACE = 2
|
||||
};
|
||||
|
||||
int operator-(
|
||||
Boundaries b,
|
||||
const int a
|
||||
) {
|
||||
return static_cast<int>(static_cast<uint8_t>(b) - static_cast<uint8_t>(a));
|
||||
}
|
||||
|
||||
struct Bounds {
|
||||
double r_star_ref;
|
||||
double r_inf_ref;
|
||||
};
|
||||
|
||||
enum BoundsError : uint8_t {
|
||||
CANNOT_FIND_VACUUM
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
95
libmeanfield/interface/fem.cppm
Normal file
95
libmeanfield/interface/fem.cppm
Normal file
@@ -0,0 +1,95 @@
|
||||
module;
|
||||
|
||||
#include <stroid/stroid.h>
|
||||
#include <memory>
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:fem;
|
||||
export import :physics.contexts;
|
||||
export import :boundary.contexts;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :utils.misc;
|
||||
export import :utils.user;
|
||||
export import :quadrature.mfem;
|
||||
|
||||
export namespace mean_field::fem {
|
||||
struct FEM {
|
||||
|
||||
stroid::StroidMesh smesh;
|
||||
std::unique_ptr<mfem::ParMesh> mesh;
|
||||
|
||||
// =====================================
|
||||
// 2. Finite Element Collections
|
||||
// =====================================
|
||||
// H1 (Continuous): For Gravitational Potential (Phi) and Velocity (v)
|
||||
std::unique_ptr<mfem::FiniteElementCollection> H1_fec;
|
||||
|
||||
// L2 (Discontinuous): For Density (rho) to fix O-grid boundary scalloping
|
||||
std::unique_ptr<mfem::FiniteElementCollection> L2_fec;
|
||||
|
||||
// H(div)/RT space for gravitational field
|
||||
std::unique_ptr<mfem::RT_FECollection> RT_fec;
|
||||
|
||||
|
||||
// =====================================
|
||||
// 3. Finite Element Spaces
|
||||
// =====================================
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> H1_fes; // Scalar continuous (Gravity)
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> Vec_H1_fes; // Vector continuous (Velocity field)
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> L2_fes; // Scalar discontinuous (Density)
|
||||
std::unique_ptr<mfem::ParFiniteElementSpace> RT_fes; // H(div)/RT space for gravitational field
|
||||
|
||||
// Preconditioning for Gravity
|
||||
std::unique_ptr<mfem::ParLORDiscretization> H1_lor_disc;
|
||||
const mfem::ParFiniteElementSpace *H1_lor_fes{nullptr};
|
||||
|
||||
// =====================================
|
||||
// 4. Domain Mapping
|
||||
// =====================================
|
||||
std::unique_ptr<mapping::DomainMapper> mapping;
|
||||
|
||||
// =====================================
|
||||
// 5. Global System Tracking
|
||||
// =====================================
|
||||
// [ Velocity | Density | Mapping Parameters (Surface) ]
|
||||
mfem::Array<int> block_true_offsets;
|
||||
|
||||
mfem::Array<int> gravity_block_true_offsets;
|
||||
|
||||
// Essential Boundary Conditions for the fluid (e.g., surface stress-free)
|
||||
mfem::Array<int> ess_v_tdofs;
|
||||
|
||||
// Elements entirely in the vacuum domain where fluid equations are not solved
|
||||
mfem::Array<int> vacuum_tdof_rho;
|
||||
mfem::Array<int> vacuum_tdof_v;
|
||||
|
||||
// =====================================
|
||||
// 6. Multiphysics State & Integration
|
||||
// =====================================
|
||||
mfem::Vector com;
|
||||
mfem::DenseMatrix Q;
|
||||
|
||||
int int_order{3};
|
||||
std::unique_ptr<mfem::IntegrationRule> int_rule;
|
||||
|
||||
physics::GravityContext gravity_context;
|
||||
boundary::BoundaryContext boundary_context;
|
||||
|
||||
std::unique_ptr<quadrature::RuleFactory> quadrature_factory;
|
||||
|
||||
// =====================================
|
||||
// 7. Utilities
|
||||
// =====================================
|
||||
[[nodiscard]] bool okay() const {
|
||||
return (mesh != nullptr) &&
|
||||
(H1_fec != nullptr) && (L2_fec != nullptr) && (RT_fec != nullptr) &&
|
||||
(H1_fes != nullptr) && (Vec_H1_fes != nullptr) && (L2_fes != nullptr) && (RT_fes != nullptr);
|
||||
}
|
||||
|
||||
[[nodiscard]] bool has_mapping() const { return mapping != nullptr; }
|
||||
};
|
||||
|
||||
|
||||
FEM setup_fem(const std::string &filename, const utils::Args &args, int extra_refine = 0);
|
||||
}
|
||||
|
||||
28
libmeanfield/interface/integrators/advection.cppm
Normal file
28
libmeanfield/interface/integrators/advection.cppm
Normal file
@@ -0,0 +1,28 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.advection;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class AdvectionIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
explicit AdvectionIntegrator(const mapping::DomainMapper &map);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper &m_map;
|
||||
};
|
||||
}
|
||||
32
libmeanfield/interface/integrators/centrifugal.cppm
Normal file
32
libmeanfield/interface/integrators/centrifugal.cppm
Normal file
@@ -0,0 +1,32 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.centrifugal;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class CentrifugalForceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
CentrifugalForceIntegrator(const mapping::DomainMapper& map, const mfem::Vector& omega);
|
||||
|
||||
void SetOmega(const mfem::Vector& omega);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
mfem::Vector m_omega;
|
||||
};
|
||||
|
||||
}
|
||||
28
libmeanfield/interface/integrators/coriolis.cppm
Normal file
28
libmeanfield/interface/integrators/coriolis.cppm
Normal file
@@ -0,0 +1,28 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.coriolis;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class CoriolisIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
CoriolisIntegrator(const mapping::DomainMapper& map, const mfem::Vector& omega);
|
||||
|
||||
void AssembleElementVector(const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec) override;
|
||||
|
||||
void AssembleElementGrad(const mfem::Array<const mfem::FiniteElement*> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats) override;
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
mfem::Vector m_omega;
|
||||
mfem::DenseMatrix m_omega_mat;
|
||||
};
|
||||
|
||||
}
|
||||
32
libmeanfield/interface/integrators/gravity.cppm
Normal file
32
libmeanfield/interface/integrators/gravity.cppm
Normal file
@@ -0,0 +1,32 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.gravity;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class GravityForceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
GravityForceIntegrator(const mapping::DomainMapper& map, const mfem::GridFunction& phi);
|
||||
|
||||
void SetPotential(const mfem::GridFunction& phi);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
const mfem::GridFunction* m_phi;
|
||||
};
|
||||
}
|
||||
62
libmeanfield/interface/integrators/mass_continuity.cppm
Normal file
62
libmeanfield/interface/integrators/mass_continuity.cppm
Normal file
@@ -0,0 +1,62 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.mass_continuity;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class ContinuityVolumeIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
explicit ContinuityVolumeIntegrator(const mapping::DomainMapper& map);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
};
|
||||
|
||||
class ContinuityFaceIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
explicit ContinuityFaceIntegrator(const mapping::DomainMapper& map);
|
||||
|
||||
void AssembleFaceVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el1,
|
||||
const mfem::Array<const mfem::FiniteElement *> &el2,
|
||||
mfem::FaceElementTransformations &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvect
|
||||
) override;
|
||||
|
||||
void AssembleFaceGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el1,
|
||||
const mfem::Array<const mfem::FiniteElement *> &el2,
|
||||
mfem::FaceElementTransformations &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
private:
|
||||
static bool skip_face(const mfem::FaceElementTransformations& Tr);
|
||||
|
||||
static double compute_u_n(
|
||||
const mfem::Vector& v_dofs,
|
||||
const mfem::Vector& shape_v_minus,
|
||||
const mfem::Vector& n_unit,
|
||||
int dof_v_minus,
|
||||
int dim
|
||||
);
|
||||
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
};
|
||||
|
||||
}
|
||||
168
libmeanfield/interface/integrators/pressure_gradient.cppm
Normal file
168
libmeanfield/interface/integrators/pressure_gradient.cppm
Normal file
@@ -0,0 +1,168 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
#include "xad_promote_polyfill.h"
|
||||
#include <XAD/XAD.hpp>
|
||||
export module mean_field:integrators.pressure_gradient;
|
||||
import :mapping.domain_mapper;
|
||||
import :utils.misc;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
template <utils::is_xad EOS_T>
|
||||
class PressureGradientIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
PressureGradientIntegrator(const mapping::DomainMapper& map, utils::EOS_P<EOS_T> eos);
|
||||
|
||||
|
||||
void AssembleElementVector(const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec) override;
|
||||
void AssembleElementGrad(const mfem::Array<const mfem::FiniteElement*> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats) override;
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
utils::EOS_P<EOS_T> m_eos;
|
||||
};
|
||||
|
||||
template <utils::is_xad EOS_T>
|
||||
PressureGradientIntegrator<EOS_T>::PressureGradientIntegrator(
|
||||
const mapping::DomainMapper& map,
|
||||
utils::EOS_P<EOS_T> eos
|
||||
) : m_map(map), m_eos(std::move(eos)) {}
|
||||
|
||||
template <utils::is_xad EOS_T>
|
||||
void PressureGradientIntegrator<EOS_T>::AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) {
|
||||
if (utils::is_vacuum(Tr, elvec)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const mfem::FiniteElement* fe_v = el[0];
|
||||
const mfem::FiniteElement* fe_rho = el[1];
|
||||
|
||||
const int dof_v = fe_v->GetDof();
|
||||
const int dof_rho = fe_rho->GetDof();
|
||||
const int dim = Tr.GetSpaceDim();
|
||||
|
||||
const mfem::Vector& rho_dofs = *elfun[1];
|
||||
|
||||
mfem::Vector& r_v = *elvec[0];
|
||||
r_v.SetSize(dof_v * dim);
|
||||
r_v = 0.0;
|
||||
if (elvec[1]) {
|
||||
elvec[1]->SetSize(dof_rho);
|
||||
*elvec[1] = 0.0;
|
||||
}
|
||||
|
||||
mfem::DenseMatrix dshape_v_ref(dof_v, dim), dshape_v_phys(dof_v, dim);
|
||||
mfem::Vector shape_rho(dof_rho);
|
||||
|
||||
const mfem::IntegrationRule* ir = &mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
|
||||
|
||||
for (int q = 0; q < ir->GetNPoints(); ++q) {
|
||||
const mfem::IntegrationPoint& ip = ir->IntPoint(q);
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
||||
|
||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
||||
fe_rho->CalcShape(ip, shape_rho);
|
||||
|
||||
double rho_val = 0.0;
|
||||
for (int i = 0; i < dof_rho; ++i) rho_val += rho_dofs(i) * shape_rho(i);
|
||||
|
||||
// Guard against negative density from Newton solver overshoots
|
||||
if (rho_val < 1e-15) rho_val = 1e-15;
|
||||
|
||||
// Evaluate the exact Equation of State Pressure
|
||||
EOS_T x_rho = rho_val;
|
||||
double P_val = m_eos(x_rho, EOS_T(0.0)).value();
|
||||
|
||||
for (int i = 0; i < dof_v; ++i) {
|
||||
for (int c = 0; c < dim; ++c) {
|
||||
r_v(i + c * dof_v) -= dshape_v_phys(i, c) * P_val * weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <utils::is_xad EOS_T>
|
||||
void PressureGradientIntegrator<EOS_T>::AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement*> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) {
|
||||
const mfem::FiniteElement* fe_v = el[0];
|
||||
const mfem::FiniteElement* fe_rho = el[1];
|
||||
|
||||
const int dof_v = fe_v->GetDof();
|
||||
const int dof_rho = fe_rho->GetDof();
|
||||
const int dim = Tr.GetSpaceDim();
|
||||
|
||||
const mfem::Vector& rho_dofs = *elfun[1];
|
||||
|
||||
mfem::DenseMatrix* dv_dv = elmats(0, 0);
|
||||
mfem::DenseMatrix* dv_drho = elmats(0, 1);
|
||||
|
||||
if (dv_dv) *dv_dv = 0.0;
|
||||
if (dv_drho) *dv_drho = 0.0;
|
||||
if (!dv_drho) return;
|
||||
|
||||
mfem::DenseMatrix dshape_v_ref(dof_v, dim), dshape_v_phys(dof_v, dim);
|
||||
mfem::Vector shape_rho(dof_rho);
|
||||
|
||||
const mfem::IntegrationRule* ir = &mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
|
||||
|
||||
for (int q = 0; q < ir->GetNPoints(); ++q) {
|
||||
using Scalar = EOS_T::value_type;
|
||||
xad::Tape<Scalar> tape;
|
||||
const mfem::IntegrationPoint& ip = ir->IntPoint(q);
|
||||
Tr.SetIntPoint(&ip);
|
||||
|
||||
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
|
||||
|
||||
fe_v->CalcDShape(ip, dshape_v_ref);
|
||||
mfem::Mult(dshape_v_ref, J_inv, dshape_v_phys);
|
||||
fe_rho->CalcShape(ip, shape_rho);
|
||||
|
||||
EOS_T x_rho(0.0);
|
||||
tape.registerInput(x_rho);
|
||||
tape.newRecording();
|
||||
|
||||
for (int i = 0; i < dof_rho; ++i) {
|
||||
x_rho += rho_dofs(i) * shape_rho(i);
|
||||
}
|
||||
if (x_rho < 1e-15) x_rho = EOS_T(1e-15);
|
||||
EOS_T x_P = m_eos(x_rho, EOS_T(0.0));
|
||||
tape.registerOutput(x_P);
|
||||
x_P.setAdjoint(1.0);
|
||||
tape.computeAdjoints();
|
||||
double dP_drho = x_rho.getAdjoint();
|
||||
|
||||
double debug_K = 1.5;
|
||||
double debug_n = 3.0;
|
||||
double analytic_dp = debug_K * (1.0 + 1.0 / debug_n) * std::pow(xad::value(x_rho), 1.0 / debug_n);
|
||||
|
||||
double ad_err = std::abs(dP_drho - analytic_dp);
|
||||
|
||||
for (int i = 0; i < dof_v; ++i) {
|
||||
for (int c = 0; c < dim; ++c) {
|
||||
int row = i + c * dof_v;
|
||||
for (int j = 0; j < dof_rho; ++j) {
|
||||
int col = j;
|
||||
double term = dshape_v_phys(i, c) * dP_drho * shape_rho(j);
|
||||
(*dv_drho)(row, col) -= term * weight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
32
libmeanfield/interface/integrators/viscosity.cppm
Normal file
32
libmeanfield/interface/integrators/viscosity.cppm
Normal file
@@ -0,0 +1,32 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
export module mean_field:integrators.viscosity;
|
||||
import :mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::integrators {
|
||||
class ViscosityIntegrator : public mfem::BlockNonlinearFormIntegrator {
|
||||
public:
|
||||
ViscosityIntegrator(const mapping::DomainMapper& map, double mu, int quad_boost);
|
||||
|
||||
void SetMu(const double mu);
|
||||
|
||||
void AssembleElementVector(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array<mfem::Vector *> &elvec
|
||||
) override;
|
||||
|
||||
void AssembleElementGrad(
|
||||
const mfem::Array<const mfem::FiniteElement *> &el,
|
||||
mfem::ElementTransformation &Tr,
|
||||
const mfem::Array<const mfem::Vector *> &elfun,
|
||||
const mfem::Array2D<mfem::DenseMatrix *> &elmats
|
||||
) override;
|
||||
private:
|
||||
const mapping::DomainMapper& m_map;
|
||||
double m_mu;
|
||||
int m_quad_boost;
|
||||
};
|
||||
|
||||
}
|
||||
95
libmeanfield/interface/mapping/coefficients.cppm
Normal file
95
libmeanfield/interface/mapping/coefficients.cppm
Normal file
@@ -0,0 +1,95 @@
|
||||
module;
|
||||
#include "mean_field.h"
|
||||
|
||||
export module mean_field:mapping.coefficients;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :mapping.types;
|
||||
|
||||
export namespace mean_field::mapping {
|
||||
class MappedScalarCoefficient : public mfem::Coefficient {
|
||||
public:
|
||||
MappedScalarCoefficient(
|
||||
const DomainMapper &map,
|
||||
mfem::Coefficient &coeff,
|
||||
COORDINATE_SPACE coord_space = COORDINATE_SPACE::PHYSICAL
|
||||
);
|
||||
|
||||
double Eval(
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
) override;
|
||||
|
||||
private:
|
||||
static double eval_at_point(
|
||||
mfem::Coefficient &c,
|
||||
mfem::ElementTransformation &T,
|
||||
const mfem::IntegrationPoint &ip
|
||||
);
|
||||
|
||||
private:
|
||||
const DomainMapper &m_map;
|
||||
mfem::Coefficient &m_coeff;
|
||||
COORDINATE_SPACE m_coord_space;
|
||||
};
|
||||
|
||||
class MappedDiffusionCoefficient : public mfem::MatrixCoefficient {
|
||||
public:
|
||||
MappedDiffusionCoefficient(
|
||||
const DomainMapper &map,
|
||||
mfem::Coefficient &sigma,
|
||||
int dim
|
||||
);
|
||||
|
||||
MappedDiffusionCoefficient(
|
||||
const DomainMapper &map,
|
||||
mfem::MatrixCoefficient &sigma
|
||||
);
|
||||
|
||||
void Eval(mfem::DenseMatrix &K, mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) override;
|
||||
|
||||
private:
|
||||
const DomainMapper &m_map;
|
||||
mfem::Coefficient *m_scalar;
|
||||
mfem::MatrixCoefficient *m_tensor;
|
||||
};
|
||||
|
||||
class MappedVectorCoefficient : public mfem::VectorCoefficient {
|
||||
public:
|
||||
MappedVectorCoefficient(
|
||||
const DomainMapper &map,
|
||||
mfem::VectorCoefficient &coeff
|
||||
);
|
||||
|
||||
void Eval(mfem::Vector &V, mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) override;
|
||||
|
||||
private:
|
||||
const DomainMapper &m_map;
|
||||
mfem::VectorCoefficient &m_coeff;
|
||||
};
|
||||
|
||||
class PhysicalPositionFunctionCoefficient : public mfem::Coefficient {
|
||||
public:
|
||||
using Func = std::function<double(const mfem::Vector &x)>;
|
||||
|
||||
PhysicalPositionFunctionCoefficient(
|
||||
const DomainMapper &map,
|
||||
Func f
|
||||
);
|
||||
|
||||
double Eval(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) override;
|
||||
|
||||
private:
|
||||
Func m_f;
|
||||
const DomainMapper &m_map;
|
||||
};
|
||||
|
||||
class MappedHDivMassCoefficient final : public mfem::MatrixCoefficient {
|
||||
public:
|
||||
MappedHDivMassCoefficient(const DomainMapper& map, const int dim);
|
||||
|
||||
void Eval(mfem::DenseMatrix& matrix, mfem::ElementTransformation& transformation, const mfem::IntegrationPoint& integration_point) override;
|
||||
private:
|
||||
const DomainMapper& m_map;
|
||||
|
||||
};
|
||||
}
|
||||
103
libmeanfield/interface/mapping/domain_mapper.cppm
Normal file
103
libmeanfield/interface/mapping/domain_mapper.cppm
Normal file
@@ -0,0 +1,103 @@
|
||||
module;
|
||||
|
||||
#include "mean_field.h"
|
||||
|
||||
export module mean_field:mapping.domain_mapper;
|
||||
|
||||
export namespace mean_field::mapping {
|
||||
class DomainMapper {
|
||||
public:
|
||||
struct VolumeQuadratureContext {
|
||||
mfem::DenseMatrix J_inv;
|
||||
double detJ;
|
||||
double weight;
|
||||
};
|
||||
|
||||
struct FaceQuadratureContext {
|
||||
mfem::Vector normal;
|
||||
double ds;
|
||||
double v_dot_n_scale;
|
||||
};
|
||||
|
||||
public:
|
||||
explicit DomainMapper(const double r_star_ref, const double r_inf_ref);
|
||||
|
||||
explicit DomainMapper(const mfem::GridFunction &d, const double r_star_ref, const double r_inf_ref);
|
||||
|
||||
[[nodiscard]] bool is_vacuum(const mfem::ElementTransformation &T) const;
|
||||
|
||||
void SetDisplacement(const mfem::GridFunction &d);
|
||||
|
||||
[[nodiscard]] bool IsIdentity() const;
|
||||
|
||||
void ResetDisplacement();
|
||||
|
||||
void ComputeJacobian(mfem::ElementTransformation &T, mfem::DenseMatrix &J) const;
|
||||
|
||||
double ComputeDetJ(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) const;
|
||||
|
||||
void ComputeMappedDiffusionTensor(mfem::ElementTransformation &T, mfem::DenseMatrix &D) const;
|
||||
|
||||
void ComputeInverseJacobian(mfem::ElementTransformation &T, mfem::DenseMatrix &JInv) const;
|
||||
|
||||
VolumeQuadratureContext GetQuadratureContext(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip) const;
|
||||
|
||||
FaceQuadratureContext GetFaceQuadratureContext(mfem::FaceElementTransformations &T, const mfem::IntegrationPoint &ip) const;
|
||||
|
||||
void GetPhysicalPoint(mfem::ElementTransformation &T, const mfem::IntegrationPoint &ip, mfem::Vector &x_phys) const;
|
||||
|
||||
void GetVectorValue(const int i, const mfem::IntegrationPoint &ip, mfem::Vector &val) const;
|
||||
|
||||
[[nodiscard]] const mfem::GridFunction *GetDisplacement() const;
|
||||
|
||||
[[nodiscard]] double GetPhysInfRadius() const;
|
||||
|
||||
[[nodiscard]] size_t GetCacheHits() const;
|
||||
|
||||
[[nodiscard]] size_t GetCacheMisses() const;
|
||||
|
||||
[[nodiscard]] double GetCacheHitRate() const;
|
||||
|
||||
void ResetCacheStats() const;
|
||||
|
||||
private:
|
||||
void InitAllScratchSpaces() const;
|
||||
|
||||
void ApplyKelvinMapping(const mfem::Vector &x_ref, mfem::Vector &x_phys) const;
|
||||
|
||||
void ComputeKelvinJacobian(const mfem::Vector &x_ref, const mfem::Vector &x_disp, const mfem::DenseMatrix &J_D, mfem::DenseMatrix &J) const;
|
||||
|
||||
void InvalidateCache() const;
|
||||
|
||||
void UpdateElementCache(const mfem::ElementTransformation &T) const;
|
||||
|
||||
private:
|
||||
const mfem::GridFunction *m_d;
|
||||
std::unique_ptr<mfem::GridFunction> m_internal_d;
|
||||
const int m_dim{3};
|
||||
const int m_vacuum_attr{3};
|
||||
const double m_r_star_ref{1.0};
|
||||
const double m_r_inf_ref{2.0};
|
||||
const double m_xi_clamp{0.9999};
|
||||
|
||||
mutable int m_cached_elem_id{-1};
|
||||
mutable int m_cached_elem_type{mfem::ElementTransformation::ELEMENT};
|
||||
mutable const mfem::FiniteElement *m_fe{nullptr};
|
||||
|
||||
mutable mfem::Vector m_elem_dofs;
|
||||
mutable mfem::DenseMatrix m_dof_mat;
|
||||
mutable mfem::DenseMatrix m_dshape;
|
||||
mutable mfem::Vector m_shape;
|
||||
|
||||
mutable size_t m_cache_hits{0};
|
||||
mutable size_t m_cache_misses{0};
|
||||
|
||||
mutable mfem::DenseMatrix m_J_D;
|
||||
mutable mfem::DenseMatrix m_J_temp;
|
||||
mutable mfem::DenseMatrix m_JInv_temp;
|
||||
mutable mfem::Vector m_x_ref;
|
||||
mutable mfem::Vector m_x_disp;
|
||||
mutable mfem::Vector m_d_val;
|
||||
};
|
||||
|
||||
}
|
||||
10
libmeanfield/interface/mapping/types.cppm
Normal file
10
libmeanfield/interface/mapping/types.cppm
Normal file
@@ -0,0 +1,10 @@
|
||||
module;
|
||||
#include <cstdint>
|
||||
export module mean_field:mapping.types;
|
||||
|
||||
namespace mean_field::mapping {
|
||||
enum class COORDINATE_SPACE : uint8_t {
|
||||
PHYSICAL,
|
||||
REFERENCE
|
||||
};
|
||||
}
|
||||
21
libmeanfield/interface/mean_field.cppm
Normal file
21
libmeanfield/interface/mean_field.cppm
Normal file
@@ -0,0 +1,21 @@
|
||||
export module mean_field;
|
||||
|
||||
export import :fem;
|
||||
export import :utils.misc;
|
||||
export import :utils.user;
|
||||
export import :utils.domain;
|
||||
export import :physics.gravity;
|
||||
export import :physics.contexts;
|
||||
export import :boundary.contexts;
|
||||
export import :analysis.integral;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :mapping.coefficients;
|
||||
export import :integrators.advection;
|
||||
export import :integrators.centrifugal;
|
||||
export import :integrators.gravity;
|
||||
export import :integrators.coriolis;
|
||||
export import :integrators.mass_continuity;
|
||||
export import :integrators.pressure_gradient;
|
||||
export import :integrators.viscosity;
|
||||
export import :quadrature.policy;
|
||||
export import :quadrature.mfem;
|
||||
28
libmeanfield/interface/physics/context.cppm
Normal file
28
libmeanfield/interface/physics/context.cppm
Normal file
@@ -0,0 +1,28 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:physics.contexts;
|
||||
export import :mapping.coefficients;
|
||||
|
||||
export namespace mean_field::physics {
|
||||
struct GravityContext {
|
||||
std::unique_ptr<mfem::ParBilinearForm> m_form;
|
||||
std::unique_ptr<mfem::ParMixedBilinearForm> b_form;
|
||||
|
||||
std::unique_ptr<mfem::BlockOperator> block_A;
|
||||
|
||||
std::unique_ptr<mfem::Solver> prec_M;
|
||||
std::unique_ptr<mfem::HypreBoomerAMG> prec_Phi;
|
||||
std::unique_ptr<mfem::BlockDiagonalPreconditioner> block_prec;
|
||||
|
||||
std::unique_ptr<mfem::MINRESSolver> minres;
|
||||
|
||||
mfem::Array<int> stellar_mask;
|
||||
|
||||
std::unique_ptr<mfem::TransposeOperator> BT;
|
||||
std::unique_ptr<mfem::HypreParMatrix> Schur;
|
||||
|
||||
std::unique_ptr<mfem::MatrixCoefficient> mapped_hdiv_mass_coeff;
|
||||
|
||||
};
|
||||
}
|
||||
45
libmeanfield/interface/physics/gravity.cppm
Normal file
45
libmeanfield/interface/physics/gravity.cppm
Normal file
@@ -0,0 +1,45 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:physics.gravity;
|
||||
|
||||
export import :fem;
|
||||
|
||||
export namespace mean_field::physics {
|
||||
struct GravitySolution {
|
||||
mfem::ParGridFunction gradPhi;
|
||||
mfem::ParGridFunction phi;
|
||||
|
||||
explicit GravitySolution(fem::FEM& fem): gradPhi(fem.RT_fes.get()), phi(fem.L2_fes.get()) {}
|
||||
};
|
||||
|
||||
GravitySolution grav_potential(
|
||||
fem::FEM &f,
|
||||
const utils::Args &args,
|
||||
const mfem::GridFunction &rho,
|
||||
bool phi_warm = false
|
||||
);
|
||||
|
||||
mfem::GridFunction get_potential(
|
||||
fem::FEM &fem,
|
||||
const utils::Args &args,
|
||||
const mfem::GridFunction &rho,
|
||||
bool warm = false
|
||||
);
|
||||
|
||||
mfem::DenseMatrix compute_quadrupole_moment_tensor(
|
||||
const fem::FEM &fem,
|
||||
const mfem::GridFunction &rho,
|
||||
const mfem::Vector &com
|
||||
);
|
||||
|
||||
double l2_multipole_potential(
|
||||
const fem::FEM &fem,
|
||||
double total_mass,
|
||||
const mfem::Vector &phys_x
|
||||
);
|
||||
|
||||
void update_stiffness_matrix(fem::FEM &fem);
|
||||
}
|
||||
|
||||
|
||||
9
libmeanfield/interface/physics/solid.cppm
Normal file
9
libmeanfield/interface/physics/solid.cppm
Normal file
@@ -0,0 +1,9 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:physics.solid_body;
|
||||
export import :fem;
|
||||
|
||||
export namespace mean_field::physics {
|
||||
double compute_moment_of_inertia(const fem::FEM &fem, const mfem::GridFunction &rho_ref);
|
||||
}
|
||||
198
libmeanfield/interface/quadrature/mfem.cppm
Normal file
198
libmeanfield/interface/quadrature/mfem.cppm
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
256
libmeanfield/interface/quadrature/policy.cppm
Normal file
256
libmeanfield/interface/quadrature/policy.cppm
Normal 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.");
|
||||
}
|
||||
|
||||
}
|
||||
24
libmeanfield/interface/utils/domain.cppm
Normal file
24
libmeanfield/interface/utils/domain.cppm
Normal file
@@ -0,0 +1,24 @@
|
||||
module;
|
||||
#include <mfem.hpp>
|
||||
|
||||
export module mean_field:utils.domain;
|
||||
export import :fem;
|
||||
export import :mapping.domain_mapper;
|
||||
export import :boundary.contexts;
|
||||
|
||||
export namespace mean_field::utils {
|
||||
|
||||
bool get_reference_point(
|
||||
const fem::FEM &fem,
|
||||
const mfem::Vector &x_phys_target,
|
||||
mfem::Vector &x_ref
|
||||
);
|
||||
|
||||
double eval_grid_function_at_point(
|
||||
const fem::FEM &fem,
|
||||
const mfem::GridFunction &u,
|
||||
const mfem::Vector &x,
|
||||
mapping::COORDINATE_SPACE vspace = mapping::COORDINATE_SPACE::REFERENCE,
|
||||
mapping::COORDINATE_SPACE rspace = mapping::COORDINATE_SPACE::PHYSICAL
|
||||
);
|
||||
}
|
||||
101
libmeanfield/interface/utils/misc.cppm
Normal file
101
libmeanfield/interface/utils/misc.cppm
Normal file
@@ -0,0 +1,101 @@
|
||||
module;
|
||||
#include <string_view>
|
||||
#include <functional>
|
||||
#include <expected>
|
||||
|
||||
#include <mfem.hpp>
|
||||
|
||||
#include "xad_promote_polyfill.h"
|
||||
#include <XAD/XAD.hpp>
|
||||
|
||||
export module mean_field:utils.misc;
|
||||
import :boundary.contexts;
|
||||
|
||||
export namespace mean_field::utils {
|
||||
constexpr double APPROX_MAX_ACCEPTABLE_POTENTIAL_ERROR_SI_BURNING = 1e-4;
|
||||
|
||||
|
||||
bool is_vacuum(const mfem::ElementTransformation &Tr, mfem::Array<mfem::Vector*> elvec) {
|
||||
if (Tr.Attribute == 3) {
|
||||
const int size_elvec = elvec.Size();
|
||||
for (int i = 0; i < size_elvec; i++) {
|
||||
if (elvec[i]) {
|
||||
*elvec[i] = 0.0;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
constexpr std::string_view ANSI_GREEN = "\033[32m";
|
||||
constexpr std::string_view ANSI_RED = "\033[31m";
|
||||
constexpr std::string_view ANSI_YELLOW = "\033[33m";
|
||||
constexpr std::string_view ANSI_BLUE = "\033[34m";
|
||||
constexpr std::string_view ANSI_MAGENTA = "\033[35m";
|
||||
constexpr std::string_view ANSI_CYAN = "\033[36m";
|
||||
constexpr std::string_view ANSI_RESET = "\033[0m";
|
||||
constexpr std::string_view ANSI_BCYAN = "\033[1;36m";
|
||||
|
||||
|
||||
constexpr double G = 1.0;
|
||||
constexpr double MASS = 1.0;
|
||||
constexpr double RADIUS = 1.0;
|
||||
|
||||
[[maybe_unused]] constexpr char HOST[10] = "localhost";
|
||||
[[maybe_unused]] constexpr int PORT = 19916;
|
||||
|
||||
|
||||
template<typename T>
|
||||
concept is_xad =
|
||||
std::is_same_v<T, xad::AReal<long double> >
|
||||
|| std::is_same_v<T, xad::AReal<double> >
|
||||
|| std::is_same_v<T, xad::AReal<float> >;
|
||||
|
||||
template<typename T>
|
||||
concept is_real = std::is_floating_point_v<T> || is_xad<T>;
|
||||
|
||||
template<is_real T>
|
||||
using EOS_P = std::function<T(const T& rho, const T& temp)>;
|
||||
|
||||
enum class DOMAINS : uint8_t {
|
||||
CORE = 1 << 0,
|
||||
ENVELOPE = 1 << 1,
|
||||
VACUUM = 1 << 2,
|
||||
STELLAR = CORE | ENVELOPE,
|
||||
ALL = CORE | ENVELOPE | VACUUM
|
||||
};
|
||||
|
||||
|
||||
DOMAINS operator|(
|
||||
DOMAINS lhs,
|
||||
DOMAINS rhs
|
||||
);
|
||||
|
||||
DOMAINS operator&(
|
||||
DOMAINS lhs,
|
||||
DOMAINS rhs
|
||||
);
|
||||
|
||||
void populate_element_mask(
|
||||
const mfem::Mesh* mesh,
|
||||
DOMAINS domain,
|
||||
mfem::Array<int> &mask
|
||||
);
|
||||
|
||||
void populate_domain_tdofs(
|
||||
const mfem::ParFiniteElementSpace *fes,
|
||||
const mfem::Array<int> &element_mask,
|
||||
mfem::Array<int> &ess_tdof
|
||||
);
|
||||
|
||||
std::expected<boundary::Bounds, boundary::BoundsError> discover_bounds(
|
||||
const mfem::Mesh *mesh,
|
||||
int vacuum_attr
|
||||
);
|
||||
|
||||
int get_mesh_order(
|
||||
const mfem::Mesh &mesh
|
||||
);
|
||||
|
||||
}
|
||||
36
libmeanfield/interface/utils/user.cppm
Normal file
36
libmeanfield/interface/utils/user.cppm
Normal file
@@ -0,0 +1,36 @@
|
||||
module;
|
||||
#include <string>
|
||||
export module mean_field:utils.user;
|
||||
export import :quadrature.policy;
|
||||
|
||||
export namespace mean_field::utils {
|
||||
struct potential {
|
||||
double rtol;
|
||||
double atol;
|
||||
int max_iters;
|
||||
};
|
||||
|
||||
struct rot {
|
||||
bool enabled;
|
||||
double omega;
|
||||
double L;
|
||||
};
|
||||
|
||||
struct Args {
|
||||
std::string mesh_file;
|
||||
potential p{};
|
||||
rot r{};
|
||||
bool verbose{};
|
||||
double index{};
|
||||
double mass{};
|
||||
double c{};
|
||||
|
||||
int quad_boost{0};
|
||||
|
||||
int max_iters{};
|
||||
double tol{};
|
||||
|
||||
quadrature::QuadratureOptions quadrature{};
|
||||
};
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user