diff --git a/CHANGELOG.md b/CHANGELOG.md index ebe74bb..0e5e2f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,11 @@ ProcessBasedModelling.jl follows semver 2.0. Changelog is kept with respect to v1 release. +## 1.3 + +- Better error messages for duplicate processes given to `process_to_mtkmodel`. +- New exported function `equation(p::Process)` that returns `lhs(p) ~ rhs(p)`. + ## 1.2 The API for default processes has been drastically improved. diff --git a/Project.toml b/Project.toml index 7a1ed32..702ca90 100644 --- a/Project.toml +++ b/Project.toml @@ -1,7 +1,7 @@ name = "ProcessBasedModelling" uuid = "ca969041-2cf3-4b10-bc21-86f4417093eb" authors = ["Datseris "] -version = "1.2.4" +version = "1.3.0" [deps] ModelingToolkit = "961ee093-0014-501f-94e3-6117800e7a78" diff --git a/src/API.jl b/src/API.jl index bf626d8..d086fcc 100644 --- a/src/API.jl +++ b/src/API.jl @@ -110,3 +110,10 @@ function lhs_variable(x) # basically x is SymbolicUtils.BasicSymbolic{Real} throw(ArgumentError("We analyzed the LHS `$(x)` "* "but could not extract a single variable it represents.")) end + +""" + equation(process) + +Return the `Equation` represented by the given process. +""" +equation(proc) = lhs(proc) ~ rhs(proc) \ No newline at end of file diff --git a/src/ProcessBasedModelling.jl b/src/ProcessBasedModelling.jl index a71b990..1c46e16 100644 --- a/src/ProcessBasedModelling.jl +++ b/src/ProcessBasedModelling.jl @@ -23,7 +23,6 @@ export processes_to_mtkmodel export new_derived_named_parameter export has_symbolic_var, default_value export @convert_to_parameters, LiteralParameter -# export lhs_variable, rhs, lhs # I am not sure whether these should be exported. -export all_equations +export all_equations, equation end diff --git a/src/make.jl b/src/make.jl index 597692b..0275452 100644 --- a/src/make.jl +++ b/src/make.jl @@ -67,7 +67,7 @@ function processes_to_mtkmodel(_processes::Vector, default::Dict{Num, Any}; # Setup: obtain lhs-variables so we can track new variables that are not # in this vector. The vector has to be of type `Num` lhs_vars = Num[lhs_variable(p) for p in processes] - ensure_unique_vars(lhs_vars) + ensure_unique_vars(lhs_vars, processes) # First pass: generate equations from given processes # and collect variables without equations incomplete = Num[] @@ -76,7 +76,7 @@ function processes_to_mtkmodel(_processes::Vector, default::Dict{Num, Any}; for proc in processes append_incomplete_variables!(incomplete, introduced, lhs_vars, proc) # add the generated equation in the pool of equations - push!(eqs, lhs(proc) ~ rhs(proc)) + push!(eqs, equation(proc)) end # Second pass: attempt to add default processes to incomplete variables # throw an error if default does not exist @@ -169,9 +169,22 @@ function append_incomplete_variables!(incomplete, introduced, lhs_vars, process) return end -function ensure_unique_vars(lhs_vars) +function ensure_unique_vars(lhs_vars, processes) nonun = nonunique(lhs_vars) - isempty(nonun) || error("The following variables have more than one processes assigned to them: $(nonun)") + isempty(nonun) && return # all good! + dupprocs = [] + for var in nonun + idxs = findall(p -> Symbol(lhs_variable(p)) == Symbol(var), processes) + append!(dupprocs, processes[idxs]) + end + errormsg = """ + The following variables have more than one processes assigned to them: $(nonun). + The duplicate processes are: + """ + for p in dupprocs + errormsg *= "\n"*sprint(show, p) + end + throw(ArgumentError(errormsg)) return end diff --git a/test/runtests.jl b/test/runtests.jl index 7556611..bfef75e 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -160,6 +160,11 @@ end @test p == 0.5 end + @testset "equation" begin + @variables x(t) + @test equation(ParameterProcess(x, LiteralParameter(0.5))) == (x ~ 0.5) + end + end @testset "default processes, has_thing" begin