From 0b837814823f76b4f0e2d1b83c3f7b6cf2ee1a08 Mon Sep 17 00:00:00 2001 From: Martijn Visser Date: Mon, 25 Sep 2023 11:00:56 +0200 Subject: [PATCH] Add more julia docstrings and convenience functions (#607) I started this off simply wanting to switch to Documenter.jl version 1.0 that recently got released. But what wasn't clear from #470 is that the [DocumenterMarkdown](https://github.com/JuliaDocs/DocumenterMarkdown.jl) backend we use is not actively maintained, meaning we are stuck for now on the old Documenter 0.27. In any case this addresses a few Documenter 0.27 warnings about missing docstrings. And when I started adding docstrings I figured the key functions really need some docstrings. I also added some more convenient methods, e.g. extending `solve!` from SciML on our Model, and adding `model = Ribasim.Model(config)` instead of only the more verbose BMI interface method `model = BMI.initialize(Ribasim.Model, config)`. --- core/src/Ribasim.jl | 14 ++++++++++++++ core/src/bmi.jl | 26 ++++++++++++++++++++++++-- core/src/config.jl | 27 +++++++++++++++++++++++++-- core/src/lib.jl | 34 +++++++++++++++++++++++++--------- core/test/bmi.jl | 3 +-- docs/make.jl | 2 +- docs/src/index.md | 25 +++++++++++++++++++++++-- 7 files changed, 113 insertions(+), 18 deletions(-) diff --git a/core/src/Ribasim.jl b/core/src/Ribasim.jl index 8821ef2c8..1acfde3f4 100644 --- a/core/src/Ribasim.jl +++ b/core/src/Ribasim.jl @@ -1,3 +1,17 @@ +""" + module Ribasim + +Ribasim is a water resources model. +The computational core is implemented in Julia in the Ribasim package. +It is currently mainly designed to be used as an application. +To run a simulation from Julia, use [`Ribasim.run`](@ref). + +For more granular access, see: +- [`Config`](@ref) +- [`Model`](@ref) +- [`solve!`](@ref) +- [`BMI.finalize`](@ref) +""" module Ribasim import IterTools diff --git a/core/src/bmi.jl b/core/src/bmi.jl index 2667ec9b5..fdfda2ef5 100644 --- a/core/src/bmi.jl +++ b/core/src/bmi.jl @@ -1,8 +1,18 @@ +""" + BMI.initialize(T::Type{Model}, config_path::AbstractString)::Model + +Initialize a [`Model`](@ref) from the path to the TOML configuration file. +""" function BMI.initialize(T::Type{Model}, config_path::AbstractString)::Model config = Config(config_path) BMI.initialize(T, config) end +""" + BMI.initialize(T::Type{Model}, config::Config)::Model + +Initialize a [`Model`](@ref) from a [`Config`](@ref). +""" function BMI.initialize(T::Type{Model}, config::Config)::Model alg = algorithm(config.solver) gpkg_path = input_path(config, config.geopackage) @@ -134,6 +144,11 @@ function BMI.initialize(T::Type{Model}, config::Config)::Model return Model(integrator, config, saved_flow) end +""" + BMI.finalize(model::Model)::Model + +Write all output to the configured output files. +""" function BMI.finalize(model::Model)::Model compress = get_compressor(model.config.output) write_basin_output(model, compress) @@ -528,6 +543,13 @@ BMI.get_end_time(model::Model) = seconds_since(model.config.endtime, model.confi BMI.get_time_units(model::Model) = "s" BMI.get_time_step(model::Model) = get_proposed_dt(model.integrator) +""" + run(config_file::AbstractString)::Model + run(config::Config)::Model + +Run a [`Model`](@ref), given a path to a TOML configuration file, or a Config object. +Running a model includes initialization, solving to the end with `[`solve!`](@ref)` and writing output with [`BMI.finalize`](@ref). +""" run(config_file::AbstractString)::Model = run(Config(config_file)) function is_current_module(log) @@ -549,8 +571,8 @@ function run(config::Config)::Model end with_logger(logger) do - model = BMI.initialize(Model, config) - solve!(model.integrator) + model = Model(config) + solve!(model) BMI.finalize(model) return model end diff --git a/core/src/config.jl b/core/src/config.jl index 1a8aa8e8b..a677a33b9 100644 --- a/core/src/config.jl +++ b/core/src/config.jl @@ -1,9 +1,16 @@ +""" + module config + +Ribasim.config is a submodule of [`Ribasim`](@ref) to handle the configuration of a Ribasim model. +It is implemented using the [Configurations](https://configurations.rogerluo.dev/stable/) package. +A full configuration is represented by [`Config`](@ref), which is the main API. +Ribasim.config is a submodule mainly to avoid name clashes between the configuration sections and the rest of Ribasim. +""" module config using Configurations: Configurations, Maybe, @option, from_toml, @type_alias using DataStructures: DefaultDict using Dates -using Legolas: Legolas, record_type using Logging: LogLevel, Debug, Info, Warn, Error using ..Ribasim: Ribasim, isnode, nodetype using OrdinaryDiffEq @@ -169,7 +176,23 @@ function Base.show(io::IO, c::TableOption) end end -"Map from config string to supported algorithm type" +""" + const algorithms::Dict{String, Type} + +Map from config string to a supported algorithm type from [OrdinaryDiffEq](https://docs.sciml.ai/DiffEqDocs/stable/solvers/ode_solve/). + +Supported algorithms: + +- `QNDF` +- `Rosenbrock23` +- `TRBDF2` +- `Rodas5` +- `KenCarp4` +- `Tsit5` +- `RK4` +- `ImplicitEuler` +- `Euler` +""" const algorithms = Dict{String, Type}( "QNDF" => QNDF, "Rosenbrock23" => Rosenbrock23, diff --git a/core/src/lib.jl b/core/src/lib.jl index 1ef2be0a9..b18804bfb 100644 --- a/core/src/lib.jl +++ b/core/src/lib.jl @@ -1,13 +1,12 @@ """ - Model( - sys::MTK.AbstractODESystem, - config::Config, - saved_flow::SavedValues(Float64, Vector{Float64}), - integrator::SciMLBase.AbstractODEIntegrator - ) - -Struct that combines data from the System and Integrator that we will need during and after -model construction. + Model(config_path::AbstractString) + Model(config::Config) + +Initialize a Model. + +The Model struct is an initialized model, combined with the [`Config`](@ref) used to create it and saved outputs. +The Basic Model Interface ([BMI](https://github.com/Deltares/BasicModelInterface.jl)) is implemented on the Model. +A Model can be created from the path to a TOML configuration file, or a Config object. """ struct Model{T} integrator::T @@ -22,6 +21,14 @@ struct Model{T} end end +function Model(config_path::AbstractString)::Model + return BMI.initialize(Model, config_path::AbstractString) +end + +function Model(config::Config)::Model + return BMI.initialize(Model, config::Config) +end + timesteps(model::Model) = model.integrator.sol.t function Base.show(io::IO, model::Model) @@ -34,3 +41,12 @@ end function SciMLBase.successful_retcode(model::Model)::Bool return SciMLBase.successful_retcode(model.integrator.sol) end + +""" + solve!(model::Model)::ODESolution + +Solve a Model until the configured `endtime`. +""" +function SciMLBase.solve!(model::Model)::ODESolution + return solve!(model.integrator) +end diff --git a/core/test/bmi.jl b/core/test/bmi.jl index 7f5508ccf..f56f384b4 100644 --- a/core/test/bmi.jl +++ b/core/test/bmi.jl @@ -1,5 +1,4 @@ using Test -using Configurations: from_toml using Ribasim import BasicModelInterface as BMI @@ -31,7 +30,7 @@ end ) @test config.solver.algorithm == "ImplicitEuler" @test !config.solver.adaptive - model = BMI.initialize(Ribasim.Model, config) + model = Ribasim.Model(config) @test BMI.get_time_step(model) == dt BMI.update(model) diff --git a/docs/make.jl b/docs/make.jl index 20420a403..0fa0fed5e 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -6,7 +6,7 @@ using DocumenterMarkdown DocMeta.setdocmeta!(Ribasim, :DocTestSetup, :(using Ribasim); recursive = true) makedocs(; - modules = [Ribasim], + modules = [Ribasim, Ribasim.config], format = Markdown(), repo = "https://github.com/Deltares/Ribasim.jl/blob/{commit}{path}#L{line}", sitename = "Ribasim.jl", diff --git a/docs/src/index.md b/docs/src/index.md index 2c05208d6..dc071f5c4 100644 --- a/docs/src/index.md +++ b/docs/src/index.md @@ -4,11 +4,11 @@ ```@contents ``` -## Functions +## Modules ```@autodocs Modules = [Ribasim, Ribasim.config] -Order = [:function] +Order = [:module] ``` ## Types @@ -18,6 +18,27 @@ 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