diff --git a/.github/workflows/core_testmodels.yml b/.github/workflows/core_testmodels.yml index 9679cbbf8..91d5f6e3f 100644 --- a/.github/workflows/core_testmodels.yml +++ b/.github/workflows/core_testmodels.yml @@ -29,7 +29,7 @@ jobs: - x64 steps: - uses: actions/checkout@v4 - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 with: cache-compiled: "true" cache-registries: "true" diff --git a/.github/workflows/core_tests.yml b/.github/workflows/core_tests.yml index 2ba330004..921469bc4 100644 --- a/.github/workflows/core_tests.yml +++ b/.github/workflows/core_tests.yml @@ -29,7 +29,7 @@ jobs: - x64 steps: - uses: actions/checkout@v4 - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 with: cache-compiled: "true" cache-registries: "true" diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index ccd50d8e5..45bb7d427 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -20,7 +20,7 @@ jobs: contents: write steps: - uses: actions/checkout@v4 - - uses: julia-actions/cache@v1 + - uses: julia-actions/cache@v2 with: cache-compiled: "true" cache-registries: "true" @@ -33,9 +33,6 @@ jobs: - name: Check Quarto installation and all engines run: pixi run quarto-check - - name: Generate Julia docs - run: pixi run build-julia-docs - - name: Render Quarto Project run: pixi run quarto-render diff --git a/.gitignore b/.gitignore index 5e8b06ffc..7e2d4e441 100644 --- a/.gitignore +++ b/.gitignore @@ -5,10 +5,6 @@ # Files generated by invoking Julia with --track-allocation *.jl.mem -# Build artifacts for creating documentation generated by the Documenter package -docs/build/ -docs/site/ - /generated_testmodels build/ribasim/ build/cli/target diff --git a/.teamcity/Ribasim_Linux/buildTypes/Ribasim_Linux_TestRibasimBinaries.xml b/.teamcity/Ribasim_Linux/buildTypes/Ribasim_Linux_TestRibasimBinaries.xml index a49348465..c8c7e38e7 100644 --- a/.teamcity/Ribasim_Linux/buildTypes/Ribasim_Linux_TestRibasimBinaries.xml +++ b/.teamcity/Ribasim_Linux/buildTypes/Ribasim_Linux_TestRibasimBinaries.xml @@ -16,8 +16,7 @@ source /usr/share/Modules/init/bash module load pixi -pixi --version -pixi run install-python]]> +pixi --version]]> @@ -30,7 +29,6 @@ pixi run install-python]]> source /usr/share/Modules/init/bash module load pixi -pixi run --environment=dev install pixi run test-ribasim-api pixi run test-ribasim-cli]]> diff --git a/.teamcity/Ribasim_Windows/buildTypes/Ribasim_Windows_TestRibasimBinaries.xml b/.teamcity/Ribasim_Windows/buildTypes/Ribasim_Windows_TestRibasimBinaries.xml index 23a1e8ca0..86e53b375 100644 --- a/.teamcity/Ribasim_Windows/buildTypes/Ribasim_Windows_TestRibasimBinaries.xml +++ b/.teamcity/Ribasim_Windows/buildTypes/Ribasim_Windows_TestRibasimBinaries.xml @@ -10,7 +10,7 @@ - + @@ -18,8 +18,7 @@ - diff --git a/Manifest.toml b/Manifest.toml index cdb214bc6..5ca38ecd5 100644 --- a/Manifest.toml +++ b/Manifest.toml @@ -2,18 +2,13 @@ julia_version = "1.10.3" manifest_format = "2.0" -project_hash = "045162196d64ccb59bdab2af0422fde0b0e83c77" +project_hash = "dc6d536cc58558be9be8b5e2e4d511d0451ed14f" [[deps.ADTypes]] git-tree-sha1 = "016833eb52ba2d6bea9fcb50ca295980e728ee24" uuid = "47edcb42-4c32-4615-8424-f2b9edc5f35b" version = "0.2.7" -[[deps.ANSIColoredPrinters]] -git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" -uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" -version = "0.0.1" - [[deps.AbstractTrees]] git-tree-sha1 = "2d9c9a55f9c93e8887ad391fbae72f8ef55e1177" uuid = "1520ce14-60c1-5f80-bbc7-55ef81b5835c" @@ -438,18 +433,6 @@ git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" version = "0.9.3" -[[deps.Documenter]] -deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] -git-tree-sha1 = "39fd748a73dce4c05a9655475e437170d8fb1b67" -uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -version = "0.27.25" - -[[deps.DocumenterMarkdown]] -deps = ["Documenter"] -git-tree-sha1 = "9af057a98652336e30586d8092fac06f8b28ecdc" -uuid = "997ab1e6-3595-5248-9280-8efb232c3433" -version = "0.2.2" - [[deps.Downloads]] deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" @@ -498,9 +481,9 @@ version = "0.3.2" [[deps.FastLapackInterface]] deps = ["LinearAlgebra"] -git-tree-sha1 = "0a59c7d1002f3131de53dc4568a47d15a44daef7" +git-tree-sha1 = "f4102aab9c7df8691ed09f9c42e34f5ab5458ab9" uuid = "29a986be-02c6-4525-aec4-84b980013641" -version = "2.0.2" +version = "2.0.3" [[deps.FileIO]] deps = ["Pkg", "Requires", "UUIDs"] @@ -626,12 +609,6 @@ git-tree-sha1 = "47ac8cc196b81001a711f4b2c12c97372338f00c" uuid = "7073ff75-c697-5162-941a-fcdaad2a7d2a" version = "1.24.2" -[[deps.IOCapture]] -deps = ["Logging", "Random"] -git-tree-sha1 = "8b72179abc660bfab5e28472e019392b97d0985c" -uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" -version = "0.2.4" - [[deps.IfElse]] git-tree-sha1 = "debdd00ffef04665ccbb3e150747a77560e8fad1" uuid = "615f187c-cbe4-4ef1-ba3b-2fcf58d6d173" @@ -753,9 +730,9 @@ version = "0.6.0" [[deps.Krylov]] deps = ["LinearAlgebra", "Printf", "SparseArrays"] -git-tree-sha1 = "8a6837ec02fe5fb3def1abc907bb802ef11a0729" +git-tree-sha1 = "267dad6b4b7b5d529c76d40ff48d33f7e94cb834" uuid = "ba0b0d4f-ebba-5204-a429-3ac8c609bfb7" -version = "0.9.5" +version = "0.9.6" [[deps.LaTeXStrings]] git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec" @@ -1211,9 +1188,9 @@ version = "1.3.4" [[deps.RecursiveArrayTools]] deps = ["Adapt", "ArrayInterface", "DocStringExtensions", "GPUArraysCore", "IteratorInterfaceExtensions", "LinearAlgebra", "RecipesBase", "SparseArrays", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "Tables"] -git-tree-sha1 = "d8f131090f2e44b145084928856a561c83f43b27" +git-tree-sha1 = "6305b6fe0391eeb4f280a4a403ac0c350b82c718" uuid = "731186ca-8d62-57ce-b412-fbd966d074cd" -version = "3.13.0" +version = "3.15.0" [deps.RecursiveArrayTools.extensions] RecursiveArrayToolsFastBroadcastExt = "FastBroadcast" @@ -1303,9 +1280,9 @@ version = "3.45.0+0" [[deps.SciMLBase]] deps = ["ADTypes", "ArrayInterface", "CommonSolve", "ConstructionBase", "Distributed", "DocStringExtensions", "EnumX", "FunctionWrappersWrappers", "IteratorInterfaceExtensions", "LinearAlgebra", "Logging", "Markdown", "PrecompileTools", "Preferences", "Printf", "RecipesBase", "RecursiveArrayTools", "Reexport", "RuntimeGeneratedFunctions", "SciMLOperators", "SciMLStructures", "StaticArraysCore", "Statistics", "SymbolicIndexingInterface", "Tables"] -git-tree-sha1 = "beb1f94b08c4976ed1db0ca01b9e6bac89706faf" +git-tree-sha1 = "397367599b9526a49cc06a4db70835807498b561" uuid = "0bca4576-84f4-4d90-8ffe-ffa030f20462" -version = "2.35.0" +version = "2.36.1" [deps.SciMLBase.extensions] SciMLBaseChainRulesCoreExt = "ChainRulesCore" @@ -1530,10 +1507,10 @@ uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" version = "7.2.1+1" [[deps.SymbolicIndexingInterface]] -deps = ["Accessors", "ArrayInterface", "MacroTools", "RuntimeGeneratedFunctions", "StaticArraysCore"] -git-tree-sha1 = "7a7be02e16d11c17e2407bab80c2dd1410f774cb" +deps = ["Accessors", "ArrayInterface", "RuntimeGeneratedFunctions", "StaticArraysCore"] +git-tree-sha1 = "b479c7a16803f08779ac5b7f9844a42621baeeda" uuid = "2efcf032-c050-4f8e-a9bb-153293bab1f5" -version = "0.3.17" +version = "0.3.21" [[deps.TOML]] deps = ["Dates"] diff --git a/Project.toml b/Project.toml index 3b2e47a5b..97269cbb7 100644 --- a/Project.toml +++ b/Project.toml @@ -17,8 +17,6 @@ DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" Dictionaries = "85a47980-9c8c-11e8-2b9f-f7ca1fa99fb4" DiffEqCallbacks = "459566f4-90b8-5000-8ac3-15dfb0a30def" -Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" -DocumenterMarkdown = "997ab1e6-3595-5248-9280-8efb232c3433" EnumX = "4e289a0a-7415-4d19-859d-a7e5c4648b56" FiniteDiff = "6a86dc24-6348-571c-b903-95158fe2bd41" ForwardDiff = "f6369f11-7733-5829-9624-2563aa707210" diff --git a/core/Project.toml b/core/Project.toml index 4d7b647a2..1a9fb12e3 100644 --- a/core/Project.toml +++ b/core/Project.toml @@ -56,7 +56,6 @@ DataStructures = "0.18" Dates = "<0.0.1,1" Dictionaries = "0.3.25, 0.4" DiffEqCallbacks = "3.6" -Documenter = "0.27,1" EnumX = "1.0" FiniteDiff = "2.21" ForwardDiff = "0.10" @@ -74,7 +73,7 @@ OrdinaryDiffEq = "6.7" PreallocationTools = "0.4" ReTestItems = "1.20" SQLite = "1.5.1" -SciMLBase = "1.60, 2" +SciMLBase = "2.36" SparseArrays = "<0.0.1,1" StructArrays = "0.6.13" TOML = "<0.0.1,1" @@ -89,7 +88,6 @@ julia = "1.10" Aqua = "4c88cf16-eb10-579e-8560-4a9242c79595" CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" -Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" IOCapture = "b5f81e59-6552-4d32-b1f0-c071b021bf89" Logging = "56ddb016-857b-54e1-b83d-db4d58db5568" ReTestItems = "817f1d60-ba6b-4fd5-9520-3cf149f6a823" @@ -111,4 +109,4 @@ PrecompileNonStiff = false PrecompileStiff = false [targets] -test = ["Aqua", "CSV", "DataFrames", "Documenter", "IOCapture", "Logging", "ReTestItems", "TerminalLoggers", "Test", "TOML"] +test = ["Aqua", "CSV", "DataFrames", "IOCapture", "Logging", "ReTestItems", "TerminalLoggers", "Test", "TOML"] diff --git a/core/src/Ribasim.jl b/core/src/Ribasim.jl index f8d027f63..a761c4b34 100644 --- a/core/src/Ribasim.jl +++ b/core/src/Ribasim.jl @@ -55,6 +55,7 @@ using SciMLBase: init, solve!, step!, + check_error!, SciMLBase, ReturnCode, successful_retcode, diff --git a/core/src/model.jl b/core/src/model.jl index 602503dd6..dec8c6480 100644 --- a/core/src/model.jl +++ b/core/src/model.jl @@ -229,12 +229,7 @@ function SciMLBase.solve!(model::Model)::Model update_allocation!(integrator) step!(integrator, timestep, true) end - - if integrator.sol.retcode != ReturnCode.Default - return model - end - # TODO replace with `check_error!` https://github.com/SciML/SciMLBase.jl/issues/669 - integrator.sol = SciMLBase.solution_new_retcode(integrator.sol, ReturnCode.Success) + check_error!(integrator) else solve!(integrator) end diff --git a/core/src/schema.jl b/core/src/schema.jl index 9ca14f9c6..1b6c8b42d 100644 --- a/core/src/schema.jl +++ b/core/src/schema.jl @@ -8,12 +8,17 @@ @schema "ribasim.basin.profile" BasinProfile @schema "ribasim.basin.state" BasinState @schema "ribasim.basin.subgrid" BasinSubgrid +@schema "ribasim.basin.concentration" BasinConcentration +@schema "ribasim.basin.concentrationexternal" BasinConcentrationExternal +@schema "ribasim.basin.concentrationstate" BasinConcentrationState @schema "ribasim.terminal.static" TerminalStatic @schema "ribasim.fractionalflow.static" FractionalFlowStatic @schema "ribasim.flowboundary.static" FlowBoundaryStatic @schema "ribasim.flowboundary.time" FlowBoundaryTime +@schema "ribasim.flowboundary.concentration" FlowBoundaryConcentration @schema "ribasim.levelboundary.static" LevelBoundaryStatic @schema "ribasim.levelboundary.time" LevelBoundaryTime +@schema "ribasim.levelboundary.concentration" LevelBoundaryConcentration @schema "ribasim.linearresistance.static" LinearResistanceStatic @schema "ribasim.manningresistance.static" ManningResistanceStatic @schema "ribasim.pidcontrol.static" PidControlStatic @@ -99,6 +104,21 @@ end urban_runoff::Union{Missing, Float64} end +@version BasinConcentrationV1 begin + node_id::Int32 + time::DateTime + substance::String + drainage::Union{Missing, Float64} + precipitation::Union{Missing, Float64} +end + +@version BasinConcentrationExternalV1 begin + node_id::Int32 + time::DateTime + substance::String + concentration::Union{Missing, Float64} +end + @version BasinProfileV1 begin node_id::Int32 area::Float64 @@ -110,6 +130,12 @@ end level::Float64 end +@version BasinConcentrationStateV1 begin + node_id::Int32 + substance::String + concentration::Union{Missing, Float64} +end + @version BasinSubgridV1 begin subgrid_id::Int32 node_id::Int32 @@ -135,6 +161,13 @@ end level::Float64 end +@version LevelBoundaryConcentrationV1 begin + node_id::Int32 + time::DateTime + substance::String + concentration::Float64 +end + @version FlowBoundaryStaticV1 begin node_id::Int32 active::Union{Missing, Bool} @@ -147,6 +180,13 @@ end flow_rate::Float64 end +@version FlowBoundaryConcentrationV1 begin + node_id::Int32 + time::DateTime + substance::String + concentration::Float64 +end + @version LinearResistanceStaticV1 begin node_id::Int32 active::Union{Missing, Bool} diff --git a/core/test/docs_test.jl b/core/test/docs_test.jl deleted file mode 100644 index 1f2e78f8c..000000000 --- a/core/test/docs_test.jl +++ /dev/null @@ -1,7 +0,0 @@ -@testitem "Doctests" begin - using Documenter - - DocMeta.setdocmeta!(Ribasim, :DocTestSetup, :(using Ribasim); recursive = true) - - doctest(Ribasim; manual = false) -end diff --git a/docs/.gitignore b/docs/.gitignore index 0c28493e0..c8f1e55fb 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -4,5 +4,4 @@ python/reference/ python/data/ *.html -/Manifest.toml objects.json diff --git a/docs/_quarto.yml b/docs/_quarto.yml index e3cd0e3e5..b360503d7 100644 --- a/docs/_quarto.yml +++ b/docs/_quarto.yml @@ -32,7 +32,6 @@ website: - core/equations.qmd - core/allocation.qmd - core/numerics.qmd - - build/index.md - title: "Python tooling" contents: - python/index.qmd diff --git a/docs/contribute/core.qmd b/docs/contribute/core.qmd index ef4e52fc3..35485aff0 100644 --- a/docs/contribute/core.qmd +++ b/docs/contribute/core.qmd @@ -75,11 +75,6 @@ The first run will be slow. ## Render documentation Example models are created and simulated as part of the rendering of the documentation. -The Julia API reference is created using Documenter.jl by running this command: - -```bash -pixi run build-julia-docs -``` In order to preview documentation you can run the following command from the `docs/` folder. Afterwards, a browser tab will open with the rendered documentation, updating it as you diff --git a/docs/make.jl b/docs/make.jl deleted file mode 100644 index 07942b191..000000000 --- a/docs/make.jl +++ /dev/null @@ -1,17 +0,0 @@ -cd(@__DIR__) - -using Documenter, Ribasim -using DocumenterMarkdown - -DocMeta.setdocmeta!(Ribasim, :DocTestSetup, :(using Ribasim); recursive = true) - -makedocs(; - modules = [Ribasim, Ribasim.config], - format = Markdown(), - repo = "https://github.com/Deltares/Ribasim.jl/blob/{commit}{path}#L{line}", - sitename = "Ribasim.jl", - authors = "Deltares and contributors", - doctest = false, # we doctest as part of normal CI -) - -# TODO Make fully compatible with Quarto, like LaTeX and references diff --git a/docs/src/index.md b/docs/src/index.md deleted file mode 100644 index dc071f5c4..000000000 --- a/docs/src/index.md +++ /dev/null @@ -1,45 +0,0 @@ -# API Reference -*This is the private internal documentation of the Ribasim API.* - -```@contents -``` - -## Modules - -```@autodocs -Modules = [Ribasim, Ribasim.config] -Order = [:module] -``` - -## Types - -```@autodocs -Modules = [Ribasim, Ribasim.config] -Order = [:type] -``` - -## Functions - -```@autodocs -Modules = [Ribasim, Ribasim.config] -Order = [:function] -``` - -## Constants - -```@autodocs -Modules = [Ribasim, Ribasim.config] -Order = [:constant] -``` - -## Macros - -```@autodocs -Modules = [Ribasim, Ribasim.config] -Order = [:macro] -``` - -## Index - -```@index -``` diff --git a/python/ribasim/ribasim/config.py b/python/ribasim/ribasim/config.py index d36416862..9572db9c2 100644 --- a/python/ribasim/ribasim/config.py +++ b/python/ribasim/ribasim/config.py @@ -16,6 +16,9 @@ # These schemas are autogenerated from ribasim.schemas import ( + BasinConcentrationExternalSchema, + BasinConcentrationSchema, + BasinConcentrationStateSchema, BasinProfileSchema, BasinStateSchema, BasinStaticSchema, @@ -24,11 +27,13 @@ DiscreteControlConditionSchema, DiscreteControlLogicSchema, DiscreteControlVariableSchema, + FlowBoundaryConcentrationSchema, FlowBoundaryStaticSchema, FlowBoundaryTimeSchema, FlowDemandStaticSchema, FlowDemandTimeSchema, FractionalFlowStaticSchema, + LevelBoundaryConcentrationSchema, LevelBoundaryStaticSchema, LevelBoundaryTimeSchema, LevelDemandStaticSchema, @@ -189,6 +194,10 @@ class LevelBoundary(MultiNodeModel): default_factory=TableModel[LevelBoundaryTimeSchema], json_schema_extra={"sort_keys": ["node_id", "time"]}, ) + concentration: TableModel[LevelBoundaryConcentrationSchema] = Field( + default_factory=TableModel[LevelBoundaryConcentrationSchema], + json_schema_extra={"sort_keys": ["node_id", "substance", "time"]}, + ) class Pump(MultiNodeModel): @@ -240,6 +249,10 @@ class FlowBoundary(MultiNodeModel): default_factory=TableModel[FlowBoundaryTimeSchema], json_schema_extra={"sort_keys": ["node_id", "time"]}, ) + concentration: TableModel[FlowBoundaryConcentrationSchema] = Field( + default_factory=TableModel[FlowBoundaryConcentrationSchema], + json_schema_extra={"sort_keys": ["node_id", "substance", "time"]}, + ) class FlowDemand(MultiNodeModel): @@ -278,6 +291,18 @@ class Basin(MultiNodeModel): default_factory=SpatialTableModel[BasinAreaSchema], json_schema_extra={"sort_keys": ["node_id"]}, ) + concentration: TableModel[BasinConcentrationSchema] = Field( + default_factory=TableModel[BasinConcentrationSchema], + json_schema_extra={"sort_keys": ["node_id", "substance", "time"]}, + ) + concentration_external: TableModel[BasinConcentrationExternalSchema] = Field( + default_factory=TableModel[BasinConcentrationExternalSchema], + json_schema_extra={"sort_keys": ["node_id", "substance", "time"]}, + ) + concentration_state: TableModel[BasinConcentrationStateSchema] = Field( + default_factory=TableModel[BasinConcentrationStateSchema], + json_schema_extra={"sort_keys": ["node_id", "substance"]}, + ) class ManningResistance(MultiNodeModel): diff --git a/python/ribasim/ribasim/nodes/basin.py b/python/ribasim/ribasim/nodes/basin.py index 0e529cdc1..f155f848b 100644 --- a/python/ribasim/ribasim/nodes/basin.py +++ b/python/ribasim/ribasim/nodes/basin.py @@ -4,6 +4,9 @@ from ribasim.geometry.area import BasinAreaSchema from ribasim.input_base import TableModel from ribasim.schemas import ( + BasinConcentrationExternalSchema, + BasinConcentrationSchema, + BasinConcentrationStateSchema, BasinProfileSchema, BasinStateSchema, BasinStaticSchema, @@ -11,7 +14,15 @@ BasinTimeSchema, ) -__all__ = ["Static", "Time", "State", "Profile", "Subgrid", "Area"] +__all__ = [ + "Static", + "Time", + "State", + "Profile", + "Subgrid", + "Area", + "Concentration", +] class Static(TableModel[BasinStaticSchema]): @@ -42,3 +53,18 @@ def __init__(self, **kwargs): class Area(TableModel[BasinAreaSchema]): def __init__(self, **kwargs): super().__init__(df=GeoDataFrame(dict(**kwargs))) + + +class Concentration(TableModel[BasinConcentrationSchema]): + def __init__(self, **kwargs): + super().__init__(df=GeoDataFrame(dict(**kwargs))) + + +class ConcentrationExternal(TableModel[BasinConcentrationExternalSchema]): + def __init__(self, **kwargs): + super().__init__(df=GeoDataFrame(dict(**kwargs))) + + +class ConcentrationState(TableModel[BasinConcentrationStateSchema]): + def __init__(self, **kwargs): + super().__init__(df=GeoDataFrame(dict(**kwargs))) diff --git a/python/ribasim/ribasim/nodes/flow_boundary.py b/python/ribasim/ribasim/nodes/flow_boundary.py index 12ec8c028..096652f6f 100644 --- a/python/ribasim/ribasim/nodes/flow_boundary.py +++ b/python/ribasim/ribasim/nodes/flow_boundary.py @@ -2,11 +2,12 @@ from ribasim.input_base import TableModel from ribasim.schemas import ( + FlowBoundaryConcentrationSchema, FlowBoundaryStaticSchema, FlowBoundaryTimeSchema, ) -__all__ = ["Static", "Time"] +__all__ = ["Static", "Time", "Concentration"] class Static(TableModel[FlowBoundaryStaticSchema]): @@ -17,3 +18,8 @@ def __init__(self, **kwargs): class Time(TableModel[FlowBoundaryTimeSchema]): def __init__(self, **kwargs): super().__init__(df=DataFrame(dict(**kwargs))) + + +class Concentration(TableModel[FlowBoundaryConcentrationSchema]): + def __init__(self, **kwargs): + super().__init__(df=DataFrame(dict(**kwargs))) diff --git a/python/ribasim/ribasim/nodes/level_boundary.py b/python/ribasim/ribasim/nodes/level_boundary.py index da23c3c61..1fb9d5d81 100644 --- a/python/ribasim/ribasim/nodes/level_boundary.py +++ b/python/ribasim/ribasim/nodes/level_boundary.py @@ -2,11 +2,12 @@ from ribasim.input_base import TableModel from ribasim.schemas import ( + LevelBoundaryConcentrationSchema, LevelBoundaryStaticSchema, LevelBoundaryTimeSchema, ) -__all__ = ["Static", "Time"] +__all__ = ["Static", "Time", "Concentration"] class Static(TableModel[LevelBoundaryStaticSchema]): @@ -17,3 +18,8 @@ def __init__(self, **kwargs): class Time(TableModel[LevelBoundaryTimeSchema]): def __init__(self, **kwargs): super().__init__(df=DataFrame(dict(**kwargs))) + + +class Concentration(TableModel[LevelBoundaryConcentrationSchema]): + def __init__(self, **kwargs): + super().__init__(df=DataFrame(dict(**kwargs))) diff --git a/python/ribasim/ribasim/schemas.py b/python/ribasim/ribasim/schemas.py index 40f0e0a38..3686b2398 100644 --- a/python/ribasim/ribasim/schemas.py +++ b/python/ribasim/ribasim/schemas.py @@ -11,6 +11,27 @@ class Config: coerce = True +class BasinConcentrationExternalSchema(_BaseSchema): + node_id: Series[Int32] = pa.Field(nullable=False, default=0) + time: Series[Timestamp] = pa.Field(nullable=False) + substance: Series[str] = pa.Field(nullable=False) + concentration: Series[float] = pa.Field(nullable=True) + + +class BasinConcentrationStateSchema(_BaseSchema): + node_id: Series[Int32] = pa.Field(nullable=False, default=0) + substance: Series[str] = pa.Field(nullable=False) + concentration: Series[float] = pa.Field(nullable=True) + + +class BasinConcentrationSchema(_BaseSchema): + node_id: Series[Int32] = pa.Field(nullable=False, default=0) + time: Series[Timestamp] = pa.Field(nullable=False) + substance: Series[str] = pa.Field(nullable=False) + drainage: Series[float] = pa.Field(nullable=True) + precipitation: Series[float] = pa.Field(nullable=True) + + class BasinProfileSchema(_BaseSchema): node_id: Series[Int32] = pa.Field(nullable=False, default=0) area: Series[float] = pa.Field(nullable=False) @@ -70,6 +91,13 @@ class DiscreteControlVariableSchema(_BaseSchema): look_ahead: Series[float] = pa.Field(nullable=True) +class FlowBoundaryConcentrationSchema(_BaseSchema): + node_id: Series[Int32] = pa.Field(nullable=False, default=0) + time: Series[Timestamp] = pa.Field(nullable=False) + substance: Series[str] = pa.Field(nullable=False) + concentration: Series[float] = pa.Field(nullable=False) + + class FlowBoundaryStaticSchema(_BaseSchema): node_id: Series[Int32] = pa.Field(nullable=False, default=0) active: Series[pa.BOOL] = pa.Field(nullable=True) @@ -101,6 +129,13 @@ class FractionalFlowStaticSchema(_BaseSchema): control_state: Series[str] = pa.Field(nullable=True) +class LevelBoundaryConcentrationSchema(_BaseSchema): + node_id: Series[Int32] = pa.Field(nullable=False, default=0) + time: Series[Timestamp] = pa.Field(nullable=False) + substance: Series[str] = pa.Field(nullable=False) + concentration: Series[float] = pa.Field(nullable=False) + + class LevelBoundaryStaticSchema(_BaseSchema): node_id: Series[Int32] = pa.Field(nullable=False, default=0) active: Series[pa.BOOL] = pa.Field(nullable=True) diff --git a/python/ribasim_testmodels/ribasim_testmodels/basic.py b/python/ribasim_testmodels/ribasim_testmodels/basic.py index 3fe92ebf8..48f857199 100644 --- a/python/ribasim_testmodels/ribasim_testmodels/basic.py +++ b/python/ribasim_testmodels/ribasim_testmodels/basic.py @@ -1,3 +1,4 @@ +from collections.abc import Sequence from pathlib import Path from typing import Any @@ -37,6 +38,16 @@ def basic_model() -> ribasim.Model: potential_evaporation=[0.001 / 86400], precipitation=[0.002 / 86400] ), basin.State(level=[0.04471158417652035]), + basin.Concentration( + time="2020-01-01 00:00:00", + substance=["Cl"], + drainage=[0.0], + precipitation=[0.0], + ), + basin.ConcentrationState(substance=["Cl"], concentration=[0.0]), + basin.ConcentrationExternal( + time="2020-01-01 00:00:00", substance=["Cl"], concentration=[0.0] + ), ] node_ids = [1, 3, 6, 9] node_geometries = [ @@ -107,16 +118,33 @@ def basic_model() -> ribasim.Model: model.pump.add(Node(7, Point(4.0, 1.0)), [pump.Static(flow_rate=[0.5 / 3600])]) # Setup flow boundary - flow_boundary_data = [flow_boundary.Static(flow_rate=[1e-4])] + flow_boundary_data: Sequence[TableModel[Any]] = [ + flow_boundary.Static(flow_rate=[1e-4]), + flow_boundary.Concentration( + time="2020-01-01 00:00:00", substance=["Tracer"], concentration=[1.0] + ), + ] model.flow_boundary.add(Node(15, Point(3.0, 3.0)), flow_boundary_data) model.flow_boundary.add(Node(16, Point(0.0, 1.0)), flow_boundary_data) # Setup level boundary model.level_boundary.add( - Node(11, Point(2.0, 2.0)), [level_boundary.Static(level=[1.0])] + Node(11, Point(2.0, 2.0)), + [ + level_boundary.Static(level=[1.0]), + level_boundary.Concentration( + time="2020-01-01 00:00:00", substance=["Cl"], concentration=[34.0] + ), + ], ) model.level_boundary.add( - Node(17, Point(6.0, 1.0)), [level_boundary.Static(level=[1.5])] + Node(17, Point(6.0, 1.0)), + [ + level_boundary.Static(level=[1.5]), + level_boundary.Concentration( + time="2020-01-01 00:00:00", substance=["Cl"], concentration=[34.0] + ), + ], ) # Setup terminal @@ -340,9 +368,9 @@ def outlet_model(): [ level_boundary.Time( time=[ - "2020-01-01", - "2020-06-01", - "2021-01-01", + "2020-01-01 00:00:00", + "2020-06-01 00:00:00", + "2021-01-01 00:00:00", ], level=[1.0, 3.0, 3.0], ) diff --git a/ribasim_qgis/metadata.txt b/ribasim_qgis/metadata.txt index 1478f2aad..9363b34f2 100644 --- a/ribasim_qgis/metadata.txt +++ b/ribasim_qgis/metadata.txt @@ -4,7 +4,7 @@ # This file should be included when you package your plugin.# Mandatory items: [general] -name=Ribasim-QGIS +name=Ribasim qgisMinimumVersion=3.0 description=QGIS plugin to setup Ribasim models version=2024.7.0