Skip to content

Commit 1328896

Browse files
authored
Improve default processes: allow registration per module (#8)
* allow DESystems in processes_to_mtkmodel * allow Differential and differential*p in LHS of equations as processes * add changelog entry * add warning comment * fix type of vector expansion container * show that differential can be used in the docs * add new info to docs * add default function * correct version parse * add optinal code for default loading * finish docstring of default * ensure default dict is stored * better code for deafult * changelog * tests * bump version * fix the tests
1 parent f41091a commit 1328896

File tree

6 files changed

+82
-16
lines changed

6 files changed

+82
-16
lines changed

CHANGELOG.md

+8
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,14 @@
33
ProcessBasedModelling.jl follows semver 2.0.
44
Changelog is kept with respect to v1 release.
55

6+
## 1.2
7+
8+
The API for default processes has been drastically improved.
9+
Now, each `Module` can track its own default processes via the new function
10+
`register_default_process!`. This allows creating submodules dedicated to
11+
physical "subsystems" which need to track their own list of variables,
12+
parameters, and default processes.
13+
614
## 1.1
715

816
- New keyword `warn_default` in `processes_to_mtkmodel`.

Project.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
name = "ProcessBasedModelling"
22
uuid = "ca969041-2cf3-4b10-bc21-86f4417093eb"
33
authors = ["Datseris <[email protected]>"]
4-
version = "1.1.0"
4+
version = "1.2.0"
55

66
[deps]
77
ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78"

src/ProcessBasedModelling.jl

+1-5
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,13 @@ end ProcessBasedModelling
1010
using Reexport
1111
using ModelingToolkit: t_nounits as t, D_nounits as D
1212
@reexport using ModelingToolkit
13-
export t
1413

1514
include("API.jl")
1615
include("utils.jl")
16+
include("default.jl")
1717
include("make.jl")
1818
include("processes_basic.jl")
1919

20-
# TODO: Make an "addition process" that adds to processes
21-
# It checks whether they target the same variable
22-
23-
# TODO: Perhaps not don't export `t`?
2420
export t
2521
export Process, ParameterProcess, TimeDerivative, ExpRelaxation, AdditionProcess
2622
export processes_to_mtkmodel

src/default.jl

+34
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
export register_default_process!, default_processes
2+
3+
const _DEFAULT_PROCESSES = Dict{Module, Dict}()
4+
5+
"""
6+
register_default_process!(process, m::Module; warn = true)
7+
8+
Register a `process` (`Equation` or `Process`) as a default process for its LHS variable
9+
in the list of default processes tracked by the given module.
10+
If `warn`, throw a warning if a default process with same LHS variable already
11+
exists and will be overwritten.
12+
"""
13+
function register_default_process!(process::Union{Process, Equation}, m::Module; warn = true)
14+
mdict = default_processes(m)
15+
lhsvar = lhs_variable(process)
16+
# overwritting here should never happen but oh well.
17+
if haskey(mdict, lhsvar) && warn
18+
@warn("Overwritting default process for variable $(lhsvar)")
19+
end
20+
mdict[lhsvar] = process
21+
return nothing
22+
end
23+
24+
"""
25+
default_processes(m::Module)
26+
27+
Return the dictionary of default processes tracked by the given module.
28+
"""
29+
function default_processes(m::Module)
30+
if !haskey(_DEFAULT_PROCESSES, m)
31+
_DEFAULT_PROCESSES[m] = Dict{Num}{Any}()
32+
end
33+
return _DEFAULT_PROCESSES[m]
34+
end

src/make.jl

+18-9
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
"""
2-
processes_to_mtkmodel(processes::Vector, default::Vector = []; kw...)
2+
processes_to_mtkmodel(processes::Vector [, default]; kw...)
33
44
Construct a ModelingToolkit.jl model/system using the provided `processes` and `default` processes.
55
The model/system is _not_ structurally simplified.
@@ -19,13 +19,16 @@ The model/system is _not_ structurally simplified.
1919
as if they were given as a vector of equations like above. This allows the convenience
2020
of straightforwardly coupling already existing systems.
2121
22-
`default` is a vector that can contain the first two possibilities only
23-
as it contains default processes that may be assigned to individual variables introduced in
24-
`processes` but they don't themselves have an assigned process.
22+
## Default processes
2523
26-
It is expected that downstream packages that use ProcessBasedModelling.jl to make a
27-
field-specific library implement a 1-argument version of `processes_to_mtkmodel`,
28-
or provide a wrapper function for it, and add a default value for `default`.
24+
`processes_to_mtkmodel` allows for specifying default processes by giving `default`.
25+
These default processes are assigned to variables introduced in the main input `processes`
26+
without themselves having an assigned process in the main input.
27+
28+
`default` can be a `Vector` of individual processes (`Equation` or `Process`).
29+
Alternatively, `default` can be a `Module`. ProcessBasedModelling.jl allows modules to
30+
register their own default processes via the function [`register_default_process!`](@ref).
31+
These registered processes are used when `default` is a `Module`.
2932
3033
## Keyword arguments
3134
@@ -36,11 +39,17 @@ or provide a wrapper function for it, and add a default value for `default`.
3639
- `warn_default::Bool = true`: if `true`, throw a warning when a variable does not
3740
have an assigned process but it has a default value so that it becomes a parameter instead.
3841
"""
39-
function processes_to_mtkmodel(_processes::Vector, _default = [];
42+
processes_to_mtkmodel(procs::Vector; kw...) =
43+
processes_to_mtkmodel(procs, Dict{Num, Any}(); kw...)
44+
processes_to_mtkmodel(procs::Vector, m::Module; kw...) =
45+
processes_to_mtkmodel(procs, default_processes(m); kw...)
46+
processes_to_mtkmodel(procs::Vector, v::Vector; kw...) =
47+
processes_to_mtkmodel(procs, default_dict(v); kw...)
48+
49+
function processes_to_mtkmodel(_processes::Vector, default::Dict{Num, Any};
4050
type = ODESystem, name = nameof(type), independent = t, warn_default::Bool = true,
4151
)
4252
processes = expand_multi_processes(_processes)
43-
default = default_dict(_default)
4453
# Setup: obtain lhs-variables so we can track new variables that are not
4554
# in this vector. The vector has to be of type `Num`
4655
lhs_vars = Num[lhs_variable(p) for p in processes]

test/runtests.jl

+20-1
Original file line numberDiff line numberDiff line change
@@ -208,4 +208,23 @@ end
208208
sys2 = processes_to_mtkmodel([sys, w ~ x*y])
209209
@test length(equations(sys2)) == 4
210210
@test sort(ModelingToolkit.getname.(unknowns(sys2))) == [:w, :x, :y, :z]
211-
end
211+
end
212+
213+
module TestDefault
214+
using ProcessBasedModelling
215+
@variables x(t) = 0.5 y(t) = 0.2
216+
register_default_process!.([
217+
Differential(t)(x) ~ 0.2y - x,
218+
y ~ x^2,
219+
], Ref(TestDefault))
220+
end
221+
222+
@testset "registering default" begin
223+
using .TestDefault
224+
@variables z(t) = 0.1
225+
eqs = [z ~ TestDefault.x - 1]
226+
mtk = processes_to_mtkmodel(eqs, TestDefault)
227+
@test length(unknowns(mtk)) == 3
228+
@test has_symbolic_var(mtk, z)
229+
@test has_symbolic_var(mtk, TestDefault.x)
230+
end

0 commit comments

Comments
 (0)