def test_get_simulation_conditions(): """Test get_simulation_conditions""" # only simulation condition measurement_df = pd.DataFrame(data={ SIMULATION_CONDITION_ID: ['c0', 'c1', 'c0', 'c1'], }) expected = pd.DataFrame(data={ SIMULATION_CONDITION_ID: ['c0', 'c1'], }) actual = petab.get_simulation_conditions(measurement_df) assert actual.equals(expected) # simulation and preequilibration condition measurement_df = pd.DataFrame( data={ SIMULATION_CONDITION_ID: ['c0', 'c1', 'c0', 'c1'], PREEQUILIBRATION_CONDITION_ID: ['c1', 'c0', 'c1', 'c0'], }) expected = pd.DataFrame( data={ SIMULATION_CONDITION_ID: ['c0', 'c1'], PREEQUILIBRATION_CONDITION_ID: ['c1', 'c0'], }) actual = petab.get_simulation_conditions(measurement_df) assert actual.equals(expected) # simulation with and without preequilibration measurement_df = pd.DataFrame( data={ SIMULATION_CONDITION_ID: ['c0', 'c1', 'c0', 'c1'], PREEQUILIBRATION_CONDITION_ID: ['', '', 'c1', 'c0'], }) expected = pd.DataFrame( data={ SIMULATION_CONDITION_ID: ['c0', 'c1', 'c0', 'c1'], PREEQUILIBRATION_CONDITION_ID: ['', '', 'c1', 'c0'], }).sort_values( [SIMULATION_CONDITION_ID, PREEQUILIBRATION_CONDITION_ID], ignore_index=True) actual = petab.get_simulation_conditions(measurement_df) assert actual.equals(expected) # simulation with and without preequilibration; NaNs measurement_df = pd.DataFrame( data={ SIMULATION_CONDITION_ID: ['c0', 'c1', 'c0', 'c1'], PREEQUILIBRATION_CONDITION_ID: [np.nan, np.nan, 'c1', 'c0'], }) expected = pd.DataFrame( data={ SIMULATION_CONDITION_ID: ['c0', 'c1', 'c0', 'c1'], PREEQUILIBRATION_CONDITION_ID: ['', '', 'c1', 'c0'], }).sort_values( [SIMULATION_CONDITION_ID, PREEQUILIBRATION_CONDITION_ID], ignore_index=True) actual = petab.get_simulation_conditions(measurement_df) assert actual.equals(expected)
def rdatas_to_measurement_df(rdatas: Sequence[amici.ReturnData], model: AmiciModel, measurement_df: pd.DataFrame) -> pd.DataFrame: """ Create a measurement dataframe in the PEtab format from the passed `rdatas` and own information. :param rdatas: A sequence of rdatas with the ordering of `petab.get_simulation_conditions`. :param model: AMICI model used to generate `rdatas`. :param measurement_df: PEtab measurement table used to generate `rdatas`. :return: A dataframe built from the rdatas in the format of `measurement_df`. """ df = pd.DataFrame(columns=list(measurement_df.columns)) simulation_conditions = petab.get_simulation_conditions(measurement_df) observable_ids = model.getObservableIds() # iterate over conditions for (_, condition), rdata in zip(simulation_conditions.iterrows(), rdatas): # current simulation matrix y = rdata['y'] # time array used in rdata t = list(rdata['t']) # extract rows for condition cur_measurement_df = petab.get_rows_for_condition( measurement_df, condition) # iterate over entries for the given condition # note: this way we only generate a dataframe entry for every # row that existed in the original dataframe. if we want to # e.g. have also timepoints non-existent in the original file, # we need to instead iterate over the rdata['y'] entries for _, row in cur_measurement_df.iterrows(): # copy row row_sim = copy.deepcopy(row) # extract simulated measurement value timepoint_idx = t.index(row[TIME]) observable_idx = observable_ids.index(row[OBSERVABLE_ID]) measurement_sim = y[timepoint_idx, observable_idx] # change measurement entry row_sim[MEASUREMENT] = measurement_sim # append to dataframe df = df.append(row_sim, ignore_index=True) return df
def create_objective( self, model: 'amici.Model' = None, solver: 'amici.Solver' = None, edatas: Sequence['amici.ExpData'] = None, force_compile: bool = False ) -> 'PetabAmiciObjective': """ Create a pypesto.PetabAmiciObjective. """ # get simulation conditions simulation_conditions = petab.get_simulation_conditions( self.petab_problem.measurement_df) # create model if model is None: model = self.create_model(force_compile=force_compile) # create solver if solver is None: solver = self.create_solver(model) # create conditions and edatas from measurement data if edatas is None: edatas = self.create_edatas( model=model, simulation_conditions=simulation_conditions) parameter_mapping = amici.petab_objective.create_parameter_mapping( petab_problem=self.petab_problem, simulation_conditions=simulation_conditions, scaled_parameters=True, amici_model=model) par_ids = self.petab_problem.x_ids # fill in dummy parameters (this is needed since some objective # initialization e.g. checks for preeq parameters) problem_parameters = {key: val for key, val in zip( self.petab_problem.x_ids, self.petab_problem.x_nominal_scaled)} amici.parameter_mapping.fill_in_parameters( edatas=edatas, problem_parameters=problem_parameters, scaled_parameters=True, parameter_mapping=parameter_mapping, amici_model=model) # create objective obj = PetabAmiciObjective( petab_importer=self, amici_model=model, amici_solver=solver, edatas=edatas, x_ids=par_ids, x_names=par_ids, parameter_mapping=parameter_mapping) return obj
def rdatas_to_measurement_df(self, rdatas, model=None): """ Create a measurement dataframe in the petab format from the passed `rdatas` and own information. Parameters ---------- rdatas: list of amici.RData A list of rdatas as produced by pypesto.AmiciObjective.__call__(x, return_dict=True)['rdatas']. Returns ------- df: pandas.DataFrame A dataframe built from the rdatas in the format as in self.petab_problem.measurement_df. """ # create model if model is None: model = self.create_model() measurement_df = self.petab_problem.measurement_df # initialize dataframe df = pd.DataFrame( columns=list(self.petab_problem.measurement_df.columns)) # get simulation conditions simulation_conditions = petab.get_simulation_conditions(measurement_df) # get observable ids observable_ids = model.getObservableIds() # iterate over conditions for data_idx, condition in simulation_conditions.iterrows(): # current rdata rdata = rdatas[data_idx] # current simulation matrix y = rdata['y'] # time array used in rdata t = list(rdata['t']) # extract rows for condition cur_measurement_df = petab.get_rows_for_condition( measurement_df, condition) # iterate over entries for the given condition # note: this way we only generate a dataframe entry for every # row that existed in the original dataframe. if we want to # e.g. have also timepoints non-existent in the original file, # we need to instead iterate over the rdata['y'] entries for _, row in cur_measurement_df.iterrows(): # copy row row_sim = copy.deepcopy(row) # extract simulated measurement value timepoint_idx = t.index(row.time) observable_idx = observable_ids.index("observable_" + row.observableId) measurement_sim = y[timepoint_idx, observable_idx] # change measurement entry row_sim.measurement = measurement_sim # append to dataframe df = df.append(row_sim, ignore_index=True) return df
def create_objective(self, model=None, solver=None, edatas=None, force_compile: bool = False): """ Create a pypesto.PetabAmiciObjective. """ # get simulation conditions simulation_conditions = petab.get_simulation_conditions( self.petab_problem.measurement_df) # create model if model is None: model = self.create_model(force_compile=force_compile) # create solver if solver is None: solver = self.create_solver(model) # create conditions and edatas from measurement data if edatas is None: edatas = self.create_edatas( model=model, simulation_conditions=simulation_conditions) # simulation <-> optimization parameter mapping par_opt_ids = self.petab_problem.get_optimization_parameters() parameter_mappings = \ petab.get_optimization_to_simulation_parameter_mapping( condition_df=self.petab_problem.condition_df, measurement_df=self.petab_problem.measurement_df, parameter_df=self.petab_problem.parameter_df, sbml_model=self.petab_problem.sbml_model, simulation_conditions=simulation_conditions, ) scale_mappings = \ petab.get_optimization_to_simulation_scale_mapping( parameter_df=self.petab_problem.parameter_df, mapping_par_opt_to_par_sim=parameter_mappings, measurement_df=self.petab_problem.measurement_df ) # unify and check preeq and sim mappings parameter_mapping, scale_mapping = _merge_preeq_and_sim_pars( parameter_mappings, scale_mappings) # simulation ids (for correct order) par_sim_ids = list(model.getParameterIds()) # create lists from dicts in correct order parameter_mapping = _mapping_to_list(parameter_mapping, par_sim_ids) scale_mapping = _mapping_to_list(scale_mapping, par_sim_ids) # check whether there is something suspicious in the mapping _check_parameter_mapping_ok(parameter_mapping, par_sim_ids, model, edatas) # create objective obj = PetabAmiciObjective(petab_importer=self, amici_model=model, amici_solver=solver, edatas=edatas, x_ids=par_opt_ids, x_names=par_opt_ids, mapping_par_opt_to_par_sim=parameter_mapping, mapping_scale_opt_to_scale_sim=scale_mapping) return obj
def create_edatas(self, model=None, simulation_conditions=None): """ Create list of amici.ExpData objects. """ # create model if model is None: model = self.create_model() condition_df = self.petab_problem.condition_df.reset_index() measurement_df = self.petab_problem.measurement_df # number of amici simulations will be number of unique # (preequilibrationConditionId, simulationConditionId) pairs. # Can be improved by checking for identical condition vectors. if simulation_conditions is None: simulation_conditions = petab.get_simulation_conditions( measurement_df) observable_ids = model.getObservableIds() fixed_parameter_ids = model.getFixedParameterIds() edatas = [] for _, condition in simulation_conditions.iterrows(): # amici.ExpData for each simulation # extract rows for condition df_for_condition = petab.get_rows_for_condition( measurement_df, condition) # make list of all timepoints for which measurements exist timepoints = sorted(df_for_condition.time.unique().astype(float)) # init edata object edata = amici.ExpData(model.get()) # find rep numbers of time points timepoints_w_reps = [] for time in timepoints: # subselect for time df_for_time = df_for_condition[df_for_condition.time == time] # rep number is maximum over rep numbers for observables n_reps = max( df_for_time.groupby(['observableId', 'time']).size()) # append time point n_rep times timepoints_w_reps.extend([time] * n_reps) # set time points in edata edata.setTimepoints(timepoints_w_reps) # handle fixed parameters _handle_fixed_parameters(edata, condition_df, fixed_parameter_ids, condition) # prepare measurement matrix y = np.full(shape=(edata.nt(), edata.nytrue()), fill_value=np.nan) # prepare sigma matrix sigma_y = np.full(shape=(edata.nt(), edata.nytrue()), fill_value=np.nan) # add measurements and sigmas # iterate over time points for time in timepoints: # subselect for time df_for_time = df_for_condition[df_for_condition.time == time] time_ix_0 = timepoints_w_reps.index(time) # remember used time indices for each observable time_ix_for_obs_ix = {} # iterate over measurements for _, measurement in df_for_time.iterrows(): # extract observable index observable_ix = observable_ids.index( f'observable_{measurement.observableId}') # update time index for observable if observable_ix in time_ix_for_obs_ix: time_ix_for_obs_ix[observable_ix] += 1 else: time_ix_for_obs_ix[observable_ix] = time_ix_0 # fill observable and possibly noise parameter y[time_ix_for_obs_ix[observable_ix], observable_ix] = measurement.measurement if isinstance(measurement.noiseParameters, numbers.Number): sigma_y[time_ix_for_obs_ix[observable_ix], observable_ix] = measurement.noiseParameters # fill measurements and sigmas into edata edata.setObservedData(y.flatten()) edata.setObservedDataStdDev(sigma_y.flatten()) # append edata to edatas list edatas.append(edata) return edatas
def create_objective(self, model: 'amici.Model' = None, solver: 'amici.Solver' = None, edatas: Sequence['amici.ExpData'] = None, force_compile: bool = False, **kwargs) -> AmiciObjective: """Create a :class:`pypesto.AmiciObjective`. Parameters ---------- model: The AMICI model. solver: The AMICI solver. edatas: The experimental data in AMICI format. force_compile: Whether to force-compile the model if not passed. **kwargs: Additional arguments passed on to the objective. Returns ------- objective: A :class:`pypesto.AmiciObjective` for the model and the data. """ # get simulation conditions simulation_conditions = petab.get_simulation_conditions( self.petab_problem.measurement_df) # create model if model is None: model = self.create_model(force_compile=force_compile) # create solver if solver is None: solver = self.create_solver(model) # create conditions and edatas from measurement data if edatas is None: edatas = self.create_edatas( model=model, simulation_conditions=simulation_conditions) parameter_mapping = amici.petab_objective.create_parameter_mapping( petab_problem=self.petab_problem, simulation_conditions=simulation_conditions, scaled_parameters=True, amici_model=model) par_ids = self.petab_problem.x_ids # fill in dummy parameters (this is needed since some objective # initialization e.g. checks for preeq parameters) problem_parameters = { key: val for key, val in zip(self.petab_problem.x_ids, self.petab_problem.x_nominal_scaled) } amici.parameter_mapping.fill_in_parameters( edatas=edatas, problem_parameters=problem_parameters, scaled_parameters=True, parameter_mapping=parameter_mapping, amici_model=model) # create objective obj = AmiciObjective(amici_model=model, amici_solver=solver, edatas=edatas, x_ids=par_ids, x_names=par_ids, parameter_mapping=parameter_mapping, amici_object_builder=self, **kwargs) return obj