CRNNondim 1.0.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- crnnondim-1.0.0/.gitignore +90 -0
- crnnondim-1.0.0/CITATION.cff +17 -0
- crnnondim-1.0.0/LICENSE +21 -0
- crnnondim-1.0.0/PKG-INFO +27 -0
- crnnondim-1.0.0/README.md +11 -0
- crnnondim-1.0.0/examples/5D_SEIRV_example.py +78 -0
- crnnondim-1.0.0/examples/find_optimal_nondim_example.py +53 -0
- crnnondim-1.0.0/examples/parse_reactions_examples.py +90 -0
- crnnondim-1.0.0/examples/process_CRN_examples.py +69 -0
- crnnondim-1.0.0/examples/process_CRN_given_nondimensionalisation_examples.py +81 -0
- crnnondim-1.0.0/full_example.py +140 -0
- crnnondim-1.0.0/pyproject.toml +51 -0
- crnnondim-1.0.0/src/crnnondim/CRN_analyser.py +1344 -0
- crnnondim-1.0.0/src/crnnondim/_LEXIWrapper.py +60 -0
- crnnondim-1.0.0/src/crnnondim/__init__.py +148 -0
- crnnondim-1.0.0/src/crnnondim/_assignment_pool.py +334 -0
- crnnondim-1.0.0/src/crnnondim/_integer_search.py +138 -0
- crnnondim-1.0.0/src/crnnondim/_parallel_assignments.py +181 -0
- crnnondim-1.0.0/src/crnnondim/_polynomial_basis.py +167 -0
- crnnondim-1.0.0/src/crnnondim/analyse_results.py +163 -0
- crnnondim-1.0.0/src/crnnondim/example_CRNs.py +141 -0
- crnnondim-1.0.0/src/crnnondim/factor_generators_columnwise.py +83 -0
- crnnondim-1.0.0/src/crnnondim/find_optimal_nondim.py +999 -0
- crnnondim-1.0.0/src/crnnondim/objective_function_utils.py +537 -0
- crnnondim-1.0.0/src/crnnondim/parse_reactions.py +224 -0
- crnnondim-1.0.0/src/crnnondim/poly_system_to_CRN.py +140 -0
- crnnondim-1.0.0/src/crnnondim/process_CRN.py +243 -0
- crnnondim-1.0.0/src/crnnondim/process_CRN_given_nondimensionalisation.py +503 -0
- crnnondim-1.0.0/src/crnnondim/utils.py +1508 -0
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
# ------------------------------------------------------------------------------
|
|
2
|
+
# OS files
|
|
3
|
+
# ------------------------------------------------------------------------------
|
|
4
|
+
.DS_Store
|
|
5
|
+
Thumbs.db
|
|
6
|
+
|
|
7
|
+
# ------------------------------------------------------------------------------
|
|
8
|
+
# Python bytecode / cache
|
|
9
|
+
# ------------------------------------------------------------------------------
|
|
10
|
+
__pycache__/
|
|
11
|
+
*.py[cod]
|
|
12
|
+
*$py.class
|
|
13
|
+
|
|
14
|
+
# ------------------------------------------------------------------------------
|
|
15
|
+
# Virtual environments
|
|
16
|
+
# ------------------------------------------------------------------------------
|
|
17
|
+
.venv/
|
|
18
|
+
venv/
|
|
19
|
+
env/
|
|
20
|
+
ENV/
|
|
21
|
+
|
|
22
|
+
# Conda
|
|
23
|
+
.conda/
|
|
24
|
+
conda-env/
|
|
25
|
+
*.conda
|
|
26
|
+
|
|
27
|
+
# ------------------------------------------------------------------------------
|
|
28
|
+
# Build / packaging
|
|
29
|
+
# ------------------------------------------------------------------------------
|
|
30
|
+
build/
|
|
31
|
+
dist/
|
|
32
|
+
*.egg-info/
|
|
33
|
+
.eggs/
|
|
34
|
+
pip-wheel-metadata/
|
|
35
|
+
*.egg
|
|
36
|
+
|
|
37
|
+
# ------------------------------------------------------------------------------
|
|
38
|
+
# Logs / debugging
|
|
39
|
+
# ------------------------------------------------------------------------------
|
|
40
|
+
*.log
|
|
41
|
+
*.tmp
|
|
42
|
+
|
|
43
|
+
# ------------------------------------------------------------------------------
|
|
44
|
+
# Test / coverage artifacts
|
|
45
|
+
# ------------------------------------------------------------------------------
|
|
46
|
+
.pytest_cache/
|
|
47
|
+
.coverage
|
|
48
|
+
.coverage.*
|
|
49
|
+
htmlcov/
|
|
50
|
+
.tox/
|
|
51
|
+
.nox/
|
|
52
|
+
.cache/
|
|
53
|
+
|
|
54
|
+
# ------------------------------------------------------------------------------
|
|
55
|
+
# Notebooks
|
|
56
|
+
# ------------------------------------------------------------------------------
|
|
57
|
+
.ipynb_checkpoints/
|
|
58
|
+
|
|
59
|
+
# ------------------------------------------------------------------------------
|
|
60
|
+
# Editors / IDEs
|
|
61
|
+
# ------------------------------------------------------------------------------
|
|
62
|
+
.vscode/
|
|
63
|
+
.idea/
|
|
64
|
+
*.iml
|
|
65
|
+
|
|
66
|
+
# ------------------------------------------------------------------------------
|
|
67
|
+
# Documentation builds (if using Sphinx, etc.)
|
|
68
|
+
# ------------------------------------------------------------------------------
|
|
69
|
+
docs/_build/
|
|
70
|
+
site/
|
|
71
|
+
|
|
72
|
+
# ------------------------------------------------------------------------------
|
|
73
|
+
# Environment / local config
|
|
74
|
+
# ------------------------------------------------------------------------------
|
|
75
|
+
.env
|
|
76
|
+
.env.*
|
|
77
|
+
*.env
|
|
78
|
+
|
|
79
|
+
# ------------------------------------------------------------------------------
|
|
80
|
+
# uv / Python version files
|
|
81
|
+
# ------------------------------------------------------------------------------
|
|
82
|
+
.python-version
|
|
83
|
+
.uv_cache/
|
|
84
|
+
.uv-cache/
|
|
85
|
+
|
|
86
|
+
# ------------------------------------------------------------------------------
|
|
87
|
+
# Misc
|
|
88
|
+
# ------------------------------------------------------------------------------
|
|
89
|
+
*.swp
|
|
90
|
+
*.swo
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use this software, please cite the following paper."
|
|
3
|
+
title: "Algorithmic Non-dimensionalisation of Polynomial Dynamical Systems with CRNNondim"
|
|
4
|
+
authors:
|
|
5
|
+
- family-names: "Hawi"
|
|
6
|
+
given-names: "Georgio"
|
|
7
|
+
- family-names: "Wechselberger"
|
|
8
|
+
given-names: "Martin"
|
|
9
|
+
preferred-citation:
|
|
10
|
+
type: article
|
|
11
|
+
authors:
|
|
12
|
+
- family-names: "Hawi"
|
|
13
|
+
given-names: "Georgio"
|
|
14
|
+
- family-names: "Wechselberger"
|
|
15
|
+
given-names: "Martin"
|
|
16
|
+
title: "Algorithmic Non-dimensionalisation of Polynomial Dynamical Systems with CRNNondim"
|
|
17
|
+
year: 2026
|
crnnondim-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Georgio Hawi and Martin Wechselberger
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
crnnondim-1.0.0/PKG-INFO
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: CRNNondim
|
|
3
|
+
Version: 1.0.0
|
|
4
|
+
Summary: Automated non-dimensionalisation of polynomial dynamical systems via chemical reaction networks
|
|
5
|
+
Project-URL: Homepage, https://github.com/georgio-hawi/crnnondim
|
|
6
|
+
Project-URL: Repository, https://github.com/georgio-hawi/crnnondim
|
|
7
|
+
Author-email: Georgio Hawi <georgio.hawi@sydney.edu.au>, Martin Wechselberger <martin.wechselberger@sydney.edu.au>
|
|
8
|
+
License-Expression: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Keywords: CRN,non-dimensionalisation,polynomial dynamical system
|
|
11
|
+
Requires-Python: <3.13,>=3.11.7
|
|
12
|
+
Requires-Dist: numpy<2,>=1.26.4
|
|
13
|
+
Requires-Dist: scipy<2,>=1.14.0
|
|
14
|
+
Requires-Dist: sympy<2,>=1.13.1
|
|
15
|
+
Description-Content-Type: text/markdown
|
|
16
|
+
|
|
17
|
+
# CRNNondim
|
|
18
|
+
CRNNondim is a Python library for automating the non-dimensionalisation of polynomial dynamical systems via chemical reaction networks (CRNs). It was developed by Georgio Hawi and Martin Wechselberger, with an accompanying paper available soon. Please direct all enquiries to georgio.hawi (at) sydney.edu.au.
|
|
19
|
+
|
|
20
|
+
Given a polynomial CRN, CRNNondim helps you move from human-readable reaction lists to carefully chosen dimensionless variables and parameters. You can analyse a proposed non-dimensionalisation, or ask the library to search for one that is optimal under a precise objective (for example, keeping parameters O(1) over a chosen time window).
|
|
21
|
+
|
|
22
|
+
CRNNondim provides tools to automate analysing and non-dimensionalising chemical reaction networks (CRNs).
|
|
23
|
+
CRNNondim includes functions that let you:
|
|
24
|
+
- parse readable reaction network descriptions or a polynomial ODE system into a symbolic CRN-like ODE system (stoichiometry matrix `S`, reaction vector `V`, species vector `X`, and rate constants),
|
|
25
|
+
- analyse CRNs to derive algebraic constraints on concentration and time scales and construct non-dimensionalisations that minimise the number of free parameters,
|
|
26
|
+
- non-dimensionalise a CRN given an explicit choice of species scales, so you can test or refine hand-crafted scalings,
|
|
27
|
+
- search for optimal non-dimensionalisations using typical initial conditions and rate constants, targeting O(1) parameters over a specified time window
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
# CRNNondim
|
|
2
|
+
CRNNondim is a Python library for automating the non-dimensionalisation of polynomial dynamical systems via chemical reaction networks (CRNs). It was developed by Georgio Hawi and Martin Wechselberger, with an accompanying paper available soon. Please direct all enquiries to georgio.hawi (at) sydney.edu.au.
|
|
3
|
+
|
|
4
|
+
Given a polynomial CRN, CRNNondim helps you move from human-readable reaction lists to carefully chosen dimensionless variables and parameters. You can analyse a proposed non-dimensionalisation, or ask the library to search for one that is optimal under a precise objective (for example, keeping parameters O(1) over a chosen time window).
|
|
5
|
+
|
|
6
|
+
CRNNondim provides tools to automate analysing and non-dimensionalising chemical reaction networks (CRNs).
|
|
7
|
+
CRNNondim includes functions that let you:
|
|
8
|
+
- parse readable reaction network descriptions or a polynomial ODE system into a symbolic CRN-like ODE system (stoichiometry matrix `S`, reaction vector `V`, species vector `X`, and rate constants),
|
|
9
|
+
- analyse CRNs to derive algebraic constraints on concentration and time scales and construct non-dimensionalisations that minimise the number of free parameters,
|
|
10
|
+
- non-dimensionalise a CRN given an explicit choice of species scales, so you can test or refine hand-crafted scalings,
|
|
11
|
+
- search for optimal non-dimensionalisations using typical initial conditions and rate constants, targeting O(1) parameters over a specified time window
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Examples showing how to use poly_system_to_CRN to convert the
|
|
3
|
+
5D SEIRV epidemic model to a mass-action CRN representation (S, V, X, etc),
|
|
4
|
+
and use process_CRN to analyse it.
|
|
5
|
+
"""
|
|
6
|
+
import sympy as sp
|
|
7
|
+
from crnnondim import poly_system_to_CRN, process_CRN, analyse_results
|
|
8
|
+
|
|
9
|
+
# ---------------------------------------------------------------------------
|
|
10
|
+
# Example: 5D SEIRV epidemic model
|
|
11
|
+
# ---------------------------------------------------------------------------
|
|
12
|
+
# STATE VARIABLES (species):
|
|
13
|
+
# S(t): Susceptible individuals
|
|
14
|
+
# E(t): Exposed (infected but not yet infectious)
|
|
15
|
+
# I(t): Infectious
|
|
16
|
+
# R(t): Recovered with immunity
|
|
17
|
+
# V(t): Vaccinated and currently protected
|
|
18
|
+
#
|
|
19
|
+
# PARAMETERS:
|
|
20
|
+
# Lambda : recruitment rate (birth/immigration) into S
|
|
21
|
+
# mu : natural per-capita death rate (applies to all compartments)
|
|
22
|
+
# beta : infection rate (S becomes E via contact with I)
|
|
23
|
+
# sigma : progression rate from exposed to infectious (E -> I)
|
|
24
|
+
# gamma : recovery rate from infectious to recovered (I -> R)
|
|
25
|
+
# nu : vaccination rate of susceptibles (S -> V)
|
|
26
|
+
# omega : waning immunity rate in recovered (R -> S)
|
|
27
|
+
# omega_V : waning vaccine protection rate (V -> S)
|
|
28
|
+
#
|
|
29
|
+
# MODEL EQUATIONS:
|
|
30
|
+
#
|
|
31
|
+
# dS/dt = Lambda - beta*S*I - nu*S + omega*R + omega_V*V - mu*S
|
|
32
|
+
# dE/dt = beta*S*I - sigma*E - mu*E
|
|
33
|
+
# dI/dt = sigma*E - gamma*I - mu*I
|
|
34
|
+
# dR/dt = gamma*I - omega*R - mu*R
|
|
35
|
+
# dV/dt = nu*S - omega_V*V - mu*V
|
|
36
|
+
# ---------------------------------------------------------------------------
|
|
37
|
+
|
|
38
|
+
# Define species (state variables) as SymPy symbols
|
|
39
|
+
S, E, I, R, V = sp.symbols("S E I R V", nonnegative=True)
|
|
40
|
+
X_syms = [S, E, I, R, V]
|
|
41
|
+
|
|
42
|
+
# Define parameters as SymPy symbols (positive)
|
|
43
|
+
Lambda, mu, beta, sigma, gamma, nu, omega, omega_V = sp.symbols(
|
|
44
|
+
"Lambda mu beta sigma gamma nu omega omega_V", positive=True
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
# ODE right-hand sides
|
|
48
|
+
dXdt = [
|
|
49
|
+
Lambda - beta*S*I - nu*S + omega*R + omega_V*V - mu*S,
|
|
50
|
+
beta*S*I - sigma*E - mu*E,
|
|
51
|
+
sigma*E - gamma*I - mu*I,
|
|
52
|
+
gamma*I - omega*R - mu*R,
|
|
53
|
+
nu*S - omega_V*V - mu*V]
|
|
54
|
+
|
|
55
|
+
# Convert the ODE system into objects usable by CRNNondim and print a small summary of the parsed CRN.
|
|
56
|
+
parsed_out = poly_system_to_CRN(
|
|
57
|
+
_X=X_syms,
|
|
58
|
+
ode_rhs=dXdt,
|
|
59
|
+
verbose=True
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
species_names = parsed_out["species"]
|
|
63
|
+
_S = parsed_out['_S']
|
|
64
|
+
_X = parsed_out['_X']
|
|
65
|
+
_V = parsed_out['_V']
|
|
66
|
+
rate_constants = parsed_out['rate_constants']
|
|
67
|
+
|
|
68
|
+
# Map species -> scale symbols. These scale symbols are held fixed when analysing the CRN.
|
|
69
|
+
S_0, I_0 = sp.symbols('S_0 I_0', positive=True)
|
|
70
|
+
fixed_K = {S: S_0, I: I_0}
|
|
71
|
+
|
|
72
|
+
# Analyse the CRN, optionally asking it to construct an explicit example
|
|
73
|
+
# non-dimensionalisation that attains the minimum possible number of
|
|
74
|
+
# free parameters (find_example_nondim=True).
|
|
75
|
+
all_results = process_CRN(_S, _V, _X, fixed_K=fixed_K, find_example_nondim=True, verbose=True, basis_type="Laurent")
|
|
76
|
+
|
|
77
|
+
# Analyse the results and print the analysis (if verbose=True).
|
|
78
|
+
all_transformed_results = analyse_results(all_results, verbose=True)
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Example showing how to use find_optimal_nondim to find
|
|
3
|
+
the optimal non-dimensionalisation given numerical values for
|
|
4
|
+
typical initial conditions and rate constants.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from crnnondim import find_optimal_nondim, analyse_results, Kim_ForgerExample
|
|
8
|
+
import sympy as sp
|
|
9
|
+
|
|
10
|
+
def Kim_Forger_example():
|
|
11
|
+
# Instantiate the Kim-Forger example.
|
|
12
|
+
kf_example = Kim_ForgerExample()
|
|
13
|
+
|
|
14
|
+
# Example dimensional initial conditions for the species.
|
|
15
|
+
x_0_num = {kf_example.X: 1.0, kf_example.Y: 1.0, kf_example.Z: 0.06128, kf_example.S: 0.06128, kf_example.C: 0.0}
|
|
16
|
+
|
|
17
|
+
# Characteristic concentration scales for each species with non-zero initial condition.
|
|
18
|
+
x0, y0, z0, s0 = sp.symbols('x_0 y_0 z_0 s_0', positive=True)
|
|
19
|
+
|
|
20
|
+
# Map species -> scale symbols. These scale symbols are held fixed when searching for
|
|
21
|
+
# optimal non-dimensionalisations.
|
|
22
|
+
fixed_K = {kf_example.X: x0, kf_example.Y: y0, kf_example.Z: z0, kf_example.S: s0}
|
|
23
|
+
|
|
24
|
+
# Example dimensional rate constants used to evaluate O(1) deviation penalty.
|
|
25
|
+
k_num = {kf_example.k1: 0.07, kf_example.k2: 0.07, kf_example.k3: 0.05, kf_example.k4: 0.05, kf_example.k5: 0.05, kf_example.k6: 0.05, kf_example.kf: 1.0, kf_example.kb: 1.0, kf_example.ku: 0.05}
|
|
26
|
+
|
|
27
|
+
# Time window (in dimensional time) over which we want to consider a penalty.
|
|
28
|
+
T_max = 12
|
|
29
|
+
T_min = T_max/2
|
|
30
|
+
|
|
31
|
+
# Non-dimensionalisation metric
|
|
32
|
+
nondim_metric = "deviation" #"maximum"
|
|
33
|
+
|
|
34
|
+
# Dimensioanlly consistent sets
|
|
35
|
+
# Optional: list of sets of dimensionally consistent state variables
|
|
36
|
+
# default=None assumes all state variables have the same dimensions.
|
|
37
|
+
dimensionally_consistent_sets=None
|
|
38
|
+
|
|
39
|
+
# Compute the optimal non-dimensionalisation for this CRN.
|
|
40
|
+
solver_opts=dict(method="Radau", atol=1e-12, rtol=1e-9)
|
|
41
|
+
res = find_optimal_nondim(kf_example._S, kf_example._V, kf_example._X, fixed_K=fixed_K,
|
|
42
|
+
dimensionally_consistent_sets=dimensionally_consistent_sets,
|
|
43
|
+
k_numeric=k_num, x0_numeric=x_0_num, T_min=T_min, T_max=T_max, nondim_metric=nondim_metric, solver_opts=solver_opts, basis_type="Polynomial", n_jobs=None,
|
|
44
|
+
# export results to a pickle format.
|
|
45
|
+
export_results=True,
|
|
46
|
+
output_path=f"out/Kim_Forger_{nondim_metric}_nondim.pkl")
|
|
47
|
+
return res
|
|
48
|
+
|
|
49
|
+
# Run the example.
|
|
50
|
+
all_results = Kim_Forger_example()
|
|
51
|
+
|
|
52
|
+
# Analyse the results and print the analysis (if verbose=True).
|
|
53
|
+
all_transformed_results = analyse_results(all_results, verbose=True)
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Examples showing how to use build_mass_action_system to convert
|
|
3
|
+
a list of reactions to a mass-action CRN representation (S, V, X, etc).
|
|
4
|
+
"""
|
|
5
|
+
from crnnondim import reaction, reversible, build_mass_action_system
|
|
6
|
+
|
|
7
|
+
def Michaelis_Menten_example():
|
|
8
|
+
"""
|
|
9
|
+
Defines the reaction list for the reversible Michaelis-Menten scheme.
|
|
10
|
+
|
|
11
|
+
Returns
|
|
12
|
+
-------
|
|
13
|
+
rxns : list
|
|
14
|
+
List of reaction objects (forward + reverse) that can be passed to
|
|
15
|
+
build_mass_action_system.
|
|
16
|
+
"""
|
|
17
|
+
rxns = []
|
|
18
|
+
# E + S <-> C with forward rate k1 and reverse rate km1
|
|
19
|
+
rxns += reversible("E + S <-> C", kf="k1", kr="km1")
|
|
20
|
+
# C <-> P + E with forward rate k2 and reverse rate km2
|
|
21
|
+
rxns += reversible("C <-> P + E", kf="k2", kr="km2")
|
|
22
|
+
return rxns
|
|
23
|
+
|
|
24
|
+
def Kim_Forger_example():
|
|
25
|
+
"""
|
|
26
|
+
Defines the reaction list for the Kim-Forger (KF) model, a simplified
|
|
27
|
+
circadian clock model.
|
|
28
|
+
"""
|
|
29
|
+
rxns = [
|
|
30
|
+
# S -> X + S : basal production of X driven by S (rate constant k1)
|
|
31
|
+
reaction("S -> X + S", k="k1"),
|
|
32
|
+
# X -> 0 : degradation/removal of X (rate constant k2)
|
|
33
|
+
reaction("X -> 0", k="k2"),
|
|
34
|
+
# X -> X + Y : production of Y catalysed by X (rate constant k3)
|
|
35
|
+
reaction("X -> X + Y", k="k3"),
|
|
36
|
+
# Y -> 0 : degradation/removal of Y (rate constant k4)
|
|
37
|
+
reaction("Y -> 0", k="k4"),
|
|
38
|
+
# Y -> Y + Z : production of Z catalysed by Y (rate constant k5)
|
|
39
|
+
reaction("Y -> Y + Z", k="k5"),
|
|
40
|
+
# Z -> 0 : degradation/removal of Z (rate constant k6)
|
|
41
|
+
reaction("Z -> 0", k="k6"),
|
|
42
|
+
# C -> S : conversion/decay of complex C back to free S
|
|
43
|
+
reaction("C -> S", k="ku")]
|
|
44
|
+
# Reversible binding/unbinding between S and Z to form complex C.
|
|
45
|
+
# Forward binding S + Z -> C has rate constant kf,
|
|
46
|
+
# reverse unbinding C -> S + Z has rate constant kb.
|
|
47
|
+
rxns+= reversible("S + Z <-> C", kf="kf", kr="kb")
|
|
48
|
+
return rxns
|
|
49
|
+
|
|
50
|
+
def McKeithan_example(n=6):
|
|
51
|
+
"""
|
|
52
|
+
Defines the reaction list for the McKeithan TCR proofreading chain with n
|
|
53
|
+
intermediate ligand-receptor complexes.
|
|
54
|
+
|
|
55
|
+
Parameters
|
|
56
|
+
----------
|
|
57
|
+
n : int
|
|
58
|
+
Number of proofreading steps (C0 -> C1 -> ... -> Cn).
|
|
59
|
+
"""
|
|
60
|
+
rxns = []
|
|
61
|
+
# Association/dissociation of the first complex C0.
|
|
62
|
+
rxns.extend(reversible("T + M <-> C0", kf="k1", kr="km1"))
|
|
63
|
+
# Forward proofreading step through the chain of complexes.
|
|
64
|
+
for i in range(n):
|
|
65
|
+
rxns.append(reaction(f"C{i} -> C{i+1}", k=f"k2")) # forward proofreading step
|
|
66
|
+
# Each complex can dissociate back to T + M with the same rate km1.
|
|
67
|
+
for i in range(1,n+1):
|
|
68
|
+
rxns.append(reaction(f"C{i} -> T + M", k=f"km1"))
|
|
69
|
+
return rxns
|
|
70
|
+
|
|
71
|
+
# Select which example to parse and convert into a mass-action CRN.
|
|
72
|
+
example_name = "McKeithan"
|
|
73
|
+
|
|
74
|
+
match example_name:
|
|
75
|
+
case "Michaelis-Menten":
|
|
76
|
+
reactions = Michaelis_Menten_example()
|
|
77
|
+
case "Kim-Forger":
|
|
78
|
+
reactions = Kim_Forger_example()
|
|
79
|
+
case _:
|
|
80
|
+
reactions = McKeithan_example()
|
|
81
|
+
|
|
82
|
+
# Convert the reaction list into objects usable by CRNNondim and print a small summary of the parsed CRN.
|
|
83
|
+
parsed_out = build_mass_action_system(reactions, verbose=True)
|
|
84
|
+
|
|
85
|
+
species_names = parsed_out["species"]
|
|
86
|
+
_S = parsed_out['_S']
|
|
87
|
+
_X = parsed_out['_X']
|
|
88
|
+
_V = parsed_out['_V']
|
|
89
|
+
rate_constants = parsed_out['rate_constants']
|
|
90
|
+
expanded_ODEs = parsed_out['expanded_ODEs']
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Examples showing how to use process_CRN to analyse CRNs, derive restrictions
|
|
3
|
+
on scaling factors so that the number of free parameters in the resulting non-dimensional
|
|
4
|
+
system is minimised, and construct an example non-dimensionalisation that attains this minimum.
|
|
5
|
+
"""
|
|
6
|
+
from crnnondim import process_CRN, analyse_results, Michaelis_MentenExample, Kim_ForgerExample, McKeithanExample
|
|
7
|
+
import sympy as sp
|
|
8
|
+
|
|
9
|
+
def Michaelis_Menten_example(find_example_nondim=False):
|
|
10
|
+
# Instantiate the Michaelis-Menten example.
|
|
11
|
+
mm_example = Michaelis_MentenExample()
|
|
12
|
+
|
|
13
|
+
# Characteristic concentration scales for S and E.
|
|
14
|
+
s0, e0 = sp.symbols('s_0 e_0', positive=True)
|
|
15
|
+
|
|
16
|
+
# Map species -> scale symbols. These scale symbols are held fixed when analysing the CRN.
|
|
17
|
+
fixed_K = {mm_example.S: s0, mm_example.E: e0}
|
|
18
|
+
|
|
19
|
+
# Analyse the CRN, optionally asking it to construct an explicit example
|
|
20
|
+
# non-dimensionalisation that attains the minimum possible number of
|
|
21
|
+
# free parameters (find_example_nondim=True).
|
|
22
|
+
res = process_CRN(mm_example._S, mm_example._V, mm_example._X, fixed_K=fixed_K, find_example_nondim=find_example_nondim, verbose=True, basis_type="Laurent")
|
|
23
|
+
return res
|
|
24
|
+
|
|
25
|
+
def Kim_Forger_example(find_example_nondim=False):
|
|
26
|
+
# Instantiate the Kim-Forger example.
|
|
27
|
+
kf_example = Kim_ForgerExample()
|
|
28
|
+
|
|
29
|
+
# Characteristic concentration scales for X, Y, Z, S.
|
|
30
|
+
x0, y0, z0, s0 = sp.symbols('x_0 y_0 z_0 s_0', positive=True)
|
|
31
|
+
|
|
32
|
+
# Map species -> scale symbols. These scale symbols are held fixed when analysing the CRN.
|
|
33
|
+
fixed_K = {kf_example.X: x0, kf_example.Y: y0, kf_example.Z: z0, kf_example.S: s0}
|
|
34
|
+
|
|
35
|
+
# Analyse the CRN, optionally asking it to construct an explicit example
|
|
36
|
+
# non-dimensionalisation that attains the minimum possible number of
|
|
37
|
+
# free parameters (find_example_nondim=True).
|
|
38
|
+
res = process_CRN(kf_example._S, kf_example._V, kf_example._X, fixed_K=fixed_K, find_example_nondim=find_example_nondim, verbose=True, basis_type="Laurent")
|
|
39
|
+
return res
|
|
40
|
+
|
|
41
|
+
def McKeithan_example(find_example_nondim=False):
|
|
42
|
+
# Instantiate the McKeithan TCR proofreading example.
|
|
43
|
+
m_example = McKeithanExample()
|
|
44
|
+
|
|
45
|
+
# Characteristic concentration scales for T and M.
|
|
46
|
+
T_0, M_0 = sp.symbols('T_0 M_0', positive=True)
|
|
47
|
+
|
|
48
|
+
# Map species -> scale symbols. These scale symbols are held fixed when analysing the CRN.
|
|
49
|
+
fixed_K = {m_example.T: T_0, m_example.M: M_0}
|
|
50
|
+
|
|
51
|
+
# Analyse the CRN, optionally asking it to construct an explicit example
|
|
52
|
+
# non-dimensionalisation that attains the minimum possible number of
|
|
53
|
+
# free parameters (find_example_nondim=True).
|
|
54
|
+
res = process_CRN(m_example._S, m_example._V, m_example._X, fixed_K=fixed_K, find_example_nondim=find_example_nondim, verbose=True, basis_type="Laurent")
|
|
55
|
+
return res
|
|
56
|
+
|
|
57
|
+
# Choose which example to run.
|
|
58
|
+
example_name = "McKeithan"
|
|
59
|
+
find_example_nondim = True
|
|
60
|
+
match example_name:
|
|
61
|
+
case "Michaelis-Menten":
|
|
62
|
+
all_results = Michaelis_Menten_example(find_example_nondim=find_example_nondim)
|
|
63
|
+
case "Kim-Forger":
|
|
64
|
+
all_results = Kim_Forger_example(find_example_nondim=find_example_nondim)
|
|
65
|
+
case _:
|
|
66
|
+
all_results = McKeithan_example(find_example_nondim=find_example_nondim)
|
|
67
|
+
|
|
68
|
+
# Analyse the results and print the analysis (if verbose=True).
|
|
69
|
+
all_transformed_results = analyse_results(all_results, verbose=True)
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Examples showing how to use process_CRN_given_nondimensionalisation to
|
|
3
|
+
non-dimensionalise a CRN given a specific non-dimensionalisation.
|
|
4
|
+
"""
|
|
5
|
+
from crnnondim import process_CRN_given_nondimensionalisation, analyse_results, Michaelis_MentenExample, Kim_ForgerExample, McKeithanExample
|
|
6
|
+
import sympy as sp
|
|
7
|
+
|
|
8
|
+
def Michaelis_Menten_example(return_all_families=False):
|
|
9
|
+
# Instantiate the Michaelis-Menten example.
|
|
10
|
+
mm_example = Michaelis_MentenExample()
|
|
11
|
+
|
|
12
|
+
# Characteristic concentration scales for S and E.
|
|
13
|
+
s_0, e_0 = sp.symbols('s_0 e_0', positive=True)
|
|
14
|
+
|
|
15
|
+
#Give an explicit choice of non-dimensionalisation.
|
|
16
|
+
nondim = {mm_example.S: s_0, mm_example.E: e_0, mm_example.C: e_0, mm_example.P: e_0}
|
|
17
|
+
|
|
18
|
+
# Non-dimensionalise the CRN given this particular non-dimensionalisation.
|
|
19
|
+
# Time scaling, via K_T, can be provided if desired.
|
|
20
|
+
res = process_CRN_given_nondimensionalisation(
|
|
21
|
+
mm_example._S,
|
|
22
|
+
mm_example._V,
|
|
23
|
+
mm_example._X,
|
|
24
|
+
nondim=nondim,
|
|
25
|
+
basis_type="Laurent",
|
|
26
|
+
return_all_families=return_all_families
|
|
27
|
+
)
|
|
28
|
+
return res
|
|
29
|
+
|
|
30
|
+
def Kim_Forger_example(return_all_families=False):
|
|
31
|
+
# Instantiate the Kim-Forger example.
|
|
32
|
+
kf_example = Kim_ForgerExample()
|
|
33
|
+
|
|
34
|
+
# Characteristic concentration scales for X, Y, Z, S.
|
|
35
|
+
x_0, y_0, z_0, s_0 = sp.symbols('x_0 y_0 z_0 s_0', positive=True)
|
|
36
|
+
|
|
37
|
+
#Give an explicit choice of non-dimensionalisation.
|
|
38
|
+
nondim1 = {kf_example.X: x_0, kf_example.Y: y_0, kf_example.Z: z_0, kf_example.S: s_0, kf_example.C:z_0}
|
|
39
|
+
|
|
40
|
+
# Non-dimensionalise the CRN given this particular non-dimensionalisation.
|
|
41
|
+
# Time scaling, via K_T, can be provided if desired.
|
|
42
|
+
res1 = process_CRN_given_nondimensionalisation(kf_example._S, kf_example._V, kf_example._X, nondim=nondim1, basis_type="Laurent", return_all_families=return_all_families)
|
|
43
|
+
|
|
44
|
+
# Second choice of non-dimensionalisation.
|
|
45
|
+
nondim2 = {kf_example.X: x_0, kf_example.Y: y_0, kf_example.Z: z_0, kf_example.S: s_0, kf_example.C:x_0} # species-keyed
|
|
46
|
+
res2 = process_CRN_given_nondimensionalisation(kf_example._S, kf_example._V, kf_example._X, nondim=nondim2, basis_type="Laurent", return_all_families=return_all_families)
|
|
47
|
+
|
|
48
|
+
return [res1, res2]
|
|
49
|
+
|
|
50
|
+
def McKeithan_example(return_all_families=False):
|
|
51
|
+
# Instantiate the McKeithan TCR proofreading example.
|
|
52
|
+
m_example = McKeithanExample()
|
|
53
|
+
|
|
54
|
+
# Characteristic concentration scales for T and M.
|
|
55
|
+
T_0, M_0 = sp.symbols('T_0 M_0', positive=True)
|
|
56
|
+
|
|
57
|
+
# consider a dimensionalisation where the scaling factors for C0, C1, C2, C3, C4, C5, C6 are T_0.
|
|
58
|
+
nondim = {m_example.T: T_0, m_example.M: M_0}
|
|
59
|
+
for sym in [m_example.C0, m_example.C1, m_example.C2, m_example.C3, m_example.C4, m_example.C5, m_example.C6]:
|
|
60
|
+
# All complexes share the same concentration scale T_0.
|
|
61
|
+
nondim[sym] = T_0
|
|
62
|
+
|
|
63
|
+
# Non-dimensionalise the CRN given this particular non-dimensionalisation.
|
|
64
|
+
# Time scaling, via K_T, can be provided if desired.
|
|
65
|
+
res = process_CRN_given_nondimensionalisation(m_example._S, m_example._V, m_example._X, nondim=nondim, basis_type="Laurent", return_all_families=return_all_families)
|
|
66
|
+
return res
|
|
67
|
+
|
|
68
|
+
# Choose which example to run and whether to return all families. If return_all_families is true,
|
|
69
|
+
# all families where K_T is chosen to minimise the number of free parameters will be printed.
|
|
70
|
+
example_name = "Michaelis-Menten"
|
|
71
|
+
return_all_families = True
|
|
72
|
+
match example_name:
|
|
73
|
+
case "Michaelis-Menten":
|
|
74
|
+
all_results = Michaelis_Menten_example(return_all_families=return_all_families)
|
|
75
|
+
case "Kim-Forger":
|
|
76
|
+
all_results = Kim_Forger_example(return_all_families=return_all_families)
|
|
77
|
+
case _:
|
|
78
|
+
all_results = McKeithan_example(return_all_families=return_all_families)
|
|
79
|
+
|
|
80
|
+
# Analyse the results and print the analysis (if verbose=True).
|
|
81
|
+
all_transformed_results = analyse_results(all_results, verbose=True)
|