From e3d32aaa6a747b54b183b7d77557afed5b6caa47 Mon Sep 17 00:00:00 2001 From: Tijs Alleman Date: Tue, 8 Oct 2024 21:16:24 -0400 Subject: [PATCH] Change 'states' --> 'initial_states' when initializing model (#102) --- README.md | 2 +- docs/models.md | 12 ++++++------ docs/quickstart.md | 12 ++++++------ docs/workflow.md | 4 ++-- src/pySODM/models/base.py | 16 ++++++---------- tutorials/SIR/workflow_tutorial.py | 4 ++-- .../calibrate_intrinsic_kinetics.py | 2 +- tutorials/influenza_1718/calibration.py | 3 ++- 8 files changed, 26 insertions(+), 29 deletions(-) diff --git a/README.md b/README.md index 0e38ae5..af87591 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Does other simulation software exist in Python? Sure, but most of them hold your - Version 0.2.4 (2023-12-04, PR #62) > Validated the use of Python 3.11. Efficiency gains in simulation of jump processes. Ommitted dependency on Numba. All changes related to publishing our software manuscript in Journal of Computational Science. Improved nomenclature in model defenition. - IN PROGRESS: 0.2.5 - > Validated the use of Python 3.12. Validated pySODM on macOS Sonoma 14.5. 'draw functions' only have 'parameters' as mandatory input, followed by an arbitrary number of additional parameters (PR #75). Tutorial environment can now be found in `tutorial_env.yml` and was renamed `PYSODM-TUTORIALS` (PR #76). Users can choose when the simulation starts when calibrating a model (PR #92). Initial model states can now be a function returning a dictionary of states. This initial condition function can have arguments, which become part of the model's parameters, and can therefore be optimised (PR #99). Deprecation of legacy 'warmup' parameter (PR #100). + > Validated the use of Python 3.12. Validated pySODM on macOS Sonoma 14.5. 'draw functions' only have 'parameters' as mandatory input, followed by an arbitrary number of additional parameters (PR #75). Tutorial environment can now be found in `tutorial_env.yml` and was renamed `PYSODM-TUTORIALS` (PR #76). Users can choose when the simulation starts when calibrating a model (PR #92). Initial model states can now be a function returning a dictionary of states. This initial condition function can have arguments, which become part of the model's parameters, and can therefore be optimised (PR #99). Deprecation of legacy 'warmup' parameter (PR #100). Change 'states' --> 'initial_states' as input needed to initialize a model (PR #102). - Version 0.1 (2022-12-23, PR #14) > Application pySODM to three use cases. Documentation website. Unit tests for ODE, JumpProcess and calibration. - Version 0.1.1 (2023-01-09, PR #20) diff --git a/docs/models.md b/docs/models.md index 4f089fe..6d72e56 100644 --- a/docs/models.md +++ b/docs/models.md @@ -48,7 +48,7 @@ To intialize this model, the following arguments must be provided. **Parameters:** -* **states** (dict or callable) - Initial states. If a dictionary. Keys: names of model states. Values: initial values of model states. The dictionary does not need to contain all model states, missing states are filled with zeros upon initialization. If a callable (*initial condition function*): a function that creates such a dictionary. +* **initial_states** (dict or callable) - Initial condition. If a dictionary. Keys: names of model states. Values: initial values of model states. The dictionary does not need to contain all model states, missing states are filled with zeros upon initialization. If a callable (*initial condition function*): a function that creates such a dictionary. * **parameters** (dict) - Model parameters. Keys: names of parameters. Values: values of parameters. A key,value pair must be provided for all parameter names listed in `parameters` and `stratified_parameters` of the model declaration. If *time dependent parameter functions* with additional parameters are used, these parameters must be included as well. If an *initial condition function* with parameters is used, these parameters must be included as well. @@ -59,7 +59,7 @@ To intialize this model, the following arguments must be provided. For our example, ```python -model = MY_MODEL(states={'Y1': 1000, 'Y2': 0}, parameters={'alpha': 1}) +model = MY_MODEL(initial_states={'Y1': 1000, 'Y2': 0}, parameters={'alpha': 1}) ``` Or using an *initial condition function*, @@ -68,7 +68,7 @@ Or using an *initial condition function*, def initial_condition_function(Y1_0): return {'Y1': Y1_0, 'Y2': 0} -model = MY_MODEL(states=initial_condition_function, parameters={'alpha': 1, 'Y1_0': 1000}) +model = MY_MODEL(initial_states=initial_condition_function, parameters={'alpha': 1, 'Y1_0': 1000}) ``` The parameters of the initial condition function become a part of the model's parameters and can therefore be optimised. @@ -157,7 +157,7 @@ To intialize the user-defined model class, the following arguments must be provi **Parameters:** -* **states** (dict or callable) - Initial states. If a dictionary. Keys: names of model states. Values: initial values of model states. The dictionary does not need to contain all model states, missing states are filled with zeros upon initialization. If a callable (*initial condition function*): a function that creates such a dictionary. +* **initial_states** (dict or callable) - Initial condition. If a dictionary. Keys: names of model states. Values: initial values of model states. The dictionary does not need to contain all model states, missing states are filled with zeros upon initialization. If a callable (*initial condition function*): a function that creates such a dictionary. * **parameters** (dict) - Model parameters. Keys: names of parameters. Values: values of parameters. A key,value pair must be provided for all parameter names listed in `parameters` and `stratified_parameters` of the model declaration. If *time dependent parameter functions* with additional parameters are used, these parameters must be included as well. @@ -168,7 +168,7 @@ To intialize the user-defined model class, the following arguments must be provi For our example, ```python -model = MY_MODEL(states={'Y1': 1000, 'Y2': 0}, parameters={'alpha': 1}) +model = MY_MODEL(initial_states={'Y1': 1000, 'Y2': 0}, parameters={'alpha': 1}) ``` Or using an *initial condition function*, @@ -177,7 +177,7 @@ Or using an *initial condition function*, def initial_condition_function(Y1_0): return {'Y1': Y1_0, 'Y2': 0} -model = MY_MODEL(states=initial_condition_function, parameters={'alpha': 1, 'Y1_0': 1000}) +model = MY_MODEL(initial_states=initial_condition_function, parameters={'alpha': 1, 'Y1_0': 1000}) ``` The parameters of the initial condition function become a part of the model's parameters and can therefore be optimised. diff --git a/docs/quickstart.md b/docs/quickstart.md index 238f989..ca9688f 100644 --- a/docs/quickstart.md +++ b/docs/quickstart.md @@ -41,10 +41,10 @@ class SIR(ODE): return dS, dI, dR ``` -To initialize the model, provide a dictionary containing the initial values of the model states and a dictionary containing all model parameters. Undefined initial states are automatically filled with zeros. +To initialize the model, provide a dictionary containing the initial condition and a dictionary containing all model parameters. Undefined initial states are automatically filled with zeros. ```python -model = SIR(states={'S': 1000, 'I': 1}, parameters={'beta': 0.35, 'gamma': 5}) +model = SIR(initial_states={'S': 1000, 'I': 1}, parameters={'beta': 0.35, 'gamma': 5}) ``` Alternatively, use an *initial condition function* to define the initial states, @@ -55,7 +55,7 @@ def initial_condition_function(S0): return {'S': S0, 'I': 1} # that become part of the model's parameters and can be optimised.. -model = SIR(states=initial_condition_function, parameters={'beta': 0.35, 'gamma': 5, 'S0': 1000}) +model = SIR(initial_states=initial_condition_function, parameters={'beta': 0.35, 'gamma': 5, 'S0': 1000}) ``` Simulate the model using its `sim()` method. pySODM supports the use of dates to index simulations, string representations of dates with the format `'yyyy-mm-dd'` as well as `datetime.datetime()` can be used. @@ -128,7 +128,7 @@ class stratified_SIR(ODE): When initializing your model, provide a dictionary containing coordinates for every dimension declared previously. In the example below, we'll declare four age groups: 0-5, 5-15, 15-65 and 65-120 year olds. **All** model states are now 1D vectors of shape `(4,)`. ```python -model = stratified_SIR(states={'S': 1000*np.ones(4), 'I': np.ones(4)}, +model = stratified_SIR(initial_states={'S': 1000*np.ones(4), 'I': np.ones(4)}, parameters={'beta': 0.35, 'gamma': 5}, coordinates={'age_groups': ['0-5','5-15', '15-65','65-120']}) out = model.sim(121) @@ -192,7 +192,7 @@ params={'alpha': np.array([0.05, 0.1, 0.2, 0.15]), 'gamma': 5, 'beta': 7} init_states = {'S': [606938, 1328733, 7352492, 2204478], 'S_v': 1e6, 'I_v': 2} coordinates={'age_group': ['0-5','5-15', '15-65','65-120']} # Initialize model -model = ODE_SIR_SI(states=init_states, parameters=params, coordinates=coordinates) +model = ODE_SIR_SI(initial_states=init_states, parameters=params, coordinates=coordinates) # Simulate the model out = model.sim(120) print(out) @@ -321,7 +321,7 @@ def vary_my_parameter(t, states, param, an_additional_parameter): When initialising the model, all we need to do is use the `time_dependent_parameters` keyword to declare what parameter our TDPF should be applied to. Additional parameters introduced in TDPFs, in this example `an_additional_parameter`, should be added to the parameters dictionary. ```python -model = SIR(states={'S': 1000, 'I': 1}, +model = SIR(initial_states={'S': 1000, 'I': 1}, parameters={'beta': 0.35, 'gamma': 5, 'an_additional_parameter': any_datatype_you_want}, time_dependent_parameters={'beta': vary_my_parameter}) ``` \ No newline at end of file diff --git a/docs/workflow.md b/docs/workflow.md index 331bef9..92138bd 100644 --- a/docs/workflow.md +++ b/docs/workflow.md @@ -126,7 +126,7 @@ class ODE_SIR(ODE): After defining our model, we'll initialize it by supplying a dictionary of initial states and a dictionary of model parameters. In this example, we'll assume the disease spreads in a relatively small population of 1000 individuals. At the start of the simulation we'll assume there is one "patient zero". There's no need to define the number of recovered individuals as undefined states are automatically set to zero by pySODM. ```python -model = ODE_SIR(states={'S': 1000, 'I': 1}, parameters={'beta': 0.35, 'gamma': 5}) +model = ODE_SIR(initial_states={'S': 1000, 'I': 1}, parameters={'beta': 0.35, 'gamma': 5}) ``` ### Calibrating the model @@ -409,7 +409,7 @@ We will apply this function to the infectivity parameter `beta`, and declare thi model.parameters.update({'start_measures': '2023-01-21'}) # Initialize the model with the time dependent parameter funtion -model_with = ODE_SIR(states=init_states, parameters=model.parameters, +model_with = ODE_SIR(initial_states=init_states, parameters=model.parameters, time_dependent_parameters={'beta': lower_infectivity}) ``` diff --git a/src/pySODM/models/base.py b/src/pySODM/models/base.py index c2330a0..aa6eeb2 100644 --- a/src/pySODM/models/base.py +++ b/src/pySODM/models/base.py @@ -22,7 +22,7 @@ class JumpProcess: ---------- To initialise the model, provide following inputs: - states : dictionary + initial_states : dictionary contains the initial values of all non-zero model states, f.i. for an SIR model, e.g. {'S': 1000, 'I': 1} initialising zeros is not required @@ -46,17 +46,15 @@ class JumpProcess: dimensions = None dimensions_per_state = None - def __init__(self, states, parameters, coordinates=None, time_dependent_parameters=None): + def __init__(self, initial_states, parameters, coordinates=None, time_dependent_parameters=None): # Add a suffix _names to all user-defined name declarations self.states_names = self.states self.parameters_names = self.parameters self.parameters_stratified_names = self.stratified_parameters self.dimensions_names = self.dimensions - self.states = states + self.states = initial_states parameters = parameters - - # Do not undergo manipulation during model initialization (#TODO: no input check?) self.coordinates = coordinates self.time_dependent_parameters = time_dependent_parameters @@ -499,7 +497,7 @@ class ODE: ---------- To initialise the model, provide following inputs: - states : dictionary or callable + initial_states : dictionary or callable contains the initial values of all non-zero model states, f.i. for an SIR model, e.g. {'S': 1000, 'I': 1} initialising zeros is not required @@ -525,17 +523,15 @@ class ODE: dimensions_per_state = None # TODO: states, parameters, dimensions --> list containing str (check input!) - def __init__(self, states, parameters, coordinates=None, time_dependent_parameters=None): + def __init__(self, initial_states, parameters, coordinates=None, time_dependent_parameters=None): # Add a suffix _names to all user-defined name declarations self.states_names = self.states self.parameters_names = self.parameters self.parameters_stratified_names = self.stratified_parameters self.dimensions_names = self.dimensions - self.states = states + self.states = initial_states parameters = parameters - - # Do not undergo manipulation during model initialization self.coordinates = coordinates self.time_dependent_parameters = time_dependent_parameters diff --git a/tutorials/SIR/workflow_tutorial.py b/tutorials/SIR/workflow_tutorial.py index 047f0f4..c08fba8 100644 --- a/tutorials/SIR/workflow_tutorial.py +++ b/tutorials/SIR/workflow_tutorial.py @@ -67,7 +67,7 @@ def integrate(t, S, I, R, beta, gamma): return dS, dI, dR # Initialize model -model = ODE_SIR(states={'S': 1000, 'I': 1}, parameters={'beta':0.35, 'gamma':5}) +model = ODE_SIR(initial_states={'S': 1000, 'I': 1}, parameters={'beta':0.35, 'gamma':5}) # Simulate from t=0 until t=121 out = model.sim([0, 121]) @@ -216,7 +216,7 @@ def draw_fcn(parameters, samples, ramp_length): model.parameters.update({'start_measures': end_date}) # Initialize the model with the time dependent parameter funtion - model_with = ODE_SIR(states=model.initial_states, parameters=model.parameters, time_dependent_parameters={'beta': lower_infectivity}) + model_with = ODE_SIR(initial_states=model.initial_states, parameters=model.parameters, time_dependent_parameters={'beta': lower_infectivity}) # Simulate the model out_with = model_with.sim([start_date, end_date+pd.Timedelta(days=2*28)], N=100, draw_function=draw_fcn, diff --git a/tutorials/enzyme_kinetics/calibrate_intrinsic_kinetics.py b/tutorials/enzyme_kinetics/calibrate_intrinsic_kinetics.py index 56d0399..d039bf5 100644 --- a/tutorials/enzyme_kinetics/calibrate_intrinsic_kinetics.py +++ b/tutorials/enzyme_kinetics/calibrate_intrinsic_kinetics.py @@ -55,7 +55,7 @@ # Define an initial condition init_states = {'S': 46, 'A': 61, 'W': 37, 'Es': 0} # Initialize model -model = PPBB_model(states=init_states, parameters=params) +model = PPBB_model(initial_states=init_states, parameters=params) ############### ## Load data ## diff --git a/tutorials/influenza_1718/calibration.py b/tutorials/influenza_1718/calibration.py index 020f768..255b8dd 100644 --- a/tutorials/influenza_1718/calibration.py +++ b/tutorials/influenza_1718/calibration.py @@ -119,7 +119,8 @@ # Define model coordinates coordinates={'age_group': age_groups} # Initialize model -model = influenza_model(states=init_states,parameters=params,coordinates=coordinates,time_dependent_parameters={'N': contact_function}) +model = influenza_model(initial_states=init_states, parameters=params, coordinates=coordinates, + time_dependent_parameters={'N': contact_function}) ##################### ## Calibrate model ##