def create_parameter_mapping( petab_problem: petab.Problem, simulation_conditions: Union[pd.DataFrame, Dict], scaled_parameters: bool, amici_model: AmiciModel, ) -> ParameterMapping: """Generate AMICI specific parameter mapping. :param petab_problem: PEtab problem :param simulation_conditions: Result of `petab.get_simulation_conditions`. Can be provided to save time if this has been obtained before. :param scaled_parameters: If True, problem_parameters are assumed to be on the scale provided in the PEtab parameter table and will be unscaled. If False, they are assumed to be in linear scale. :param amici_model: AMICI model. :return: List of the parameter mappings. """ if simulation_conditions is None: simulation_conditions = \ petab_problem.get_simulation_conditions_from_measurement_df() # Because AMICI globalizes all local parameters during model import, # we need to do that here as well to prevent parameter mapping errors # (PEtab does currently not care about SBML LocalParameters) if petab_problem.sbml_document: converter_config = libsbml.SBMLLocalParameterConverter() \ .getDefaultProperties() petab_problem.sbml_document.convert(converter_config) else: logger.debug("No petab_problem.sbml_document is set. Cannot convert " "SBML LocalParameters. If the model contains " "LocalParameters, parameter mapping will fail.") prelim_parameter_mapping = \ petab_problem.get_optimization_to_simulation_parameter_mapping( warn_unmapped=False, scaled_parameters=scaled_parameters, allow_timepoint_specific_numeric_noise_parameters= not petab.lint.observable_table_has_nontrivial_noise_formula( petab_problem.observable_df ) ) parameter_mapping = ParameterMapping() for (_, condition), prelim_mapping_for_condition in \ zip(simulation_conditions.iterrows(), prelim_parameter_mapping): mapping_for_condition = create_parameter_mapping_for_condition( prelim_mapping_for_condition, condition, petab_problem, amici_model) parameter_mapping.append(mapping_for_condition) return parameter_mapping
def create_parameter_table(problem: petab.Problem, nominal_parameters): """Create PEtab parameter table""" df = petab.create_parameter_df(problem.sbml_model, problem.condition_df, problem.observable_df, problem.measurement_df, include_optional=True, lower_bound=1e-3, upper_bound=1e5) df['hierarchicalOptimization'] = 0 df.loc['scaling_x1_common', 'hierarchicalOptimization'] = 1 df.loc['offset_x2_batch_0', 'hierarchicalOptimization'] = 1 df.loc['offset_x2_batch_1', 'hierarchicalOptimization'] = 1 df.loc['x1withsigma_sigma', 'hierarchicalOptimization'] = 1 for pid, val in nominal_parameters.items(): if pid in df.index: df.loc[pid, ptc.NOMINAL_VALUE] = val df.loc[pid, ptc.PARAMETER_SCALE] = ptc.LOG10 df.loc[pid, ptc.ESTIMATE] = 1 elif pid.startswith('noiseParameter') \ or pid.startswith('observableParameter'): continue else: print("extra parameter", pid, val) # offsets can be negative: adapt scaling and bounds: offsets = df.index.str.startswith('offset_') df.loc[offsets, ptc.PARAMETER_SCALE] = ptc.LIN problem.parameter_df = df
def create_parameter_table(problem: petab.Problem, parameter_file, nominal_parameters): """Create PEtab parameter table""" df = problem.create_parameter_df(lower_bound=-3, upper_bound=5) # TODO: move to peTAB df['hierarchicalOptimization'] = 0 df.loc['scaling_x1_common', 'hierarchicalOptimization'] = 1 df.loc['offset_x2_batch-0', 'hierarchicalOptimization'] = 1 df.loc['offset_x2_batch-1', 'hierarchicalOptimization'] = 1 df.loc['x1withsigma_sigma', 'hierarchicalOptimization'] = 1 #df.parameterScale = 'lin' #df.estimate = 0 print(nominal_parameters) for pid, val in nominal_parameters.items(): if pid in df.index: df.loc[pid, 'nominalValue'] = val df.loc[pid, 'parameterScale'] = 'log10' df.loc[pid, 'estimate'] = 1 elif pid.startswith('noiseParameter') \ or pid.startswith('observableParameter'): continue else: print("extra parameter", pid, val) # offsets can be negative: adapt scaling and bounds: offsets = df.index.str.startswith('offset_') df.loc[offsets, 'parameterScale'] = 'lin' df.loc[offsets, 'lowerBound'] = np.power(10.0, df.loc[offsets, 'lowerBound']) df.loc[offsets, 'upperBound'] = np.power(10.0, df.loc[offsets, 'upperBound']) problem.parameter_df = df df.to_csv(parameter_file, sep="\t", index=True)
def get_summary( petab_problem: petab.Problem, petab_problem_id: str = None, ) -> Dict: """Get dictionary with stats for the given PEtab problem""" return { 'petab_problem_id': petab_problem_id, 'conditions': petab_problem.get_simulation_conditions_from_measurement_df().shape[0], 'estimated_parameters': np.sum(petab_problem.parameter_df[petab.ESTIMATE]), 'events': len(petab_problem.sbml_model.getListOfEvents()), 'measurements': len(petab_problem.measurement_df.index), 'observables': len(petab_problem.measurement_df[petab.OBSERVABLE_ID].unique()), 'species': len(petab_problem.sbml_model.getListOfSpecies()), 'reference_uris': get_reference_uris(petab_problem.sbml_model), }
def create_edatas( amici_model: AmiciModel, petab_problem: petab.Problem, simulation_conditions: Union[pd.DataFrame, Dict] = None, ) -> List[amici.ExpData]: """Create list of :class:`amici.amici.ExpData` objects for PEtab problem. :param amici_model: AMICI model. :param petab_problem: Underlying PEtab problem. :param simulation_conditions: Result of `petab.get_simulation_conditions`. Can be provided to save time if this has be obtained before. :return: List with one :class:`amici.amici.ExpData` per simulation condition, with filled in timepoints and data. """ if simulation_conditions is None: simulation_conditions = \ petab_problem.get_simulation_conditions_from_measurement_df() observable_ids = amici_model.getObservableIds() edatas = [] for _, condition in simulation_conditions.iterrows(): # Create amici.ExpData for each simulation edata = create_edata_for_condition( condition=condition, amici_model=amici_model, petab_problem=petab_problem, observable_ids=observable_ids, ) edatas.append(edata) return edatas
def simulate_petab( petab_problem: petab.Problem, amici_model: AmiciModel, solver: Optional[amici.Solver] = None, problem_parameters: Optional[Dict[str, float]] = None, simulation_conditions: Union[pd.DataFrame, Dict] = None, edatas: List[AmiciExpData] = None, parameter_mapping: ParameterMapping = None, scaled_parameters: Optional[bool] = False, log_level: int = logging.WARNING ) -> Dict[str, Any]: """Simulate PEtab model. :param petab_problem: PEtab problem to work on. :param amici_model: AMICI Model assumed to be compatible with ``petab_problem``. :param solver: An AMICI solver. Will use default options if None. :param problem_parameters: Run simulation with these parameters. If None, PEtab `nominalValues` will be used). To be provided as dict, mapping PEtab problem parameters to SBML IDs. :param simulation_conditions: Result of `petab.get_simulation_conditions`. Can be provided to save time if this has be obtained before. Not required if `edatas` and `parameter_mapping` are provided. :param edatas: Experimental data. Parameters are inserted in-place for simulation. :param parameter_mapping: Optional precomputed PEtab parameter mapping for efficiency, as generated by `create_parameter_mapping`. :param scaled_parameters: If True, problem_parameters are assumed to be on the scale provided in the PEtab parameter table and will be unscaled. If False, they are assumed to be in linear scale. :param log_level: Log level, see :mod:`amici.logging` module. :return: Dictionary of * cost function value (LLH), * const function sensitivity w.r.t. parameters (SLLH), (**NOTE**: Sensitivities are computed for the scaled parameters) * list of `ReturnData` (RDATAS), corresponding to the different simulation conditions. For ordering of simulation conditions, see :meth:`petab.Problem.get_simulation_conditions_from_measurement_df`. """ logger.setLevel(log_level) if solver is None: solver = amici_model.getSolver() # Get parameters if problem_parameters is None: # Use PEtab nominal values as default problem_parameters = {t.Index: getattr(t, NOMINAL_VALUE) for t in petab_problem.parameter_df.itertuples()} scaled_parameters = False # number of amici simulations will be number of unique # (preequilibrationConditionId, simulationConditionId) pairs. # Can be optimized by checking for identical condition vectors. if simulation_conditions is None and parameter_mapping is None \ and edatas is None: simulation_conditions = \ petab_problem.get_simulation_conditions_from_measurement_df() # Get parameter mapping if parameter_mapping is None: parameter_mapping = create_parameter_mapping( petab_problem=petab_problem, simulation_conditions=simulation_conditions, scaled_parameters=scaled_parameters, amici_model=amici_model) # Get edatas if edatas is None: # Generate ExpData with all condition-specific information edatas = create_edatas( amici_model=amici_model, petab_problem=petab_problem, simulation_conditions=simulation_conditions) # Fill parameters in ExpDatas (in-place) fill_in_parameters( edatas=edatas, problem_parameters=problem_parameters, scaled_parameters=scaled_parameters, parameter_mapping=parameter_mapping, amici_model=amici_model) # Simulate rdatas = amici.runAmiciSimulations(amici_model, solver, edata_list=edatas) # Compute total llh llh = sum(rdata['llh'] for rdata in rdatas) # Compute total sllh sllh = aggregate_sllh(amici_model=amici_model, rdatas=rdatas, parameter_mapping=parameter_mapping) # Log results sim_cond = petab_problem.get_simulation_conditions_from_measurement_df() for i, rdata in enumerate(rdatas): logger.debug(f"Condition: {sim_cond.iloc[i, :].values}, status: " f"{rdata['status']}, llh: {rdata['llh']}") return { LLH: llh, SLLH: sllh, RDATAS: rdatas }
def create_parameterized_edatas( amici_model: AmiciModel, petab_problem: petab.Problem, problem_parameters: Dict[str, numbers.Number], scaled_parameters: bool = False, parameter_mapping: ParameterMapping = None, simulation_conditions: Union[pd.DataFrame, Dict] = None, ) -> List[amici.ExpData]: """Create list of :class:amici.ExpData objects with parameters filled in. :param amici_model: AMICI Model assumed to be compatible with ``petab_problem``. :param petab_problem: PEtab problem to work on. :param problem_parameters: Run simulation with these parameters. If None, PEtab `nominalValues` will be used). To be provided as dict, mapping PEtab problem parameters to SBML IDs. :param scaled_parameters: If True, problem_parameters are assumed to be on the scale provided in the PEtab parameter table and will be unscaled. If False, they are assumed to be in linear scale. :param parameter_mapping: Optional precomputed PEtab parameter mapping for efficiency, as generated by `create_parameter_mapping`. :param simulation_conditions: Result of `petab.get_simulation_conditions`. Can be provided to save time if this has been obtained before. :return: List with one :class:`amici.amici.ExpData` per simulation condition, with filled in timepoints, data and parameters. """ # number of amici simulations will be number of unique # (preequilibrationConditionId, simulationConditionId) pairs. # Can be optimized by checking for identical condition vectors. if simulation_conditions is None: simulation_conditions = \ petab_problem.get_simulation_conditions_from_measurement_df() # Get parameter mapping if parameter_mapping is None: parameter_mapping = create_parameter_mapping( petab_problem=petab_problem, simulation_conditions=simulation_conditions, scaled_parameters=scaled_parameters, amici_model=amici_model) # Generate ExpData with all condition-specific information edatas = create_edatas( amici_model=amici_model, petab_problem=petab_problem, simulation_conditions=simulation_conditions) # Fill parameters in ExpDatas (in-place) fill_in_parameters( edatas=edatas, problem_parameters=problem_parameters, scaled_parameters=scaled_parameters, parameter_mapping=parameter_mapping, amici_model=amici_model) return edatas
def subset_petab_problem( petab_problem: petab.Problem, timecourse_id: str, ) -> Sequence[petab.Problem]: petab_problem = deepcopy(petab_problem) petab_problem.observable_df.loc[DUMMY_OBSERVABLE_ID] = \ { OBSERVABLE_FORMULA: DUMMY_MEASUREMENT, NOISE_FORMULA: DUMMY_NOISE, } # TODO allow no specification of timecourse if only one timecourse in # problem. TODO raise error if multiple timecourses but no timecourse ID # specified petab_problem.measurement_df = petab_problem.measurement_df[ petab_problem.measurement_df[SIMULATION_CONDITION_ID] == timecourse_id] timecourse = parse_timecourse_string( petab_problem.timecourse_df.loc[timecourse_id][TIMECOURSE], ) # FIXME timepoints not necessarily float timecourse = [(float(_t), _id) for _t, _id in timecourse] petab_problems = [] for index, (timepoint, condition_id) in enumerate(timecourse): petab_problems.append(deepcopy(petab_problem)) petab_problems[-1].condition_df.loc[timecourse_id] = \ petab_problems[-1].condition_df.loc[condition_id] # Drop other conditions # FIXME test how this affects other conditions or how to combine normal conditions + timecourses... # or only allow timecourses? petab_problems[-1].condition_df = ( petab_problems[-1].condition_df.loc[[timecourse_id]]) petab_problems[-1].measurement_df = \ petab_problems[-1].measurement_df[ petab_problems[-1].measurement_df[TIME].astype(float) >= timepoint ] if index < len(timecourse) - 1: next_timepoint = timecourse[index + 1][0] petab_problems[-1].measurement_df = \ petab_problems[-1].measurement_df[ petab_problems[-1].measurement_df[TIME].astype(float) <= next_timepoint ] # Add dummy data to ensure endpoint is outputted. petab_problems[-1].measurement_df = \ petab_problems[-1].measurement_df.append( { OBSERVABLE_ID: DUMMY_OBSERVABLE_ID, SIMULATION_CONDITION_ID: timecourse_id, TIME: next_timepoint, MEASUREMENT: DUMMY_MEASUREMENT, }, ignore_index=True, ) # Remove condition parameters from the parameters table. condition_components = [ c for c in petab_problems[-1].condition_df.loc[timecourse_id].index if c not in NON_COMPONENT_CONDITION_LABELS ] petab_problems[-1].parameter_df.drop( condition_components, inplace=True, errors='ignore', # only parameters that are in the table are dropped ) #for t in [timepoint, next_timepoint]: # if not any( # t == petab_problems[-1].measurement_df[TIME].astype(float) # ): # # FIXME add dummy data # print(t) # breakpoint() # pass return petab_problems
def simulate_timecourse_objective( parent_petab_problem: petab.Problem, timecourse_id: str, problem_parameters: Dict[str, float], parameter_mapping, sensi_orders: Tuple[int, ...] = (0, ), return_all: bool = False, max_abs_grad: float = None, **kwargs, ): #unscaled_problem_parameters = unscale_parameters( # scaled_parameters=problem_parameters, # petab_problem=parent_petab_problem, #) unscaled_problem_parameters = parent_petab_problem.unscale_parameters( scaled_parameters=problem_parameters, ) #print('in') results = simulate_timecourse( parent_petab_problem, timecourse_id, problem_parameters=unscaled_problem_parameters, parameter_mapping=parameter_mapping, sensi_orders=sensi_orders, **kwargs, ) #print('out') if kwargs.get('initial_states', None) is not None: pass #breakpoint() #sensitivity_parameter_ids = results[0]['sllh'].keys() sensitivity_parameter_ids = problem_parameters.keys() #print('l1') #print(problem_parameters) #breakpoint() #sensitivity_parameter_ids = parent_petab_problem.x_ids for result in results: if result['sllh'].keys() != sensitivity_parameter_ids: # FIXME reimplement so this still holds? #raise NotImplementedError( # 'All conditions must provide sensitivities for the same set ' # 'of parameters.' #) pass #print('l2') accumulated_result = { FVAL: sum(-result['llh'] for result in results), GRAD: [ sum(-result['sllh'][k] for result in results if k in result['sllh']) for k in sensitivity_parameter_ids #if k in result['sllh'] ] #GRAD: { # k: sum(-result['sllh'][k] for result in results) # for k in sensitivity_parameter_ids #} } #print('l3') if return_all: # TODO magic constant accumulated_result[FINAL_STATES] = \ one(results[-1]['rdatas']).x[-1].flatten() #accumulated_result[RESULTS] = results #print('l4') #print(accumulated_result) #print(accumulated_result) #breakpoint() #print(accumulated_result) if max_abs_grad is not None: pass #accumulated_result[GRAD] = list(np.nan_to_num( # np.array(accumulated_result[GRAD]), # nan=np.nan, # posinf=max_abs_grad, # neginf=-max_abs_grad, #)) #print(accumulated_result) return accumulated_result
def filter_observables(petab_problem: petab.Problem): petab_problem.measurement_df = petab_problem.measurement_df.loc[ petab_problem.measurement_df[petab.OBSERVABLE_ID].apply( lambda x: x in petab_problem.observable_df.index ), : ]