示例#1
0
                def _set_initial_concentration(condition_id, species_id,
                                               init_par_id,
                                               par_map, scale_map):
                    value = petab.to_float_if_float(
                        self.petab_problem.condition_df.loc[
                            condition_id, species_id])
                    if isinstance(value, float):
                        # numeric initial state
                        par_map[init_par_id] = value
                        scale_map[init_par_id] = ptc.LIN
                    else:
                        # parametric initial state
                        try:
                            # try find in mapping
                            par_map[init_par_id] = par_map[value]
                            scale_map[init_par_id] = scale_map[value]
                        except KeyError:
                            # otherwise look up in parameter table
                            if (self.petab_problem.parameter_df.loc[
                                        value, ptc.ESTIMATE] == 0):
                                par_map[init_par_id] = \
                                    self.petab_problem.parameter_df.loc[
                                        value, ptc.NOMINAL_VALUE]
                            else:
                                par_map[init_par_id] = value

                            if (ptc.PARAMETER_SCALE
                                    not in self.petab_problem.parameter_df
                                    or not self.petab_problem.parameter_df.loc[
                                        value, ptc.PARAMETER_SCALE]):
                                scale_map[init_par_id] = ptc.LIN
                            else:
                                scale_map[init_par_id] = \
                                    self.petab_problem.parameter_df.loc[
                                        value, ptc.PARAMETER_SCALE]
示例#2
0
    def write_measurements(self):
        """
        Write measurements to hdf5 dataset
        """

        # create inverse mapping for faster lookup
        observable_id_to_index = {
            name: idx for idx, name in enumerate(self.observable_ids)}

        measurement_df = self.petab_problem.measurement_df
        if ptc.NOISE_PARAMETERS not in measurement_df:
            measurement_df[ptc.NOISE_PARAMETERS] = np.nan

        for sim_idx, (preeq_cond_idx, sim_cond_idx) \
                in enumerate(self.condition_map):
            # print("Condition", sim_idx, (preeq_cond_idx, sim_cond_idx))

            cur_mes_df = self._get_measurements_for_condition(
                sim_idx, preeq_cond_idx, sim_cond_idx)

            # get the required, possibly non-unique (replicates) timepoints
            grp = cur_mes_df.groupby([ptc.OBSERVABLE_ID, ptc.TIME]).size() \
                .reset_index().rename(columns={0: 'sum'}) \
                .groupby([ptc.TIME])['sum'].agg(['max']).reset_index()

            timepoints = np.sort(np.repeat(grp[ptc.TIME], grp['max'])).tolist()
            mes = np.full(shape=(len(timepoints), self.ny), fill_value=np.nan)
            sd = mes.copy()

            # write measurements from each row in measurementDf
            for index, row in cur_mes_df.iterrows():
                observable_idx = observable_id_to_index[row[ptc.OBSERVABLE_ID]]
                time_idx = timepoints.index(row.time)
                while not np.isnan(mes[time_idx, observable_idx]):
                    time_idx += 1
                    if timepoints[time_idx] != row.time:
                        raise AssertionError(
                            "Replicate handling failed for "
                            f'{row[ptc.SIMULATION_CONDITION_ID]} - '
                            f'{row[ptc.OBSERVABLE_ID]}'
                            f' time {row[ptc.TIME]}\n' + str(cur_mes_df))
                mes[time_idx, observable_idx] = float(row[ptc.MEASUREMENT])
                sigma = to_float_if_float(row[ptc.NOISE_PARAMETERS])
                if isinstance(sigma, float):
                    sd[time_idx, observable_idx] = sigma

            # write to file
            g = self.f.require_group("measurements")
            g.create_dataset(name=f"y/{sim_idx}", data=mes, dtype='f8',
                             compression=self.compression)
            g.create_dataset(name=f"ysigma/{sim_idx}", data=sd, dtype='f8',
                             compression=self.compression)
            g.create_dataset(name=f"t/{sim_idx}", data=timepoints, dtype='f8',
                             compression=self.compression)
示例#3
0
 def _set_initial_concentration(condition_id, species_id, init_par_id,
                                par_map, scale_map):
     value = petab.to_float_if_float(
         petab_problem.condition_df.loc[condition_id, species_id])
     par_map[init_par_id] = value
     if isinstance(value, float):
         # numeric initial state
         scale_map[init_par_id] = petab.LIN
     else:
         # parametric initial state
         scale_map[init_par_id] = petab_problem.parameter_df.loc[
             value, PARAMETER_SCALE]
示例#4
0
 def _set_initial_concentration(condition_id, species_id, init_par_id,
                                par_map, scale_map):
     value = petab.to_float_if_float(
         petab_problem.condition_df.loc[condition_id, species_id])
     if pd.isna(value):
         value = float(
             get_species_initial(
                 petab_problem.sbml_model.getSpecies(species_id)))
         logger.debug(
             f'The species {species_id} has no initial value '
             f'defined for the condition {condition_id} in '
             'the PEtab conditions table. The initial value is '
             f'now set to {value}, which is the initial value '
             'defined in the SBML model.')
     par_map[init_par_id] = value
     if isinstance(value, float):
         # numeric initial state
         scale_map[init_par_id] = petab.LIN
     else:
         # parametric initial state
         scale_map[init_par_id] = petab_problem.parameter_df.loc[
             value, PARAMETER_SCALE]
示例#5
0
    def _generate_simulation_to_optimization_parameter_mapping(self) -> None:
        """
        Create dataset n_parameters_simulation x n_conditions with indices of
        respective parameters in parameters_optimization
        """

        # get list of tuple of parameters dicts for all conditions
        self.parameter_mapping = self.petab_problem \
            .get_optimization_to_simulation_parameter_mapping(
                warn_unmapped=False, scaled_parameters=False)

        variable_par_ids = self.amici_model.getParameterIds()
        fixed_par_ids = self.amici_model.getFixedParameterIds()

        # Translate parameter ID mapping to index mapping
        # create inverse mapping for faster lookup
        print(self.problem_parameter_ids)
        optimization_parameter_name_to_index = {
            name: idx for idx, name in enumerate(self.problem_parameter_ids)}
        self.optimization_parameter_name_to_index = \
            optimization_parameter_name_to_index

        # use in-memory matrix, don't write every entry to file directly
        num_model_parameters = self.amici_model.np()
        mapping_matrix = np.zeros(
            shape=(num_model_parameters, self.condition_map.shape[0]),
            dtype='<i4')
        override_matrix = np.full(shape=mapping_matrix.shape,
                                  fill_value=np.nan)
        pscale_matrix = np.full(shape=mapping_matrix.shape, dtype='<i4',
                                fill_value=amici.ParameterScaling_none)

        # AMICI fixed parameters
        self.nk = len(fixed_par_ids)
        print(Fore.CYAN + "Number of fixed parameters:",
              len(fixed_par_ids))
        # TODO: can fixed parameter differ between same condition vector used
        #  in different sim x preeq combinations?
        fixed_parameter_matrix = np.full(
            shape=(self.nk, self.num_condition_vectors),
            fill_value=np.nan)

        # For handling initial states
        species_in_condition_table = [
            col for col in self.petab_problem.condition_df
            if self.petab_problem.sbml_model.getSpecies(col) is not None]

        # Merge and preeq and sim parameters, filter fixed parameters
        for condition_idx, \
            (condition_map_preeq, condition_map_sim,
             condition_scale_map_preeq, condition_scale_map_sim) \
                in enumerate(self.parameter_mapping):

            preeq_cond_idx, sim_cond_idx = self.condition_map[condition_idx]
            preeq_cond_id = self.condition_ids[preeq_cond_idx] \
                if preeq_cond_idx != NO_PREEQ_CONDITION_IDX else None
            sim_cond_id = self.condition_ids[sim_cond_idx]
            print(preeq_cond_idx, preeq_cond_id, sim_cond_idx, sim_cond_id)

            if len(condition_map_preeq) != len(condition_scale_map_preeq) \
                    or len(condition_map_sim) != len(condition_scale_map_sim):
                raise AssertionError(
                    "Number of parameters and number of parameter "
                    "scales do not match.")
            if len(condition_map_preeq) \
                    and len(condition_map_preeq) != len(condition_map_sim):
                # logger.debug(
                #     f"Preequilibration parameter map: {condition_map_preeq}")
                # logger.debug(f"Simulation parameter map: {condition_map_sim}")
                raise AssertionError(
                    "Number of parameters for preequilibration "
                    "and simulation do not match.")

            # TODO: requires special handling of initial concentrations
            if species_in_condition_table:
                # set indicator fixed parameter for preeq
                # (we expect here, that this parameter was added during AMICI
                # model import and that it was not added by the user with a
                # different meaning...)
                if preeq_cond_idx != NO_PREEQ_CONDITION_IDX:
                    condition_map_preeq[PREEQ_INDICATOR_ID] = 1.0
                    condition_scale_map_preeq[PREEQ_INDICATOR_ID] = ptc.LIN

                condition_map_sim[PREEQ_INDICATOR_ID] = 0.0
                condition_scale_map_sim[PREEQ_INDICATOR_ID] = ptc.LIN

                def _set_initial_concentration(condition_id, species_id,
                                               init_par_id,
                                               par_map, scale_map):
                    value = petab.to_float_if_float(
                        self.petab_problem.condition_df.loc[
                            condition_id, species_id])
                    if isinstance(value, float):
                        # numeric initial state
                        par_map[init_par_id] = value
                        scale_map[init_par_id] = ptc.LIN
                    else:
                        # parametric initial state
                        try:
                            # try find in mapping
                            par_map[init_par_id] = par_map[value]
                            scale_map[init_par_id] = scale_map[value]
                        except KeyError:
                            # otherwise look up in parameter table
                            if (self.petab_problem.parameter_df.loc[
                                        value, ptc.ESTIMATE] == 0):
                                par_map[init_par_id] = \
                                    self.petab_problem.parameter_df.loc[
                                        value, ptc.NOMINAL_VALUE]
                            else:
                                par_map[init_par_id] = value

                            if (ptc.PARAMETER_SCALE
                                    not in self.petab_problem.parameter_df
                                    or not self.petab_problem.parameter_df.loc[
                                        value, ptc.PARAMETER_SCALE]):
                                scale_map[init_par_id] = ptc.LIN
                            else:
                                scale_map[init_par_id] = \
                                    self.petab_problem.parameter_df.loc[
                                        value, ptc.PARAMETER_SCALE]

                for species_id in species_in_condition_table:
                    # for preequilibration
                    init_par_id = f'initial_{species_id}_preeq'

                    # need to set dummy value for preeq parameter anyways, as it
                    #  is expected below (set to 0, not nan, because will be
                    #  multiplied with indicator variable in initial assignment)
                    condition_map_sim[init_par_id] = 0.0
                    condition_scale_map_sim[init_par_id] = ptc.LIN

                    if preeq_cond_idx != NO_PREEQ_CONDITION_IDX:
                        _set_initial_concentration(
                            preeq_cond_id, species_id, init_par_id,
                            condition_map_preeq,
                            condition_scale_map_preeq)
                        # enable state reinitialization
                        self.f['/fixedParameters/simulationConditions'][condition_idx, 2] = 1

                    # for simulation
                    init_par_id = f'initial_{species_id}_sim'
                    _set_initial_concentration(
                        sim_cond_id, species_id, init_par_id,
                        condition_map_sim,
                        condition_scale_map_sim)

            print(condition_map_preeq, condition_map_sim)

            # split into fixed and variable parameters:
            condition_map_preeq_var = condition_scale_map_preeq_var = None
            condition_map_preeq_fix = None
            if condition_map_preeq:
                condition_map_preeq_var, condition_map_preeq_fix = \
                    subset_dict(condition_map_preeq, variable_par_ids,
                                fixed_par_ids)
                condition_scale_map_preeq_var, _ = \
                    subset_dict(condition_scale_map_preeq, variable_par_ids,
                                fixed_par_ids)

            condition_map_sim_var, condition_map_sim_fix = \
                subset_dict(condition_map_sim, variable_par_ids, fixed_par_ids)
            condition_scale_map_sim_var, condition_scale_map_sim_fix = \
                subset_dict(condition_scale_map_sim, variable_par_ids,
                            fixed_par_ids)

            if condition_map_preeq:
                # merge after having removed potentially fixed parameters
                # which may differ between preequilibration and simulation
                petab.merge_preeq_and_sim_pars_condition(
                    condition_map_preeq_var, condition_map_sim_var,
                    condition_scale_map_preeq_var, condition_scale_map_sim_var,
                    condition_idx)

            print(self.problem_parameter_ids)
            # mapping for each model parameter
            for model_parameter_idx, model_parameter_id \
                    in enumerate(variable_par_ids):
                mapped_parameter = condition_map_sim[model_parameter_id]
                mapped_parameter = to_float_if_float(mapped_parameter)
                try:
                    (mapped_idx, override) = self.get_index_mapping_for_par(
                        mapped_parameter, optimization_parameter_name_to_index)
                    mapping_matrix[model_parameter_idx, condition_idx] = \
                        mapped_idx
                    override_matrix[model_parameter_idx, condition_idx] = \
                        override
                except IndexError as e:
                    print(Fore.RED + "Error in parameter mapping:", e)
                    print(model_parameter_idx, mapped_parameter)
                    print(self.parameter_mapping)
                    raise e

            # Set parameter scales for simulation
            pscale_matrix[:, condition_idx] = list(
                petab_scale_to_amici_scale(condition_scale_map_sim[amici_id])
                for amici_id in variable_par_ids)

            fixed_parameter_matrix[:, self.condition_map[condition_idx, 1]] = \
                np.array([condition_map_sim_fix[par_id]
                         for par_id in fixed_par_ids])

            if condition_map_preeq:
                fixed_parameter_matrix[:, self.condition_map[condition_idx, 0]] = \
                    np.array([condition_map_preeq_fix[par_id]
                             for par_id in fixed_par_ids])

        # write to file
        self.create_fixed_parameter_dataset_and_write_attributes(
            fixed_par_ids, fixed_parameter_matrix)

        self.f.require_dataset('/parameters/pscaleSimulation',
                               shape=pscale_matrix.T.shape, dtype="<i4",
                               data=pscale_matrix.T)

        write_parameter_map(self.f, mapping_matrix, override_matrix,
                            num_model_parameters, self.compression)

        # for cost function parameters
        petab_opt_par_scale = \
            self.petab_problem.get_optimization_parameter_scales()
        pscale_opt_par = np.array(
            list(petab_scale_to_amici_scale(petab_opt_par_scale[par_id])
                 for par_id in self.problem_parameter_ids))

        self.f.require_dataset('/parameters/pscaleOptimization',
                               shape=pscale_opt_par.shape, dtype="<i4",
                               data=pscale_opt_par)

        self.f.flush()
示例#6
0
def get_model_for_condition(
        petab_problem: "petab.Problem",
        sim_condition_id: str = None,
        preeq_condition_id: Optional[str] = None,
) -> Tuple[libsbml.SBMLDocument, libsbml.Model]:
    """Create an SBML model for the given condition.

    Creates a copy of the model and updates parameters according to the PEtab
    files. Estimated parameters are set to their ``nominalValue``.
    Observables defined in the observables table are not added to the model.

    :param petab_problem: PEtab problem
    :param sim_condition_id: Simulation ``conditionId`` for which to generate a
        model
    :param preeq_condition_id: Preequilibration ``conditionId`` of the settings
        for which to generate a model. This is only used to determine the
        relevant output parameter overrides. Preequilibration is not encoded
        in the resulting model.
    :return: The generated SBML document, and SBML model
    """
    condition_dict = {petab.SIMULATION_CONDITION_ID: sim_condition_id}
    if preeq_condition_id:
        condition_dict[petab.PREEQUILIBRATION_CONDITION_ID] = \
            preeq_condition_id
    cur_measurement_df = petab.measurements.get_rows_for_condition(
        measurement_df=petab_problem.measurement_df,
        condition=condition_dict,
    )
    parameter_map, scale_map = \
        petab.parameter_mapping.get_parameter_mapping_for_condition(
            condition_id=sim_condition_id,
            is_preeq=False,
            cur_measurement_df=cur_measurement_df,
            sbml_model=petab_problem.sbml_model,
            condition_df=petab_problem.condition_df,
            parameter_df=petab_problem.parameter_df,
            warn_unmapped=True,
            scaled_parameters=False,
            fill_fixed_parameters=True,
            # will only become problematic once the observable and noise terms
            #  are added to the model
            allow_timepoint_specific_numeric_noise_parameters=True,
        )
    # create a copy of the model
    sbml_doc = petab_problem.sbml_model.getSBMLDocument().clone()
    sbml_model = sbml_doc.getModel()

    # fill in parameters
    def get_param_value(parameter_id: str):
        """Parameter value from mapping or nominal value"""
        mapped_value = parameter_map.get(parameter_id)
        if not isinstance(mapped_value, str):
            return mapped_value

        # estimated parameter, look up in nominal parameters
        return petab_problem.parameter_df.loc[mapped_value,
                                              petab.NOMINAL_VALUE]

    def remove_rules(target_id: str):
        if sbml_model.removeRuleByVariable(target_id):
            warn("An SBML rule was removed to set the component "
                 f"{target_id} to a constant value.")
        sbml_model.removeInitialAssignment(target_id)

    for parameter in sbml_model.getListOfParameters():
        new_value = get_param_value(parameter.getId())
        if new_value:
            parameter.setValue(new_value)
            # remove rules that would override that value
            remove_rules(parameter.getId())

    # set concentrations for any overridden species
    for component_id in petab_problem.condition_df:
        sbml_species = sbml_model.getSpecies(component_id)
        if not sbml_species:
            continue

        # remove any rules overriding that species' initials
        remove_rules(component_id)

        # set initial concentration/amount
        new_value = petab.to_float_if_float(
            petab_problem.condition_df.loc[sim_condition_id, component_id])
        if not isinstance(new_value, Number):
            # parameter reference in condition table
            new_value = get_param_value(new_value)

        if sbml_species.isSetInitialAmount() \
            or (sbml_species.getHasOnlySubstanceUnits()
                and not sbml_species.isSetInitialConcentration()):
            sbml_species.setInitialAmount(new_value)
        else:
            sbml_species.setInitialConcentration(new_value)

    # set compartment size for any compartments in the condition table
    for component_id in petab_problem.condition_df:
        sbml_compartment = sbml_model.getCompartment(component_id)
        if not sbml_compartment:
            continue

        # remove any rules overriding that compartment's size
        remove_rules(component_id)

        # set initial concentration/amount
        new_value = petab.to_float_if_float(
            petab_problem.condition_df.loc[sim_condition_id, component_id])
        if not isinstance(new_value, Number):
            # parameter reference in condition table
            new_value = get_param_value(new_value)

        sbml_compartment.setSize(new_value)

    return sbml_doc, sbml_model