feat(libmeanfield): centrifugal + pressure

This commit is contained in:
2026-08-04 14:24:55 -04:00
parent 9bc4f2758a
commit dc912fd15e
115 changed files with 260058 additions and 163261 deletions

View File

@@ -4,7 +4,10 @@ module;
module mean_field;
namespace mean_field::integrators {
ContinuityVolumeIntegrator::ContinuityVolumeIntegrator(const mapping::DomainMapper& map) : m_map(map) {};
ContinuityVolumeIntegrator::ContinuityVolumeIntegrator(
const mapping::DomainMapper &map
)
: m_map(map) { };
void ContinuityVolumeIntegrator::AssembleElementVector(
const mfem::Array<const mfem::FiniteElement *> &el,
@@ -16,35 +19,37 @@ namespace mean_field::integrators {
return;
}
const mfem::FiniteElement *fe_v = el[0];
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 int dof_v = fe_v->GetDof();
const int dof_rho = fe_rho->GetDof();
const int dim = Tr.GetSpaceDim();
const mfem::Vector v_dofs = *elfun[0];
const mfem::Vector rho_dofs = *elfun[1];
const mfem::Vector v_dofs = *elfun[0];
const mfem::Vector rho_dofs = *elfun[1];
void* data_rho_before = elvec[1] ? (void*)elvec[1]->GetData() : nullptr;
void *data_rho_before =
elvec[1] ? (void *)elvec[1]->GetData() : nullptr;
int size_rho_before = elvec[1] ? elvec[1]->Size() : -1;
if (elvec[0]) {
elvec[0]->SetSize(dof_v * dim);
*elvec[0] = 0.0;
}
mfem::Vector& r_rho = *elvec[1];
mfem::Vector &r_rho = *elvec[1];
r_rho.SetSize(dof_rho);
r_rho = 0.0;
mfem::Vector shape_v(dof_v), shape_rho(dof_rho);
mfem::DenseMatrix dshape_rho_ref(dof_rho, dim), dshape_rho_phys(dof_rho, dim);
mfem::DenseMatrix dshape_rho_ref(dof_rho, dim),
dshape_rho_phys(dof_rho, dim);
const mfem::IntegrationRule* ir = &mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
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);
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
Tr.SetIntPoint(&ip);
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
@@ -54,7 +59,8 @@ namespace mean_field::integrators {
fe_rho->CalcDShape(ip, dshape_rho_ref);
mfem::Mult(dshape_rho_ref, J_inv, dshape_rho_phys);
mfem::Vector v_val(dim); v_val = 0.0;
mfem::Vector v_val(dim);
v_val = 0.0;
for (int i = 0; i < dof_v; ++i) {
for (int c = 0; c < dim; ++c) {
const int row = i + c * dof_v;
@@ -83,32 +89,38 @@ namespace mean_field::integrators {
const mfem::Array2D<mfem::DenseMatrix *> &elmats
) {
const mfem::FiniteElement *fe_v = el[0];
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 int dof_v = fe_v->GetDof();
const int dof_rho = fe_rho->GetDof();
const int dim = Tr.GetSpaceDim();
const mfem::Vector& v_dofs = *elfun[0];
const mfem::Vector& rho_dofs = *elfun[1];
const mfem::Vector &v_dofs = *elfun[0];
const mfem::Vector &rho_dofs = *elfun[1];
mfem::DenseMatrix* drho_dv = elmats(1, 0);
mfem::DenseMatrix* drho_drho = elmats(1, 1);
mfem::DenseMatrix *drho_dv = elmats(1, 0);
mfem::DenseMatrix *drho_drho = elmats(1, 1);
if (elmats(0, 0)) *elmats(0, 0) = 0.0;
if (elmats(0, 1)) *elmats(0, 1) = 0.0;
if (elmats(0, 0))
*elmats(0, 0) = 0.0;
if (elmats(0, 1))
*elmats(0, 1) = 0.0;
if (drho_dv) *drho_dv = 0.0;
if (drho_drho) *drho_drho = 0.0;
if (drho_dv)
*drho_dv = 0.0;
if (drho_drho)
*drho_drho = 0.0;
mfem::Vector shape_v(dof_v), shape_rho(dof_rho);
mfem::DenseMatrix dshape_rho_ref(dof_rho, dim), dshape_rho_phys(dof_rho, dim);
mfem::DenseMatrix dshape_rho_ref(dof_rho, dim),
dshape_rho_phys(dof_rho, dim);
const mfem::IntegrationRule* ir = &mfem::IntRules.Get(fe_v->GetGeomType(), 2 * fe_v->GetOrder());
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);
const mfem::IntegrationPoint &ip = ir->IntPoint(q);
Tr.SetIntPoint(&ip);
auto [J_inv, detJ, weight] = m_map.GetQuadratureContext(Tr, ip);
@@ -118,7 +130,8 @@ namespace mean_field::integrators {
fe_rho->CalcDShape(ip, dshape_rho_ref);
mfem::Mult(dshape_rho_ref, J_inv, dshape_rho_phys);
mfem::Vector v_val(dim); v_val = 0.0;
mfem::Vector v_val(dim);
v_val = 0.0;
for (int i = 0; i < dof_v; ++i) {
for (int c = 0; c < dim; ++c) {
const int row = i + c * dof_v;
@@ -136,7 +149,8 @@ namespace mean_field::integrators {
for (int j = 0; j < dof_v; ++j) {
for (int d = 0; d < dim; ++d) {
const int col = j + d * dof_v;
(*drho_dv)(i, col) -= dshape_rho_phys(i, d) * rho_val * shape_v(j) * weight;
(*drho_dv)(i, col) -= dshape_rho_phys(i, d) *
rho_val * shape_v(j) * weight;
}
}
}
@@ -149,15 +163,19 @@ namespace mean_field::integrators {
grad_psi_dot_v += dshape_rho_phys(i, c) * v_val(c);
}
for (int j = 0; j < dof_rho; ++j) {
(*drho_drho)(i, j) -= grad_psi_dot_v * shape_rho(j) * weight;
(*drho_drho)(i, j) -=
grad_psi_dot_v * shape_rho(j) * weight;
}
}
}
}
}
ContinuityFaceIntegrator::ContinuityFaceIntegrator(const mapping::DomainMapper& map): m_map(map) {}
ContinuityFaceIntegrator::ContinuityFaceIntegrator(
const mapping::DomainMapper &map
)
: m_map(map) {
}
void ContinuityFaceIntegrator::AssembleFaceVector(
const mfem::Array<const mfem::FiniteElement *> &el1,
@@ -166,19 +184,19 @@ namespace mean_field::integrators {
const mfem::Array<const mfem::Vector *> &elfun,
const mfem::Array<mfem::Vector *> &elvect
) {
const mfem::FiniteElement *fe_v_minus = el1[0];
const mfem::FiniteElement *fe_v_plus = el2[0];
const mfem::FiniteElement *fe_v_minus = el1[0];
const mfem::FiniteElement *fe_v_plus = el2[0];
const mfem::FiniteElement *fe_rho_minus = el1[1];
const mfem::FiniteElement *fe_rho_plus = el2[1];
const mfem::FiniteElement *fe_rho_plus = el2[1];
const int dof_v_minus = fe_v_minus->GetDof();
const int dof_v_plus = fe_v_plus->GetDof();
const int dof_v_minus = fe_v_minus->GetDof();
const int dof_v_plus = fe_v_plus->GetDof();
const int dof_rho_minus = fe_rho_minus->GetDof();
const int dof_rho_plus = fe_rho_plus->GetDof();
const int dof_rho_minus = fe_rho_minus->GetDof();
const int dof_rho_plus = fe_rho_plus->GetDof();
const int dim = Tr.GetSpaceDim();
const int dim = Tr.GetSpaceDim();
if (elvect[0]) {
elvect[0]->SetSize(dim * dof_v_minus + dim * dof_v_plus);
@@ -186,10 +204,10 @@ namespace mean_field::integrators {
}
mfem::Vector &r_rho = *elvect[1];
r_rho.SetSize(dof_rho_minus + dof_rho_plus);
r_rho = 0.0;
r_rho = 0.0;
const int attr_minus = Tr.Elem1->Attribute;
const int attr_plus = (Tr.Elem2 != nullptr) ? Tr.Elem2->Attribute : -1;
const int attr_plus = (Tr.Elem2 != nullptr) ? Tr.Elem2->Attribute : -1;
constexpr int VACUUM_ATTR = 3;
if (attr_minus == VACUUM_ATTR || attr_plus == VACUUM_ATTR) {
@@ -200,30 +218,39 @@ namespace mean_field::integrators {
return; // Boundary face,
}
const mfem::Vector &v_dofs = *elfun[0]; // Size: dim * dof_v_minus + dim*dof_v_plus
const mfem::Vector &rho_dofs = *elfun[1]; // Size: dof_rho_minus + dof_rho_plus
const mfem::Vector &v_dofs =
*elfun[0]; // Size: dim * dof_v_minus + dim*dof_v_plus
const mfem::Vector &rho_dofs =
*elfun[1]; // Size: dof_rho_minus + dof_rho_plus
// Helpers to auto offset to the correct point in the dof array
auto rho_minus_dof = [&](const int i) {return rho_dofs(i);};
auto rho_plus_dof = [&](const int i) {return rho_dofs(i + dof_rho_minus);};
auto v_minus_dof = [&](const int k, const int c) {return v_dofs(k + c * dof_v_minus);};
auto rho_minus_dof = [&](const int i) { return rho_dofs(i); };
auto rho_plus_dof = [&](const int i) {
return rho_dofs(i + dof_rho_minus);
};
auto v_minus_dof = [&](const int k, const int c) {
return v_dofs(k + c * dof_v_minus);
};
const int p_v = fe_v_minus->GetOrder();
const int p_rho = fe_rho_minus->GetOrder();
const int p_v = fe_v_minus->GetOrder();
const int p_rho = fe_rho_minus->GetOrder();
const int int_order = 2 * std::max(p_v, p_rho) + 1;
const mfem::IntegrationRule *ir = &mfem::IntRules.Get(Tr.GetGeometryType(), int_order);
const mfem::IntegrationRule *ir =
&mfem::IntRules.Get(Tr.GetGeometryType(), int_order);
mfem::Vector shape_v_minus(dof_v_minus), shape_rho_minus(dof_rho_minus), shape_rho_plus(dof_rho_plus);
mfem::Vector shape_v_minus(dof_v_minus), shape_rho_minus(dof_rho_minus),
shape_rho_plus(dof_rho_plus);
for (int q = 0; q < ir->GetNPoints(); ++q) {
const mfem::IntegrationPoint& face_ip = ir->IntPoint(q);
const mfem::IntegrationPoint &face_ip = ir->IntPoint(q);
Tr.SetAllIntPoints(&face_ip);
const mfem::IntegrationPoint &ip_minus = Tr.GetElement1IntPoint();
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
auto [n_unit, ds, v_dot_n_scale] = m_map.GetFaceQuadratureContext(Tr, face_ip);
auto [n_unit, ds, v_dot_n_scale] =
m_map.GetFaceQuadratureContext(Tr, face_ip);
fe_v_minus->CalcShape(ip_minus, shape_v_minus);
fe_rho_minus->CalcShape(ip_minus, shape_rho_minus);
@@ -251,12 +278,14 @@ namespace mean_field::integrators {
}
// Upwind density
// I use the convention that the flow is positive when moving from minus to plus
// I use the convention that the flow is positive when moving from
// minus to plus
const double rho_up = (u_n >= 0) ? rho_minus_val : rho_plus_val;
const double flux_weighted = u_n * rho_up * ds;
// Note the normals need to be in opposite directions for these two fluxes
// Note the normals need to be in opposite directions for these two
// fluxes
for (int i = 0; i < dof_rho_minus; ++i) {
r_rho(i) += shape_rho_minus(i) * flux_weighted;
}
@@ -274,25 +303,26 @@ namespace mean_field::integrators {
const mfem::Array<const mfem::Vector *> &elfun,
const mfem::Array2D<mfem::DenseMatrix *> &elmats
) {
const mfem::FiniteElement *fe_v_minus = el1[0];
const mfem::FiniteElement *fe_v_plus = el2[0];
const mfem::FiniteElement *fe_v_minus = el1[0];
const mfem::FiniteElement *fe_v_plus = el2[0];
const mfem::FiniteElement *fe_rho_minus = el1[1];
const mfem::FiniteElement *fe_rho_plus = el2[1];
const mfem::FiniteElement *fe_rho_plus = el2[1];
const int dof_v_minus = fe_v_minus->GetDof();
const int dof_v_plus = fe_v_plus->GetDof();
const int dof_rho_minus = fe_rho_minus->GetDof();
const int dof_rho_plus = fe_rho_plus->GetDof();
const int dim = Tr.GetSpaceDim();
const int dof_v_minus = fe_v_minus->GetDof();
const int dof_v_plus = fe_v_plus->GetDof();
const int dof_rho_minus = fe_rho_minus->GetDof();
const int dof_rho_plus = fe_rho_plus->GetDof();
const int dim = Tr.GetSpaceDim();
const int N_v_total = dim * (dof_v_minus + dof_v_plus);
const int N_rho_total = dof_rho_minus + dof_rho_plus;
const int N_v_total = dim * (dof_v_minus + dof_v_plus);
const int N_rho_total = dof_rho_minus + dof_rho_plus;
auto size_and_zero_mat = [&](mfem::DenseMatrix* mat, const int r_size, const int c_size) {
if (mat) {
mat->SetSize(r_size, c_size);
*mat = 0.0;
}
auto size_and_zero_mat = [&](mfem::DenseMatrix *mat, const int r_size,
const int c_size) {
if (mat) {
mat->SetSize(r_size, c_size);
*mat = 0.0;
}
};
size_and_zero_mat(elmats(0, 0), N_v_total, N_v_total);
@@ -300,34 +330,41 @@ namespace mean_field::integrators {
size_and_zero_mat(elmats(1, 0), N_rho_total, N_v_total);
size_and_zero_mat(elmats(1, 1), N_rho_total, N_rho_total);
if (skip_face(Tr)) return;
if (skip_face(Tr))
return;
mfem::DenseMatrix *drho_dv = elmats(1, 0);
mfem::DenseMatrix *drho_dv = elmats(1, 0);
mfem::DenseMatrix *drho_drho = elmats(1, 1);
if (!drho_dv && !drho_drho) return;
if (!drho_dv && !drho_drho)
return;
const mfem::Vector &v_dofs = *elfun[0];
const mfem::Vector &v_dofs = *elfun[0];
const mfem::Vector &rho_dofs = *elfun[1];
const int int_order = 2 * std::max(fe_v_minus->GetOrder(), fe_rho_minus->GetOrder()) + 1;
const mfem::IntegrationRule *ir = &mfem::IntRules.Get(Tr.GetGeometryType(), int_order);
const int int_order =
2 * std::max(fe_v_minus->GetOrder(), fe_rho_minus->GetOrder()) + 1;
const mfem::IntegrationRule *ir =
&mfem::IntRules.Get(Tr.GetGeometryType(), int_order);
mfem::Vector shape_v_minus(dof_v_minus), shape_rho_minus(dof_rho_minus), shape_rho_plus(dof_rho_plus);
mfem::Vector shape_v_minus(dof_v_minus), shape_rho_minus(dof_rho_minus),
shape_rho_plus(dof_rho_plus);
for (int q = 0; q < ir->GetNPoints(); ++q) {
const mfem::IntegrationPoint& face_ip = ir->IntPoint(q);
const mfem::IntegrationPoint &face_ip = ir->IntPoint(q);
Tr.SetAllIntPoints(&face_ip);
const mfem::IntegrationPoint &ip_minus = Tr.GetElement1IntPoint();
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
const mfem::IntegrationPoint &ip_plus = Tr.GetElement2IntPoint();
auto [n_unit, ds, v_dot_n_scale] = m_map.GetFaceQuadratureContext(Tr, face_ip);
auto [n_unit, ds, v_dot_n_scale] =
m_map.GetFaceQuadratureContext(Tr, face_ip);
fe_v_minus->CalcShape(ip_minus, shape_v_minus);
fe_rho_minus->CalcShape(ip_minus, shape_rho_minus);
fe_rho_plus->CalcShape(ip_plus, shape_rho_plus);
const double u_n = compute_u_n(v_dofs, shape_v_minus, n_unit, dof_v_minus, dim);
const double u_n =
compute_u_n(v_dofs, shape_v_minus, n_unit, dof_v_minus, dim);
double rho_minus_val = 0.0;
for (int i = 0; i < dof_rho_minus; ++i) {
@@ -353,18 +390,21 @@ namespace mean_field::integrators {
(*drho_drho)(i, ip) += shape_rho_minus(i) * col_w;
}
for (int j = 0; j < dof_rho_plus; ++j) {
(*drho_drho)(dof_rho_minus + j, ip) -= shape_rho_plus(j) * col_w;
(*drho_drho)(dof_rho_minus + j, ip) -=
shape_rho_plus(j) * col_w;
}
}
} else {
for (int jp = 0; jp < dof_rho_plus; ++jp) {
const double col_w = u_w * shape_rho_plus(jp);
const int col_idx = dof_rho_minus + jp;
const int col_idx = dof_rho_minus + jp;
for (int i = 0; i < dof_rho_minus; ++i) {
(*drho_drho)(i, col_idx) += shape_rho_minus(i) * col_w;
(*drho_drho)(i, col_idx) +=
shape_rho_minus(i) * col_w;
}
for (int j = 0; j < dof_rho_plus; ++j) {
(*drho_drho)(dof_rho_minus + j, col_idx) -= shape_rho_plus(j) * col_w;
(*drho_drho)(dof_rho_minus + j, col_idx) -=
shape_rho_plus(j) * col_w;
}
}
}
@@ -375,13 +415,15 @@ namespace mean_field::integrators {
for (int c = 0; c < dim; ++c) {
const double n_c_rho_w = n_unit(c) * rho_w;
for (int k = 0; k < dof_v_minus; ++k) {
const int col_idx = k + c * dof_v_minus;
const int col_idx = k + c * dof_v_minus;
const double col_w = n_c_rho_w * shape_v_minus(k);
for (int i = 0; i < dof_rho_minus; ++i) {
(*drho_dv)(i, col_idx) += shape_rho_minus(i) * col_w;
(*drho_dv)(i, col_idx) +=
shape_rho_minus(i) * col_w;
}
for (int j = 0; j < dof_rho_plus; ++j) {
(*drho_dv)(dof_rho_minus + j, col_idx) -= shape_rho_plus(j) * col_w;
(*drho_dv)(dof_rho_minus + j, col_idx) -=
shape_rho_plus(j) * col_w;
}
}
}
@@ -389,9 +431,11 @@ namespace mean_field::integrators {
}
}
bool ContinuityFaceIntegrator::skip_face(const mfem::FaceElementTransformations& Tr) {
bool ContinuityFaceIntegrator::skip_face(
const mfem::FaceElementTransformations &Tr
) {
constexpr int VACUUM_ATTR = 3;
const int attr_minus = Tr.Elem1->Attribute;
const int attr_minus = Tr.Elem1->Attribute;
const int attr_plus = (Tr.Elem2 != nullptr) ? Tr.Elem2->Attribute : -1;
if (attr_minus == VACUUM_ATTR || attr_plus == VACUUM_ATTR) {
return true; // No flux contribution for vacuum faces
@@ -402,7 +446,13 @@ namespace mean_field::integrators {
return false;
}
double ContinuityFaceIntegrator::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) {
double ContinuityFaceIntegrator::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
) {
double u_n = 0.0;
for (int c = 0; c < dim; ++c) {
double v_c = 0.0;
@@ -413,5 +463,4 @@ namespace mean_field::integrators {
}
return u_n;
}
}
} // namespace mean_field::integrators