pub mod heat_stochastic;
pub mod pathwise;
pub mod random_fields;
pub mod wave_stochastic;
pub use heat_stochastic::{
HeatSnapshot, NoiseType, StochasticHeatConfig, StochasticHeatSolution, StochasticHeatSolver1D,
StochasticHeatSolver2D,
};
pub use wave_stochastic::{
StochasticWaveConfig, StochasticWaveSolution, StochasticWaveSolver, WaveSnapshot,
};
pub use random_fields::{CorrelationFunction, RandomField};
pub use pathwise::{
AndersonMattinglyConfig, AndersonMattinglyScheme, AndersonMattinglySolution, ImexParabolicSolver,
ImexSolution, SpectralGalerkinConfig, SpectralGalerkinSolution, SpectralGalerkinSolver,
};
#[cfg(test)]
mod integration_tests {
use super::*;
use scirs2_core::ndarray::Array1;
use scirs2_core::random::prelude::*;
#[test]
fn test_spde_heat_1d_smoke() {
let config = StochasticHeatConfig {
diffusion: 0.05,
sigma: 0.01,
noise_type: NoiseType::Additive,
dt: 5e-5,
..Default::default()
};
let solver = StochasticHeatSolver1D::new(config, 1.0, 16, 5).expect("StochasticHeatSolver1D::new should succeed");
let u0 = Array1::zeros(16);
let mut rng = seeded_rng(1234);
let sol = solver.solve(u0.view(), 0.0, 0.01, &mut rng).expect("solver.solve should succeed");
assert!(sol.len() >= 2, "Should have at least initial + final snapshot");
assert_eq!(sol.grid.len(), 16);
assert_eq!(sol.shape, vec![16]);
assert_eq!(sol.dim, 1);
for snap in &sol.snapshots {
assert_eq!(snap.len(), 16);
assert!(snap.iter().all(|v| v.is_finite()));
}
let mean = sol.mean_field().expect("mean_field should succeed");
assert_eq!(mean.len(), 16);
}
#[test]
fn test_spde_wave_1d_smoke() {
let config = StochasticWaveConfig {
wave_speed: 1.0,
sigma: 0.1,
dt: 5e-5,
};
let solver = StochasticWaveSolver::new(config, 1.0, 20, 10).expect("StochasticWaveSolver::new should succeed");
let u0 = Array1::from_vec(
(0..20)
.map(|i| ((i as f64 + 1.0) * std::f64::consts::PI / 21.0).sin() * 0.1)
.collect(),
);
let v0 = Array1::zeros(20);
let mut rng = seeded_rng(5678);
let sol = solver.solve(&u0, &v0, 0.0, 0.01, &mut rng).expect("solver.solve should succeed");
assert!(!sol.is_empty());
let energies = sol.energy_series();
assert_eq!(energies.len(), sol.len());
assert!(energies.iter().all(|&e| e.is_finite() && e >= 0.0));
}
#[test]
fn test_random_field_as_initial_condition() {
let mut rng = seeded_rng(9999);
let gx = Array1::linspace(1.0 / 17.0, 16.0 / 17.0, 16);
let gy = Array1::from_vec(vec![0.0]);
let cov = CorrelationFunction::Gaussian { length_scale: 0.3 };
let field =
RandomField::sample_kl_expansion(gx.view(), gy.view(), cov, 8, &mut rng).expect("sample_kl_expansion should succeed");
let u0_vec: Vec<f64> = (0..16).map(|i| field[[i, 0]] * 0.01).collect();
let u0 = Array1::from_vec(u0_vec);
let config = StochasticHeatConfig {
diffusion: 0.05,
sigma: 0.005,
dt: 5e-5,
..Default::default()
};
let solver = StochasticHeatSolver1D::new(config, 1.0, 16, 10).expect("StochasticHeatSolver1D::new should succeed");
let sol = solver.solve(u0.view(), 0.0, 0.005, &mut rng).expect("solver.solve should succeed");
assert!(!sol.is_empty());
}
#[test]
fn test_imex_via_spde_module() {
let solver = ImexParabolicSolver::new(0.2, 0.05, 2e-3, 1.0, 12, 5).expect("ImexParabolicSolver::new should succeed");
let u0 = Array1::from_vec(vec![0.1_f64; 12]);
let mut rng = seeded_rng(42);
let sol = solver
.solve(&u0, |_t, _u| Array1::zeros(12), 0.0, 0.05, &mut rng)
.expect("solver.solve should succeed");
assert!(!sol.is_empty());
}
#[test]
fn test_spectral_galerkin_via_spde_module() {
let cfg = SpectralGalerkinConfig {
diffusion: 1.0,
sigma: 0.2,
n_modes: 8,
domain_length: 1.0,
mode_sigmas: None,
};
let solver = SpectralGalerkinSolver::new(cfg, 5).expect("SpectralGalerkinSolver::new should succeed");
let a0 = Array1::zeros(8);
let grid = Array1::linspace(0.1, 0.9, 10);
let mut rng = seeded_rng(1111);
let sol = solver.solve(&a0, 1e-3, &grid, 0.0, 0.1, &mut rng).expect("solver.solve should succeed");
assert!(!sol.is_empty());
assert_eq!(sol.grid.len(), 10);
}
}