feat(equations): simplified the supported equation set

previously we modeled gravity as a mixed formulation. However, this turns out to not be needed with the improved surface prescription. Removing this and returning to a simpler gravity system dramatically reduces the number of unknowns and therefore speeds up the system.
This commit is contained in:
2026-11-09 13:08:08 -05:00
parent 48bc7d5472
commit 9760e46477
16 changed files with 415 additions and 1529 deletions

View File

@@ -0,0 +1,67 @@
#pragma once
#include <optional>
#include <string_view>
#include "serif/discretization/blocks/fields.hpp"
#include "serif/equations/companion.hpp"
#include "serif/equations/point.hpp"
#include "serif/equations/rigid_rotation.hpp"
namespace serif::equations {
/**
* @brief Set the effective potential to one unknown level on the selected isobar.
*
* Integrate this point relation against the existing surface shape basis with
* a fixed dimensionless reference measure. The constant mode is retained.
* This is a boundary equation, not a volume displacement force.
*/
class SurfacePotentialBalance final {
public:
using Potential = discretization::blocks::gravity::potential;
using SurfaceLevel = discretization::blocks::barotropic_constant::mass_normalization;
using AngularVelocity = discretization::blocks::rotation::angular_velocity;
using Operands = utils::types::TypeList<discretization::forms::Operand<Potential>,
discretization::forms::Operand<SurfaceLevel>, discretization::forms::Operand<AngularVelocity>>;
using ResidualQuantity = dimensions::GravitationalPotential;
static constexpr std::string_view name = "surface effective potential balance";
/** @brief Use the same physical rotation axis, origin and companion as the interior equation. */
explicit SurfacePotentialBalance(const RigidRotation::Vector& axis = {0.0, 0.0, 1.0},
const RigidRotation::Vector& center = {}, std::optional<PointMassCompanion> companion = std::nullopt) :
m_rotation(RigidRotation::unit_rotation(axis, center)), m_companion(companion) {}
/** @brief Differentiate at fixed pulled-back potential; geometry moves only the centrifugal term. */
[[nodiscard]] PointLinearization<Operands> evaluate(const EquationPoint<Operands>& point) const {
const double omega = point.fields.get<AngularVelocity>();
const double centrifugal = m_rotation.centrifugal_potential(point.position);
PointLinearization<Operands> result;
result.residual = point.fields.get<Potential>() - omega * omega * centrifugal - point.fields.get<SurfaceLevel>();
result.field_derivatives.get<Potential>() = 1.0;
result.field_derivatives.get<SurfaceLevel>() = -1.0;
result.field_derivatives.get<AngularVelocity>() = -2.0 * omega * centrifugal;
result.position_derivative = m_rotation.centrifugal_potential_gradient(point.position);
for (double& component : result.position_derivative) {
component *= -omega * omega;
}
if (m_companion) {
result.residual += m_companion->potential(point.position);
const auto gradient = m_companion->potential_gradient(point.position);
for (int axis = 0; axis < 3; ++axis) { result.position_derivative[axis] += gradient[axis]; }
}
return result;
}
/** @brief Inspect the physical rotation convention. */
[[nodiscard]] const RigidRotation& rotation() const noexcept { return m_rotation; }
/** @brief Inspect the companion, if any. */
[[nodiscard]] const std::optional<PointMassCompanion>& companion() const noexcept { return m_companion; }
private:
RigidRotation m_rotation;
std::optional<PointMassCompanion> m_companion;
};
}