spongekit

    MoonBit-native small-site stormwater retrofit and rain-garden sizing toolkit.

    stormwater
    runoff
    rain-garden
    sponge-city
    bioretention
    treatment-train
    retrofit-planning
    green-infrastructure
    maintenance
    wasm
    Download zip
    Author
    Version
    0.1.1
    License
    MIT
    Last updated
    2 months ago
    Downloads
    34

    No dependencies

    #SpongeKit

    SpongeKit 是一个 MoonBit 原生雨水径流与雨水花园初步尺寸估算工具包。它面向海绵城市、校园微更新、屋顶径流管理、低影响开发教学示例和 WebAssembly 端快速估算场景,提供可测试、可复现的纯函数计算核心。

    #解决的问题

    很多小型雨水花园或滞蓄设施在方案早期只用表格估算,参数和结果难以复查。SpongeKit 把常见的径流系数法、SCS Curve Number 法、有效蓄水深度、下渗排空时间、分舱面积、土壤剖面调参、多雨型复核、候选面积比较、设施组合、成本估算、预算适配、情景压力测试、维护优先级和改造交付卡整理成 MoonBit API,方便在 CLI、网页、课程或 CI 中复用。

    #差异化定位

    SpongeKit 不做 Markdown、文档检查、项目验收、供应链安全、静态站点或通用 parser。它的边界是小尺度雨水花园和海绵设施的初步水量计算、处理链配置、成本维护和场地交付。2026-08-20 查重中,Mooncakes 上 spongekit、stormwater、runoff、rain garden、bioretention、bioswale、treatment train 等均无同题包;GitHub 上 MoonBit stormwater、MoonBit runoff、MoonBit rain garden、MoonBit bioretention、MoonBit bioswale、SpongeKit MoonBit 也未发现同类 MoonBit 仓库。记录见 docs/COLLISION_RESEARCH.md。

    #安装方式

    moon add BB-ai-nb/spongekit

    在 moon.pkg 中导入:

    import {
    "BB-ai-nb/spongekit"
    }

    #最小使用示例

    let event = @spongekit.rain_event("25mm design storm", 25.0)
    let catchments = [
    @spongekit.catchment_from_surface("roof", 120.0, @spongekit.Roof),
    @spongekit.catchment_from_surface("walkway", 80.0, @spongekit.Pavement),
    ]
    let plan = @spongekit.size_rain_garden(
    catchments,
    event,
    @spongekit.default_garden_spec(),
    )

    #扩展使用示例

    土壤剖面可以直接调整雨水花园参数,并给汇水面径流系数做保守修正:

    let soil = @spongekit.soil_profile(@spongekit.EngineeredMedia)
    let tuned = @spongekit.spec_with_soil(@spongekit.default_garden_spec(), soil)

    多雨型序列可以用于找出控制工况和加权平均径流:

    let events = [
    @spongekit.weighted_event("small storm", 10.0, 0.60),
    @spongekit.weighted_event("design storm", 25.0, 0.30),
    @spongekit.weighted_event("stress storm", 45.0, 0.10),
    ]
    let summary = @spongekit.evaluate_event_series(
    catchments,
    events,
    @spongekit.default_garden_spec(),
    )

    候选面积比较可以把“现有空地能不能用”变成可排序结果:

    let candidates = [
    @spongekit.area_candidate("tree pit retrofit", 8.0),
    @spongekit.area_candidate("courtyard strip", 22.0),
    @spongekit.area_candidate("sunken lawn edge", 32.0),
    ]
    let comparison = @spongekit.compare_candidate_areas(
    catchments,
    event,
    @spongekit.default_garden_spec(),
    candidates,
    )

    设施组合和成本估算可以评估一组串联设施,而不只计算单个雨水花园面积:

    match @spongekit.recommend_facility_mix(catchments, event, 36.0) {
    Ok(train) => {
    match @spongekit.estimate_treatment_train_cost(
    train,
    @spongekit.default_cost_profile(),
    ) {
    Ok(costs) => println(costs.total_capital_cost.to_string())
    Err(error) => println(error.label())
    }
    }
    Err(error) => println(error.label())
    }

    情景比较可以同时改变降雨、径流、下渗、可用面积、泥沙负荷和预算:

    let scenarios = @spongekit.default_stress_scenarios(36.0)
    let comparison = @spongekit.compare_retrofit_scenarios(
    catchments,
    event,
    @spongekit.default_garden_spec(),
    scenarios,
    )

    改造交付卡可以把 sizing、设施组合、成本和维护动作压缩成现场移交摘要:

    let passport = @spongekit.scenario_passport("library courtyard", scenario_result)
    println(passport.to_markdown())

    可运行示例位于 cmd/main:

    moon run cmd/main

    示例输出包含 sizing 状态、推荐面积、设施组合捕获率、成本和情景比较摘要:

    status=ready recommended_area_m2=26.285714285714285 {"status":"ready","event":"25mm campus retrofit storm",...} train_capture_ratio=0.9978504347826087 train_capital_cost=35745.419279999995 best_scenario=showcase upgrade average_scenario_score=81

    #本地验证

    moon check moon build moon test moon run cmd/main moon package moon publish --dry-run

    moon publish --dry-run 和正式发布需要先使用参赛者账号执行 moon login。

    #核心功能

    • runoff_coefficient(kind):为屋顶、硬质铺装、压实土、草坪和草甸提供默认径流系数。
    • runoff_volume(catchment, event):用径流系数法计算单个汇水面径流深、体积和升数。
    • total_runoff_volume(catchments, event):合并多个汇水面,输出总体设计径流。
    • curve_number_runoff_depth(rainfall_mm, curve_number):用 SCS Curve Number 方程计算径流深。
    • curve_number_runoff(area_m2, rainfall_mm, curve_number):输出 retention、initial abstraction、径流深和体积。
    • default_garden_spec():提供一组保守的雨水花园默认参数。
    • effective_storage_depth_mm(spec):计算表面滞蓄和介质孔隙共同形成的有效蓄水深度。
    • size_rain_garden(catchments, event, spec):生成推荐面积、分舱数量、单舱面积、下渗排空时间、捕获率和复核事项。
    • soil_profile(kind):提供砂土、砂壤土、壤土、黏壤土、黏土、城市回填土和工程介质的参数模板。
    • spec_with_soil(spec, soil):用土壤剖面更新孔隙率和下渗速率。
    • adjusted_catchment_for_soil(catchment, soil):根据土壤条件保守调整汇水面径流系数。
    • blended_soil_profile(name, soils, weights):按权重混合多个土壤剖面,生成场地复合参数。
    • maintenance_plan(plan, soil, sediment_load_index, months_since_service):根据排空、捕获率、土壤堵塞风险、泥沙负荷和维护间隔输出维护优先级。
    • weighted_event(name, depth_mm, weight):构造带权重的降雨事件。
    • evaluate_event_series(catchments, events, spec):批量评估多个降雨工况,输出控制雨型、加权径流和逐事件结果。
    • area_candidate(name, area_m2):构造候选雨水花园面积。
    • evaluate_candidate_area(catchments, event, spec, candidate):计算固定面积方案的容量、旁通量、捕获率、评分和问题列表。
    • compare_candidate_areas(catchments, event, spec, candidates):比较多个候选面积并返回得分最高方案。
    • facility_template(kind, name, footprint_area_m2):按设施类型生成雨水花园、生态浅沟、透水铺装、蓄水桶、绿屋顶、树池沟和干井模板。
    • facility_with_hydraulics(...):用自定义水力参数创建设施。
    • facility_storage_capacity_m3(facility):计算设施静态蓄水能力。
    • evaluate_facility(event_runoff_m3, facility):计算单个设施的容量、捕获量、旁通量、排空时间、韧性评分和复核 notes。
    • evaluate_treatment_train(catchments, event, facilities):按顺序将旁通量路由到下一设施,生成设施组合汇总。
    • recommend_facility_mix(catchments, event, available_area_m2):按可用面积生成一个默认设施组合并评估。
    • cost_profile(tier) / default_cost_profile():提供经济型、标准型、耐久型和展示型成本参数。
    • custom_cost_profile(...):构造自定义成本参数。
    • estimate_facility_cost(contribution, profile):估算单个设施的建造成本、年维护成本、生命周期成本和单位捕获量成本。
    • estimate_treatment_train_cost(plan, profile):汇总设施组合成本并找出成本最高项。
    • budget_fit_score(summary, capital_budget, annual_budget):计算方案与建设预算、年维护预算的适配得分。
    • retrofit_scenario(name, rainfall_multiplier, available_area_m2):快速构造改造情景。
    • scenario_with_budget(...):构造包含降雨、径流、下渗、目标捕获率、面积、泥沙、成本档位和预算的完整情景。
    • default_stress_scenarios(available_area_m2):生成 baseline、compact retrofit、climate stress 和 showcase upgrade 四种默认压力情景。
    • evaluate_retrofit_scenario(catchments, event, spec, scenario):输出单情景下的水量、候选面积、设施组合、维护、成本和综合评分。
    • compare_retrofit_scenarios(catchments, event, spec, scenarios):比较多个情景,输出最佳、最差、平均得分、最大径流和最小捕获率。
    • build_retrofit_passport(site_name, garden, train, cost, maintenance):把设计卡、设施组合、成本和维护计划合成小场地改造交付卡。
    • scenario_passport(site_name, scenario_result):从情景结果生成可交付摘要。
    • passport_followup_days(passport):根据交付卡评级和维护优先级计算下次跟进天数。
    • passport_handoff_checklist(passport):生成现场移交检查清单。
    • GardenPlan::to_json() / GardenPlan::to_markdown():导出机器可读或人工可读设计卡。
    • SeriesSummary::to_json() / SeriesSummary::to_markdown():导出多雨型复核报告。
    • CandidateComparison::to_json() / CandidateComparison::to_markdown():导出候选面积比较报告。
    • SoilProfile::to_json() / MaintenancePlan::to_json() / CandidatePerformance::to_json():导出土壤、维护和候选单项结果。
    • TreatmentTrainPlan::to_json() / TreatmentTrainPlan::to_markdown():导出设施组合报告。
    • TrainCostSummary::to_json() / TrainCostSummary::to_markdown():导出成本报告。
    • ScenarioComparison::to_json() / ScenarioComparison::to_markdown():导出情景比较报告。
    • RetrofitPassport::to_json() / RetrofitPassport::to_markdown():导出改造交付卡。

    #功能边界

    • 这是早期方案估算工具,不替代注册工程师设计、地方规范审查或施工图计算。
    • 不包含地区降雨数据库,调用方需要传入设计降雨深度。
    • 不读取文件系统,不联网,不引入第三方数据或素材。
    • 多雨型序列是离散事件加权评估,不模拟连续降雨、水质污染物、地下水回灌、溢流构筑物和管网水力。
    • 设施组合按简化顺序路由旁通量,不替代详细管线高程、溢流口和水力坡降设计。
    • 成本估算使用调用方传入或默认的概算参数,不代表任何地区定额。
    • 情景分析用于早期方案比较,不预测长期气候变化和全生命周期资产状态。
    • 维护计划是风险分级建议,不替代现场巡检、检测报告或运营制度。
    • Curve Number 方法采用常用 SCS 经验公式,默认 initial abstraction ratio 为 0.2。

    #开源许可证与第三方说明

    本项目使用 MIT 许可证。核心实现为 MoonBit 原生代码,不移植第三方源码,不包含图片、音频、字体或来源不明测试数据。公式为公开水文工程常识表达,项目文档中明确标注适用边界。

    AreaCandidate

    pub(all) struct AreaCandidate {
    name : String
    area_m2 : Double
    max_cell_area_m2 : Double
    } derive(Eq,
    Debug
    )

    CandidateComparison

    pub(all) struct CandidateComparison {
    candidate_count : Int
    best_name : String
    best_score : Int
    performances : Array[CandidatePerformance]
    } derive(Eq,
    Debug
    )

    CandidateComparison::to_json

    fn CandidateComparison::to_json(self : CandidateComparison) -> String

    CandidateComparison::to_markdown

    fn CandidateComparison::to_markdown(self : CandidateComparison) -> String

    CandidatePerformance

    pub(all) struct CandidatePerformance {
    name : String
    area_m2 : Double
    cell_count : Int
    cell_area_m2 : Double
    storage_capacity_m3 : Double
    runoff_volume_m3 : Double
    captured_volume_m3 : Double
    bypass_volume_m3 : Double
    capture_ratio : Double
    drawdown_hours : Double
    score : Int
    status : PlanStatus
    issues : Array[PlanIssue]
    } derive(Eq,
    Debug
    )

    CandidatePerformance::to_json

    fn CandidatePerformance::to_json(self : CandidatePerformance) -> String

    Catchment

    pub(all) struct Catchment {
    name : String
    area_m2 : Double
    runoff_coefficient : Double
    } derive(Eq,
    Debug
    )

    CostProfile

    pub(all) struct CostProfile {
    tier : CostTier
    currency : String
    construction_per_m2 : Double
    excavation_per_m3 : Double
    media_per_m3 : Double
    planting_per_m2 : Double
    pretreatment_each : Double
    inspection_per_visit : Double
    sediment_service_per_visit : Double
    annual_maintenance_rate : Double
    design_markup_rate : Double
    contingency_rate : Double
    lifespan_years : Int
    } derive(Eq,
    Debug
    )

    CostProfile::to_json

    fn CostProfile::to_json(self : CostProfile) -> String

    CostTier

    pub(all) enum CostTier {
    Economy
    Standard
    Durable
    Showcase
    } derive(Eq,
    Debug
    )

    CostTier::label

    fn CostTier::label(self : CostTier) -> String

    CurveNumberResult

    pub(all) struct CurveNumberResult {
    rainfall_mm : Double
    curve_number : Double
    retention_mm : Double
    initial_abstraction_mm : Double
    runoff_depth_mm : Double
    runoff_volume_m3 : Double
    } derive(Eq,
    Debug
    )

    EventSizing

    pub(all) struct EventSizing {
    event_name : String
    depth_mm : Double
    weight : Double
    runoff_volume_m3 : Double
    recommended_area_m2 : Double
    capture_ratio : Double
    drawdown_hours : Double
    status : PlanStatus
    } derive(Eq,
    Debug
    )

    FacilityContribution

    pub(all) struct FacilityContribution {
    name : String
    kind : FacilityKind
    footprint_area_m2 : Double
    storage_capacity_m3 : Double
    event_runoff_m3 : Double
    captured_volume_m3 : Double
    bypass_volume_m3 : Double
    capture_ratio : Double
    drawdown_hours : Double
    resilience_score : Int
    status : PlanStatus
    notes : Array[String]
    } derive(Eq,
    Debug
    )

    FacilityContribution::to_json

    fn FacilityContribution::to_json(self : FacilityContribution) -> String

    FacilityCost

    pub(all) struct FacilityCost {
    name : String
    kind : FacilityKind
    currency : String
    footprint_area_m2 : Double
    capital_cost : Double
    annual_maintenance_cost : Double
    lifecycle_cost : Double
    annualized_cost : Double
    cost_per_captured_m3 : Double
    recommended_visits_per_year : Int
    notes : Array[String]
    } derive(Eq,
    Debug
    )

    FacilityCost::to_json

    fn FacilityCost::to_json(self : FacilityCost) -> String

    FacilityKind

    pub(all) enum FacilityKind {
    RainGarden
    Bioswale
    PermeablePavement
    Cistern
    GreenRoof
    TreeTrench
    DryWell
    } derive(Eq,
    Debug
    )

    FacilityKind::label

    fn FacilityKind::label(self : FacilityKind) -> String

    FacilitySpec

    pub(all) struct FacilitySpec {
    kind : FacilityKind
    name : String
    footprint_area_m2 : Double
    storage_depth_mm : Double
    infiltration_rate_mm_per_hr : Double
    drain_delay_hours : Double
    pretreatment_score : Double
    vegetation_score : Double
    max_capture_ratio : Double
    overflow_priority : Int
    } derive(Eq,
    Debug
    )

    FacilitySpec::to_json

    fn FacilitySpec::to_json(self : FacilitySpec) -> String

    GardenPlan

    pub(all) struct GardenPlan {
    status : PlanStatus
    event_name : String
    catchment_count : Int
    catchment_area_m2 : Double
    design_rain_mm : Double
    runoff_volume_m3 : Double
    storage_depth_mm : Double
    required_area_m2 : Double
    recommended_area_m2 : Double
    cell_count : Int
    cell_area_m2 : Double
    drawdown_hours : Double
    capture_ratio : Double
    issues : Array[PlanIssue]
    } derive(Eq,
    Debug
    )

    GardenPlan::to_json

    fn GardenPlan::to_json(self : GardenPlan) -> String

    GardenPlan::to_markdown

    fn GardenPlan::to_markdown(self : GardenPlan) -> String

    GardenSpec

    pub(all) struct GardenSpec {
    ponding_depth_mm : Double
    media_depth_mm : Double
    media_porosity : Double
    infiltration_rate_mm_per_hr : Double
    safety_factor : Double
    target_drawdown_hours : Double
    target_capture_ratio : Double
    max_cell_area_m2 : Double
    } derive(Eq,
    Debug
    )

    MaintenanceAction

    pub(all) enum MaintenanceAction {
    InspectInlet
    RemoveSediment
    RenewMulch
    CheckOverflow
    ReplantBareSoil
    LoosenSurface
    } derive(Eq,
    Debug
    )

    MaintenanceAction::label

    fn MaintenanceAction::label(self : MaintenanceAction) -> String

    MaintenancePlan

    pub(all) struct MaintenancePlan {
    priority : MaintenancePriority
    interval_days : Int
    risk_score : Int
    actions : Array[MaintenanceAction]
    note : String
    } derive(Eq,
    Debug
    )

    MaintenancePlan::to_json

    fn MaintenancePlan::to_json(self : MaintenancePlan) -> String

    MaintenancePriority

    pub(all) enum MaintenancePriority {
    Routine
    Watch
    ServiceSoon
    Restore
    } derive(Eq,
    Debug
    )

    MaintenancePriority::label

    fn MaintenancePriority::label(self : MaintenancePriority) -> String

    PassportBand

    pub(all) enum PassportBand {
    Excellent
    Solid
    Watchlist
    Rework
    } derive(Eq,
    Debug
    )

    PassportBand::label

    fn PassportBand::label(self : PassportBand) -> String

    PlanIssue

    pub(all) struct PlanIssue {
    kind : PlanIssueKind
    message : String
    } derive(Eq,
    Debug
    )

    PlanIssueKind

    pub(all) enum PlanIssueKind {
    DrawdownTooSlow
    CaptureBelowTarget
    OversizedCell
    NoRunoff
    } derive(Eq,
    Debug
    )

    PlanIssueKind::label

    fn PlanIssueKind::label(self : PlanIssueKind) -> String

    PlanStatus

    pub(all) enum PlanStatus {
    Ready
    NeedsReview
    Invalid
    } derive(Eq,
    Debug
    )

    PlanStatus::label

    fn PlanStatus::label(self : PlanStatus) -> String

    RainEvent

    pub(all) struct RainEvent {
    name : String
    depth_mm : Double
    } derive(Eq,
    Debug
    )

    RetrofitPassport

    pub(all) struct RetrofitPassport {
    site_name : String
    event_name : String
    band : PassportBand
    overall_score : Int
    footprint_area_m2 : Double
    runoff_volume_m3 : Double
    captured_volume_m3 : Double
    bypass_volume_m3 : Double
    capture_ratio : Double
    capital_cost : Double
    annual_maintenance_cost : Double
    maintenance_priority : MaintenancePriority
    maintenance_interval_days : Int
    public_summary : String
    field_actions : Array[String]
    assumptions : Array[String]
    } derive(Eq,
    Debug
    )

    RetrofitPassport::to_json

    fn RetrofitPassport::to_json(self : RetrofitPassport) -> String

    RetrofitPassport::to_markdown

    fn RetrofitPassport::to_markdown(self : RetrofitPassport) -> String

    RetrofitScenario

    pub(all) struct RetrofitScenario {
    name : String
    rainfall_multiplier : Double
    runoff_multiplier : Double
    infiltration_multiplier : Double
    target_capture_ratio : Double
    available_area_m2 : Double
    sediment_load_index : Double
    cost_tier : CostTier
    capital_budget : Double
    annual_budget : Double
    } derive(Eq,
    Debug
    )

    RetrofitScenario::to_json

    fn RetrofitScenario::to_json(self : RetrofitScenario) -> String

    RunoffResult

    pub(all) struct RunoffResult {
    depth_mm : Double
    volume_m3 : Double
    volume_liters : Double
    } derive(Eq,
    Debug
    )

    ScenarioComparison

    pub(all) struct ScenarioComparison {
    scenario_count : Int
    best_name : String
    worst_name : String
    average_score : Double
    max_runoff_m3 : Double
    min_capture_ratio : Double
    results : Array[ScenarioResult]
    } derive(Eq,
    Debug
    )

    ScenarioComparison::to_json

    fn ScenarioComparison::to_json(self : ScenarioComparison) -> String

    ScenarioComparison::to_markdown

    fn ScenarioComparison::to_markdown(self : ScenarioComparison) -> String

    ScenarioResult

    pub(all) struct ScenarioResult {
    name : String
    adjusted_rain_mm : Double
    adjusted_runoff_m3 : Double
    recommended_area_m2 : Double
    candidate_best_name : String
    candidate_best_score : Int
    treatment_capture_ratio : Double
    treatment_bypass_m3 : Double
    treatment_resilience_score : Int
    maintenance_priority : MaintenancePriority
    maintenance_risk_score : Int
    total_capital_cost : Double
    lifecycle_cost : Double
    budget_fit_score : Int
    overall_score : Int
    status : PlanStatus
    notes : Array[String]
    } derive(Eq,
    Debug
    )

    ScenarioResult::to_json

    fn ScenarioResult::to_json(self : ScenarioResult) -> String

    SeriesSummary

    pub(all) struct SeriesSummary {
    event_count : Int
    ready_count : Int
    review_count : Int
    controlling_event_name : String
    max_recommended_area_m2 : Double
    weighted_runoff_m3 : Double
    weighted_capture_ratio : Double
    results : Array[EventSizing]
    } derive(Eq,
    Debug
    )

    SeriesSummary::to_json

    fn SeriesSummary::to_json(self : SeriesSummary) -> String

    SeriesSummary::to_markdown

    fn SeriesSummary::to_markdown(self : SeriesSummary) -> String

    SoilClass

    pub(all) enum SoilClass {
    Sand
    SandyLoam
    Loam
    ClayLoam
    Clay
    UrbanFill
    EngineeredMedia
    } derive(Eq,
    Debug
    )

    SoilClass::label

    fn SoilClass::label(self : SoilClass) -> String

    SoilProfile

    pub(all) struct SoilProfile {
    kind : SoilClass
    name : String
    infiltration_rate_mm_per_hr : Double
    porosity : Double
    runoff_adjustment : Double
    clogging_risk : Double
    maintenance_interval_days : Int
    } derive(Eq,
    Debug
    )

    SoilProfile::to_json

    fn SoilProfile::to_json(self : SoilProfile) -> String

    SpongeError

    pub(all) enum SpongeError {
    NonPositiveArea
    NegativeRainfall
    InvalidRunoffCoefficient
    InvalidCurveNumber
    InvalidInfiltrationRate
    InvalidStorageDepth
    InvalidSafetyFactor
    InvalidCellLimit
    InvalidWeight
    InvalidCandidateArea
    InvalidSedimentLoad
    InvalidFacilitySpec
    InvalidCostProfile
    InvalidScenarioInput
    } derive(Eq,
    Debug
    )

    SpongeError::label

    fn SpongeError::label(self : SpongeError) -> String

    SurfaceKind

    pub(all) enum SurfaceKind {
    Roof
    Pavement
    CompactedSoil
    Lawn
    Meadow
    } derive(Eq,
    Debug
    )

    TrainCostSummary

    pub(all) struct TrainCostSummary {
    currency : String
    facility_count : Int
    total_capital_cost : Double
    annual_maintenance_cost : Double
    lifecycle_cost : Double
    annualized_cost : Double
    captured_volume_m3 : Double
    cost_per_captured_m3 : Double
    highest_cost_name : String
    highest_cost : Double
    items : Array[FacilityCost]
    notes : Array[String]
    } derive(Eq,
    Debug
    )

    TrainCostSummary::to_json

    fn TrainCostSummary::to_json(self : TrainCostSummary) -> String

    TrainCostSummary::to_markdown

    fn TrainCostSummary::to_markdown(self : TrainCostSummary) -> String

    TreatmentTrainPlan

    pub(all) struct TreatmentTrainPlan {
    event_name : String
    facility_count : Int
    runoff_volume_m3 : Double
    footprint_area_m2 : Double
    total_capacity_m3 : Double
    total_captured_m3 : Double
    bypass_volume_m3 : Double
    capture_ratio : Double
    weighted_drawdown_hours : Double
    resilience_score : Int
    status : PlanStatus
    contributions : Array[FacilityContribution]
    notes : Array[String]
    } derive(Eq,
    Debug
    )

    TreatmentTrainPlan::to_json

    fn TreatmentTrainPlan::to_json(self : TreatmentTrainPlan) -> String

    TreatmentTrainPlan::to_markdown

    fn TreatmentTrainPlan::to_markdown(self : TreatmentTrainPlan) -> String

    WeightedRainEvent

    pub(all) struct WeightedRainEvent {
    event : RainEvent
    weight : Double
    } derive(Eq,
    Debug
    )

    adjusted_catchment_for_soil

    fn adjusted_catchment_for_soil(catchment : Catchment, soil : SoilProfile) -> Result[Catchment, SpongeError]

    area_candidate

    fn area_candidate(name : String, area_m2 : Double) -> AreaCandidate

    area_candidate_with_cell_limit

    fn area_candidate_with_cell_limit(name : String, area_m2 : Double, max_cell_area_m2 : Double) -> AreaCandidate

    blended_soil_profile

    fn blended_soil_profile(name : String, soils : Array[SoilProfile], weights : Array[Double]) -> Result[SoilProfile, SpongeError]

    budget_fit_score

    fn budget_fit_score(summary : TrainCostSummary, capital_budget : Double, annual_budget : Double) -> Result[Int, SpongeError]

    build_retrofit_passport

    fn build_retrofit_passport(site_name : String, garden : GardenPlan, train : TreatmentTrainPlan, cost : TrainCostSummary, maintenance : MaintenancePlan) -> RetrofitPassport

    catchment

    fn catchment(name : String, area_m2 : Double, runoff_coefficient : Double) -> Catchment

    catchment_from_surface

    fn catchment_from_surface(name : String, area_m2 : Double, kind : SurfaceKind) -> Catchment

    compare_candidate_areas

    fn compare_candidate_areas(catchments : Array[Catchment], event : RainEvent, spec : GardenSpec, candidates : Array[AreaCandidate]) -> Result[CandidateComparison, SpongeError]

    compare_retrofit_scenarios

    fn compare_retrofit_scenarios(catchments : Array[Catchment], base_event : RainEvent, spec : GardenSpec, scenarios : Array[RetrofitScenario]) -> Result[ScenarioComparison, SpongeError]

    cost_profile

    fn cost_profile(tier : CostTier) -> CostProfile

    curve_number_runoff

    fn curve_number_runoff(area_m2 : Double, rainfall_mm : Double, curve_number : Double) -> Result[CurveNumberResult, SpongeError]

    curve_number_runoff_depth

    fn curve_number_runoff_depth(rainfall_mm : Double, curve_number : Double) -> Result[Double, SpongeError]

    custom_cost_profile

    fn custom_cost_profile(currency : String, construction_per_m2 : Double, excavation_per_m3 : Double, media_per_m3 : Double, planting_per_m2 : Double, pretreatment_each : Double, inspection_per_visit : Double, sediment_service_per_visit : Double, annual_maintenance_rate : Double, design_markup_rate : Double, contingency_rate : Double, lifespan_years : Int) -> CostProfile

    default_cost_profile

    fn default_cost_profile() -> CostProfile

    default_garden_spec

    fn default_garden_spec() -> GardenSpec

    default_stress_scenarios

    fn default_stress_scenarios(available_area_m2 : Double) -> Array[RetrofitScenario]

    effective_storage_depth_mm

    fn effective_storage_depth_mm(spec : GardenSpec) -> Result[Double, SpongeError]

    estimate_facility_cost

    fn estimate_facility_cost(contribution : FacilityContribution, profile : CostProfile) -> Result[FacilityCost, SpongeError]

    estimate_treatment_train_cost

    fn estimate_treatment_train_cost(plan : TreatmentTrainPlan, profile : CostProfile) -> Result[TrainCostSummary, SpongeError]

    evaluate_candidate_area

    fn evaluate_candidate_area(catchments : Array[Catchment], event : RainEvent, spec : GardenSpec, candidate : AreaCandidate) -> Result[CandidatePerformance, SpongeError]

    evaluate_event_series

    fn evaluate_event_series(catchments : Array[Catchment], events : Array[WeightedRainEvent], spec : GardenSpec) -> Result[SeriesSummary, SpongeError]

    evaluate_facility

    fn evaluate_facility(event_runoff_m3 : Double, facility : FacilitySpec) -> Result[FacilityContribution, SpongeError]

    evaluate_retrofit_scenario

    fn evaluate_retrofit_scenario(catchments : Array[Catchment], base_event : RainEvent, spec : GardenSpec, scenario : RetrofitScenario) -> Result[ScenarioResult, SpongeError]

    evaluate_treatment_train

    fn evaluate_treatment_train(catchments : Array[Catchment], event : RainEvent, facilities : Array[FacilitySpec]) -> Result[TreatmentTrainPlan, SpongeError]

    facility_storage_capacity_m3

    fn facility_storage_capacity_m3(facility : FacilitySpec) -> Result[Double, SpongeError]

    facility_template

    fn facility_template(kind : FacilityKind, name : String, footprint_area_m2 : Double) -> FacilitySpec

    facility_with_hydraulics

    fn facility_with_hydraulics(kind : FacilityKind, name : String, footprint_area_m2 : Double, storage_depth_mm : Double, infiltration_rate_mm_per_hr : Double, drain_delay_hours : Double, pretreatment_score : Double, vegetation_score : Double, max_capture_ratio : Double, overflow_priority : Int) -> FacilitySpec

    maintenance_plan

    fn maintenance_plan(plan : GardenPlan, soil : SoilProfile, sediment_load_index : Double, months_since_service : Int) -> Result[MaintenancePlan, SpongeError]

    passport_followup_days

    fn passport_followup_days(passport : RetrofitPassport) -> Int

    passport_handoff_checklist

    fn passport_handoff_checklist(passport : RetrofitPassport) -> Array[String]

    rain_event

    fn rain_event(name : String, depth_mm : Double) -> RainEvent

    recommend_facility_mix

    fn recommend_facility_mix(catchments : Array[Catchment], event : RainEvent, available_area_m2 : Double) -> Result[TreatmentTrainPlan, SpongeError]

    retrofit_scenario

    fn retrofit_scenario(name : String, rainfall_multiplier : Double, available_area_m2 : Double) -> RetrofitScenario

    runoff_coefficient

    fn runoff_coefficient(kind : SurfaceKind) -> Double

    runoff_volume

    fn runoff_volume(catchment : Catchment, event : RainEvent) -> Result[RunoffResult, SpongeError]

    scenario_passport

    fn scenario_passport(site_name : String, scenario : ScenarioResult) -> RetrofitPassport

    scenario_with_budget

    fn scenario_with_budget(name : String, rainfall_multiplier : Double, runoff_multiplier : Double, infiltration_multiplier : Double, target_capture_ratio : Double, available_area_m2 : Double, sediment_load_index : Double, cost_tier : CostTier, capital_budget : Double, annual_budget : Double) -> RetrofitScenario

    size_rain_garden

    fn size_rain_garden(catchments : Array[Catchment], event : RainEvent, spec : GardenSpec) -> Result[GardenPlan, SpongeError]

    soil_profile

    fn soil_profile(kind : SoilClass) -> SoilProfile

    spec_with_soil

    fn spec_with_soil(spec : GardenSpec, soil : SoilProfile) -> Result[GardenSpec, SpongeError]

    total_runoff_volume

    fn total_runoff_volume(catchments : Array[Catchment], event : RainEvent) -> Result[RunoffResult, SpongeError]

    weighted_event

    fn weighted_event(name : String, depth_mm : Double, weight : Double) -> WeightedRainEvent