///|
/// 沐澜水文 CLI 子命令模块
///
/// 提供率定、校验、批量仿真、不确定性分析等子命令函数。
/// 各子命令返回结构化结果,可序列化为JSON供外部调用。
/// 由于MoonBit标准库暂无argv模块,main函数作为分发器调用各子命令。
///|
/// CLI子命令结果
struct CliResult {
command : String
success : Bool
message : String
details : String
}
///|
/// 重复字符串n次
fn repeat_str(s : String, n : Int) -> String {
// T62修复:使用StringBuilder避免O(n²)字符串拼接
let buf = StringBuilder()
for _ in 0.. String {
if s.length() <= max_bytes {
return s
}
let buf = StringBuilder()
let mut byte_count = 0
for ch in s.iter() {
let ch_len = ch.to_string().length()
if byte_count + ch_len > max_bytes {
break
}
buf.write_char(ch)
byte_count = byte_count + ch_len
}
buf.to_string() + "..."
}
///|
/// 打印CLI结果
fn print_cli_result(result : CliResult) -> Unit {
let status = if result.success { "[OK]" } else { "[FAIL]" }
println("\{status} [\{result.command}] \{result.message}")
if result.details.length() > 0 {
println(result.details)
}
}
///|
/// 子命令: help - 显示帮助信息
fn cli_help() -> Unit {
println("沐澜水文 V0.9.2 - 命令行子命令")
println(repeat_str("=", 50))
println("可用子命令:")
println(" demo 完整功能演示(默认)")
println(" sim 单次新安江模型仿真")
println(" calibrate SCE-UA参数率定")
println(" dds DDS动态维度搜索率定")
println(" validate 流域校验(闽江/飞云江/青弋江)")
println(" batch 批量多流域仿真")
println(" ensemble 集合仿真")
println(" uncertainty 蒙特卡洛不确定性分析")
println(" sensitivity 参数敏感性扫描")
println(" swe 1D/2D浅水方程仿真")
println(" coupling 新安江+SWE耦合仿真")
println(" timeseries 时间序列分析")
println(" metrics 扩展评价指标计算")
println(" json JSON API端到端演示")
println(" bench 性能基准测试")
println(" persistence 持久化存储演示(方案/结果/参数集)")
println(" auth 权限框架演示(用户/鉴权/方案隔离)")
println(" ai_forecast AI混合预报演示(LSTM残差校正)")
println(" gis GIS接口演示(DEM流向/汇流累积/河网提取)")
println(" flood 洪水淹没推演(2D水深/风险图/损失评估)")
println(" help 显示此帮助信息")
println("")
println("用法: moon run -- [subcommand]")
println(
"注意: 当前MoonBit标准库暂无argv模块,默认运行demo子命令",
)
}
///|
/// 子命令: sim - 单次新安江模型仿真
fn cli_sim() -> CliResult {
let model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 10.0, evaporation: 2.0, datetime: "2026-09-01T00:00", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "2026-09-01T01:00", },
{ rainfall: 5.0, evaporation: 3.0, datetime: "2026-09-01T02:00", },
{ rainfall: 0.0, evaporation: 1.0, datetime: "2026-09-01T03:00", },
{ rainfall: 30.0, evaporation: 2.0, datetime: "2026-09-01T04:00", },
]
let result = model.run(forcings)
let runoff_str = result.runoff_series.map(fn(x) { x.to_string() }).join(", ")
{
command: "sim",
success: true,
message: "新安江模型仿真完成(5步)",
details: "径流序列: [\{runoff_str}]",
}
}
///|
/// 子命令: calibrate - SCE-UA参数率定
fn cli_calibrate() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 15.0, evaporation: 1.5, datetime: "t2", },
{ rainfall: 5.0, evaporation: 2.0, datetime: "t3", },
{ rainfall: 0.0, evaporation: 1.0, datetime: "t4", },
]
let model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let observed = model.run(forcings).runoff_series
let cfg : @shared.SCEUAConfig = {
max_iter: 50,
n_complexes: 4,
complex_size: 0,
cce_iterations: 0,
seed: 42,
target_metric: "nse",
params: @shared.default_calib_params(),
convergence_threshold: 0.000001,
max_no_improve: 20,
}
let result = @shared.sceua_calibrate(
cfg,
area=100.0,
dt=1.0,
forcings,
observed,
)
let detail = "最优NSE: \{result.best_metric}, 迭代: \{result.n_iter}, 函数调用: \{result.n_function_evals}, 收敛: \{result.converged}"
{
command: "calibrate",
success: true,
message: "SCE-UA率定完成(11参数)",
details: detail,
}
}
///|
/// 子命令: dds - DDS动态维度搜索率定
fn cli_dds() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 12.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 18.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 8.0, evaporation: 1.5, datetime: "t2", },
{ rainfall: 3.0, evaporation: 1.0, datetime: "t3", },
]
let model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=200.0,
dt=1.0,
)
let observed = model.run(forcings).runoff_series
let cfg : @shared.DDSConfig = {
max_iter: 30,
r: 0.2,
seed: 123,
target_metric: "nse",
params: @shared.default_calib_params(),
max_no_improve: 100,
}
let result = @shared.dds_calibrate(
cfg,
area=200.0,
dt=1.0,
forcings,
observed,
)
let detail = "最优NSE: \{result.best_metric}, 迭代: \{result.n_iter}, 收敛: \{result.converged}"
{
command: "dds",
success: true,
message: "DDS率定完成(11参数)",
details: detail,
}
}
///|
/// 子命令: validate - 流域校验
fn cli_validate() -> CliResult {
let report = @shared.generate_validation_report()
let mut detail = "总案例: \{report.total_cases}, 通过: \{report.passed_count}, 失败: \{report.failed_count}\n"
detail = detail +
"平均NSE: \{report.mean_nse}, 范围: [\{report.min_nse}, \{report.max_nse}]\n"
for r in report.results {
let grade_str = match r.grade {
@shared.ForecastGrade::Excellent => "甲等"
@shared.ForecastGrade::Good => "乙等"
@shared.ForecastGrade::Qualified => "丙等"
@shared.ForecastGrade::Unqualified => "不合格"
}
detail = detail +
" \{r.case_name}: NSE=\{r.nse}, KGE=\{r.kge}, 等级=\{grade_str}\n"
}
{
command: "validate",
success: report.failed_count == 0,
message: "流域校验完成(\{report.total_cases}个案例)",
details: detail,
}
}
///|
/// 子命令: batch - 批量多流域仿真
fn cli_batch() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 5.0, evaporation: 3.0, datetime: "t2", },
{ rainfall: 0.0, evaporation: 1.0, datetime: "t3", },
]
let model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let observed = model.run(forcings).runoff_series
let tasks : Array[@shared.SimTask] = []
let basin_names = [
"闽江竹岐", "飞云江", "青弋江", "合成流域A", "合成流域B",
]
for i in 0..<5 {
tasks.push({
task_id: "basin_\{i}",
basin_name: basin_names[i],
params: @shared.XinanjiangParams::default(),
area: 100.0 + i.to_double() * 50.0,
dt: 1.0,
forcings,
observed,
})
}
let result = @shared.run_batch_sim(tasks)
let detail = "总任务: \{result.total_tasks}, 成功: \{result.success_count}, 失败: \{result.failure_count}\n平均NSE: \{result.summary_stats.mean_nse}, 平均KGE: \{result.summary_stats.mean_kge}\n平均洪峰: \{result.summary_stats.mean_peak_flow}, 总体积: \{result.summary_stats.total_volume}"
{
command: "batch",
success: result.failure_count == 0,
message: "批量仿真完成(\{result.total_tasks}个流域)",
details: detail,
}
}
///|
/// 子命令: ensemble - 集合仿真
fn cli_ensemble() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 15.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 25.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 10.0, evaporation: 1.5, datetime: "t2", },
{ rainfall: 2.0, evaporation: 1.0, datetime: "t3", },
]
let params_set : Array[@shared.XinanjiangParams] = []
let base = @shared.XinanjiangParams::default()
let wm_values = [10.0, 15.0, 20.0, 25.0, 30.0]
for wm in wm_values {
params_set.push({ ..base, wm, })
}
let result = @shared.run_ensemble_sim(
basin_name="测试流域",
params_set,
area=150.0,
dt=1.0,
forcings,
)
let detail = "成员数: \{result.total_tasks}, 成功: \{result.success_count}\n平均NSE: \{result.summary_stats.mean_nse}, 平均KGE: \{result.summary_stats.mean_kge}\n平均洪峰: \{result.summary_stats.mean_peak_flow}"
{
command: "ensemble",
success: result.failure_count == 0,
message: "集合仿真完成(\{result.total_tasks}个成员)",
details: detail,
}
}
///|
/// 子命令: uncertainty - 蒙特卡洛不确定性分析
fn cli_uncertainty() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 12.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 22.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 8.0, evaporation: 1.5, datetime: "t2", },
{ rainfall: 1.0, evaporation: 1.0, datetime: "t3", },
{ rainfall: 0.0, evaporation: 0.5, datetime: "t4", },
]
let result = @shared.monte_carlo_uncertainty(
@shared.XinanjiangParams::default(),
@shared.default_calib_params(),
n_samples=50,
area=120.0,
dt=1.0,
forcings,
seed=42,
)
let detail = "采样数: \{result.n_samples}\n洪峰: 均值=\{result.peak_flow_mean}, 标准差=\{result.peak_flow_std}\n90%置信区间: [\{result.peak_flow_p5}, \{result.peak_flow_p95}]\n总量: 均值=\{result.volume_mean}, 标准差=\{result.volume_std}"
{
command: "uncertainty",
success: true,
message: "蒙特卡洛不确定性分析完成(50次采样)",
details: detail,
}
}
///|
/// 子命令: sensitivity - 参数敏感性扫描
fn cli_sensitivity() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 15.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 5.0, evaporation: 1.5, datetime: "t2", },
]
let model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let observed = model.run(forcings).runoff_series
let results = @shared.param_sensitivity_scan(
@shared.XinanjiangParams::default(),
param_name="wm",
lower=10.0,
upper=30.0,
n_samples=5,
area=100.0,
dt=1.0,
forcings,
observed,
)
let mut detail = "参数wm敏感性扫描:\n"
for pair in results {
let (wm_val, r) = pair
detail = detail +
" wm=\{wm_val}: NSE=\{r.nse}, KGE=\{r.kge}, 峰值=\{r.peak_flow}\n"
}
{
command: "sensitivity",
success: true,
message: "参数敏感性扫描完成(\{results.length()}个样本)",
details: detail,
}
}
///|
/// 子命令: swe - 浅水方程仿真
fn cli_swe() -> CliResult {
let grid1d = @shared.SWEGrid1D::uniform(nx=50, dx=1.0, h0=1.0)
let config1d : @shared.SWESolverConfig = {
dt: 0.01,
n_steps: 50,
cfl: 0.4,
boundary: {
left: @shared.SWEBoundaryType::SolidWall,
right: @shared.SWEBoundaryType::Transmissive,
},
}
let result1d = grid1d.run(config1d)
let grid2d = @shared.SWEGrid2D::uniform(nx=20, ny=20, dx=1.0, dy=1.0, h0=0.1)
ignore(grid2d.set_block(i0=0, i1=10, j0=0, j1=20, h_value=2.0))
let config2d : @shared.SWE2DSolverConfig = {
dt: 0.005,
n_steps: 30,
cfl: 0.3,
boundary: @shared.SWE2DBoundary::SolidWall,
}
let result2d = grid2d.run(config2d)
let mut max_h = 0.0
for k in 0.. max_h {
max_h = result2d.max_depth[k]
}
}
let detail = "1D SWE: 50单元, 稳定性=\{result1d.stable}\n2D SWE: 20x20网格(dam-break), 稳定性=\{result2d.stable}, 实际步数=\{result2d.n_steps_actual}\n2D全域最大水深: \{max_h}"
{
command: "swe",
success: result1d.stable && result2d.stable,
message: "浅水方程仿真完成(1D+2D)",
details: detail,
}
}
///|
/// 子命令: coupling - 新安江+SWE耦合仿真
fn cli_coupling() -> CliResult {
let xaj_model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 5.0, evaporation: 3.0, datetime: "t2", },
{ rainfall: 0.0, evaporation: 1.0, datetime: "t3", },
{ rainfall: 30.0, evaporation: 2.0, datetime: "t4", },
]
let coupling_params : @shared.CouplingParams = {
lateral_inflow_coeff: 0.8,
feedback_coeff: 0.01,
cell_area: 100.0,
river_cells: [10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
base_flow_threshold: 0.3,
}
let swe_boundary : @shared.SWEBoundary = {
left: @shared.SWEBoundaryType::SolidWall,
right: @shared.SWEBoundaryType::Transmissive,
}
let grid = @shared.SWEGrid1D::uniform(nx=50, dx=1.0, h0=0.5)
let result = @shared.couple_run(
xaj_model, grid, coupling_params, swe_boundary, forcings, 0.005,
)
let detail = "耦合稳定性: \{result.stable}\n侧向入流过程: \{result.lateral_inflow_series.length()}步\n河道水位过程: \{result.water_level_series.length()}步"
{
command: "coupling",
success: result.stable,
message: "新安江+SWE耦合仿真完成",
details: detail,
}
}
///|
/// 子命令: timeseries - 时间序列分析
fn cli_timeseries() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 5.0, evaporation: 3.0, datetime: "t2", },
{ rainfall: 0.0, evaporation: 1.0, datetime: "t3", },
{ rainfall: 30.0, evaporation: 2.0, datetime: "t4", },
]
let model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let runoff = model.run(forcings).runoff_series
let stats = @shared.ts_stats(runoff)
let peaks = @shared.detect_peaks(runoff)
let baseflow = @shared.baseflow_separation(runoff)
let detail = "统计: 均值=\{stats.mean}, 标准差=\{stats.stddev}\n范围: [\{stats.min_val}, \{stats.max_val}], 趋势=\{stats.trend}\n洪峰位置: \{peaks.length()}个\n基流分离: \{baseflow.length()}步"
{
command: "timeseries",
success: true,
message: "时间序列分析完成",
details: detail,
}
}
///|
/// 子命令: metrics - 扩展评价指标
fn cli_metrics() -> CliResult {
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 5.0, evaporation: 3.0, datetime: "t2", },
{ rainfall: 0.0, evaporation: 1.0, datetime: "t3", },
{ rainfall: 30.0, evaporation: 2.0, datetime: "t4", },
]
let model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let obs = model.run(forcings).runoff_series
let sim = obs
let ext = @shared.evaluate_extended(obs, sim)
let detail = "LogNSE=\{ext.log_nse}, RSR=\{ext.rsr}, d=\{ext.index_of_agreement}\nKGE分解: r=\{ext.r}, alpha=\{ext.alpha}, beta=\{ext.beta}\nMAE=\{ext.mae}, MSE=\{ext.mse}\nPFC=\{ext.percent_forecast_correct}%, 持续性指数=\{ext.persistence_index}"
{
command: "metrics",
success: true,
message: "扩展评价指标计算完成",
details: detail,
}
}
///|
/// 子命令: json - JSON API端到端演示
fn cli_json() -> CliResult raise {
let request : @shared.XajRunRequest = {
params: @shared.XinanjiangParams::default(),
area: 100.0,
dt: 1.0,
forcings: [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
],
observed: [],
}
let request_json = @shared.to_json_string(request)
let response_json = @shared.xaj_json_endpoint(request_json)
// T61修复:使用字符级安全截断,避免截断UTF-8多字节字符
let req_preview = safe_preview(request_json, 100)
let resp_preview = safe_preview(response_json, 100)
let detail = "请求JSON: \{req_preview}\n响应JSON: \{resp_preview}"
{
command: "json",
success: true,
message: "JSON API端到端演示完成",
details: detail,
}
}
///|
/// 子命令: demo - 完整功能演示
fn cli_demo() -> Unit {
println("沐澜水文 V0.9.2 - 完整功能演示")
println(repeat_str("=", 50))
let commands : Array[String] = [
"sim", "calibrate", "dds", "validate", "batch", "ensemble", "uncertainty", "sensitivity",
"swe", "coupling", "timeseries", "metrics", "json", "bench", "persistence", "auth",
"ai_forecast", "gis", "flood",
]
for cmd in commands {
dispatch(cmd) catch {
e => println("[FAIL] [\{cmd}] 子命令异常: \{e}")
}
}
println("\n" + repeat_str("=", 50))
println("所有子命令执行完毕")
cli_help()
}
///|
/// 子命令: bench - 性能基准测试
fn cli_bench() -> CliResult {
let report = @shared.run_all_benchmarks()
{
command: "bench",
success: true,
message: "性能基准测试完成",
details: report,
}
}
///|
/// 子命令: persistence - 持久化存储演示
fn cli_persistence() -> CliResult raise {
let store = @persistence.DataStore::new()
let now = @env.now() // P2-54:@env.now()引入非确定性,测试时应注入固定时间戳
// 保存仿真方案
let scheme : @persistence.SimulationScheme = {
id: @persistence.generate_id("scheme", now),
name: "闽江竹岐基准方案",
basin_name: "闽江竹岐",
area: 54500.0,
dt: 6.0,
params: @shared.XinanjiangParams::default(),
forcings: [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
],
created_at: now,
updated_at: now,
}
store.save_scheme(scheme)
// 保存参数集
let param_set : @persistence.ParameterSet = {
id: @persistence.generate_id("param", now),
name: "闽江默认参数",
basin_name: "闽江竹岐",
params: @shared.XinanjiangParams::default(),
description: "闽江竹岐流域默认新安江参数",
created_at: now,
}
store.save_param_set(param_set)
// 运行仿真并保存结果
let xaj_model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let forcings : Array[@shared.ForcingData] = [
{ rainfall: 10.0, evaporation: 2.0, datetime: "t0", },
{ rainfall: 20.0, evaporation: 1.0, datetime: "t1", },
{ rainfall: 5.0, evaporation: 3.0, datetime: "t2", },
]
let sim_result = xaj_model.run(forcings)
// 计算洪峰
let mut peak_flow = 0.0
let mut peak_time = 0
for i in 0.. peak_flow {
peak_flow = sim_result.runoff_series[i]
peak_time = i
}
}
let result_record : @persistence.ResultRecord = {
id: @persistence.generate_id("result", now),
scheme_id: scheme.id,
basin_name: "闽江竹岐",
peak_flow,
peak_time,
nse: sim_result.nse,
kge: sim_result.kge,
pbias: sim_result.pbias,
runoff_series: sim_result.runoff_series,
created_at: now,
}
store.save_result(result_record)
// JSON序列化演示
let json_str = store.to_json_string()
// P1修复:使用字符级安全截断,避免截断UTF-8多字节字符
let json_preview = safe_preview(json_str, 300)
// 反序列化验证
let store2 = @persistence.DataStore::from_json_string(json_str)
let stats = store2.stats()
{
command: "persistence",
success: true,
message: "持久化存储演示完成",
details: "统计: \{stats}\nJSON预览: \{json_preview}",
}
}
///|
/// 子命令: auth - 权限框架演示
fn cli_auth() -> CliResult raise {
println("沐澜水文 权限框架演示")
println(repeat_str("=", 50))
let now = @env.now() // P2-54:@env.now()引入非确定性,测试时应注入固定时间戳
let auth = @shared.AuthManager::new()
// 注册用户
let admin_id = auth.register(
username="admin",
password="admin123",
role=@shared.Role::Admin,
timestamp=now,
)
let engineer_id = auth.register(
username="engineer1",
password="eng123",
role=@shared.Role::Engineer,
timestamp=now + 1UL,
)
let viewer_id = auth.register(
username="viewer1",
password="view123",
role=@shared.Role::Viewer,
timestamp=now + 2UL,
)
println(
"注册用户: admin(管理员), engineer1(工程师), viewer1(查看者)",
)
// 登录
let admin_token = auth.login(
username="admin",
password="admin123",
timestamp=now + 100UL,
)
let eng_token = auth.login(
username="engineer1",
password="eng123",
timestamp=now + 101UL,
)
let viewer_token = auth.login(
username="viewer1",
password="view123",
timestamp=now + 102UL,
)
println("登录成功: 3个用户均获取Token")
// 方案所有权
auth.grant_scheme_ownership(user_id=engineer_id, scheme_id="scheme_A")
auth.grant_scheme_ownership(
user_id=engineer_id,
scheme_id="scheme_B",
is_public=true,
)
auth.grant_scheme_ownership(user_id=admin_id, scheme_id="scheme_C")
println(
"方案所有权: engineer1拥有scheme_A(私有)+scheme_B(公开), admin拥有scheme_C",
)
// 权限检查
let admin_user = auth.users[admin_id]
let eng_user = auth.users[engineer_id]
let viewer_user = auth.users[viewer_id]
println("\n--- 权限检查 ---")
// Admin可以用户管理
auth.check_permission(admin_user, @shared.Permission::UserManage)
println("[OK] admin -> 用户管理权限")
// Engineer不能用户管理
let eng_perm = try {
auth.check_permission(eng_user, @shared.Permission::UserManage)
true
} catch {
_ => false
}
let eng_status = if eng_perm { "OK" } else { "DENY" }
println("[\{eng_status}] engineer1 -> 用户管理权限")
// 方案访问
println("\n--- 方案隔离 ---")
auth.check_scheme_access(eng_user, "scheme_A")
println("[OK] engineer1 -> 访问自己的scheme_A")
auth.check_scheme_access(viewer_user, "scheme_B")
println("[OK] viewer1 -> 只读访问公开scheme_B")
auth.check_scheme_access(admin_user, "scheme_A")
println("[OK] admin -> 访问任何scheme_A")
let viewer_access_private = try {
auth.check_scheme_access(viewer_user, "scheme_A")
true
} catch {
_ => false
}
let viewer_status = if viewer_access_private { "OK" } else { "DENY" }
println("[\{viewer_status}] viewer1 -> 访问私有scheme_A")
// 统计
println("\n--- 统计 ---")
println(auth.stats())
// Token验证
let verified = auth.verify_token(admin_token, current_time=now + 200UL)
println(
"Token验证: admin -> \{verified.username}(\{Show::to_string(verified.role)})",
)
// 登出
let mut logout_details = ""
if !auth.logout(eng_token) {
logout_details = logout_details + "engineer1登出失败; "
}
if !auth.logout(viewer_token) {
logout_details = logout_details + "viewer1登出失败; "
}
println("登出: engineer1, viewer1 已登出")
println(auth.stats())
println("\n权限框架演示完成")
let r : CliResult = {
command: "auth",
success: true,
message: "权限框架演示完成",
details: logout_details,
}
r
}
///|
/// 子命令: ai_forecast - AI混合预报演示
fn cli_ai_forecast() -> CliResult {
println("沐澜水文 AI混合预报演示")
println(repeat_str("=", 50))
// 生成合成降雨-径流数据
let forcings : Array[@shared.ForcingData] = []
let observed : Array[Double] = []
for i in 0..<50 {
let r = if i < 10 {
20.0 - i.to_double()
} else if i < 30 {
5.0 + 10.0 * @math.sin(i.to_double() * 0.3)
} else {
3.0
}
forcings.push({ rainfall: r, evaporation: 1.0, datetime: "t\{i}", })
// 合成径流:非线性变换 + 噪声
let q = r * 0.8 + r * r * 0.01 + 2.0
observed.push(q)
}
println("生成合成数据: 50步降雨-径流序列")
// 物理模型预报(新安江)
let xaj_model = @shared.XinanjiangModel::new(
params=@shared.XinanjiangParams::default(),
area=100.0,
dt=1.0,
)
let sim_result = xaj_model.run(forcings)
let physical = sim_result.runoff_series
println("物理模型(新安江)预报完成: \{physical.length()}步")
// AI混合预报
let config : @ml.HybridConfig = {
lstm_config: { input_dim: 5, hidden_dim: 8, output_dim: 1, },
lookback: 5,
n_forecast: 5,
train_ratio: 0.6,
seed: 42,
}
println("LSTM配置: input=5, hidden=8, output=1, lookback=5")
let result = @ml.hybrid_forecast(config, physical, observed)
// 输出结果
println("\n--- 预报结果对比 ---")
println("物理模型NSE: \{result.physical_nse}")
println("混合预报NSE: \{result.hybrid_nse}")
println("NSE改进: \{result.improvement}")
// 显示部分预报值
println("\n--- 预报序列(后10步) ---")
let n = result.hybrid_forecast.length()
let start = if n > 10 { n - 10 } else { 0 }
println("步数 物理预报 AI校正 混合预报 观测值")
for i in start.. CliResult {
println("沐澜水文 GIS接口演示")
println(repeat_str("=", 50))
// 1. 生成合成DEM
println("\n--- 1. 生成合成DEM ---")
let dem = @gis.synthetic_dem(nx=20, ny=15, dx=100.0, dy=100.0)
let (min_h, max_h, mean_h, cell_count) = @gis.dem_stats(dem)
println("DEM尺寸: \{dem.nx}x\{dem.ny}, 分辨率: \{dem.dx}m x \{dem.dy}m")
println(
"高程范围: \{min_h}m ~ \{max_h}m, 平均: \{mean_h}m, 单元数: \{cell_count}",
)
// 2. D8流向分析
println("\n--- 2. D8流向分析 ---")
let fd = @gis.compute_flow_direction(dem)
let mut dir_counts = 0
for i in 0.. 0 {
dir_counts = dir_counts + 1
}
}
}
println(
"流向计算完成: \{dir_counts}个单元有流向(共\{fd.nx * fd.ny}个)",
)
// 3. 汇流累积
println("\n--- 3. 汇流累积 ---")
let fa = @gis.compute_flow_accumulation(fd)
let mut max_accum = 0
let mut max_i = 0
let mut max_j = 0
for i in 0.. max_accum {
max_accum = fa.accum[i][j]
max_i = i
max_j = j
}
}
}
println(
"汇流累积计算完成, 最大累积值: \{max_accum}(位于[\{max_i},\{max_j}])",
)
// 4. 流域delineation
println("\n--- 4. 流域delineation ---")
let watershed = @gis.delineate_watershed(fd, outlet_i=max_i, outlet_j=max_j)
let ws_area = @gis.watershed_area(dem, watershed)
println(
"流域单元数: \{watershed.length()}, 流域面积: \{ws_area}km²",
)
// 5. 河网提取
println("\n--- 5. 河网提取 ---")
let threshold = max_accum / 5
let river_cells = @gis.extract_river_network(fa, threshold~)
println(
"河网阈值: \{threshold}, 河道单元数: \{river_cells.length()}",
)
// 6. 河网拓扑分析
println("\n--- 6. 河网拓扑分析 ---")
let network = @gis.extract_network_from_dem(dem, fa, threshold~)
println("河网统计: \{network.stats()}")
// 拓扑排序
let topo_order = network.topological_order()
println("拓扑排序河段数: \{topo_order.length()}")
// 追溯源头和出口
if network.outlet_id >= 0 {
let sources = network.trace_to_sources(network.outlet_id)
let outlet_path = network.trace_to_outlet(network.outlet_id)
println("从出口追溯源头数: \{sources.length()}")
println("出口路径长度: \{outlet_path.length()}")
}
// 7. 流域边界多边形演示
println("\n--- 7. 流域边界多边形 ---")
let boundary_pts : Array[@gis.XYPoint] = [
{ x: 0.0, y: 1000.0, },
{ x: 5000.0, y: 1000.0, },
{ x: 5000.0, y: 0.0, },
{ x: 0.0, y: 0.0, },
]
let polygon : @gis.Polygon = {
exterior: boundary_pts,
holes: [],
name: "示例流域",
}
let basin = @gis.BasinBoundary::from_polygon(name="示例流域", polygon)
println("流域名称: \{basin.name}")
println("流域面积: \{basin.area}km²")
println("流域形心: (\{basin.centroid.x}, \{basin.centroid.y})")
println("\nGIS接口演示完成")
let r : CliResult = {
command: "gis",
success: true,
message: "GIS接口演示完成",
details: "",
}
r
}
///|
/// 子命令: flood - 洪水淹没推演演示
fn cli_flood() -> CliResult {
println("沐澜水文 洪水淹没推演演示")
println(repeat_str("=", 50))
// 1. 构造合成洪水场景
println("\n--- 1. 构造洪水场景 ---")
let (grid, config) = @flood.synthetic_flood_scenario(nx=40, ny=30)
println("网格: \{grid.nx}x\{grid.ny}, 分辨率: \{grid.dx}m x \{grid.dy}m")
println("时间步: \{config.n_steps}, dt=\{config.dt}s, CFL=\{config.cfl}")
// 2. 运行淹没仿真
println("\n--- 2. 运行淹没仿真 ---")
let result = @flood.simulate_inundation(grid, config)
println(
"仿真完成: \{result.n_steps_actual}步, 稳定性: \{result.stable}",
)
let (count, area, max_h, mean_h) = @flood.inundation_stats(result)
println(
"淹没单元: \{count}, 淹没面积: \{area}km², 最大水深: \{max_h}m, 平均水深: \{mean_h}m",
)
// 3. 提取淹没范围
println("\n--- 3. 淹没范围 ---")
let extent = @flood.extract_inundation_extent(result, threshold=0.1)
println("淹没范围(水深>0.1m): \{extent.length()}个单元")
// 4. 生成风险图
println("\n--- 4. 风险图 ---")
let risk_map = @flood.generate_risk_map(
result.max_depth,
result.hu_final,
result.hv_final,
nx=result.nx,
ny=result.ny,
final_depth=result.final_depth,
)
let risk_stats = @flood.risk_statistics(risk_map)
println(risk_stats.to_summary())
// 5. ASCII风险图
println("\n--- 5. ASCII风险图 ---")
let ascii_map = @flood.to_ascii_map(risk_map, max_width=60)
println(ascii_map)
// 6. 损失评估
println("\n--- 6. 损失评估 ---")
let land_use = @flood.synthetic_land_use(nx=result.nx, ny=result.ny)
let damage = @flood.estimate_damage(result.max_depth, land_use)
println(damage.to_summary())
println("\n洪水淹没推演演示完成")
let r : CliResult = {
command: "flood",
success: true,
message: "洪水淹没推演演示完成",
details: "",
}
r
}