diff --git a/__init__.py b/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/biosimulator_processes/__init__.py b/biosimulator_processes/__init__.py index 731a630b0..e23786aee 100644 --- a/biosimulator_processes/__init__.py +++ b/biosimulator_processes/__init__.py @@ -19,7 +19,7 @@ ('amici', 'amici_process.AmiciProcess')] STEPS_TO_REGISTER = [ - ('get_sbml_step', 'get_sbml.GetSbmlStep'), + # ('get_sbml_step', 'get_sbml.GetSbmlStep'), ('plotter', 'viz.CompositionPlotter'), ('plotter2d', 'viz.Plotter2d')] diff --git a/biosimulator_processes/data_model/sed_data_model.py b/biosimulator_processes/data_model/sed_data_model.py index 5cb2aa1db..f95be096b 100644 --- a/biosimulator_processes/data_model/sed_data_model.py +++ b/biosimulator_processes/data_model/sed_data_model.py @@ -3,11 +3,11 @@ from types import NoneType import requests from abc import abstractmethod, ABC + from pydantic import Field, create_model -from biosimulator_processes.data_model import _BaseClass +from biosimulator_processes.data_model import _BaseClass -__all__ = ['SedDataModel'] @dataclass class SimulationModelParameter(_BaseClass): diff --git a/biosimulator_processes/data_model/verify_data_model.py b/biosimulator_processes/data_model/verify_data_model.py index bb12ecc7a..f3842cb96 100644 --- a/biosimulator_processes/data_model/verify_data_model.py +++ b/biosimulator_processes/data_model/verify_data_model.py @@ -1,5 +1,9 @@ from dataclasses import dataclass +from process_bigraph.experiments.parameter_scan import RunProcess + +from biosimulator_processes import CORE + @dataclass class OutputAspectVerification: @@ -7,3 +11,22 @@ class OutputAspectVerification: is_verified: bool expected_data: any process_data: any + + +class ODEProcess(RunProcess): + def __init__(self, config=None, core=CORE, **kwargs): + """ODE-based wrapper of RunProcess from process_bigraph. + + kwargs: + 'process_address': 'string', + 'process_config': 'tree[any]', + 'observables': 'list[path]', + 'timestep': 'float', + 'runtime': 'float' + """ + configuration = config or kwargs + configuration['observables'] = kwargs.get('observables') or self.set_observables() + super().__init__(configuration, core) + + def set_observables(self): + return [(k, v) for k, v in self.process.inputs().items()] diff --git a/biosimulator_processes/instance.py b/biosimulator_processes/instance.py new file mode 100644 index 000000000..939d6fe00 --- /dev/null +++ b/biosimulator_processes/instance.py @@ -0,0 +1,59 @@ +import matplotlib.pyplot as plt +from process_bigraph.experiments.parameter_scan import RunProcess + +from biosimulator_processes import CORE +from biosimulator_processes.steps.ode_simulation import ODEProcess + + +def get_observables(proc: RunProcess): + observables = [] + for port_name, port_dict in proc.process.inputs().items(): + if port_name.lower() == 'floating_species_concentrations': + if isinstance(port_dict, dict): + for name, typeVal in port_dict.items(): + obs = [port_name, name] + observables.append(obs) + else: + obs = [port_name] + observables.append(obs) + return observables + + +def generate_ode_instance(process_address: str, model_fp: str, step_size: float, duration: float) -> ODEProcess: + ode_process_config = {'model': {'model_source': model_fp}} + proc = RunProcess( + config={ + 'process_address': process_address, + 'process_config': ode_process_config, + 'timestep': step_size, + 'runtime': duration}, + core=CORE) + obs = get_observables(proc) + + return ODEProcess( + address=process_address, + model_fp=model_fp, + observables=obs, + step_size=step_size, + duration=duration) + + +def plot_ode_output_data(data: dict): + time = data['results']['time'] + spec_outputs = [] + for name, output in data['results']['floating_species_concentrations'].items(): + spec_outputs.append({name: output}) + + # Plotting the data + plt.figure(figsize=(10, 8)) + for output in spec_outputs: + for name, out in output.items(): + plt.plot(time, out, label=name) + + plt.xlabel('Time') + plt.ylabel('Concentration') + plt.title('Species Concentrations Over Time') + plt.legend() + plt.grid(True) + plt.show() + diff --git a/biosimulator_processes/processes/instance.py b/biosimulator_processes/processes/instance.py deleted file mode 100644 index c05d75f15..000000000 --- a/biosimulator_processes/processes/instance.py +++ /dev/null @@ -1,62 +0,0 @@ -from dataclasses import dataclass -from typing import * - -from process_bigraph.experiments.parameter_scan import RunProcess - -from biosimulator_processes import CORE -from biosimulator_processes.data_model import _BaseClass - - -class ODEProcess(RunProcess): - def __init__(self, config=None, core=None): - super().__init__(config, core) - - def run(self, input_state=None): - return self.update(input_state or {}) - - -@dataclass -class ProcessObservable(_BaseClass): - path_root: str - root_children: list[str] - path: list[str] = None - - def __post_init__(self): - self.path = [self.path_root, *self.root_children] - - -def generate_ode_process_instance( - entrypoint: Union[str, dict[str, any]], # either sbml model path or sed_model dict which conforms to the spec in sed data model in this repo. - process_address: str, - observables: List[List[str]], - step_size: float, - duration: float, - **process_config -) -> ODEProcess: - """Generate loaded ode process. - - Args: - entrypoint (Union[str, dict[str, any]]): either sbml model path or sed_model dict which conforms to the spec in sed data model in this repo. - process_address (str): the address in registry of the process to be loaded as per the CORE registry - observables (list[str]): observables to be loaded in path form - step_size (float): the step size in seconds - duration (float): the duration in seconds - **process_config (dict): the process config kwargs specific to the simulator process - - Returns: - ODEProcess instance - """ - if not isinstance(entrypoint, str or dict[str, any]): - raise ValueError('entrypoint must be a string sbml model path or a dict defining SED_MODEL within biosimulator_processes.data_model.sed_data_model') - - config = {'model': {'model_source': entrypoint, **process_config}} if isinstance(entrypoint, str) else entrypoint - return ODEProcess( - config={ - 'process_address': f'local:{process_address}', - 'process_config': config, - 'observables': observables, - 'timestep': step_size, - 'runtime': duration - }, - core=CORE) - diff --git a/biosimulator_processes/steps/ode_simulation.py b/biosimulator_processes/steps/ode_simulation.py index 59582a98e..d24a6675f 100644 --- a/biosimulator_processes/steps/ode_simulation.py +++ b/biosimulator_processes/steps/ode_simulation.py @@ -1,5 +1,9 @@ import abc + from process_bigraph import Step +from process_bigraph.experiments.parameter_scan import RunProcess + +from biosimulator_processes import CORE class OdeSimulation(Step, abc.ABC): @@ -37,3 +41,35 @@ def set_global_parameters(self): @abc.abstractmethod def set_reactions(self): pass + + +class ODEProcess(RunProcess): + def __init__(self, + address: str, + model_fp: str, + observables: list[list[str]], + step_size: float, + duration: float, + config=None, + core=CORE, + **kwargs): + """ + Kwargs: + 'process_address': 'string', + 'process_config': 'tree[any]', + 'observables': 'list[path]', + 'timestep': 'float', + 'runtime': 'float' + """ + configuration = config or {} + if not config: + configuration['process_address'] = address + configuration['timestep'] = step_size + configuration['runtime'] = duration + configuration['process_config'] = {'model': {'model_source': model_fp}} + configuration['observables'] = observables + super().__init__(config=configuration, core=core) + + def run(self, inputs=None): + input_state = inputs or {} + return self.update(input_state) diff --git a/composer-notebooks/amici_process_composer.ipynb b/composer-notebooks/amici_process_composer.ipynb index b3ae9763b..5b6f1ebd3 100644 --- a/composer-notebooks/amici_process_composer.ipynb +++ b/composer-notebooks/amici_process_composer.ipynb @@ -11,6 +11,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "import sys\n", "\n", @@ -27,8 +28,7 @@ "from biosimulator_processes.data_model.compare_data_model import ODEComparisonDocument, DocumentFactory\n", "from biosimulator_processes import CORE\n", "from process_bigraph import Composite, pp" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -41,6 +41,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "#### Step 1: Define the document to be read by the Composite, which is implemented by the Process.\n", "biomodel_id = 'BIOMD0000000630'\n", @@ -57,8 +58,7 @@ " model_filepath=model_fp)\n", "\n", "comparison_document.composite" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -71,6 +71,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "# Amici Model from compiled module\n", "sbml_importer = amici.SbmlImporter(model_fp)\n", @@ -86,8 +87,7 @@ "compiled_model = model_module.getModel()\n", "# instantiate solver\n", "method = compiled_model.getSolver()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -100,6 +100,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "# From load sbml model module \n", "sbml_reader = libsbml.SBMLReader()\n", @@ -108,8 +109,7 @@ "species_objects_list = sbml_model.getListOfSpecies()\n", "floating_species_list = [s.getId() for s in species_objects_list]\n", "floating_species_initial = dict(zip(floating_species_list, [s.getInitialConcentration() for s in species_objects_list]))" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -122,11 +122,11 @@ }, "collapsed": false }, + "outputs": [], "source": [ "for s in species_objects_list:\n", " print(s.getInitialAmount())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -139,10 +139,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "[s.getId() for s in species_objects_list]" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -155,10 +155,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "floating_species_initial" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -171,10 +171,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "dict(zip(floating_species_list, [s.getInitialConcentration() for s in species_objects_list]))" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -187,10 +187,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "floating_species_initial" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -203,10 +203,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "species_objects_list = sbml_model.getListOfSpecies()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -219,12 +219,12 @@ }, "collapsed": false }, + "outputs": [], "source": [ "for i, s in enumerate(species_objects_list):\n", " print(s.getId())\n", " print(i, s.getInitialConcentration())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -237,10 +237,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "dir(model)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -253,10 +253,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "model.getParameters()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -269,10 +269,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "model.getParameterList()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -285,10 +285,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "model.getParameterIds()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -297,10 +297,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "model_parameters_list = model.getP" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -313,10 +313,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "dir(sbml_model)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -329,10 +329,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "model_parameter_objects = sbml_model.getListOfParameters()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -345,10 +345,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "model_parameter_objects" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -361,13 +361,13 @@ }, "collapsed": false }, + "outputs": [], "source": [ "for m in model_parameter_objects:\n", " print(dir(m))\n", " print(m.getValue())\n", " print(m.getName())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -376,12 +376,12 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "model_parameter_objects = sbml_model.getListOfParameters()\n", "model_parameters_list = [param.getName() for param in model_parameter_objects]\n", "model_parameters_values = [param.getValue() for param in model_parameter_objects]" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -394,10 +394,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "dir(sbml_model)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -410,13 +410,13 @@ }, "collapsed": false }, + "outputs": [], "source": [ "reaction_objects = sbml_model.reactions\n", "reaction_list = [reaction.getName() for reaction in reaction_objects]\n", "\n", "reaction_list" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -429,10 +429,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "dir(reaction_objects[0])" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -445,10 +445,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "reaction_objects[0].getProduct()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -461,10 +461,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "dir(sbml_model)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -477,6 +477,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "from biosimulator_processes.processes.amici_process import AmiciProcess\n", "\n", @@ -488,8 +489,7 @@ " sbml_model_fp=model_fp)\n", "\n", "amici_process_document" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -502,10 +502,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_process_config = amici_process_document[process_id]['config']" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -518,10 +518,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_process_config" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -534,12 +534,12 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_workflow = Composite(\n", " config={'state': amici_process_document},\n", " core=CORE)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -552,10 +552,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_process: AmiciProcess = amici_workflow.state[process_id]['instance']" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -568,10 +568,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_process.initial_state()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -584,10 +584,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_process.reaction_list" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -600,10 +600,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_process.initial_state()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -616,6 +616,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "# Let's compare that against copasi process\n", "from biosimulator_processes.processes.copasi_process import CopasiProcess\n", @@ -623,8 +624,7 @@ "\n", "copasi_process: CopasiProcess = CopasiProcess(\n", " config=comparison_document.composite['copasi_0']['config'])" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -637,10 +637,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "copasi_process.outputs() == amici_process.outputs()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -653,10 +653,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "amici_process.initial_state() == copasi_process.initial_state()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -669,10 +669,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "copasi_process.reaction_list == amici_process.reaction_list" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -681,8 +681,8 @@ "metadata": { "collapsed": false }, - "source": [], - "outputs": [] + "outputs": [], + "source": [] } ], "metadata": { diff --git a/composer-notebooks/copasi_process_composer.ipynb b/composer-notebooks/copasi_process_composer.ipynb index c0d90b5ab..09c7acc4f 100644 --- a/composer-notebooks/copasi_process_composer.ipynb +++ b/composer-notebooks/copasi_process_composer.ipynb @@ -21,12 +21,12 @@ }, "collapsed": false }, + "outputs": [], "source": [ "import sys \n", "\n", "sys.path.insert(0, '..')" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -39,13 +39,13 @@ }, "collapsed": false }, + "outputs": [], "source": [ "import os \n", "from process_bigraph import pp, pf \n", "from biosimulator_processes.data_model import *\n", "from biosimulator_processes.biosimulator_builder import BiosimulatorBuilder" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -58,10 +58,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "from bigraph_schema.registry import map_type_to_pydantic" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -74,6 +74,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "c = {'process_name': 'Rose'}\n", "\n", @@ -83,8 +84,7 @@ "tree = StringTree(a=10, b=20, c=30)\n", "\n", "tree" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -103,10 +103,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "b = BiosimulatorBuilder()" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -139,12 +139,12 @@ }, "collapsed": false }, + "outputs": [], "source": [ "model_filepath = '../biosimulator_processes/model_files/BIOMD0000000061_url.xml'\n", "\n", "os.path.exists(model_filepath)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -153,12 +153,12 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "# Uncomment if you wish to inspect the species referenced below\n", "# model_from_file = load_model(model_filepath)\n", "# get_species(model=model_from_file)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -167,6 +167,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "# 1. specify model changes (we know the model specs as we are providing the file. TODO: allow users to introspect the model before change)\n", "process_model_changes = TimeCourseModelChanges(\n", @@ -175,8 +176,7 @@ "\n", "\n", "pp(process_model_changes.model_dump())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -185,6 +185,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "# 2. define the model schema to be used by the composite process (one of the copasiprocess config parameters)\n", "\n", @@ -197,8 +198,7 @@ "\n", "\n", "pp(process_model_from_file.model_dump())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -207,6 +207,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "# 3. Define config schema to be used as 'config' parameter of Process constructor\n", "process_config_from_file = CopasiProcessConfigSchema(\n", @@ -217,8 +218,7 @@ "\n", "\n", "pp(process_config_from_file.model_dump())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -227,10 +227,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "process_config_from_file.process_name, process_config_from_file.method, process_config_from_file.model" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -239,6 +239,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "# 4. Add the process instance by the name of 'simple_copasi' to the builder\n", "\n", @@ -248,8 +249,7 @@ " model=process_config_from_file.model,\n", " method=process_config_from_file.method\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -268,6 +268,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "# Uncomment if you wish to introspect the model referred below\n", "# from basico import *\n", @@ -277,8 +278,7 @@ "# biomodel_id = 'BIOMD0000000861'\n", "# biomodel = load_biomodel(biomodel_id)\n", "# get_species(model=biomodel)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -287,12 +287,12 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "# reaction_names = get_reactions(model=biomodel)\n", "# \n", "# reaction_names" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -301,6 +301,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "rparam = ReactionParameter(\n", " parameter_name='EpoRpRJAK2',\n", @@ -321,8 +322,7 @@ " reaction_name='reaction_11',\n", " reaction_scheme='A + B -> C'\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -331,12 +331,12 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "biomodel_process_changes = TimeCourseModelChanges(\n", " reaction_changes=[rc1, rc2]\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -345,10 +345,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "pp(biomodel_process_changes.model_dump())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -357,6 +357,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "biomodel_id = 'BIOMD0000000861'\n", "\n", @@ -369,8 +370,7 @@ ")\n", "\n", "pp(biomodel_process_model.model_dump())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -379,6 +379,7 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "biomodel_process_config = CopasiProcessConfigSchema(\n", " process_name='copasi_process_from_biomodel',\n", @@ -388,8 +389,7 @@ "\n", "\n", "pp(biomodel_process_config.model_dump())" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -408,14 +408,14 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "b[biomodel_process_config.process_name].add_process(\n", " name='CopasiProcess',\n", " model=biomodel_process_config.model,\n", " method=biomodel_process_config.method\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -434,10 +434,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "b.visualize()" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -456,12 +456,12 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "b.connect_all(append_to_store_name='_store')\n", "\n", "b" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -470,10 +470,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "b.visualize()" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -492,10 +492,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "composite = b.generate()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -504,10 +504,10 @@ "metadata": { "collapsed": false }, + "outputs": [], "source": [ "composite.run(10)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -530,10 +530,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2 = BiosimulatorBuilder()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -546,13 +546,13 @@ }, "collapsed": false }, + "outputs": [], "source": [ "single_process_model = TimeCourseModel(\n", " model_source=ModelFilepath(value=model_filepath),\n", " model_id='BIOMD0000000061'\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -565,6 +565,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "single_process_config = CopasiProcessConfigSchema(\n", " process_name='single_copasi_process',\n", @@ -573,8 +574,7 @@ ")\n", "\n", "pp(single_process_config.model_dump())" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -587,14 +587,14 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2[single_process_config.process_name].add_process(\n", " name='CopasiProcess',\n", " model=single_process_config.model,\n", " method=single_process_config.method\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -607,10 +607,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2.connect_all(append_to_store_name='_store')" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -623,10 +623,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2.visualize()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -639,10 +639,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "pp(b2)" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -655,10 +655,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "composite2 = b2.generate()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -671,12 +671,12 @@ }, "collapsed": false }, + "outputs": [], "source": [ "# TODO: try different solvers for this: certainly stochastic\n", "\n", "composite2.run(10)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -699,6 +699,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "from biosimulator_processes.data_model import EmitterConfig, EmittedType\n", "\n", @@ -711,8 +712,7 @@ " ],\n", " name='emitter'\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -725,6 +725,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "# b2[emitter_config.name].add_process(\n", "# name='ram-emitter',\n", @@ -738,8 +739,7 @@ " 'floating_species': 'tree[float]',\n", " 'time': 'float'}\n", ")" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -752,10 +752,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2.connect_all()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -768,10 +768,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2.visualize()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -784,10 +784,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -800,10 +800,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "composite3 = b2.generate()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -816,10 +816,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "composite3.run(10)" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -842,10 +842,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "b2.write(filename='single_copasi_process_with_emitter')" - ], - "outputs": [] + ] }, { "cell_type": "markdown", @@ -866,10 +866,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "!ls out" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -882,10 +882,10 @@ }, "collapsed": false }, + "outputs": [], "source": [ "!cat out/single_copasi_process_with_emitter.json" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -898,6 +898,7 @@ }, "collapsed": false }, + "outputs": [], "source": [ "import json \n", "\n", @@ -907,8 +908,7 @@ " \n", " \n", "data.keys()" - ], - "outputs": [] + ] }, { "cell_type": "code", @@ -917,8 +917,8 @@ "metadata": { "collapsed": false }, - "source": [], - "outputs": [] + "outputs": [], + "source": [] } ], "metadata": { diff --git a/composer-notebooks/tests.ipynb b/composer-notebooks/tests.ipynb index 80ea35e2f..49bee8fe0 100644 --- a/composer-notebooks/tests.ipynb +++ b/composer-notebooks/tests.ipynb @@ -2,14 +2,16 @@ "cells": [ { "cell_type": "code", + "execution_count": 2, "id": "initial_id", "metadata": { - "collapsed": true, "ExecuteTime": { "end_time": "2024-05-13T21:02:38.898151Z", "start_time": "2024-05-13T21:02:38.818296Z" - } + }, + "collapsed": true }, + "outputs": [], "source": [ "import itertools\n", "import numpy as np \n", @@ -29,31 +31,34 @@ "\n", "data = {}\n", "data['process_outputs'] = process_outputs" - ], - "execution_count": 2, - "outputs": [] + ] }, { + "cell_type": "code", + "execution_count": 3, + "id": "cb687937cff4c0dd", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:02:38.995881Z", "start_time": "2024-05-13T21:02:38.987678Z" } }, - "cell_type": "code", - "source": "data", - "id": "cb687937cff4c0dd", - "execution_count": 3, - "outputs": [] + "outputs": [], + "source": [ + "data" + ] }, { + "cell_type": "code", + "execution_count": 4, + "id": "6c7bb2899830d818", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:02:39.135699Z", "start_time": "2024-05-13T21:02:39.133660Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def generate_pairwise_mapping(results: dict, rTol: float, aTol: float):\n", " \"\"\"\n", @@ -64,19 +69,19 @@ " \n", " \"\"\"\n", " pass" - ], - "id": "6c7bb2899830d818", - "execution_count": 4, - "outputs": [] + ] }, { + "cell_type": "code", + "execution_count": 5, + "id": "7c717eafb0a6d919", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:02:39.305366Z", "start_time": "2024-05-13T21:02:39.302816Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "somelists = [\n", " [1, 2, 3],\n", @@ -85,32 +90,34 @@ "]\n", "for element in itertools.product(*somelists):\n", " print(element)" - ], - "id": "7c717eafb0a6d919", - "execution_count": 5, - "outputs": [] + ] }, { + "cell_type": "code", + "execution_count": 20, + "id": "efb17dd215b11b40", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:19:10.349879Z", "start_time": "2024-05-13T21:19:10.347102Z" } }, - "cell_type": "code", - "source": "results_data = {'sim_a': np.array([0.20, 0.30]), 'sim_b': np.array([0.43, 0.21]), 'sim_c': np.array([2.3, 0.34])}\n", - "id": "efb17dd215b11b40", - "execution_count": 20, - "outputs": [] + "outputs": [], + "source": [ + "results_data = {'sim_a': np.array([0.20, 0.30]), 'sim_b': np.array([0.43, 0.21]), 'sim_c': np.array([2.3, 0.34])}\n" + ] }, { + "cell_type": "code", + "execution_count": 33, + "id": "d74c83f75f844104", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:27:32.448609Z", "start_time": "2024-05-13T21:27:32.442161Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "prods = {}\n", "\n", @@ -125,19 +132,19 @@ "param_outputs = pd.DataFrame(outputs, columns=param_names, index=list(results_data.keys()))\n", "\n", "param_outputs" - ], - "id": "d74c83f75f844104", - "execution_count": 33, - "outputs": [] + ] }, { + "cell_type": "code", + "execution_count": 35, + "id": "b51cb2ccb94c925e", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:28:00.354363Z", "start_time": "2024-05-13T21:28:00.349166Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "col_vectors = np.stack(outputs, axis=1)\n", "\n", @@ -151,53 +158,53 @@ "feature_vals = pd.DataFrame(col_vectors, columns=feature_names, index=param_names)\n", "\n", "feature_vals" - ], - "id": "b51cb2ccb94c925e", - "execution_count": 35, - "outputs": [] + ] }, { + "cell_type": "code", + "execution_count": 12, + "id": "f49a1b5117217d01", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:10:45.013284Z", "start_time": "2024-05-13T21:10:45.009944Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "names = list(x.keys())\n", "vals = list(x.values())" - ], - "id": "f49a1b5117217d01", - "execution_count": 12, - "outputs": [] + ] }, { + "cell_type": "code", + "execution_count": 13, + "id": "645b85a1c8592be", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:10:45.157237Z", "start_time": "2024-05-13T21:10:45.154505Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "names_product = itertools.product(*names)\n", "\n", "for el in names_product:\n", " print(el)" - ], - "id": "645b85a1c8592be", - "execution_count": 13, - "outputs": [] + ] }, { + "cell_type": "code", + "execution_count": 14, + "id": "3c21aba2eac3298", "metadata": { "ExecuteTime": { "end_time": "2024-05-13T21:13:03.164130Z", "start_time": "2024-05-13T21:13:03.160288Z" } }, - "cell_type": "code", + "outputs": [], "source": [ "def generate_binary_combinations(elements):\n", " \"\"\"\n", @@ -229,18 +236,15 @@ "print(\"All possible combinations of elements:\")\n", "for combo in combinations:\n", " print(combo)" - ], - "id": "3c21aba2eac3298", - "execution_count": 14, - "outputs": [] + ] }, { - "metadata": {}, "cell_type": "code", "execution_count": null, - "source": "", "id": "1628409e45c78943", - "outputs": [] + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/demos/biolab_api_demo.ipynb b/demos/biolab_api_demo.ipynb deleted file mode 100644 index 0eee55ab7..000000000 --- a/demos/biolab_api_demo.ipynb +++ /dev/null @@ -1,473 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "8087f67dcdaefdee", - "metadata": { - "collapsed": false - }, - "source": [ - "# BioLab API Demo (BioLab container)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "c253d92e47737dd9", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:49.375459Z", - "start_time": "2024-05-01T18:23:49.229821Z" - } - }, - "source": [ - "# TODO: create sep repo and pypi for data model so that you can install it and import like `import sed_data as sed`" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "initial_id", - "metadata": { - "collapsed": true, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:49.375680Z", - "start_time": "2024-05-01T18:23:49.234219Z" - } - }, - "source": [ - "import sys\n", - "import os\n", - "\n", - "sys.path.insert(0, '..')" - ], - "outputs": [] - }, - { - "cell_type": "markdown", - "id": "572ce5fd9c49efcb", - "metadata": { - "collapsed": false - }, - "source": [ - "#### **_Experiment 1_**: Here we cross a boundary in the stack that is a biological simulation. We go from model configuration, to experiment. Thus, this tooling sits at that level: both experiment specification AND experiment execution. It's not just a way to specify an experiment, but it is also a way to run it, given the many knobs and buttons that you can use predefine and customize the way the actual model is being solved. Our users are seeking to be involved in an experiment as a \"stack\". We should make a bigger distinction between terms like \"model\"." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "e3218a2629726818", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:51.747571Z", - "start_time": "2024-05-01T18:23:49.237895Z" - } - }, - "source": [ - "from process_bigraph import pp\n", - "from biosimulator_processes.biosimulator_builder import BuildPrompter\n", - "from biosimulator_processes.data_model.sed_data_model import SedDataModel as sed " - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "871b58285775fb24", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:52.256123Z", - "start_time": "2024-05-01T18:23:51.745806Z" - } - }, - "source": [ - "# 1a. define a model for the process composition. In this case, just one model to be re-used as configuration for the processes we create:\n", - "tumor_control_biomodel_id = 'BIOMD0000000749'\n", - "simple_tc_model = sed.TimeCourseModel(model_source=tumor_control_biomodel_id)\n", - "\n", - "pp(simple_tc_model)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "1519914d8b9a85ce", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:52.257772Z", - "start_time": "2024-05-01T18:23:52.254603Z" - } - }, - "source": [ - "# 1b. view model info for model source:\n", - "\n", - "pp(simple_tc_model.source_info)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "a30f5e94167513c9", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:52.266338Z", - "start_time": "2024-05-01T18:23:52.258070Z" - } - }, - "source": [ - "# 1c. define a TimeCourse process instance using the above object as a parameter. The other parameter is method. See BasiCO documentation for more details on solvers\n", - "\n", - "simple_tc_process = sed.TimeCourseProcess(model=simple_tc_model, method='lsoda')" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "a9c15126dda87970", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:52.266655Z", - "start_time": "2024-05-01T18:23:52.261921Z" - } - }, - "source": [ - "# >> The process model instance is viewable as a dataclass...\n", - "\n", - "pp(simple_tc_process)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 8, - "id": "ba3d6e8bae50f216", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:52.268987Z", - "start_time": "2024-05-01T18:23:52.265517Z" - } - }, - "source": [ - "# >> ...or a dict:\n", - "\n", - "pp(simple_tc_process.to_dict())" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 9, - "id": "f6d099ae829fb063", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:52.319339Z", - "start_time": "2024-05-01T18:23:52.269208Z" - } - }, - "source": [ - "# 2. instantiate the prompter:\n", - "\n", - "prompter = BuildPrompter()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 10, - "id": "6ff0228586348da1", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:59.152054Z", - "start_time": "2024-05-01T18:23:52.273445Z" - } - }, - "source": [ - "# 3. add process(es) to the bigraph with the Time Course model instance we created above. For now, just one process will be added.\n", - "\n", - "prompter.add_single_process(config=simple_tc_process)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b833c7217603645c", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T18:23:59.157229Z", - "start_time": "2024-05-01T18:23:59.153391Z" - } - }, - "source": [ - "# 4. Inspect the builder instance within prompter:\n", - "\n", - "pp(prompter.builder_instance)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "8400f44e3a2e8433", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.155333Z" - } - }, - "source": [ - "# 5. Visualize the fully-connected composition:\n", - "\n", - "prompter.visualize_bigraph()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "38052757b3b95baa", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.156753Z" - } - }, - "source": [ - "# 6. Generate a composite engine and use to execute the bigraph that we just created:\n", - "\n", - "prompter.run()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "45ae5b121110cdce", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.158776Z" - } - }, - "source": [ - "# 7. Clear the builder and start from scratch, writing it out first:\n", - "\n", - "prompter.flush(fp='simple_single_demo')" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "79fbea4fa6708088", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.160556Z" - } - }, - "source": [ - "prompter.builder_instance" - ], - "outputs": [] - }, - { - "cell_type": "markdown", - "id": "b65a6fab79ad097c", - "metadata": { - "collapsed": false - }, - "source": [ - "#### **_Experiment 2_**: Load an SBML model from a specified model filepath and add Model changes to the composite before adding it to the bigraph. Here, we expect the user to be familiar enough with the model file they are passing to make individual species/parameter/reaction changes for specific species types. In the Caravagna model, for example, the species involved are T, E, I. Let's change the initial concentration for some of these as an example of model changes:" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "89739e0302d6b89a", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.162011Z" - } - }, - "source": [ - "caravagna_model_filepath = '../biosimulator_processes/model_files/Caravagna2010.xml'\n", - "print(os.path.exists(caravagna_model_filepath))" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "55e063c857e51f3", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.163295Z" - } - }, - "source": [ - "# first make the timecourse model which is easily configured with objects related to model changes\n", - "adjusted_tc_model_from_file = sed.TimeCourseModel(\n", - " model_source=caravagna_model_filepath, \n", - " model_changes=sed.TimeCourseModelChanges(\n", - " species_changes=sed.SpeciesChange(species_name='T', initial_concentration=0.234)\n", - " )\n", - ")\n", - "\n", - "\n", - "pp(adjusted_tc_model_from_file)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c1ddec005282e13f", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.164702Z" - } - }, - "source": [ - "adjusted_tc_process = sed.TimeCourseProcess(model=adjusted_tc_model_from_file, method='stochastic')\n", - "\n", - "pp(adjusted_tc_process)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "32b4be407a09f96", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.165980Z" - } - }, - "source": [ - "# add the process we just created with the prompter. The prompter will create a new instance of builder for us, if not passed:\n", - "\n", - "prompter.add_single_process(config=adjusted_tc_process)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "d0121977a95c320c", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.167039Z" - } - }, - "source": [ - "# visualize the adjusted creation\n", - "\n", - "prompter.visualize_bigraph()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a6e83469c5b8b93d", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.167933Z" - } - }, - "source": [ - "# view the builder document\n", - "\n", - "prompter.builder_instance.document()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "121064387d7729b0", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.168771Z" - } - }, - "source": [ - "# run the composite\n", - "\n", - "prompter.run()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "6918be74a9a99f7d", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.169791Z" - } - }, - "source": [ - "# stochastic works with Caravagna!!" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f160008fa3538b5", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T18:23:59.170806Z" - } - }, - "source": [], - "outputs": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/demos/compositions.ipynb b/demos/compositions.ipynb deleted file mode 100644 index 1161f850c..000000000 --- a/demos/compositions.ipynb +++ /dev/null @@ -1,615 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "source": [ - "import sys\n", - "\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "import requests\n", - "import json" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T08:45:09.699631Z", - "start_time": "2024-05-01T08:45:09.646937Z" - } - }, - "id": "24fc5d62890368dd", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 2, - "source": [ - "from biosimulator_processes.compare import ComparisonDocument\n", - "from biosimulator_processes import CORE\n", - "from process_bigraph import pp, Composite" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T08:45:13.511424Z", - "start_time": "2024-05-01T08:45:10.281028Z" - } - }, - "id": "1dc1ba69e5acc44", - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### Example Composite process using copasi and tellurium" - ], - "metadata": { - "collapsed": false - }, - "id": "8491845ac8f593cd" - }, - { - "cell_type": "code", - "execution_count": 3, - "source": [ - "simulators = ['copasi', 'tellurium'] # , 'amici']\n", - "duration = 30\n", - "n_steps = 200\n", - "model_filepath = '../biosimulator_processes/model_files/sbml/Caravagna2010.xml'\n", - "\n", - "\n", - "comparison = ComparisonDocument(simulators, duration, n_steps, model_filepath)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:59:32.979028Z", - "start_time": "2024-05-01T06:59:32.976561Z" - } - }, - "id": "d9fce82a600bb9af", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 4, - "source": [ - "pp(comparison.composite)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:59:32.985217Z", - "start_time": "2024-05-01T06:59:32.981251Z" - } - }, - "id": "57a94e90c5c2ba41", - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [ - "### ODE Simulator Comparison" - ], - "metadata": { - "collapsed": false - }, - "id": "659245544fd8d1b3" - }, - { - "cell_type": "code", - "execution_count": 5, - "source": [ - "from biosimulator_processes.compare import ComparisonDocument\n", - "\n", - "sbml_model_path = '../biosimulator_processes/model_files/sbml/BIOMD0000000630_url.xml'\n", - "simulators = ['copasi', 'copasi'] # , 'tellurium']\n", - "duration = 30 \n", - "n_steps = 50 \n", - "target_parameter = {\n", - " 'name': 'plasmin',\n", - " 'value': 2.01\n", - "}\n", - "\n", - "\n", - "def create_comparison_document(\n", - " sbml_model_path: str, \n", - " simulators: list[str], \n", - " duration: int, \n", - " n_steps: int, \n", - " target_param: dict = None\n", - " ) -> ComparisonDocument:\n", - " return ComparisonDocument(\n", - " simulators=simulators, \n", - " duration=duration, \n", - " num_steps=n_steps,\n", - " model_filepath=sbml_model_path,\n", - " target_parameter=target_param)\n", - "\n", - "\n", - "def generate_workflow(document: ComparisonDocument):\n", - " return Composite(\n", - " config={'state': document.composite},\n", - " core=CORE)\n", - "\n", - "\n", - "ode_comparison_document = create_comparison_document(sbml_model_path, simulators, duration, n_steps, target_parameter)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:59:32.991192Z", - "start_time": "2024-05-01T06:59:32.986334Z" - } - }, - "id": "3cc9032bbca74784", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 6, - "source": [ - "pp(ode_comparison_document.composite)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:59:33.502935Z", - "start_time": "2024-05-01T06:59:33.496658Z" - } - }, - "id": "5f99df92f1acbf52", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 7, - "source": [ - "ode_comparison_workflow = Composite(config={'state': ode_comparison_document.composite}, core=CORE)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:59:34.342968Z", - "start_time": "2024-05-01T06:59:34.257050Z" - } - }, - "id": "9c44bd491ad5ddb0", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 8, - "source": [ - "ode_comparison_workflow.run(duration)\n", - "ode_comparison_results = ode_comparison_workflow.gather_results()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:59:34.956538Z", - "start_time": "2024-05-01T06:59:34.946595Z" - } - }, - "id": "a52b1903520045a0", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 9, - "source": [ - "ode_comparison_results" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:59:35.546107Z", - "start_time": "2024-05-01T06:59:35.539397Z" - } - }, - "id": "806d60012d71a2eb", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 9, - "source": [], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:28.165350Z", - "start_time": "2024-05-01T06:56:28.160529Z" - } - }, - "id": "da55f1556e28363f", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 9, - "source": [], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:28.166914Z", - "start_time": "2024-05-01T06:56:28.163347Z" - } - }, - "id": "3330d11b7b80252b", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 10, - "source": [ - "import tellurium as te\n", - "\n", - "simulator = te.loadSBMLModel('../biosimulator_processes/model_files/sbml/BIOMD0000000630_url.xml')\n" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:28.959849Z", - "start_time": "2024-05-01T06:56:28.167336Z" - } - }, - "id": "5f07a08ac835b2b5", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 11, - "source": [ - "dir(simulator)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:28.967633Z", - "start_time": "2024-05-01T06:56:28.963005Z" - } - }, - "id": "f4fd7072004772cb", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 12, - "source": [ - "simulator.getReactionRates()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:28.973429Z", - "start_time": "2024-05-01T06:56:28.967766Z" - } - }, - "id": "e92d5b185840048f", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 13, - "source": [ - "simulator.getReactionIds()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:28.976229Z", - "start_time": "2024-05-01T06:56:28.971951Z" - } - }, - "id": "278ae59c7dedfc33", - "outputs": [] - }, - { - "cell_type": "markdown", - "source": [], - "metadata": { - "collapsed": false - }, - "id": "264bd8c515dda5aa" - }, - { - "cell_type": "code", - "execution_count": 14, - "source": [ - "simulator.integrator = 'stochastic'" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:29.393537Z", - "start_time": "2024-05-01T06:56:28.975565Z" - } - }, - "id": "3692858d8548cbee", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "source": [ - "simulator.integrator" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T06:56:29.398884Z", - "start_time": "2024-05-01T06:56:29.394793Z" - } - }, - "id": "f688e9553786d36e", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "source": [ - "simulator.getIds()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "start_time": "2024-05-01T06:56:29.397421Z" - } - }, - "id": "850c62b4ab027800", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 11, - "source": [], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T08:34:23.555250Z", - "start_time": "2024-05-01T08:34:23.547556Z" - } - }, - "id": "66b8d04c5b4d6d38", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 6, - "source": [ - "import numpy as np \n", - "type(np.random.rand(3, 4))" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T16:16:16.860293Z", - "start_time": "2024-05-01T16:16:16.843628Z" - } - }, - "id": "665d11516a211ac8", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 2, - "source": [ - "import numpy as np\n", - "from dataclasses import dataclass\n", - "from random import randint\n", - "\n", - "\n", - "@dataclass\n", - "class BestOutput:\n", - " value: float \n", - " generation: int \n", - " index: int \n", - " winning_value: float \n", - " \n", - "\n", - "# Fetch experimental data\n", - "def get_experimental_data(param_name: str = None) -> float:\n", - " # TODO: enable this\n", - " return np.random.rand()\n", - "\n", - "# Initialize parameters\n", - "winning_value = get_experimental_data() # TODO: Fetch this data from experimental online\n", - "population_size = 100 # Number of simulators being compared\n", - "mutation_rate = 0.1 # Initial mutation rate\n", - "range_low = 0 \n", - "range_high = 20 # TODO: make low and high derived automatically from population size and winning value\n", - "\n", - "\n", - "# Fitness function\n", - "def calculate_fitness(population):\n", - " return [abs(individual - winning_value) for individual in population]\n", - "\n", - "# Selection function\n", - "def select_individuals(fitness, num_parents):\n", - " fitness = np.array(fitness)\n", - " sorted_indices = np.argsort(fitness)\n", - " return sorted_indices[:num_parents]\n", - "\n", - "# Crossover function\n", - "def crossover(parents, num_offspring):\n", - " offspring = []\n", - " for _ in range(num_offspring):\n", - " parent1, parent2 = np.random.choice(parents, 2, replace=False)\n", - " child = (parent1 + parent2) / 2\n", - " offspring.append(child)\n", - " return offspring\n", - "\n", - "# Mutation function\n", - "def mutate(offspring, mutation_rate):\n", - " for i in range(len(offspring)):\n", - " if np.random.rand() < mutation_rate:\n", - " offspring[i] += np.random.normal(0, 0.1)\n", - " return offspring\n", - "\n", - "# Feedback function to adjust algorithm parameters based on real-world testing\n", - "def feedback_adjustment(best_output, current_range):\n", - " error = abs(best_output - winning_value)\n", - " new_mutation_rate = max(0.01, mutation_rate - 0.02 * (1 - error / (range_high - range_low)))\n", - " new_range_low, new_range_high = current_range\n", - " if error < 1:\n", - " new_range_low, new_range_high = best_output - 5, best_output + 5\n", - " return new_mutation_rate, new_range_low, new_range_high\n", - "\n", - "# Main genetic algorithm function with dynamic stopping\n", - "def genetic_algorithm(improvement_threshold=0.000001, max_stagnation=40):\n", - " global range_low, range_high, mutation_rate\n", - " population = np.random.uniform(low=range_low, high=range_high, size=population_size)\n", - " best_output = None\n", - " best_index = None\n", - " last_best_fitness = float('inf')\n", - " stagnation_counter = 0\n", - "\n", - " generation = 0\n", - " while True:\n", - " fitness = calculate_fitness(population)\n", - " current_best_fitness = min(fitness)\n", - " print(f\"Generation {generation}\")\n", - " print(\"Best fitness:\", current_best_fitness)\n", - "\n", - " if current_best_fitness < last_best_fitness:\n", - " if last_best_fitness - current_best_fitness < improvement_threshold:\n", - " stagnation_counter += 1\n", - " else:\n", - " stagnation_counter = 0\n", - " last_best_fitness = current_best_fitness\n", - " else:\n", - " stagnation_counter += 1\n", - "\n", - " if stagnation_counter >= max_stagnation:\n", - " print(f\"Stopping: No improvement in {max_stagnation} generations.\")\n", - " break\n", - "\n", - " selected_indices = select_individuals(fitness, population_size // 2)\n", - " selected = [population[i] for i in selected_indices]\n", - "\n", - " offspring = crossover(selected, population_size - len(selected))\n", - " offspring = mutate(offspring, mutation_rate)\n", - "\n", - " population = np.array(selected + offspring)\n", - "\n", - " best_index = np.argmin(calculate_fitness(population))\n", - " best_output = population[best_index]\n", - " mutation_rate, range_low, range_high = feedback_adjustment(best_output, (range_low, range_high))\n", - "\n", - " generation += 1\n", - "\n", - " return BestOutput(value=best_output, generation=generation, index=best_index, winning_value=winning_value)\n", - "\n", - "\n", - "# Running the enhanced genetic algorithm\n", - "best_output = genetic_algorithm()\n", - "print(f\"The winning value: {winning_value}\")\n", - "print(\"Best output closest to winning value with dynamic stopping:\", best_output)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-01T17:26:10.121893Z", - "start_time": "2024-05-01T17:26:10.084506Z" - } - }, - "id": "e6938f543d913ac", - "outputs": [] - }, - { - "cell_type": "code", - "source": [ - "def euclidian_distance(p1, p2):\n", - " from math import sqrt\n", - " return sqrt(((p1[0] - p2[0]) ** 2) + ((p1[1] - p2[1]) ** 2))\n", - "\n", - "\n", - "dist = euclidian_distance([1.0, 2.0], [4.5, 2.5])" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-13T17:23:20.562213Z", - "start_time": "2024-05-13T17:23:20.560068Z" - } - }, - "id": "21fcf6952f0ba30", - "execution_count": 7, - "outputs": [] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-13T17:23:21.115195Z", - "start_time": "2024-05-13T17:23:21.112726Z" - } - }, - "cell_type": "code", - "source": "dist", - "id": "9cef32173d70af12", - "execution_count": 8, - "outputs": [] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-13T17:23:21.523197Z", - "start_time": "2024-05-13T17:23:21.519616Z" - } - }, - "cell_type": "code", - "source": "dist", - "id": "7379fb6fc71f9d9a", - "execution_count": 9, - "outputs": [] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-13T17:23:44.149883Z", - "start_time": "2024-05-13T17:23:44.146658Z" - } - }, - "cell_type": "code", - "source": [ - "from math import sqrt\n", - "\n", - "sqrt(14).hex" - ], - "id": "44efe05ea87e827", - "execution_count": 11, - "outputs": [] - }, - { - "metadata": {}, - "cell_type": "code", - "execution_count": null, - "source": "", - "id": "a78843b27fac13b", - "outputs": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/demos/copasi_process_demo.ipynb b/demos/copasi_process_demo.ipynb deleted file mode 100644 index 0de779cd1..000000000 --- a/demos/copasi_process_demo.ipynb +++ /dev/null @@ -1,709 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "id": "40898635d17c0f08", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:46:15.246340Z", - "start_time": "2024-05-02T17:46:15.195226Z" - } - }, - "source": [ - "import sys\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "import requests\n", - "import json" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "initial_id", - "metadata": { - "collapsed": true, - "ExecuteTime": { - "end_time": "2024-05-02T17:46:18.648654Z", - "start_time": "2024-05-02T17:46:15.382959Z" - } - }, - "source": [ - "from biosimulator_processes.utils import prepare_single_copasi_process_schema\n", - "from biosimulator_processes import CORE\n", - "from process_bigraph import Composite, pp" - ], - "outputs": [] - }, - { - "cell_type": "markdown", - "id": "c7dca241b02a7265", - "metadata": {}, - "source": [ - "#### Step 1: Define the document to be read by the Composite, which is implemented by the Process." - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "2633feac24b596a6", - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-02T17:46:18.651630Z", - "start_time": "2024-05-02T17:46:18.643502Z" - } - }, - "source": [ - "biomodel_id = 'BIOMD0000000630'\n", - "model_fp = f'../biosimulator_processes/model_files/sbml/{biomodel_id}_url.xml'\n", - "species_context = 'concentrations'\n", - "species_port_name = f'floating_species_{species_context}'\n", - "species_store = [f'floating_species_{species_context}_store']\n", - "duration = 30\n", - "\n", - "document = prepare_single_copasi_process_schema(\n", - " process_name='copasi_A',\n", - " sbml_model_fp=model_fp)\n", - "\n", - "document" - ], - "outputs": [] - }, - { - "cell_type": "markdown", - "id": "e502cb54666345af", - "metadata": {}, - "source": [ - "\n", - "\n", - "#### Step 2: Define the instance composition along with the process registry" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "bd91dca0be22cd27", - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-02T17:40:47.750756Z", - "start_time": "2024-05-02T17:40:47.687910Z" - } - }, - "source": [ - "workflow = Composite(\n", - " config={'state': document},\n", - " core=CORE\n", - ")" - ], - "outputs": [] - }, - { - "cell_type": "markdown", - "id": "857667277d39c647", - "metadata": {}, - "source": [ - "#### Step 3: Run the workflow for a duration and get the results" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "7c6f72142af0616b", - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-02T17:40:48.035636Z", - "start_time": "2024-05-02T17:40:47.887576Z" - } - }, - "source": [ - "workflow.run(duration)\n", - "\n", - "results = workflow.gather_results()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "c7a254aee3009b8c", - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-02T02:22:57.402016Z", - "start_time": "2024-05-02T02:22:57.387107Z" - } - }, - "source": [ - "pp(results)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "76259bde7fd711f5", - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-02T02:22:59.583591Z", - "start_time": "2024-05-02T02:22:59.423936Z" - } - }, - "source": [ - "emitter = workflow.state['emitter']['instance']" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "7924d2e8b42e432d", - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-02T02:28:40.448604Z", - "start_time": "2024-05-02T02:28:40.443409Z" - } - }, - "source": [ - "workflow.state" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "27ae371af7ff2fa6", - "metadata": {}, - "source": [ - "\n", - "\n", - "x" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "136275c9f8743a57", - "metadata": {}, - "source": [ - "from biosimulator_processes.steps.viz import parse_composition_results\n", - "\n", - "\n", - "results = parse_composition_results(workflow)\n", - "\n", - "pp(results)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f6bbb65c9a862f12", - "metadata": {}, - "source": [ - "y_data = []\n", - "times = list(results.keys())\n", - "index = 'floating_species_concentrations'\n", - "\n", - "\n", - " \n", - "\n", - "for timestamp, result in results.items():\n", - " \n", - " root_data = result[index]\n", - " names = list(root_data.keys())\n", - " for name in names:\n", - " y_data.append(results[timestamp][index][name])\n", - " print(f'Got data for name {name}: {y_data}')\n", - " y_data.clear()\n", - " \n", - " \n", - " " - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "150dc15755417a42", - "metadata": {}, - "source": [ - "workflow.state['global_time']" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b1614b8359c0651f", - "metadata": {}, - "source": [ - "from biosimulator_processes.steps.viz import ResultsAnimation, Plotter2d" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "601a2e10c945b363", - "metadata": {}, - "source": [ - "output = results.copy()" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "538db282c51069d6", - "metadata": {}, - "source": [ - "output_vals = output[('emitter',)]" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a44c1cc0f9850758", - "metadata": {}, - "source": [ - "timescale = list(set([val.get('time', 0.0) for val in output_vals]))" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "5c510ec6dac592eb", - "metadata": {}, - "source": [ - "timescale" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f27e97fdebb17b07", - "metadata": {}, - "source": [ - "data = []\n", - "counts_data = []" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "c476add07372b47c", - "metadata": {}, - "source": [ - "for i, val in enumerate(output_vals):\n", - " species_data = val.get('floating_species_concentrations')\n", - " data.append(species_data.get('plasminogen'))\n", - " counts = val.get('floating_species_counts')\n", - " counts_data.append(counts.get('plasminogen'))" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "f84f85bf43a82b40", - "metadata": {}, - "source": [ - "len(timescale), len(data)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4311ca8a4fce3a7c", - "metadata": {}, - "source": [ - "Plotter2d.plot_single_output(timescale=timescale, data=data, species_name='plasminogen concentration')" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "a385d75479e50b1c", - "metadata": {}, - "source": [ - "Plotter2d.plot_single_output(timescale=timescale, data=counts_data, species_name='plasminogen counts', plot_concentration=False)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "4b07263ce48d2094", - "metadata": {}, - "source": [ - "Plotter2d.plot_output(x_data=data, y_data=counts_data, title='Plasminogen concentration over counts', x_label='concentration', y_label='counts', species='plasminogen')" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "1e5efa38b0de7505", - "metadata": {}, - "source": [], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "65cf4a00f212edaa", - "metadata": {}, - "source": [ - "class_name = 'TelluriumProcess'\n", - "module_name = 'tellurium_process'\n", - "module__ = module_name.split('_')\n", - "for i, v in enumerate(module__):\n", - " val = v.replace(v[0], v[0].upper())\n", - " module__.pop(i)\n", - " module__.insert(i, val)\n", - "print(module__.join())\n", - "import_statement = f'biosimulator_processes.processes.{module_name}'\n", - "\n", - "module = __import__(\n", - " import_statement, fromlist=[class_name])" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "2b43d4e3d39be4ff", - "metadata": { - "collapsed": false - }, - "source": [ - "module" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "db19fb9af030507", - "metadata": { - "collapsed": false - }, - "source": [ - "class_name\n" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "9aa632d6ba1240d1", - "metadata": { - "collapsed": false - }, - "source": [ - "x = list(range(10))\n", - "y = list(range(10))\n", - "z = [x, y]\n", - "\n", - "def func(z):\n", - " for i, v in enumerate(z):\n", - " if z[i + 1] != z[i]:\n", - " return" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "5e19d61cb651a822", - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:46:29.460012Z", - "start_time": "2024-05-02T17:46:29.441447Z" - } - }, - "source": [ - "from biosimulator_processes.processes.copasi_process import CopasiProcess \n", - "\n", - "\n", - "process_name = 'copasi'\n", - "module_name = f'{process_name}_process'\n", - "import_statement = f'biosimulator_processes.processes.{module_name}'\n", - "module_paths = module_name.split('_')\n", - "module_id = module_paths[0]\n", - "module_type = module_paths[1]\n", - "class_name = module_id.replace(module_id[0], module_id[0].upper())\n", - "class_name += module_type.replace(module_type[0], module_type[0].upper())\n", - "module = __import__(\n", - " import_statement, fromlist=[class_name])\n", - "# Get the class from the module\n", - "bigraph_class = getattr(module, class_name)" - ], - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 5, - "source": [ - "document['copasi_A']['config']" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:46:31.253580Z", - "start_time": "2024-05-02T17:46:31.241197Z" - } - }, - "id": "d560d9964c489785", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 6, - "source": [ - "copasi_process: CopasiProcess = bigraph_class(config=document['copasi_A']['config'])\n", - "\n", - "process_attributes = vars(copasi_process)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:46:32.631847Z", - "start_time": "2024-05-02T17:46:32.573561Z" - } - }, - "id": "c1aff67afe1cd8e8", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 7, - "source": [ - "new_initial_state = copasi_process.initial_state().copy()\n", - "\n", - "new_initial_state['model_parameters']['degradation constant 1'] = 0.50\n", - "\n", - "new_initial_state" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:46:33.853711Z", - "start_time": "2024-05-02T17:46:33.843267Z" - } - }, - "id": "8b3a24a6e47f6eab", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 12, - "source": [], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T18:01:29.107236Z", - "start_time": "2024-05-02T18:01:29.092702Z" - } - }, - "id": "6a2e21d03e963604", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 13, - "source": [ - "\n", - "\n", - "\n", - "def parse_state_params(state) -> list[str]:\n", - " state_parameters = []\n", - " _nested_vals = {}\n", - " \n", - " def parse_state(state): \n", - " for param_name, val in state.items():\n", - " if not isinstance(val, dict):\n", - " state_parameters.append(param_name)\n", - " else:\n", - " _nested_vals[param_name] = val\n", - " \n", - " parse_state(state)\n", - " nested = _nested_vals is not None\n", - " \n", - " def parse_nested(state, is_nested):\n", - " if not _nested_vals:\n", - " nested = False\n", - " print('nesting complete')\n", - " return\n", - " else:\n", - " print('is nested')\n", - " parse_state(state)\n", - " _nested_vals.clear()\n", - " \n", - " while nested:\n", - " parse_state(_nested_vals)\n", - " \n", - " return state_parameters\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - "\n", - " \n", - " " - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T18:09:55.905065Z", - "start_time": "2024-05-02T18:09:55.895769Z" - } - }, - "id": "4206e75e0d01fbb8", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 15, - "source": [ - "params = parse_state_params(new_initial_state)" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-03T15:03:11.977888Z", - "start_time": "2024-05-02T18:10:16.601120Z" - } - }, - "id": "6258b8ec1891a27d", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 9, - "source": [ - "\n", - "copasi_process.initial_state = new_initial_state" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:48:28.917017Z", - "start_time": "2024-05-02T17:48:28.904501Z" - } - }, - "id": "75aadcdd3dc1c8db", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 8, - "source": [ - "one_step = copasi_process.update(new_initial_state, 100.0)\n", - "\n", - "one_step" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:47:21.105371Z", - "start_time": "2024-05-02T17:47:21.091725Z" - } - }, - "id": "f7c8f328902103c", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 11, - "source": [ - "copasi_process.initial_state()" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:48:44.839724Z", - "start_time": "2024-05-02T17:48:44.666280Z" - } - }, - "id": "d64f8f8de7463a00", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 7, - "source": [ - "workflow.state" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:41:00.790459Z", - "start_time": "2024-05-02T17:41:00.773632Z" - } - }, - "id": "2fd1d1169b59660b", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": 6, - "source": [ - "workflow" - ], - "metadata": { - "collapsed": false, - "ExecuteTime": { - "end_time": "2024-05-02T17:40:58.396766Z", - "start_time": "2024-05-02T17:40:58.305142Z" - } - }, - "id": "c74e508f13eaceeb", - "outputs": [] - }, - { - "cell_type": "code", - "execution_count": null, - "source": [], - "metadata": { - "collapsed": false - }, - "id": "50919eb9594a555", - "outputs": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/demos/nf1_model.xml b/demos/nf1_model.xml deleted file mode 100644 index a8eeba8c0..000000000 --- a/demos/nf1_model.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - k_diff_WT - - - - - - - - - - - - - k_diff_Het - - - - - - - - - - - - - k_diff_Null - - - - - - - - - - - - - - - k_tumor - - - - - - - - - - - - - - - diff --git a/demos/ode_process_demo.ipynb b/demos/ode_process_demo.ipynb new file mode 100644 index 000000000..47c7617cb --- /dev/null +++ b/demos/ode_process_demo.ipynb @@ -0,0 +1,205 @@ +{ + "cells": [ + { + "cell_type": "code", + "id": "initial_id", + "metadata": { + "collapsed": true, + "ExecuteTime": { + "end_time": "2024-05-26T18:47:36.234190Z", + "start_time": "2024-05-26T18:47:34.708184Z" + } + }, + "source": [ + "import sys\n", + "import os \n", + "\n", + "import numpy as np\n", + "from process_bigraph import pp\n", + "from process_bigraph.experiments.parameter_scan import RunProcess\n", + "\n", + "\n", + "sys.path.insert(0, '..')\n", + "\n", + "\n", + "from biosimulator_processes import CORE\n", + "from biosimulator_processes.services.rest_service import BiosimulationsRestService\n", + "from biosimulator_processes.instance import generate_ode_instance" + ], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CobraProcess registered successfully as cobra.\n", + "\n", + "CopasiProcess registered successfully as copasi.\n", + "\n", + "TelluriumProcess registered successfully as tellurium.\n", + "\n", + "AmiciProcess registered successfully as amici.\n", + "\n", + "Available processes:\n", + "[ 'console-emitter',\n", + " 'ram-emitter',\n", + " 'composite',\n", + " 'cobra',\n", + " 'copasi',\n", + " 'tellurium',\n", + " 'amici']\n", + "CompositionPlotter registered successfully as plotter.\n", + "\n", + "Plotter2d registered successfully as plotter2d.\n", + "\n", + "Available processes:\n", + "[ 'console-emitter',\n", + " 'ram-emitter',\n", + " 'composite',\n", + " 'cobra',\n", + " 'copasi',\n", + " 'tellurium',\n", + " 'amici',\n", + " 'plotter',\n", + " 'plotter2d']\n" + ] + } + ], + "execution_count": 1 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T18:47:36.237044Z", + "start_time": "2024-05-26T18:47:36.235328Z" + } + }, + "cell_type": "code", + "source": [ + "model_fp = '../test_suite/examples/sbml-core/Caravagna-J-Theor-Biol-2010-tumor-suppressive-oscillations/Caravagna2010.xml'\n", + "ode_process_config = {'model': {'model_source': model_fp}}\n", + "step_size = 0.25\n", + "duration = 10.0" + ], + "id": "d4cdc5e03d9ccfa6", + "outputs": [], + "execution_count": 2 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T18:47:36.295379Z", + "start_time": "2024-05-26T18:47:36.237603Z" + } + }, + "cell_type": "code", + "source": "copasi_process = generate_ode_instance(process_address='local:copasi', model_fp=model_fp, step_size=step_size, duration=duration)", + "id": "fe2876b09d9d0e1a", + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "found a filepath\n", + "found a filepath\n" + ] + } + ], + "execution_count": 3 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T18:47:36.350706Z", + "start_time": "2024-05-26T18:47:36.296031Z" + } + }, + "cell_type": "code", + "source": "data = copasi_process.run()", + "id": "bb0bfcad2ead76f8", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/alex/Desktop/uchc_work/biosimulators-2.0/biosimulator-processes/demos/../biosimulator_processes/processes/copasi_process.py:194: FutureWarning:\n", + "\n", + "Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "\n" + ] + } + ], + "execution_count": 4 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T18:47:36.354084Z", + "start_time": "2024-05-26T18:47:36.352268Z" + } + }, + "cell_type": "code", + "source": "from biosimulator_processes.instance import plot_ode_output_data", + "id": "a7cf4c427f5eeafc", + "outputs": [], + "execution_count": 5 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T18:47:36.445755Z", + "start_time": "2024-05-26T18:47:36.354856Z" + } + }, + "cell_type": "code", + "source": "plot_ode_output_data(data)", + "id": "187172c397cb1448", + "outputs": [ + { + "data": { + "text/plain": [ + "
" + ], + "image/png": "iVBORw0KGgoAAAANSUhEUgAAA04AAAK9CAYAAAAT0TyCAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjkuMCwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy80BEi2AAAACXBIWXMAAA9hAAAPYQGoP6dpAACVL0lEQVR4nOzdd3gU5d7G8XuTbHojpFFCD713RCkqHRR7pwk2EJVjOeg5CnoUPYrYu4gNO+p5VXpV6b33HkiAQHrb7M77R8iSkABJSDLZ5Pu5rr1255n2280D2Tsz84zFMAxDAAAAAIALcjO7AAAAAACo6AhOAAAAAHAJBCcAAAAAuASCEwAAAABcAsEJAAAAAC6B4AQAAAAAl0BwAgAAAIBLIDgBAAAAwCUQnAAAAADgEghOAFAOLBaLJk2aZHYZKCMHDx6UxWLRjBkzzC6lyqlXr55GjBhhdhkAqgCCE4BKYcuWLbr55ptVt25deXt7q1atWurTp4/efvtts0szVVJSkiZPnqw2bdrI399fPj4+atmypZ566ikdO3bM7PJK3bFjxzRp0iRt3LixTLY/c+ZMvfHGG2Wy7bJms9n01ltvqVOnTgoICJC/v786deqkt956SzabzezynJYsWSKLxVKkBwCUJ4thGIbZRQDA5Vi+fLl69+6tOnXqaPjw4YqMjNSRI0e0cuVK7du3T3v37jW7RGVkZMjDw0MeHh7lts/9+/fr2muv1eHDh3XLLbfoyiuvlKenpzZv3qxvvvlGISEh2r17d7nVUx7Wrl2rTp066bPPPiuToxCDBw/W1q1bdfDgwXzthmEoMzNTVqtV7u7upb7fy5WamqpBgwZp6dKlGjx4sPr37y83NzfNmTNH//vf/9SzZ0/9/vvv8vPzM7tUxcXFaf78+fnaJk6cKH9/fz3zzDP52u+++25lZmbKzc1NVqu1PMsEUAWV329wACgjL774ooKCgrRmzRoFBwfnm3fixAlzijqPt7d3ue4vOztbN954o+Li4rRkyRJdeeWV+ea/+OKLeuWVV8q1poooLS1Nvr6+l70di8VS7j/j4pgwYYKWLl2qt99+W+PGjXO2P/jgg3r33Xc1btw4Pf7443r//ffLrSbDMJSRkSEfH5987REREbr77rvztb388ssKDQ0t0C5JXl5eZVonAOTiVD0ALm/fvn1q0aJFgdAkSeHh4fmmLRaLxo0bp6+//lpNmjSRt7e3OnTooGXLlhVYNyYmRqNGjVJERIS8vLzUokULTZ8+vcByGRkZmjRpkho3bixvb2/VqFFDN954o/bt25dvv+df41TU7b/99ttq0aKFfH19Va1aNXXs2FEzZ8686Gfy008/adOmTXrmmWcKhCZJCgwM1Isvvpiv7YcfflCHDh3k4+Pj/JIaExOTb5kRI0bI399fMTExGjp0qPz9/RUWFqbHH39cdrs937IOh0NvvvmmWrVqJW9vb4WFhal///5au3ZtvuW++uor535DQkJ0++2368iRI/mW6dWrl1q2bKnt27erd+/e8vX1Va1atfTf//7XucySJUvUqVMnSdLIkSOdp3PlXneUu41169apR48e8vX11dNPPy1J+vXXXzVo0CDVrFlTXl5eatiwoV544YV876lXr176/fffdejQIee269WrJ+nC1zgtWrRIV111lfz8/BQcHKzrr79eO3bsyLfMpEmTZLFYtHfvXo0YMULBwcEKCgrSyJEjlZaWlm/Z+fPn68orr1RwcLD8/f3VpEkT53u4kKNHj+rTTz/V1VdfnS805Ro7dqx69+6tTz75REePHpUktWzZUr179y6wrMPhUK1atXTzzTfna3vjjTfUokULeXt7KyIiQvfff7/OnDmTb9169epp8ODBmjt3rjp27CgfHx99+OGHF629KM6/xmnGjBmyWCz666+/NH78eIWFhSk4OFj333+/srKylJCQoGHDhqlatWqqVq2annzySZ1/8k1R3xOAqoUjTgBcXt26dbVixQpt3bpVLVu2vOTyS5cu1Xfffafx48fLy8tL7733nvr376/Vq1c714+Li1PXrl2dQSssLEyzZ8/Wvffeq6SkJD366KOSJLvdrsGDB2vhwoW6/fbb9cgjjyg5OVnz58/X1q1b1bBhw0JrKOr2P/74Y40fP14333yzHnnkEWVkZGjz5s1atWqV7rzzzgu+x//973+SpHvuuadIn+GMGTM0cuRIderUSVOmTFFcXJzefPNN/f3339qwYUO+UGq329WvXz916dJFr732mhYsWKCpU6eqYcOGevDBB53L3XvvvZoxY4YGDBig0aNHKzs7W3/++adWrlypjh07Sso58vXvf/9bt956q0aPHq2TJ0/q7bffVo8ePQrs98yZM+rfv79uvPFG3Xrrrfrxxx/11FNP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fij0yMeF5H4RvfvuuzV8+PBCl2ndunWJayzO9ps1a6Zdu3bpt99+05w5c/TTTz/pvffe07PPPqvJkydfcB9NmzbVhg0bdOTIkQJfFC9XaQ237XA4ZLFYNHv27EK3ef71Qxfar1GMu2qcP4KbJCUkJKhnz54KDAzU888/r4YNG8rb21vr16/XU089VayjO5fjUu/Px8dHy5Yt0+LFi/X7779rzpw5+u6773T11Vdr3rx5F1y/WbNmkqTNmzerbdu2hS6zefNmSVLz5s2dbbfddpsmTpyoH374QY8++qi+//57BQUFqX///s5lHA6HwsPDC/zRMNf5Abuwz7+sXOjzKKw9bx8q7nsCUHVU6eA0YMAADRgw4ILzMzMz9cwzz+ibb75RQkKCWrZsqVdeeUW9evWSpAIjGT3yyCOaN2+eZs2a5QxOuV/gJOmf//xn2bwRAIXKHYDg+PHj+dr37NlTYNndu3fL19fX+aUoICBAdrtd11577UX30bBhQ61atUo2m63IF4yHhYUVefuS5Ofnp9tuu0233XabsrKydOONN+rFF1/UxIkTLzgE9pAhQ/TNN9/oq6++0sSJEy+6/bp160rKuXD/6quvzjdv165dzvnF0bBhQ82dO1enT5++4FGnhg0byjAM1a9fX40bNy72PgpTkpuiLlmyRPHx8Zo1a5Z69OjhbD9w4ECJt5/3Mz3fzp07FRoaWqJ7Jrm5uemaa67RNddco9dff10vvfSSnnnmGS1evPiCfWnAgAFyd3fXl19+ecEBIr744gt5eHjkC0X169dX586d9d1332ncuHGaNWuWhg4dmm/474YNG2rBggXq3r17uYaislQZ3xOA0lGlT9W7lHHjxmnFihX69ttvtXnzZt1yyy3q379/oV+6ciUmJl701BQApW/x4sWFHnXIvY7k/NOlVqxY4byGSJKOHDmiX3/9VX379pW7u7vc3d1100036aefftLWrVsLbPfkyZPO1zfddJNOnTqld955p8ByFzoSUpztx8fH55vn6emp5s2byzAM2Wy2QrcvSTfffLNatWqlF198UStWrCgwPzk52Xkz0Y4dOyo8PFwffPCBMjMzncvMnj1bO3bs0KBBgy64nwu56aabZBhGoUfFcj+XG2+8Ue7u7po8eXKBz8owjALvvShyw0hCQkKR18k9ApG3hqysLL333nuFbr8op+7VqFFDbdu21eeff56vlq1bt2revHkaOHBgkevLdfr06QJtuUeQ8v7czhcVFaWRI0dqwYIFhd6n6YMPPtCiRYt07733qnbt2vnm3XbbbVq5cqWmT5+uU6dO5TtNT8oZCdBut+uFF14osN3s7Oxi/Rwqisr4ngCUjip9xOliDh8+rM8++0yHDx9WzZo1JUmPP/645syZo88++0wvvfRSgXW+//57rVmzplTuSwGg6B5++GGlpaXphhtuUNOmTZWVlaXly5fru+++U7169QoMBtCyZUv169cv33DkkvJ9yX/55Ze1ePFidenSRWPGjFHz5s11+vRprV+/XgsWLHB+iR02bJi++OILTZgwQatXr9ZVV12l1NRULViwQA899JCuv/76Qmsu6vb79u2ryMhIde/eXREREdqxY4feeecdDRo06KIX+1utVs2aNUvXXnutevTooVtvvVXdu3eX1WrVtm3bNHPmTFWrVk0vvviirFarXnnlFY0cOVI9e/bUHXfc4RyOvF69eiU6zbh3796655579NZbb2nPnj3q37+/HA6H/vzzT/Xu3Vvjxo1Tw4YN9Z///EcTJ07UwYMHNXToUAUEBOjAgQP6+eefdd999+nxxx8v1n4bNmyo4OBgffDBBwoICJCfn5+6dOly0WtrrrjiClWrVk3Dhw/X+PHjZbFY9OWXXxYafDt06KDvvvtOEyZMUKdOneTv768hQ4YUut1XX31VAwYMULdu3XTvvfc6hyMPCgoqcE+vonj++ee1bNkyDRo0SHXr1tWJEyf03nvvqXbt2oXeqyuvadOmaefOnXrooYc0Z84c55GluXPn6tdff1XPnj01derUAuvdeuutevzxx/X4448rJCSkwFGtnj176v7779eUKVO0ceNG9e3bV1arVXv27NEPP/ygN998M989n1xBZXxPAEpJOY/iV2FJMn7++WfndO4wvH5+fvkeHh4exq233lpg/UWLFhm+vr7G559/fsF91K1b15g2bVoZVA9UbbNnzzZGjRplNG3a1PD39zc8PT2NRo0aGQ8//LARFxeXb1lJxtixY42vvvrKiI6ONry8vIx27doZixcvLrDduLg4Y+zYsUZUVJRhtVqNyMhI45prrjE++uijfMulpaUZzzzzjFG/fn3ncjfffLOxb9++fPvNOxx5Ubf/4YcfGj169DCqV69ueHl5GQ0bNjSeeOIJIzExsUifzZkzZ4xnn33WaNWqleHr62t4e3sbLVu2NCZOnGgcP34837Lfffed0a5dO8PLy8sICQkx7rrrLuPo0aP5lhk+fLjh5+dXYD+5Q2rnlZ2dbbz66qtG06ZNDU9PTyMsLMwYMGCAsW7dunzL/fTTT8aVV17p/H+2adOmxtixY41du3Y5l+nZs2ehw7IPHz68wPDgv/76q9G8eXPDw8Mj3xDhF9qGYRjG33//bXTt2tXw8fExatas6RzSXlK+vpGSkmLceeedRnBwsCHJue/ChiM3DMNYsGCB0b17d8PHx8cIDAw0hgwZYmzfvr3Qz+78YcZzh9U+cOCAYRiGsXDhQuP66683atasaXh6eho1a9Y07rjjDmP37t2FvqfzZWZmGtOmTTM6dOhg+Pn5Gb6+vkb79u2NN954o9Ch+3N1797dkGSMHj36gst89NFHRocOHQwfHx8jICDAaNWqlfHkk08ax44dcy5Tt25dY9CgQUWq9XwlGY58zZo1+Za70Od8oT5dlPcEoGqxGEYxrqqtxCwWi37++WcNHTpUkvTdd9/prrvu0rZt2wpcSOrv75/vhoBLly7VoEGD9Prrr+u+++674D7q1aunRx991HljSwDlz2KxaOzYsYWeWgcAAHAhnKp3Ae3atZPdbteJEyecd58vzJIlSzR48GC98sorFw1NAAAAAFxXlQ5OKSkp2rt3r3P6wIED2rhxo0JCQtS4cWPdddddGjZsmKZOnap27drp5MmTWrhwoVq3bq1BgwZp8eLFGjx4sB555BHddNNNio2NlZRz8XbuABFZWVnOe8hkZWUpJiZGGzdulL+/vxo1alT+bxoAAABAsVXpU/WWLFmi3r17F2gfPny4ZsyYIZvNpv/85z/64osvFBMTo9DQUHXt2lWTJ09Wq1atNGLECH3++ecF1u/Zs6eWLFkiSTp48GChFyXnXQZA+eFUPQAAUBJVOjgBAAAAQFFwHycAAAAAuASCEwAAAABcQpUbHMLhcOjYsWMKCAiQxWIxuxwAAAAAJjEMQ8nJyapZs6bc3C5+TKnKBadjx44pKirK7DIAAAAAVBBHjhxR7dq1L7pMlQtOAQEBknI+nMDAQJOrkWw2m+bNm6e+ffvKarWaXQ4qOPoLios+g+Kiz6C46DMororUZ5KSkhQVFeXMCBdT5YJT7ul5gYGBFSY4+fr6KjAw0PSOg4qP/oLios+guOgzKC76DIqrIvaZolzCw+AQAAAAAHAJBCcAAAAAuASCEwAAAABcQpW7xqkoDMNQdna27HZ7me/LZrPJw8NDGRkZ5bI/SXJ3d5eHhwfDsQMAAABFRHA6T1ZWlo4fP660tLRy2Z9hGIqMjNSRI0fKNcj4+vqqRo0a8vT0LLd9AgAAAK6K4JSHw+HQgQMH5O7urpo1a8rT07PMw4zD4VBKSor8/f0vedOt0mAYhrKysnTy5EkdOHBA0dHR5bJfAAAAwJURnPLIysqSw+FQVFSUfH19y2WfDodDWVlZ8vb2LrcA4+PjI6vVqkOHDjn3DQAAAODCONRQiKpwBKYqvEcAAACgtPDtGQAAAAAugeAEAAAAAJdAcAIAAACASyA4VQIWi+Wij0mTJpldIgAAAODSGFWvEjh+/Ljz9Xfffadnn31Wu3btcrb5+/ubURYAAABQaRCcLsEwDKXb7GW2fYfDofQsuzyysguMdOdjdS/SfaQiIyOdr4OCgmSxWPK1AQAAALg8BKdLSLfZ1fzZuabse/vz/eTryY8IAAAAMBvXOAEAAADAJXA44xJ8rO7a/ny/Mtu+w+FQclKyAgIDCj1VDwAAAID5CE6XYLFYyvR0OYfDoWxPd/l6ehQITgAAAAAqBr6pAwAAAMAlEJwAAAAA4BIITgAAAABwCQSnSmbEiBFKSEgwuwwAAACgUiE4AQAAAMAlEJwAAAAAlJu52+K0N9HsKoqP4cgBAAAAlIvD8Wl66uetSst0V6f98erRJNLskoqMI04AAAAAyly23aFHv9ug1Ey76gdIneuFmF1SsRCcAAAAAJS5txbt1frDCQrw9tA90Xa5u1nMLqlYCE4AAAAAytSag6f1zqI9kqTnhzRTiJfJBZUAwQkAAABAmUlMt+nRbzfKYUg3tq+lwa1rmF1SiRCcAAAAAJQJwzD071+2KiYhXXVCfPX89S3NLqnECE4AAAAAysTPG2L0v03H5O5m0Zu3t5W/l+sO6k1wAgAAAFDqDsen6dlft0mSHr0mWu3qVDO5ostDcKokRowYIYvFUuDRv39/s0sDAABAFWOzO/TIdxuUkpmtzvVC9FDvRmaXdNlc91gZCujfv78+++yzfG1eXi44ZAkAAABc2tsL92jD2aHHp93e1uWGHi8MwelSDEOypZXd9h2OnO1nuUtu5x0AtPpKlqJ3Mi8vL0VGus7dlwEAAFD5rD5wWu8s3itJeumGVqoV7GNyRaWD4HQptjTppZpltnk3ScEXmvn0McnTr8z2DQAAAJSmxHSbHvsuZ+jxm9rX1pA2Zfc9urxxjVMl8ttvv8nf3z/f46WXXjK7LAAAAFQBhmHoX2eHHq9b3VeTr29hdkmliiNOl2L1zTnyU0YcDoeSkpMVGBAgt8JO1SuG3r176/3338/XFhIScrklAgAAAJc0a32M/u/s0ONv3ObaQ48XpnK9m7JgsZTt6XIOh2S15+zj/OBUTH5+fmrUyPVHLAEAAIBrORSfqmd/3SpJeuxa1x96vDCcqgcAAACgxGx2hx75dqNSs+zqXD9ED/aqnH/I54hTJZKZmanY2Nh8bR4eHgoNDTWpIgAAAFR2by3co41HEhTo7aFpt1WOoccLQ3CqRObMmaMaNWrka2vSpIl27txpUkUAAACozFYfOK13c4cev7HyDD1eGE7VqyRmzJghwzAKPAhNAAAAKAt5hx6/uUNtDW5deYYeL4ypwen9999X69atFRgYqMDAQHXr1k2zZ8++4PIzZsyQxWLJ9/D29i7HigEAAACcP/T4pOsq19DjhTH1VL3atWvr5ZdfVnR0tAzD0Oeff67rr79eGzZsUIsWhX/4gYGB2rVrl3PaYqmc51ACAAAAFVXu0OMebha9eXu7Sjf0eGFMfYdDhgzJN/3iiy/q/fff18qVKy8YnCwWiyIjI8ujPAAAAADnyTf0eJ/GahsVbG5B5aTCREO73a4ffvhBqamp6tat2wWXS0lJUd26deVwONS+fXu99NJLFwxZUs5Ic5mZmc7ppKQkSZLNZpPNZsu3rM1mk2EYcjgccjgcl/mOisYwDOdzee1TyrnxrmEYstlscnd3L7f94vLk9tnz+y5wIfQZFBd9BsVFn6labHaHxn+zIWfo8XrVdO8VdYr9s69IfaY4NViM3G/uJtmyZYu6deumjIwM+fv7a+bMmRo4cGChy65YsUJ79uxR69atlZiYqNdee03Lli3Ttm3bVLt27ULXmTRpkiZPnlygfebMmfL19c3X5uHhocjISEVFRcnT0/Py31wFlpWVpSNHjig2NlbZ2dlmlwMAAAAX8PthN82LcZOPu6Gn2thVzcvsii5PWlqa7rzzTiUmJiowMPCiy5oenLKysnT48GElJibqxx9/1CeffKKlS5eqefPml1zXZrOpWbNmuuOOO/TCCy8UukxhR5yioqJ06tSpAh9ORkaGjhw5onr16pXboBOGYSg5OVkBAQHler1WRkaGDh48qKioKAbYcCE2m03z589Xnz59ZLVazS4HLoA+g+Kiz6C46DNVx5qDZ3T39DVyGNJbt7XWgJYlu3ymIvWZpKQkhYaGFik4mX6qnqenpxo1yrm7cIcOHbRmzRq9+eab+vDDDy+5rtVqVbt27bR3794LLuPl5SUvr4JR2Gq1FvhB2e12WSwWubm5yc2tfAYczD09L3e/5cXNzU0Wi6XQzwEVHz83FBd9BsVFn0Fx0Wcqt9OpWZrwwxY5DOmWDrV1Xbuoy95mRegzxdl/hbuPk8PhyHeE6GLsdru2bNlS4KavAAAAAEqHw2FowvcbFZuUoYZhflVi6PHCmHrEaeLEiRowYIDq1Kmj5ORkzZw5U0uWLNHcuXMlScOGDVOtWrU0ZcoUSdLzzz+vrl27qlGjRkpISNCrr76qQ4cOafTo0Wa+DQAAAKDS+ujP/Vqy66S8PNz07l3t5VcFhh4vjKnv+sSJExo2bJiOHz+uoKAgtW7dWnPnzlWfPn0kSYcPH853+tqZM2c0ZswYxcbGqlq1aurQoYOWL19epOuhAAAAABTP2oOn9ercnHuoTr6uhZpGXvw6oMrM1OD06aefXnT+kiVL8k1PmzZN06ZNK8OKXNeIESOUkJCgX375xexSAAAAUAmcSc3Sw99skN1haGjbmrqt0+Vf1+TKKtw1TgAAAADM5XAY+scPm3Q8MUMNQv30nxtalesI0BVR1TxBsRgMw1B6dnqZbd/hcCg9O10eNo8Co+r5ePhU+Q4KAACA8vfJX/u1aOcJeXq46Z0728u/il7XlBefwCWkZ6ery8wupux71Z2r5Gv1vfSCAAAAQClZd+iMXpmTc13TpCEt1Lxm1b2uKS9O1QMAAAAgSUpIy9L4s9c1DWlTU3d0rtrXNeXFEadL8PHw0ao7V5XZ9h0Oh5KTkxUQEFDoqXoAAABAeTAMQ4//sEkxCemqH+qnl25oyWUjeRCcLsFisZTp6XIOh0PZHtnytfoWCE4AAABAefn0rwNasCP3uqZ2CvC2ml1ShcI3dQAAAKCK23D4jF6evVOS9O/BzdWiZpDJFVU8BCcAAACgCktMs2nczA3Kdhga1LqG7u5Sx+ySKiSCEwAAAFBFGYahx3/Mua6pbnVfvXwj92u6EK5xqiRmzJhhdgkAAABwMdP/Pqj52+Pk6e6md+9sz3VNF8ERJwAAAKAK2ngkQS/P3iFJ+tfgZmpZi+uaLobgBAAAAFQxiek2jZu5Xja7oYGtInVP17pml1ThEZwAAACAKsQwDD354yYdPZOuOiG+evmm1lzXVAQEJwAAAKAKmbH8oOZui5PV3aJ37mynQK5rKhKCUyEMwzC7hDJXFd4jAAAA8tt8NEEv/ZFzXdMzA5upde1gcwtyIQSnPKzWnLSdlpZmciVlL/c95r5nAAAAVG6J6TaNPXtdU/8WkRp+RT2zS3IpDEeeh7u7u4KDg3XixAlJkq+vb5mf7+lwOJSVlaWMjAy5uZV9jjUMQ2lpaTpx4oSCg4Pl7u5e5vsEAACAuQzD0D9/2qwjp9NVu5qPXrmZ65qKi+B0nsjISElyhqeyZhiG0tPT5ePjU66dNzg42PleAQAAULl9ufKQZm+NPXtdU3sF+XDWUXERnM5jsVhUo0YNhYeHy2azlfn+bDabli1bph49epTbaXNWq5UjTQAAAFXEpiMJ+s9vOdc1/XNAM7WNCja3IBdFcLoAd3f3cgkX7u7uys7Olre3N9cbAQAAoFSdTs3Sg1+tU5bdob7NIzSqez2zS3JZDA4BAAAAVEJ2h6Hx32zQscQM1Q/102u3tuG6pstAcAIAAAAqodfn79Jfe0/Jx+quD+7uwP2aLhPBCQAAAKhk5m2L1buL90mSXr6plZpEBphckesjOAEAAACVyP6TKfrH95skSSO719P1bWuZXFHlQHACAAAAKom0rGw98NU6JWdmq1O9anp6YDOzS6o0CE4AAABAJZBzk9st2h2XorAAL717Z3tZ3fm6X1r4JAEAAIBKYMbyg/rfpmPycLPovbvaKzzQ2+ySKhWCEwAAAODi1hw8rRd/z7nJ7dMDm6lTvRCTK6p8CE4AAACACzuRlKGHvl6vbIehIW1qaiQ3uS0TBCcAAADARdnsDo2duV4nkzPVJCJAr9zUipvclhGCEwAAAOCipvyxU2sOnlGAl4fev7u9fD09zC6p0iI4AQAAAC7o140xmv73AUnS1FvbqEGYv8kVVW4EJwAAAMDF7IpN1j9/2iJJeqhXQ/VtEWlyRZUfwQkAAABwIUkZNj3w1Tql2+y6slGo/tG3idklVQkEJwAAAMBFOByG/vH9Jh04lapawT566452cndjMIjyQHACAAAAXMT7S/dp/vY4ebq76b272ivEz9PskqoMghMAAADgAv7cc1JT5+2SJE2+voXaRAWbW1AVQ3ACAAAAKriYhHSN/2aDHIZ0a8faur1TlNklVTkEJwAAAKACy7DZ9eBX63QmzaZWtYL0/PUtucmtCQhOAAAAQAU2+f+2afPRRAX7WvXeXe3lbXU3u6QqieAEAAAAVFDfrzmib1YfkcUivXl7O0WF+JpdUpVFcAIAAAAqoHWHzuhfv2yVJE24trF6Ng4zuaKqjeAEAAAAVDDHE9P1wFfrlGV3qG/zCI3t3cjskqo8ghMAAABQgWTY7Lrvi3U6mZypppEBmnZbW7lxk1vTEZwAAACACsIwDD3102ZtiUlUNV+rPh7WUX5eHmaXBRGcAAAAgArjw2X79evGY3J3s+jdu9ozGEQFQnACAAAAKoBFO+P0ypydkqRJQ5rrioahJleEvAhOAAAAgMn2nkjWI99slGFId3Suo7u71jW7JJyH4AQAAACYKDHNptGfr1VyZrY61wvR5OtayGJhMIiKhuAEAAAAmCTb7tC4b9brYHyaagX76L2728vTg6/oFRE/FQAAAMAkL8/eqT/3nJKP1V0fDeugUH8vs0vCBRCcAAAAABP8uO6oPvnrgCRp6q1t1KJmkMkV4WIITgAAAEA5W3/4jJ6etUWSNP6aaA1sVcPkinApBCcAAACgHMUmZuj+L9cpy+5QvxYRevSaaLNLQhEQnAAAAIBykmGz674v1+pkcqaaRgbo9Vvbys2NEfRcAcEJAAAAKAeGYeipnzZr89FEVfO16uNhHeXn5WF2WSgighMAAABQDj5ctl+/bjwmdzeL3r2rvaJCfM0uCcVAcAIAAADK2OKdJ/TKnJ2SpElDmuuKhqEmV4TiIjgBAAAAZWjviWSN/2aDDEO6o3Md3d21rtkloQQITgAAAEAZSUyzacwX65Scma3O9UI0+boWslgYDMIVEZwAAACAMpBtd2jcN+t14FSqagX76L2728vTg6/froqfHAAAAFAGXp69U3/uOSUfq7s+GtZBof5eZpeEy0BwAgAAAErZ92uP6JO/DkiSpt7aRi1qBplcES4XwQkAAAAoRcv3ntLTs7ZIksZfE62BrWqYXBFKA8EJAAAAKCV7T6Toga/WKdthaEibmnrs2mizS0IpITgBAAAApSA+JVMjZ6xWUka2OtStpldvbs0IepWIqcHp/fffV+vWrRUYGKjAwEB169ZNs2fPvug6P/zwg5o2bSpvb2+1atVKf/zxRzlVCwAAABQuw2bXfV+u05HT6aoT4quP7ukgb6u72WWhFJkanGrXrq2XX35Z69at09q1a3X11Vfr+uuv17Zt2wpdfvny5brjjjt07733asOGDRo6dKiGDh2qrVu3lnPlAAAAQA6Hw9ATP27WukNnFOjtoekjOqk6I+hVOqYGpyFDhmjgwIGKjo5W48aN9eKLL8rf318rV64sdPk333xT/fv31xNPPKFmzZrphRdeUPv27fXOO++Uc+UAAABAjmkLduv/Nh2Th5tFH9zdQY3C/c0uCWXAw+wCctntdv3www9KTU1Vt27dCl1mxYoVmjBhQr62fv366ZdffrngdjMzM5WZmemcTkpKkiTZbDbZbLbLL/wy5dZQEWpBxUd/QXHRZ1Bc9BkUV1XvM7M2xOjtRXslSS9c31yd6gZV2c+iqCpSnylODaYHpy1btqhbt27KyMiQv7+/fv75ZzVv3rzQZWNjYxUREZGvLSIiQrGxsRfc/pQpUzR58uQC7fPmzZOvr+/lFV+K5s+fb3YJcCH0FxQXfQbFRZ9BcVXFPrMn0aL3d7hJsqhPLYd8Yzfpjz82mV2Wy6gIfSYtLa3Iy5oenJo0aaKNGzcqMTFRP/74o4YPH66lS5deMDwV18SJE/MdpUpKSlJUVJT69u2rwMDAUtnH5bDZbJo/f7769Okjq9Vqdjmo4OgvKC76DIqLPoPiqqp9Zv/JVD378SrZjWwNahmp129pJTc3RtAriorUZ3LPRisK04OTp6enGjVqJEnq0KGD1qxZozfffFMffvhhgWUjIyMVFxeXry0uLk6RkZEX3L6Xl5e8vApenGe1Wk3/QeVV0epBxUZ/QXHRZ1Bc9BkUV1XqM6dTs3Tf1xuUmJ6tdnWCNfW2tvJiBL1iqwh9pjj7r3D3cXI4HPmuScqrW7duWrhwYb62+fPnX/CaKAAAAKA0Zdjsuu+LtToUn6aoEB99PKwjw45XEaYecZo4caIGDBigOnXqKDk5WTNnztSSJUs0d+5cSdKwYcNUq1YtTZkyRZL0yCOPqGfPnpo6daoGDRqkb7/9VmvXrtVHH31k5tsAAABAFWAYhp76abPWHjqjAG8PfTaik0IZdrzKMDU4nThxQsOGDdPx48cVFBSk1q1ba+7cuerTp48k6fDhw3JzO3dQ7IorrtDMmTP1r3/9S08//bSio6P1yy+/qGXLlma9BQAAAFQR0xbs0a8b8w47HmB2SShHpganTz/99KLzlyxZUqDtlltu0S233FJGFQEAAAAFzVp/VG8t3CNJevGGlureKNTkilDeKtw1TgAAAEBFsmp/vJ76abMk6YGeDXVbpzomVwQzEJwAAACACzhwKlX3f7VONruhga0i9WS/JmaXBJMQnAAAAIBCnEnN0sjPVishzaY2UcF6/da23KupCiM4AQAAAOfJzLbr/i/X6WB8mmoF++gThh2v8ghOAAAAQB6GYeifP23R6oOnFeDloc9GdlJYAMOOV3UEJwAAACCPtxbu1c8bYuTuZtF7d7dX4wiGHQfBCQAAAHD6fu0RTVuwW5L0wvUtdVV0mMkVoaIgOAEAAACSFu88oYmztkjKGXb8zi4MO45zCE4AAACo8jYeSdBDX6+X3WHoxna19FR/hh1HfgQnAAAAVGkHTqVq1Iw1SrfZdVV0qF65ubUsFoYdR34EJwAAAFRZJ5IzNGz6Kp1OzVKrWkF6/+4OsrrzFRkF0SsAAABQJaVkZmvUjDU6cjpddav7avqITvL38jC7LFRQBCcAAABUOVnZDj341TptjUlSdT9PfT6yM/dqwkURnAAAAFClOByGnvpps/7cc0o+VndNH9FJ9UL9zC4LFRzBCQAAAFXKK3N35rvBbZuoYLNLggsgOAEAAKDK+OzvA/pw6X5J0is3tVbvJuEmVwRXQXACAABAlfDb5mN6/rftkqQn+jXRzR1qm1wRXAnBCQAAAJXein3xmvDdJhmGNKxbXT3Uq6HZJcHFEJwAAABQqe04nqT7vlirLLtDA1pG6rkhLbjBLYqN4AQAAIBKKyYhXSM+W63kzGx1rheiabe1lbsboQnFR3ACAABApZSQlqXh01crLilTjSP89fGwjvK2uptdFlwUwQkAAACVTobNrns/X6u9J1JUI8hbM0Z2VpCv1eyy4MIITgAAAKhU7A5D47/ZoHWHzijQ20Ofj+qsmsE+ZpcFF0dwAgAAQKVhGIae/XWr5m2Pk6eHmz4Z3kmNIwLMLguVAMEJAAAAlcY7i/bq61WHZbFIb93eVp3rh5hdEioJghMAAAAqhe/WHNbU+bslSZOva6H+LWuYXBEqE4ITAAAAXN4fW45r4qwtkqSHejXUsG71zC0IlQ7BCQAAAC5t6e6TeuTbDXIY0h2do/REvyZml4RKiOAEAAAAl7Xm4Gnd/+Va2eyGBreuof8MbSWLhRvcovQRnAAAAOCStsYkatRna5Rhc6hXkzC9fmtbubsRmlA2CE4AAABwOftOpmj49NVKzsxW53ohev+uDvL04Kstyg69CwAAAC4lJiFd93yySvGpWWpZK1CfjOgoH093s8tCJUdwAgAAgMs4mZypez5ZpWOJGWoY5qfPR3ZWoLfV7LJQBRCcAAAA4BIS020aNn219p9KVa1gH301uouq+3uZXRaqCIITAAAAKry0rGzdO2ONdhxPUqi/l74a3UU1gnzMLgtVCMEJAAAAFVpmtl33f7lOaw+dUaC3h768t7Pqh/qZXRaqGIITAAAAKqxsu0OPfrtRf+45JR+ruz4b2VnNagSaXRaqIIITAAAAKiTDMPT0z1s0e2usPN3d9NGwDupQt5rZZaGKIjgBAACgwjEMQ//5fYe+X3tUbhbprTva6aroMLPLQhVGcAIAAECF8/aivfr0rwOSpP/e3Eb9W0aaXBGqOoITAAAAKpTP/j6g1+fvliQ9O7i5bu5Q2+SKAIITAAAAKpCf1h3V5P/bLkl67NrGGnVlfZMrAnIQnAAAAFAhzNkaqyd+3CRJGtW9vsZf08jkioBzCE4AAAAw3V97Tmn8NxvkMKRbOtTWvwY1k8ViMbsswIngBAAAAFOtPXha9325Vll2hwa0jNSUG1vJzY3QhIqF4AQAAADTrD98RiM+W6O0LLuuig7VG7e3lYc7X1FR8dArAQAAYIrNRxM0fPpqpWRmq1uD6vrono7y8nA3uyygUAQnAAAAlLutMYm659PVSs7IVud6Ifp0REf5eBKaUHERnAAAAFCudsYm6Z5PVykx3ab2dYI1fWQn+Xp6mF0WcFEEJwAAAJSbPXHJuuvjVTqTZlObqGDNGNVZ/l6EJlR8BCcAAACUi30nU3THx6sUn5qllrUC9cWozgr0tppdFlAkBCcAAACUuYOnUnXnxyt1KiVTzWoE6qt7uyjIh9AE10FwAgAAQJk6HJ+mOz5eqbikTDWJCNDXo7so2NfT7LKAYiE4AQAAoMwcPZMTmo4nZqhhmJ++Gt1FIX6EJrgeghMAAADKxPHEdN358SrFJKSrQaifvhnTVWEBXmaXBZQIwQkAAAClLi4pQ3d8tFKHT6epbnVfzRzTVeGB3maXBZQYwQkAAACl6mRypu74eKUOxqepdjUfzRzTVZFBhCa4NoITAAAASk18Sqbu/Hil9p9MVc0gb30zpqtqBfuYXRZw2QhOAAAAKBVnUrN01yertOdEiiIDvfXNfV0VFeJrdllAqeA2zQAAALhsiek2DZ+xTjtjkxUW4KWZY7qobnU/s8sCSg1HnAAAAHBZ0rOlkZ+v07ZjSQr199Q3Y7qoQZi/2WUBpYojTgAAACix5IxsfbDDXQdTkhTi56mvR3dVo/AAs8sCSh1HnAAAAFAiyRk2jflyvQ6mWBTk46Gv7u2iJpGEJlROHHECAABAsSWm2zR8+mptPJIgH3dDM4Z3VPOagWaXBZQZghMAAACKJSEtS/d8ulpbYhIV7GPV6EbpalmL0ITKjVP1AAAAUGTxKZm64+NV2hKTqOp+nvpyVEdFMQ4EqgBTg9OUKVPUqVMnBQQEKDw8XEOHDtWuXbsuus6MGTNksVjyPby9uRM1AABAWTuZnKk7Pl6pHceTFOrvpW/v66qmXNOEKsLU4LR06VKNHTtWK1eu1Pz582Wz2dS3b1+lpqZedL3AwEAdP37c+Th06FA5VQwAAFA1xSVl6PaPVmh3XIoiAr303f1dFR1BaELVYeo1TnPmzMk3PWPGDIWHh2vdunXq0aPHBdezWCyKjIws0j4yMzOVmZnpnE5KSpIk2Ww22Wy2ElRdunJrqAi1oOKjv6C46DMoLvoMCnM8MUP3TF+rQ6fTVCPIW1+O7Kg6wV75vk/RZ1BUFanPFKcGi2EYRhnWUix79+5VdHS0tmzZopYtWxa6zIwZMzR69GjVqlVLDodD7du310svvaQWLVoUuvykSZM0efLkAu0zZ86Ur69vqdYPAABQ2cRnSO9ud1d8pkUhXobGNberOldJoJJIS0vTnXfeqcTERAUGXnyAkwoTnBwOh6677jolJCTor7/+uuByK1as0J49e9S6dWslJibqtdde07Jly7Rt2zbVrl27wPKFHXGKiorSqVOnLvnhlAebzab58+erT58+slqtZpeDCo7+guKiz6C46DPI69DpNA2bvlbHEjNUJ8RHX43qpBpB+VMTfQbFVZH6TFJSkkJDQ4sUnCrMcORjx47V1q1bLxqaJKlbt27q1q2bc/qKK65Qs2bN9OGHH+qFF14osLyXl5e8vLwKtFutVtN/UHlVtHpQsdFfUFz0GRQXfQb7Tqbork/XKC4pUw3C/PTNmK6KCLzwoSb6DIqrIvSZ4uy/QgSncePG6bffftOyZcsKPWp0MVarVe3atdPevXvLqDoAAICqZU9csu74eJVOpWSqcYS/vh7dVWEBBf8QDVQlpo6qZxiGxo0bp59//lmLFi1S/fr1i70Nu92uLVu2qEaNGmVQIQAAQNWy43iSbv9opU6lZKppZIC+GUNoAiSTjziNHTtWM2fO1K+//qqAgADFxsZKkoKCguTj4yNJGjZsmGrVqqUpU6ZIkp5//nl17dpVjRo1UkJCgl599VUdOnRIo0ePNu19AAAAVAZbYxJ196erlJBmU8tagfpyVBdV8/M0uyygQjA1OL3//vuSpF69euVr/+yzzzRixAhJ0uHDh+Xmdu7A2JkzZzRmzBjFxsaqWrVq6tChg5YvX67mzZuXV9kAAACVzsYjCRr26SolZWSrbVSwPh/VWUE+XLME5DI1OBVlQL8lS5bkm542bZqmTZtWRhUBAABUPesOndbw6WuUkpmtDnWracbITgrwJjQBeVWIwSEAAABgjlX74zVqxhqlZtnVpX6Ipo/oJD8vviIC5+NfBQAAQBX1995TGv35WqXb7LqyUag+HtZRPp7uZpcFVEgEJwAAgCpoya4Tuv/LdcrMdqhn4zB9eE8HeVsJTcCFEJwAAACqmP/bdEwTvt8om93Qtc3C9e5d7eXlQWgCLobgBAAAUIV8s/qwnv55iwxDGtKmpqbe0kaeHqbe2hNwCQQnAACAKuKDpfv08uydkqS7utTR89e3lLubxeSqANdAcAIAAKjkDMPQf+fu0vtL9kmSHurVUE/0ayKLhdAEFBXBCQAAoBKzOww9++tWfb3qsCTpnwOa6oGeDU2uCnA9BCcAAIBKymZ3aML3m/R/m47JYpFeuqGV7uhcx+yyAJdEcAIAAKiE0rPseujrdVq866Ss7hZNu62tBreuaXZZgMsiOAEAAFQySRk2jZ6xVqsPnpa31U0f3N1BvZqEm10W4NIITgAAAJVIfEqmhk1frW3HkhTg5aHpIzupU70Qs8sCXB7BCQAAoJKISUjXPZ+u0v6Tqaru56nPR3VWy1pBZpcFVAoEJwAAgEpg/8kU3f3JKh1LzFDNIG99NbqLGoT5m10WUGkQnAAAAFzc1phEDZ++WvGpWWoQ5qev7u2imsE+ZpcFVCoEJwAAABe25uBpjfpsjZIzs9WiZqA+H9VZof5eZpcFVDoEJwAAABe1eNcJPfjVOmXYHOpcL0SfjOioQG+r2WUBlRLBCQAAwAX936Zjeuy7jcp2GOrdJEzv3dVBPp7uZpcFVFoEJwAAABczc9VhPfPLFhmGNKRNTU29pY08PdzMLguo1AhOAAAALsIwDL21cK+mLdgtSbqrSx09f31LubtZTK4MqPwITgAAAC4g2+7Qv3/dpm9WH5Ykje3dUI/3bSKLhdAElAeCEwAAQAWXnmXXw9+s14IdJ2SxSM9f10L3dKtndllAlUJwAgAAqMBOp2bp3s/XaMPhBHl5uOnN29upf8tIs8sCqhyCEwAAQAV15HSahk9frf2nUhXkY9WnwzuqY70Qs8sCqiSCEwAAQAW0NSZRI2es0cnkTNUK9tHnozqpUXiA2WUBVRbBCQAAoIL5c89JPfDlOqVm2dU0MkCfj+qsiEBvs8sCqjSCEwAAQAXy84ajeuKHzcp2GOrWoLo+HNZBgd5Ws8sCqjyCEwAAQAVgGIY+XLZfL8/eKUm6rk1NvXpLa3l5uJtcGQCJ4AQAAGA6u8PQC79t14zlByVJY66qr4kDmsmNG9sCFQbBCQAAwEQZNrsmfL9Rf2yJlST9a1Azjb6qgclVATgfwQkAAMAkiWk2jflirVYfPC1PdzdNvbWNhrSpaXZZAApBcAIAADDBsYR0DZ++WntOpCjAy0MfDuugKxqGml0WgAsgOAEAAJSznbFJGjF9jWKTMhQR6KXPR3VW08hAs8sCcBEEJwAAgHK0Yl+87vtyrZIzshUd7q8ZozqrVrCP2WUBuASCEwAAQDn5bfMxTfhuk7LsDnWqV00fD+uoYF9Ps8sCUAQEJwAAgDJmGIbeW7JPr87dJUnq3yJSb9zeVt5W7tEEuAqCEwAAQBnKynZo4qwt+mn9UUnSqO719cygZnLnHk2ASyE4AQAAlJGEtCzd/+U6rTpwWu5uFk26roXu6VrX7LIAlADBCQAAoAwcOJWqUTPW6MCpVPl7eeidO9upV5Nws8sCUEIEJwAAgFK2an+87v9qnRLSbKoV7KPpIzqpSWSA2WUBuAwEJwAAgFL007qj+ueszbLZDbWJCtbHwzooPMDb7LIAXCaCEwAAQCkwDEPT5u/WW4v2SpIGtorU1FvayseTkfOAyoDgBAAAcJkybHY98eNm/d+mY5KkB3s11BN9m8iNkfOASoPgBAAAcBlOpWTqvi/Wav3hBHm4WfTSDa10a6cos8sCUMoITgAAACW0Jy5Zoz5foyOn0xXo7aEP7umgKxqGml0WgDJAcAIAACiBv/ac0oNfr1NyRrbqVvfV9BGd1DDM3+yyAJQRghMAAEAxfbP6sP71y1bZHYY61q2mj4Z1VIifp9llAShDBCcAAIAicjgMvTJnpz5ctl+SNLRtTb1yc2t5eTByHlDZEZwAAACKIC0rW49+u1HztsdJkh69NlqPXBMti4WR84CqgOAEAABwCXFJGRr9+VptiUmUp7ub/ntzaw1tV8vssgCUI4ITAADARaw/fEYPfLlOJ5IzFeLnqQ/v6aBO9ULMLgtAOStxcHI4HNq7d69OnDghh8ORb16PHj0uuzAAAACz/bjuqJ6etUVZdocaR/jr42EdVbe6n9llATBBiYLTypUrdeedd+rQoUMyDCPfPIvFIrvdXirFAQAAmCHb7tBLf+zU9L8PSJL6NI/QtNvayt+Lk3WAqqpE//ofeOABdezYUb///rtq1KjBRZEAAKDSSEjL0sPfbNCfe05JksZfE61Hr4mWmxvfd4CqrETBac+ePfrxxx/VqFGj0q4HAADANLvjkjXmi7U6FJ8mH6u7pt7aRgNb1TC7LAAVgFtJVurSpYv27t1b2rUAAACYZsH2ON3w7t86FJ+mWsE++unBKwhNAJxKdMTp4Ycf1j/+8Q/FxsaqVatWslqt+ea3bt26VIoDAAAoa4Zh6L0l+/TavF0yDKlL/RC9d1d7Vff3Mrs0ABVIiYLTTTfdJEkaNWqUs81iscgwDAaHAAAALiMtK1tP/LhZv28+Lkm6p2tdPTukuazuJTopB0AlVqLgdODAgdKuAwAAoFzFJKRrzOdrtf14kjzcLHr++pa6s0sds8sCUEGVKDjVrVu3tOsAAAAoN6sPnNaDX61TfGqWqvt56v27O6hzfW5qC+DCSnwzgn379umNN97Qjh07JEnNmzfXI488ooYNG5ZacQAAAKXt61WH9Nyv25TtMNSiZqA+GtZRtYJ9zC4LQAVXohN4586dq+bNm2v16tVq3bq1WrdurVWrVqlFixaaP39+adcIAABw2Wx2h/71yxY98/NWZTsMDW5dQz8+cAWhCUCRlOiI0z//+U899thjevnllwu0P/XUU+rTp0+pFAcAAFAa4lMy9eDX67X6wGlZLNLjfZvooV4NZbFwU1sARVOiI047duzQvffeW6B91KhR2r59+2UXBQAAUFq2H0vSde/8rdUHTsvfy0Mf39NRY3s3IjQBKJYSBaewsDBt3LixQPvGjRsVHh5+uTUBAACUip83HNWN7/+tmIR01avuq58fukLXNo8wuywALqhEwWnMmDG677779Morr+jPP//Un3/+qZdffln333+/xowZU+TtTJkyRZ06dVJAQIDCw8M1dOhQ7dq165Lr/fDDD2ratKm8vb3VqlUr/fHHHyV5GwAAoJLKynbo2V+36rHvNinD5lCPxmH6deyVio4IMLs0AC6qRNc4/fvf/1ZAQICmTp2qiRMnSpJq1qypSZMmafz48UXeztKlSzV27Fh16tRJ2dnZevrpp9W3b19t375dfn5+ha6zfPly3XHHHZoyZYoGDx6smTNnaujQoVq/fr1atmxZkrcDAAAqkeOJ6Xro6/XacDhBkjT+mmg9ck203N04NQ9AyZUoOFksFj322GN67LHHlJycLEkKCCj+X3DmzJmTb3rGjBkKDw/XunXr1KNHj0LXefPNN9W/f3898cQTkqQXXnhB8+fP1zvvvKMPPvig2DUAAIDKY/m+U3p45gbFp2Yp0NtDb9zeVlc35dQ8AJevxPdxylWSwHQhiYmJkqSQkAvfgG7FihWaMGFCvrZ+/frpl19+KXT5zMxMZWZmOqeTkpIkSTabTTab7TIrvny5NVSEWlDx0V9QXPQZFJer9hnDMPTxXwc1df4eOQypaWSA3r2jjeqE+Lrce3E1rtpnYJ6K1GeKU4PFMAyjKAu2b99eCxcuVLVq1dSuXbuLjkSzfv36IheQy+Fw6LrrrlNCQoL++uuvCy7n6empzz//XHfccYez7b333tPkyZMVFxdXYPlJkyZp8uTJBdpnzpwpX1/fYtcJAAAqloxs6et9btp8OufS7c5hDt1S3yFPd5MLA1DhpaWl6c4771RiYqICAwMvumyRjzhdf/318vLycr4u7SE8x44dq61bt140NJXExIkT8x2hSkpKUlRUlPr27XvJD6c82Gw2zZ8/X3369JHVajW7HFRw9BcUF30GxeVqfWZPXIrGfrNRB06nyepu0b8HNdXtHWsz1Hg5crU+A/NVpD6TezZaURQ5OD333HPO15MmTSpWQZcybtw4/fbbb1q2bJlq16590WUjIyMLHFmKi4tTZGRkoct7eXk5A19eVqvV9B9UXhWtHlRs9BcUF30GxeUKfebXjTH6509blG6zq2aQt967u4PaRgWbXVaV5Qp9BhVLRegzxdl/iYYjb9CggeLj4wu0JyQkqEGDBkXejmEYGjdunH7++WctWrRI9evXv+Q63bp108KFC/O1zZ8/X926dSvyfgEAgOvKynZo0v+26ZFvNyrdZteVjUL12/irCE0AylSJBoc4ePCg7HZ7gfbMzEwdPXq0yNsZO3asZs6cqV9//VUBAQGKjY2VJAUFBcnHx0eSNGzYMNWqVUtTpkyRJD3yyCPq2bOnpk6dqkGDBunbb7/V2rVr9dFHH5XkrQAAABcSl5Shh75er3WHzkiSxvZuqAl9mjDUOIAyV6zg9L///c/5eu7cuQoKCnJO2+12LVy4sEhHjXK9//77kqRevXrla//ss880YsQISdLhw4fl5nbuwNgVV1yhmTNn6l//+peefvppRUdH65dffuEeTgAAVHIr98dr3MwNOpWSqQAvD71+W1v1ac5Q4wDKR7GC09ChQyXl3Mdp+PDh+eZZrVbVq1dPU6dOLfL2ijKg35IlSwq03XLLLbrllluKvB8AAOC6DMPQJ38e0MtzdsruMNQ0MkAf3N1B9UL9zC4NQBVSrODkcDgkSfXr19eaNWsUGhpaJkUBAABIUkpmtp78cZP+2JJzOv8N7WrppRtayYexxgGUsxJd43TgwIHSrgMAACCfPXHJeuCrddp3MjVnqPHBzXVP17oMNQ7AFCUKTpKUmpqqpUuX6vDhw8rKyso3b/z48ZddGAAAqJoMw9AP647q2V+3KsPmUGSgt967u73a16lmdmkAqrASBacNGzZo4MCBSktLU2pqqkJCQnTq1Cn5+voqPDyc4AQAAEokNTNb//5lq2ZtiJEkXdkoVG/c3lah/gXvyQgA5alE93F67LHHNGTIEJ05c0Y+Pj5auXKlDh06pA4dOui1114r7RoBAEAVsON4kq575y/N2hAjN4v0eN/G+mJUZ0ITgAqhREecNm7cqA8//FBubm5yd3dXZmamGjRooP/+978aPny4brzxxtKuEwAAVFKGYeib1Uc0+f+2KTPboYhAL711ezt1aVDd7NIAwKlEwclqtTrvrRQeHq7Dhw+rWbNmCgoK0pEjR0q1QAAAUHklZ9j09M9b9X+bjkmSejUJ09Rb2qg6R5kAVDAlCk7t2rXTmjVrFB0drZ49e+rZZ5/VqVOn9OWXX3IjWgAAUCRbYxI1buZ6HYxPk7ubRU/0a6L7rmogNzdGzQNQ8ZToGqeXXnpJNWrUkCS9+OKLqlatmh588EGdPHlSH330UakWCAAAKhfDMPTlioO68b3lOhifpppB3vr+/q56oGdDQhOACqvYR5wMw1B4eLjzyFJ4eLjmzJlT6oUBAIDKJynDpn/+tNl5Q9trm4XrtVvaKNjX0+TKAODiShScGjVqpG3btik6OrosagIAAJXQ5qMJGjtzvY6cTpfV3aKn+jfVvVfW54a2AFxCsYOTm5uboqOjFR8fT3ACAACXZBiGPvv7oKbM3iGb3VDtaj565872ahsVbHZpAFBkJbrG6eWXX9YTTzyhrVu3lnY9AACgEklMs+n+L9fp+d+2y2Y31L9FpH4ffxWhCYDLKdGoesOGDVNaWpratGkjT09P+fj45Jt/+vTpUikOAAC4rvWHz+jhmRsUk5AuT3c3PTOomYZ1q8upeQBcUomC07Rp0/hPDwAAFMrhMPTJX/v13zm7lO0wVLe6r965o71a1Q4yuzQAKLESBacRI0aUchkAAKAyiEvK0OM/bNKfe05Jkga3rqEpN7ZSgLfV5MoA4PKUKDi5u7vr+PHjCg8Pz9ceHx+v8PBw2e32UikOAAC4jnnbYvXUT5t1Js0mb6ub/j24ue7sXIezVABUCiUKToZhFNqemZkpT0/uwwAAQFWSlpWt//y+QzNXHZYktagZqDdvb6dG4f4mVwYApadYwemtt96SJFksFn3yySfy9z/3H6LdbteyZcvUtGnT0q0QAABUWFtjEjX+2w3afzJVknR/jwaa0LexvDzcTa4MAEpXsYLTtGnTJOUccfrggw/k7n7uP0VPT0/Vq1dPH3zwQelWCAAAKhyHw9DHf+7Xa/N2yWY3FBHopddvbavujULNLg0AykSxgtOBAwckSb1799asWbNUrVq1MikKAABUXMcT0/WP7zdp+b54SVK/FhF6+cbWqubH6foAKq8SXeO0ePHi0q4DAAC4gNlbjuufs7YoMd0mH6u7nhvSXLd1imIACACVXomCk91u14wZM7Rw4UKdOHFCDocj3/xFixaVSnEAAKBiSM3M1vP/t13frT0iSWpVK0hv3t5WDcIYAAJA1VCi4PTII49oxowZGjRokFq2bMlfmQAAqMQ2HUnQo99t1IFTqbJYpAd6NtRj1zaWp4eb2aUBQLkpUXD69ttv9f3332vgwIGlXQ8AAKgg7A5DHyzdp2nzdyvbYahGkLdev7WtujWsbnZpAFDuShScPD091ahRo9KuBQAAVBDHEtL1xKxtWn3gtCRpUKsaeumGVgrytZpcGQCYo0TH2P/xj3/ozTffvOCNcAEAgOvacMqiIe+u0OoDp+Xr6a5Xb26td+5sR2gCUKWV6IjTX3/9pcWLF2v27Nlq0aKFrNb8/5HOmjWrVIoDAADlJzHdpud+2aJf9rhLylabqGC9eVtb1Qv1M7s0ADBdiYJTcHCwbrjhhtKuBQAAmOTPPSf15I+bdTwxQxYZerBnQz3Wt4ms7gwAAQBSCYPTZ599Vtp1AAAAE6RmZmvK7B36auVhSVLdEF/dUDNJY69tRGgCgDxK/D9idna2FixYoA8//FDJycmSpGPHjiklJaXUigMAAGVnzcHTGvjWn87QNLxbXf1vbFfVDzC5MACogEp0xOnQoUPq37+/Dh8+rMzMTPXp00cBAQF65ZVXlJmZqQ8++KC06wQAAKUkw2bX6/N36+M/98swpJpB3vrvzW10ZXSobDab2eUBQIVUoiNOjzzyiDp27KgzZ87Ix8fH2X7DDTdo4cKFpVYcAAAoXVuOJmrI23/po2U5oemWDrU157EeujI61OzSAKBCK9ERpz///FPLly+Xp6dnvvZ69eopJiamVAoDAAClx2Z36J1Fe/XO4r2yOwyF+ntpyo2t1Kd5hNmlAYBLKFFwcjgcstvtBdqPHj2qgABOjAYAoCLZHZesCd9v1NaYJEk5N7N9YWhLhfh5XmJNAECuEp2q17dvX73xxhvOaYvFopSUFD333HMaOHBgadUGAAAug91h6KNl+zT47b+0NSZJwb5WvX1HO717V3tCEwAUU4mOOE2dOlX9+vVT8+bNlZGRoTvvvFN79uxRaGiovvnmm9KuEQAAFNPBU6l6/IdNWnvojCTp6qbhevnGVgoP9Da5MgBwTSUKTrVr19amTZv03XffadOmTUpJSdG9996ru+66K99gEQAAoHwZhqGvVh3WS7/vULrNLn8vDz07uLlu6VhbFovF7PIAwGWVKDhJkoeHh+666y7dddddpVkPAAAooWMJ6Xrqp836c88pSVK3BtX135tbKyrE1+TKAMD1lSg4TZkyRRERERo1alS+9unTp+vkyZN66qmnSqU4AABwaYZh6Ie1R/XC79uVnJEtb6ub/tm/qYZ1qyc3N44yAUBpKNHgEB9++KGaNm1aoL1Fixbc/BYAgHJ05HSa7vl0tZ78abOSM7LVNipYf4y/SiO61yc0AUApKtERp9jYWNWoUaNAe1hYmI4fP37ZRQEAgIuzOwx9vvygXp27S+k2u7w83PR43yYa2b2ePNxL9HdRAMBFlCg4RUVF6e+//1b9+vXztf/999+qWbNmqRQGAAAKt/dEsp78cbPWH06QJHWpH6JXbmqteqF+5hYGAJVYiYLTmDFj9Oijj8pms+nqq6+WJC1cuFBPPvmk/vGPf5RqgQAAIIfN7tCHS/fprYV7lWV3yN/LQxMHNtUdnepwWh4AlLESBacnnnhC8fHxeuihh5SVlSVJ8vb21lNPPaWJEyeWaoEAAEDaGpOoJ37crB3HkyRJvZuE6cUbWqlmMLcBAYDyUKLgZLFY9Morr+jf//63duzYIR8fH0VHR8vLy6u06wMAoErLsNn15sI9+mjZftkdhqr5WvXckBa6vm1N7ssEAOWoxPdxkiR/f3916tSptGoBAAB5rDl4Wk/9uFn7T6VKkga1rqHJ17VQqD9/qASA8lai4JSamqqXX35ZCxcu1IkTJ+RwOPLN379/f6kUBwBAVZSSma1X5+zUFysPyTCk8AAvvTC0pfq1iDS7NACoskoUnEaPHq2lS5fqnnvuUY0aNThVAACAUrJs90lNnLVFMQnpkqRbO9bWMwObK8jXanJlAFC1lSg4zZ49W7///ru6d+9e2vUAAFAlJaRl6T+/79CP645KkmpX89HLN7bWldGhJlcGAJBKGJyqVaumkJCQ0q4FAIAqxzAMzdkaq3//uk2nUjJlsUgjrqinx/s2kZ/XZV2KDAAoRSX6H/mFF17Qs88+q88//1y+vr6lXRMAAFXC0TNpeu7XbVq484QkqWGYn/57c2t1qMsfJwGgoilRcJo6dar27duniIgI1atXT1Zr/vOu169fXyrFAQBQGdnsDn329wFNm79H6Ta7rO4W3d+jocZd3UjeVnezywMAFKJEwWno0KGlXAYAAFXD+sNn9PSsLdoZmyxJ6lwvRC/e0FLREQEmVwYAuJgSBafnnnuutOsAAKBSS0y36dW5O/X1qsMyDCnY16qnBzTTzR1qy82N0WkBoKK7rKtO161bpx07dkiSWrRooXbt2pVKUQAAVBaGYei3zcf1/G/bdTI5U5J0U/vaenpgU1XnRrYA4DJKFJxOnDih22+/XUuWLFFwcLAkKSEhQb1799a3336rsLCw0qwRAACXdDg+Tf/6dauW7T4pSWoQ6qf/3NBSVzRkiHEAcDVuJVnp4YcfVnJysrZt26bTp0/r9OnT2rp1q5KSkjR+/PjSrhEAAJeSle3Qu4v3qs+0pVq2+6Q83d306LXRmv3oVYQmAHBRJTriNGfOHC1YsEDNmjVztjVv3lzvvvuu+vbtW2rFAQDgatYcPK2nZ23RnhMpkqQrGlbXf4a2VIMwf5MrAwBcjhIFJ4fDUWAIckmyWq1yOByXXRQAAK4mIS1LL8/eqW/XHJEkVffz1DODmumGdrVksTD4AwC4uhIFp6uvvlqPPPKIvvnmG9WsWVOSFBMTo8cee0zXXHNNqRYIAEBFZhiGft4Qoxd/36H41CxJ0u2dovTPAU0V7OtpcnUAgNJSouD0zjvv6LrrrlO9evUUFRUlSTpy5Ihatmypr776qlQLBACgotp3MkX//mWrlu+LlyRFh/vrpRtbqVO9EJMrAwCUthIFp6ioKK1fv14LFizQzp07JUnNmjXTtddeW6rFAQBQEaVmZuvtRXv16V/7ZbMb8vJw0/hrojXmqgby9CjRuEsAgAquWMFp0aJFGjdunFauXKnAwED16dNHffr0kSQlJiaqRYsW+uCDD3TVVVeVSbEAAJgp955ML/6+Q7FJGZKkXk3C9Px1LVWnuq/J1QEAylKxgtMbb7yhMWPGKDAwsMC8oKAg3X///Xr99dcJTgCASmdXbLKe+99Wrdx/WpIUFeKj5wa30DXNwhn8AQCqgGIFp02bNumVV1654Py+ffvqtddeu+yiAACoKJIybHpzwR7NWH5QdkfOaXljezfSfT0ayNvqbnZ5AIByUqwTsePi4godhjyXh4eHTp48WeTtLVu2TEOGDFHNmjVlsVj0yy+/XHT5JUuWyGKxFHjExsYWeZ8AABSFYRj6ad1RXf3aUn361wHZHYb6tYjQggk9Nf6aaEITAFQxxTriVKtWLW3dulWNGjUqdP7mzZtVo0aNIm8vNTVVbdq00ahRo3TjjTcWeb1du3blO10wPDy8yOsCAHAp244l6rlft2ntoTOSpPqhfpp0XQv1bBxmcmUAALMUKzgNHDhQ//73v9W/f395e3vnm5eenq7nnntOgwcPLvL2BgwYoAEDBhSnBEk5QSk4OLjY6wEAcDEJaVl6ff5ufbXykByG5OvproevjtaoK+vJy4MjTABQlRUrOP3rX//SrFmz1LhxY40bN05NmjSRJO3cuVPvvvuu7Ha7nnnmmTIpNK+2bdsqMzNTLVu21KRJk9S9e/cLLpuZmanMzEzndFJSkiTJZrPJZrOVea2XkltDRagFFR/9BcVFnykah8PQj+tj9Nr8PTqTlvNZDWoZqaf6N1aNIG/JcMhmc5hcZfmgz6C46DMororUZ4pTg8UwDKM4Gz906JAefPBBzZ07V7mrWiwW9evXT++++67q169fvGpzC7FY9PPPP2vo0KEXXGbXrl1asmSJOnbsqMzMTH3yySf68ssvtWrVKrVv377QdSZNmqTJkycXaJ85c6Z8fRk6FgCqukMp0o/73XU4NWdkvEgfQzfXdyg6qFi/HgEALigtLU133nmnEhMTCx05PK9iB6dcZ86c0d69e2UYhqKjo1WtWrUSFesspAjBqTA9e/ZUnTp19OWXXxY6v7AjTlFRUTp16tQlP5zyYLPZNH/+fPXp0+eiA28AEv0FxUefubDTqVmaOn+PflgfI8OQ/Lzc9cjVjXR3lyhZ3avuTWzpMygu+gyKqyL1maSkJIWGhhYpOBXrVL28qlWrpk6dOpV09VLTuXNn/fXXXxec7+XlJS8vrwLtVqvV9B9UXhWtHlRs9BcUF33mHJvdoS9XHNIbC3YrKSNbknRju1r658CmCg/wvsTaVQd9BsVFn0FxVYQ+U5z9lzg4VRQbN24s1kh+AICqyTAMLdp5Qi/+sUP7T6ZKkprVCNTz17dQp3ohJlcHAKjoTA1OKSkp2rt3r3P6wIED2rhxo0JCQlSnTh1NnDhRMTEx+uKLLyRJb7zxhurXr68WLVooIyNDn3zyiRYtWqR58+aZ9RYAAC5gV2yy/vP7dv2555QkKdTfU//o20S3doySu5vF5OoAAK7A1OC0du1a9e7d2zk9YcIESdLw4cM1Y8YMHT9+XIcPH3bOz8rK0j/+8Q/FxMTI19dXrVu31oIFC/JtAwCAXPEpmXp9/m59s/qwHIbk6e6mUVfW19jeDRXgzSlFAICiMzU49erVSxcbm2LGjBn5pp988kk9+eSTZVwVAMDVZWbb9fnyg3p74V4lZ+ZcxzSwVaT+2b+Z6lRnRFUAQPG5/DVOAADkMgxDc7fFacrsHToUnyZJalEzUM8Obq4uDaqbXB0AwJURnAAAlcK2Y4l64bftWrn/tCQpLMBLT/Zropva15Yb1zEBAC4TwQkA4NJOJGdo6tzd+n7dERmG5OXhpjFXNdCDvRrKz4tfcwCA0sFvFACAS8qw2fXpXwf03uK9Ss2yS5KGtKmpp/o3Ue1qXMcEAChdBCcAgEsxDEO/bzmuKX/sVExCuiSpTVSwnh3cTB3qcj8mAEDZIDgBAFzGukOn9dIfO7Xu0BlJUmSgt54a0ETXt6nFdUwAgDJFcAIAVHh7T6Tov3N2at72OEmSt9VND/RsqPt6NJCvJ7/KAABlj982AIAK60RShqYt2KPv1x6R3WHIzSLd2jFKj17bWJFB3maXBwCoQghOAIAKJyUzWx8t3aeP/zygdFvOwA/XNovQU/2bKDoiwOTqAABVEcEJAFBhZGU79M3qw3pr4R7Fp2ZJktrVCdbEAc3UuT4DPwAAzENwAgCYzjAM/bElVv+du1OH4tMkSfVD/fRkvybq3zJSFgsDPwAAzEVwAgCYauX+eE2ZvVObjiRIkkL9vfTItdG6vVOUrO5u5hYHAMBZBCcAgCl2xSbrlTk7tWjnCUmSr6e77uvRQGOuaiA/L349AQAqFn4zAQDK1fHEdE2bv1s/rjsqhyG5u1l0Z+c6Gn9NtMICvMwuDwCAQhGcAADlIjHdpg+W7tP0vw4oM9shSRrQMlJP9GuiBmH+JlcHAMDFEZwAAGUqNTNbM5Yf1IdL9ykpI1uS1KleNf1zQDN1qFvN5OoAACgaghMAoExk2Oz6etVhvb9kr06l5Awt3jjCX0/0a6prm4UzUh4AwKUQnAAApcpmd+iHtUf19qI9Op6YIUmqW91XE/o01uDWNeXuRmACALgeghMAoFTYHYb+tylGbyzY47wXU40gb42/Jlo3d6jN0OIAAJdGcAIAXBbDMDR3W6xen79bu+NSJEmh/p56qFcj3dmljryt7iZXCADA5SM4AQBKxDAMLd19UlPn7daWmERJUqC3h+7v2VAjrqjHvZgAAJUKv9UAAMW2+sBpvTZ3l1YfPC0p5+a1915ZX6OvaqAgH6vJ1QEAUPoITgCAItt8NEGvzdutZbtPSpI8Pdw0rGtdPdiroar7c/NaAEDlRXACAFzS7rhkTZ23S3O3xUmSPNwsuq1TlB6+OlqRQd4mVwcAQNkjOAEALmhXbLLeWrRHf2w5LsOQ3CzS0Ha19Og1jVWnuq/Z5QEAUG4ITgCAAnbGJumthXv0x5ZYZ9uAlpGa0KexoiMCTKwMAABzEJwAAE47jucEptlbzwWmga0i9fDV0WpWI9DEygAAMBfBCQCgbccS9dbCPc5rmCwWaWCrGhp/dbSaRHKECQAAghMAVGFbY3IC07zt5wLT4NY19fDVjdSYU/IAAHAiOAFAFbQ1JlFvLNijBTvOBaYhZwMT1zABAFAQwQkAqpDNRxP05oI9WrjzhKScUfKua1NT466OVqNwf5OrAwCg4iI4AUAVsPloot5dekCL8gSm69vW0rirG6lhGIEJAIBLITgBQCW24UiCPtzhpu0rVkk6dx+mcb0bqQGBCQCAIiM4AUAlYxiG/tp7Su8u3quV+09LcpO7m0U3nA1M9UL9zC4RAACXQ3ACgErC4TA0b3us3l28T1tiEiVJVneL2ofY9eLdPdQoIsjkCgEAcF0EJwBwcTa7Q79uPKYPlu7T3hMpkiRvq5vu6FxHI7vV0Ya/F6luiK/JVQIA4NoITgDgojJsdn235og+WrZfMQnpkqRAbw8Nv6KeRlxRT9X9vWSz2bTB5DoBAKgMCE4A4GKSMmz6auUhTf/rgE6lZEmSQv29NPqq+rqrSx0FeFtNrhAAgMqH4AQALuJUSqY++/uAvlh+SMmZ2ZKk2tV8dH+PBrqlY5S8re4mVwgAQOVFcAKACi4mIV0fL9uvb9ccVobNIUlqFO6vh3o11JA2NWV1dzO5QgAAKj+CEwBUUPtOpuiDJfv084YYZTsMSVKb2kF6qHcj9WkWITc3i8kVAgBQdRCcAKACMQxD6w6d0UfL9mv+jjgZOXlJVzSsrod6NVL3RtVlsRCYAAAobwQnAKgA7A5D87bF6qM/92vD4QRn+7XNIvRQ74ZqX6eaecUBAACCEwCYKT3Lrh/XHdEnfx3Qofg0SZKnu5tubF9Lo6+qr0bhASZXCAAAJIITAJjiVEqmvlh+UF+uPKQzaTZJUpCPVfd0rathV9RVeIC3yRUCAIC8CE4AUI72nUzRJ38e0E/rjyorO2eEvKgQH42+soFu6Vhbvp78twwAQEXEb2gAKGOGYWjt2QEfFuQZ8KFNVLDu79FA/VpEyp0R8gAAqNAITgBQRuwOQ3O3xeqjZfu18UiCs/3aZhG6r0cDdapXjRHyAABwEQQnAChlaVnZ+nHdUX3y5wEdPn12wAcPN93UvrbuvbK+GoX7m1whAAAoLoITAJSSmIR0fbHioL5dfUSJ6TkDPgT7WjWsa13d062ewgK8TK4QAACUFMEJAC5D7vVLn/19QHO3xcnuyLmAqU6Ir0ZfVV83d2DABwAAKgN+mwNACWRm2/X75uP67O+D2hKT6Gy/omF1jexeX1c3DWfABwAAKhGCEwAUw8nkTH296pC+WnlYp1IyJUleHm66oV0tjeheT00jA02uEAAAlAWCEwAUwdaYRE3/+4B+23RcWfac+y9FBHppWLd6uqNzHYX4eZpcIQAAKEsEJwC4gGy7Q/O3x+mzvw9q9cHTzva2UcEadWV9DWgZKau7m4kVAgCA8kJwAoDzJKbZ9O2aw/pixSHFJKRLkjzcLBrYqoZGdq+ndnWqmVwhAAAobwQnADhrd1yyvlhxUD+ti1G6zS5JCvHz1J2d6+jurnUVGeRtcoUAAMAsBCcAVZrN7tC8bXH6cuVBrdx/7nS8ppEBGtm9nq5vW0veVncTKwQAABUBwQlAlRSbmKGZqw/r29WHdSI5Z3Q8N4t0bbMIjeheT90aVJfFwnDiAAAgB8EJQJVhGIZW7IvXlysPad72czerDfX30p2do3R75zqqGexjcpUAAKAiIjgBqPSSMmyate6ovlx5SPtOpjrbO9cP0T1d66pfi0h5ejA6HgAAuDCCE4BKa/uxJH258pB+2XBusAc/T3fd0L6W7ulaT00iA0yuEAAAuAqCE4BKJTPbrjlbY/XlikNae+iMsz063F/DutXV0Ha1FOBtNbFCAADgighOACqFo2fSNHPVYX235ojiU7Mk5dx7qV/LSN3Tta661A9hsAcAAFBiBCcALstmd2jRzhP6ZvVhLd19UkbOWA+KDPTWnV3q6PZOUQoP5N5LAADg8hGcALicI6fT9O2aw/ph7VHnUOKSdEXD6hrWra6ubRYhD3cGewAAAKXH1G8Wy5Yt05AhQ1SzZk1ZLBb98ssvl1xnyZIlat++vby8vNSoUSPNmDGjzOsEYL6sbIf+2HJc93y6Slf9d7HeXbxPJ5IzFervqft7NtDix3tp5piu6t+yBqEJAACUOlOPOKWmpqpNmzYaNWqUbrzxxksuf+DAAQ0aNEgPPPCAvv76ay1cuFCjR49WjRo11K9fv3KoGEB5O3AqVd+uOayf1h3VqZQsZ/tV0aG6o3MdXdssgqHEAQBAmTM1OA0YMEADBgwo8vIffPCB6tevr6lTp0qSmjVrpr/++kvTpk0jOAGVSGa2XXO3xembVYe1Yn+8sz08wEu3dKyt2zrWUZ3qviZWCAAAqhqXusZpxYoVuvbaa/O19evXT48++ugF18nMzFRm5rlrIJKSkiRJNptNNputTOosjtwaKkItqPgqe3/ZdzJV3689qp83HtOZtJz3aLFIPaJDdXvH2urVONR5Gl5l/QxKW2XvMyh99BkUF30GxVWR+kxxanCp4BQbG6uIiIh8bREREUpKSlJ6erp8fHwKrDNlyhRNnjy5QPu8efPk61tx/mI9f/58s0uAC6lM/SXLLm06bdGKODftSz43XHiwp6Gu4Ya6hDsU4hWrrAOxmnfAxEJdXGXqMygf9BkUF30GxVUR+kxaWlqRl3Wp4FQSEydO1IQJE5zTSUlJioqKUt++fRUYGGhiZTlsNpvmz5+vPn36yGrlppy4uMrSXwzD0OaYJP20Pka/bYlVcka2JMnNIvVuEqZbO9ZWj0bVGeShFFSWPoPyQ59BcdFnUFwVqc/kno1WFC4VnCIjIxUXF5evLS4uToGBgYUebZIkLy8veXl5FWi3Wq2m/6Dyqmj1oGJz1f5yMjlTP284qh/WHtWeEynO9lrBPrq9U5Ru6RilyCDuu1QWXLXPwDz0GRQXfQbFVRH6THH271LBqVu3bvrjjz/ytc2fP1/dunUzqSIAl5KVnXOT2h/XHdHiXSdld+TcpdbLw00DWkbqlo5R6tagutzcLJfYEgAAgHlMDU4pKSnau3evc/rAgQPauHGjQkJCVKdOHU2cOFExMTH64osvJEkPPPCA3nnnHT355JMaNWqUFi1apO+//16///67WW8BwAXsjE3SD2uP6pcNMYpPPTeMeLs6wbqlQ5QGt6mhQG/+MgkAAFyDqcFp7dq16t27t3M691qk4cOHa8aMGTp+/LgOHz7snF+/fn39/vvveuyxx/Tmm2+qdu3a+uSTTxiKHKggEtKy9L9Nx/TD2qPaEpPobA8L8NKN7Wvplg611Sg8wMQKAQAASsbU4NSrVy8ZhnHB+TNmzCh0nQ0bNpRhVQCKw+4w9Oeek/ph3VHN3xanLLtDkmR1t+iaphG6pWNt9WwcxkAPAADApbnUNU4AKo69J1I0a/1RzVofo9ikDGd7sxqBuqVDbQ1tV0shfp4mVggAAFB6CE4AiuxUSqb+b9Mx/bwhRpuPnjsVL9jXqqFta+nmDrXVslaQiRUCAACUDYITgIvKsNk1b3ucftkQo6W7z42K5+FmUc/GYbqxfW1d2zxcXh7uJlcKAABQdghOAApwOAytPBCvn9fHaPbWWKVkZjvntakdpBva1dKQNjVV3b/gPdIAAAAqI4ITAKfdccn6eUOMft0Qo2OJ565bqhXsoxva1dLQdrXUKNzfxAoBAADMQXACqrgTyRn638ac65a2HUtytgd4e2hw6xoa2raWOtUL4Qa1AACgSiM4AVVQepZd87bHatb6GP2556TOXrYkDzeLejUJ143ta+nqpuHytnLdEgAAgERwAqqMrGyHlu0+qf/bfEzzt8cpLcvunNc2Klg3tq+lwa1rMoQ4AABAIQhOQCVmdxhatT9e/9t0TLO3xiox3eacFxXioxva1dbQtjXVIIzrlgAAAC6G4ARUMoZhaMORBP1v4zH9vuW4TiZnOueFBXhpcOsauq5NTbWNCpbFwnVLAAAARUFwAiqJnbFJ+t/GY/q/zcd05HS6sz3Ix6oBLSN1XZua6tKgutwZ5AEAAKDYCE6ACzsUn+oMS7vjUpztvp7u6tM8Qte1qamrosPk6eFmYpUAAACuj+AEuJiETOmz5Yf0+5ZYbTqa6Gz3dHdTryZhGtKmpq5pFi5fT/55AwAAlBa+WQEuIC4pQ7O3HNdvm49p3SF3GdolSXKzSN0bhWpIm5rq1yJSQT5WkysFAAConAhOQAUVm5ihP7Yc1x9bjmvd4TMyjNw5FnWoE6zr29XSgJY1FBbgZWaZAAAAVQLBCahAjiWka/bW2JywdOhMvnnt6wSrf4sIWeO26e4bOstq5egSAABAeSE4ASaLSUjX7C3H9fuW49pwOCHfvI51q2lgqxoa0CpSNYJ8ZLPZ9Mcf28wpFAAAoAojOAEmOHomTbO3xOr3Lce18UiCs91ikTrVDdGAVpEa0LKGIoO8zSsSAAAATgQnoJwcOZ3mvGYp72h4FovUqV6IBrWqof4tIxURSFgCAACoaAhOQBkxDEO741I0d1us5myN1fbjSc55bhapc/2csNSvRaTCCUsAAAAVGsEJKEUOh6ENRxI0b1us5m6L1cH4NOc8N4vUpX51DWxdQ/1bRDIaHgAAgAshOAGXyWZ3aOX+eM3ZGqv52+N0IjnTOc/Tw009okPVt0Wkrm0WoRA/TxMrBQAAQEkRnIASSMvK1rLdJzV3W5wW7ohTUka2c16Al4d6Nw1XvxaR6tUkTH5e/DMDAABwdXyjA4ooIS1LC3ac0Nxtsfpzz0ll2BzOeaH+XurTPEL9WkSoW8Pq8vJwN7FSAAAAlDaCE3ARR8+kaeGOE5q3PVYr95+W3WE450WF+Khf80j1axmp9nWqyd3NYmKlAAAAKEsEJyAPh8PQ5phELdgepwU74rQzNjnf/KaRAerXIlL9WkSqWY0AWSyEJQAAgKqA4IQqLz3Lrr/2ntLCHXFauPOETuYZ3MHNInWsF6Jrm+Vcs1S3up+JlQIAAMAsBCdUSSeSMrRw5wkt2B6nv/aeUmb2ueuV/L081LNJmK5tFq5ejcNVjZHwAAAAqjyCE6oEwzC043iyFu7IOQVv09HEfPNrBfuoT/MIXdssQp3rh8jTw82kSgEAAFAREZxQaWVm27Vq/2kt2BGnhTtOKCYhPd/8tlHBurZZuK5tHqEmEVyvBAAAgAsjOKFSiUlI15JdJ7R450kt33dKaVl25zxvq5uubBSmPs3D1btpuMIDvE2sFAAAoJKz26TkWCn5uJQUIyUdl5KPyT3hqLof3i7Z+0hWq9lVFhnBCS7NZndo/aEzWrzrpBbvPKFdcflHwQsP8NI1zcJ1bbMIdW8UKm8r91cCAAC4bJnJUtKxnEfy8cJfp56UZBRY1U1SqCRb6gnJu145F15yBCe4nBPJGVq666SW7DqpZXtOKjkj2znPzSK1r1NNvZuGq1eTMDWvEcgpeAAAAEVlS885SpQSlxOCco8YJedOH885cpSVfOltSZKbVQqsIQXUzHkOrCW7X7jW741VW6/Asn0vpYzghArP7jC0+WiC86jSlpj8AzuE+HmqZ+Mw9W4arh7RoQr2ZRQ8AACAfLIzLxCIYvM8jksZCUXfplegFFBDCqyZ88j7OrBmTljyrS655R90y2Gz6Vj8H2rrFVC677GMEZxQISWkZWnp7pyjSkt3n9Tp1Kx881vXDlKvJuHq3SRMrWsHy92No0oAAKCKMQwp/cy5QJRy4uxznkfy2efiBCIPbykgUvKPzHkOqJHnOeLc0SMXCz6Xi+CECiHb7tDGIwlatvuklu45pc1HE2TkOSU2wNtDPaLD1KtJmHo1CVdYgJd5xQIAAJQVw5CyUnJCUOrJs88ncp6TY88LRyckh63o23b3zB+ECgSjsw/vYIlLHQogOME0R06n6c89p7Rs90n9ve9UvmuVJKlJRIB6N805qtS+bjVZ3bm3EgAAcEG5R4byBaGTOdPO13meszOKt32fajkhyD9c8o/IOSrkn/sIPzfPpxqB6DIQnFBu0rKytXJ/vJbtzglL+0+l5psf7GvVlY1C1aNxmHpEhykyiOHCAQBABWQYUlaqlHZKSs19nA1CafFnX+dpSz0pObIvvd28rH6Sf5jkFy75hZ0NQ4WEI78wyYMzccoDwQllxjAMbT+epGW7T+nPPSe19uAZZdkdzvnubha1iwrOCUqNw9SqVhDXKgEAgPJnGDnDa6fFS2mnzwWitNzwczYM5Q1K2enF3493UE4Q8j8bhvzCzr32Dz8bkkJzXnv6lf77xGUhOKFUnUzO1N97c44oLdtzSqdSMvPNr13Nx3lE6YpG1RXo7To3PQMAAC7ClnE2BMXnhJ2003mm8zxS87wuzrVCuTx8zgag6jnPvqE5wccv9Ny0f9i5kMSRIZdGcMJlSc3M1uoDp/XX3lP6e+8p7YzNP6a/j9Vd3RpWV4/onFPw6of6cV8lAABQNIYhZSRK6aeltDNnn09f5PlMzrMt9dLbLozVL2f4bN+QnGe/sIJBKG9Q4qhQlUJwQrHY7A5tOpLgDEobDico25H/jtDNawSePf0uVB3qVpOXh7tJ1QIAgArB4ZAyE6X0hJxwk/vIyJ1OOBd60vMEoPQzkmEv2T7dPM6GoAs8/ELPBaTch9WnFN80KhuCEy7KMAztjktxBqVV++OVmpX/P7A6Ib7q3qi6ujcKVbcG1VXdn8PQAABUOrnDZKcn5ASejJwgZEk9rQYnVshtySYp60LhKEGScbGtX5zVV/IJkXyrnX0OuchztZxQ5BXICHIoVQQnFBCTkK6/zwalv/fGF7hOKcTPU90aVteVjULVvWGo6lT3NalSAABQLLaMnMCTmZTznJF4Ltjkvj4biPK/PrtsIUd/PCS1kqSYIuzf6if5BOeEG59qOYMl5L72CS48DPlUk6yMtAvzEZyg+JRMrdx/Wiv2n9LyvfEFhgn3trqpc/3quvLsUaVmkYFyY/Q7AADKl92WM/JbZpKUkXTuuUAQyjt93nx71uXX4e6Zc4NU7yDJJ1gOz0AdO5OqGg1ayN2vep4QlBuOgs+1MTgCXBjBqQo6k5qlVQfitWJfvFbuP61dcfkHdHB3s6h17aCcI0qNQtWuTjDXKQEAUFK5gScr5WzwSckJMs4AdDYMZSbnPDIS87flLlOS4a8LZZG8AyWvoJxn7+CcUOMdVPD12XCUb56Hd75T4Ow2m9b98YcG9h8odyuj5aLyIjhVAYlpNq06EH/2qFK8dsYmyTjvNOOmkQHq2iDniFKXBiEMEw4AqLoMQ7Kl5dzgNDM55zkr5dx0vhB0fiBKlrLyvk6RsjNKtz6rr+QVkHMNj3du+Ak6bzr4wvM9/SU3t9KtCagCCE6VUFKGTWsOnNbK/fFasT9e244VDErR4f7q1rC6ujWori4NqivEz9OcYgEAuBwO+7mQk/dhy32ddi70OANQbgjKbU8+bzpFlzWQwYV4eOcEHk//s0d8ch8BOQ/vwHOByCswz3RAnuUCJXe+vgFm4F9eJZBhsztD0sp98doSk6jzRghXgzA/dWtQXV3PPsICOMcYAFAODCPnVDXb2RBjS8/zOveRfjbsnJ0ubLmslLMh6LxQVGqnr12Ap3/OvXpyn3ODjKf/2df+OWEm33SA5Jn39dlnd87mAFwZwakSuPPjlVp/OCFfW73qvuraoLq6NcwJShGBjEYDAMjD4cgJHbaMfM+WjBSFJm+XZa9VcmSdDTBpOaeb5YacfI88bdmFtGWllvw+PMViyRNyfHOerX7npq1+OUHG8+zDK28gyg1F/vmnrb6c0gbAieDk4pIybM7QdHOH2rribFCqGcwN3ACgwjMMyZEtZWeefWScfWTmhBBnW55nW2HtGefNz7jI89mgdIHR1TwkdZekvWXwft08cgKM1edcmHG+Pvso7PX5IcjT/1x77uO8AQsAoLQRnFzcrticEfFqBnnrtVvamFwNAFRghpFzPYw96+zDJtnPBhbn69x5eV9nnV3m7HIFXmedCz652yvwOutssMnd9tnX2Rkqk2tpisvNmhNgPLxleHgrJTNbfsFhcvM8G2zyPXzPPXt4n9fmk3+ec/2zIYdT1QC4MIKTi9txPEmS1LRGoMmVAKj0HI6coyMOW05ocNjzvD477XydLdkvsqw9OydM5L522M6GlLyvc7dzdjr3de528gWg3GfbeW3nva4IIeVinAHGKyd45Hu+QHuB5X1ybhbqfPY+F3Au9Ox27pYT2TabFv3xhwYOHCg3hpYGACeCk4vbcTxJQ9yWa2zyDumHoJxffhZ3yeKWc162xf1cm3OepWCb29l252u3PNvJM8857Xbefs5fPrfNkn9eYQ+3C7Sfvw1ZCm/PfUiXWC/vtIVTOiojw8h5yJAMx3mP89vOThe67NmHI++0PU+7Pc/2zm93nDdtP+/5QvMc+adzl8m7nCM7z+u809nnQo1zOmcZd7tNXU/Eyf3rT85uMzvPw34u5Dinz5+fZ9pwmP0TLn3unpK7V86REA+vs9Oe573OXSbPaw/Pc+s627zOrZcbYpyvzz7nLu/hfW4/Hl7n1s8TYAAAFQvBycXtOpagL60fyy8+U4o3uxpXZCkkUJ0XtnLbZZEsOm+6uM959ivlCW+W/K8vMM9D0tUpKfI48mIRgl9Rg2Gev8DnG7e+qO1G/tf52lRIW2HL5Q07eV/rAu15tuEMP3m2Byc3SRGSlHyJBUvK4pZzlMTNI2eIZOfrs8+FvrbmLOvuWcLXZ7fnDDfW856L+NrNgz+gAACKjODkwuwOQ1lxu+XnnimHh4/c+ky+8F+xC/yFu5Bp5/Lnr5M7bZw3fZG/sBf4635hf82/2HK521X+9gJHBy73y3LeL98Vn0VSgCSV8r0Uq7bCjmTmOUKa74hoUdpzj9AWdsT3vCO2znkXOzrskTPt5nFuXr5pj5z18833OLsvD2Ub0ubNW9W6fQd5WL3OBZi82y0wbS1kvvvZdvdz4Sd33wAAVAEEJxd2+HSaGtj3S+6SJbKV1OV+s0syh3H+kYdCTtHKe6TiQkcrCn2du74KHikp8Oy4yDwp/9GVkk1nZ2dr5cqV6tq1izwuegPEIoRJwyh4lEs67y/wRW235H+dr02FtBW2XN4jfOcd7btgu1v+7bi55593odM687ZXcobNpiMxf6hVi4ES16sAAFBiBCcXtuN4klq4HZQkWWq0NrcYMzm/WFf+v3wbNpvityXKqHslX4IBAADKUeX/plmJ7TyepBaWgzkTka1MrQUAAACozAhOLmz7sSS1cDuUMxFZhY84AQAAAGWM4OTCTh/fr2qWFBkWdym8udnlAAAAAJUWwclFJWXYVD15pyTJEdok5yaHAAAAAMoEwclF7TyerOaWnNP03Gu2MbkaAAAAoHIjOLmonbHnRtTj+iYAAACgbBGcXNSO40lq7hwYghH1AAAAgLJEcHJRR2NiVNtyKmeC4AQAAACUqQoRnN59913Vq1dP3t7e6tKli1avXn3BZWfMmCGLxZLv4e1dtQZGsDsMeZzYKkmyBdaRfILNLQgAAACo5EwPTt99950mTJig5557TuvXr1ebNm3Ur18/nThx4oLrBAYG6vjx487HoUOHyrFi8x2KT1VDxwFJkgcDQwAAAABlzvTg9Prrr2vMmDEaOXKkmjdvrg8++EC+vr6aPn36BdexWCyKjIx0PiIiIsqxYvPtjE12DgxhqUFwAgAAAMqah5k7z8rK0rp16zRx4kRnm5ubm6699lqtWLHiguulpKSobt26cjgcat++vV566SW1aNGi0GUzMzOVmZnpnE5KSpIk2Ww22Wy2UnonJZdbQ3Fq2Xo0QUMtByVJ2WHNZVSA94HyUZL+gqqNPoPios+guOgzKK6K1GeKU4OpwenUqVOy2+0FjhhFRERo586dha7TpEkTTZ8+Xa1bt1ZiYqJee+01XXHFFdq2bZtq165dYPkpU6Zo8uTJBdrnzZsnX1/f0nkjpWD+/PlFXnbVDpv+YTkmSVq47YQy9vxRVmWhgipOfwEk+gyKjz6D4qLPoLgqQp9JS0sr8rKmBqeS6Natm7p16+acvuKKK9SsWTN9+OGHeuGFFwosP3HiRE2YMME5nZSUpKioKPXt21eBgYHlUvPF2Gw2zZ8/X3369JHVai3SOr9t+0TuFkNZXiG6+vq7JIuljKtERVGS/oKqjT6D4qLPoLjoMyiuitRncs9GKwpTg1NoaKjc3d0VFxeXrz0uLk6RkZFF2obValW7du20d+/eQud7eXnJy8ur0PXM/kHlVdR6kjJsCk/dLVlzrm+yenqWQ3WoaCpa/0XFR59BcdFnUFz0GRRXRegzxdm/qYNDeHp6qkOHDlq4cKGzzeFwaOHChfmOKl2M3W7Xli1bVKNGjbIqs0LZeTxZzS05owhaazEwBAAAAFAeTD9Vb8KECRo+fLg6duyozp0764033lBqaqpGjhwpSRo2bJhq1aqlKVOmSJKef/55de3aVY0aNVJCQoJeffVVHTp0SKNHjzbzbZSbnbFJan12RD3VaG1qLQAAAEBVYXpwuu2223Ty5Ek9++yzio2NVdu2bTVnzhzngBGHDx+Wm9u5A2NnzpzRmDFjFBsbq2rVqqlDhw5avny5mjdvbtZbKFe7jp3WrZbDORORHHECAAAAyoPpwUmSxo0bp3HjxhU6b8mSJfmmp02bpmnTppVDVRVT4tGd8rbYlO3uK4+QBmaXAwAAAFQJpt8AF0Vndxjyjd8mSbKFNZfc+PEBAAAA5YFv3i7kUHyqoh37JUleUe1MrgYAAACoOghOLmRn7LkR9dwYGAIAAAAoNwQnF7LjWKJa5I6oF0lwAgAAAMoLwcmFxB3Zp2BLqhwWDym8mdnlAAAAAFUGwcmFuMVtliSlBzeSPLxMrgYAAACoOghOLiIx3aYa6bslSdZabc0tBgAAAKhiCE4uYleegSE8a7c1txgAAACgiiE4uYgdx5PUnIEhAAAAAFMQnFzE4aNHVMsSnzMR2crcYgAA+P/27j0oqvtg4/izu8ACclEh3BQiUQhGUVAUL53GJFbrRBsahxiTWGJn8kdftEHaTjGNOn2bSE0nrbVojJm2ad+GahOrtjZJNXhJTJOoQUxoFO9KNIBoZLl4gd19/7DSUKgrSfR3Vr4fh5nd3551nwM/3fNwLgsAPQzFyU+0ntwrSWrulSQFRxhOAwAAAPQsFCc/4PZ4Ff7pR5Ikb9xQw2kAAACAnofi5AeOn2lWqveoJCk0aYThNAAAAEDPQ3HyA/s++fcV9ezxww2nAQAAAHoeipMfOHSyTrfZTl2+E88V9QAAAIAbjeLkB5pPVMhh8+p8UJQUHmc6DgAAANDjUJz8QODpf0qSLkZzYQgAAADABIqTxTWcb1W/CwckScGJGWbDAAAAAD0UxcniqmoaNcR++cIQFCcAAADADIqTxe0/eVZpturLd7iiHgAAAGAExcnizhyvlNPWqouOXlKfZNNxAAAAgB6J4mR1NR9Ikpp6p0l2flwAAACACWyJW5jb41Wfhn2SJEcCh+kBAAAAplCcLOz4mWbd7j0mSYoYkGk2DAAAANCDUZwsbN8pl+6wH5Mk2dnjBAAAABhDcbKwU8erFGlrUZstQLplsOk4AAAAQI9FcbKwSx9XSJIawgZKAUFmwwAAAAA9GMXJwkLP/FOS5I5JN5wEAAAA6NkoThbVcL5ViZcOSZLCB4w0nAYAAADo2ShOFrX/E5eG2I9LkkKSMsyGAQAAAHo4ipNFHT1xXPG2s5fvxA41GwYAAADo4ShOFtV0bI8k6dPgRCk4wnAaAAAAoGejOFlUwOkPJUnno4YYTgIAAACA4mRBbo9XtzRWSZKciRlmwwAAAACgOFnR8TPNStNRSVLv27IMpwEAAABAcbKgA9U1SrbVSJIc8cMMpwEAAABAcbKgM0f2yG7zyhXQVwqPNR0HAAAA6PEoThbk/WSvJMkVOdhwEgAAAAASxcmSIs7tkyTZEoYbTgIAAABAojhZTsP5Vg1oPSyJC0MAAAAAVkFxspiqk2d0u61aktTr1kzDaQAAAABIFCfLqTn8gZy2Np23hUq9B5iOAwAAAEAUJ8u5UF0hSaoPS5Xs/HgAAAAAK2DL3GKC6yslSW0x6YaTAAAAALiC4mQhbo9XcecPSOL8JgAAAMBKKE4Wcqy+SWk6LkmKGjTKcBoAAAAAV1CcLOT44X2KsLWoVQFyxKSZjgMAAADgXyhOFtJ4tFySVBecLAUEGU4DAAAA4AqKk4XY6z6QJLVEDTGcBAAAAMBnUZwspK9rvyQpsF+G2SAAAAAAOqA4WUTD+VYNdB+RJEWncGEIAAAAwEooThZx5Pgxxdk+lUc2hSVlmI4DAAAA4DMoThZx9vD7kqS6wH6SM8xwGgAAAACfRXGyCM+pDyVJ5yK4DDkAAABgNRQniwg799HlG3HDzAYBAAAA0AnFyQI8Xinx4iFJUuRtIw2nAQAAAPCfKE4W8GnLBd2qGklSTOpow2kAAAAA/CeKkwV4z1XLbvPqjD1KjvAY03EAAAAA/AeKkwWENh2XJNX1SjWcBAAAAEBXKE4W0Pfi5eLUGj3UcBIAAAAAXaE4WUBi2+XiFMwH3wIAAACWFGA6QE/X0NSigfpYkhSXlt2t57o9bm2r3qbVVavVcLFBU5Kn6BsDv6GokKjrkBQAAADouShOhlUf3KNMW5saFaqIuEHX9JyGiw1ad3Cd/rj/jzrVfKp9fN/ZfVq2Z5nuTrxb01Ona0z8GNlt7FQEAAAAviiKk2GNR/dIkk46BynNZrvqsofPHVbpvlL99chfdb7tvCSpt7O3clNzFR8Wr3UH1+nD+g+16fgmbTq+Sf3C+ml6ynTlDMrRLaG3XPd1AQAAAG5WFCfDbLWVkqSmPnd0+bjH69FbH7+ll/a9pHc+ead9PLVPqh4Z/IimJE9RcECwJCk3NVdVZ6v0yoFX9Lcjf9PJppNatmeZllcs153979T01OkanzBeDrvj+q8YAAAAcBOhOBnWx7VfkuSIT+8w3nSpSesPrVfp/lJVN1ZLkuw2u+5OvFsPDX5IWbFZsnWxh+r2vrfrR2N+pMKsQm06tklrD67Vnro92lK9RVuqtyiuV5zuH3S/vpnyTcX1irv+KwgAAADcBCxxAszy5cs1YMAABQcHKzs7Wzt37rzq8i+//LLS0tIUHBys9PR0vfrqqzco6ZfL7Xbr1tbDkqQ+A0dKko41HFPxe8W65+V7tGTXElU3Vis8KFyzh8zWq/e/ql/c9QuNihvVZWn6rJCAEN036D79fsrvtf6+9Xpk8COKdEaqprlGK/au0OS1k5Vflq8tJ7aozdN23dcVAAAA8GfG9zitWbNGhYWFWrlypbKzs7V06VJNnjxZVVVViomJ6bT8P/7xD82cOVPFxcWaOnWqSktLlZOTo/Lycg0d6l+fg/Tx0X261XZeF7yBOhraomfe+B+9dfKt9scHRg7UQ4Mf0tTbpio0MPRzv87A3gP1w9E/VMHIAr1x/A2tPbhWu2p26c2P39SbH7+pW0JuUc6gHN2fcr/6h/f/MlYNAAAAuKnYvF6v12SA7OxsjRo1SiUlJZIkj8ejxMREzZ07V0VFRZ2WnzFjhpqbm7Vx48b2sTFjxigjI0MrV670+Xoul0uRkZFqaGhQRETEl7cin8Pbf3te1fv/Vy9G9NXJoMtjNtl0Z/879dDghzQmfozPPUuf17GGY/rzwT9rw+ENOnvhbPt4pDNSTrtTzgCnnA6nghxBCnYEK8gRJKfD2f4V5AhScEDncafDqUB7oGw2m2y6nP2zt6/cv7KuXS5j6/jYF3W9vocmuNvcKi8v14gRI+QI+GLnqhn+p48bxO3+zJxx3DznN3rF/L1e3G639pTvUeaIzC80Z/gZXcVN9q1pc7epYk+FMjIzFOD4/L+TvxnnjJXea630/XW73aqoqNC8qfMUHhJuNEt3uoHR4nTp0iWFhobqlVdeUU5OTvt4Xl6ezp07pw0bNnR6TlJSkgoLC1VQUNA+tmjRIq1fv1579+7ttPzFixd18eLF9vsul0uJiYmqr683Xpy+/X+TVOGolySFBoTqvoH3aUbqDCWFJ92wDK3uVm07uU3rDq3TuzXv3rDXBQAAQM/26rRXFRdu9px7l8ul6OjoaypORg/Vq6+vl9vtVmxsbIfx2NhY7d+/v8vn1NTUdLl8TU1Nl8sXFxfrxz/+cafxTZs2KTT08x/+9mW4ozleNSH1yrh0u0YlPCBnrVOVtZWqVOUNzzJVUzUhYoJavC1q87apTW1q9baqTW1q87apVa3t49dy/4rP/nbD+68//+2x9ttfYpe30m9X4D++rL2dAKzlZjoCAVfH/+PX15f1/d2xfYdC7Wa3x1taWq55WePnOF1v8+fPV2FhYfv9K3ucJk2aZHyP09e9X9fc1laVvVGmr33tawoMDDSaB9bX2tqqzZs3M19wzZgz6C7mDLqLOYPustKccblc17ys0eIUHR0th8Oh2traDuO1tbWKi+t6t11cXFy3lnc6nXI6nZ3GAwMDjf+gpMuXGJeskwf+gfmC7mLOoLuYM+gu5gy6ywpzpjuvb/Ry5EFBQRo5cqTKysraxzwej8rKyjR27NgunzN27NgOy0vS5s2b/+vyAAAAAPBFGT9Ur7CwUHl5ecrKytLo0aO1dOlSNTc3a/bs2ZKkb33rW+rXr5+Ki4slSY8//rjuvPNOPfvss7r33nu1evVq7d69W6tWrTK5GgAAAABuYsaL04wZM3T69GktXLhQNTU1ysjI0Ouvv95+AYgTJ07Ibv/3jrFx48aptLRUTz75pJ544gmlpKRo/fr1fvcZTgAAAAD8h/HiJElz5szRnDlzunxs27ZtncZyc3OVm5t7nVMBAAAAwGVGz3ECAAAAAH9AcQIAAAAAHyhOAAAAAOADxQkAAAAAfKA4AQAAAIAPFCcAAAAA8IHiBAAAAAA+UJwAAAAAwAeKEwAAAAD4QHECAAAAAB8oTgAAAADgA8UJAAAAAHygOAEAAACADxQnAAAAAPCB4gQAAAAAPlCcAAAAAMAHihMAAAAA+EBxAgAAAAAfKE4AAAAA4APFCQAAAAB8CDAd4Ebzer2SJJfLZTjJZa2trWppaZHL5VJgYKDpOLA45gu6izmD7mLOoLuYM+guK82ZK53gSke4mh5XnBobGyVJiYmJhpMAAAAAsILGxkZFRkZedRmb91rq1U3E4/Ho1KlTCg8Pl81mMx1HLpdLiYmJqq6uVkREhOk4sDjmC7qLOYPuYs6gu5gz6C4rzRmv16vGxkYlJCTIbr/6WUw9bo+T3W5X//79TcfoJCIiwvjEgf9gvqC7mDPoLuYMuos5g+6yypzxtafpCi4OAQAAAAA+UJwAAAAAwAeKk2FOp1OLFi2S0+k0HQV+gPmC7mLOoLuYM+gu5gy6y1/nTI+7OAQAAAAAdBd7nAAAAADAB4oTAAAAAPhAcQIAAAAAHyhOAAAAAOADxcmg5cuXa8CAAQoODlZ2drZ27txpOhIsqri4WKNGjVJ4eLhiYmKUk5Ojqqoq07HgR37605/KZrOpoKDAdBRY2MmTJ/XII48oKipKISEhSk9P1+7du03HgkW53W4tWLBAycnJCgkJ0cCBA/WTn/xEXHcMV7z55puaNm2aEhISZLPZtH79+g6Pe71eLVy4UPHx8QoJCdHEiRN18OBBM2GvAcXJkDVr1qiwsFCLFi1SeXm5hg8frsmTJ6uurs50NFjQ9u3blZ+fr3fffVebN29Wa2urJk2apObmZtPR4Ad27dql559/XsOGDTMdBRb26aefavz48QoMDNRrr72mjz76SM8++6z69OljOhosasmSJXruuedUUlKiffv2acmSJXrmmWf0q1/9ynQ0WERzc7OGDx+u5cuXd/n4M888o2XLlmnlypV677331KtXL02ePFkXLly4wUmvDZcjNyQ7O1ujRo1SSUmJJMnj8SgxMVFz585VUVGR4XSwutOnTysmJkbbt2/XV7/6VdNxYGFNTU0aMWKEVqxYoaeeekoZGRlaunSp6ViwoKKiIr399tt66623TEeBn5g6dapiY2P161//un1s+vTpCgkJ0R/+8AeDyWBFNptN69atU05OjqTLe5sSEhL0ve99T9///vclSQ0NDYqNjdWLL76oBx980GDarrHHyYBLly7p/fff18SJE9vH7Ha7Jk6cqHfeecdgMviLhoYGSVLfvn0NJ4HV5efn69577+3w/w3Qlb/85S/KyspSbm6uYmJilJmZqRdeeMF0LFjYuHHjVFZWpgMHDkiS9u7dqx07dmjKlCmGk8EfHD16VDU1NR3enyIjI5WdnW3Z7eEA0wF6ovr6erndbsXGxnYYj42N1f79+w2lgr/weDwqKCjQ+PHjNXToUNNxYGGrV69WeXm5du3aZToK/MCRI0f03HPPqbCwUE888YR27dql7373uwoKClJeXp7peLCgoqIiuVwupaWlyeFwyO126+mnn9bDDz9sOhr8QE1NjSR1uT185TGroTgBfiY/P1+VlZXasWOH6SiwsOrqaj3++OPavHmzgoODTceBH/B4PMrKytLixYslSZmZmaqsrNTKlSspTujSn/70J7300ksqLS3VkCFDVFFRoYKCAiUkJDBncFPiUD0DoqOj5XA4VFtb22G8trZWcXFxhlLBH8yZM0cbN27U1q1b1b9/f9NxYGHvv/++6urqNGLECAUEBCggIEDbt2/XsmXLFBAQILfbbToiLCY+Pl533HFHh7HBgwfrxIkThhLB6n7wgx+oqKhIDz74oNLT0zVr1izNmzdPxcXFpqPBD1zZ5vWn7WGKkwFBQUEaOXKkysrK2sc8Ho/Kyso0duxYg8lgVV6vV3PmzNG6deu0ZcsWJScnm44Ei7vnnnv04YcfqqKiov0rKytLDz/8sCoqKuRwOExHhMWMHz++08ccHDhwQLfeequhRLC6lpYW2e0dNyUdDoc8Ho+hRPAnycnJiouL67A97HK59N5771l2e5hD9QwpLCxUXl6esrKyNHr0aC1dulTNzc2aPXu26WiwoPz8fJWWlmrDhg0KDw9vP/Y3MjJSISEhhtPBisLDwzudA9erVy9FRUVxbhy6NG/ePI0bN06LFy/WAw88oJ07d2rVqlVatWqV6WiwqGnTpunpp59WUlKShgwZoj179ujnP/+5vv3tb5uOBotoamrSoUOH2u8fPXpUFRUV6tu3r5KSklRQUKCnnnpKKSkpSk5O1oIFC5SQkNB+5T2r4XLkBpWUlOhnP/uZampqlJGRoWXLlik7O9t0LFiQzWbrcvy3v/2tHn300RsbBn5rwoQJXI4cV7Vx40bNnz9fBw8eVHJysgoLC/XYY4+ZjgWLamxs1IIFC7Ru3TrV1dUpISFBM2fO1MKFCxUUFGQ6Hixg27ZtuuuuuzqN5+Xl6cUXX5TX69WiRYu0atUqnTt3Tl/5yle0YsUKpaamGkjrG8UJAAAAAHzgHCcAAAAA8IHiBAAAAAA+UJwAAAAAwAeKEwAAAAD4QHECAAAAAB8oTgAAAADgA8UJAAAAAHygOAEAAACADxQnAMBN69FHH1VOTo7pGACAm0CA6QAAAHweNpvtqo8vWrRIv/zlL+X1em9QIgDAzYziBADwS5988kn77TVr1mjhwoWqqqpqHwsLC1NYWJiJaACAmxCH6gEA/FJcXFz7V2RkpGw2W4exsLCwTofqTZgwQXPnzlVBQYH69Omj2NhYvfDCC2pubtbs2bMVHh6uQYMG6bXXXuvwWpWVlZoyZYrCwsIUGxurWbNmqb6+/gavMQDAJIoTAKBH+d3vfqfo6Gjt3LlTc+fO1Xe+8x3l5uZq3LhxKi8v16RJkzRr1iy1tLRIks6dO6e7775bmZmZ2r17t15//XXV1tbqgQceMLwmAIAbieIEAOhRhg8frieffFIpKSmaP3++goODFR0drccee0wpKSlauHChzpw5ow8++ECSVFJSoszMTC1evFhpaWnKzMzUb37zG23dulUHDhwwvDYAgBuFc5wAAD3KsGHD2m87HA5FRUUpPT29fSw2NlaSVFdXJ0nau3evtm7d2uX5UocPH1Zqaup1TgwAsAKKEwCgRwkMDOxw32azdRi7crU+j8cjSWpqatK0adO0ZMmSTn9XfHz8dUwKALASihMAAFcxYsQIrV27VgMGDFBAAG+bANBTcY4TAABXkZ+fr7Nnz2rmzJnatWuXDh8+rL///e+aPXu23G636XgAgBuE4gQAwFUkJCTo7bffltvt1qRJk5Senq6CggL17t1bdjtvowDQU9i8fKQ6AAAAAFwVvyoDAAAAAB8oTgAAAADgA8UJAAAAAHygOAEAAACADxQnAAAAAPCB4gQAAAAAPlCcAAAAAMAHihMAAAAA+EBxAgAAAAAfKE4AAAAA4APFCQAAAAB8+H+LnaA2KTevpgAAAABJRU5ErkJggg==" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "execution_count": 6 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T18:47:36.447869Z", + "start_time": "2024-05-26T18:47:36.446498Z" + } + }, + "cell_type": "code", + "source": "", + "id": "2886af0283eb3da3", + "outputs": [], + "execution_count": 6 + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/demos/output.json b/demos/output.json new file mode 100644 index 000000000..e778f5cb8 --- /dev/null +++ b/demos/output.json @@ -0,0 +1,178 @@ +{ + "results": { + "floating_species_concentrations": { + "T": [ + 0.0, + 6.299322095779684e+20, + 6.589261280593098e+20, + 6.892545520199003e+20, + 7.209789047532627e+20, + 7.54163436666159e+20, + 7.888753553994528e+20, + 8.251849619403908e+20, + 8.631657929609198e+20, + 9.028949054784826e+20, + 9.44452777850933e+20, + 9.879237577919735e+20, + 1.0333949829215061e+21, + 1.0809591120294731e+21, + 1.1307124759561045e+21, + 1.182755838542504e+21, + 1.2371946011565558e+21, + 1.2941390163697169e+21, + 1.353704411254099e+21, + 1.4160114209363366e+21, + 1.4811862328938212e+21, + 1.5493608425423338e+21, + 1.620673320477493e+21, + 1.6952680921287714e+21, + 1.7732962302209035e+21, + 1.854915760714328e+21, + 1.940291982812496e+21, + 2.0295978037199716e+21, + 2.123014088795361e+21, + 2.2207300277733347e+21, + 2.3229435179163383e+21, + 2.429861564750658e+21, + 2.5417007012572336e+21, + 2.6586874263483953e+21, + 2.7810586635242156e+21, + 2.9090622406387827e+21, + 3.042957391731596e+21, + 3.183015281970347e+21, + 3.3295195567294555e+21, + 3.4827669159488976e+21, + 3.643067714901443e+21 + ], + "E": [ + 0.0, + 6.007827780841133e+20, + 5.995034046685892e+20, + 5.983813209836576e+20, + 5.974221513649175e+20, + 5.966317910882444e+20, + 5.960164187500897e+20, + 5.955825092185685e+20, + 5.953368471773908e+20, + 5.952865538710503e+20, + 5.954390783887974e+20, + 5.95802239553189e+20, + 5.963841260277044e+20, + 5.971933503230099e+20, + 5.982388776862739e+20, + 5.995300971309247e+20, + 6.010768409048184e+20, + 6.028894048299702e+20, + 6.04978569558604e+20, + 6.0735562280622e+20, + 6.100323826079037e+20, + 6.130212216504265e+20, + 6.163350927140152e+20, + 6.199875552969433e+20, + 6.23992803459889e+20, + 6.283656949543164e+20, + 6.331217816907921e+20, + 6.382773416125843e+20, + 6.43849412035549e+20, + 6.498558245187251e+20, + 6.563152413478432e+20, + 6.632471936937427e+20, + 6.706721215288307e+20, + 6.786114153807206e+20, + 6.870874600082149e+20, + 6.961236800882434e+20, + 7.057445880047908e+20, + 7.15975833839482e+20, + 7.268442576614459e+20, + 7.38377944225497e+20, + 7.506062801861098e+20 + ], + "I": [ + 0.0, + 4.946045714752396e+19, + 4.0889582626806083e+18, + 3.6591953712157786e+17, + 6.165403009770167e+16, + 3.808651045110392e+16, + 3.763268488033212e+16, + 3.915329927041339e+16, + 4.091805778775523e+16, + 4.279018207373362e+16, + 4.476410489954128e+16, + 4.6845464846250536e+16, + 4.9041265195493256e+16, + 5.1359160781794376e+16, + 5.3807421252572216e+16, + 5.639496189397319e+16, + 5.91314083285764e+16, + 6.202715874746418e+16, + 6.509345151767727e+16, + 6.83424389134117e+16, + 7.178726756668879e+16, + 7.544216626607394e+16, + 7.932254178827099e+16, + 8.34450834934808e+16, + 8.782787751852931e+16, + 9.249053144013611e+16, + 9.745431039108794e+16, + 1.0274228568941142e+17, + 1.0837949713815904e+17, + 1.1439313027712138e+17, + 1.2081270995958291e+17, + 1.276703117858137e+17, + 1.3500079304257477e+17, + 1.4284204496616062e+17, + 1.512352683071362e+17, + 1.6022527436306666e+17, + 1.698608138479768e+17, + 1.8019493617710736e+17, + 1.9128538200361622e+17, + 2.0319501208352624e+17, + 2.1599227585094493e+17 + ] + }, + "time": [ + 0.0, + 0.25, + 0.5, + 0.75, + 1.0, + 1.25, + 1.5, + 1.75, + 2.0, + 2.25, + 2.5, + 2.75, + 3.0, + 3.25, + 3.5, + 3.75, + 4.0, + 4.25, + 4.5, + 4.75, + 5.0, + 5.25, + 5.5, + 5.75, + 6.0, + 6.25, + 6.5, + 6.75, + 7.0, + 7.25, + 7.5, + 7.75, + 8.0, + 8.25, + 8.5, + 8.75, + 9.0, + 9.25, + 9.5, + 9.75, + 10.0 + ] + } +} \ No newline at end of file diff --git a/demos/test_suite_demo.ipynb b/demos/test_suite_demo.ipynb deleted file mode 100644 index 4cee4340a..000000000 --- a/demos/test_suite_demo.ipynb +++ /dev/null @@ -1,160 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "id": "initial_id", - "metadata": { - "collapsed": true, - "ExecuteTime": { - "end_time": "2024-05-18T15:17:32.545659Z", - "start_time": "2024-05-18T15:17:31.090958Z" - } - }, - "source": [ - "import enum\n", - "import sys\n", - "\n", - "sys.path.insert(0, '..')\n", - "\n", - "import os\n", - "import requests\n", - "import json\n", - "from tempfile import mkdtemp\n", - "from urllib.request import urlretrieve\n", - "\n", - "import libsbml\n", - "from process_bigraph import pp \n", - "\n", - "from test_suite.test_data_model import TestCompositionResults" - ], - "execution_count": 1, - "outputs": [] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-18T15:17:32.549856Z", - "start_time": "2024-05-18T15:17:32.546749Z" - } - }, - "cell_type": "code", - "source": [ - "test_archive_fp = '../test_suite/examples/sbml-core/Varusai-Sci-Rep-2018-mTOR-signaling-LSODA-LSODAR-SBML.omex'\n", - "os.path.exists(test_archive_fp)" - ], - "id": "f7329fc0b6d2f5a0", - "execution_count": 2, - "outputs": [] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-18T15:17:32.553067Z", - "start_time": "2024-05-18T15:17:32.550550Z" - } - }, - "cell_type": "code", - "source": [ - "from dataclasses import dataclass\n", - "\n", - "\n", - "@dataclass(frozen=True)\n", - "class A:\n", - " x: float\n", - " y: float \n", - " \n", - "\n", - "a1 = A(x=0.5, y=0.5 / 2)\n", - "\n", - "a1.x" - ], - "id": "8736db2d5dbe199e", - "execution_count": 3, - "outputs": [] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-18T15:17:32.614584Z", - "start_time": "2024-05-18T15:17:32.553715Z" - } - }, - "cell_type": "code", - "source": "a1.x = 0.3\n", - "id": "76617db4b0cf1622", - "execution_count": 4, - "outputs": [] - }, - { - "metadata": { - "ExecuteTime": { - "end_time": "2024-05-18T15:17:32.615520Z", - "start_time": "2024-05-18T15:17:32.615470Z" - } - }, - "cell_type": "code", - "source": [ - "@dataclass\n", - "class B:\n", - " x: float\n", - " y: float" - ], - "id": "2a4eb4d6b3d74946", - "execution_count": null, - "outputs": [] - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "b1 = B(x=0.5, y=0.5)\n", - "\n", - "b1.x" - ], - "id": "9104001913e636b", - "execution_count": null, - "outputs": [] - }, - { - "metadata": {}, - "cell_type": "code", - "source": [ - "b1.x = 0.3\n", - "\n", - "b1.x" - ], - "id": "41ddc0673a6b0187", - "execution_count": null, - "outputs": [] - }, - { - "metadata": {}, - "cell_type": "code", - "source": "", - "id": "ad828894daaf69e", - "execution_count": null, - "outputs": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.6" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/demos/various.ipynb b/demos/various.ipynb index 97445a178..87741b2c1 100644 --- a/demos/various.ipynb +++ b/demos/various.ipynb @@ -6,8 +6,8 @@ "metadata": { "collapsed": true, "ExecuteTime": { - "end_time": "2024-05-21T19:58:40.075077Z", - "start_time": "2024-05-21T19:58:38.555281Z" + "end_time": "2024-05-26T18:29:37.847750Z", + "start_time": "2024-05-26T18:29:36.130539Z" } }, "source": [ @@ -16,48 +16,793 @@ "\n", "import numpy as np\n", "from process_bigraph import pp\n", + "from process_bigraph.experiments.parameter_scan import RunProcess\n", "\n", "\n", "sys.path.insert(0, '..')\n", "\n", "\n", - "from biosimulator_processes.services.rest_service import BiosimulationsRestService" + "from biosimulator_processes import CORE\n", + "from biosimulator_processes.services.rest_service import BiosimulationsRestService\n", + "from biosimulator_processes.instance import generate_ode_instance" ], - "execution_count": 1, - "outputs": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "CobraProcess registered successfully as cobra.\n", + "\n", + "CopasiProcess registered successfully as copasi.\n", + "\n", + "TelluriumProcess registered successfully as tellurium.\n", + "\n", + "AmiciProcess registered successfully as amici.\n", + "\n", + "Available processes:\n", + "[ 'console-emitter',\n", + " 'ram-emitter',\n", + " 'composite',\n", + " 'cobra',\n", + " 'copasi',\n", + " 'tellurium',\n", + " 'amici']\n", + "CompositionPlotter registered successfully as plotter.\n", + "\n", + "Plotter2d registered successfully as plotter2d.\n", + "\n", + "Available processes:\n", + "[ 'console-emitter',\n", + " 'ram-emitter',\n", + " 'composite',\n", + " 'cobra',\n", + " 'copasi',\n", + " 'tellurium',\n", + " 'amici',\n", + " 'plotter',\n", + " 'plotter2d']\n" + ] + } + ], + "execution_count": 1 }, { "metadata": { "ExecuteTime": { - "end_time": "2024-05-21T19:58:40.099182Z", - "start_time": "2024-05-21T19:58:40.076169Z" + "end_time": "2024-05-26T18:29:38.681578Z", + "start_time": "2024-05-26T18:29:38.606873Z" } }, "cell_type": "code", "source": [ - "import tellurium as te \n", "\n", - "teModel = te.loadSBMLModel('/Users/alexanderpatrie/Desktop/repos/biosimulator-processes/test_suite/examples/sbml-core/Caravagna-J-Theor-Biol-2010-tumor-suppressive-oscillations/Caravagna2010.xml')\n", "\n", "\n", - "results = teModel.simulate(0, 100.0, 1000)" + " " ], "id": "51505516b1a7bbd6", - "execution_count": 2, - "outputs": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "found a filepath\n", + "found a filepath\n" + ] + } + ], + "execution_count": 2 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T18:29:50.976867Z", + "start_time": "2024-05-26T18:29:50.970854Z" + } + }, + "cell_type": "code", + "source": "copasi_process.observables_schema", + "id": "7350506cf46d61f", + "outputs": [ + { + "data": { + "text/plain": [ + "{'floating_species_concentrations': {'T': {'_type': 'float',\n", + " '_apply': 'set',\n", + " '_check': 'check_float',\n", + " '_serialize': 'to_string',\n", + " '_description': '64-bit floating point precision number',\n", + " '_default': '0.0',\n", + " '_deserialize': 'deserialize_float',\n", + " '_divide': 'divide_float',\n", + " '_dataclass': 'dataclass_float',\n", + " '_inherit': ['number']},\n", + " 'E': {'_type': 'float',\n", + " '_apply': 'set',\n", + " '_check': 'check_float',\n", + " '_serialize': 'to_string',\n", + " '_description': '64-bit floating point precision number',\n", + " '_default': '0.0',\n", + " '_deserialize': 'deserialize_float',\n", + " '_divide': 'divide_float',\n", + " '_dataclass': 'dataclass_float',\n", + " '_inherit': ['number']},\n", + " 'I': {'_type': 'float',\n", + " '_apply': 'set',\n", + " '_check': 'check_float',\n", + " '_serialize': 'to_string',\n", + " '_description': '64-bit floating point precision number',\n", + " '_default': '0.0',\n", + " '_deserialize': 'deserialize_float',\n", + " '_divide': 'divide_float',\n", + " '_dataclass': 'dataclass_float',\n", + " '_inherit': ['number']}}}" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 3 }, { "metadata": { "ExecuteTime": { - "end_time": "2024-05-21T19:58:40.153255Z", - "start_time": "2024-05-21T19:58:40.099880Z" + "end_time": "2024-05-26T18:30:07.274492Z", + "start_time": "2024-05-26T18:30:07.092693Z" } }, "cell_type": "code", - "source": "teModel.plot()", + "source": [ + "copasi_process.update({})\n", + " \n", + " " + ], + "id": "d0a405764a3cc445", + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/alex/Desktop/uchc_work/biosimulators-2.0/biosimulator-processes/demos/../biosimulator_processes/processes/copasi_process.py:194: FutureWarning:\n", + "\n", + "Series.__getitem__ treating keys as positions is deprecated. In a future version, integer keys will always be treated as labels (consistent with DataFrame behavior). To access a value by position, use `ser.iloc[pos]`\n", + "\n" + ] + }, + { + "data": { + "text/plain": [ + "{'results': {'floating_species_concentrations': {'T': [0.0,\n", + " 6.83079198377033e+20,\n", + " 7.748028731440816e+20,\n", + " 8.788431819287454e+20,\n", + " 9.96854191895316e+20,\n", + " 1.1307122399587347e+21,\n", + " 1.28254399102252e+21,\n", + " 1.4547644120182555e+21,\n", + " 1.6501103684582347e+21,\n", + " 1.8716867987166881e+21,\n", + " 2.1230160780901032e+21,\n", + " 2.4080935990194555e+21,\n", + " 2.731450983790765e+21,\n", + " 3.09822833435186e+21,\n", + " 3.5142559289006925e+21,\n", + " 3.986146883170015e+21,\n", + " 4.521402256557749e+21,\n", + " 5.128530265607685e+21,\n", + " 5.817181499295535e+21,\n", + " 6.598302283402908e+21,\n", + " 7.48430862924337e+21,\n", + " 8.489283527337315e+21,\n", + " 9.629200717708054e+21,\n", + " 1.0922178487036007e+22,\n", + " 1.2388767518731545e+22,\n", + " 1.4052277361001472e+22,\n", + " 1.5939146687894377e+22,\n", + " 1.8079363221786104e+22,\n", + " 2.0506939968567713e+22,\n", + " 2.3260455306493686e+22,\n", + " 2.6383665474314118e+22,\n", + " 2.992619914475577e+22,\n", + " 3.394434506889458e+22,\n", + " 3.850194521405723e+22,\n", + " 4.367140748756413e+22,\n", + " 4.953485404529471e+22,\n", + " 5.618542318801316e+22,\n", + " 6.372874540787739e+22,\n", + " 7.228461667282777e+22,\n", + " 8.198889522666622e+22,\n", + " 9.29956515556076e+22,\n", + " 1.0547960508169528e+23,\n", + " 1.1963888553328864e+23,\n", + " 1.3569816180871307e+23,\n", + " 1.5391218685925112e+23,\n", + " 1.745698131522728e+23,\n", + " 1.979985404225486e+23,\n", + " 2.2456966519618366e+23,\n", + " 2.5470411037213363e+23,\n", + " 2.8887902291491733e+23,\n", + " 3.276352386268451e+23,\n", + " 3.7158572510207876e+23,\n", + " 4.214251273446244e+23,\n", + " 4.779405553293363e+23,\n", + " 5.4202376900990935e+23,\n", + " 6.146849340523026e+23,\n", + " 6.970681404426974e+23,\n", + " 7.904688976746933e+23,\n", + " 8.963538422070396e+23,\n", + " 1.0163829142968867e+24,\n", + " 1.1524342862906181e+24,\n", + " 1.3066323528865028e+24,\n", + " 1.4813791171663654e+24,\n", + " 1.6793893192047275e+24,\n", + " 1.9037296962889093e+24,\n", + " 2.1578626554361383e+24,\n", + " 2.445695340842326e+24,\n", + " 2.771633362879643e+24,\n", + " 3.140639239224882e+24,\n", + " 3.5583011670390173e+24,\n", + " 4.0309041291532977e+24,\n", + " 4.56550686783991e+24,\n", + " 5.170029267253974e+24,\n", + " 5.853345381621044e+24,\n", + " 6.625381826611558e+24,\n", + " 7.497223179605485e+24,\n", + " 8.481223112411385e+24,\n", + " 9.591120721888665e+24,\n", + " 1.08421506579293e+25,\n", + " 1.2251171684198561e+25,\n", + " 1.383677642554252e+25,\n", + " 1.5619401253122906e+25,\n", + " 1.7621426279566167e+25,\n", + " 1.9867259945566113e+25,\n", + " 2.238340310424559e+25,\n", + " 2.5198486517328447e+25,\n", + " 2.834327531578091e+25,\n", + " 3.185063387613141e+25,\n", + " 3.5755444749470746e+25,\n", + " 4.009447591899566e+25,\n", + " 4.490619156283455e+25,\n", + " 5.0230502940338835e+25,\n", + " 5.6108457719126565e+25,\n", + " 6.258186798736865e+25,\n", + " 6.9692879143957185e+25,\n", + " 7.74834838842781e+25,\n", + " 8.59949867401335e+25,\n", + " 9.526742663268595e+25,\n", + " 1.0533896363884417e+26,\n", + " 1.1624524084609614e+26,\n", + " 1.2801871959948031e+26,\n", + " 1.4068801614972046e+26,\n", + " 1.54277201230192e+26,\n", + " 1.688051364418503e+26,\n", + " 1.8428475177007878e+26,\n", + " 2.0072239946681798e+26,\n", + " 2.1811711586280486e+26,\n", + " 2.3645996146730767e+26,\n", + " 2.55733324129285e+26,\n", + " 2.7591023848129002e+26,\n", + " 2.969537041566523e+26,\n", + " 3.188160134412045e+26,\n", + " 3.4143809134363305e+26,\n", + " 3.647488424816571e+26,\n", + " 3.8866458130089044e+26,\n", + " 4.130883474155715e+26,\n", + " 4.379094718807394e+26,\n", + " 4.630029735226247e+26,\n", + " 4.8822918040376797e+26,\n", + " 5.134333498409118e+26,\n", + " 5.3844542096001133e+26,\n", + " 5.630798186940407e+26,\n", + " 5.871354398247399e+26,\n", + " 6.103957653424055e+26,\n", + " 6.326291334043341e+26,\n", + " 6.535892765886724e+26,\n", + " 6.730159590387429e+26,\n", + " 6.906360786712416e+26,\n", + " 7.061648499864484e+26,\n", + " 7.193075573746354e+26,\n", + " 7.29761649091365e+26,\n", + " 7.372192740952614e+26,\n", + " 7.413705310225113e+26,\n", + " 7.419073801477519e+26,\n", + " 7.385286519286019e+26,\n", + " 7.309447862749846e+26,\n", + " 7.188860766145177e+26,\n", + " 7.021118288150479e+26,\n", + " 6.804193572619243e+26,\n", + " 6.536595057668764e+26,\n", + " 6.217525971713187e+26,\n", + " 5.8471084265157016e+26,\n", + " 5.42666051286518e+26],\n", + " 'E': [0.0,\n", + " 5.985928883990624e+20,\n", + " 5.962411615326241e+20,\n", + " 5.952928728351746e+20,\n", + " 5.959007667448317e+20,\n", + " 5.982388558032022e+20,\n", + " 6.025050948674591e+20,\n", + " 6.089249869712886e+20,\n", + " 6.177547908729176e+20,\n", + " 6.292859114159783e+20,\n", + " 6.438495998083077e+20,\n", + " 6.618222463758416e+20,\n", + " 6.836313996439188e+20,\n", + " 7.097626458992727e+20,\n", + " 7.407673889254695e+20,\n", + " 7.772716742699213e+20,\n", + " 8.199861990766977e+20,\n", + " 8.69717665904131e+20,\n", + " 9.273816610629017e+20,\n", + " 9.940172621200876e+20,\n", + " 1.0708036066839234e+21,\n", + " 1.1590786856189363e+21,\n", + " 1.2603606592514582e+21,\n", + " 1.376372035074689e+21,\n", + " 1.5090670908920373e+21,\n", + " 1.6606629788165512e+21,\n", + " 1.833675003816133e+21,\n", + " 2.0309566367795108e+21,\n", + " 2.255744896936631e+21,\n", + " 2.511711823596063e+21,\n", + " 2.803022853351915e+21,\n", + " 3.1344030281809584e+21,\n", + " 3.511212084449947e+21,\n", + " 3.9395296108008906e+21,\n", + " 4.4262516232878524e+21,\n", + " 4.979200089516093e+21,\n", + " 5.607247126679495e+21,\n", + " 6.320455845115096e+21,\n", + " 7.130240053283336e+21,\n", + " 8.049545348791058e+21,\n", + " 9.093054447577366e+21,\n", + " 1.0277419983786325e+22,\n", + " 1.1621528441283334e+22,\n", + " 1.314679935447712e+22,\n", + " 1.4877524477029973e+22,\n", + " 1.6841252213658028e+22,\n", + " 1.906922331907724e+22,\n", + " 2.1596864644856748e+22,\n", + " 2.446434859940098e+22,\n", + " 2.7717226975999027e+22,\n", + " 3.1407148919456233e+22,\n", + " 3.559267405491337e+22,\n", + " 4.034019320142946e+22,\n", + " 4.572497066170174e+22,\n", + " 5.1832323828439325e+22,\n", + " 5.875895780112321e+22,\n", + " 6.6614474835800474e+22,\n", + " 7.55230809276326e+22,\n", + " 8.56255144586794e+22,\n", + " 9.70812245639768e+22,\n", + " 1.1007083011573278e+23,\n", + " 1.247988940388177e+23,\n", + " 1.4149705127613988e+23,\n", + " 1.604275316868966e+23,\n", + " 1.8188712543060736e+23,\n", + " 2.062116303583612e+23,\n", + " 2.3378089394239453e+23,\n", + " 2.650243964502258e+23,\n", + " 3.0042740382764396e+23,\n", + " 3.4053828114822565e+23,\n", + " 3.8597620887384316e+23,\n", + " 4.374397088808335e+23,\n", + " 4.957164784702175e+23,\n", + " 5.616941520584176e+23,\n", + " 6.363720375976202e+23,\n", + " 7.208741112226354e+23,\n", + " 8.164632820505494e+23,\n", + " 9.24557038508327e+23,\n", + " 1.0467433742339886e+24,\n", + " 1.1848000872463803e+24,\n", + " 1.3407134202591789e+24,\n", + " 1.5166985590724043e+24,\n", + " 1.7152211851307112e+24,\n", + " 1.9390198078367675e+24,\n", + " 2.191128668212374e+24,\n", + " 2.474900876176168e+24,\n", + " 2.794031363796288e+24,\n", + " 3.1525791568743767e+24,\n", + " 3.55498838292613e+24,\n", + " 4.006107372638089e+24,\n", + " 4.5112051339667003e+24,\n", + " 5.075984446981056e+24,\n", + " 5.706590806167148e+24,\n", + " 6.409616454861105e+24,\n", + " 7.192098753607318e+24,\n", + " 8.061512209174574e+24,\n", + " 9.025753662318045e+24,\n", + " 1.009311992888638e+25,\n", + " 1.1272277840156677e+25,\n", + " 1.2572225927130381e+25,\n", + " 1.4002248403426005e+25,\n", + " 1.5571859984322395e+25,\n", + " 1.7290743642080164e+25,\n", + " 1.9168678975982407e+25,\n", + " 2.121546320315743e+25,\n", + " 2.3440824504274658e+25,\n", + " 2.585432637743973e+25,\n", + " 2.8465265953114806e+25,\n", + " 3.1282563526367896e+25,\n", + " 3.431464597181655e+25,\n", + " 3.7569322420365596e+25,\n", + " 4.105365359744778e+25,\n", + " 4.477381398587427e+25,\n", + " 4.873494750483522e+25,\n", + " 5.294102313707575e+25,\n", + " 5.7394670909165164e+25,\n", + " 6.209703433993839e+25,\n", + " 6.704759653120907e+25,\n", + " 7.224401916817844e+25,\n", + " 7.76819727653516e+25,\n", + " 8.335496974367726e+25,\n", + " 8.925419147281733e+25,\n", + " 9.536832525568793e+25,\n", + " 1.0168339860866444e+26,\n", + " 1.081826222866361e+26,\n", + " 1.1484625151326553e+26,\n", + " 1.2165143054314561e+26,\n", + " 1.2857209699544405e+26,\n", + " 1.3557885203960633e+26,\n", + " 1.4263889005521079e+26,\n", + " 1.4971595732460889e+26,\n", + " 1.5677031100856878e+26,\n", + " 1.6375876549298046e+26,\n", + " 1.7063472067410558e+26,\n", + " 1.7734840054365622e+26,\n", + " 1.8384684796488765e+26,\n", + " 1.900743460922515e+26,\n", + " 1.9597289876815883e+26,\n", + " 2.0148247496743157e+26,\n", + " 2.0654194611449342e+26,\n", + " 2.1108979395831877e+26,\n", + " 2.1506530065973797e+26,\n", + " 2.1841000290760603e+26],\n", + " 'I': [0.0,\n", + " 5.816981536332695e+17,\n", + " 3.729701496546664e+16,\n", + " 4.165489205590582e+16,\n", + " 4.727518987830204e+16,\n", + " 5.38073885818209e+16,\n", + " 6.143473205165925e+16,\n", + " 7.0384981342547e+16,\n", + " 8.094154936186803e+16,\n", + " 9.345859813983093e+16,\n", + " 1.08379629015087e+17,\n", + " 1.2626227628080874e+17,\n", + " 1.47809149207249e+17,\n", + " 1.739077389249872e+17,\n", + " 2.056814390117769e+17,\n", + " 2.4455490543169443e+17,\n", + " 2.923378029301655e+17,\n", + " 3.513321282011976e+17,\n", + " 4.24469753406721e+17,\n", + " 5.1548869964495776e+17,\n", + " 6.291590284558682e+17,\n", + " 7.715722752000956e+17,\n", + " 9.505122168605908e+17,\n", + " 1.1759296903763348e+18,\n", + " 1.460550435024469e+18,\n", + " 1.8206528714049065e+18,\n", + " 2.2770627826749207e+18,\n", + " 2.856424566753614e+18,\n", + " 3.5928247381604234e+18,\n", + " 4.529863479542868e+18,\n", + " 5.723295246207201e+18,\n", + " 7.244390879628133e+18,\n", + " 9.18421275459501e+18,\n", + " 1.1659042805753481e+19,\n", + " 1.4817262613729083e+19,\n", + " 1.8848057180720275e+19,\n", + " 2.399240183561513e+19,\n", + " 3.055689676329845e+19,\n", + " 3.893113874625411e+19,\n", + " 4.960946557141142e+19,\n", + " 6.321807707248698e+19,\n", + " 8.054872673060305e+19,\n", + " 1.0260038707733928e+20,\n", + " 1.3063051519429272e+20,\n", + " 1.662177720101933e+20,\n", + " 2.1133826661677974e+20,\n", + " 2.684575833890042e+20,\n", + " 3.4064097905991975e+20,\n", + " 4.3168417502738606e+20,\n", + " 5.462670789589918e+20,\n", + " 6.901325097395839e+20,\n", + " 8.702915371292994e+20,\n", + " 1.0952563574232634e+21,\n", + " 1.375300718452619e+21,\n", + " 1.722746818864634e+21,\n", + " 2.1522764331248842e+21,\n", + " 2.6812628978271026e+21,\n", + " 3.330119779642166e+21,\n", + " 4.1226617090270917e+21,\n", + " 5.086473287530762e+21,\n", + " 6.253283468513638e+21,\n", + " 7.659345293155263e+21,\n", + " 9.345824472910041e+21,\n", + " 1.1359204614642866e+22,\n", + " 1.375172176817816e+22,\n", + " 1.6581845168132427e+22,\n", + " 1.991482570572514e+22,\n", + " 2.382333899576219e+22,\n", + " 2.838821373511856e+22,\n", + " 3.3699396494601908e+22,\n", + " 3.985691595346343e+22,\n", + " 4.6972179240541225e+22,\n", + " 5.516936796637091e+22,\n", + " 6.458709302696067e+22,\n", + " 7.5380222485513095e+22,\n", + " 8.772194010580573e+22,\n", + " 1.0180602176716361e+23,\n", + " 1.1784934654781455e+23,\n", + " 1.3609447440886649e+23,\n", + " 1.568127031191383e+23,\n", + " 1.803070819481287e+23,\n", + " 2.06915677593932e+23,\n", + " 2.3701499915947646e+23,\n", + " 2.71023544959553e+23,\n", + " 3.094054322171001e+23,\n", + " 3.526740609360287e+23,\n", + " 4.0139574951159005e+23,\n", + " 4.5619326751901374e+23,\n", + " 5.177491777989112e+23,\n", + " 5.8680889018952785e+23,\n", + " 6.641833168006825e+23,\n", + " 7.507510129606983e+23,\n", + " 8.474596839389969e+23,\n", + " 9.553269394188806e+23,\n", + " 1.0754401765775199e+24,\n", + " 1.2089554850743588e+24,\n", + " 1.357095492863096e+24,\n", + " 1.5211460411841878e+24,\n", + " 1.7024516754850944e+24,\n", + " 1.90240983499984e+24,\n", + " 2.12246383416892e+24,\n", + " 2.364094419728192e+24,\n", + " 2.6288102017177813e+24,\n", + " 2.918136639596423e+24,\n", + " 3.233603838748436e+24,\n", + " 3.5767331836490845e+24,\n", + " 3.9490225158234144e+24,\n", + " 4.3519304061485885e+24,\n", + " 4.786859027772775e+24,\n", + " 5.255136064598995e+24,\n", + " 5.757995416967139e+24,\n", + " 6.296556897987198e+24,\n", + " 6.871804819242886e+24,\n", + " 7.484565531841691e+24,\n", + " 8.135484951682379e+24,\n", + " 8.825003025414047e+24,\n", + " 9.553330704611004e+24,\n", + " 1.032042282091618e+25,\n", + " 1.1125952936821893e+25,\n", + " 1.196928678171079e+25,\n", + " 1.2849456098359883e+25,\n", + " 1.3765131504848915e+25,\n", + " 1.4714596866762383e+25,\n", + " 1.5695723117814726e+25,\n", + " 1.6705943451426314e+25,\n", + " 1.774223117413949e+25,\n", + " 1.8801074940129505e+25,\n", + " 1.987846298412364e+25,\n", + " 2.09698622863949e+25,\n", + " 2.2070206085635655e+25,\n", + " 2.3173886403489155e+25,\n", + " 2.427474581508771e+25,\n", + " 2.536608255852681e+25,\n", + " 2.6440652651039667e+25,\n", + " 2.7490699372821376e+25,\n", + " 2.8507977285009806e+25,\n", + " 2.9483717323796403e+25,\n", + " 3.0408859505164942e+25,\n", + " 3.1273895429812504e+25,\n", + " 3.206916977225403e+25,\n", + " 3.2784792015318745e+25,\n", + " 3.341096536343521e+25,\n", + " 3.393803384478866e+25]},\n", + " 'time': [0.0,\n", + " 0.7,\n", + " 1.4,\n", + " 2.1,\n", + " 2.8,\n", + " 3.5,\n", + " 4.2,\n", + " 4.9,\n", + " 5.6,\n", + " 6.3,\n", + " 7.0,\n", + " 7.7,\n", + " 8.4,\n", + " 9.1,\n", + " 9.8,\n", + " 10.5,\n", + " 11.2,\n", + " 11.9,\n", + " 12.6,\n", + " 13.3,\n", + " 14.0,\n", + " 14.7,\n", + " 15.4,\n", + " 16.1,\n", + " 16.8,\n", + " 17.5,\n", + " 18.2,\n", + " 18.9,\n", + " 19.6,\n", + " 20.3,\n", + " 21.0,\n", + " 21.7,\n", + " 22.4,\n", + " 23.1,\n", + " 23.8,\n", + " 24.5,\n", + " 25.2,\n", + " 25.9,\n", + " 26.6,\n", + " 27.3,\n", + " 28.0,\n", + " 28.7,\n", + " 29.4,\n", + " 30.1,\n", + " 30.8,\n", + " 31.5,\n", + " 32.2,\n", + " 32.9,\n", + " 33.6,\n", + " 34.3,\n", + " 35.0,\n", + " 35.7,\n", + " 36.4,\n", + " 37.1,\n", + " 37.8,\n", + " 38.5,\n", + " 39.2,\n", + " 39.9,\n", + " 40.6,\n", + " 41.3,\n", + " 42.0,\n", + " 42.7,\n", + " 43.4,\n", + " 44.1,\n", + " 44.8,\n", + " 45.5,\n", + " 46.2,\n", + " 46.9,\n", + " 47.6,\n", + " 48.3,\n", + " 49.0,\n", + " 49.7,\n", + " 50.4,\n", + " 51.1,\n", + " 51.8,\n", + " 52.5,\n", + " 53.2,\n", + " 53.9,\n", + " 54.6,\n", + " 55.3,\n", + " 56.0,\n", + " 56.7,\n", + " 57.4,\n", + " 58.1,\n", + " 58.8,\n", + " 59.5,\n", + " 60.2,\n", + " 60.9,\n", + " 61.6,\n", + " 62.3,\n", + " 63.0,\n", + " 63.7,\n", + " 64.4,\n", + " 65.1,\n", + " 65.8,\n", + " 66.5,\n", + " 67.2,\n", + " 67.9,\n", + " 68.6,\n", + " 69.3,\n", + " 70.0,\n", + " 70.7,\n", + " 71.4,\n", + " 72.1,\n", + " 72.8,\n", + " 73.5,\n", + " 74.2,\n", + " 74.9,\n", + " 75.6,\n", + " 76.3,\n", + " 77.0,\n", + " 77.7,\n", + " 78.4,\n", + " 79.1,\n", + " 79.8,\n", + " 80.5,\n", + " 81.2,\n", + " 81.9,\n", + " 82.6,\n", + " 83.3,\n", + " 84.0,\n", + " 84.7,\n", + " 85.4,\n", + " 86.1,\n", + " 86.8,\n", + " 87.5,\n", + " 88.2,\n", + " 88.9,\n", + " 89.6,\n", + " 90.3,\n", + " 91.0,\n", + " 91.7,\n", + " 92.4,\n", + " 93.1,\n", + " 93.8,\n", + " 94.5,\n", + " 95.2,\n", + " 95.9,\n", + " 96.6,\n", + " 97.3,\n", + " 98.0,\n", + " 98.7,\n", + " 99.4]}}" + ] + }, + "execution_count": 5, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 5 + }, + { + "metadata": { + "ExecuteTime": { + "end_time": "2024-05-26T17:49:27.783300Z", + "start_time": "2024-05-26T17:49:27.780784Z" + } + }, + "cell_type": "code", + "source": "observables", "id": "7b7907231df4a571", - "execution_count": 3, - "outputs": [] + "outputs": [ + { + "data": { + "text/plain": [ + "[['time'],\n", + " ['floating_species_concentrations', 'T'],\n", + " ['floating_species_concentrations', 'E'],\n", + " ['floating_species_concentrations', 'I'],\n", + " ['model_parameters', 'r2'],\n", + " ['model_parameters', 'b'],\n", + " ['model_parameters', 'a'],\n", + " ['model_parameters', 'g2'],\n", + " ['model_parameters', 'p1'],\n", + " ['model_parameters', 'g1'],\n", + " ['model_parameters', 'mu2'],\n", + " ['model_parameters', 'c'],\n", + " ['model_parameters', 'p2'],\n", + " ['model_parameters', 'g3'],\n", + " ['model_parameters', 'mu3'],\n", + " ['model_parameters', 'V'],\n", + " ['model_parameters', 's1'],\n", + " ['model_parameters', 's2'],\n", + " ['reactions', 'Induction of tumor'],\n", + " ['reactions',\n", + " 'Removal of tumor from the system by the action of immune response'],\n", + " ['reactions', 'Activation and transfer of effector cells to the action site'],\n", + " ['reactions',\n", + " 'Deactivation and removal of effector cells from the site of tumor'],\n", + " ['reactions', 'Activation of interleukin 2'],\n", + " ['reactions', 'Deactivation of interleukin2']]" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], + "execution_count": 14 }, { "metadata": {