diff --git a/docs/distributed_tellurium.rst b/docs/distributed_tellurium.rst
new file mode 100644
index 00000000..e19b5a17
--- /dev/null
+++ b/docs/distributed_tellurium.rst
@@ -0,0 +1,323 @@
+======================
+Parallel Programming
+======================
+
+Tellurium in Distributed Environment
+====================
+
+Tellurium features a new functionality that can help users to perform simulation much faster. In the background it runs on a distributed cluster of machines and computations are done in-memory to achieve a very low latency. Currently, it allows users to run the computations/simulations with regards to parameter scans, parameter fitting, sensitivity analysis and parameter identifiability. `Apache Spark `_ has been integrated with Tellurium and this allow users to run different simulations parallelly.
+
+To run this, first it is required to setup Spark Cluster on one ore more machines which follows Master-Slave architecture. Spark can run on Spark's Standalone, `Apache Mesos `_ and `Hadoop YARN `_. If you are a python lover, you are in garden. Run the below pip command to install spark in a single machine.
+
+.. code-block:: python
+
+ pip install pyspark
+
+Or follow the instruction available in `Spark Downloads `_ Page.
+
+
+Getting Started
+========================
+
+First it is required to initialize spark context (sc) as this coordinates everything that needs to run parallelly. This is available in default if you open pyspark from terminal or through `Zeppelin `_.
+
+.. code-block:: python
+
+ from pyspark import SparkContext,SparkConf
+ conf = SparkConf().setAppName('').setMaster('')
+ sc = SparkContext(conf=conf)
+
+The two important things that needs to get replaced are which can be anything that a program can be named while the other thing is which can be local[2] (Which means your application uses 2 threads and it can be any 'n' value) if you are running it on a single machine or it could be of the form spark://127.208.10.259:8000 assuming your spark master is on 8000 port and running on node with IP 127.208.10.259.
+
+Your First Stochastic Simulation
+========================
+
+After the Spark Context is perfectly initialised, lets run our first simple stochastic simulation.
+
+.. code-block:: python
+
+ import tellurium as te
+
+ model_def = 'S1 -> S2; k1*S1; k1 = 0.1; S1 = 40'
+ stochastic_simulation_model = te.StochasticSimulationModel(model=model_def,
+ seed=1234, # not used
+ variable_step_size = False,
+ from_time=0,
+ to_time=40,
+ step_points=50)
+ stochastic_simulation_model.integrator = "gillespie"
+ results = te.distributed_stochastic_simulation(sc,stochastic_simulation_model,50)
+ te.plot_stochastic_result(results)
+
+In the above example, we have created a model as an antimony string and then created a StochasticSimulationModel object with the parameters mentioned above. From the above example your model provided in the form of antimony string will simulate from 0 to 40 with 50 step points. You might see the result that looks like below
+
+.. image:: images/stochastic_image.png
+ :scale: 100 %
+ :alt: Stochastic Simulation Result
+ :align: right
+
+
+Parameter Estimation
+========================
+
+As a next example, you want to run Parameter Estimation for a specific set of attributes of your model(s). Additionally you may need to provide an optimization function so as to estimate values accurately. It begins with usual object creation of stochastic simulation model (Check the above code for reference)
+
+Lets test Lotka Volterra Model and try estimating parameters in that model. We will use differential_evolution as an optimization function available in scipy library.
+
+.. code-block:: python
+
+ import tellurium as te
+ from scipy.optimize import differential_evolution as diff_evol
+
+Now we will initialise our Lotka-Volterra antimony model.
+
+.. code-block:: python
+
+ # Load the Lotka-Volterra model
+ lotka_volterra_antimony_model_definition = '''
+ model *LVModel()
+ // Compartments and Species:
+ compartment compartment_;
+ species A in compartment_, B in compartment_;
+ // Reactions:
+ R1: A => 2A; compartment_*R1_k1*A;
+ R2: A => B; compartment_*A*B*R2_p;
+ R4: B => ; compartment_*R4_k1*B;
+ // Species initializations:
+ A = 71;
+ B = 79;
+ // Compartment initializations:
+ compartment_ = 1;
+ // Variable initializations:
+ R1_k1 = 0.5;
+ R2_p = 0.0025;
+ R4_k1 = 0.3;
+ // Other declarations:
+ const compartment_;
+ // Unit definitions:
+ unit volume = 1e-3 litre;
+ unit substance = item;
+ end
+ '''
+
+We use the above initialisation in order to create a Stochastic Simulation Model
+
+.. code-block:: python
+
+ stochastic_simulation_model = te.StochasticSimulationModel(model=lotka_volterra_antimony_model_definition,
+ seed=1234, # not used
+ variable_step_size = False,
+ from_time=0,
+ to_time=1000,
+ step_points=1000)
+ stochastic_simulation_model.integrator = "gillespie"
+
+Defining the bounds of the parameters we wish to estimate
+
+.. code-block:: python
+
+ bounds = {"R1_k1":(0.0,1.0),"R4_k1":(0.0,0.5)}
+
+If you wish to run it as a stochastic simulation with running number of simulation in a distributed enviroment.
+
+.. code-block:: python
+
+ from pyspark import SparkContext,SparkConf
+ conf = SparkConf().setAppName('RunningMonteCluster').setMaster('SPARK_MASTER')
+ sc = SparkContext(conf=conf)
+
+Now, you just need to call run function to evaluate and estimate the parameters based on the bounds provided
+
+.. code-block:: python
+
+ parameter_est = te.ParameterEstimation(stochastic_simulation_model,bounds,stochastic=False, sc=None)
+ path = "/home/shaik/year/stoch-param-fitting-benchmarks/zimmer/ID/"
+ parameter_est.setDataFromFile(path+FILENAME)
+ print parameter_est.run(diff_evol,maxiter=1)
+
+If we want to test it for Immigration-Death Model, all we need to do is to change the antimony_model string and change the bounds.
+
+.. code-block:: python
+
+ immigration_death_antimony_model_definition = '''
+ model *IDModel()
+
+ // Compartments and Species:
+ compartment compartment_;
+ species A in compartment_;
+
+ // Reactions:
+ R1: => A; compartment_*p1;
+ R2: A => ; compartment_*p2*A;
+
+ // Species initializations:
+ A = 10;
+
+ // Compartment initializations:
+ compartment_ = 1;
+
+ // Variable initializations:
+ p1 = 1;
+ p2 = 0.1;
+
+ // Other declarations:
+ const compartment_, p1, p2;
+
+ // Unit definitions:
+ unit volume = 1e-3 litre;
+ unit substance = item;
+ end
+ '''
+ bounds = {"p1":(0.0,5.0),"p2":(0.0,0.5)}
+
+
+Lets look into more Complex models using Stochastic Simulations
+
+
+.. code-block:: python
+
+ from scipy.optimize import differential_evolution as diff_evol
+ stochastic_simulation_model = te.StochasticSimulationModel(model=antimony_model,
+ seed=1234, # not used
+ variable_step_size = False,
+ from_time=0,
+ to_time=1000,
+ step_points=1000)
+ stochastic_simulation_model.integrator = "gillespie"
+
+Here we are using differential evolution as optimization function and we are creating a stochastic simulation model providing antimony string as model along with necessary arguments. The next step would be providing parameters with their lower and upper bounds
+
+.. code-block:: python
+
+ bounds = {
+ "kdegMdm2":(0.0000001, 0.9),
+ "kdegp53":(0.0000001,0.9),
+ "kbinMdm2p53":(0.000001,9),
+ "krelMdm2p53":(0.00000001,0.09),
+ "kphosMdm2":(0.001,10000.0),
+ "kdephosMdm2":(0.0001,900),
+ "kdegATMMdm2":(0.0000001,0.9)
+ }
+
+
+Then to trigger Parameter Estimation we need to call ParameterEstimation from tellurium module.
+
+.. code-block:: python
+
+ parameter_est = te.ParameterEstimation(stochastic_simulation_model,bounds,stochastic=True, sc=sc)
+
+The key points that we need to change here are
+
+- **stochastic**
+Can be True/False. True will run stochastic simulation and get the mean of the results. It should be noted that sc which represents Spark Context should be provided if you need to set stochastic as True. If set to False, this will run in normal python without Spark and will perform only a sinle run.
+
+- **sc**
+This represents the Spark Context Object created. This is a mandatory argument when stochastic is True
+
+.. code-block:: python
+
+ from pyspark import SparkContext,SparkConf
+ conf = SparkConf().setAppName('').setMaster('')
+ sc = SparkContext(conf=conf)
+
+After creating ParameterEstimation object we need to set the data which is compared against and then need to run.
+
+.. code-block:: python
+
+ parameter_est.setDataFromFile(path+FILENAME)
+ print parameter_est.run(diff_evol,maxiter=1)
+
+In the above block we have configured our data using the setDataFromFile method which accepts FILEPATH as an argument. Then we performed **run** method which accepts the optimization function along with the other arguments required for the optimization function. Your result structure may look similar to this.
+
+.. code-block:: python
+
+ {
+ 'Estimated Result': array([8.09843570e-04, 2.05751914e-05, 2.06783537e-03,4.93490582e-04]),
+ 'Average SSE': 9.2357328599694437,
+ 'Parameters': ['kdegp53', 'krelMdm2p53', 'kbinMdm2p53', 'kdegMdm2']
+ }
+
+The results are in the form of numpy array along with Average SSE (Sum of Squared Errors) for the simulations. Here is the explanation of the mapping
+
+- **kdegp53** : 8.09843570e-04
+- **krelMdm2p53** : 2.05751914e-05
+- **kbinMdm2p53** : 2.06783537e-03
+- **kdegMdm2** : 4.93490582e-04
+- **Average SSE** : 9.2357328599694437
+
+
+Parameter Scanning
+========================
+
+With Distributed nature of tellurium, now you can run parameter scanning for multiple models. More work is currently in progress which enables user to store images in multiple formats and also in HDFS or any other file system.
+
+.. code-block:: python
+
+ model_one_road_runner = '''
+ J1: $Xo -> x; 0.1 + k1*x^2/(k2+x^3);
+ x -> $w; k3*x;
+
+ k1 = 0.9;
+ k2 = 0.3;
+ k3 = 0.7;
+ x = 0;
+ '''
+
+ model_two_road_runner = '''
+ J1: $Xo -> x; 0.1 + k1*x^4/(k2+x^4);
+ x -> $w; k3*x;
+
+ k1 = 0.8;
+ k2 = 0.7;
+ k3 = 0.5;
+ x = 0;
+ '''
+
+ model_one_parameters = {"startTime" : 0,"endTime" : 15,"numberOfPoints" : 50,"polyNumber" : 10,"endValue" : 1.8,"alpha" : 0.8,"value" : "x","selection" : "x","color" : ['#0F0F3D', '#141452', '#1A1A66', '#1F1F7A', '#24248F', '#2929A3','#2E2EB8', '#3333CC', '#4747D1', '#5C5CD6'] }
+
+ model_two_parameters = {"startTime" : 0,"endTime" : 20,"numberOfPoints" : 60,"polyNumber" : 10,"endValue" : 1.5,"alpha" : 0.6,"value" : "x","selection" : "x","color" : ['#0F0F3D', '#141452', '#1A1A66', '#1F1F7A', '#24248F', '#2929A3','#2E2EB8', '#3333CC', '#4747D1', '#5C5CD6'] }
+
+
+We have created two models and parameters separately and we are interested in running Parameter Scan for these models (it can be run for any number of models Parallelly), we wrap it an array and call distributed_parameter_scanning method.
+
+.. code-block:: python
+
+ plots = te.distributed_parameter_scanning(sc,[(model_one_road_runner,model_one_parameters),model_two_road_runner,model_two_parameters)],"plotPolyArray")
+
+
+After the computation, plotting the results is easy
+
+
+.. code-block:: python
+
+ for fig in plots:
+ te.plotImage(fig)
+
+You should see results similar to the ones below
+
+
+.. image:: images/paramest1.png
+ :width: 49 %
+ :alt: For the First Model
+.. image:: images/paramest2.png
+ :width: 49 %
+ :alt: For the Second Model
+
+Check this space for more information ...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/docs/images/paramest1.png b/docs/images/paramest1.png
new file mode 100644
index 00000000..03ffb6ba
Binary files /dev/null and b/docs/images/paramest1.png differ
diff --git a/docs/images/paramest2.png b/docs/images/paramest2.png
new file mode 100644
index 00000000..668cdd4d
Binary files /dev/null and b/docs/images/paramest2.png differ
diff --git a/docs/images/stochastic_image.png b/docs/images/stochastic_image.png
new file mode 100644
index 00000000..26dbd62a
Binary files /dev/null and b/docs/images/stochastic_image.png differ
diff --git a/docs/index.rst b/docs/index.rst
index 0686f1f1..4aa3b799 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -17,6 +17,7 @@ Contents:
walkthrough.rst
notebooks.rst
antimony.rst
+ distributed_tellurium.rst
tellurium_methods.rst
API.rst
FAQ
diff --git a/docs/tellurium_methods.rst b/docs/tellurium_methods.rst
index 0008d5de..afff949a 100644
--- a/docs/tellurium_methods.rst
+++ b/docs/tellurium_methods.rst
@@ -81,6 +81,68 @@ Use these routines to carry out Gillespie style stochastic simulations.
.. include:: _notebooks/core/tellurium_stochastic.rst
+----------------------------------------
+Distributed Stochastic Simulation
+----------------------------------------
+
+Use these in order to run simulations in distributed environment.
+
+.. autoclass:: tellurium.StochasticSimulationModel
+ :members: model, seed, variable_step_size, from_time, to_time, step_points, integrator
+
+----------------------------------------
+Distributed Stochastic Simulation Utility
+----------------------------------------
+
+Use these in order to run simulations in distributed environment. It uses the object defined with StochasticSimulationModel.
+
+.. autofunction:: tellurium.distributed_stochastic_simulation
+
+
+----------------------------------------
+Plot Distributed Stochastic Simulation Results
+----------------------------------------
+
+To plot the results retrieved from distributed_stochastic_simulation.
+
+.. autofunction:: tellurium.plot_stochastic_result
+
+----------------------------------------
+Distributed Parameter Scanning
+----------------------------------------
+
+Parameter Scanning one/more models in a distributed environment
+
+.. autofunction:: tellurium.distributed_parameter_scanning
+
+----------------------------------------
+Plotting Image of Parameter Scan
+----------------------------------------
+
+Helps in plotting the results parameter Scanning of one/more models run in a distributed environment
+
+.. autofunction:: tellurium.plotImage
+
+
+----------------------------------------
+Distributed Sensitivity Analysis
+----------------------------------------
+
+Use these in order to run Sensitivity Analysis in distributed environment.
+
+.. autoclass:: tellurium.SensitivityAnalysis
+ :members: model, sbml, conservedMoietyAnalysis, filename, bounds, allowLog
+
+
+----------------------------------------
+Distributed Sensitivity Analysis Utility
+----------------------------------------
+
+Running the Sensitivity analysis using the model created using tellurium.SensitivityAnalysis
+
+.. autofunction:: tellurium.distributed_sensitivity_analysis
+
+
----------------------------------------
Math
----------------------------------------
diff --git a/tellurium/analysis/parameterestimation.py b/tellurium/analysis/parameterestimation.py
index ebb5294d..84281505 100644
--- a/tellurium/analysis/parameterestimation.py
+++ b/tellurium/analysis/parameterestimation.py
@@ -7,25 +7,191 @@
import tellurium as te
from scipy.optimize import differential_evolution
import random
+import pandas
+
class ParameterEstimation(object):
- """Parameter Estimation"""
- def __init__(self, stochastic_simulation_model,bounds, data=None):
- if(data is not None):
- self.data = data
+ def __init__(self, stochastic_simulation_model, bounds, species=None, data=None, stochastic=False, sc=None,
+ allow_log=False, func=None):
+ self._model = stochastic_simulation_model
+ self._bounds = bounds
+ self._species = species
+ self._data = data
+ self._stochastic = stochastic
+ self._sc = sc
+ self._allow_log = allow_log
+ self._func = func
+ self._collected_values = np.array([])
+ self.validate_parameters()
+
+
+ @property
+ def model(self):
+ return self._model
+
+ @model.setter
+ def model(self, value):
+ self._model = value
+ self.validate_parameters()
+
+ @model.deleter
+ def model(self):
+ del self._model
+
+ @property
+ def bounds(self):
+ return self._bounds
+
+ @bounds.setter
+ def bounds(self, value):
+ self._bounds = value
+ self.validate_parameters()
+
+ @bounds.deleter
+ def bounds(self):
+ del self._bounds
+
+ @property
+ def species(self):
+ return self._species
+
+ @species.setter
+ def species(self, value):
+ self._species = value
+ self.validate_parameters()
+
+ @species.deleter
+ def species(self):
+ del self._species
+
+ @property
+ def data(self):
+ return self._data
+
+ @data.setter
+ def data(self, value):
+ self._data = value
+ self.validate_parameters()
+
+ @data.deleter
+ def data(self):
+ del self._data
+
+ @property
+ def stochastic(self):
+ return self._stochastic
+
+ @stochastic.setter
+ def stochastic(self, value):
+ self._stochastic = value
+
+ @stochastic.deleter
+ def stochastic(self):
+ del self._stochastic
+
+ @property
+ def sc(self):
+ return self._sc
+
+ @sc.setter
+ def sc(self, value):
+ self._sc = value
+ self.validate_parameters()
+
+ @sc.deleter
+ def sc(self):
+ del self._sc
+
+ @property
+ def allow_log(self):
+ return self._allow_log
+
+ @allow_log.setter
+ def allow_log(self, value):
+ self._allow_log = value
+ self.validate_parameters()
+
+ @allow_log.deleter
+ def allow_log(self):
+ del self._allow_log
+
+ @property
+ def func(self):
+ return self._func
+
+ @func.setter
+ def func(self, value):
+ self._func = value
+
+
+ @func.deleter
+ def func(self):
+ del self._func
+
+ def validate_parameters(self):
+ if(self._stochastic):
+ if self._sc is None:
+ raise ValueError('If you want to run it in a distributed mode, provide spark context')
+
+
+ def _handle_allow_log(self):
+ if self._allow_log:
+ for each_parameter in self._bounds.keys():
+ _begin = self._bounds[each_parameter][0]*1.0
+ _end = self._bounds[each_parameter][1]*1.0
+ self._bounds[each_parameter] = tuple(np.logspace(_begin,_end, num=2))
+
+
+ def run(self, func=None, **kwargs):
+ """
+ Allows the user to set the data from a File
+ This data is to be compared with the simulated data in the process of parameter estimation
+
+ Args:
+ func: An Optional Variable with default value (None) which by default run differential evolution
+ which is from scipy function. Users can provide reference to their defined function as argument.
+
+
+ Returns:
+ The Value of the parameter(s) which are estimated by the function provided.
+
+ .. sectionauthor:: Shaik Asifullah
+
+ """
+
+ if self._data is None:
+ raise ValueError('Data is not available. Set the data using setDataFromFile method')
+ return
+
+ self._handle_allow_log()
+ self._parameter_names = self._bounds.keys()
+ self._parameter_bounds = self._bounds.values()
- self.model = stochastic_simulation_model
- self.bounds = bounds
-
+ for key, value in kwargs.iteritems():
+ print("%s == %s" % (key, value))
+ if (self._func is None): # Then Differential Evolution is used (default)
+ result = differential_evolution(self._SSE, self._parameter_bounds, **kwargs)
- def setDataFromFile(self,FILENAME, delimiter=",", headers=True):
+ else:
+ result = func(self._SSE, self._parameter_bounds,**kwargs)
+
+ metrics = {
+ "Parameters": self._parameter_names,
+ "Average SSE": self._collected_values.mean(0),
+ "Estimated Result": result.x
+ }
+
+ self._collected_values = np.array([])
+ return (metrics)
+
+ def setDataFromFile(self, FILENAME, delimiter=",", headers=True, time_column="time", usecols=None):
"""Allows the user to set the data from a File
This data is to be compared with the simulated data in the process of parameter estimation
-
+
Args:
FILENAME: A Complete/relative readable Filename with proper permissions
- delimiter: An Optional variable with comma (",") as default value.
+ delimiter: An Optional variable with comma (",") as default value.
A delimiter with which the File is delimited by.
It can be Comma (",") , Tab ("\t") or anyother thing
headers: Another optional variable, with Boolean True as default value
@@ -33,126 +199,126 @@ def setDataFromFile(self,FILENAME, delimiter=",", headers=True):
Returns:
None but sets class Variable data with the data provided
-
- .. sectionauthor:: Shaik Asifullah
-
-
- """
- with open(FILENAME,'r') as dest_f:
- data_iter = csv.reader(dest_f,
- delimiter = ",",
- quotechar = '"')
- self.data = [data for data in data_iter]
- if(headers):
- self.data = self.data[1:]
-
- self.data = np.asarray(self.data, dtype = float)
-
-
- def run(self,func=None):
- """Allows the user to set the data from a File
- This data is to be compared with the simulated data in the process of parameter estimation
-
- Args:
- func: An Optional Variable with default value (None) which by default run differential evolution
- which is from scipy function. Users can provide reference to their defined function as argument.
-
- Returns:
- The Value of the parameter(s) which are estimated by the function provided.
-
.. sectionauthor:: Shaik Asifullah
-
-
+
+
"""
-
- self._parameter_names = self.bounds.keys()
- self._parameter_bounds = self.bounds.values()
- self._model_roadrunner = te.loada(self.model.model)
- x_data = self.data[:,0]
- y_data = self.data[:,1:]
- arguments = (x_data,y_data)
-
- if(func is not None):
- result = differential_evolution(self._SSE, self._parameter_bounds, args=arguments)
- return(result.x)
- else:
- result = func(self._SSE,self._parameter_bounds,args=arguments)
- return(result.x)
+
+ data = np.genfromtxt(FILENAME, dtype=float, delimiter=delimiter, names=headers, usecols=usecols)
+ self._data = pandas.DataFrame(data=data, index=data[time_column])
+ self._data.drop(["time"], axis=1, inplace=True)
+
+
+
def _set_theta_values(self, theta):
""" Sets the Theta Value in the range of bounds provided to the Function.
Not intended to be called by user.
-
+
Args:
theta: The Theta Value that is set for the function defined/provided
-
+
Returns:
None but it sets the parameter(s) to the stochastic model provided
-
+
.. sectionauthor:: Shaik Asifullah
-
-
+
+
"""
- for theta_i,each_theta in enumerate(self._parameter_names):
+ for theta_i, each_theta in enumerate(self._parameter_names):
setattr(self._model_roadrunner, each_theta, theta[theta_i])
+ def _prepare_model(self):
+ random.seed()
+ self._model_roadrunner = te.loada(self._model.model)
+ self._model_roadrunner.integrator.variable_step_size = self._model.variable_step_size
+ self._model_roadrunner.integrator = self._model.integrator
- def _SSE(self,parameters, *data):
+ def _SSE(self,parameters):
""" Runs a simuation of SumOfSquares that get parameters and data and compute the metric.
Not intended to be called by user.
-
+
Args:
parameters: The tuple of theta values whose output is compared against the data provided
- data: The data provided by the user through FileName or manually
+ data: The data provided by the user through FileName or manually
which is used to compare against the simulations
-
+
Returns:
Sum of Squared Error
-
+
.. sectionauthor:: Shaik Asifullah
-
-
+
+
"""
theta = parameters
-
- x, y = data
- sample_x, sample_y = data
+ random.seed()
+ self._prepare_model()
self._set_theta_values(theta)
- random.seed()
- # it is now safe to use random.randint
- #self._model.setSeed(random.randint(1000, 99999))
- self._model_roadrunner.integrator.variable_step_size = self.model.variable_step_size
- self._model_roadrunner.reset()
- simulated_data = self._model_roadrunner.simulate(self.model.from_time, self.model.to_time,
- self.model.step_points)
+ try: # The Simulation may fail. If so, throw a large penalty
+ sim_data = None
+ if self._stochastic:
+ modified_model = self._model_roadrunner.getCurrentAntimony()
+ stochastic_simulation_model = te.StochasticSimulationModel(model=modified_model,
+ seed=1234, # not used
+ variable_step_size=self._model.variable_step_size,
+ from_time=self._model.from_time,
+ to_time=self._model.to_time,
+ step_points=self.model._step_points)
+ stochastic_simulation_model.integrator = self._model.integrator
+ results = te.distributed_stochastic_simulation(self._sc, stochastic_simulation_model, 50)
+
+ column_names = results[0][0]
+ column_names = [item[1:-1] if (item != "time" and item[0] == '[') else item for item in column_names]
+
+ mean_result = np.array([item[1] for item in results]).mean(0)
+
+ sim_data = pandas.DataFrame(data=mean_result, columns=column_names)
+
+ else:
+
+ normal_sim = self._model_roadrunner.simulate(self._model.from_time, self._model.to_time,
+ self._model.step_points)
+
+ self._model_roadrunner.reset()
+
+ sim_data = pandas.DataFrame(data=normal_sim, index=normal_sim["time"], columns=normal_sim.colnames)
+
+ column_names = {}
+ for each_column in normal_sim.colnames:
+ if (each_column != "time" and each_column[0] == '['):
+ column_names[each_column] = each_column[1:-1]
+ else:
+ column_names[each_column] = each_column
+
+ sim_data.rename(columns=column_names,inplace=True)
+
+
+
+ if sim_data is None:
+ raise ValueError("Something wrong in calculating Simulation Data")
+
+ partial_result = 0.0
+ total_observations = 0
+ for _, row in sim_data.iterrows():
- simulated_data = np.array(simulated_data)
- simulated_x = simulated_data[:,0]
- simulated_y = simulated_data[:,1:]
+ row_timestamp = float(row["time"])
- SEARCH_BEGIN_INDEX = 0
- SSE_RESULT = 0
+ comp_data = self._data[self._data.index <= row_timestamp].iloc[-1]
- for simulated_i in range(len(simulated_y)):
- y_i = simulated_y[simulated_i]
- #yhat_i = sample_y[simulated_i]
+ for each_key in comp_data.keys():
+ partial_result += (comp_data[each_key] - row[each_key]) ** 2
+ total_observations += 1
- x_i = simulated_x[simulated_i]
- for search_i in range(SEARCH_BEGIN_INDEX+1,len(sample_x)):
- if(sample_x[search_i-1] <= x_i < sample_x[search_i]):
- yhat_i = sample_y[search_i-1]
- break
- SEARCH_BEGIN_INDEX += 1
+ final_result = (partial_result / total_observations) ** 0.5
- partial_result = 0
- for sse_i in range(len(y_i)):
- partial_result += (float(y_i[sse_i]) - float(yhat_i[sse_i])) ** 2
- SSE_RESULT += partial_result
+ self._collected_values = np.append(self._collected_values, final_result)
+ return(final_result)
- return SSE_RESULT ** 0.5
+ except Exception as e:
+ return 10000000.