mod compressible;
mod immersed_2d;
mod incompressible_2d;
mod observe;
pub use compressible::{
AcousticImex1d, CompressibleEuler1d, CompressibleMarcher2d, CompressibleMarcher3d,
CompressibleMarcher3dFitted, EulerState, EulerState2d, EulerState3d, EulerStateTt2d,
EulerStateTt3d, FittedNormalShock, ForcingRegion, Park2tClosure, PostShockState,
REDUCED_MASS_AMU, StagnationOutcome, conservation_round, ideal_gas_pressure,
ideal_gas_pressure_2d, positivity_floor, reduced_mass_amu,
};
pub use immersed_2d::QttImmersed2d;
pub use incompressible_2d::QttIncompressible2d;
pub use observe::{
divergence_residual, drag_lift, kinetic_energy, max_bond, max_speed,
penalization_heat_integral, preserved_drag_fraction, strip_pressure_force,
};
use crate::CfdScalar;
use crate::tensor_bridge::{dequantize, gradient, laplacian, quantize};
use crate::traits::Marcher;
use alloc::format;
use deep_causality_algebra::ConjugateScalar;
use deep_causality_physics::PhysicsError;
use deep_causality_tensor::{
CausalTensor, CausalTensorTrain, CausalTensorTrainOperator, TensorTrain, TensorTrainOperator,
Truncation,
};
pub struct QttLinear1d<R>
where
R: CfdScalar + ConjugateScalar<Real = R>,
{
l: usize,
dt: R,
c: R,
nu: R,
grad: CausalTensorTrainOperator<R>,
lap: CausalTensorTrainOperator<R>,
trunc: Truncation<R>,
}
impl<R> QttLinear1d<R>
where
R: CfdScalar + ConjugateScalar<Real = R>,
{
pub fn new(
l: usize,
dx: R,
dt: R,
c: R,
nu: R,
trunc: Truncation<R>,
) -> Result<Self, PhysicsError> {
let grad = gradient::<R>(l, dx, &trunc)?;
let lap = laplacian::<R>(l, dx, &trunc)?;
Ok(Self {
l,
dt,
c,
nu,
grad,
lap,
trunc,
})
}
pub fn run(&self, u0: &CausalTensor<R>, steps: usize) -> Result<CausalTensor<R>, PhysicsError> {
let n = u0.as_slice().len();
if n != (1usize << self.l) {
return Err(PhysicsError::DimensionMismatch(format!(
"field length {n} does not match the grid size 2^{}",
self.l
)));
}
let mut state = quantize(u0, &self.trunc)?;
for _ in 0..steps {
state = self.advance(&state, &())?;
}
dequantize(&state)
}
}
impl<R> Marcher<R> for QttLinear1d<R>
where
R: CfdScalar + ConjugateScalar<Real = R>,
{
type State = CausalTensorTrain<R>;
type Ambient = ();
type Output = CausalTensorTrain<R>;
fn advance(
&self,
state: &Self::State,
_ambient: &Self::Ambient,
) -> Result<Self::Output, PhysicsError> {
let neg_c = R::zero() - self.c;
let grad_u = self.grad.apply(state, &self.trunc)?;
let lap_u = self.lap.apply(state, &self.trunc)?;
let rate = grad_u.scale(neg_c).add(&lap_u.scale(self.nu))?;
let next = state.add(&rate.scale(self.dt))?.round(&self.trunc)?;
Ok(next)
}
}