Beispiel #1
0
    def __setstate__(self, state: Dict):
        self.__dict__.update(state)

        model = amici_petab_import.import_petab_problem(self.petab_problem)
        solver = model.getSolver()

        _fd, _file = tempfile.mkstemp()
        try:
            # write solver settings to temporary file
            with open(_fd, 'wb', closefd=False) as f:
                f.write(state['amici_solver_settings'])
            # read in solver settings
            try:
                amici.readSolverSettingsFromHDF5(_file, solver)
            except AttributeError as err:
                if not err.args:
                    err.args = ('', )
                err.args += ("Unpickling an AmiciObjective requires an AMICI "
                             "installation with HDF5 support.", )
                raise
        finally:
            # close file descriptor and remove temporary file
            os.close(_fd)
            os.remove(_file)

        self.amici_model = model
        self.amici_solver = solver
Beispiel #2
0
    def __init__(
        self,
        petab_problem: petab.Problem,
        amici_model: "amici.Model" = None,
        amici_solver: "amici.Solver" = None,
    ):
        super().__init__(petab_problem=petab_problem)

        if amici_model is None:
            amici_model = amici_petab_import.import_petab_problem(
                petab_problem)
        self.amici_model = amici_model

        if amici_solver is None:
            amici_solver = self.amici_model.getSolver()
        self.amici_solver = amici_solver
Beispiel #3
0
 def create_objective(self, **kwargs):
     # FIXME assumes first model will have all required features for later
     #       models (e.g. same condition parameters etc)
     # FIXME move to `__init__`, use `self.petab_problem`?
     amici_model = import_petab_problem(self.petab_problems[0])
     return PetabTimecourseObjective(
         petab_problem=self.petab_problem,
         timecourse_id=self.timecourse_id,
         #x_names=list(amici_model.getParameterIds()),
         x_names=list(self.petab_problem.parameter_df.index),
         # 1 is the number of condition. Currently only 1 "condition" (1
         # timecourse) is supported.
         parameter_mapping=create_identity_parameter_mapping(
             amici_model, 1),
         **kwargs,
     )
Beispiel #4
0
def test_model():
    petab_problem = petab.Problem.from_yaml(str(petab_yaml_path()))
    model = import_petab_problem(
        petab_problem, force_compile=False)  # FIXME force_compile True
    solver = model.getSolver()
    solver.setSensitivityOrder(1)
    solver.setSensitivityMethod(1)

    rdatas = []
    rdata = None
    for row_index, (t_start, q_) in enumerate(timecourse_q_):
        if q_ is None:
            break
        t_end = timecourse_q_[row_index + 1, 0]
        model.setTimepoints(
            np.linspace(t_start, t_end,
                        OUTPUT_DENSITY * (t_end - t_start) + 1))
        #model.setFixedParameterById('q_', q_)
        model.setParameterById({'q_': q_})

        # Continue the next sub-simulation from the previous simulation.
        if rdatas:
            model.setT0(t_start)
            model.setInitialStates(rdatas[-1].x[-1])
            # 0th column is sensitivity of x_ w.r.t. p_
            # 1st column is sensitivity of x_ w.r.t. q_
            model.setInitialStateSensitivities(rdatas[-1].sx[-1][:, 0])
        rdatas.append(amici.runAmiciSimulation(model, solver))

    # Collect
    # FIXME magic number `0`
    x_ = list(
        chain.from_iterable([rdata.x[:, 0].flatten() for rdata in rdatas]))

    # Collect simulated forward sensitivities.
    sx_ = list(
        chain.from_iterable([rdata.sx[:, 0, :].flatten() for rdata in rdatas]))

    T = list(chain.from_iterable([rdata.ts for rdata in rdatas]))
    analytical_x_ = [np.round(get_analytical_x_(t), 5) for t in T]
    analytical_sx_ = [np.round(get_analytical_sx_(t), 5) for t in T]

    # The state (x_) trajectory is correct.
    assert np.isclose(x_, analytical_x_).all()
    # The state (x_) forward sensitivity w.r.t. the parameter (p_) is correct.
    assert np.isclose(sx_, analytical_sx_).all()
Beispiel #5
0
def simulate_timecourse(
    parent_petab_problem: petab.Problem,
    timecourse_id: str,
    solver_settings: Dict[str, Any],
    problem_parameters: Dict[str, float] = None,
    parameter_mapping=None,
    sensi_orders: Tuple[int, ...] = (0, 1),
    # FIXME Dict typehint
    initial_states: Union[Dict, Tuple[float, ...]] = None,
    model_settings: Dict[str, Any] = None,
    #solver_customizer: Callable[[amici.Solver], None] = None
):
    """
    Solver settings are a required attribute to ensure these are not
    forgotten...

    To use a default solver, supply an empty dictionary (`solver_settings={}`).

    initial_states:
        FIXME
        Can supply a dictionary or a tuple.
    """
    timecourse = get_timecourse(
        petab_problem=parent_petab_problem,
        timecourse_id=timecourse_id,
    )
    petab_problems = subset_petab_problem(
        petab_problem=parent_petab_problem,
        timecourse_id=timecourse_id,
    )
    #print([petab_problem.measurement_df for petab_problem in petab_problems])
    results = []
    #amici_model = import_petab_problem(petab_problems[0])
    for index, petab_problem in enumerate(petab_problems):
        if petab_problem.measurement_df.empty:
            # FIXME resolve this properly. Is it due to timecourse pieces
            #       that are defined to occur after the last measured time
            #       point?
            break
        # FIXME uncomment, remove global `amici_model = ...` above

        # Replace a controlled parameter with the ID of its timepoint-specific
        # control parameter (hack to ensure sensitivities are computed correctly)
        #print(1)
        replace_timecourse_parameters = {
            k: v
            for k, v in petab_problem.condition_df.loc[timecourse_id].items()
            if isinstance(v, str) and k != CONDITION_NAME
        }
        petab_problem.condition_df.drop(
            replace_timecourse_parameters,
            axis=1,
            inplace=True,
        )
        for old_parameter_id, new_parameter_id in replace_timecourse_parameters.items(
        ):
            if old_parameter_id in problem_parameters:
                raise ValueError(
                    'A timecourse parameter was assigned a value via '
                    '`problem_parameters`, but should receive its value '
                    'from the timecourse information.')
            if new_parameter_id not in problem_parameters:
                raise ValueError(
                    'Please supply a value for estimated timecourse '
                    'replacement parameters (parameter IDs in the rows) '
                    'of the condition table of a PEtab Timecourse problem.')
            problem_parameters[old_parameter_id] = \
                problem_parameters[new_parameter_id]
            # Duplicate control parameter in parameter_df, new index value is the
            # controlled parameter, such that sensitivities are output for the
            # controlled parameter (and can be interpreted as the sensitivities for
            # the control parameter)
            petab_problem.parameter_df.loc[old_parameter_id] = \
                petab_problem.parameter_df.loc[new_parameter_id]
        #print(2)

        amici_model = import_petab_problem(petab_problem)
        amici_model.setT0(float(timecourse[index][0]))
        #if initial_states is not None:
        #    breakpoint()
        #print(f'\n\nTime: {amici_model.t0()}\n\n')

        amici_edatas = create_edatas(amici_model, petab_problem)
        if problem_parameters is not None:
            # FIXME temp fix to add into parameters that AMICI automatically
            #       sets to be estimated from the SBML model (that weren't
            #       fixed like parameters in a condition table)
            model_parameters = dict(
                zip(amici_model.getParameterIds(),
                    amici_model.getParameters()))

            #assert parameter_mapping is not None
            #print(problem_parameters)
            #print(petab_problem.measurement_df)
            if parameter_mapping is None:
                parameter_mapping = \
                    create_identity_parameter_mapping(amici_model, 1)
            # Remove parameters from problem parameters if they are already
            # specified by the timecourse.
            # May break if a problem parameter is named `'conditionName'`.
            subset_problem_parameters = {
                parameter_id: parameter_value
                for parameter_id, parameter_value in {
                    **model_parameters,
                    **problem_parameters
                }.items()
                #for parameter_id, parameter_value in problem_parameters.items()
                if parameter_id not in petab_problem.condition_df.columns
            }
            removed_problem_parameters = \
                set(problem_parameters).difference(subset_problem_parameters)
            warnings.warn(
                'The following parameters were removed from the supplied '
                '`problem_parameters`, as they are already specified by the '
                f'timecourse: {removed_problem_parameters}')

            #notpositive = {
            #    k: v
            #    for k, v in subset_problem_parameters.items()
            #    if v <= 0
            #}
            #print(f'not positive parameters: {notpositive}')  # FIXME

            amici.parameter_mapping.fill_in_parameters(
                edatas=amici_edatas,
                problem_parameters=subset_problem_parameters,
                scaled_parameters=True,
                parameter_mapping=parameter_mapping,
                amici_model=amici_model,
            )
        else:
            subset_problem_parameters = None
        #amici_model.setParameterById(problem_parameters)
        #parameters = [
        #    problem_parameters[parameter_id]
        #    for parameter_id in amici_model.getParameterIds()
        #]
        #amici_edatas = create_edatas(amici_model, petab_problem)
        #one(amici_edatas).parameters = parameters
        #print(3)

        if results:
            one(amici_edatas).x0 = one(results[-1]['rdatas']).x[-1].flatten()
            one(amici_edatas).sx0 = one(results[-1]['rdatas']).sx[-1].flatten()
        elif initial_states is not None:
            # TODO untested
            #print(initial_states)
            #print(amici_model.getStateIds())
            if isinstance(initial_states, dict):
                indexed_initial_states = [
                    initial_states[state_id]
                    for state_id in amici_model.getStateIds()
                ]
            else:
                indexed_initial_states = initial_states
            #print(indexed_initial_states)
            #print(amici_model.getStateIds())
            #print(4)
            one(amici_edatas).x0 = indexed_initial_states
            #print(5)

        amici_solver = amici_model.getSolver()
        # TODO allow a user to specify these settings
        if model_settings is not None:
            for setter, value in model_settings.items():
                getattr(amici_model, setter)(value)
        if solver_settings is not None:
            for setter, value in solver_settings.items():
                getattr(amici_solver, setter)(value)
        #print(4)
        #amici_solver.setSensitivityOrder(amici.SensitivityOrder_first)
        #amici_solver.setSensitivityMethod(amici.SensitivityMethod_forward)
        #amici_solver.setMaxSteps(int(1e6))

        #solver_settings = {
        #    'setSensitivityOrder': amici.SensitivityOrder_first,
        #    'setSensitivityMethod': amici.SensitivityMethod_forward,
        #    'setMaxSteps': int(1e6),
        #    'setMaxTime': 60,
        #}

        #amici_solver.setAbsoluteTolerance(1e-8)
        #amici_solver.setRelativeTolerance(1e-6)
        #amici_solver.setAbsoluteToleranceFSA(1e-8)
        #amici_solver.setRelativeToleranceFSA(1e-6)

        #print(one(amici_edatas).parameters)
        #import functools
        #sp = lambda x: simulate_petab(
        #    petab_problem=petab_problem,
        #    amici_model=amici_model,
        #    solver=amici_solver,
        #    problem_parameters=x,
        #)
        results.append(
            simulate_petab(
                petab_problem=petab_problem,
                amici_model=amici_model,
                solver=amici_solver,
                edatas=amici_edatas,
                problem_parameters=subset_problem_parameters,
            ))
        #print(5)

        #print(problem_parameters)
        #print(results)
        if initial_states is not None:
            pass
        for old_parameter_id, new_parameter_id in replace_timecourse_parameters.items(
        ):
            results[-1]['sllh'][new_parameter_id] = \
                results[-1]['sllh'][old_parameter_id]
            # Was artifically added, so remove now
            del problem_parameters[old_parameter_id]
    return results
Beispiel #6
0
def visualize_optimized_model_fit(
    petab_problem: petab.Problem,
    result: Union[Result, Sequence[Result]],
    start_index: int = 0,
    **kwargs,
) -> Union[matplotlib.axes.Axes, None]:
    """
    Visualize the optimized model fit of a PEtab problem.

    Function calls the PEtab visualization file of the petab_problem and
    visualizes the fit of the optimized parameter. Common additional
    argument is `subplot_dir` to specify the directory each subplot is
    saved to. Further keyword arguments are delegated to
    petab.visualize.plot_with_vis_spec, see there for more information.

    Parameters
    ----------
    petab_problem:
        The :py:class:`petab.Problem` that was optimized.
    result:
        The result object from optimization.
    start_index:
        The index of the optimization run in `result.optimize_result.list`.

    Returns
    -------
    axes: `matplotlib.axes.Axes` object of the created plot.
    None: In case subplots are saved to file
    """
    if petab_problem is not None:
        if petab is None:
            raise

    problem_parameters = dict(
        zip(
            petab_problem.parameter_df.index,
            result.optimize_result.list[start_index]['x'],
        )
    )

    amici_model = petab_import.import_petab_problem(
        petab_problem,
        model_output_dir=kwargs.pop('model_output_dir', None),
        force_compile=kwargs.pop('force_compile', False),
    )

    res = simulate_petab(
        petab_problem,
        amici_model=amici_model,
        scaled_parameters=True,
        problem_parameters=problem_parameters,
        solver=kwargs.pop('amici_solver', None),
    )

    sim_df = rdatas_to_simulation_df(
        res["rdatas"], amici_model, petab_problem.measurement_df
    )

    # function to call, to plot data and simulations
    axes = plot_problem(
        petab_problem=petab_problem, simulations_df=sim_df, **kwargs
    )
    return axes
Beispiel #7
0
        pysb.SelfExporter.cleanup()
        pysb.SelfExporter.do_export = True
        case_dir = os.path.join(petabtests.PYSB_DIR, case)
        # import petab problem
        yaml_file = os.path.join(case_dir, petabtests.problem_yaml_name(case))
        problem = PysbPetabProblem.from_yaml(yaml_file,
                                             flatten=case.startswith('0006'))
    else:
        raise ValueError(f"Unsupported model_type: {model_type}")

    # compile amici model
    if case.startswith('0006') and model_type != "pysb":
        petab.flatten_timepoint_specific_output_overrides(problem)
    model_output_dir = f'amici_models/model_{case}'
    model = import_petab_problem(problem,
                                 model_output_dir=model_output_dir,
                                 force_compile=True)

    # simulate
    ret = simulate_petab(problem, model, log_level=logging.DEBUG)

    rdatas = ret['rdatas']
    chi2 = sum(rdata['chi2'] for rdata in rdatas)
    llh = ret['llh']
    simulation_df = rdatas_to_measurement_df(rdatas, model,
                                             problem.measurement_df)
    petab.check_measurement_df(simulation_df, problem.observable_df)
    simulation_df = simulation_df.rename(
        columns={petab.MEASUREMENT: petab.SIMULATION})
    simulation_df[petab.TIME] = simulation_df[petab.TIME].astype(int)
    solution = petabtests.load_solution(case, model_type)
Beispiel #8
0
def _test_case(case):
    """Run a single PEtab test suite case"""
    case = petabtests.test_id_str(case)
    logger.debug(f"Case {case}")

    # load
    case_dir = os.path.join(petabtests.CASES_DIR, case)

    # import petab problem
    yaml_file = os.path.join(case_dir, petabtests.problem_yaml_name(case))
    problem = petab.Problem.from_yaml(yaml_file)

    # compile amici model
    model_output_dir = f'amici_models/model_{case}'
    model = import_petab_problem(
        problem, model_output_dir=model_output_dir)

    # simulate
    chi2s_match = llhs_match = simulations_match = False
    ret = simulate_petab(problem, model, log_level=logging.DEBUG)

    rdatas = ret['rdatas']
    chi2 = sum(rdata['chi2'] for rdata in rdatas)
    llh = ret['llh']
    simulation_df = rdatas_to_measurement_df(rdatas, model,
                                             problem.measurement_df)
    petab.check_measurement_df(simulation_df, problem.observable_df)
    simulation_df = simulation_df.rename(
        columns={petab.MEASUREMENT: petab.SIMULATION})
    simulation_df[petab.TIME] = simulation_df[petab.TIME].astype(int)
    solution = petabtests.load_solution(case)
    gt_chi2 = solution[petabtests.CHI2]
    gt_llh = solution[petabtests.LLH]
    gt_simulation_dfs = solution[petabtests.SIMULATION_DFS]
    tol_chi2 = solution[petabtests.TOL_CHI2]
    tol_llh = solution[petabtests.TOL_LLH]
    tol_simulations = solution[petabtests.TOL_SIMULATIONS]

    chi2s_match = petabtests.evaluate_chi2(chi2, gt_chi2, tol_chi2)
    llhs_match = petabtests.evaluate_llh(llh, gt_llh, tol_llh)
    simulations_match = petabtests.evaluate_simulations(
        [simulation_df], gt_simulation_dfs, tol_simulations)

    logger.log(logging.DEBUG if chi2s_match else logging.ERROR,
               f"CHI2: simulated: {chi2}, expected: {gt_chi2},"
               f" match = {chi2s_match}")
    logger.log(logging.DEBUG if simulations_match else logging.ERROR,
               f"LLH: simulated: {llh}, expected: {gt_llh}, "
               f"match = {llhs_match}")
    logger.log(logging.DEBUG if simulations_match else logging.ERROR,
               f"Simulations: match = {simulations_match}")

    # FIXME case 7 fails due to #963
    if case not in ['0007', '0016']:
        check_derivatives(problem, model)

    # FIXME case 7 fails due to #963
    if not all([llhs_match, simulations_match]) \
            or (not chi2s_match and case not in ['0007', '0016']):
        # chi2s_match ignored until fixed in amici
        logger.error(f"Case {case} failed.")
        raise AssertionError(f"Case {case}: Test results do not match "
                             "expectations")

    logger.info(f"Case {case} passed.")