Skip to content

Commit

Permalink
Merge pull request #280 from TorkelE/master
Browse files Browse the repository at this point in the history
Fix ModelingTookit extension
  • Loading branch information
pogudingleb authored Feb 1, 2024
2 parents 3cfc392 + 18d3647 commit 15e2a28
Show file tree
Hide file tree
Showing 8 changed files with 61 additions and 14 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ jobs:
matrix:
group:
- Core
- ModelingToolkitExt
- ModelingToolkitSIExt
version:
- '1'
- '1.6'
Expand Down
2 changes: 1 addition & 1 deletion Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"

[extensions]
ModelingToolkitExt = ["ModelingToolkit", "SymbolicUtils", "Symbolics"]
ModelingToolkitSIExt = ["ModelingToolkit", "SymbolicUtils", "Symbolics"]

[compat]
AbstractAlgebra = "0.34.5, 0.35"
Expand Down
2 changes: 1 addition & 1 deletion docs/src/tutorials/creating_ode.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ assess_identifiability(ode)

## Defining using `ModelingToolkit`

`StructuralIdentifiability` has an extension `ModelingToolkitExt` which allows to use `ODESystem` from `ModelingToolkit` to describe
`StructuralIdentifiability` has an extension `ModelingToolkitSIExt` which allows to use `ODESystem` from `ModelingToolkit` to describe
a model. The extension is loaded automatically once `ModelingToolkit` is loaded via `using ModelingToolkit`.
In this case, one should encode the equations for the states as `ODESystem` and specify the outputs separately.
In order to do this, we first introduce all functions and scalars:
Expand Down
2 changes: 1 addition & 1 deletion docs/src/tutorials/discrete_time.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ assess_local_identifiability(dds; funcs_to_check = [β * S])
As other main functions in the package, `assess_local_identifiability` accepts an optional parameter `loglevel` (default: `Logging.Info`)
to adjust the verbosity of logging.

If one loads `ModelingToolkit` (and thus the `ModelingToolkitExt` extension), one can use `DiscreteSystem` from `ModelingToolkit` to
If one loads `ModelingToolkit` (and thus the `ModelingToolkitSIExt` extension), one can use `DiscreteSystem` from `ModelingToolkit` to
describe the input model (now in terms of difference!):

```@example discrete_mtk
Expand Down
11 changes: 4 additions & 7 deletions ext/ModelingToolkitExt.jl → ext/ModelingToolkitSIExt.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
module ModelingToolkitExt
module ModelingToolkitSIExt

using DataStructures
using Logging
Expand All @@ -15,9 +15,6 @@ else
using ..ModelingToolkit
end

export mtk_to_si
export assess_local_identifiability, assess_identifiability, find_identifiable_functions

# ------------------------------------------------------------------------------

function eval_at_nemo(e::Num, vals::Dict)
Expand Down Expand Up @@ -96,7 +93,7 @@ Output:
- `conversion` dictionary from the symbols in the input MTK model to the variable
involved in the produced `ODE` object
"""
function mtk_to_si(
function StructuralIdentifiability.mtk_to_si(
de::ModelingToolkit.AbstractTimeDependentSystem,
measured_quantities::Array{ModelingToolkit.Equation},
)
Expand All @@ -106,7 +103,7 @@ function mtk_to_si(
)
end

function mtk_to_si(
function StructuralIdentifiability.mtk_to_si(
de::ModelingToolkit.AbstractTimeDependentSystem,
measured_quantities::Array{<:Symbolics.Num},
)
Expand All @@ -116,7 +113,7 @@ function mtk_to_si(
)
end

function mtk_to_si(
function StructuralIdentifiability.mtk_to_si(
de::ModelingToolkit.AbstractTimeDependentSystem,
measured_quantities::Array{<:SymbolicUtils.BasicSymbolic},
)
Expand Down
6 changes: 6 additions & 0 deletions src/StructuralIdentifiability.jl
Original file line number Diff line number Diff line change
Expand Up @@ -172,4 +172,10 @@ end
using PrecompileTools
include("precompile.jl")

### Extensions ###

# ModelingToolkit extension.
function mtk_to_si end
export mtk_to_si

end
46 changes: 45 additions & 1 deletion test/extensions/modelingtoolkit.jl
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
if GROUP == "All" || GROUP == "ModelingToolkitExt"
if GROUP == "All" || GROUP == "ModelingToolkitSIExt"
@testset "Check identifiability of `ODESystem` object" begin
using ModelingToolkit
using ModelingToolkit: parameters
Expand Down Expand Up @@ -656,4 +656,48 @@ if GROUP == "All" || GROUP == "ModelingToolkitExt"
) == c[:res]
end
end

@testset "Exporting ModelingToolkit Model to SI Model" begin

# Creates MTK model and assesses its identifiability.
@parameters r1, r2, c1, c2, beta1, beta2, chi1, chi2
@variables t, x1(t), x2(t), y(t), u(t)
D = Differential(t)
eqs = [
D(x1) ~ r1 * x1 * (1 - c1 * x1) + beta1 * x1 * x2 / (chi1 + x2) + u,
D(x2) ~ r2 * x2 * (1 - c2 * x2) + beta2 * x1 * x2 / (chi2 + x1),
]
measured_quantities = [y ~ x1]
ode_mtk = ODESystem(eqs, t, name = :mutualist)

global_id_1 =
assess_identifiability(ode_mtk, measured_quantities = measured_quantities)
local_id_1 =
assess_local_identifiability(ode_mtk, measured_quantities = measured_quantities)
ifs_1 =
find_identifiable_functions(ode_mtk, measured_quantities = measured_quantities)

# Converts mtk model to si model, and assesses its identifiability.
si_model, _ = mtk_to_si(ode_mtk, measured_quantities)
global_id_2 = assess_identifiability(si_model)
local_id_2 = assess_local_identifiability(si_model)
ifs_2 = find_identifiable_functions(si_model)

# Converts the output dicts from StructuralIdentifiability functions from "weird symbol => stuff" to "symbol => stuff" (the output have some strange meta data which prevents equality checks, this enables this).
# Structural identifiability also provides variables like x (rather than x(t)). This is a bug, but we have to convert to make it work (now just remove any (t) to make them all equal).
function sym_dict(dict_in)
dict_out = Dict{Symbol, Any}()
for key in keys(dict_in)
sym_key = Symbol(key)
sym_key = Symbol(replace(String(sym_key), "(t)" => ""))
dict_out[sym_key] = dict_in[key]
end
return dict_out
end

# Checks that the two approaches yields the same result
@test issetequal(sym_dict(local_id_1), sym_dict(local_id_2))
@test issetequal(sym_dict(local_id_1), sym_dict(local_id_2))
@test length(ifs_1) == length(ifs_2)
end
end
4 changes: 2 additions & 2 deletions test/runtests.jl
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ using StructuralIdentifiability:
const GROUP = get(ENV, "GROUP", "All")

@static if VERSION >= v"1.10.0"
if GROUP == "All" || GROUP == "ModelingToolkitExt"
if GROUP == "All" || GROUP == "ModelingToolkitSIExt"
using Pkg
Pkg.add("ModelingToolkit")
Pkg.add("Symbolics")
Expand Down Expand Up @@ -123,7 +123,7 @@ function get_test_files(group)
if group == "All" ||
(group == "Core" && dir != "./extensions") ||
(
group == "ModelingToolkitExt" &&
group == "ModelingToolkitSIExt" &&
dir == "./extensions" &&
VERSION >= v"1.10.0"
)
Expand Down

0 comments on commit 15e2a28

Please sign in to comment.