Source code for pkpd.protocols.protocol_pkpd_simulate_generic_pd

# **************************************************************************
# *
# * Authors:     Carlos Oscar Sorzano (info@kinestat.com)
# *
# * Kinestat Pharma
# *
# * This program is free software; you can redistribute it and/or modify
# * it under the terms of the GNU General Public License as published by
# * the Free Software Foundation; either version 2 of the License, or
# * (at your option) any later version.
# *
# * This program is distributed in the hope that it will be useful,
# * but WITHOUT ANY WARRANTY; without even the implied warranty of
# * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# * GNU General Public License for more details.
# *
# * You should have received a copy of the GNU General Public License
# * along with this program; if not, write to the Free Software
# * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
# * 02111-1307  USA
# *
# *  All comments concerning this program package may be sent to the
# *  e-mail address 'info@kinestat.com'
# *
# **************************************************************************

import sys

import pyworkflow.protocol.params as params
from .protocol_pkpd import ProtPKPD
from pkpd.objects import PKPDVariable, PKPDUnit
from pyworkflow.protocol.constants import LEVEL_ADVANCED
from pkpd.utils import parseRange
from pkpd.models.pd_models import *


[docs]class ProtPKPDSimulateGenericPD(ProtPKPD): """ Simulate a generic pharmacodynamic response Y=f(X).\n Protocol created by http://www.kinestatpharma.com\n""" _label = 'simulate generic' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form, fullForm=True): form.addSection('Input') form.addParam('inputExperiment', params.PointerParam, label="Input experiment", pointerClass='PKPDExperiment', help='Select an experiment with samples') form.addParam('predictor', params.StringParam, label="Predictor variable (X)", default="Cp", help='The predictor variable is X in Y=f(X). X must be one of the variables of the experiment. '\ 'It is normally a concentration.') form.addParam('predicted', params.StringParam, label="Predicted variable (Y)", default="E", help='The predicted variable is Y in Y=f(X). Y must not exist in the experiment. It is normally the effect') form.addParam('predictedUnit', params.StringParam, label="Units for Y", default="none", expertLevel=LEVEL_ADVANCED, help='Valid units are none, g, h, ...') form.addParam('predictedComment', params.StringParam, label="Comment for Y", default="Simulated pharmacodynamic feature", help='This comment will appear in the output experiment') form.addParam('modelType', params.EnumParam, choices=["Linear (Polynomial 1)","Log-linear","Saturated","Sigmoid","Gompertz", "Logistic1 ","Logistic 2","Logistic 3","Logistic 4", "Richards","Morgan-Mercer-Flodin","Weibull"], label="Generic model", default=0, help='Linear: Y=e1*X+e0\nLog-linear: Y=m*log(X-X0)\n'\ 'Saturated: Y=emin+emax*X/(ec50+X)\nSigmoid: Y=e0+(emax*(X**h)/((eC50**h)+(X**h)))\n'\ 'Gompertz: Y=e0+a*exp(-exp(b-g*X))\nLogistic 1: Y=e0+(a/(1+exp(b-g*X)))\n'\ 'Logistic 2: Y=e0+(1/(a+exp(b-g*X)))\nLogistic 3: Y=e0+(a/(1+b*exp(-g*X)))\n'\ 'Logistic 4: Y=e0+(1/(a+b*exp(-g*X)))\nRichards: Y=e0+(a/((1+exp(b-g*X))^(1/d)))\n'\ 'Morgan-Mercer-Flodin: Y=e0+((b*g+a*(X^d))/(g+(X^d)))\nWeibull: Y=a-b*exp(-g*(X^d))\n'\ 'Polynomial n: en*X^n+...+e1*X+e0') form.addParam('paramValues', params.StringParam, label="Parameter values", default="", help='Parameter values for the simulation.\nExample: 3.5;-1 is 3.5 for the first parameter, -1 for the second parameter\n' 'Linear: e1;e0\n'\ 'Log-linear: m;X0\n'\ 'Saturated: e0;emax;eC50\n'\ 'Sigmoid: e0;emax;eC50;h\n'\ 'Gompertz: e0;a;b;g\n'\ 'Logistic 1: e0;a;b;g\n'\ 'Logistic 2: e0;a;b;g\n'\ 'Logistic 3: e0;a;b;g\n'\ 'Logistic 4: e0;a;b;g\n'\ 'Richards: e0;a;b;g;d\n'\ 'Morgan-Mercer-Flodin: e0;b;g;a;d\n'\ 'Weibull: a;b;g;d\n'\ 'Polynomial n: en; ...; e1; e0\n') form.addParam('reportX', params.StringParam, label="Evaluate at X=", default="", expertLevel=LEVEL_ADVANCED, help='Evaluate the model at these X values\nExample 1: [0,5,10,20,40,100]\nExample 2: 0:2:10, from 0 to 10 in steps of 2') form.addParam('noiseType', params.EnumParam, label="Type of noise to add", choices=["None","Additive","Multiplicative"], default=0, expertLevel=LEVEL_ADVANCED, help='Additive: noise is normally distributed (mean=0 and standard deviation=sigma)\n'\ 'Multiplicative: noise is normally distributed (mean=0 and standard deviation=sigma*X)\n') form.addParam('noiseSigma', params.FloatParam, label="Noise sigma", default=0.0, expertLevel=LEVEL_ADVANCED, condition="noiseType>0", help='See help of Type of noise to add\n') #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('runSimulate',self.inputExperiment.get().getObjId(), self.predictor.get(), \ self.predicted.get(), self.modelType.get(), self.paramValues.get(), self.reportX.get()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions --------------------------------------------
[docs] def addNoise(self,y): if self.noiseType.get()==0: return y elif self.noiseType.get()==1: return y+np.random.normal(0.0,self.noiseSigma.get(),y.shape) elif self.noiseType.get()==2: return y*(1+np.random.normal(0.0,self.noiseSigma.get(),y.shape))
[docs] def runSimulate(self, objId, X, Y, modelType, paramValues, reportX): reportX = parseRange(self.reportX.get()) self.experiment = self.readExperiment(self.inputExperiment.get().fnPKPD) # Setup model self.printSection("Model setup") if self.modelType.get()==0: model = PDPolynomial1() elif self.modelType.get()==1: model = PDLogLinear() elif self.modelType.get()==2: model = PDSaturated() elif self.modelType.get()==3: model = PDSigmoid() elif self.modelType.get()==4: model = PDGompertz() elif self.modelType.get()==5: model = PDLogistic1() elif self.modelType.get()==6: model = PDLogistic2() elif self.modelType.get()==7: model = PDLogistic3() elif self.modelType.get()==8: model = PDLogistic4() elif self.modelType.get()==9: model = PDRichards() elif self.modelType.get()==10: model = PDMorgan() elif self.modelType.get()==11: model = PDWeibull() elif self.modelType.get()==12: model = PDPolynomial2() elif self.modelType.get()==13: model = PDPolynomial3() elif self.modelType.get()==14: model = PDPolynomial4() elif self.modelType.get()==15: model = PDPolynomial5() elif self.modelType.get()==16: model = PDPolynomial6() elif self.modelType.get()==17: model = PDPolynomial7() elif self.modelType.get()==18: model = PDPolynomial8() elif self.modelType.get()==19: model = PDPolynomial9() model.setExperiment(self.experiment) model.setXVar(self.predictor.get()) model.printSetup() # Create list of parameters tokens=self.paramValues.get().split(';') if len(tokens)!=model.getNumberOfParameters(): raise Exception("The list of parameter values has not the same number of parameters as the model") model.parameters=[] for token in tokens: try: model.parameters.append(float(token.strip())) except: raise Exception("Cannot convert %s to float"%token) print("Simulated model: %s"%model.getEquation()) if self.noiseType.get()==1: print("Adding additive noise with sigma=%f"%self.noiseSigma.get()) elif self.noiseType.get()==2: print("Adding multiplicative noise with sigma=%f*X"%self.noiseSigma.get()) # Add new variable to experiment newVariable = PKPDVariable() newVariable.varName = self.predicted.get() newVariable.varType = PKPDVariable.TYPE_NUMERIC newVariable.displayString = "%f" newVariable.role = PKPDVariable.ROLE_MEASUREMENT newVariable.comment = self.predictedComment.get() newVariable.units = PKPDUnit(self.predictedUnit.get()) self.experiment.variables[newVariable.varName] = newVariable for sampleName, sample in self.experiment.samples.items(): model.x = np.array(sample.getValues(self.predictor.get()),dtype=np.float) y = model.forwardModel(model.parameters,model.x) y = self.addNoise(y) sample.addMeasurementColumn(newVariable.varName,y) print("==========================================") sample._printToStream(sys.stdout) print("==========================================") sample._printMeasurements(sys.stdout) print(" ") if reportX!=None: print("Evaluation of the model at specified values") yReportX = model.forwardModel(model.parameters, reportX) yReportX = self.addNoise(yReportX) print("==========================================") print("X Ypredicted log10(Ypredicted)") print("==========================================") for n in range(0,reportX.shape[0]): print("%f %f %f"%(reportX[n],yReportX[n],math.log10(yReportX[n]))) print(' ')
[docs] def createOutputStep(self): self.experiment.write(self._getPath("experiment.pkpd")) self._defineOutputs(outputFitting=self.experiment) self._defineSourceRelation(self.inputExperiment, self.experiment)
#--------------------------- INFO functions -------------------------------------------- def _summary(self): msg=[] modelTypeStr="unknown" if self.modelType.get()==0: modelTypeStr = "linear" elif self.modelType.get()==1: modelTypeStr = "Log-Linear" elif self.modelType.get()==2: modelTypeStr = "Saturated" elif self.modelType.get()==3: modelTypeStr = "Sigmoid" elif self.modelType.get()==4: modelTypeStr = "Gompertz" elif self.modelType.get()==5: modelTypeStr == "Logistic1" elif self.modelType.get() == 6: modelTypeStr == "Logistic 2" elif self.modelType.get() == 7: modelTypeStr == "Logistic 3" elif self.modelType.get() == 8: modelTypeStr == "Logistic 4" elif self.modelType.get() == 9: modelTypeStr == "Richards" elif self.modelType.get() == 10: modelTypeStr == "Morgan-Mercer-Flodin" elif self.modelType.get() == 11: modelTypeStr == "Weibull" elif self.modelType.get() == 12: modelTypeStr == "Polynomial 2" elif self.modelType.get() == 13: modelTypeStr == "Polynomial 3" elif self.modelType.get() == 14: modelTypeStr == "Polynomial 4" elif self.modelType.get() == 15: modelTypeStr == "Polynomial 5" elif self.modelType.get() == 16: modelTypeStr == "Polynomial 6" elif self.modelType.get() == 17: modelTypeStr == "Polynomial 7" elif self.modelType.get() == 18: modelTypeStr == "Polynomial 8" elif self.modelType.get() == 19: modelTypeStr == "Polynomial 9" msg.append("Variable %s added to experiment by simulation of a %s model"%(self.predicted.get(),modelTypeStr)) msg.append("Parameter values: %s"%self.paramValues) return msg def _validate(self): msg=[] experiment = self.readExperiment(self.inputExperiment.get().fnPKPD) if self.predicted.get() in experiment.variables: msg.append("The experiment already has a column called %s"%self.predicted.get()) units = PKPDUnit() if units._fromString(self.predictedUnit.get()) is None: msg.append("Predicted unit is not valid") return msg
[docs] def filterVarForWizard(self, v): """ Define the type of variables required (used in wizard). """ return v.isMeasurement() and v.isNumeric()