Files
MeanField/libmeanfield/impl/integrators/gravity.cpp
Emily Boudreaux 9bc4f2758a feat(mean_field): added initial implementation
note this implementation lacks many tests
2026-07-15 09:44:43 -04:00

124 lines
4.2 KiB
C++

module;
#include <mfem.hpp>
module mean_field;
namespace mean_field::integrators {
GravityForceIntegrator::GravityForceIntegrator(
const mapping::DomainMapper& map,
const mfem::GridFunction& phi
): m_map(map), m_phi(&phi) {}
void GravityForceIntegrator::SetPotential(const mfem::GridFunction& phi) { m_phi = &phi; };
void GravityForceIntegrator::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::Vector shape_v(dof_v), shape_rho(dof_rho);
mfem::Vector grad_phi_ref(dim), grad_phi_phys(dim), grad_phi_elem(dim);
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);
m_phi->GetGradient(Tr, grad_phi_elem);
mfem::DenseMatrix J_map(dim, dim), J_map_inv(dim, dim);
m_map.ComputeJacobian(Tr, J_map);
mfem::CalcInverse(J_map, J_map_inv);
J_map_inv.MultTranspose(grad_phi_elem, grad_phi_phys);
fe_v->CalcShape(ip, shape_v);
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);
}
for (int i = 0; i < dof_v; ++i) {
for (int c = 0; c < dim; ++c) {
r_v(i + c * dof_v) += shape_v(i) * rho_val * grad_phi_phys(c) * weight;
}
}
}
}
void GravityForceIntegrator::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();
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::Vector shape_v(dof_v), shape_rho(dof_rho);
mfem::Vector grad_phi_ref(dim), grad_phi_phys(dim), grad_phi_elem(dim);
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);
m_phi->GetGradient(Tr, grad_phi_elem);
mfem::DenseMatrix J_map(dim, dim), J_map_inv(dim, dim);
m_map.ComputeJacobian(Tr, J_map);
mfem::CalcInverse(J_map, J_map_inv);
J_map_inv.MultTranspose(grad_phi_elem, grad_phi_phys);
fe_v->CalcShape(ip, shape_v);
fe_rho->CalcShape(ip, shape_rho);
for (int i = 0; i < dof_v; ++i) {
for (int c = 0; c < dim; ++c) {
const int row = i + c * dof_v;
for (int j = 0; j < dof_rho; ++j) {
(*dv_drho)(row, j) += shape_v(i) * shape_rho(j) * grad_phi_phys(c) * weight;
}
}
}
}
}
}