Files
MeanField_SERiF/tests/equations/gravity_port_fixture.cpp
Emily Boudreaux cb20faeb3d test(tests): added test suite
The test suite is extensive. Note that LLMs were used to aid in the development of the test suite. All LLM generated code was manually reviewed.
2026-11-09 13:53:17 -05:00

166 lines
7.2 KiB
C++

#include <algorithm>
#include <cmath>
#include <vector>
#include <stroid/stroid.h>
#include "serif/tests/equations/gravity_port.hpp"
namespace serif::tests::equations::gravity_port {
/// Project an old test polynomial into the same registered coefficient representation.
Vector project_vector(const discretization::backend::mfem::DofMap& binding, std::function<void(const Vector&, Vector&)> function) {
::mfem::VectorFunctionCoefficient coefficient(3, std::move(function));
::mfem::GridFunction values(&binding.space());
values.ProjectCoefficient(coefficient);
return binding.gather(values);
}
Coefficients zeros(const GravityFixture& f) {
return {constant(f.potential_binding.size(), 0.0),
constant(f.density_binding.size(), 0.0), constant(f.displacement_binding.size(), 0.0)};
}
Vector sequence(int size, double scale, double phase) {
Vector v(size);
for (int i = 0; i < size; ++i) {
const double index = i + 1;
v[i] = scale * (std::sin(0.31 * index + phase) + 0.37 * std::cos(0.17 * index - phase));
}
return v;
}
Vector prepared_sequence(int size, double phase) {
Vector v(size);
for (int i = 0; i < size; ++i) {
const double index = i + 1;
v[i] = std::sin(0.37 * index + phase) + 0.31 * std::cos(0.19 * index - 0.5 * phase);
}
return v;
}
Vector operator_sequence(int size, double phase) {
Vector v(size);
for (int i = 0; i < size; ++i) {
const double index = i + 1;
v[i] = 0.4 * std::sin(0.37 * index + phase) + 0.2 * std::cos(0.19 * index - phase);
}
return v;
}
Coefficients state(GravityFixture& f, bool deformed) {
return {sequence(f.potential_binding.size(), 0.3, 0.37),
sequence(f.density_binding.size(), 0.7, 0.11), prepared_displacement(f, deformed ? 1.0 : 0.0)};
}
Coefficients direction(GravityFixture& f, int column) {
auto d = zeros(f);
if (column == 0) {
d.density = sequence(d.density.Size(), 0.13, 0.19);
} else {
d.potential = sequence(d.potential.Size(), 0.09, 0.41);
}
return d;
}
Vector prepared_displacement(GravityFixture& f, double scale) {
return project_vector(f.displacement_binding, [scale](const Vector& x, Vector& u) {
u.SetSize(3);
u[0] = scale * (0.04 * x[0] + 0.01 * x[1] * x[2]);
u[1] = scale * (-0.03 * x[1] + 0.008 * x[0] * x[2]);
u[2] = scale * (0.02 * x[2] - 0.006 * x[0] * x[1]);
});
}
Vector affine_displacement(GravityFixture& f, double scale) {
return project_vector(f.displacement_binding, [scale](const Vector& x, Vector& u) {
u = x;
u *= scale;
});
}
Vector kernel_displacement(GravityFixture& f) {
return project_vector(f.displacement_binding, [](const Vector& x, Vector& u) {
u.SetSize(3);
u[0] = 0.025 * x[0] + 0.006 * x[1] * x[2];
u[1] = -0.018 * x[1] + 0.005 * x[0] * x[2];
u[2] = 0.014 * x[2] + 0.004 * x[0] * x[1];
});
}
Vector geometry_direction(GravityFixture& f, int index) {
return project_vector(f.displacement_binding, [index](const Vector& x, Vector& u) {
u.SetSize(3);
if (index == 0) {
u[0] = 0.16 * x[0] + 0.03 * x[1];
u[1] = -0.11 * x[1] + 0.02 * x[2];
u[2] = 0.13 * x[2] - 0.025 * x[0];
} else {
u[0] = -0.07 * x[1] + 0.025 * x[2];
u[1] = 0.09 * x[0] + 0.04 * x[2];
u[2] = -0.08 * x[2] + 0.03 * x[0] * x[1];
}
});
}
Vector kernel_density(GravityFixture& f, bool secondary) {
return f.project(f.density_binding, [secondary](const Vector& x) {
return secondary ? 0.8 - 0.11 * x[0] + 0.13 * x[1] - 0.06 * x[2] + 0.03 * x[1] * x[2]
: 1.2 + 0.16 * x[0] - 0.09 * x[1] + 0.07 * x[2] + 0.04 * x[0] * x[1];
});
}
Vector domain_density(GravityFixture& f, bool stellar) {
Vector density(f.density_space.GetVSize());
std::vector<bool> stellar_dofs(density.Size(), false);
::mfem::Array<int> dofs;
for (int element = 0; element < f.mesh.GetNE(); ++element) {
if (!Schema::template domain_id_belongs_to<discretization::domain::StellarDomains>(f.mesh.GetAttribute(element))) {
continue;
}
f.density_space.GetElementDofs(element, dofs);
for (const int dof : dofs) {
stellar_dofs[dof] = true;
}
}
for (int dof = 0; dof < density.Size(); ++dof) {
density[dof] = stellar_dofs[dof] == stellar ? 1.0 : 0.0;
}
return density;
}
std::unique_ptr<GravityFixture> stellar_fixture(int refinement_levels, int geometry_order) {
stroid::config::MeshConfig config;
config.refinement_levels = refinement_levels;
config.order = geometry_order;
config.include_external_domain = true;
config.r_core = 0.25;
config.r_star = 1.0;
config.r_infinity = 4.0;
config.flattening = 0.0;
config.optimization_methods = stroid::config::OptimizationMethods{false, true};
auto mesh = stroid::GenerateMesh(config);
REQUIRE(mesh.exterior_coordinate != nullptr);
REQUIRE(mesh.exterior_coordinate->values != nullptr);
auto fixture = std::make_unique<GravityFixture>(::mfem::Mesh(*mesh.mesh));
::mfem::GridFunctionCoefficient coordinate(mesh.exterior_coordinate->values.get());
fixture->compactification.ProjectCoefficient(coordinate);
return fixture;
}
Coefficients shifted(const Coefficients& v, const Coefficients& d, double scale) {
auto result = v;
result.potential.Add(scale, d.potential);
result.density.Add(scale, d.density);
result.displacement.Add(scale, d.displacement);
return result;
}
double relative(const Vector& actual, const Vector& expected, double floor) {
REQUIRE(actual.Size() == expected.Size());
Vector difference(actual);
difference -= expected;
return difference.Norml2() / std::max(expected.Norml2(), floor);
}
double symmetric_relative(const Vector& first, const Vector& second) {
REQUIRE(first.Size() == second.Size());
Vector difference(first);
difference -= second;
return difference.Norml2() / std::max({first.Norml2(), second.Norml2(), 1.0e-14});
}
double prepared_relative(const Vector& actual, const Vector& expected) {
return relative(actual, expected, std::numeric_limits<double>::epsilon());
}
double pairing_relative(double actual, double expected) {
return std::abs(actual - expected) / std::max(std::abs(expected), std::numeric_limits<double>::epsilon());
}
Vector combination(const Vector& first, double a, const Vector& second, double b) {
Vector result(first);
result *= a;
result.Add(b, second);
return result;
}
} // namespace serif::tests::equations::gravity_port