def plotQuantity(self, quantity_id, param_values): ''' Plot a simulated quantity vs its data points using Tellurium.''' from data import measured_quantity_ids, measured_quantity_id_to_name_map from data import t1, t2, time_end, n1, n2, n3 quantity_name = measured_quantity_id_to_name_map.get(quantity_id,quantity_id) iq = measured_quantity_ids.index(quantity_id) reference_data = array(self.reference_values[:,iq]) r = RoadRunner(self.sbml) r.reset() r.resetAll() r.resetToOrigin() self._setParameterVector(param_values, self.param_list, r) # r.oneStep(0., 10) # print('plotQuantity OAA\' = {}'.format(r["OAA'"])) s1 = r.simulate(0., t1, n1, ['time', quantity_id]) s2 = r.simulate(t1, t2, n2, ['time', quantity_id]) # print(quantity_id) # if quantity_id == 'GLC': # print('BM before {}'.format(r['[BM]'])) # print(iq) # print(reference_data) s3 = r.simulate(t2, time_end, n3, ['time', quantity_id]) sim = vstack(( s1, s2, s3, )) assert sim.shape[0] == reference_data.shape[0] residuals = sim[:,1] - reference_data r.reset() r.resetAll() r.resetToOrigin() self._setParameterVector(param_values, self.param_list, r) # self._setParameterVector(param_values, self.param_list, r) s = r.simulate(0,time_end,1000,['time',quantity_id]) import tellurium as te te.plot(sim[:,0], reference_data, scatter=True, name=quantity_name+' data', show=False, title=quantity_name, error_y_pos=maximum(residuals,0), error_y_neg=-minimum(residuals,0)) te.plot(s[:,0], s[:,1], name=quantity_name+' sim')
class B3Problem(TimecourseSimBiopredyn): ''' Class that performs a timecourse simulation and evaluates the objective function for b1.''' def __init__(self, sbml): self.sbml = sbml self.r = RoadRunner(sbml) from data import measured_quantity_ids, exp_data self.measured_quantity_ids = measured_quantity_ids self.reference_values = exp_data self.reference_value_means_squared = mean(self.reference_values, axis=0)**2 from params import new_param_ids as param_ids self.param_list = param_ids self.penalty_scale = 1. def evaluate(self, x): # type: (array) -> SupportsFloat """ Evaluate and return the objective function. """ from interruptingcow import timeout # from data import time_end, n_points from data import t1, t2, time_end, n1, n2, n3 self.reset() self.r.resetAll() self.r.resetToOrigin() self.setParameterVector(x) self.r.reset() def worker(): # sim = array(self.r.simulate(0., time_end, n_points, self.measured_quantity_ids)) s1 = self.r.simulate(0., t1, n1, self.measured_quantity_ids) s2 = self.r.simulate(t1, t2, n2, self.measured_quantity_ids) s3 = self.r.simulate(t2, time_end, n3, self.measured_quantity_ids) sim = vstack(( s1, s2, s3, )) residuals = sim-self.reference_values normalized_mse_per_quantity = mean(residuals**2,axis=0)/self.reference_value_means_squared # from pprint import pprint # print('residuals:') # pprint({id: value for id,value in zip(self.measured_quantity_ids, sqrt(normalized_mse_per_quantity))}) return sqrt(mean(normalized_mse_per_quantity)) try: with timeout(10, StalledSimulation): return worker() except (RuntimeError, StalledSimulation): # if convergence fails, use a penalty score return 1e9*self.penalty_scale def plotQuantity(self, quantity_id, param_values): ''' Plot a simulated quantity vs its data points using Tellurium.''' from data import measured_quantity_ids, measured_quantity_id_to_name_map from data import t1, t2, time_end, n1, n2, n3 quantity_name = measured_quantity_id_to_name_map.get(quantity_id,quantity_id) iq = measured_quantity_ids.index(quantity_id) reference_data = array(self.reference_values[:,iq]) r = RoadRunner(self.sbml) r.reset() r.resetAll() r.resetToOrigin() self._setParameterVector(param_values, self.param_list, r) # r.oneStep(0., 10) # print('plotQuantity OAA\' = {}'.format(r["OAA'"])) s1 = r.simulate(0., t1, n1, ['time', quantity_id]) s2 = r.simulate(t1, t2, n2, ['time', quantity_id]) # print(quantity_id) # if quantity_id == 'GLC': # print('BM before {}'.format(r['[BM]'])) # print(iq) # print(reference_data) s3 = r.simulate(t2, time_end, n3, ['time', quantity_id]) sim = vstack(( s1, s2, s3, )) assert sim.shape[0] == reference_data.shape[0] residuals = sim[:,1] - reference_data r.reset() r.resetAll() r.resetToOrigin() self._setParameterVector(param_values, self.param_list, r) # self._setParameterVector(param_values, self.param_list, r) s = r.simulate(0,time_end,1000,['time',quantity_id]) import tellurium as te te.plot(sim[:,0], reference_data, scatter=True, name=quantity_name+' data', show=False, title=quantity_name, error_y_pos=maximum(residuals,0), error_y_neg=-minimum(residuals,0)) te.plot(s[:,0], s[:,1], name=quantity_name+' sim') # print('deviation for {}: {}/{} = {}'.format(quantity_id, sqrt(mean(residuals**2)), sqrt(self.reference_value_means_squared[iq]), sqrt(mean(residuals**2)/self.reference_value_means_squared[iq]))) def getParameterValue(self,param_index): from params import param_index_to_name_map try: return self.r[param_index_to_name_map[param_index]] except KeyError: raise KeyError('No such parameter for index {}, must be 0-1758 inclusive'.format(param_index))
class B5Problem(TimecourseSimBiopredyn): ''' Class that performs a timecourse simulation and evaluates the objective function for b1.''' def __init__(self, sbml): self.sbml = sbml self.r = RoadRunner(sbml) self.r.integrator.absolute_tolerance = 1e-15 self.r.integrator.relative_tolerance = 1e-9 self.r.integrator.stiff = True from observables import observables self.measured_quantity_ids = observables from json import load with open(join(dirname(realpath(__file__)), 'exp_data.json')) as f: self.reference_value_collection = [array(a) for a in load(f)] self.reference_value_means_squared_collection = [] for a in self.reference_value_collection: self.reference_value_means_squared_collection.append( mean(a, axis=0)**2) with open(join(dirname(realpath(__file__)), 'exp_y0.json')) as f: self.exp_y0_collection = [array(a) for a in load(f)] with open(join(dirname(realpath(__file__)), 'stimuli.json')) as f: self.stimuli_collection = [d for d in load(f)] from parameters import param_ids self.param_list = param_ids self.penalty_scale = 1. def setExperimentNumber(self, n): ''' Villaverde et al. use a set of 10 different experiments with respective different stimuli combinations and expected results. This method initialized appropriate variables for the given experiment. ''' self.reference_values = self.reference_value_collection[n] self.reference_value_means_squared = self.reference_value_means_squared_collection[ n] self.exp_y0 = self.exp_y0_collection[n] from species import species for k, s in enumerate(species): self.r.setValue('init({})'.format(s), float(self.exp_y0[k])) self.stimuli = self.stimuli_collection[n] for s, b in self.stimuli.items(): print('{} = {}'.format(s, b * 1.)) self.r[s] = b * 1. def evaluate(self, x): # type: (array) -> SupportsFloat """ Evaluate and return the objective function. """ from interruptingcow import timeout for n in range(10): self.setExperimentNumber(n) self.reset() def worker(): self.r.reset() self.r.resetAll() self.setParameterVector(x, exponential=False) sim = self.r.simulate(0., 30., 16, self.measured_quantity_ids) residuals = sim - self.reference_values normalized_mse_per_quantity = mean( residuals**2, axis=0) / self.reference_value_means_squared return sqrt(mean(normalized_mse_per_quantity)) try: with timeout(10, StalledSimulation): return worker() except (RuntimeError, StalledSimulation): # if convergence fails, use a penalty score return 1e9 * self.penalty_scale def plotQuantity(self, quantity_id, param_values, exp_number): ''' Plot a simulated quantity vs its data points using Tellurium.''' self.setExperimentNumber(exp_number) iq = self.measured_quantity_ids.index(quantity_id) reference_data = array(self.reference_values[:, iq]) # self.r.reset() # self.r.resetAll() # # r.resetToOrigin() # self.setParameterVector(param_values, exponential=False) # sim = self.r.simulate(0., 30., 16, ['time', quantity_id]) # # print(self.r.getReactionRates()) # assert sim.shape[0] == reference_data.shape[0] # residuals = sim[:,1] - reference_data self.r.reset() self.r.resetAll() # r.resetToOrigin() self.setParameterVector(param_values, exponential=False) s = self.r.simulate(0, 25., 100, ['time', quantity_id]) import tellurium as te # te.plot(sim[:,0], reference_data, scatter=True, # name=quantity_id+' data', show=False, # title=quantity_id, # error_y_pos=maximum(residuals,0), # error_y_neg=-minimum(residuals,0)) print(quantity_id + ' sim') te.plot(s[:, 0], s[:, 1], name=quantity_id + ' sim') def getParameterValue(self, param_index): from params import param_index_to_name_map try: return self.r[param_index_to_name_map[param_index]] except KeyError: raise KeyError( 'No such parameter for index {}, must be 0-1758 inclusive'. format(param_index))
class TimecourseModel(Evaluator): ''' Class that performs a timecourse simulation and calculates the residuals for b4.''' def __init__(self, sbml, data_quantities, measurement_map): ''' Constructor. :param measurement_map: A dictionary that maps the names of quantities to measurements to their respective (numpy) arrays. ''' self.sbml = sbml self.r = RoadRunner(sbml) self.residuals = [] #print(self.r.getFloatingSpeciesIds()) self.timepoints = unique(hstack(a[:, 0] for a in data_quantities)) self.reset() self.measurement_map = measurement_map # keep track of the number of times a measurement is used # (check correct number of residuals) self.measurement_count = OrderedDict( (quantity, 0) for quantity in self.measurement_map) self.quantity_residuals = dict( (quantity, list()) for quantity in self.measurement_map) def calcResiduals(self, t): ''' Try to calculate residuals at the current time t and add them to self.residuals. If they do not exist for certain datasets at time t, just pass over the dataset.''' self.usage_map = dict((q, False) for q in self.measurement_map) for quantity in self.measurement_map.keys(): self.tryAddResidual(t, self.r[quantity], quantity) def tryAddResidual(self, t, predicted_value, identifier): ''' Append a residual to the list of residuals. Call with a single value from a simulation and pass array of measurements for that quantity. If there is no measurement at this time point (t), do nothing.''' a = self.measurement_map[identifier] try: # if there is a measurement a this timepoint, append to list r = predicted_value - valueAtTime(a, t) self.residuals.append(r) self.quantity_residuals[identifier].append(r) # increment the residual use count (check all measurements are used exactly once) self.measurement_count[identifier] += 1 self.usage_map[identifier] = True except MissingValue: # no measurement at this timepoint, do nothing return def plotQuantity(self, identifier, bars=True): ''' Plot a simulated quantity vs its data points using Tellurium. The residuals should already be calculated.''' data = self.measurement_map[identifier] # data contains one column of time and one column of values import tellurium as te te.plot(data[:, 0], data[:, 1], scatter=True, name=identifier + ' data', show=False, error_y_pos=maximum(array(self.quantity_residuals[identifier]), 0), error_y_neg=-minimum( array(self.quantity_residuals[identifier]), 0)) # simulate and plot the model r = RoadRunner(self.sbml) s = r.simulate(0, self.timepoints[-1], 1000, ['time', identifier]) te.plot(s[:, 0], s[:, 1], name=identifier + ' sim') def MSE(self): ''' Calc the MSE for all residuals. Call this after calculating all residuals.''' r = array(self.residuals) return (r**2).mean() def simulateToNextTime(self): t_begin = self.t t_end = self.timepoints[self.next_ti] delta = t_end - t_begin stepsize = 0.1 steps = int(max(100, delta / stepsize)) self.r.simulate(t_begin, t_end, steps) return t_end def reset(self): self.r.resetAll() self.t = self.timepoints[0] # next time index self.next_ti = 0 def buildResidualList(self): # simulate to the first timepoint (not necessarily zero) delta = self.timepoints[0] stepsize = 0.1 steps = int(max(100, delta / stepsize)) self.r.simulate(0, delta, steps) self.next_ti = 1 if len(self.timepoints) < 2: raise RuntimeError('Expected at least two timepoints') # calculate the residuals self.calcResiduals(self.t) # simulate to the rest of the timepoints while self.next_ti < self.timepoints.shape[0]: self.t = self.simulateToNextTime() self.calcResiduals(self.t) self.next_ti += 1 def setParameterVector(self, x, param_list): # type: (array, List) -> None # TODO: sample in log space expect( len(x) == len(param_list), 'Wrong length for parameter vector - expected {} but got {}'. format(len(param_list), len(x))) for i, v in enumerate(x): self.r[param_list[i]] = v def evaluate(self, x): # type: (array) -> SupportsFloat """ Evaluate and return the objective function. """ self.reset() self.setParameterVector(x) try: self.buildResidualList() except RuntimeError: # if convergence fails, use a penalty score return 1e9 return self.MSE() def getUsageByQuantity(self): ''' Calculates the number of times a given quantity is used. Should be equal to the number of datap oints for that quantity if all goes well. ''' total = 0 total_used = 0 usage_for_quantity = OrderedDict() for q in self.measurement_count: a = self.measurement_map[q] used = self.measurement_count[q] usage_for_quantity[q] = used n = a.shape[0] total += n total_used += used return (total, total_used, usage_for_quantity) def printDatapointUsage(self): ''' For debugging. Make sure every data point is used.''' total, total_used, usage_for_quantity = self.getUsageByQuantity() for q, used in usage_for_quantity.keys(): a = self.measurement_map[q] n = a.shape[0] print('Usage for {}: {}/{}'.format(q, used, n)) print('*** Total usage: {}/{} ({:.1f}%)'.format( total_used, total, 100. * total_used / total))
class TimecourseSimIrreg(TimecourseSimBase): ''' Performs a timecourse simulation on an irregular grid.''' def __init__(self, sbml, data_quantities, measurement_map): ''' Constructor. :param measurement_map: A dictionary that maps the names of quantities to measurements to their respective (numpy) arrays. ''' self.sbml = sbml self.r = RoadRunner(sbml) # self.r.integrator.stiff = False # self.r.integrator.minimum_time_step = 0.0001 # self.r.integrator.maximum_time_step = 1. # self.residuals = [] #print(self.r.getFloatingSpeciesIds()) self.timepoints = unique(hstack(a[:, 0] for a in data_quantities)) self.reset() self.measurement_map = measurement_map # map a quantity to its mean measured value self.mean_measurement_map = { quantity: mean(values[:, 1]) for quantity, values in self.measurement_map.items() } # keep track of the number of times a measurement is used # (check correct number of residuals) self.measurement_count = OrderedDict( (quantity, 0) for quantity in self.measurement_map) self.penalty_scale = 1. def plotQuantity(self, identifier, param_values, bars=True): ''' Plot a simulated quantity vs its data points using Tellurium. The residuals should already be calculated.''' data = self.measurement_map[identifier] # data contains one column of time and one column of values import tellurium as te te.plot(data[:, 0], data[:, 1], scatter=True, name=identifier + ' data', show=False, error_y_pos=maximum(array(self.quantity_residuals[identifier]), 0), error_y_neg=-minimum( array(self.quantity_residuals[identifier]), 0)) # simulate and plot the model r = RoadRunner(self.sbml) if param_values is not None: self._setParameterVector(param_values, self.param_list, r) s = r.simulate(0, self.timepoints[-1], 1000, ['time', identifier]) te.plot(s[:, 0], s[:, 1], name=identifier + ' sim') def calcResiduals(self, t): ''' Try to calculate residuals at the current time t and add them to self.residuals. If they do not exist for certain datasets at time t, just pass over the dataset.''' self.usage_map = dict((q, False) for q in self.measurement_map) for quantity in self.measurement_map.keys(): self.tryAddResidual(t, self.r[quantity], quantity) def tryAddResidual(self, t, predicted_value, identifier): ''' Append a residual to the list of residuals. Call with a single value from a simulation and pass array of measurements for that quantity. If there is no measurement at this time point (t), do nothing.''' a = self.measurement_map[identifier] try: # if there is a measurement a this timepoint, append to list r = predicted_value - valueAtTime(a, t) # self.residuals.append(r) self.quantity_residuals[identifier].append(r) # increment the residual use count (check all measurements are used exactly once) self.measurement_count[identifier] += 1 self.usage_map[identifier] = True except MissingValue: # no measurement at this timepoint, do nothing return def simulateToNextTime(self): t_begin = self.t t_end = self.timepoints[self.next_ti] delta = t_end - t_begin stepsize = 0.1 steps = int(max(100, delta / stepsize)) self.r.simulate(t_begin, t_end, steps) return t_end def reset(self): self.r.resetAll() self.t = self.timepoints[0] # next time index self.next_ti = 0 def buildResidualList(self): # simulate to the first timepoint (not necessarily zero) delta = self.timepoints[0] stepsize = 0.1 steps = int(max(100, delta / stepsize)) self.r.simulate(0, delta, steps) if self.divergent(): raise RuntimeError('Diverged at first time step') self.next_ti = 1 if len(self.timepoints) < 2: raise RuntimeError('Expected at least two timepoints') # calculate the residuals self.calcResiduals(self.t) # simulate to the rest of the timepoints while self.next_ti < self.timepoints.shape[0]: self.t = self.simulateToNextTime() if self.divergent(): raise RuntimeError('Diverged at time step {}'.format( self.next_ti)) self.calcResiduals(self.t) self.next_ti += 1 def evaluate(self, x): # type: (array) -> SupportsFloat """ Evaluate and return the objective function. """ from interruptingcow import timeout self.reset() self.setParameterVector(x) self.quantity_residuals = dict( (quantity, list()) for quantity in self.measurement_map) def worker(): self.buildResidualList() if self.divergent(): return 1e9 * self.penalty_scale try: with timeout(10, StalledSimulation): worker() except (RuntimeError, StalledSimulation): # if convergence fails, use a penalty score return 1e9 * self.penalty_scale print('evaluate') # for quantity,residuals in self.quantity_residuals.items(): # print(quantity,mean(array(residuals)**2.),self.mean_measurement_map[quantity]) return sqrt(mean(array([ mean(array(residuals)**2.)/self.mean_measurement_map[quantity]**2. \ for quantity,residuals in self.quantity_residuals.items() \ ]))) def getUsageByQuantity(self): ''' Calculates the number of times a given quantity is used. Should be equal to the number of datap oints for that quantity if all goes well. ''' total = 0 total_used = 0 usage_for_quantity = OrderedDict() for q in self.measurement_count: a = self.measurement_map[q] used = self.measurement_count[q] usage_for_quantity[q] = used n = a.shape[0] total += n total_used += used return (total, total_used, usage_for_quantity) def printDatapointUsage(self): ''' For debugging. Make sure every data point is used.''' total, total_used, usage_for_quantity = self.getUsageByQuantity() for q, used in usage_for_quantity.keys(): a = self.measurement_map[q] n = a.shape[0] print('Usage for {}: {}/{}'.format(q, used, n)) print('*** Total usage: {}/{} ({:.1f}%)'.format( total_used, total, 100. * total_used / total)) def RMSE_quantity(self, identifier): ''' Calc the RMSE of a quantity.''' from math import sqrt return sqrt( float((array(self.quantity_residuals[identifier])** 2).mean())) / self.mean_measurement_map[identifier]