// MoonBit Marine Biogeochemical Box Model Engine Entrypoint & Demo
///|
fn main {
println(
"================================================================================",
)
println(
" MoonBit Marine Biogeochemical Box Model Engine (`moonbit-biogeochem`) v0.1.2 ",
)
println(
"================================================================================\n",
)
// Demo 1: Run 4-Compartment NPZD Ecosystem Simulation using Classic RK4
println("[1] Running NPZD Seawater Box Ecosystem Simulation (RK4 Solver)...")
let npzd_model = @models.create_npzd_model(15.0, 0.5, 0.1, 0.2)
let env_fn = fn(t) { @types.EnvironmentForcing::seasonal_forcing(t, 45.0) }
match @solver.solve_rk4(npzd_model, 30.0, 0.5, env_fn) {
Ok(traj) => {
println(
" -> Completed " +
traj.length().to_string() +
" simulation time steps successfully.",
)
let p_series = traj.get_time_series("P").unwrap()
let plot = @exporter.render_ascii_plot(
p_series, "Phytoplankton Concentration (mmol N/m^3)", 30, 6,
)
println("\n" + plot)
let diag = @analysis.diagnose_npzd_trajectory(traj).unwrap()
println(" Mass Balance Status: " + diag.mass_conservation_status)
if diag.mass_conservation_status == "OPEN_SYSTEM_EXPORT" {
println(
" Note: Detritus sinking is modeled as an expected export from the box.",
)
}
println(
" Initial Mass: " +
diag.initial_total_mass.to_string() +
" | Final Mass: " +
diag.final_total_mass.to_string(),
)
}
Err(err) => println(" Error running NPZD simulation: " + err)
}
// Demo 2: Run Coupled NPZD-O2-Carbonate System using Adaptive RKF45 Solver
println(
"\n[2] Running Fully Coupled NPZD - Ocean Carbonate & Hypoxia Box Model (RK45 Adaptive Solver)...",
)
let coupled_model = @models.create_coupled_carbon_npzd_model(
12.0, 0.8, 0.2, 0.1, 240.0, 2100.0, 2300.0,
)
let cfg = @solver.AdaptiveSolverConfig::default()
match @solver.solve_rk45(coupled_model, 20.0, 0.5, cfg, env_fn) {
Ok(traj) => {
println(
" -> Adaptive solver steps executed: " + traj.length().to_string(),
)
let _dic_series = traj.get_time_series("DIC").unwrap()
let csv = @exporter.export_trajectory_csv(traj)
let preview_len = if csv.length() < 70 { csv.length() } else { 70 }
println(
" -> Trajectory CSV preview (first header line):\n " +
csv[0:preview_len].to_owned() +
"...\n",
)
}
Err(err) => println(" Error running coupled simulation: " + err)
}
// Demo 3: Sensitivity Analysis on Max Phytoplankton Growth Rate
println("[3] Performing Local Sensitivity Analysis (Delta = 5%)...")
let npzd_base = @models.create_npzd_model(15.0, 0.5, 0.1, 0.2)
match
@analysis.compute_local_sensitivity(
fn(p) { @models.create_npzd_model_with_params(p) },
npzd_base.config.parameters,
"v_max",
"P",
0.05,
10.0,
) {
Ok(sens) => {
println(" Parameter: " + sens.param_id + " -> Target: " + sens.var_id)
println(
" Normalized Sensitivity Coefficient: " +
sens.normalized_sensitivity.to_string(),
)
}
Err(err) => println(" Sensitivity calculation note: " + err)
}
// Demo 4: 1D Vertical Water Column Extension & Sediment Coupling
println(
"\n[4] Initializing 1D Vertical Water Column Grid & Sediment Coupling...",
)
let col = @extensions.WaterColumn1D::create(5, 50.0, [15.0, 0.5])
let diff = col.compute_vertical_diffusion(0)
println(
" -> 5-Layer Vertical Diffusion Term array initialized: " +
diff.length().to_string() +
" layers computed.",
)
let sed = @extensions.SedimentBox::default()
let (n_flux, o2_flux) = sed.compute_benthic_fluxes(18.0)
println(
" -> Sediment Benthic Return Flux: " +
n_flux.to_string() +
" mmol N/m^2/day | O2 Demand: " +
o2_flux.to_string() +
" mmol O2/m^2/day",
)
// Demo 5: Mermaid Flow Topology Diagram Export
println("\n[5] Exporting Model Architecture Mermaid Diagram...")
let diagram = @exporter.export_mermaid_diagram("NPZD", ["N", "P", "Z", "D"])
println(diagram)
println(
"All biogeochemical engine demonstration tasks completed successfully.",
)
}