Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix ModelingTookit extension #280

Merged
merged 4 commits into from
Feb 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@
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 @@
- `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(

Check warning on line 96 in ext/ModelingToolkitSIExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/ModelingToolkitSIExt.jl#L96

Added line #L96 was not covered by tests
de::ModelingToolkit.AbstractTimeDependentSystem,
measured_quantities::Array{ModelingToolkit.Equation},
)
Expand All @@ -106,7 +103,7 @@
)
end

function mtk_to_si(
function StructuralIdentifiability.mtk_to_si(

Check warning on line 106 in ext/ModelingToolkitSIExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/ModelingToolkitSIExt.jl#L106

Added line #L106 was not covered by tests
de::ModelingToolkit.AbstractTimeDependentSystem,
measured_quantities::Array{<:Symbolics.Num},
)
Expand All @@ -116,7 +113,7 @@
)
end

function mtk_to_si(
function StructuralIdentifiability.mtk_to_si(

Check warning on line 116 in ext/ModelingToolkitSIExt.jl

View check run for this annotation

Codecov / codecov/patch

ext/ModelingToolkitSIExt.jl#L116

Added line #L116 was not covered by tests
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
Loading