Source code for pharmpy.modeling.power_on_ruv

"""
:meta private:
"""
from __future__ import annotations

from typing import Optional, Union

from pharmpy.deps import sympy
from pharmpy.internals.expr.parse import parse as parse_expr
from pharmpy.internals.expr.subs import subs
from pharmpy.model import Assignment, Model, Parameter, Parameters

from .error import has_proportional_error_model
from .expressions import create_symbol
from .help_functions import _format_input_list


[docs]def set_power_on_ruv( model: Model, list_of_eps: Optional[Union[str, list]] = None, lower_limit: Optional[float] = 0.01, ipred: Optional[Union[str, sympy.Symbol]] = None, zero_protection: bool = False, ): """Applies a power effect to provided epsilons. Initial estimates for new thetas are 1 if the error model is proportional, otherwise they are 0.1. Parameters ---------- model : Model Pharmpy model to create block effect on. list_of_eps : str or list or None Name/names of epsilons to apply power effect. If None, all epsilons will be used. None is default. lower_limit : float or None Lower limit of power (theta). None for no limit. ipred : Symbol Symbol to use as IPRED. Default is to autodetect expression for IPRED. zero_protection : bool Set to True to add code protecting from IPRED=0 Return ------ Model Pharmpy model object Examples -------- >>> from pharmpy.modeling import * >>> model = load_example_model("pheno") >>> model = set_power_on_ruv(model) >>> model.statements.find_assignment("Y") power₁ Y = EPS₁⋅F + F See also -------- set_iiv_on_ruv """ list_of_eps = _format_input_list(list_of_eps) eps = model.random_variables.epsilons if list_of_eps is not None: eps = eps[list_of_eps] pset, sset = list(model.parameters), model.statements if ipred is None: ipred = get_ipred(model) else: ipred = parse_expr(ipred) if has_proportional_error_model(model): theta_init = 1 else: theta_init = 0.1 # Find for example W = IPRED for s in sset: if isinstance(s, Assignment) and s.expression == ipred: alternative = s.symbol if zero_protection: guard_expr = sympy.Piecewise( (2.225e-307, sympy.Eq(s.expression, 0)), (s.expression, True) ) guard_assignment = Assignment(ipred, guard_expr) ind = sset.find_assignment_index('Y') sset = sset[0:ind] + guard_assignment + sset[ind:] break else: alternative = None for e in eps.names: theta_name = str(create_symbol(model, stem='power', force_numbering=True)) if lower_limit is None: theta = Parameter(theta_name, theta_init) else: theta = Parameter(theta_name, theta_init, lower=lower_limit) pset.append(theta) sset = sset.subs( {sympy.Symbol(e) * ipred: sympy.Symbol(e)} ) # To avoid getting F*EPS*F**THETA if alternative: # To avoid getting W*EPS*F**THETA sset = sset.subs({sympy.Symbol(e) * alternative: sympy.Symbol(e)}) sset = sset.subs({sympy.Symbol(e): ipred ** sympy.Symbol(theta.name) * sympy.Symbol(e)}) model = model.replace(statements=sset) model = model.replace(parameters=Parameters.create(pset), statements=sset) return model.update_source()
def get_ipred(model): # FIXME: handle other DVs? dv = list(model.dependent_variables.keys())[0] expr = model.statements.after_odes.full_expression(dv) ipred = subs( expr, {sympy.Symbol(rv): 0 for rv in model.random_variables.names}, simultaneous=True ) for s in model.statements: if isinstance(s, Assignment) and s.expression == ipred: ipred = s.symbol break return ipred