Skip to content

Commit

Permalink
Merge pull request #241 from SciML/loglevels
Browse files Browse the repository at this point in the history
Adding log levels to the functions and using internal logger
  • Loading branch information
pogudingleb authored Nov 13, 2023
2 parents f1a1db5 + 6c71712 commit 2ee1ade
Show file tree
Hide file tree
Showing 42 changed files with 456 additions and 286 deletions.
1 change: 1 addition & 0 deletions Project.toml
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
SymbolicUtils = "d1185830-fcd6-423d-90d6-eec64667417b"
Symbolics = "0c5d862f-8b57-4792-8d23-62f2024744c7"
TimerOutputs = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"

[compat]
AbstractAlgebra = "0.13, 0.18, 0.19, 0.20, 0.21, 0.22, 0.23, 0.24, 0.25, 0.26, 0.27, 0.28, 0.29, 0.30, 0.31, 0.32, 0.33"
Expand Down
9 changes: 6 additions & 3 deletions benchmarking/IdentifiableFunctions/experiments.jl
Original file line number Diff line number Diff line change
Expand Up @@ -988,14 +988,17 @@ begin
)

using Nemo, Logging
using JuliaInterpreter
# using JuliaInterpreter
Groebner = StructuralIdentifiability.Groebner
# ParamPunPam = StructuralIdentifiability.ParamPunPam
Base.global_logger(ConsoleLogger(Logging.Info))
end

dennums, ring =
StructuralIdentifiability.initial_identifiable_functions(Pivastatin, p = 0.99);
begin
StructuralIdentifiability.find_identifiable_functions(Pivastatin)
StructuralIdentifiability.print_timings_table()
end

fracs = StructuralIdentifiability.dennums_to_fractions(dennums);

rff = StructuralIdentifiability.RationalFunctionField(dennums);
Expand Down
6 changes: 0 additions & 6 deletions docs/src/identifiability/identifiability.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,6 @@ assess_identifiability
assess_local_identifiability
```

## Assessing Global Identifiability

```@docs
assess_global_identifiability
```

## Finding Identifiable Functions

```@docs
Expand Down
3 changes: 3 additions & 0 deletions docs/src/tutorials/discrete_time.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,9 @@ assess_local_identifiability(sir; measured_quantities = [I], funcs_to_check = [
principle it may produce incorrect result but the probability of correctness of the returned result is guaranteed to be at least `p`
(in fact, the employed bounds are quite conservative, so in practice incorrect result is almost never produced).

As other main functions in the package, `assess_local_identifiability` accepts an optional parameter `loglevel` (default: `Logging.Info`)
to adjust the verbosity of logging.

The implementation is based on a version of the observability rank criterion and will be described in a forthcoming paper.

[^1]: > S. Nõmm, C. Moog, [*Identifiability of discrete-time nonlinear systems*](https://doi.org/10.1016/S1474-6670(17)31245-4), IFAC Proceedings Volumes, 2004.
4 changes: 4 additions & 0 deletions docs/src/tutorials/identifiability.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ Function `assess_local_identifiability` has several optional parameters
likely to be much higher.
- `type` (default `:SE`). By default, the algorithm checks the standard single-experiment identifiability. If one sets `type = :ME`, then the algorithm
checks multi-experiment identifiability, that is, identifiability from several experiments with independent initial conditions (the algorithm from [^2] is used).
- `loglevel` (default `Logging.Info`). The minimal level of logging messages to be displayed. Available options: `Logging.Debug`,
`Logging.Info`, `Logging.Warn`, and `Logging.Error`.

Note that the scaling symmetry given above suggests that $b x_2(t)$ may in fact be identifiable. This can be checked using `funcs_to_check` parameter:

Expand Down Expand Up @@ -107,6 +109,8 @@ Similarly to `assess_local_identifiability`, this function has optional paramete
error probability is much lower than 1%.
Also, currently, the probability of correctness does not include the probability of correctness of the modular reconstruction for Groebner bases.
This probability is ensured by an additional check modulo a large prime, and can be neglected for practical purposes.
- `loglevel` (default `Logging.Info`). The minimal level of logging messages to be displayed. Available options: `Logging.Debug`,
`Logging.Info`, `Logging.Warn`, and `Logging.Error`.

Using `funcs_to_check` parameter, one can further inverstigate the nature of the lack of identifiability in the model at hand.
For example, for the Goodwin oscillator, we can check if `beta + delta` and `beta * delta` are identifiable:
Expand Down
3 changes: 3 additions & 0 deletions docs/src/tutorials/identifiable_functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,7 @@ By default, `find_identifiable_functions` tries to simplify the output functions
the degree of simplification. The default value is `:standard` but one could use `:strong` to try to simplify further
(at the expense of heavier computation) or use `:weak` to simplify less (but compute faster).

As `assess_identifiability` and `assess_local_identifiability`, `find_identifiable_functions` accepts an optional parameter `loglevel` (default: `Logging.Info`)
to adjust the verbosity of logging.

[^1]: > Y. Lecourtier, F. Lamnabhi-Lagarrigue, and E. Walter, [*A method to prove that nonlinear models can be unidentifiable*](https://doi.org/10.1109/CDC.1987.272467), Proceedings of the 26th Conference on Decision and Control, December 1987, 2144-2145;
7 changes: 1 addition & 6 deletions examples/CRN.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# Conradi, C., Shiu, A.,
# Dynamics of post-translational modification systems: recent progress and future directions
# Eq. 3.4
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
x1'(t) = -k1 * x1(t) * x2(t) + k2 * x4(t) + k4 * x6(t),
x2'(t) = -k1 * x1(t) * x2(t) + k2 * x4(t) + k3 * x4(t),
Expand All @@ -19,4 +14,4 @@ ode = @ODEmodel(
y2(t) = x2(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))
11 changes: 5 additions & 6 deletions examples/Crauste.jl
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Debug)
global_logger(logger)

ode = @ODEmodel(
N'(t) = -N(t) * mu_N - N(t) * P(t) * delta_NE,
E'(t) =
Expand All @@ -17,4 +12,8 @@ ode = @ODEmodel(
y3(t) = M(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))

# Not everything is identifiable, so we may wonder what are the identifiable functions

println(find_identifiable_functions(ode, with_states = true))
11 changes: 5 additions & 6 deletions examples/Fujita.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Decoupling of receptor and downstream signals in the Akt pathway by its low-pass filter characteristics
# https://doi.org/10.1126/scisignal.2000810

using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Debug)
global_logger(logger)

ode = @ODEmodel(
EGFR'(t) =
EGFR_turnover * pro_EGFR(t) + EGF_EGFR(t) * reaction_1_k2 -
Expand Down Expand Up @@ -42,4 +37,8 @@ ode = @ODEmodel(
y3(t) = a3 * pS6(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))

# Not everything is identifiable, so we may wonder what are the identifiable functions

println(find_identifiable_functions(ode, with_states = true))
11 changes: 5 additions & 6 deletions examples/Goodwin.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Oscillatory behavior in enzymatic control processes
# https://doi.org/10.1016/0065-2571(65)90067-1

using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
x1'(t) = -b * x1(t) + 1 / (c + x4(t)),
x2'(t) = alpha * x1(t) - beta * x2(t),
Expand All @@ -17,4 +12,8 @@ ode = @ODEmodel(
y(t) = x1(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))

# Not everything is identifiable, so we may wonder what are the identifiable functions

println(find_identifiable_functions(ode, with_states = true))
11 changes: 5 additions & 6 deletions examples/HIV.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Specific therapy regimes could lead to long-term immunological control of HIV
# https://doi.org/10.1073/pnas.96.25.14464
# Page 1
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
x'(t) = lm - d * x(t) - beta * x(t) * v(t),
y'(t) = beta * x(t) * v(t) - a * y(t),
Expand All @@ -19,4 +14,8 @@ ode = @ODEmodel(
y2(t) = z(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))

# Not everything is identifiable, so we may wonder what are the identifiable functions

println(find_identifiable_functions(ode, with_states = true))
11 changes: 5 additions & 6 deletions examples/LV.jl
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
# Lotka-Volterra model
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Debug)
global_logger(logger)

ode = @ODEmodel(
x1'(t) = a * x1(t) - b * x1(t) * x2(t) + u(t),
x2'(t) = -c * x2(t) + d * x1(t) * x2(t),
y(t) = x1(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))

# Not everything is identifiable, so we may wonder what are the identifiable functions

println(find_identifiable_functions(ode, with_states = true))
7 changes: 1 addition & 6 deletions examples/MAPK.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# A. K. Manrai and J. Gunawardena.
# The geometry of multisite phosphorylation
# https://dx.doi.org/10.1529%2Fbiophysj.108.140632
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
KS00'(t) =
-a00 * K(t) * S00(t) +
Expand Down Expand Up @@ -52,4 +47,4 @@ ode = @ODEmodel(
y5(t) = S11(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))
5 changes: 0 additions & 5 deletions examples/NFkB.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# An iterative identification procedure for dynamic modeling of biochemical networks
# https://doi.org/10.1186/1752-0509-4-11
# The model is out of reach at the moment but can be analyzed by SIAN (https://github.com/pogudingleb/SIAN)
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
x1'(t) = k_prod - k_deg * x1(t) - k1 * x1(t) * u(t),
x2'(t) =
Expand Down
7 changes: 1 addition & 6 deletions examples/Pharm.jl
Original file line number Diff line number Diff line change
@@ -1,13 +1,8 @@
# Demignot, S., D., D.,
# Effect of prosthetic sugar groups on the pharmacokinetics of glucose-oxidase
# https://pubmed.ncbi.nlm.nih.gov/2855567/
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Debug)
global_logger(logger)

ode = @ODEmodel(
x0'(t) =
a1 * (x1(t) - x0(t)) - (ka * n * x0(t)) / (kc * ka + kc * x2(t) + ka * x0(t)),
Expand All @@ -18,4 +13,4 @@ ode = @ODEmodel(
y1(t) = x0(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))
6 changes: 0 additions & 6 deletions examples/QWWC.jl
Original file line number Diff line number Diff line change
@@ -1,11 +1,5 @@
using Logging

using StructuralIdentifiability

#QWWC
logger = Logging.SimpleLogger(stdout, Logging.Debug)
global_logger(logger)

ode = @ODEmodel(
x'(t) = a * (y(t) - x(t)) + y(t) * z(t),
y'(t) = b * (x(t) + y(t)) - x(t) * z(t),
Expand Down
11 changes: 5 additions & 6 deletions examples/SEAIJRC.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Assessing parameter identifiability in compartmental dynamic models using a computational approach: application to infectious disease transmission models
# https://doi.org/10.1186/s12976-018-0097-6
# Model 2
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Debug)
global_logger(logger)

ode = @ODEmodel(
S'(t) = -b * S(t) * (I(t) + J(t) + q * A(t)) * Ninv,
E'(t) = b * S(t) * (I(t) + J(t) + q * A(t)) * Ninv - k * E(t),
Expand All @@ -20,4 +15,8 @@ ode = @ODEmodel(
y2(t) = Ninv
)

@time println(assess_global_identifiability(ode))
println(assess_identifiability(ode))

# Not everything is identifiable, so we may wonder what are the identifiable functions

println(find_identifiable_functions(ode, with_states = true))
12 changes: 5 additions & 7 deletions examples/SIAR.jl
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
# SIAR model
# https://arxiv.org/pdf/2012.00443.pdf
using Logging

# L. Gallo, M.Frasca, V. Latora, G. Russo
# Lack of practical identifiability may hamper reliable predictions in COVID-19 epidemic models
# Science Advances, DOI: 10.1126/sciadv.abg5234
# Equation (21)
using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
S'(t) =
-S(t) * (betaIa * Ia(t) + betaIs * Is(t) + betaH * H(t) + betaT * T(t)) * Ninv,
Expand All @@ -28,4 +26,4 @@ ode = @ODEmodel(
y5(t) = Ninv
)

@time println(assess_identifiability(ode))
println(find_identifiable_functions(ode, funcs_to_check = ode.parameters))
9 changes: 4 additions & 5 deletions examples/SIRS_forced.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Parameter Estimation of Some Epidemic Models. The Case of Recurrent Epidemics Caused by Respiratory Syncytial Virus
# doi.org/10.1007/s11538-009-9429-3
# Equations (7)-(11)
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
s'(t) = mu - mu * s(t) - b0 * (1 + b1 * x1(t)) * i(t) * s(t) + g * r(t),
i'(t) = b0 * (1 + b1 * x1(t)) * i(t) * s(t) - (nu + mu) * i(t),
Expand All @@ -20,3 +15,7 @@ ode = @ODEmodel(
)

@time println(assess_identifiability(ode))

# Not everything is identifiable, so we may wonder what are the identifiable functions

println(find_identifiable_functions(ode, with_states = true))
7 changes: 1 addition & 6 deletions examples/SIWR.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Model distinguishability and inference robustness in mechanisms of cholera transmission and loss of immunity
# https://doi.org/10.1016/j.jtbi.2017.01.032
# Eq. (3)
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Info)
global_logger(logger)

ode = @ODEmodel(
S'(t) = mu - bi * S(t) * I(t) - bw * S(t) * W(t) - mu * S(t) + a * R(t),
I'(t) = bw * S(t) * W(t) + bi * S(t) * I(t) - (gam + mu) * I(t),
Expand All @@ -17,4 +12,4 @@ ode = @ODEmodel(
y(t) = k * I(t)
)

@time println(assess_identifiability(ode))
println(assess_identifiability(ode))
7 changes: 1 addition & 6 deletions examples/SIWR_multioutput.jl
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,8 @@
# Model distinguishability and inference robustness in mechanisms of cholera transmission and loss of immunity
# https://doi.org/10.1016/j.jtbi.2017.01.032
# Eq. (3) + extra output
using Logging

using StructuralIdentifiability

logger = Logging.SimpleLogger(stdout, Logging.Debug)
global_logger(logger)

ode = @ODEmodel(
x_0'(t) =
mu - bi * x_0(t) * x_1(t) - bw * x_0(t) * x_2(t) - mu * x_0(t) + a * x_3(t),
Expand All @@ -19,4 +14,4 @@ ode = @ODEmodel(
y2(t) = x_0(t) + x_1(t) + x_3(t)
)

@time println(assess_global_identifiability(ode))
println(assess_identifiability(ode))
Loading

0 comments on commit 2ee1ade

Please sign in to comment.