class ProtPKPDDeconvolutionWagnerNelson(ProtPKPD): """ Calculate the absorption profile of an in vivo concentration profile using the Wagner-Nelson approach. This is only valid for profiles that have been modelled with a monocompartment PK model. The formula is Fabs(t)=(Cp(t)+Ke*AUC0t(t))/(Ke*AUC0inf) where Ke=Cl/V In this implementation it is assumed that AUC0inf is the last AUC0t observed, meaning that Cp(t) has almost vanished in the last samples""" _label = 'deconvolution Wagner Nelson' SAME_INPUT = 0 ANOTHER_INPUT = 1 BIOAVAIL_NONE = 0 BIOAVAIL_MULT = 1 BIOAVAIL_DIV = 2 #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'inputExperiment', params.PointerParam, label="In-vivo profiles", pointerClass='PKPDExperiment', help= 'Make sure that it has a clearance parameter (Cl) and central volume (V)' ) form.addParam( 'externalIV', params.EnumParam, choices=[ 'Get impulse response from the same input fit', 'Get impulse response from another fit' ], label='Impulse response source', default=self.SAME_INPUT, help= "The impulse response is an estimate of the intravenous response") form.addParam('externalIVODE', params.PointerParam, label="External impulse response ODE model", condition='externalIV==1', pointerClass='ProtPKPDMonoCompartment, ProtPKPDTwoCompartments,ProtPKPDODERefine,' \ ' ProtPKPDTwoCompartmentsClint, ProtPKPDTwoCompartmentsClintCl', help='Select a run of an ODE model. It should be ideally the intravenous response.') form.addParam('timeVar', params.StringParam, label="Time variable", default="t", help='Which variable contains the time stamps.') form.addParam('concVar', params.StringParam, label="Concentration variable", default="Cp", help='Which variable contains the plasma concentration.') form.addParam( 'normalize', params.BooleanParam, label="Normalize by dose", default=True, help= 'Normalize the output by AUC0inf, so that a total absorption is represented by 100.' ) form.addParam( 'saturate', params.BooleanParam, label="Saturate at 100%", default=True, condition='normalize', help= 'Saturate the absorption so that there cannot be values beyond 100' ) form.addParam('considerBioaval', params.EnumParam, label="Consider bioavailability", default=self.BIOAVAIL_NONE, choices=[ 'Do not correct', 'Multiply deconvolution by bioavailability', 'Divide deconvolution by bioavailability' ], help='Take into account the bioavailability') form.addParam( 'resampleT', params.FloatParam, label="Resample profiles (time step)", default=-1, help= 'Resample the input profiles at this time step (make sure it is in the same units as the input). ' 'Leave it to -1 for no resampling') form.addParam( 'smooth', params.BooleanParam, label="Monotonic smooth", default=True, help= 'Apply a Pchip interpolation to make sure that the Adissolved is monotonically increasing' ) #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('deconvolve', self.inputExperiment.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addSample(self, sampleName, t, y): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.descriptors = {} newSample.addMeasurementPattern(["A"]) newSample.addMeasurementColumn("t", t) newSample.addMeasurementColumn("A", y) self.outputExperiment.samples[sampleName] = newSample def estimateAUCrightTail(self, t, Cp, Cl, V): idx = Cp > 0 x = t[idx] y = np.log10(Cp[idx]) ydiff = np.diff(y) idx = -1 while ydiff[idx] < 0: idx -= 1 if idx < -3: p = np.polyfit(x[idx:], y[idx:], 1) Ke = Cl / V lastCt = np.power(10, p[0] * x[-1] + p[1]) return lastCt / np.abs(Ke) else: return 0 def deconvolve(self, objId1): self.experiment = self.readExperiment( self.inputExperiment.get().fnPKPD) # Create output object self.outputExperiment = PKPDExperiment() tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(self.experiment.getTimeUnits().unit) Avar = PKPDVariable() Avar.varName = "A" Avar.varType = PKPDVariable.TYPE_NUMERIC Avar.role = PKPDVariable.ROLE_MEASUREMENT Avar.units = createUnit("none") self.outputExperiment.variables[tvar.varName] = tvar self.outputExperiment.variables[Avar.varName] = Avar self.outputExperiment.general[ "title"] = "Deconvolution of the amount released" self.outputExperiment.general[ "comment"] = "Amount released at any time t" # Get the input sample from another experiment if necessary sampleFrom = None if self.externalIV.get() == self.ANOTHER_INPUT: anotherExperiment = self.readExperiment( self.externalIVODE.get().outputExperiment.fnPKPD) for _, sampleFrom in anotherExperiment.samples.items( ): # Take the first sample from the reference break timeRange = self.experiment.getRange(self.timeVar.get()) for sampleName, sample in self.experiment.samples.items(): # Get t, Cp t = np.asarray(sample.getValues(self.timeVar.get()), dtype=np.float64) Cp = np.asarray(sample.getValues(self.concVar.get()), dtype=np.float64) Cp = np.clip(Cp, 0.0, None) t = np.insert(t, 0, 0) # Add (0,0) to the profile Cp = np.insert(Cp, 0, 0) t, Cp = uniqueFloatValues(t, Cp) if self.resampleT.get() > 0: B = InterpolatedUnivariateSpline(t, Cp, k=1) t = np.arange(np.min(t), np.max(t) + self.resampleT.get(), self.resampleT.get()) Cp = B(t) # Calculate AUC0t AUC0t = calculateAUC0t(t, Cp) # Deconvolve if self.externalIV.get() == self.SAME_INPUT: sampleFrom = sample Cl = float(sampleFrom.descriptors['Cl']) V = float(sampleFrom.descriptors['V']) Ke = Cl / V AUC0inf = float(AUC0t[-1]) + self.estimateAUCrightTail( t, Cp, Cl, V) A = (Cp + Ke * AUC0t) / Ke if self.normalize.get(): A *= 100 / AUC0inf if self.saturate.get(): A = np.clip(A, None, 100.0) A = np.clip(A, 0, None) if self.smooth: if t[0] > 0: t = np.insert(t, 0, 0) A = np.insert(A, 0, 0) if self.saturate.get() and self.normalize.get(): A = np.clip(A, None, 100.0) A = np.clip(smoothPchip(t, A), 0, None) if self.saturate.get() and self.normalize.get(): A = np.clip(A, None, 100.0) if self.considerBioaval.get() == self.BIOAVAIL_DIV: A /= sample.getBioavailability() elif self.considerBioaval.get() == self.BIOAVAIL_MULT: A *= sample.getBioavailability() self.addSample(sampleName, t, A) self.outputExperiment.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputExperiment.get(), self.outputExperiment) def _validate(self): retval = [] if self.externalIV.get() == self.ANOTHER_INPUT: sample = self.readExperiment(self.externalIVODE.get( ).outputExperiment.fnPKPD).getFirstSample() else: sample = self.readExperiment( self.inputExperiment.get().fnPKPD).getFirstSample() if sample is None: reval.append('Cannot find a sample in the input experiment') else: if sample.getDescriptorValue('Cl') is None: retval.append('Cannot find Cl in the input experiment') if sample.getDescriptorValue('V') is None: retval.append('Cannot find V in the input experiment') return retval def _summary(self): retval = [] return retval
class ProtPKPDDissolutionSimulate(ProtPKPD): """ Simulate a dissolution profile\n Protocol created by http://www.kinestatpharma.com\n""" _label = 'simulate dissolution' # --------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'allowTlag', params.BooleanParam, label="Allow lag", default=False, help='Allow lag time before starting dissolution (t-tlag)') form.addParam('modelType', params.EnumParam, choices=["Zero order", "First order", "Fractional", "Weibull", "Double Weibull", "Triple Weibull", "Higuchi", "Korsmeyer-Peppas", "Hixson-Crowell", "Hopfenberg", "Hill", "Makoid-Banakar", "Splines2", "Splines3", "Splines4", "Spline5", "Splines6", "Splines7", "Splines8", "Splines9", "Splines10"], label="Dissolution model", default=3, help='Zero order: Y=K*(t-[tlag])\n' \ 'First order: Y=Ymax*(1-exp(-beta*(t-[tlag])))\n' \ 'Fractional order: Y=Ymax-pow(Ymax^alpha-alpha*beta*t,1/alpha))\n' \ 'Weibull: Y=Ymax*(1-exp(-lambda*t^b))\n' \ 'Double Weibull: Y=Ymax*(F1*(1-exp(-lambda1*t^b1))+(1-F1)*(1-exp(-lambda2*(t-tlag2)^b2)))\n' \ 'Triple Weibull: Y=Ymax*(F1*(1-exp(-lambda1*t^b1))+F2*(1-exp(-lambda2*(t-tlag2)^b2))+(1-F1-F2)*(1-exp(-lambda3*(t-tlag3)^b3)))\n' \ 'Higuchi: Y=Ymax*t^0.5\n' \ 'Korsmeyer-Peppas: Y=Ymax*t^m\n' \ 'Hixson-Crowell: Y=Ymax*(1-(1-K*t)^3)\n' 'Hopfenberg: Y=Ymax*(1-(1-K*t)^m)\n' 'Hill: Y = Ymax*t^d/(g^d+t^d)\n' 'Makoid-Banakar: Ymax*(t/tmax)^b*exp(b*(1-t/tmax))\n' 'SplinesN: Y= Ymax*Bspline(t;N,tmax)\n') form.addParam( 'parameters', params.StringParam, label="Parameters", default="", help= 'Parameter values for the simulation.\nExample: 2;5 is 2 for the first parameter, 5 for the second parameter\n' 'Zero order: [tlag];K\n' 'First order: [tlag];Ymax;beta\n' 'Fractional order: [tlag]; Ymax;beta;alpha\n' 'Weibull: [tlag]; Ymax;lambda;b\n' 'Double Weibull: [tlag]; Ymax; lambda1; b1; F1; tlag2; lambda2; b2\n' 'Triple Weibull: [tlag]; Ymax; lambda1; b1; F1; tlag2; lambda2; b2; F2; tlag3; lambda3; b3\n' 'Higuchi: [tlag]; Ymax\n' 'Korsmeyer-Peppas: [tlag]; Ymax; m\n' 'Hixson-Crowell: [tlag]; Ymax; K\n' 'Hopfenberg: [tlag]; Ymax; K; m\n' 'Hill: [tlag]; Ymax; g; d\n' 'Makoid-Banakar: [tlag]; Ymax; Tmax; b\n' 'SplinesN: [tlag]; Ymax; tmax; c1; c2; ...; cN\n') form.addParam('timeUnits', params.EnumParam, choices=["min", "h"], label="Time units", default=0) form.addParam('resampleT', params.FloatParam, label='Simulation model time step=', default=1) form.addParam('resampleT0', params.FloatParam, label='Initial time for simulation', default=0) form.addParam('resampleTF', params.FloatParam, label='Final time for simulation', default=100) form.addParam('AUnits', params.StringParam, label="Dissolution units", default="%", help="%, mg/dL, ...") 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') # --------------------------- STEPS functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('runSimulate') self._insertFunctionStep('createOutputStep') 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)) def runSimulate(self): tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME if self.timeUnits.get() == 0: tvar.units = createUnit("min") elif self.timeUnits.get() == 1: tvar.units = createUnit("h") Avar = PKPDVariable() Avar.varName = "A" Avar.varType = PKPDVariable.TYPE_NUMERIC Avar.role = PKPDVariable.ROLE_MEASUREMENT if self.AUnits.get() != "%": Avar.units = createUnit(self.AUnits.get()) else: Avar.units = createUnit("none") self.experimentSimulated = PKPDExperiment() self.experimentSimulated.variables["t"] = tvar self.experimentSimulated.variables["A"] = Avar self.experimentSimulated.general[ "title"] = "Simulated dissolution profile" self.experimentSimulated.general["comment"] = "" if self.modelType.get() == 0: self.model = Dissolution0() elif self.modelType.get() == 1: self.model = Dissolution1() elif self.modelType.get() == 2: self.model = DissolutionAlpha() elif self.modelType.get() == 3: self.model = DissolutionWeibull() elif self.modelType.get() == 4: self.model = DissolutionDoubleWeibull() elif self.modelType.get() == 5: self.model = DissolutionTripleWeibull() elif self.modelType.get() == 6: self.model = DissolutionHiguchi() elif self.modelType.get() == 7: self.model = DissolutionKorsmeyer() elif self.modelType.get() == 8: self.model = DissolutionHixson() elif self.modelType.get() == 9: self.model = DissolutionHopfenberg() elif self.modelType.get() == 10: self.model = DissolutionHill() elif self.modelType.get() == 11: self.model = DissolutionMakoidBanakar() elif self.modelType.get() == 12: self.model = DissolutionSplines2() elif self.modelType.get() == 13: self.model = DissolutionSplines3() elif self.modelType.get() == 14: self.model = DissolutionSplines4() elif self.modelType.get() == 15: self.model = DissolutionSplines5() elif self.modelType.get() == 16: self.model = DissolutionSplines6() elif self.modelType.get() == 17: self.model = DissolutionSplines7() elif self.modelType.get() == 18: self.model = DissolutionSplines8() elif self.modelType.get() == 19: self.model = DissolutionSplines9() elif self.modelType.get() == 20: self.model = DissolutionSplines10() self.model.allowTlag = self.allowTlag.get() self.model.parameters = [ float(x) for x in self.parameters.get().split(';') ] newSample = PKPDSample() newSample.sampleName = "simulatedProfile" newSample.variableDictPtr = self.experimentSimulated.variables newSample.descriptors = {} newSample.addMeasurementPattern(["A"]) t0 = self.resampleT0.get() tF = self.resampleTF.get() deltaT = self.resampleT.get() t = np.arange(t0, tF + deltaT, deltaT) self.model.setExperiment(self.experimentSimulated) self.model.setXVar("t") self.model.setYVar("A") self.model.calculateParameterUnits(newSample) y = self.model.forwardModel(self.model.parameters, t) newSample.addMeasurementColumn("t", t) newSample.addMeasurementColumn("A", y[0]) self.experimentSimulated.samples[newSample.sampleName] = newSample fnExperiment = self._getPath("experimentSimulated.pkpd") self.experimentSimulated.write(fnExperiment) self.fittingSimulated = PKPDFitting() self.fittingSimulated.fnExperiment.set(fnExperiment) self.fittingSimulated.predictor = self.experimentSimulated.variables[ "t"] self.fittingSimulated.predicted = self.experimentSimulated.variables[ "A"] self.fittingSimulated.modelDescription = self.model.getDescription() self.fittingSimulated.modelParameters = self.model.getParameterNames() self.fittingSimulated.modelParameterUnits = self.model.parameterUnits sampleFit = PKPDSampleFit() sampleFit.sampleName = newSample.sampleName sampleFit.x = [t] sampleFit.y = y sampleFit.yp = y sampleFit.yl = y sampleFit.yu = y sampleFit.parameters = self.model.parameters sampleFit.modelEquation = self.model.getEquation() sampleFit.R2 = -1 sampleFit.R2adj = -1 sampleFit.AIC = -1 sampleFit.AICc = -1 sampleFit.BIC = -1 sampleFit.significance = ["NA" for prm in sampleFit.parameters] sampleFit.lowerBound = ["NA" for prm in sampleFit.parameters] sampleFit.upperBound = ["NA" for prm in sampleFit.parameters] self.fittingSimulated.sampleFits.append(sampleFit) fnFitting = self._getPath("fittingSimulated.pkpd") self.fittingSimulated.write(fnFitting) def createOutputStep(self): self._defineOutputs(outputExperiment=self.experimentSimulated) self._defineOutputs(outputFitting=self.fittingSimulated)
class ProtPKPDDeconvolve(ProtPKPDODEBase): """ Deconvolve the drug dissolution from a compartmental model.""" _label = 'dissol deconv' BIOAVAIL_NONE = 0 BIOAVAIL_MULT = 1 BIOAVAIL_DIV = 2 #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputODE', params.PointerParam, label="Input ODE model", pointerClass='ProtPKPDMonoCompartment, ProtPKPDTwoCompartments,ProtPKPDODERefine,'\ ' ProtPKPDTwoCompartmentsClint, ProtPKPDTwoCompartmentsClintCl', help='Select a run of an ODE model') form.addParam('normalize', params.BooleanParam, label="Normalize by dose", default=True, help='Normalize the output by the input dose, so that a total absorption is represented by 100.') form.addParam('considerBioaval', params.EnumParam, label="Consider bioavailability", default=self.BIOAVAIL_NONE, choices=['Do not correct','Multiply deconvolution by bioavailability','Divide deconvolution by bioavailability'], help='Take into account the bioavailability') form.addParam('saturate', params.BooleanParam, label="Saturate at 100%", default=True, condition='normalize', help='Saturate the absorption so that there cannot be values beyond 100') form.addParam('removeTlag', params.BooleanParam, label="Remove tlag effect", default=True, help='If set to True, then the deconvolution is performed ignoring the the tlag in the absorption.' 'This homogeneizes the different responses.') #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('deconvolve',self.inputODE.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addSample(self, sampleName, t, y): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.descriptors = {} newSample.addMeasurementPattern(["A"]) tUnique, yUnique = twoWayUniqueFloatValues(t,y) newSample.addMeasurementColumn("t", tUnique) newSample.addMeasurementColumn("A",yUnique) self.outputExperiment.samples[sampleName] = newSample def deconvolve(self, objId): self.protODE = self.inputODE.get() self.experiment = self.readExperiment(self.protODE.outputExperiment.fnPKPD) self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting) self.varNameX = self.fitting.predictor.varName self.varNameY = self.fitting.predicted.varName # Create drug source self.clearGroupParameters() self.createDrugSource() # Create output object self.outputExperiment = PKPDExperiment() tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(self.experiment.getTimeUnits().unit) Avar = PKPDVariable() Avar.varName = "A" Avar.varType = PKPDVariable.TYPE_NUMERIC Avar.role = PKPDVariable.ROLE_MEASUREMENT if self.normalize.get(): Avar.units = createUnit("none") else: Avar.units = createUnit(self.experiment.getDoseUnits()) self.outputExperiment.variables[tvar.varName] = tvar self.outputExperiment.variables[Avar.varName] = Avar self.outputExperiment.general["title"]="Deconvolution of the amount released" self.outputExperiment.general["comment"]="Amount released at any time t" # Simulate the different responses timeRange = self.experiment.getRange(self.varNameX) deltaT = 0.5 t = np.arange(0.0,timeRange[1],deltaT) for sampleName, sample in self.experiment.samples.items(): self.printSection("Deconvolving "+sampleName) sample.interpretDose() drugSource = DrugSource() drugSource.setDoses(sample.parsedDoseList, 0.0, timeRange[1]) p=[] tlag=0 for paramName in drugSource.getParameterNames(): p.append(float(sample.getDescriptorValue(paramName))) if paramName.endswith('_tlag') and self.removeTlag.get(): tlag=float(sample.getDescriptorValue(paramName)) drugSource.setParameters(p) cumulatedDose=0.0 A=t*0.0 # Allocate memory totalReleased = drugSource.getAmountReleasedUpTo(10*t[-1]) print("t(min) A(%s)"%Avar.units._toString()) for i in range(t.size): cumulatedDose+=drugSource.getAmountReleasedAt(t[i],deltaT) A[i]=cumulatedDose if self.normalize.get(): A[i] *= 100.0/totalReleased print("%f %f"%(t[i],A[i])) # print("%f %f %f %f"%(t[i], A[i], drugSource.getAmountReleasedAt(t[i], 0.5), drugSource.getAmountReleasedUpTo(t[i] + 0.5))) if self.saturate.get() and self.normalize.get(): A = np.clip(A,None,100.0) if self.considerBioaval.get()==self.BIOAVAIL_DIV: A /= sample.getBioavailability() elif self.considerBioaval.get()==self.BIOAVAIL_MULT: A *= sample.getBioavailability() self.addSample(sampleName,t-tlag,A) self.outputExperiment.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputODE.get(), self.outputExperiment) def _validate(self): return [] def _summary(self): return []
class ProtPKPDODESimulate2(ProtPKPDODEBase): """ Simulate a complex sequence of doses. Each dose has its own PK profile, and the overall profile is the addition of all the individual profiles. Only the parameters from the first fitting of each model are considered. The first dose goes with the first model, the second dose with the second model, ... A single profile is simulated that is the addition of the different simulations for each one of the input models.""" _label = 'PK simulate (complex)' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputODEs', params.MultiPointerParam, label="Input ODE models", pointerClass='ProtPKPDMonoCompartment, ProtPKPDTwoCompartments, ProtPKPDMonoCompartmentPD, ProtPKPDTwoCompartmentsBothPD, '\ 'ProtPKPDODERefine, ProtPKPDTwoCompartmentsClint, ProtPKPDTwoCompartmentsClintCl', help='Select a run of an ODE model') form.addParam('doses', params.TextParam, label="Doses", height=5, width=50, default="", help="Structure: [Dose Name] ; [Via] ; [Dose type] ; [time] ; [dose] \n"\ "The dose name should have no space or special character\n"\ "The via should be one present in the input experiment to the ODE model.\n"\ "Valid units are: h, mg, ug, ...\n"\ "The description is either a bolus or an infusion as shown in the examples\n"\ "\nIt is important that there are two semicolons.\n"\ "Examples:\n"\ "Infusion0; via=Intravenous; infusion; t=0.500000:0.750000 h; d=60 mg/h\n"\ "Bolus0; via=Oral; bolus; t=0.000000 min; d=60 mg\n"\ "RepeatedBolus; via=Oral; repeated_bolus; t=0:24:120 h; d=60 mg") form.addParam('t0', params.FloatParam, label="Initial time (see help)", default=0, help="Same units as input experiment") form.addParam('tF', params.FloatParam, label="Final time (see help)", default=24 * 7, help="Same units as input experiment") form.addParam('deltaT', params.FloatParam, label="Time step (see help)", default=0.5, expertLevel=LEVEL_ADVANCED, help="Same units as input experiment") #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('runSimulate') self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addSample(self, sampleName, doseList, simulationsX, y): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.doseDictPtr = self.outputExperiment.doses newSample.descriptors = {} newSample.doseList = doseList if type(self.varNameY) != list: newSample.addMeasurementPattern([self.varNameY]) newSample.addMeasurementColumn("t", simulationsX) newSample.addMeasurementColumn(self.varNameY, y) else: for j in range(len(self.varNameY)): newSample.addMeasurementPattern([self.varNameY[j]]) newSample.addMeasurementColumn("t", simulationsX) for j in range(len(self.varNameY)): newSample.addMeasurementColumn(self.varNameY[j], y[j]) self.outputExperiment.samples[sampleName] = newSample def runSimulate(self): # Take first experiment self.protODE = self.inputODEs[0].get() if hasattr(self.protODE, "outputExperiment"): self.experiment = self.readExperiment( self.protODE.outputExperiment.fnPKPD, show=False) elif hasattr(self.protODE, "outputExperiment1"): self.experiment = self.readExperiment( self.protODE.outputExperiment1.fnPKPD, show=False) else: raise Exception("Cannot find an outputExperiment in the input ODE") if hasattr(self.protODE, "outputFitting"): self.fitting = self.readFitting( self.protODE.outputFitting.fnFitting, show=False) elif hasattr(self.protODE, "outputFitting1"): self.fitting = self.readFitting( self.protODE.outputFitting1.fnFitting, show=False) self.varNameX = self.fitting.predictor.varName if type(self.fitting.predicted) != list: self.varNameY = self.fitting.predicted.varName else: self.varNameY = [var.varName for var in self.fitting.predicted] # Create output object self.outputExperiment = PKPDExperiment() tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(self.experiment.getTimeUnits().unit) Nsamples = int( math.ceil((self.tF.get() - self.t0.get()) / self.deltaT.get())) + 1 if tvar.units == PKPDUnit.UNIT_TIME_MIN: Nsamples *= 60 self.outputExperiment.variables[self.varNameX] = tvar if type(self.fitting.predicted) != list: self.outputExperiment.variables[ self.varNameY] = self.experiment.variables[self.varNameY] else: for varName in self.varNameY: self.outputExperiment.variables[ varName] = self.experiment.variables[varName] self.outputExperiment.general["title"] = "Simulated ODE response" self.outputExperiment.general["comment"] = "Simulated ODE response" self.outputExperiment.vias = self.experiment.vias # Read the doses doseLines = [] for line in self.doses.get().replace('\n', ';;').split(';;'): doseLines.append(line) doseIdx = 0 simulationsY = None doseList = [] for protODEPtr in self.inputODEs: self.protODE = protODEPtr.get() if hasattr(self.protODE, "outputExperiment"): self.experiment = self.readExperiment( self.protODE.outputExperiment.fnPKPD, show=False) elif hasattr(self.protODE, "outputExperiment1"): self.experiment = self.readExperiment( self.protODE.outputExperiment1.fnPKPD, show=False) else: raise Exception( "Cannot find an outputExperiment in the input ODE") if hasattr(self.protODE, "outputFitting"): self.fitting = self.readFitting( self.protODE.outputFitting.fnFitting, show=False) elif hasattr(self.protODE, "outputFitting1"): self.fitting = self.readFitting( self.protODE.outputFitting1.fnFitting, show=False) for viaName in self.experiment.vias: if not viaName in self.outputExperiment.vias: self.outputExperiment.vias[viaName] = copy.copy( self.experiment.vias[viaName]) # Create drug source self.clearGroupParameters() self.createDrugSource() # Setup model self.model = self.protODE.createModel() self.model.setExperiment(self.outputExperiment) self.model.deltaT = self.deltaT.get() self.model.setXVar(self.varNameX) self.model.setYVar(self.varNameY) self.model.x = [ self.t0.get() + i * self.model.deltaT for i in range(0, Nsamples) ] self.modelList.append(self.model) tokens = doseLines[doseIdx].split(';') if len(tokens) < 5: print("Skipping dose: ", line) continue dosename = tokens[0].strip() self.outputExperiment.doses[dosename] = PKPDDose() self.outputExperiment.doses[dosename].parseTokens( tokens, self.outputExperiment.vias) doseList.append(dosename) auxSample = PKPDSample() auxSample.descriptors = {} auxSample.doseDictPtr = self.outputExperiment.doses auxSample.variableDictPtr = self.outputExperiment.variables auxSample.doseList = [dosename] auxSample.interpretDose() self.drugSource.setDoses(auxSample.parsedDoseList, self.t0.get() - 10, self.tF.get() + 10) self.model.drugSource = self.drugSource # Simulate the different responses simulationsX = self.model.x self.setTimeRange(None) parameters = self.fitting.sampleFits[0].parameters print("Input model: %s" % self.protODE.getObjLabel()) print("Sample name: %s" % self.fitting.sampleFits[0].sampleName) print("Parameters: ", parameters) print("Dose: %s" % doseLines[doseIdx]) print(" ") # Prepare source and this object self.protODE.configureSource(self.drugSource) parameterNames = self.getParameterNames( ) # Necessary to count the number of source and PK parameters # Prepare the model y = self.forwardModel(parameters, [simulationsX] * self.getResponseDimension()) # Keep results if simulationsY is None: simulationsY = copy.copy(y) else: for j in range(self.getResponseDimension()): simulationsY[j] += y[j] doseIdx += 1 self.addSample("Simulation", doseList, simulationsX, simulationsY[0]) self.outputExperiment.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) for protODEPtr in self.inputODEs: self._defineSourceRelation(protODEPtr.get(), self.outputExperiment) #--------------------------- INFO functions -------------------------------------------- def _summary(self): msg = [] return msg def _validate(self): msg = [] return msg
class ProtPKPDODESimulate(ProtPKPDODEBase): """ Simulate a population of ODE parameters. These parameters can be specifically given, from a bootstrap population, a previous fitting, or an experiment. AUC0t and AUMC0t are referred to each dose (that is, t=0 is the beginning of the dose). Ctau is the concentration at the end of the dose. Tmin, Tmax, and Ttau are referred to the beginning of the dose. This protocol writes an Excel file (nca.xlsx) in which all the simulations and doses are written.""" _label = 'PK simulate' PRM_POPULATION = 0 PRM_USER_DEFINED = 1 PRM_FITTING = 2 PRM_EXPERIMENT = 3 SRC_ODE = 0 SRC_LIST = 1 VIATYPE_IV = 0 VIATYPE_EV0 = 1 VIATYPE_EV1 = 2 PKTYPE_COMP1 = 0 PKTYPE_COMP2 = 1 PKTYPE_COMP2CLCLINT = 2 #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'odeSource', params.EnumParam, label='Source of ODE type', choices=['A previous PK fit', 'List'], default=self.SRC_ODE, help= 'The input model is used to define the absorbtion via and the type of distribution and elimination. ' 'Its parameters are not important, only its types') form.addParam('inputODE', params.PointerParam, label="Input ODE model", condition='odeSource==0', pointerClass='ProtPKPDMonoCompartment, ProtPKPDTwoCompartments, ProtPKPDMonoCompartmentPD, ProtPKPDTwoCompartmentsBothPD, '\ 'ProtPKPDODERefine, ProtPKPDTwoCompartmentsClint, ProtPKPDTwoCompartmentsClintCl', help='Select a run of an ODE model. This input is used to learn the kind of model that is needed. The parameters are ' 'taken from the sources below') form.addParam('viaType', params.EnumParam, label='Input via', condition='odeSource==1', default=0, choices=[ 'Intravenous (iv)', 'Extra vascular, 0th order absorption (ev0)', 'Extra vascular, 1st order absorption (ev1)' ], help='Parameters:\n' 'iv (vianame=Intravenous): no parameters\n' 'ev0 (vianame=Oral): Rin, tlag, F (bioavailability)\n' 'ev1 (vianame=Oral): Ka, tlag, F (bioavailability)\n') form.addParam( 'viaPrm', params.TextParam, label="Via parameters", height=8, default="", condition="odeSource==1", help= 'Specify the parameters for the via separated by commas. Example: \n' 'prm1, prm2, prm3\n' '\n' 'Parameters:\n' 'iv: no parameters\n' 'ev0: Rin, tlag, F (bioavailability)\n' 'ev1: Ka, tlag, F (bioavailability)\n') form.addParam('pkType', params.EnumParam, label='PK model', condition='odeSource==1', default=0, choices=[ '1 compartment', '2 compartments', '2 compartments Cl+Clint' ], help='Parameters:\n' '1 compartment: Cl, V\n' '2 compartments: Cl, V, Clp, Vp\n' '2 compartments Cl+Clint: Vmax, Km, Cl, V, Clp, Vp\n') form.addParam('timeUnits', params.StringParam, label='Time units', default='min', condition="odeSource==1", help='min or h') form.addParam('volumeUnits', params.StringParam, label='Volume units', default='L', condition="odeSource==1", help='mL or L') form.addParam( 'paramsSource', params.EnumParam, label="Source of parameters", condition="odeSource==0", choices=[ 'ODE Bootstrap', 'User defined', 'ODE Fitting', 'Experiment' ], default=0, help= "Choose a population of parameters, your own parameters or a previously fitted set of measurements" ) form.addParam( 'inputPopulation', params.PointerParam, label="Input population", condition="paramsSource==0 and odeSource==0", pointerClass='PKPDFitting', pointerCondition="isPopulation", help='It must be a fitting coming from a bootstrap sample') form.addParam( 'prmUser', params.TextParam, label="Simulation parameters", height=8, default="", condition="paramsSource==1 or odeSource==1", help= 'Specify the parameters for the simulation separated by commas. ' 'The parameters must be written in the same order as they are written by the protocol ' 'that generated the ODE model. Example: \n' 'prm1, prm2, prm3, prm4\n' 'prmA, prmB, prmC, prmD\n' '\n' 'If the parameters are not taken from a previous ODE:\n' '1 compartment: Cl, V\n' '2 compartments: Cl, V, Clp, Vp\n' '2 compartments Cl+Clint: Vmax, Km, Cl, V, Clp, Vp\n') form.addParam( 'inputFitting', params.PointerParam, label="Input ODE fitting", condition="paramsSource==2 and odeSource==0", pointerClass='PKPDFitting', help='It must be a fitting coming from a compartmental PK fitting') form.addParam( 'inputExperiment', params.PointerParam, label="Input experiment", condition="paramsSource==3 and odeSource==0", pointerClass='PKPDExperiment', help= 'It must contain the parameters required for the simulation (Cl, V, Clp, Vp, ...)' ) form.addParam('doses', params.TextParam, label="Doses", height=5, width=50, default="RepeatedBolus ; via=Oral; repeated_bolus; t=0:24:120 h; d=60 mg", help="Structure: [Dose Name] ; [Via] ; [Dose type] ; [time] ; [dose] \n"\ "The dose name should have no space or special character\n"\ "The via should be one present in the input experiment to the ODE model.\n"\ "Valid units are: h, mg, ug, ...\n"\ "The description is either a bolus or an infusion as shown in the examples\n"\ "\nIt is important that there are two semicolons.\n"\ "Examples:\n"\ "Infusion0; via=Intravenous; infusion; t=0.500000:0.750000 h; d=60 mg/h\n"\ "Bolus0; via=Oral; bolus; t=0.000000 min; d=60 mg\n"\ "RepeatedBolus; via=Oral; repeated_bolus; t=0:24:120 h; d=60 mg") form.addParam('t0', params.FloatParam, label="Initial time (see help)", default=0, help="Same units as input experiment") form.addParam('tF', params.FloatParam, label="Final time (see help)", default=24 * 7, help="Same units as input experiment") form.addParam('sampling', params.FloatParam, label="Sampling time (see help)", default=1, help="Same units as input experiment") form.addParam('Nsimulations', params.IntParam, label="Simulation samples", default=200, condition="paramsSource==0 and odeSource==0", expertLevel=LEVEL_ADVANCED, help='Number of simulations') form.addParam( 'addStats', params.BooleanParam, label="Add simulation statistics", default=True, condition="paramsSource==0 and odeSource==0", expertLevel=LEVEL_ADVANCED, help= "Mean, lower and upper confidence levels are added to the output") form.addParam( 'confidenceLevel', params.FloatParam, label="Confidence interval", default=95, expertLevel=LEVEL_ADVANCED, help='Confidence interval for the fitted parameters', condition="addStats and paramsSource==0 and odeSource==0") form.addParam('addIndividuals', params.BooleanParam, label="Add individual simulations", default=False, expertLevel=LEVEL_ADVANCED, help="Individual simulations are added to the output") #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('runSimulate', self.Nsimulations.get(), self.confidenceLevel.get(), self.doses.get()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addSample(self, sampleName, doseName, simulationsX, y): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.doseDictPtr = self.outputExperiment.doses newSample.descriptors = {} newSample.doseList = [doseName] tsample = np.arange(0.0, np.max(simulationsX), self.sampling.get()) if type(self.varNameY) != list: newSample.addMeasurementPattern([self.varNameY]) B = InterpolatedUnivariateSpline(simulationsX, y, k=1) newSample.addMeasurementColumn("t", tsample) newSample.addMeasurementColumn(self.varNameY, B(tsample)) else: for j in range(len(self.varNameY)): newSample.addMeasurementPattern([self.varNameY[j]]) newSample.addMeasurementColumn("t", tsample) for j in range(len(self.varNameY)): B = InterpolatedUnivariateSpline(simulationsX, y[j], k=1) newSample.addMeasurementColumn(self.varNameY[j], B(tsample)) newSample.descriptors["FromSample"] = self.fromSample newSample.descriptors["AUC0t"] = self.AUC0t newSample.descriptors["AUMC0t"] = self.AUMC0t newSample.descriptors["MRT"] = self.MRT newSample.descriptors["Cmax"] = self.Cmax newSample.descriptors["Cmin"] = self.Cmin newSample.descriptors["Cavg"] = self.Cavg newSample.descriptors["Tmax"] = self.Tmax newSample.descriptors["Tmin"] = self.Tmin self.outputExperiment.samples[sampleName] = newSample def NCA(self, t, C): AUClist = [] AUMClist = [] Cminlist = [] Cavglist = [] Cmaxlist = [] Ctaulist = [] Tmaxlist = [] Tminlist = [] Ttaulist = [] Ndoses = len(self.drugSource.parsedDoseList) for ndose in range(0, max(Ndoses, 1)): tperiod0 = self.drugSource.parsedDoseList[ndose].t0 if ndose + 1 < Ndoses: tperiodF = self.drugSource.parsedDoseList[ ndose + 1].t0 - self.model.deltaT else: tperiodF = np.max(t) - 1 idx0 = find_nearest(t, tperiod0) idxF = find_nearest(t, tperiodF) if idxF >= len(t) - 1: idxF = len(t) - 2 AUC0t = 0 AUMC0t = 0 t0 = t[idx0 + 1] for idx in range(idx0, idxF + 1): dt = (t[idx + 1] - t[idx]) if C[idx + 1] >= C[idx]: # Trapezoidal in the raise AUC0t += 0.5 * dt * (C[idx] + C[idx + 1]) AUMC0t += 0.5 * dt * (C[idx] * t[idx] + C[idx + 1] * t[idx + 1]) else: # Log-trapezoidal in the decay decrement = C[idx] / C[idx + 1] K = math.log(decrement) B = K / dt AUC0t += dt * (C[idx] - C[idx + 1]) / K AUMC0t += (C[idx] * (t[idx] - tperiod0) - C[idx + 1] * (t[idx + 1] - tperiod0)) / B - ( C[idx + 1] - C[idx]) / (B * B) if idx == idx0: Cmax = C[idx] Tmax = t[idx] - t0 Cmin = C[idx] Tmin = t[idx] - t0 else: if C[idx] < Cmin: Cmin = C[idx] Tmin = t[idx] - t0 elif C[idx] > Cmax: Cmax = C[idx] Tmax = t[idx] - t0 # if ndose==0: # Cmin=C[idx] # Tmin=t[idx]-t0 AUClist.append(AUC0t) AUMClist.append(AUMC0t) Cminlist.append(Cmin) Cmaxlist.append(Cmax) Ctaulist.append(C[idxF]) Ttaulist.append(t[idxF] - t0) Tmaxlist.append(Tmax) Tminlist.append(Tmin) Cavglist.append(AUC0t / (t[idxF] - t[idx0])) print("Fluctuation = Cmax/Cmin") print("Accumulation(1) = Cavg(n)/Cavg(1) %") print("Accumulation(n) = Cavg(n)/Cavg(n-1) %") print("Steady state fraction(n) = Cavg(n)/Cavg(last) %") for ndose in range(0, len(AUClist)): if Cminlist[ndose] != 0: fluctuation = Cmaxlist[ndose] / Cminlist[ndose] else: fluctuation = np.nan if ndose > 0: accumn = Cavglist[ndose] / Cavglist[ndose - 1] else: accumn = 0 print("Dose #%d t=[%f,%f]: Cavg= %f [%s] Cmin= %f [%s] Tmin= %d [%s] Cmax= %f [%s] Tmax= %d [%s] Ctau= %f [%s] Ttau= %d [%s] Fluct= %f %% Accum(1)= %f %% Accum(n)= %f %% SSFrac(n)= %f %% AUC= %f [%s] AUMC= %f [%s]"%\ (ndose+1,t[idx0],t[idxF],Cavglist[ndose], strUnit(self.Cunits.unit), Cminlist[ndose], strUnit(self.Cunits.unit), int(Tminlist[ndose]), strUnit(self.outputExperiment.getTimeUnits().unit), Cmaxlist[ndose], strUnit(self.Cunits.unit), int(Tmaxlist[ndose]), strUnit(self.outputExperiment.getTimeUnits().unit), Ctaulist[ndose], strUnit(self.Cunits.unit), int(Ttaulist[ndose]), strUnit(self.outputExperiment.getTimeUnits().unit), fluctuation*100, Cavglist[ndose]/Cavglist[0]*100, accumn*100, Cavglist[ndose]/Cavglist[-1]*100, AUClist[ndose],strUnit(self.AUCunits), AUMClist[ndose],strUnit(self.AUMCunits))) self.AUC0t = float(AUClist[-1]) self.AUMC0t = float(AUMClist[-1]) self.MRT = self.AUMC0t / self.AUC0t self.Cmin = float(Cminlist[-1]) self.Cmax = float(Cmaxlist[-1]) self.Tmin = float(Tminlist[-1]) self.Tmax = float(Tmaxlist[-1]) self.Cavg = float(Cavglist[-1]) self.Ctau = float(Ctaulist[-1]) self.Ttau = float(Ttaulist[-1]) self.fluctuation = self.Cmax / self.Cmin if self.Cmin > 0 else np.nan self.percentageAccumulation = Cavglist[-1] / Cavglist[0] if Cavglist[ 0] > 0 else np.nan print(" AUC0t=%f [%s]" % (self.AUC0t, strUnit(self.AUCunits))) print(" AUMC0t=%f [%s]" % (self.AUMC0t, strUnit(self.AUMCunits))) print(" MRT=%f [%s]" % (self.MRT, strUnit(self.outputExperiment.getTimeUnits().unit))) print(" Cmax=%f [%s]" % (self.Cmax, strUnit(self.Cunits.unit))) print(" Cmin=%f [%s]" % (self.Cmin, strUnit(self.Cunits.unit))) print(" Cavg=%f [%s]" % (self.Cavg, strUnit(self.Cunits.unit))) print(" Ctau=%f [%s]" % (self.Ctau, strUnit(self.Cunits.unit))) print(" Tmax=%f [%s]" % (self.Tmax, strUnit(self.outputExperiment.getTimeUnits().unit))) print(" Tmin=%f [%s]" % (self.Tmin, strUnit(self.outputExperiment.getTimeUnits().unit))) print(" Ttau=%f [%s]" % (self.Ttau, strUnit(self.outputExperiment.getTimeUnits().unit))) return AUClist, AUMClist, Cminlist, Cavglist, Cmaxlist, Ctaulist, Tmaxlist, Tminlist, Ttaulist def runSimulate(self, Nsimulations, confidenceInterval, doses): if self.odeSource.get() == self.SRC_ODE: self.protODE = self.inputODE.get() if hasattr(self.protODE, "outputExperiment"): self.experiment = self.readExperiment( self.protODE.outputExperiment.fnPKPD) elif hasattr(self.protODE, "outputExperiment1"): self.experiment = self.readExperiment( self.protODE.outputExperiment1.fnPKPD) else: raise Exception( "Cannot find an outputExperiment in the input ODE") if self.paramsSource.get() == ProtPKPDODESimulate.PRM_POPULATION: self.fitting = self.readFitting( self.inputPopulation.get().fnFitting, cls="PKPDSampleFitBootstrap") elif self.paramsSource.get() == ProtPKPDODESimulate.PRM_FITTING: self.fitting = self.readFitting( self.inputFitting.get().fnFitting) else: # User defined or experiment if hasattr(self.protODE, "outputFitting"): self.fitting = self.readFitting( self.protODE.outputFitting.fnFitting) elif hasattr(self.protODE, "outputFitting1"): self.fitting = self.readFitting( self.protODE.outputFitting1.fnFitting) self.varNameX = self.fitting.predictor.varName if type(self.fitting.predicted) != list: self.varNameY = self.fitting.predicted.varName else: self.varNameY = [var.varName for var in self.fitting.predicted] tunits = self.experiment.getTimeUnits().unit else: self.varNameX = 't' self.varNameY = 'C' self.fitting = None self.experiment = None self.protODE = None tunits = unitFromString(self.timeUnits.get()) # Create drug source self.clearGroupParameters() self.createDrugSource() # Create output object self.outputExperiment = PKPDExperiment() self.outputExperiment.general["title"] = "Simulated ODE response" self.outputExperiment.general["comment"] = "Simulated ODE response" # Create the predictor variable tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(tunits) self.outputExperiment.variables[self.varNameX] = tvar # Vias if self.odeSource.get() == self.SRC_ODE: self.outputExperiment.vias = self.experiment.vias else: # "[ViaName]; [ViaType]; [tlag]; [bioavailability]" viaPrmList = [ token for token in self.viaPrm.get().strip().split(',') ] if self.viaType.get() == self.VIATYPE_IV: tokens = [ "Intravenous", "iv", "tlag=0 min", "bioavailability=1" ] elif self.viaType.get() == self.VIATYPE_EV0: tokens = ["Oral", "ev0"] + [ "tlag=" + viaPrmList[-2].strip() + " " + self.timeUnits.get() ] + ["bioavailability=" + viaPrmList[-1].strip()] elif self.viaType.get() == self.VIATYPE_EV1: tokens = ["Oral", "ev1"] + [ "tlag=" + viaPrmList[-2].strip() + " " + self.timeUnits.get() ] + ["bioavailability=" + viaPrmList[-1].strip()] vianame = tokens[0] self.outputExperiment.vias[vianame] = PKPDVia( ptrExperiment=self.outputExperiment) self.outputExperiment.vias[vianame].parseTokens(tokens) # Read the doses dunits = PKPDUnit.UNIT_NONE for line in self.doses.get().replace('\n', ';;').split(';;'): tokens = line.split(';') if len(tokens) < 5: print("Skipping dose: ", line) continue dosename = tokens[0].strip() self.outputExperiment.doses[dosename] = PKPDDose() self.outputExperiment.doses[dosename].parseTokens( tokens, self.outputExperiment.vias) dunits = self.outputExperiment.doses[dosename].getDoseUnits() # Create predicted variables if self.odeSource.get() == self.SRC_ODE: if type(self.fitting.predicted) != list: self.outputExperiment.variables[ self.varNameY] = self.experiment.variables[self.varNameY] else: for varName in self.varNameY: self.outputExperiment.variables[ varName] = self.experiment.variables[varName] else: Cvar = PKPDVariable() Cvar.varName = "C" Cvar.varType = PKPDVariable.TYPE_NUMERIC Cvar.role = PKPDVariable.ROLE_MEASUREMENT Cvar.units = createUnit( divideUnits(dunits.unit, unitFromString(self.volumeUnits.get()))) self.outputExperiment.variables[self.varNameY] = Cvar # Setup model if self.odeSource.get() == self.SRC_ODE: self.model = self.protODE.createModel() if hasattr(self.protODE, "deltaT"): self.model.deltaT = self.protODE.deltaT.get() else: if self.pkType.get() == self.PKTYPE_COMP1: self.model = PK_Monocompartment() elif self.pkType.get() == self.PKTYPE_COMP2: self.model = PK_Twocompartment() elif self.pkType.get() == self.PKTYPE_COMP2CLCLINT: self.model = PK_TwocompartmentsClintCl() self.model.setExperiment(self.outputExperiment) self.model.setXVar(self.varNameX) self.model.setYVar(self.varNameY) Nsamples = int( math.ceil((self.tF.get() - self.t0.get()) / self.model.deltaT)) + 1 self.model.x = [ self.t0.get() + i * self.model.deltaT for i in range(0, Nsamples) ] self.modelList.append(self.model) auxSample = PKPDSample() auxSample.descriptors = {} auxSample.doseDictPtr = self.outputExperiment.doses auxSample.variableDictPtr = self.outputExperiment.variables auxSample.doseList = self.outputExperiment.doses.keys() auxSample.interpretDose() self.drugSource.setDoses(auxSample.parsedDoseList, self.t0.get() - 10, self.tF.get() + 10) self.model.drugSource = self.drugSource # Check units # Dunits = self.outputExperiment.doses[dosename].dunits # Cunits = self.experiment.variables[self.varNameY].units # Process user parameters if self.odeSource.get() == self.SRC_ODE: if self.paramsSource == ProtPKPDODESimulate.PRM_POPULATION: Nsimulations = self.Nsimulations.get() elif self.paramsSource == ProtPKPDODESimulate.PRM_USER_DEFINED: lines = self.prmUser.get().strip().replace('\n', ';;').split(';;') Nsimulations = len(lines) prmUser = [] for line in lines: tokens = line.strip().split(',') prmUser.append([float(token) for token in tokens]) elif self.paramsSource == ProtPKPDODESimulate.PRM_FITTING: Nsimulations = len(self.fitting.sampleFits) else: self.inputExperiment = self.readExperiment( self.inputExperiment.get().fnPKPD) Nsimulations = len(self.inputExperiment.samples) inputSampleNames = self.inputExperiment.samples.keys() else: lines = self.prmUser.get().strip().replace('\n', ';;').split(';;') Nsimulations = len(lines) prmUser = [] for line in lines: tokens = line.strip().split(',') prmUser.append([float(token) for token in tokens]) # Simulate the different responses simulationsX = self.model.x simulationsY = np.zeros( (Nsimulations, len(simulationsX), self.getResponseDimension())) AUCarray = np.zeros(Nsimulations) AUMCarray = np.zeros(Nsimulations) MRTarray = np.zeros(Nsimulations) CminArray = np.zeros(Nsimulations) CmaxArray = np.zeros(Nsimulations) CavgArray = np.zeros(Nsimulations) CtauArray = np.zeros(Nsimulations) TminArray = np.zeros(Nsimulations) TmaxArray = np.zeros(Nsimulations) TtauArray = np.zeros(Nsimulations) fluctuationArray = np.zeros(Nsimulations) percentageAccumulationArray = np.zeros(Nsimulations) wb = openpyxl.Workbook() wb.active.title = "Simulations" for i in range(0, Nsimulations): self.setTimeRange(None) if self.odeSource.get() == self.SRC_ODE: if self.paramsSource == ProtPKPDODESimulate.PRM_POPULATION: # Take parameters randomly from the population nfit = int(random.uniform(0, len(self.fitting.sampleFits))) sampleFit = self.fitting.sampleFits[nfit] nprm = int(random.uniform(0, sampleFit.parameters.shape[0])) parameters = sampleFit.parameters[nprm, :] self.fromSample = "Population %d" % nprm elif self.paramsSource == ProtPKPDODESimulate.PRM_USER_DEFINED: parameters = np.asarray(prmUser[i], np.double) self.fromSample = "User defined" elif self.paramsSource == ProtPKPDODESimulate.PRM_FITTING: parameters = self.fitting.sampleFits[i].parameters self.fromSample = self.fitting.sampleFits[i].sampleName else: parameters = [] self.fromSample = inputSampleNames[i] sample = self.inputExperiment.samples[self.fromSample] for prmName in self.fitting.modelParameters: parameters.append( float(sample.getDescriptorValue(prmName))) else: parameters = np.asarray(viaPrmList[:-2] + prmUser[i], np.double) self.fromSample = "User defined" print("From sample name: %s" % self.fromSample) print("Simulated sample %d: %s" % (i, str(parameters))) # Prepare source and this object self.drugSource.setDoses(auxSample.parsedDoseList, self.model.t0, self.model.tF) if self.protODE is not None: self.protODE.configureSource(self.drugSource) self.model.drugSource = self.drugSource parameterNames = self.getParameterNames( ) # Necessary to count the number of source and PK parameters # Prepare the model self.setParameters(parameters) y = self.forwardModel(parameters, [simulationsX] * self.getResponseDimension()) # Create AUC, AUMC, MRT variables and units if i == 0: if type(self.varNameY) != list: self.Cunits = self.outputExperiment.variables[ self.varNameY].units else: self.Cunits = self.outputExperiment.variables[ self.varNameY[0]].units self.AUCunits = multiplyUnits(tvar.units.unit, self.Cunits.unit) self.AUMCunits = multiplyUnits(tvar.units.unit, self.AUCunits) if self.addStats or self.addIndividuals: fromvar = PKPDVariable() fromvar.varName = "FromSample" fromvar.varType = PKPDVariable.TYPE_TEXT fromvar.role = PKPDVariable.ROLE_LABEL fromvar.units = createUnit("none") AUCvar = PKPDVariable() AUCvar.varName = "AUC0t" AUCvar.varType = PKPDVariable.TYPE_NUMERIC AUCvar.role = PKPDVariable.ROLE_LABEL AUCvar.units = createUnit(strUnit(self.AUCunits)) AUMCvar = PKPDVariable() AUMCvar.varName = "AUMC0t" AUMCvar.varType = PKPDVariable.TYPE_NUMERIC AUMCvar.role = PKPDVariable.ROLE_LABEL AUMCvar.units = createUnit(strUnit(self.AUMCunits)) MRTvar = PKPDVariable() MRTvar.varName = "MRT" MRTvar.varType = PKPDVariable.TYPE_NUMERIC MRTvar.role = PKPDVariable.ROLE_LABEL MRTvar.units = createUnit( self.outputExperiment.getTimeUnits().unit) Cmaxvar = PKPDVariable() Cmaxvar.varName = "Cmax" Cmaxvar.varType = PKPDVariable.TYPE_NUMERIC Cmaxvar.role = PKPDVariable.ROLE_LABEL Cmaxvar.units = createUnit(strUnit(self.Cunits.unit)) Tmaxvar = PKPDVariable() Tmaxvar.varName = "Tmax" Tmaxvar.varType = PKPDVariable.TYPE_NUMERIC Tmaxvar.role = PKPDVariable.ROLE_LABEL Tmaxvar.units = createUnit( self.outputExperiment.getTimeUnits().unit) Cminvar = PKPDVariable() Cminvar.varName = "Cmin" Cminvar.varType = PKPDVariable.TYPE_NUMERIC Cminvar.role = PKPDVariable.ROLE_LABEL Cminvar.units = createUnit(strUnit(self.Cunits.unit)) Tminvar = PKPDVariable() Tminvar.varName = "Tmin" Tminvar.varType = PKPDVariable.TYPE_NUMERIC Tminvar.role = PKPDVariable.ROLE_LABEL Tminvar.units = createUnit( self.outputExperiment.getTimeUnits().unit) Cavgvar = PKPDVariable() Cavgvar.varName = "Cavg" Cavgvar.varType = PKPDVariable.TYPE_NUMERIC Cavgvar.role = PKPDVariable.ROLE_LABEL Cavgvar.units = createUnit(strUnit(self.Cunits.unit)) self.outputExperiment.variables["FromSample"] = fromvar self.outputExperiment.variables["AUC0t"] = AUCvar self.outputExperiment.variables["AUMC0t"] = AUMCvar self.outputExperiment.variables["MRT"] = MRTvar self.outputExperiment.variables["Cmax"] = Cmaxvar self.outputExperiment.variables["Tmax"] = Tmaxvar self.outputExperiment.variables["Cmin"] = Cminvar self.outputExperiment.variables["Tmin"] = Tminvar self.outputExperiment.variables["Cavg"] = Cavgvar excelWriteRow([ "simulationName", "fromSample", "doseNumber", "AUC [%s]" % strUnit(self.AUCunits), "AUMC [%s]" % strUnit(self.AUMCunits), "Cmin [%s]" % strUnit(self.Cunits.unit), "Cavg [%s]" % strUnit(self.Cunits.unit), "Cmax [%s]" % strUnit(self.Cunits.unit), "Ctau [%s]" % strUnit(self.Cunits.unit), "Tmin [%s]" % strUnit(self.outputExperiment.getTimeUnits().unit), "Tmax [%s]" % strUnit(self.outputExperiment.getTimeUnits().unit), "Ttau [%s]" % strUnit(self.outputExperiment.getTimeUnits().unit) ], wb, 1, bold=True) wbRow = 2 # Evaluate AUC, AUMC and MRT in the last full period AUClist, AUMClist, Cminlist, Cavglist, Cmaxlist, Ctaulist, Tmaxlist, Tminlist, Ttaulist = self.NCA( self.model.x, y[0]) for doseNo in range(0, len(AUClist)): excelWriteRow([ "Simulation_%d" % i, self.fromSample, doseNo, AUClist[doseNo], AUMClist[doseNo], Cminlist[doseNo], Cavglist[doseNo], Cmaxlist[doseNo], Ctaulist[doseNo], Tminlist[doseNo], Tmaxlist[doseNo], Ttaulist[doseNo] ], wb, wbRow) wbRow += 1 # Keep results for j in range(self.getResponseDimension()): simulationsY[i, :, j] = y[j] AUCarray[i] = self.AUC0t AUMCarray[i] = self.AUMC0t MRTarray[i] = self.MRT CminArray[i] = self.Cmin CmaxArray[i] = self.Cmax CavgArray[i] = self.Cavg CtauArray[i] = self.Ctau TminArray[i] = self.Tmin TmaxArray[i] = self.Tmax TtauArray[i] = self.Ttau fluctuationArray[i] = self.fluctuation percentageAccumulationArray[i] = self.percentageAccumulation if self.addIndividuals or self.paramsSource != ProtPKPDODESimulate.PRM_POPULATION: self.addSample("Simulation_%d" % i, dosename, simulationsX, y[0]) # Report NCA statistics fhSummary = open(self._getPath("summary.txt"), "w") alpha_2 = (100 - self.confidenceLevel.get()) / 2 limits = np.percentile(AUCarray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "AUC %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.AUCunits), np.mean(AUCarray))) limits = np.percentile(AUMCarray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "AUMC %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.AUMCunits), np.mean(AUMCarray))) limits = np.percentile(MRTarray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "MRT %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.outputExperiment.getTimeUnits().unit), np.mean(MRTarray))) limits = np.percentile(CminArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Cmin %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.Cunits.unit), np.mean(CminArray))) limits = np.percentile(CmaxArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Cmax %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.Cunits.unit), np.mean(CmaxArray))) limits = np.percentile(CavgArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Cavg %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.Cunits.unit), np.mean(CavgArray))) limits = np.percentile(CtauArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Ctau %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.Cunits.unit), np.mean(CtauArray))) limits = np.percentile(TminArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Tmin %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.outputExperiment.getTimeUnits().unit), np.mean(TminArray))) limits = np.percentile(TmaxArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Tmax %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.outputExperiment.getTimeUnits().unit), np.mean(TmaxArray))) limits = np.percentile(TtauArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Ttau %f%% confidence interval=[%f,%f] [%s] mean=%f" % (self.confidenceLevel.get(), limits[0], limits[1], strUnit(self.outputExperiment.getTimeUnits().unit), np.mean(TtauArray))) aux = fluctuationArray[~np.isnan(fluctuationArray)] if len(aux) > 0: limits = np.percentile(aux, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Fluctuation %f%% confidence interval=[%f,%f] [%%] mean=%f" % (self.confidenceLevel.get(), limits[0] * 100, limits[1] * 100, np.mean(aux) * 100)) aux = percentageAccumulationArray[~np.isnan(percentageAccumulationArray )] limits = np.percentile(aux, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Accum(1) %f%% confidence interval=[%f,%f] [%%] mean=%f" % (self.confidenceLevel.get(), limits[0] * 100, limits[1] * 100, np.mean(aux) * 100)) fhSummary.close() # Calculate statistics if self.addStats and self.odeSource == 0 and self.paramsSource == 0: if self.paramsSource != ProtPKPDODESimulate.PRM_USER_DEFINED: limits = np.percentile(simulationsY, [alpha_2, 100 - alpha_2], axis=0) print("Lower limit NCA") self.NCA(simulationsX, limits[0]) self.fromSample = "LowerLimit" self.addSample("LowerLimit", dosename, simulationsX, limits[0]) print("Mean profile NCA") if self.getResponseDimension() == 1: mu = np.mean(simulationsY, axis=0) self.NCA(simulationsX, mu) else: mu = [] for j in range(self.getResponseDimension()): mu.append(np.mean(simulationsY[:, :, j], axis=0)) self.NCA(simulationsX, mu[0]) self.fromSample = "Mean" self.addSample("Mean", dosename, simulationsX, mu) if self.paramsSource != ProtPKPDODESimulate.PRM_USER_DEFINED: print("Upper limit NCA") self.NCA(simulationsX, limits[1]) self.fromSample = "UpperLimit" self.addSample("UpperLimit", dosename, simulationsX, limits[1]) self.outputExperiment.write(self._getPath("experiment.pkpd")) wb.save(self._getPath("nca.xlsx")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) if self.odeSource.get() == self.SRC_ODE: self._defineSourceRelation(self.inputODE.get(), self.outputExperiment) if self.paramsSource == ProtPKPDODESimulate.PRM_POPULATION: self._defineSourceRelation(self.inputPopulation.get(), self.outputExperiment) elif self.paramsSource == ProtPKPDODESimulate.PRM_POPULATION: self._defineSourceRelation(self.inputFitting.get(), self.outputExperiment) #--------------------------- INFO functions -------------------------------------------- def _summary(self): msg = [] msg.append("Dose: %s" % self.doses.get()) if self.odeSource == ProtPKPDODESimulate.SRC_ODE and self.paramsSource == ProtPKPDODESimulate.PRM_POPULATION: msg.append("Number of simulations: %d" % self.Nsimulations.get()) elif self.odeSource == ProtPKPDODESimulate.SRC_LIST or self.paramsSource == ProtPKPDODESimulate.PRM_USER_DEFINED: msg.append("Parameters:\n" + self.prmUser.get()) else: msg.append("Parameters from previous fitting") msg.append(" ") self.addFileContentToMessage(msg, self._getPath("summary.txt")) return msg def _validate(self): msg = [] if self.odeSource == self.SRC_ODE and \ self.paramsSource == ProtPKPDODESimulate.PRM_POPULATION and \ not self.inputPopulation.get().fnFitting.get().endswith("bootstrapPopulation.pkpd"): msg.append("Population must be a bootstrap sample") return msg
class ProtPKPDImportFromText(ProtPKPD): #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form, type): form.addSection('Input') inputFileHelp = "Specify a path to desired %s file.\n" % type inputFileHelp += "You may specify missing values with NA. You may also use LLOQ and ULOQ (Lower and Upper limit of quantification)\n" inputFileHelp += "to specify measurements that are below or above these limits" if type == "CSV": inputFileHelp += "The field separator must be a semicolon (;), decimal point must be a dot (.).\n" inputFileHelp += "The first row must contain the variable names and one of them must be SampleName which will serve as identifier." elif type == "ExcelTable": inputFileHelp += "The first column must be time, the rest of the columns must be measurements of each one of the individuals\n" inputFileHelp += "A column by each individual." form.addParam('inputFile', params.PathParam, label="File path", allowsNull=False, help=inputFileHelp) if type == "ExcelTable": form.addParam( 'skipLines', params.IntParam, default=0, label='Skip lines', help= 'Skip this amount of lines to reach the header line, the line with the variable names.' ) form.addParam('format',params.EnumParam, choices=["Wide format", "Long format"], default=0, label='Excel format', help='Wide format: 1st column is time, all other columns are the measurements\n'\ 'Long format: 1st column is the individualID, then all columns are as described by the variables') form.addParam( 'header', params.StringParam, label='Header format', default='ID, t, Cp', condition='format==1', help= 'The ID column is compulsory, but it does not need to be the first one. You can skip columns with the keyword SKIP.' ) form.addParam('title', params.StringParam, label="Title", default="My experiment") form.addParam('comment', params.StringParam, label="Comment", default="") form.addParam('variables', params.TextParam, height=8, width=80, label="Variables", default="", help="Structure: [Variable Name] ; [Units] ; [Type] ; [Role] ; [Comment]\n"\ "The variable name should have no space or special character\n"\ "Valid units are: h, mg, ug, ug/mL, ...\n"\ "Type is either numeric or text\n"\ "Role is either time, label or measurement\n"\ "The comment may be empty\n"\ "\nIt is important that there are three semicolons (none of them may be missing even if the comment is not present).\n"\ "Examples:\n"\ "t ; h ; numeric ; time ; \n"\ "Cp ; ug/mL ; numeric ; measurement ; plasma concentration\n"\ "weight ; g ; numeric; label ; weight of the animal\n"\ "sex ; none ; text ; label ; sex of the animal\n") form.addParam('vias', params.TextParam, height=8, width=80, label="Vias", help="[ViaName]; [ViaType]; [tlag]; [bioavailability]"\ "Valid ViaTypes are: iv (intravenous), ev0 (extra-vascular order 0), ev1 (extra-vascular order 1), \n"\ " ev01 (extra-vascular first order 0 and then order 1), evFractional (extra-vascular fractional order)\n"\ " ev0tlag1 (extra-vascular first order 0 for a fraction F0, tlag1 and then order 1 for 1-F0)\n"\ " ev1-ev1Saturable (extra-vascular first order absorption with fast and slow absorption fractions, both absorptions can be saturated\n)"\ " doubleWeibull (double Weibull\n)"\ " tripleWeibull (triple Weibull\n)"\ " splineN (Spline with N nodes\n)"\ " splineXYN (SplineXY with N nodes\n)"\ "Optional parameters are tlag (e.g. tlag=0)\n"\ " and bioavailability (e.g. bioavailability=0.8)\n"\ "Examples:\n"\ "Intravenous; iv\n"\ "Oral; ev1; tlag; bioavailability=1\n") addDoseToForm(form) form.addParam('dosesToSamples', params.TextParam, height=5, width=70, label="Assign doses to samples", default="", help="Structure: [Sample Name] ; [DoseName1,DoseName2,...] \n"\ "The sample name should have no space or special character\n"\ "\nIt is important that there is one semicolon.\n"\ "Examples:\n"\ "FemaleRat1 ; Bolus0,Bolus1,Infusion0\n"\ "If left empty, all individuals are assigned to the first dose") #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('createOutputStep', self.inputFile.get()) #--------------------------- STEPS functions -------------------------------------------- def readTextFile(self): pass def addSample(self, samplename, tokens): if not samplename in self.experiment.samples.keys(): self.experiment.samples[samplename] = PKPDSample() self.experiment.samples[samplename].parseTokens( tokens, self.experiment.variables, self.experiment.doses, self.experiment.groups) def createOutputStep(self, objId): fnFile = os.path.basename(self.inputFile.get()) copyFile(self.inputFile.get(), self._getPath(fnFile)) self.experiment = PKPDExperiment() self.experiment.general["title"] = self.title.get() self.experiment.general["comment"] = self.comment.get() ok = True # Read the variables self.listOfVariables = [] for line in self.variables.get().replace('\n', ';;').split(';;'): tokens = line.split(';') if len(tokens) != 5: print("Skipping variable: ", line) ok = False continue varname = tokens[0].strip() self.listOfVariables.append(varname) self.experiment.variables[varname] = PKPDVariable() self.experiment.variables[varname].parseTokens(tokens) # Read vias if self.vias.get(): for line in self.vias.get().replace('\n', ';;').split(';;'): if line != "": tokens = line.split(';') if len(tokens) < 2: print("Skipping via: ", line) ok = False continue vianame = tokens[0].strip() self.experiment.vias[vianame] = PKPDVia( ptrExperiment=self.experiment) self.experiment.vias[vianame].parseTokens(tokens) # Read the doses if self.doses.get(): for line in self.doses.get().replace('\n', ';;').split(';;'): if line != "": tokens = line.split(';') if len(tokens) < 5: print("Skipping dose: ", line) ok = False continue dosename = tokens[0].strip() self.experiment.doses[dosename] = PKPDDose() self.experiment.doses[dosename].parseTokens( tokens, self.experiment.vias) # Read the sample doses if self.dosesToSamples.get(): for line in self.dosesToSamples.get().replace('\n', ';;').split(';;'): try: tokens = line.split(';') samplename = tokens[0].strip() if len(tokens) > 1: tokens[1] = "dose=" + tokens[1] self.addSample(samplename, tokens) except Exception as e: ok = False print("Problem with line: ", line, str(e)) if ok: # Read the measurements self.readTextFile() if self.dosesToSamples.get( ) == "" and self.experiment.doses: # There are doses but they are not assigned dosename = list(self.experiment.doses.keys())[0] for samplename in self.experiment.samples: self.experiment.samples[samplename].doseList.append( dosename) self.experiment.write(self._getPath("experiment.pkpd")) self.experiment._printToStream(sys.stdout) self._defineOutputs(outputExperiment=self.experiment) #--------------------------- INFO functions -------------------------------------------- def _summary(self): return ["Input file: %s" % self.inputFile.get()] def _validate(self): retval = [] if self.inputFile.get() == "" or self.inputFile.get is None: retval.append("There is no input file") else: if not os.path.exists(self.inputFile.get()): retval.append("The file %s does not exist" % self.inputFile.get()) return retval
class ProtPKPDDissolutionFit(ProtPKPDFitBase): """ Fit a dissolution model. The observed measurement is modelled as Y=f(t).\n Confidence intervals calculated by this fitting may be pessimistic because it assumes that all model parameters are independent, which are not. Use Bootstrap estimates instead.\n Protocol created by http://www.kinestatpharma.com\n""" _label = 'fit dissolution' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): self._defineParams1(form, "t", "C") form.addParam( 'allowTlag', params.BooleanParam, label="Allow lag", default=False, help='Allow lag time before starting dissolution (t-tlag)') form.addParam('modelType', params.EnumParam, choices=["Zero order","First order","Fractional","Weibull", "Double Weibull", "Triple Weibull", "Higuchi", "Korsmeyer-Peppas","Hixson-Crowell","Hopfenberg","Hill", "Makoid-Banakar", "Splines2", "Splines3", "Splines4", "Spline5", "Splines6", "Splines7", "Splines8", "Splines9", "Splines10"], label="Dissolution model", default=3, help='Zero order: Y=K*(t-[tlag])\n'\ 'First order: Y=Ymax*(1-exp(-beta*(t-[tlag])))\n'\ 'Fractional order: Y=Ymax-pow(Amax^alpha-alpha*beta*t,1/alpha))\n'\ 'Weibull: Y=Ymax*(1-exp(-lambda*t^b))\n'\ 'Double Weibull: Y=Ymax*(F1*(1-exp(-lambda1*t^b1))+(1-F1)*(1-exp(-lambda2*(t-tlag2)^b2)))\n'\ 'Triple Weibull: Y=Ymax*(F1*(1-exp(-lambda1*t^b1))+F2*(1-exp(-lambda2*(t-tlag2)^b2))+(1-F1-F2)*(1-exp(-lambda3*(t-tlag3)^b3)))\n'\ 'Higuchi: Y=Ymax*t^0.5\n'\ 'Korsmeyer-Peppas: Y=Ymax*t^m\n'\ 'Hixson-Crowell: Y=Ymax*(1-(1-K*t)^3)\n' 'Hopfenberg: Y=Ymax*(1-(1-K*t)^m)\n' 'Hill: Y = Ymax*t^d/(g^d+t^d)\n' 'Makoid-Banakar: Ymax*(t/tmax)^b*exp(b*(1-t/tmax))\n' 'SplinesN: Y= Ymax*Bspline(t;N,tmax)\n') form.addParam('fitType', params.EnumParam, choices=["Linear","Logarithmic","Relative"], label="Fit mode", default=0, expertLevel=LEVEL_ADVANCED, help='Linear: sum (Cobserved-Cpredicted)^2\nLogarithmic: sum(log10(Cobserved)-log10(Cpredicted))^2\n'\ "Relative: sum ((Cobserved-Cpredicted)/Cobserved)^2") form.addParam( 'bounds', params.StringParam, label="Bounds (optional)", default="", help= 'Parameter values for the simulation.\nExample: (1,10);(0,0.05) is (1,10) for the first parameter, (0,0.05) for the second parameter\n' 'Zero order: [tlag];K\n' 'First order: [tlag];Ymax;beta\n' 'Fractional order: [tlag]; Ymax;beta;alpha\n' 'Weibull: [tlag]; Ymax;lambda;b\n' 'Double Weibull: [tlag]; Ymax; lambda1; b1; F1; tlag2; lambda2; b2\n' 'Triple Weibull: [tlag]; Ymax; lambda1; b1; F1; tlag2; lambda2; b2; F2; tlag3; lambda3; b3\n' 'Higuchi: [tlag]; Ymax\n' 'Korsmeyer-Peppas: [tlag]; Ymax; m\n' 'Hixson-Crowell: [tlag]; Ymax; K\n' 'Hopfenberg: [tlag]; Ymax; K; m\n' 'Hill: [tlag]; Ymax; g; d\n' 'Makoid-Banakar: [tlag]; Ymax; Tmax; b\n' 'SplinesN: [tlag]; Ymax; tmax; c1; c2; ...; cN\n') form.addParam('confidenceInterval', params.FloatParam, label="Confidence interval=", default=95, expertLevel=LEVEL_ADVANCED, help='Confidence interval for the fitted parameters') form.addParam( 'resampleT', params.FloatParam, label='Simulation model time step=', default=-1, help= 'If this value is greater than 0, then the fitted models will be sampled at this sampling period ' 'and the created profiles will be collected in a new output experiment. ' 'The time unit of the simulation is the same as the one of the predictor variable.' ) form.addParam( 'resampleT0', params.FloatParam, label='Initial time for simulation', default=0, condition='resampleT>0', help= 'The time unit of the simulation is the same as the one of the predictor variable.' ) form.addParam( 'resampleTF', params.FloatParam, label='Final time for simulation', default=0, condition='resampleT>0', help= 'If set to 0, then the maximum time of the sample will be taken. ' 'The time unit of the simulation is the same as the one of the predictor variable.' ) def getListOfFormDependencies(self): return [ self.allowTlag.get(), self.modelType.get(), self.bounds.get(), self.confidenceInterval.get() ] #--------------------------- STEPS functions -------------------------------------------- def createModel(self): if self.modelType.get() == 0: return Dissolution0() elif self.modelType.get() == 1: return Dissolution1() elif self.modelType.get() == 2: return DissolutionAlpha() elif self.modelType.get() == 3: return DissolutionWeibull() elif self.modelType.get() == 4: return DissolutionDoubleWeibull() elif self.modelType.get() == 5: return DissolutionTripleWeibull() elif self.modelType.get() == 6: return DissolutionHiguchi() elif self.modelType.get() == 7: return DissolutionKorsmeyer() elif self.modelType.get() == 8: return DissolutionHixson() elif self.modelType.get() == 9: return DissolutionHopfenberg() elif self.modelType.get() == 10: return DissolutionHill() elif self.modelType.get() == 11: return DissolutionMakoidBanakar() elif self.modelType.get() == 12: return DissolutionSplines2() elif self.modelType.get() == 13: return DissolutionSplines3() elif self.modelType.get() == 14: return DissolutionSplines4() elif self.modelType.get() == 15: return DissolutionSplines5() elif self.modelType.get() == 16: return DissolutionSplines6() elif self.modelType.get() == 17: return DissolutionSplines7() elif self.modelType.get() == 18: return DissolutionSplines8() elif self.modelType.get() == 19: return DissolutionSplines9() elif self.modelType.get() == 20: return DissolutionSplines10() def setupFromFormParameters(self): self.model.allowTlag = self.allowTlag.get() def prepareForAnalysis(self): if self.resampleT.get() > 0: self.experimentSimulated = PKPDExperiment() self.experimentSimulated.variables[ self.fitting.predicted.varName] = self.fitting.predicted self.experimentSimulated.variables[ self.fitting.predictor.varName] = self.fitting.predictor self.experimentSimulated.general[ "title"] = "Simulated response from dissolution profiles" self.experimentSimulated.general[ "comment"] = "Simulated response from dissolution profiles" def postSampleAnalysis(self, sampleName): self.experiment.addParameterToSample( sampleName, "tvitroMax", self.experiment.variables[self.varNameX].units.unit, "Maximum tvitro for which this fitting is valid", np.max(self.model.x)) if self.resampleT.get() > 0: newSample = PKPDSample() newSample.sampleName = sampleName + "_simulated" newSample.variableDictPtr = self.experimentSimulated.variables newSample.doseDictPtr = self.experimentSimulated.doses newSample.descriptors = {} newSample.addMeasurementPattern([self.fitting.predicted.varName]) t0 = self.resampleT0.get() tF = self.resampleTF.get() deltaT = self.resampleT.get() if tF == 0: tF = np.max(self.model.x) t = np.arange(t0, tF + deltaT, deltaT) y = self.model.forwardModel(self.model.parameters, t) newSample.addMeasurementColumn(self.fitting.predictor.varName, t) newSample.addMeasurementColumn(self.fitting.predicted.varName, y[0]) self.experimentSimulated.samples[sampleName] = newSample def postAnalysis(self): if self.resampleT.get() > 0: self.experimentSimulated.write( self._getPath("experimentSimulated.pkpd")) def createOutputStep(self): ProtPKPDFitBase.createOutputStep(self) if self.resampleT.get() > 0: self._defineOutputs( outputExperimentSimulated=self.experimentSimulated) self._defineSourceRelation(self.getInputExperiment(), self.experimentSimulated)
class ProtPKPDDeconvolutionLooRiegelmanInverse(ProtPKPD): """ Given a profile of amount absorbed, find the central and peripheral concentrations that gave raise to it. This is an inverse Loo-Riegelman problem. The parameters of this protocol are defined as microconstants. Remind that k10=Cl*V, k12=Clp*V, k21=Clp*Vp """ # Reference: Humbert, H., Cabiac, M.D., Bosshardt, H. In vitro-in vivo correlation of a modified-release oral # form of ketotifen: in vitro dissolution rate specification. J. Pharm Sci 1994, 83, 131-136 _label = 'inverse Loo-Riegelman' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputExperiment', params.PointerParam, label="In-vivo profiles", pointerClass='PKPDExperiment', help='It should have the amount absorbed') form.addParam('timeVar', params.StringParam, label="Time variable", default="t", help='Which variable contains the time stamps.') form.addParam('amountVar', params.StringParam, label="Absorbed amount variable", default="A", help='Which variable contains the amount absorbed.') form.addParam('resampleT', params.FloatParam, label="Resample profiles (time step)", default=0.1, help='Resample the input profiles at this time step (make sure it is in the same units as the input). ' 'Leave it to -1 for no resampling') form.addParam('k10', params.FloatParam, label="Elimination rate (k10)", help='Units t^-1') form.addParam('k12', params.FloatParam, label="Rate from central to peripheral (k12)", help='Units t^-1') form.addParam('k21', params.FloatParam, label="Rate from peripheral to central (k21)", help='Units t^-1') form.addParam('V', params.FloatParam, label="Central volume (V) [L]") form.addParam('Vp', params.FloatParam, label="Peripheral volume (Vp) [L]") #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('solve',self.inputExperiment.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addSample(self, sampleName, t, C, Cp): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.descriptors = {} newSample.addMeasurementPattern(["C","Cp"]) newSample.addMeasurementColumn("t", t) newSample.addMeasurementColumn("C", C) newSample.addMeasurementColumn("Cp", Cp) self.outputExperiment.samples[sampleName] = newSample def calculateConcentrations(self,t,A): k10 = float(self.k10.get()) k12 = float(self.k12.get()) k21 = float(self.k21.get()) V = float(self.V.get()) Vp = float(self.Vp.get()) C = np.zeros(t.shape) Cp = np.zeros(t.shape) AUC0t = np.zeros(t.shape) for n in range(1,C.size): DeltaA=np.abs(A[n]-A[n-1]) DeltaT=t[n]-t[n-1] DeltaT2=DeltaT/2 K1 = np.exp(-k21 * DeltaT) K2 = k10/(1+k12*DeltaT2+k10*DeltaT2) C[n] = DeltaA/V - Vp*Cp[n-1]/V*K1 + C[n-1]*k12*DeltaT2-C[n-1]*k12/k21*(1-K1)\ -C[n-1]*k10*DeltaT2-AUC0t[n-1]*K2 DeltaC = C[n]-C[n-1] # Update AUC0t if DeltaC>0: # Trapezoidal in the raise AUC0t[n] = AUC0t[n-1] + DeltaT/2 * (C[n - 1] + C[n]) else: # Log-trapezoidal in the decay if C[n-1] > 0 and C[n] > 0: decrement = C[n-1] / C[n] K = math.log(decrement) AUC0t[n] = AUC0t[n - 1] + DeltaT * (C[n-1] - C[n]) / K else: AUC0t[n] = AUC0t[n - 1] Cp[n] = Cp[n-1]*K1+k12/k21*C[n-1]*(1-K1)+k12*DeltaC*DeltaT2 if C[n]<0.0: C[n]=0.0 if Cp[n]<0.0: Cp[n]=0.0 return C, Cp def calculateConcentrations2(self,t,A): k10 = float(self.k10.get()) k12 = float(self.k12.get()) k21 = float(self.k21.get()) V = float(self.V.get()) Vp = float(self.Vp.get()) C = np.zeros(t.shape) Cp = np.zeros(t.shape) # Clp = k12*V for n in range(1,C.size): DeltaA=np.abs(A[n]-A[n-1]) DeltaT=t[n]-t[n-1] # Q12 = Clp*(C[n-1]-Cp[n-1]) # C[n]=C[n-1]+(-Cl*C[n-1]/V-Q12/V)*DeltaT+DeltaA/V # Cp[n]=Cp[n-1]+Q12/Vp*DeltaT # Q12 = Clp*(C[n-1]-Cp[n-1]) # C[n]=C[n-1]-k10*C[n-1]*DeltaT-Q12/V*DeltaT+DeltaA/V # Cp[n]=Cp[n-1]+Q12/Vp*DeltaT # C[n]=C[n-1]-k10*C[n-1]*DeltaT-(Clp*(C[n-1]-Cp[n-1]))/V*DeltaT+DeltaA/V # Cp[n]=Cp[n-1]+(Clp*(C[n-1]-Cp[n-1]))/Vp*DeltaT # C[n]=C[n-1]-k10*C[n-1]*DeltaT-Clp/V*C[n-1]*DeltaT+Clp/V*Cp[n-1]*DeltaT+DeltaA/V # Cp[n]=Cp[n-1]+Clp/Vp*C[n-1]*DeltaT-Clp/Vp*Cp[n-1]*DeltaT C[n]=C[n-1]-k10*C[n-1]*DeltaT-k12*C[n-1]*DeltaT+k21*Vp/V*Cp[n-1]*DeltaT+DeltaA/V Cp[n]=Cp[n-1]+k12*V/Vp*C[n-1]*DeltaT-k21*Cp[n-1]*DeltaT if C[n]<0.0: C[n]=0.0 if Cp[n]<0.0: Cp[n]=0.0 return C, Cp def solve(self, objId1): self.experiment = self.readExperiment(self.inputExperiment.get().fnPKPD) # Create output object self.outputExperiment = None timeRange = self.experiment.getRange(self.timeVar.get()) for sampleName, sample in self.experiment.samples.items(): # Get t, A t=np.asarray(sample.getValues(self.timeVar.get()),dtype=np.float64) A=np.asarray(sample.getValues(self.amountVar.get()),dtype=np.float64) if t[0]>0: t=np.insert(t,0,0) # Add (0,0) to the profile A=np.insert(A,0,0) t, A = uniqueFloatValues(t, A) if self.resampleT.get()>0: B = InterpolatedUnivariateSpline(t, A, k=1) t = np.arange(np.min(t),np.max(t)+self.resampleT.get(),self.resampleT.get()) A = B(t) # Find C and Cp C, Cp = self.calculateConcentrations2(t,A) if self.outputExperiment is None: self.outputExperiment = PKPDExperiment() tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(self.experiment.getTimeUnits().unit) Cvar = PKPDVariable() Cvar.varName = "C" Cvar.varType = PKPDVariable.TYPE_NUMERIC Cvar.role = PKPDVariable.ROLE_MEASUREMENT Lunits = createUnit("L") Cvar.units = createUnit(divideUnits(self.experiment.getVarUnits(self.amountVar.get()),Lunits.unit)) Cvar.comment = "Concentration central compartment" Cpvar = PKPDVariable() Cpvar.varName = "Cp" Cpvar.varType = PKPDVariable.TYPE_NUMERIC Cpvar.role = PKPDVariable.ROLE_MEASUREMENT Cpvar.units = createUnit(divideUnits(self.experiment.getVarUnits(self.amountVar.get()),Lunits.unit)) Cpvar.comment = "Concentration peripheral compartment" self.outputExperiment.variables[tvar.varName] = tvar self.outputExperiment.variables[Cvar.varName] = Cvar self.outputExperiment.variables[Cpvar.varName] = Cpvar self.outputExperiment.general["title"]="Inverse Loo-Riegelman" self.outputExperiment.general["comment"]="" self.addSample(sampleName,t,C,Cp) self.outputExperiment.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputExperiment.get(), self.outputExperiment) def _validate(self): return [] def _summary(self): retval = [] return retval
class ProtPKPDDissolutionIVIVC(ProtPKPDDissolutionLevyPlot): """ Calculate the in vitro-in vivo correlation between two experiments. Each experiment may have several profiles and all vs all profiles are calculated. You may scale the time between the two sets of experiments""" _label = 'dissol ivivc' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputInVitro', params.PointerParam, label="Dissolution profiles in vitro", pointerClass='ProtPKPDDissolutionFit', help='Select an experiment with dissolution profiles') form.addParam( 'inputInVivo', params.PointerParam, label="Dissolution profiles in vivo", pointerClass= 'ProtPKPDDeconvolve,ProtPKPDDeconvolutionWagnerNelson,ProtPKPDDeconvolutionLooRiegelman, PKPDExperiment', help='Select an experiment with dissolution profiles') form.addParam('removeInVitroTlag', params.BooleanParam, label="Remove in vitro tlag", default=True, help="If there is an in vitro tlag, set it to 0") form.addParam( 'timeScale', params.EnumParam, label="Time scaling", choices=[ "None (Fabs(t)=Adissol(t))", "t0 (Fabs(t)=Adissol(t-t0)", "Linear scale (Fabs(t)=Adissol(k*t))", "Affine transformation (Fabs(t)=Adissol(k*(t-t0))", "Power scale (Fabs(t)=Adissol(k*t^alpha)", "Delayed power scale (Fabs(t)=Adissol(k*(t-t0)^alpha)" ], default=0, help= 'Fabs is the fraction absorbed in vivo, while Adissol is the amount dissolved in vitro.' ) form.addParam( 't0Bounds', params.StringParam, label='Bounds t0', default='[-100,100]', condition='timeScale==1 or timeScale==3 or timeScale==5', help='Make sure it is in the same time units as the inputs') form.addParam( 'kBounds', params.StringParam, label='Bounds k', default='[0.1,10]', condition= 'timeScale==2 or timeScale==3 or timeScale==4 or timeScale==5') form.addParam('alphaBounds', params.StringParam, label='Bounds alpha', default='[0.1,10]', condition='timeScale==4 or timeScale==5') form.addParam( 'responseScale', params.EnumParam, label="Response scaling", choices=[ "None", "Linear scale (Fabs(t)=A*Adissol(t))", "Affine transformation (Fabs(t)=A*Adissol(t)+B" ], default=0, help= 'Fabs is the fraction absorbed in vivo, while Adissol is the amount dissolved in vitro.' ) form.addParam('ABounds', params.StringParam, label='Bounds A', default='[0.8,1.2]', condition='responseScale>=1') form.addParam('BBounds', params.StringParam, label='Bounds B', default='[-50,50]', condition='responseScale==2') #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('calculateAllIvIvC', self.inputInVitro.get().getObjId(), self.inputInVivo.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addParametersToExperiment(self, outputExperiment, sampleName, individualFrom, vesselFrom, optimum, R): if self.timeScale.get() == 1: timeScaleMsg = "tvitro=tvivo-t0" elif self.timeScale.get() == 2: timeScaleMsg = "tvitro=k*tvivo" elif self.timeScale.get() == 3: timeScaleMsg = "tvitro=k*(tvivo-t0)" elif self.timeScale.get() == 4: timeScaleMsg = "tvitro=k*tvivo^alpha" elif self.timeScale.get() == 5: timeScaleMsg = "tvitro=k*(tvivo-t0)^alpha" if self.responseScale.get() == 1: responseMsg = "Fabs(t)=A*Adissol(t)" elif self.responseScale.get() == 2: responseMsg = "Fabs(t)=A*Adissol(t)+B" t0 = None k = None alpha = None A = None B = None i = 0 for prm in self.parameters: exec("%s=%f" % (prm, optimum[i])) i += 1 outputExperiment.addLabelToSample( sampleName, "from", "individual---vesel", "%s---%s" % (individualFrom, vesselFrom)) if not t0 is None: outputExperiment.addParameterToSample(sampleName, "t0", PKPDUnit.UNIT_TIME_MIN, timeScaleMsg, t0) if not k is None: outputExperiment.addParameterToSample(sampleName, "k", PKPDUnit.UNIT_NONE, timeScaleMsg, k) if not alpha is None: outputExperiment.addParameterToSample(sampleName, "alpha", PKPDUnit.UNIT_NONE, timeScaleMsg, alpha) if not A is None: outputExperiment.addParameterToSample(sampleName, "A", PKPDUnit.UNIT_NONE, responseMsg, A) if not B is None: outputExperiment.addParameterToSample(sampleName, "B", PKPDUnit.UNIT_NONE, responseMsg, B) outputExperiment.addParameterToSample(sampleName, "R", PKPDUnit.UNIT_NONE, "IVIV Correlation coefficient", R) outputExperiment.addLabelToSample( sampleName, "from", "individual---vesel", "%s---%s" % (individualFrom, vesselFrom)) def addSample(self, sampleName, individualFrom, vesselFrom, optimum, R, set=1): newSampleFabs = PKPDSample() newSampleFabs.sampleName = sampleName newSampleFabs.variableDictPtr = self.outputExperimentFabs.variables newSampleFabs.descriptors = {} newSampleFabs.addMeasurementColumn("tvitroReinterpolated", self.tvitroReinterpolated) newSampleFabs.addMeasurementColumn("AdissolReinterpolated", self.AdissolReinterpolated) newSampleFabs.addMeasurementColumn("tvivo", self.tvivoUnique) newSampleFabs.addMeasurementColumn("FabsPredicted", self.FabsPredicted) newSampleFabs.addMeasurementColumn("Fabs", self.FabsUnique) if set == 1: self.outputExperimentFabs.samples[sampleName] = newSampleFabs self.addParametersToExperiment(self.outputExperimentFabs, sampleName, individualFrom, vesselFrom, optimum, R) else: self.outputExperimentFabsSingle.samples[sampleName] = newSampleFabs self.addParametersToExperiment(self.outputExperimentFabsSingle, sampleName, individualFrom, vesselFrom, optimum, R) if set == 1: newSampleAdissol = PKPDSample() newSampleAdissol.sampleName = sampleName newSampleAdissol.variableDictPtr = self.outputExperimentAdissol.variables newSampleAdissol.descriptors = {} newSampleAdissol.addMeasurementColumn("tvivoReinterpolated", self.tvivoReinterpolated) newSampleAdissol.addMeasurementColumn("FabsReinterpolated", self.FabsReinterpolated) newSampleAdissol.addMeasurementColumn("tvitro", self.tvitroUnique) newSampleAdissol.addMeasurementColumn("AdissolPredicted", self.AdissolPredicted) newSampleAdissol.addMeasurementColumn("Adissol", self.AdissolUnique) self.outputExperimentAdissol.samples[sampleName] = newSampleAdissol self.addParametersToExperiment(self.outputExperimentAdissol, sampleName, individualFrom, vesselFrom, optimum, R) def summarize(self, fh, x, msg): if len(x) > 0: p = np.percentile(x, [2.5, 50, 97.5], axis=0) self.doublePrint( fh, "%s: median=%f; 95%% Confidence interval=[%f,%f]" % (msg, p[1], p[0], p[2])) def guaranteeMonotonicity(self): idx = np.isnan(self.FabsUnique) idx = np.logical_or(idx, np.isnan(self.FabsPredicted)) self.FabsPredicted[~idx] = np.clip( smoothPchip(self.FabsUnique[~idx], self.FabsPredicted[~idx]), 0, 100) idx = np.isnan(self.AdissolUnique) idx = np.logical_or(idx, np.isnan(self.AdissolPredicted)) self.AdissolPredicted[~idx] = np.clip( smoothPchip(self.AdissolUnique[~idx], self.AdissolPredicted[~idx]), 0, 100) def calculateIndividualError(self, x, tvitroUnique, tvivoUnique): self.guaranteeMonotonicity() self.residualsForward = self.FabsPredicted - self.FabsUnique self.residualsBackward = self.AdissolUnique - self.AdissolPredicted idx = np.isnan(self.residualsForward) self.residualsForward[idx] = self.FabsUnique[idx] idx = np.isnan(self.residualsBackward) self.residualsBackward[idx] = self.AdissolUnique[idx] errorForward = np.sqrt(np.mean(self.residualsForward**2)) errorBackward = np.sqrt(np.mean(self.residualsBackward**2)) if errorForward > errorBackward: self.residuals = self.residualsForward else: self.residuals = self.residualsBackward diff = errorBackward - errorForward error = 0.5 * (errorBackward + errorForward) #+np.abs(diff) # error=np.sqrt(np.mean(self.residuals**2)) # error=np.sqrt(np.sum(self.residuals**2)) return error, errorBackward, errorForward def calculateError(self, x, tvitroUnique, tvivoUnique): error, errorBackward, errorForward = self.calculateIndividualError( x, tvitroUnique, tvivoUnique) if error < self.bestError: print( "New minimum error=%f (back=%f, forw=%f) R=%f" % (error, errorBackward, errorForward, self.calculateR()), "x=%s" % np.array2string(x, max_line_width=1000)) self.bestError = error sys.stdout.flush() if self.verbose: print("Forward error") for i in range(len(self.FabsPredicted)): print("i=", i, "tvitro[i]=", tvitroUnique[i], "tvivo[i]=", self.tvivoUnique[i], "FabsPredicted[i]=", self.FabsPredicted[i], "Fabs[i]", self.FabsUnique[i]) print("Backward error") for i in range(len(self.AdissolPredicted)): print("i=", i, "tvitro[i]=", self.tvitroUnique[i], "tvivo[i]=", tvivoUnique[i], "Adissol[i]=", self.AdissolUnique[i], "AdissolPredicted[i]", self.AdissolPredicted[i]) print("Error forward", np.sqrt(np.mean(self.residualsForward**2)), np.sum(self.residualsForward**2)) print("Error backward", np.sqrt(np.mean(self.residualsBackward**2)), np.sum(self.residualsBackward**2)) return error def goalFunction(self, x): t0 = 0.0 k = 1.0 alpha = 1.0 A = 1.0 B = 0.0 i = 0 try: for prm in self.parameters: if prm == "t0": t0 = x[i] elif prm == "k": k = x[i] elif prm == "alpha": alpha = x[i] elif prm == "A": A = x[i] elif prm == "B": B = x[i] i += 1 self.tvitroReinterpolated = np.clip( k * np.power(np.clip(self.tvivoUnique - t0, 0, None), alpha), self.tvitroMin, self.tvitroMax) self.AdissolReinterpolated = self.BAdissol( self.tvitroReinterpolated) self.FabsPredicted = np.clip(A * self.AdissolReinterpolated + B, 0.0, 100) self.tvivoReinterpolated = np.clip( np.power(self.tvitroUnique / k, 1.0 / alpha) + t0, self.tvivoMin, self.tvivoMax) self.FabsReinterpolated = self.BFabs(self.tvivoReinterpolated) self.AdissolPredicted = np.clip((self.FabsReinterpolated - B) / A, 0.0, 100) error = self.calculateError(x, self.tvitroReinterpolated, self.tvivoReinterpolated) except: return 1e38 return error def parseBounds(self, bounds): tokens = bounds.strip()[1:-1].split(',') return np.asarray(tokens, dtype=np.float64) def produceAdissol(self, parameterInVitro, tmax): deltaT = np.min([(tmax + 1) / 1000, 1.0]) tvitro = np.arange(0, tmax + 1, deltaT) if self.removeInVitroTlag: i = 0 for prmName in self.protFit.model.getParameterNames(): if "tlag" in prmName: parameterInVitro[i] = 0.0 i += 1 self.protFit.model.x = tvitro Avitro = self.protFit.model.forwardModel(parameterInVitro)[0] return (tvitro, Avitro) def createOutputExperiments(self, set): tvitroVar = PKPDVariable() tvitroVar.varName = "tvitro" tvitroVar.varType = PKPDVariable.TYPE_NUMERIC tvitroVar.role = PKPDVariable.ROLE_TIME tvitroVar.units = createUnit( self.experimentInVitro.getTimeUnits().unit) tvitroVar.comment = "tvitro" tvivoVar = PKPDVariable() tvivoVar.varName = "tvivo" tvivoVar.varType = PKPDVariable.TYPE_NUMERIC tvivoVar.role = PKPDVariable.ROLE_TIME tvivoVar.units = createUnit(self.experimentInVivo.getTimeUnits().unit) tvivoVar.comment = "tvivo" tvitroReinterpolatedVar = PKPDVariable() tvitroReinterpolatedVar.varName = "tvitroReinterpolated" tvitroReinterpolatedVar.varType = PKPDVariable.TYPE_NUMERIC tvitroReinterpolatedVar.role = PKPDVariable.ROLE_TIME tvitroReinterpolatedVar.units = createUnit( self.experimentInVitro.getTimeUnits().unit) tvitroReinterpolatedVar.comment = "tvitro reinterpolated" tvivoReinterpolatedVar = PKPDVariable() tvivoReinterpolatedVar.varName = "tvivoReinterpolated" tvivoReinterpolatedVar.varType = PKPDVariable.TYPE_NUMERIC tvivoReinterpolatedVar.role = PKPDVariable.ROLE_TIME tvivoReinterpolatedVar.units = createUnit( self.experimentInVivo.getTimeUnits().unit) tvivoReinterpolatedVar.comment = "tvivo reinterpolated" AdissolVar = PKPDVariable() AdissolVar.varName = "Adissol" AdissolVar.varType = PKPDVariable.TYPE_NUMERIC AdissolVar.role = PKPDVariable.ROLE_MEASUREMENT AdissolVar.units = createUnit( self.experimentInVitro.getVarUnits(self.varNameY)) AdissolVar.comment = "Amount disolved in vitro" FabsVar = PKPDVariable() FabsVar.varName = "Fabs" FabsVar.varType = PKPDVariable.TYPE_NUMERIC FabsVar.role = PKPDVariable.ROLE_MEASUREMENT FabsVar.units = createUnit(self.experimentInVivo.getVarUnits("A")) FabsVar.comment = "Amount absorbed in vivo" AdissolReinterpolatedVar = PKPDVariable() AdissolReinterpolatedVar.varName = "AdissolReinterpolated" AdissolReinterpolatedVar.varType = PKPDVariable.TYPE_NUMERIC AdissolReinterpolatedVar.role = PKPDVariable.ROLE_MEASUREMENT AdissolReinterpolatedVar.units = createUnit( self.experimentInVitro.getVarUnits(self.varNameY)) AdissolReinterpolatedVar.comment = "Time reinterpolated amount disolved in vitro" FabsReinterpolatedVar = PKPDVariable() FabsReinterpolatedVar.varName = "FabsReinterpolated" FabsReinterpolatedVar.varType = PKPDVariable.TYPE_NUMERIC FabsReinterpolatedVar.role = PKPDVariable.ROLE_MEASUREMENT FabsReinterpolatedVar.units = createUnit( self.experimentInVivo.getVarUnits("A")) FabsReinterpolatedVar.comment = "Time reinterpolated amount absorbed in vivo" AdissolPredictedVar = PKPDVariable() AdissolPredictedVar.varName = "AdissolPredicted" AdissolPredictedVar.varType = PKPDVariable.TYPE_NUMERIC AdissolPredictedVar.role = PKPDVariable.ROLE_MEASUREMENT AdissolPredictedVar.units = createUnit( self.experimentInVitro.getVarUnits(self.varNameY)) AdissolPredictedVar.comment = "Predicted amount disolved in vitro" FabsPredictedVar = PKPDVariable() FabsPredictedVar.varName = "FabsPredicted" FabsPredictedVar.varType = PKPDVariable.TYPE_NUMERIC FabsPredictedVar.role = PKPDVariable.ROLE_MEASUREMENT FabsPredictedVar.units = createUnit( self.experimentInVivo.getVarUnits("A")) FabsPredictedVar.comment = "Predicted amount absorbed in vivo" if set == 1: self.outputExperimentFabs = PKPDExperiment() self.outputExperimentFabs.variables[ tvitroReinterpolatedVar.varName] = tvitroReinterpolatedVar self.outputExperimentFabs.variables[ AdissolReinterpolatedVar.varName] = AdissolReinterpolatedVar self.outputExperimentFabs.variables[tvivoVar.varName] = tvivoVar self.outputExperimentFabs.variables[FabsVar.varName] = FabsVar self.outputExperimentFabs.variables[ FabsPredictedVar.varName] = FabsPredictedVar self.outputExperimentFabs.general[ "title"] = "In-vitro In-vivo correlation" self.outputExperimentFabs.general[ "comment"] = "Fabs vs Predicted Fabs" self.outputExperimentAdissol = PKPDExperiment() self.outputExperimentAdissol.variables[ tvivoReinterpolatedVar.varName] = tvivoReinterpolatedVar self.outputExperimentAdissol.variables[ FabsReinterpolatedVar.varName] = FabsReinterpolatedVar self.outputExperimentAdissol.variables[ tvitroVar.varName] = tvitroVar self.outputExperimentAdissol.variables[ AdissolVar.varName] = AdissolVar self.outputExperimentAdissol.variables[ AdissolPredictedVar.varName] = AdissolPredictedVar self.outputExperimentAdissol.general[ "title"] = "In-vitro In-vivo correlation" self.outputExperimentAdissol.general[ "comment"] = "Adissol vs Predicted Adissol" else: self.outputExperimentFabsSingle = PKPDExperiment() self.outputExperimentFabsSingle.variables[ tvitroReinterpolatedVar.varName] = tvitroReinterpolatedVar self.outputExperimentFabsSingle.variables[ AdissolReinterpolatedVar.varName] = AdissolReinterpolatedVar self.outputExperimentFabsSingle.variables[ tvivoVar.varName] = tvivoVar self.outputExperimentFabsSingle.variables[ FabsVar.varName] = FabsVar self.outputExperimentFabsSingle.variables[ FabsPredictedVar.varName] = FabsPredictedVar self.outputExperimentFabsSingle.general[ "title"] = "In-vitro In-vivo correlation" self.outputExperimentFabsSingle.general[ "comment"] = "Fabs vs Predicted Fabs" def calculateR(self): R2forward = np.clip( 1 - np.var(self.residualsForward) / np.var(self.FabsUnique), 0.0, 1.0) R2backward = np.clip( 1 - np.var(self.residualsBackward) / np.var(self.AdissolUnique), 0.0, 1.0) R2 = max(R2forward, R2backward) R = sqrt(R2) return R def calculateAllIvIvC(self, objId1, objId2): self.parametersInVitro, self.vesselNames, _ = self.getInVitroModels() self.profilesInVivo, self.sampleNames = self.getInVivoProfiles() self.createOutputExperiments(set=1) i = 1 allt0 = [] allk = [] allalpha = [] allA = [] allB = [] allR = [] self.parameters = [] self.bounds = [] if self.timeScale.get() == 1: # tvitro=tvivo-t0 self.parameters.append('t0') self.bounds.append(self.parseBounds(self.t0Bounds.get())) elif self.timeScale.get() == 2: # tvitro=k*tvivo self.parameters.append('k') self.bounds.append(self.parseBounds(self.kBounds.get())) elif self.timeScale.get() == 3: # tvitro=k*(tvivo-t0) self.parameters.append('k') self.parameters.append('t0') self.bounds.append(self.parseBounds(self.kBounds.get())) self.bounds.append(self.parseBounds(self.t0Bounds.get())) elif self.timeScale.get() == 4: # tvitro=k*tvivo^alpha self.parameters.append('k') self.parameters.append('alpha') self.bounds.append(self.parseBounds(self.kBounds.get())) self.bounds.append(self.parseBounds(self.alphaBounds.get())) elif self.timeScale.get() == 5: # tvitro=k*(tvivo-t0)^alpha self.parameters.append('k') self.parameters.append('alpha') self.parameters.append('t0') self.bounds.append(self.parseBounds(self.kBounds.get())) self.bounds.append(self.parseBounds(self.alphaBounds.get())) self.bounds.append(self.parseBounds(self.t0Bounds.get())) if self.responseScale.get() >= 1: # Linear self.parameters.append('A') self.bounds.append(self.parseBounds(self.ABounds.get())) if self.responseScale.get() == 2: # Affine self.parameters.append('B') self.bounds.append(self.parseBounds(self.BBounds.get())) # Compute all pairs invitroIdx = 0 self.verbose = False vitroList = [] vivoList = [] for parameterInVitro, vesselName in izip(self.parametersInVitro, self.vesselNames): invivoIdx = 0 if "tvitroMax" in self.experimentInVitro.variables: tvitroMax = float(self.experimentInVitro.samples[vesselName]. getDescriptorValue("tvitroMax")) else: tvitroMax = 1e38 for self.tvivo, self.Fabs in self.profilesInVivo: print("New combination %d" % i) self.FabsUnique, self.tvivoUnique = uniqueFloatValues( self.Fabs, self.tvivo) self.tvitro, self.Adissol = self.produceAdissol( parameterInVitro, min(np.max(self.tvivoUnique * 10), tvitroMax)) self.AdissolUnique, self.tvitroUnique = uniqueFloatValues( self.Adissol, self.tvitro) self.tvivoMin = np.min(self.tvivoUnique) self.tvivoMax = np.max(self.tvivoUnique) self.tvitroMin = np.min(self.tvitroUnique) self.tvitroMax = np.max(self.tvitroUnique) # Make sure they are sorted in x self.tvivoUnique, self.FabsUnique = uniqueFloatValues( self.tvivoUnique, self.FabsUnique) self.tvitroUnique, self.AdissolUnique = uniqueFloatValues( self.tvitroUnique, self.AdissolUnique) vivoList.append((self.tvivoUnique, self.FabsUnique)) vitroList.append((self.tvitroUnique, self.AdissolUnique)) # for i in range(len(self.tvivoUnique)): # print("i=",i,"tvivo[i]=",self.tvivoUnique[i],"Fabs[i]",self.FabsUnique[i]) # for i in range(len(self.tvitroUnique)): # print("i=",i,"tvitro[i]=",self.tvitroUnique[i],"Adissol[i]",self.AdissolUnique[i]) self.BAdissol = InterpolatedUnivariateSpline( self.tvitroUnique, self.AdissolUnique, k=1) self.BFabs = InterpolatedUnivariateSpline(self.tvivoUnique, self.FabsUnique, k=1) self.bestError = 1e38 if len(self.bounds) > 0: optimum = differential_evolution(self.goalFunction, self.bounds, popsize=50) x = optimum.x else: x = None # self.verbose=True self.goalFunction(x) j = 0 t0 = 0.0 k = 1.0 A = 1.0 B = 0.0 for prm in self.parameters: exec("%s=%f" % (prm, optimum.x[j])) exec("all%s.append(%f)" % (prm, optimum.x[j])) j += 1 # Evaluate correlation R = self.calculateR() allR.append(R) self.addSample("ivivc_%04d" % i, self.sampleNames[invivoIdx], self.vesselNames[invitroIdx], x, R, set=1) i += 1 invivoIdx += 1 invitroIdx += 1 fh = open(self._getPath("summary.txt"), "w") self.summarize(fh, allt0, "t0") self.summarize(fh, allk, "k") self.summarize(fh, allalpha, "alpha") self.summarize(fh, allA, "A") self.summarize(fh, allB, "B") self.doublePrint(fh, " ") self.summarize(fh, allR, "Correlation coefficient (R)") self.doublePrint(fh, " ") if self.timeScale.get() == 0: timeStr = "t" elif self.timeScale.get() == 1: timeStr = "t-t0" elif self.timeScale.get() == 2: timeStr = "k*t" elif self.timeScale.get() == 3: timeStr = "k*(t-t0)" elif self.timeScale.get() == 4: timeStr = "k*t^alpha" elif self.timeScale.get() == 5: timeStr = "k*(t-t0)^alpha" if self.responseScale.get() == 0: eqStr = "Fabs(t)=Adissol(%s)" % timeStr elif self.responseScale.get() == 1: eqStr = "Fabs(t)=A*Adissol(%s)" % timeStr elif self.responseScale.get() == 2: eqStr = "Fabs(t)=A*Adissol(%s)+B" % timeStr self.doublePrint(fh, "IVIVC equation: %s" % eqStr) fh.close() self.outputExperimentFabs.write(self._getPath("experimentFabs.pkpd")) self.outputExperimentAdissol.write( self._getPath("experimentAdissol.pkpd")) # Compute single print("Single IVIVC") self.tvivoUnique, self.FabsUnique = computeXYmean(vivoList) self.tvitroUnique, self.AdissolUnique = computeXYmean(vitroList) self.tvivoUnique, self.FabsUnique = uniqueFloatValues( self.tvivoUnique, self.FabsUnique) self.tvitroUnique, self.AdissolUnique = uniqueFloatValues( self.tvitroUnique, self.AdissolUnique) self.BAdissol = InterpolatedUnivariateSpline(self.tvitroUnique, self.AdissolUnique, k=1) self.BFabs = InterpolatedUnivariateSpline(self.tvivoUnique, self.FabsUnique, k=1) self.bestError = 1e38 if len(self.bounds) > 0: optimum = differential_evolution(self.goalFunction, self.bounds, popsize=50) x = optimum.x else: x = None self.goalFunction(x) R = self.calculateR() self.createOutputExperiments(set=2) self.addSample("ivivc_single", "AvgVivo", "AvgVitro", x, R, set=2) self.outputExperimentFabsSingle.write( self._getPath("experimentFabsSingle.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperimentFabs=self.outputExperimentFabs) self._defineSourceRelation(self.inputInVitro.get(), self.outputExperimentFabs) self._defineSourceRelation(self.inputInVivo.get(), self.outputExperimentFabs) self._defineOutputs( outputExperimentAdissol=self.outputExperimentAdissol) self._defineSourceRelation(self.inputInVitro.get(), self.outputExperimentAdissol) self._defineSourceRelation(self.inputInVivo.get(), self.outputExperimentAdissol) self._defineOutputs( outputExperimentFabsSingle=self.outputExperimentFabsSingle) self._defineSourceRelation(self.inputInVitro.get(), self.outputExperimentFabsSingle) self._defineSourceRelation(self.inputInVivo.get(), self.outputExperimentFabsSingle) def _validate(self): return [] def _summary(self): retval = [] if self.timeScale.get() == 0: retval.append("Time scaling: none") elif self.timeScale.get() == 1: retval.append("Time scaling: t0 (tvitro=tvivo-t0)") elif self.timeScale.get() == 2: retval.append( "Time scaling: linear transformation (tvitro=k*tvivo)") elif self.timeScale.get() == 3: retval.append( "Time scaling: affine transformation (tvitro=k*(tvivo-t0))") elif self.timeScale.get() == 4: retval.append( "Time scaling: power transformation (tvitro=k*tvivo^alpha)") elif self.timeScale.get() == 5: retval.append( "Time scaling: delayed power transformation (tvitro=k*(tvivo-t0)^alpha)" ) if self.responseScale.get() == 0: retval.append("Response scaling: none") elif self.responseScale.get() == 1: retval.append("Response scaling: Fabs(t)=A*Adissol(t)") elif self.responseScale.get() == 2: retval.append("Response scaling: Fabs(t)=A*Adissol(t)+B") self.addFileContentToMessage(retval, self._getPath("summary.txt")) return retval
class ProtPKPDApplyAllometricScaling(ProtPKPD): """ Apply an allometric scaling previously calculated to an incoming experiment. The labels specified by the allometric scaling model will be rescaled to the target weight. Note that depending on the exponent of the fitting you may want to use a different predictor (weight*maximum lifespan potential, or weight*brain weight) see the rule of exponents (Mahmood and Balian 1996). """ _label = 'apply allometric' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputPopulation', params.PointerParam, label="Input bootstrap population", pointerClass='PKPDFitting', help='The PK parameters of this experiment will be modified according to the allometric scale model.') form.addParam('inputAllometric', params.PointerParam, label="Allometric model", pointerClass='PKPDAllometricScale', help='All variables specified by the allometric scale model will be adjusted') form.addParam('targetWeight', params.FloatParam, label="Target weight (kg)", default=25, help='The PK parameters will be adjusted to this target weight') #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('runAdjust', self.targetWeight.get()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def runAdjust(self, targetWeight): scaleModel = PKPDAllometricScale() scaleModel.load(self.inputAllometric.get().fnScale.get()) self.population = self.readFitting(self.inputPopulation.get().fnFitting,cls="PKPDSampleFitBootstrap") self.experiment = PKPDExperiment() self.experiment.load(self.population.fnExperiment.get()) for sampleFit in self.population.sampleFits: sample = self.experiment.samples[sampleFit.sampleName] sampleWeight = float(sample.getDescriptorValue(scaleModel.predictor)) sample.setDescriptorValue(scaleModel.predictor,targetWeight) for varName, varUnits in scaleModel.averaged_vars: if varName in self.population.modelParameters: idx = self.population.modelParameters.index(varName) targetValue = scaleModel.models[varName][0] sampleFit.parameters[0][idx] = targetValue for varName, varUnits in scaleModel.scaled_vars: if varName in self.population.modelParameters: idx = self.population.modelParameters.index(varName) k = scaleModel.models[varName][0] a = scaleModel.models[varName][1] targetValue = k*math.pow(targetWeight,a) currentValue = k*math.pow(sampleWeight,a) for j in range(sampleFit.parameters.shape[0]): sampleFit.parameters[j][idx] *= targetValue/currentValue self.experiment.write(self._getPath("experiment.pkpd")) self.population.fnExperiment.set(self._getPath("experiment.pkpd")) self.population.write(self._getPath("bootstrapPopulation.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.experiment) self._defineOutputs(outputPopulation=self.population) self._defineSourceRelation(self.inputPopulation, self.experiment) self._defineSourceRelation(self.inputAllometric, self.experiment) self._defineSourceRelation(self.inputPopulation, self.population) self._defineSourceRelation(self.inputAllometric, self.population) #--------------------------- INFO functions -------------------------------------------- def _summary(self): msg = ["Target weight: %f"%self.targetWeight.get()] return msg def _citations(self): return ['Sharma2009','Mahmood1996']
class ProtPKPDImportFromTable(ProtPKPD): #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') inputFileHelp = "Specify a path to desired %s file.\n" % type inputFileHelp += "You may specify missing values with NA. You may also use LLOQ and ULOQ (Lower and Upper limit of quantification)\n" inputFileHelp += "to specify measurements that are below or above these limits" inputFileHelp += "If you use a CSV: the field separator must be a semicolon (;), decimal point must be a dot (.).\n" inputFileHelp += "If you use an Excel: you may have several sheets\n" inputFileHelp += "The first row must contain the name of the time variable and the name of the sample names\n" form.addParam('inputFile', params.PathParam, label="File path", allowsNull=False, help=inputFileHelp) form.addParam( 'sheetName', params.StringParam, label="Sheet", default="", help="Only valid for Excel files. Leave empty for all sheets") form.addParam('title', params.StringParam, label="Title", default="My experiment") form.addParam('comment', params.StringParam, label="Comment", default="") form.addParam('tVar', params.TextParam, height=8, width=80, label="Time variable", default="t; h; numeric; time; Time variable") form.addParam( 'xVar', params.TextParam, height=8, width=80, label="Measurement variable", default="C; none; numeric; measurement; Measurement variable") #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('createOutputStep', self.inputFile.get()) #--------------------------- STEPS functions -------------------------------------------- def addVar(self, experiment, line): tokens = line.split(';') if len(tokens) != 5: print("Skipping variable: ", line) return False varname = tokens[0].strip() experiment.variables[varname] = PKPDVariable() experiment.variables[varname].parseTokens(tokens) return True def readTables(self, fnTable): retval = [] if fnTable.endswith(".csv") or fnTable.endswith(".txt"): tableName = "" # csv fh = open(fnTable, "r") lineNo = 0 allT = [] allSamples = [] for line in fh.readlines(): tokens = line.split(";") if lineNo == 0: sampleNames = [] tokenNo = 0 for token in tokens: if tokenNo > 0: strippedToken = token.strip() if strippedToken != "": sampleNames.append(strippedToken) tokenNo += 1 else: allMeasurements = [] tokenNo = 0 for token in tokens: if tokenNo == 0: allT.append(token.strip()) else: strippedToken = token.strip() if strippedToken != "": allMeasurements.append(strippedToken) tokenNo += 1 allSamples.append(allMeasurements) lineNo += 1 fh.close() retval.append((tableName, sampleNames, allT, allSamples)) else: # excel import openpyxl wb = openpyxl.load_workbook(fnTable) sheetNames = wb.get_sheet_names() for sheetName in sheetNames: if (self.sheetName.get() != "" and sheetName == self.sheetName.get()) or self.sheetName.get() == "": tableName = "" if len(sheetNames) == 0 else "_" + sheetName sampleNames = [] allT = [] allSamples = [] sheet = wb.get_sheet_by_name(sheetName) for i in range(sheet.max_row): if i > 0: allMeasurements = [] for j in range(sheet.max_column): cellValue = str( sheet.cell(row=i + 1, column=j + 1).value).strip() if cellValue == "": continue if i == 0 and j >= 1: sampleNames.append(cellValue) elif i > 0: if j == 0: allT.append(cellValue) else: allMeasurements.append(cellValue) if i > 0: allSamples.append(allMeasurements) retval.append((tableName, sampleNames, allT, allSamples)) return retval def createOutputStep(self, objId): fnFile = os.path.basename(self.inputFile.get()) copyFile(self.inputFile.get(), self._getPath(fnFile)) tables = self.readTables(self._getPath(fnFile)) for tableName, sampleNames, allT, allMeasurements in tables: self.experiment = PKPDExperiment() self.experiment.general["title"] = self.title.get() self.experiment.general["comment"] = self.comment.get() # Add variables if not self.addVar(self.experiment, self.tVar.get()): raise Exception("Cannot process time variable") if not self.addVar(self.experiment, self.xVar.get()): raise Exception("Cannot process measurement variable") tvarName = self.tVar.get().split(';')[0].replace(';', '') xvarName = self.xVar.get().split(';')[0].replace(';', '') # Create the samples for sampleName in sampleNames: self.experiment.samples[sampleName] = PKPDSample() self.experiment.samples[sampleName].parseTokens( [sampleName], self.experiment.variables, self.experiment.doses, self.experiment.groups) self.experiment.samples[sampleName].addMeasurementPattern( [sampleName, tvarName, xvarName]) samplePtr = self.experiment.samples[sampleName] exec("samplePtr.measurement_%s=%s" % (tvarName, allT)) # Fill the samples for i in range(len(allT)): for j in range(len(sampleNames)): samplePtr = self.experiment.samples[sampleNames[j]] exec('samplePtr.measurement_%s.append("%s")' % (xvarName, allMeasurements[i][j])) self.experiment.write( self._getPath("experiment%s.pkpd" % tableName)) self.experiment._printToStream(sys.stdout) self._defineOutputs( **{"outputExperiment%s" % tableName: self.experiment}) #--------------------------- INFO functions -------------------------------------------- def _summary(self): return ["Input file: %s" % self.inputFile.get()]
class ProtPKPDDissolutionLevyPlot(ProtPKPD): """ Calculate the Levy plot between two dissolution experiments. Each experiment may have several profiles and all vs all profiles are calculated""" _label = 'dissol Levy' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputInVitro', params.PointerParam, label="Dissolution profiles in vitro", pointerClass='ProtPKPDDissolutionFit', help='Select an experiment with dissolution profiles') form.addParam( 'inputInVivo', params.PointerParam, label="Dissolution profiles in vivo", pointerClass= 'ProtPKPDDeconvolve, ProtPKPDDeconvolutionWagnerNelson, ProtPKPDDeconvolutionLooRiegelman, ProtPKPDDeconvolveFourier, PKPDExperiment', help='Select an experiment with dissolution profiles') form.addParam('limitTvitro', params.BooleanParam, label='Limit to observed tvitro', default=False, help='Limit plot to the maximum observed tvitro') #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('calculateAllLevy', self.inputInVitro.get().getObjId(), self.inputInVivo.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def getInVivoProfiles(self): if hasattr(self.inputInVivo.get(), "outputExperiment"): fnPKPD = self.inputInVivo.get().outputExperiment.fnPKPD elif hasattr(self.inputInVivo.get(), "fnPKPD"): fnPKPD = self.inputInVivo.get().fnPKPD else: raise Exception( "Cannot find a suitable filename for reading the experiment") experiment = self.readExperiment(fnPKPD) allY = [] sampleNames = [] for sampleName, sample in experiment.samples.items(): t = sample.getValues("t") y = sample.getValues("A") allY.append((np.asarray(t, dtype=np.float64), np.asarray(y, dtype=np.float64))) sampleNames.append(sampleName) self.experimentInVivo = experiment return allY, sampleNames def getInVitroModels(self): allParameters = [] self.protFit = self.inputInVitro.get() experiment = self.readExperiment(self.protFit.outputExperiment.fnPKPD) self.fitting = self.readFitting(self.protFit.outputFitting.fnFitting) self.varNameX = self.fitting.predictor.varName self.varNameY = self.fitting.predicted.varName self.protFit.model = self.protFit.createModel() self.protFit.model.setExperiment(experiment) self.protFit.model.setXVar(self.varNameX) self.protFit.model.setYVar(self.varNameY) self.protFit.setupFromFormParameters() self.protFit.experiment = experiment self.protFit.setupModel() parameterNames = self.protFit.model.getParameterNames() vesselNames = [] for sampleName, sample in experiment.samples.items(): tvitroMax = [] for sampleName, sample in experiment.samples.items(): vesselNames.append(sampleName) parameters0 = [] for parameterName in parameterNames: parameters0.append(float(sample.descriptors[parameterName])) allParameters.append(parameters0) if 'tvitroMax' in sample.descriptors: tvitroMax.append(float(sample.descriptors['tvitroMax'])) else: tvitroMax.append(np.Inf) self.experimentInVitro = experiment return allParameters, vesselNames, tvitroMax def produceLevyPlot(self, tvivo, parameterInVitro, Avivo, tvitroMax): Avivounique, tvivoUnique = uniqueFloatValues(Avivo, tvivo) B = InterpolatedUnivariateSpline(Avivounique, tvivoUnique, k=1) tmax = 10 * np.max(tvivo) if self.limitTvitro.get(): tmax = np.min([tmax, tvitroMax]) tvitro = np.arange(0, tmax, 1) self.protFit.model.x = tvitro Avitro = self.protFit.model.forwardModel(parameterInVitro)[0] tvivo = [] for i in range(tvitro.shape[0]): tvivo.append(B(Avitro[i])) return (tvitro, np.asarray(tvivo, dtype=np.float64), Avitro) def addSample(self, outputExperiment, sampleName, tvitro, tvivo, individualFrom, vesselFrom): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.descriptors = {} newSample.addMeasurementColumn("tvivo", tvivo) newSample.addMeasurementColumn("tvitro", tvitro) outputExperiment.samples[sampleName] = newSample outputExperiment.addLabelToSample( sampleName, "from", "individual---vesel", "%s---%s" % (individualFrom, vesselFrom)) def makeSuggestions(self, levyName, tvitro, tvivo): print("Polynomial fitting suggestions for %s" % levyName) for degree in range(1, 10): coeffs = np.polyfit(tvivo, tvitro, degree) p = np.poly1d(coeffs, variable='tvivo') residuals = tvitro - p(tvivo) R2 = 1 - np.var(residuals) / np.var(tvivo) print("Degree %d, R2: %f, tvitro=" % (degree, R2)) print(p) print(" ") logtvivo = np.log10(tvivo) logtvitro = np.log10(tvitro) idx = np.logical_and(np.isfinite(logtvitro), np.isfinite(logtvivo)) logtvivo = logtvivo[idx] logtvitro = logtvitro[idx] for degree in range(1, 10): coeffs = np.polyfit(logtvivo, logtvitro, degree) p = np.poly1d(coeffs, variable='log10(tvivo)') residuals = logtvitro - p(logtvivo) R2 = 1 - np.var(residuals) / np.var(logtvivo) print("Degree %d, R2: %f, log10(tvitro)=" % (degree, R2)) print(p) print(" ") def calculateAllLevy(self, objId1, objId2): parametersInVitro, vesselNames, tvitroMax = self.getInVitroModels() profilesInVivo, sampleNames = self.getInVivoProfiles() self.outputExperiment = PKPDExperiment() tvitrovar = PKPDVariable() tvitrovar.varName = "tvitro" tvitrovar.varType = PKPDVariable.TYPE_NUMERIC tvitrovar.role = PKPDVariable.ROLE_MEASUREMENT tvitrovar.units = createUnit( self.experimentInVitro.getTimeUnits().unit) tvivovar = PKPDVariable() tvivovar.varName = "tvivo" tvivovar.varType = PKPDVariable.TYPE_NUMERIC tvivovar.role = PKPDVariable.ROLE_MEASUREMENT tvivovar.units = createUnit(self.experimentInVivo.getTimeUnits().unit) self.outputExperiment.variables[tvivovar.varName] = tvivovar self.outputExperiment.variables[tvitrovar.varName] = tvitrovar self.outputExperiment.general["title"] = "Levy plots" self.outputExperiment.general[ "comment"] = "Time in vivo vs time in vitro" i = 1 levyList = [] for parameterInVitro, vesselFrom, tvitroMaxi in izip( parametersInVitro, vesselNames, tvitroMax): for aux, sampleFrom in izip(profilesInVivo, sampleNames): t, profileInVivo = aux tvitro, tvivo, _ = self.produceLevyPlot( t, parameterInVitro, profileInVivo, tvitroMaxi) tvitroUnique, tvivoUnique = twoWayUniqueFloatValues( tvitro, tvivo) idx = np.logical_and(tvitroUnique > 0, tvivoUnique > 0) tvitroUnique = tvitroUnique[idx] tvivoUnique = tvivoUnique[idx] if tvitroUnique[0] > 0 and tvivoUnique[0] > 0: tvitroUnique = np.insert(tvitroUnique, 0, 0.0) tvivoUnique = np.insert(tvivoUnique, 0, 0.0) levyName = "levy_%04d" % i levyList.append((tvitroUnique, tvivoUnique)) self.addSample(self.outputExperiment, levyName, tvitroUnique, tvivoUnique, sampleFrom, vesselFrom) self.makeSuggestions(levyName, tvitroUnique, tvivoUnique) i += 1 self.outputExperiment.write(self._getPath("experiment.pkpd")) # Single Levy plot self.outputExperimentSingle = PKPDExperiment() self.outputExperimentSingle.variables[tvivovar.varName] = tvivovar self.outputExperimentSingle.variables[tvitrovar.varName] = tvitrovar self.outputExperimentSingle.general["title"] = "Levy plots" self.outputExperimentSingle.general[ "comment"] = "Time in vivo vs time in vitro" tvitroSingle, tvivoSingle = computeXYmean(levyList) tvitroUnique, tvivoUnique = twoWayUniqueFloatValues( tvitroSingle, tvivoSingle) idx = np.logical_and(tvitroUnique > 0, tvivoUnique > 0) tvitroUnique = tvitroUnique[idx] tvivoUnique = tvivoUnique[idx] if tvitroUnique[0] > 0 and tvivoUnique[0] > 0: tvitroUnique = np.insert(tvitroUnique, 0, 0.0) tvivoUnique = np.insert(tvivoUnique, 0, 0.0) self.addSample(self.outputExperimentSingle, "levyAvg", tvitroUnique, tvivoUnique, "vivoAvg", "vitroAvg") self.outputExperimentSingle.write( self._getPath("experimentSingle.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputInVitro.get(), self.outputExperiment) self._defineSourceRelation(self.inputInVivo.get(), self.outputExperiment) self._defineOutputs(outputExperimentSingle=self.outputExperimentSingle) self._defineSourceRelation(self.inputInVitro.get(), self.outputExperimentSingle) self._defineSourceRelation(self.inputInVivo.get(), self.outputExperimentSingle) def _validate(self): return [] def _summary(self): retval = [] return retval
class ProtPKPDDissolutionPKSimulation(ProtPKPD): """ This protocol simulates the pharmacokinetic response of an ODE model when it is given a single dose of an drug whose release is modelled by an in vitro fitting and an in vitro-in vivo correlation.""" _label = 'simulate PK response' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'inputInVitro', params.PointerParam, label="Dissolution profiles in vitro", pointerClass='PKPDFitting', help='Select a fitting with dissolution profiles. ' 'It is assumed that the input dissolution profile is a percentage, between 0 and 100' ) form.addParam( 'inputPK', params.PointerParam, label="Pharmacokinetic model", pointerClass='PKPDFitting', help='Select the PK model to be simulated with this input') form.addParam( 'usePKExperiment', params.BooleanParam, label="Use experiment from PK fitting", default=True, help='If True, the PK parameters are taken from the same fitting. ' 'If False, they are taken from another experiment') form.addParam( 'inputPKOtherExperiment', params.PointerParam, label="Experiment with PK parameters", pointerClass='PKPDExperiment', condition='not usePKExperiment', help= 'The experiment must have all the PK parameters specified by the PK model' ) form.addParam( 'ignorePKbioavailability', params.BooleanParam, default=False, label='Ignore PK bioavailability', help= 'Ignore the bioavailability from the PK if it has been considered in the IVIVC' ) form.addParam( 'conversionType', params.EnumParam, label='Time/Response scaling', choices=['IVIVC', 'Levy plot', 'None'], default=0, help= 'To convert the dissolution profile into an absorption profile you may use an IVIVC (Fabs output) or a Levy plot. ' 'The Levy plot can better represent what is happening in reality with patients.' ) form.addParam( 'inputIvIvC', params.PointerParam, label="In vitro-In vivo correlation", condition='conversionType==0', pointerClass='PKPDExperiment', help='Select the Fabs output of an in vitro-in vivo correlation') form.addParam('inputLevy', params.PointerParam, label="Levy plot", condition='conversionType==1', pointerClass='PKPDExperiment', help='Select the output of a Levy plot protocol') form.addParam('inputDose', params.FloatParam, label="Dose", default=1, help='Make sure that it is in the same units as the ones at which the PK was estimated. '\ 'This dose will be given simpy once (single dose).') form.addParam( 'includeTlag', params.BooleanParam, label="Include PK tlag", default=True, help= 'If you include the tlag (if available), the simulations will be done with the same PK tlag as ' 'the input PK population. If not, tlag will be set to 0.') form.addParam( 'allCombinations', params.BooleanParam, label="All combinations of dissolutions/PK", default=False, help= 'If set to True, then all combinations of dissolutions and PK profiles are tested. ' 'Otherwise, only a random subset is chosen') form.addParam('inputN', params.IntParam, label="Number of simulations", default=100, condition='not allCombinations') form.addParam('t0', params.FloatParam, label="Initial time (h)", default=0) form.addParam('tF', params.FloatParam, label="Final time (h)", default=48) form.addParam('addIndividuals', params.BooleanParam, label="Add individual simulations", default=True, expertLevel=LEVEL_ADVANCED, help="Individual simulations are added to the output") form.addParam( 'NCAt0', params.StringParam, label="NCA Initial time (h)", default="", help= "The non-compartimental analysis is performed within NCA t0 and NCA tF. Leave empty for the whole period" ) form.addParam( 'NCAtF', params.StringParam, label="NCA Final time (h)", default="", help= "The non-compartimental analysis is performed within NCA t0 and NCA tF. Leave empty for the whole period" ) #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('simulate', self.inputInVitro.get().getObjId(), self.inputPK.get().getObjId(), self.inputDose.get(), self.inputN.get()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def getInVitroModels(self): fnFitting = self.inputInVitro.get().fnFitting cls = "PKPDSampleFitBootstrap" if fnFitting.get().find( "bootstrap") != -1 else "" self.fittingInVitro = PKPDFitting(cls) self.fittingInVitro.load(fnFitting) self.invitroClsName = self.fittingInVitro.modelDescription.split( '(')[1].split(')')[0] klass = globals()[self.invitroClsName] self.dissolutionModel = klass() self.dissolutionModel.allowTlag = "tlag" in self.fittingInVitro.modelParameters self.dissolutionPopulation = cls != "" def getScaling(self): self.allTimeScalings = {} self.allResponseScalings = {} if self.conversionType.get() == 0: experiment = self.readExperiment(self.inputIvIvC.get().fnPKPD, show=False) elif self.conversionType.get() == 1: experiment = self.readExperiment(self.inputLevy.get().fnPKPD, show=False) elif self.conversionType.get() == 2: experiment = self.readExperiment( self.inputInVitro.get().fnExperiment, show=False) tvar = experiment.getTimeVariable() for sampleName, sample in experiment.samples.items(): if self.conversionType.get() == 0: vivo = sample.getValues("tvivo") vitro = sample.getValues("tvitroReinterpolated") elif self.conversionType.get() == 1: vivo = sample.getValues("tvivo") vitro = sample.getValues("tvitro") elif self.conversionType.get() == 2: vivo = sample.getValues(tvar) vitro = sample.getValues(tvar) if self.conversionType.get() != 2: fromSample = sample.getDescriptorValue("from") fromIndividual, _ = fromSample.split("---") else: fromSample = sample.sampleName fromIndividual = sample.sampleName if not fromIndividual in self.allTimeScalings.keys(): self.allTimeScalings[fromIndividual] = [] self.allTimeScalings[fromIndividual].append( (np.asarray(vitro, dtype=np.float64), np.asarray(vivo, dtype=np.float64))) if self.conversionType.get() == 0: vivo = sample.getValues("FabsPredicted") vitro = sample.getValues("AdissolReinterpolated") if not fromIndividual in self.allResponseScalings.keys(): self.allResponseScalings[fromIndividual] = [] self.allResponseScalings[fromIndividual].append( (np.asarray(vitro, dtype=np.float64), np.asarray(vivo, dtype=np.float64))) def getPKModels(self): fnFitting = self.inputPK.get().fnFitting cls = "PKPDSampleFitBootstrap" if fnFitting.get().find( "bootstrap") != -1 else "" self.fittingPK = PKPDFitting(cls) self.fittingPK.load(fnFitting) modelDescription = self.fittingPK.modelDescription.split(';')[ 1] # Before ; there is the drug source description self.pkClsName = modelDescription.split('(')[1].split(')')[0] klass = globals()[self.pkClsName] self.pkModel = klass() self.pkModel.t0 = self.t0.get() self.pkModel.tF = self.tF.get() self.timeUnits = self.fittingPK.getTimeUnits().unit if self.timeUnits == PKPDUnit.UNIT_TIME_MIN: self.pkModel.t0 *= 60 self.pkModel.tF *= 60 self.pkModel.drugSource = DrugSource() dose = createDeltaDose(self.inputDose.get(), via=createVia("Oral; numerical")) self.pkModel.drugSource.setDoses([dose], self.pkModel.t0, self.pkModel.tF) self.pkPopulation = cls != "" self.pkNParams = self.pkModel.getNumberOfParameters() self.tlagIdx = None if self.includeTlag.get(): i = 0 for prmName in self.fittingPK.modelParameters: if prmName.endswith('_tlag'): self.tlagIdx = i print("Found tlag in %s at position %d" % (prmName, i)) break i += 1 self.bioavailabilityIdx = None if not self.ignorePKbioavailability.get(): i = 0 for prmName in self.fittingPK.modelParameters: if prmName.endswith('_bioavailability'): self.bioavailabilityIdx = i print("Found bioavailabilityIdx in %s at position %d" % (prmName, i)) break i += 1 def addSample(self, sampleName, t, y, fromSamples): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.doseDictPtr = self.outputExperiment.doses newSample.descriptors = {} newSample.doseList = ["Bolus"] newSample.addMeasurementPattern([self.fittingPK.predicted.varName]) newSample.addMeasurementColumn("t", t) newSample.addMeasurementColumn(self.fittingPK.predicted.varName, y) newSample.descriptors["AUC0t"] = self.AUC0t newSample.descriptors["AUMC0t"] = self.AUMC0t newSample.descriptors["MRT"] = self.MRT newSample.descriptors["Cmax"] = self.Cmax newSample.descriptors["Tmax"] = self.Tmax self.outputExperiment.samples[sampleName] = newSample self.outputExperiment.addLabelToSample(sampleName, "from", "individual---vesel", fromSamples) def NCA(self, t, C): self.AUC0t = 0 self.AUMC0t = 0 t0 = t[0] tperiod0 = 0 # Time at which the dose was given T0 = 0 TF = np.max(t) if self.NCAt0.get() != "" and self.NCAtF.get() != "": T0 = float(self.NCAt0.get()) TF = float(self.NCAtF.get()) if self.timeUnits == PKPDUnit.UNIT_TIME_MIN: T0 *= 60 TF *= 60 for idx in range(0, t.shape[0] - 1): if t[idx] >= T0 and t[idx] <= TF: dt = (t[idx + 1] - t[idx]) if C[idx + 1] >= C[idx]: # Trapezoidal in the raise self.AUC0t += 0.5 * dt * (C[idx] + C[idx + 1]) self.AUMC0t += 0.5 * dt * (C[idx] * t[idx] + C[idx + 1] * t[idx + 1]) else: # Log-trapezoidal in the decay decrement = C[idx] / C[idx + 1] K = math.log(decrement) B = K / dt self.AUC0t += dt * (C[idx] - C[idx + 1]) / K self.AUMC0t += (C[idx] * (t[idx] - tperiod0) - C[idx + 1] * (t[idx + 1] - tperiod0)) / B - ( C[idx + 1] - C[idx]) / (B * B) if idx == 0: self.Cmax = C[idx] self.Tmax = t[idx] - t0 else: if C[idx] > self.Cmax: self.Cmax = C[idx] self.Tmax = t[idx] - t0 self.MRT = self.AUMC0t / self.AUC0t print(" Cmax=%f [%s]" % (self.Cmax, strUnit(self.Cunits.unit))) print(" Tmax=%f [%s]" % (self.Tmax, strUnit(self.timeUnits))) print(" AUC0t=%f [%s]" % (self.AUC0t, strUnit(self.AUCunits))) print(" AUMC0t=%f [%s]" % (self.AUMC0t, strUnit(self.AUMCunits))) print(" MRT=%f [%s]" % (self.MRT, strUnit(self.timeUnits))) def simulate(self, objId1, objId2, inputDose, inputN): import sys self.getInVitroModels() self.getScaling() self.getPKModels() if not self.usePKExperiment: otherPKExperiment = PKPDExperiment() otherPKExperiment.load(self.inputPKOtherExperiment.get().fnPKPD) self.outputExperiment = PKPDExperiment() tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(self.fittingPK.predictor.units.unit) self.Cunits = self.fittingPK.predicted.units self.AUCunits = multiplyUnits(tvar.units.unit, self.Cunits.unit) self.AUMCunits = multiplyUnits(tvar.units.unit, self.AUCunits) if self.addIndividuals.get(): self.outputExperiment.variables["t"] = tvar self.outputExperiment.variables[ self.fittingPK.predicted.varName] = self.fittingPK.predicted self.outputExperiment.general[ "title"] = "Simulated ODE response from IVIVC dissolution profiles" self.outputExperiment.general[ "comment"] = "Simulated ODE response from IVIVC dissolution profiles" for via, _ in self.pkModel.drugSource.vias: self.outputExperiment.vias[via.viaName] = via for dose in self.pkModel.drugSource.parsedDoseList: self.outputExperiment.doses[dose.doseName] = dose AUCvar = PKPDVariable() AUCvar.varName = "AUC0t" AUCvar.varType = PKPDVariable.TYPE_NUMERIC AUCvar.role = PKPDVariable.ROLE_LABEL AUCvar.units = createUnit(strUnit(self.AUCunits)) AUMCvar = PKPDVariable() AUMCvar.varName = "AUMC0t" AUMCvar.varType = PKPDVariable.TYPE_NUMERIC AUMCvar.role = PKPDVariable.ROLE_LABEL AUMCvar.units = createUnit(strUnit(self.AUMCunits)) MRTvar = PKPDVariable() MRTvar.varName = "MRT" MRTvar.varType = PKPDVariable.TYPE_NUMERIC MRTvar.role = PKPDVariable.ROLE_LABEL MRTvar.units = createUnit( self.outputExperiment.getTimeUnits().unit) Cmaxvar = PKPDVariable() Cmaxvar.varName = "Cmax" Cmaxvar.varType = PKPDVariable.TYPE_NUMERIC Cmaxvar.role = PKPDVariable.ROLE_LABEL Cmaxvar.units = createUnit(strUnit(self.Cunits.unit)) Tmaxvar = PKPDVariable() Tmaxvar.varName = "Tmax" Tmaxvar.varType = PKPDVariable.TYPE_NUMERIC Tmaxvar.role = PKPDVariable.ROLE_LABEL Tmaxvar.units = createUnit( self.outputExperiment.getTimeUnits().unit) self.outputExperiment.variables["AUC0t"] = AUCvar self.outputExperiment.variables["AUMC0t"] = AUMCvar self.outputExperiment.variables["MRT"] = MRTvar self.outputExperiment.variables["Cmax"] = Cmaxvar self.outputExperiment.variables["Tmax"] = Tmaxvar t = np.arange(self.pkModel.t0, self.pkModel.tF, 1) if self.usePKExperiment: NPKFits = len(self.fittingPK.sampleFits) invivoFits = self.fittingPK.sampleFits else: NPKFits = len(otherPKExperiment.samples) invivoFits = [x for x in otherPKExperiment.samples.values()] for sample in invivoFits: sample.parameters = [ float(x) for x in sample.getDescriptorValues( self.fittingPK.modelParameters) ] NDissolFits = len(self.fittingInVitro.sampleFits) if self.allCombinations: inputN = NPKFits * NDissolFits AUCarray = np.zeros(inputN) AUMCarray = np.zeros(inputN) MRTarray = np.zeros(inputN) CmaxArray = np.zeros(inputN) TmaxArray = np.zeros(inputN) for i in range(0, inputN): print("Simulation no. %d ----------------------" % i) # Get a random PK model if self.allCombinations: nfit = int(i / NDissolFits) else: nfit = int(random.uniform(0, NPKFits)) sampleFitVivo = invivoFits[nfit] print("In vivo sample name=", sampleFitVivo.sampleName) if self.pkPopulation: nbootstrap = int( random.uniform(0, sampleFitVivo.parameters.shape[0])) pkPrmAll = sampleFitVivo.parameters[nbootstrap, :] else: pkPrmAll = sampleFitVivo.parameters pkPrm = pkPrmAll[-self.pkNParams:] # Get the last Nparams print("PK parameters: ", pkPrm) tlag = 0 if self.includeTlag.get() and (not self.tlagIdx is None): tlag = pkPrmAll[self.tlagIdx] print("tlag: ", tlag) bioavailability = 1 if not self.bioavailabilityIdx is None: bioavailability = pkPrmAll[self.bioavailabilityIdx] print("bioavailability: ", bioavailability) # Get a dissolution profile if self.allCombinations: nfit = i % NDissolFits else: nfit = int(random.uniform(0, NDissolFits)) sampleFitVitro = self.fittingInVitro.sampleFits[nfit] if self.dissolutionPopulation: nbootstrap = int( random.uniform(0, sampleFitVitro.parameters.shape[0])) dissolutionPrm = sampleFitVitro.parameters[nbootstrap, :] else: dissolutionPrm = sampleFitVitro.parameters print( "Dissolution parameters: ", np.array2string(np.asarray(dissolutionPrm, dtype=np.float64), max_line_width=1000)) sys.stdout.flush() if sampleFitVivo.sampleName in self.allTimeScalings: keyToUse = sampleFitVivo.sampleName elif len(self.allTimeScalings) == 1: keyToUse = list(self.allTimeScalings.keys())[0] else: raise Exception("Cannot find %s in the scaling keys" % sampleFitVivo.sampleName) nfit = int(random.uniform(0, len(self.allTimeScalings[keyToUse]))) tvitroLevy, tvivoLevy = self.allTimeScalings[keyToUse][nfit] tvivoLevyUnique, tvitroLevyUnique = uniqueFloatValues( tvivoLevy, tvitroLevy) BLevy = InterpolatedUnivariateSpline(tvivoLevyUnique, tvitroLevyUnique, k=1) tvitro = np.asarray(BLevy(t), dtype=np.float64) A = np.clip( self.dissolutionModel.forwardModel(dissolutionPrm, tvitro)[0], 0, 100) if self.conversionType.get() == 0: # In vitro-in vivo correlation Adissol, Fabs = self.allResponseScalings[keyToUse][nfit] AdissolUnique, FabsUnique = uniqueFloatValues(Adissol, Fabs) B = InterpolatedUnivariateSpline(AdissolUnique, FabsUnique, k=1) A = np.asarray(B(A), dtype=np.float64) # Set the dissolution profile self.pkModel.drugSource.getVia().viaProfile.setXYValues(t, A) C = self.pkModel.forwardModel( pkPrm, [t])[0] # forwardModel returns a list of arrays if tlag != 0.0: B = interp1d(t, C) C = B(np.clip(t - tlag, 0.0, None)) C[0:int(tlag)] = 0.0 C *= bioavailability self.NCA(t, C) AUCarray[i] = self.AUC0t AUMCarray[i] = self.AUMC0t MRTarray[i] = self.MRT CmaxArray[i] = self.Cmax TmaxArray[i] = self.Tmax if self.addIndividuals: self.addSample( "Simulation_%d" % i, t, C, "%s---%s" % (sampleFitVivo.sampleName, sampleFitVitro.sampleName)) # Report NCA statistics alpha_2 = (100 - 95) / 2 limits = np.percentile(AUCarray, [alpha_2, 100 - alpha_2]) fhSummary = open(self._getPath("summary.txt"), "w") self.doublePrint( fhSummary, "AUC %f%% confidence interval=[%f,%f] [%s] mean=%f" % (95, limits[0], limits[1], strUnit( self.AUCunits), np.mean(AUCarray))) limits = np.percentile(AUMCarray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "AUMC %f%% confidence interval=[%f,%f] [%s] mean=%f" % (95, limits[0], limits[1], strUnit( self.AUMCunits), np.mean(AUMCarray))) limits = np.percentile(MRTarray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "MRT %f%% confidence interval=[%f,%f] [%s] mean=%f" % (95, limits[0], limits[1], strUnit( self.timeUnits), np.mean(MRTarray))) limits = np.percentile(CmaxArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Cmax %f%% confidence interval=[%f,%f] [%s] mean=%f" % (95, limits[0], limits[1], strUnit( self.Cunits.unit), np.mean(CmaxArray))) limits = np.percentile(TmaxArray, [alpha_2, 100 - alpha_2]) self.doublePrint( fhSummary, "Tmax %f%% confidence interval=[%f,%f] [%s] mean=%f" % (95, limits[0], limits[1], strUnit( self.timeUnits), np.mean(TmaxArray))) fhSummary.close() if self.addIndividuals: self.outputExperiment.write(self._getPath("experiment.pkpd"), writeToExcel=False) def createOutputStep(self): if self.addIndividuals: self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputInVitro.get(), self.outputExperiment) self._defineSourceRelation(self.inputPK.get(), self.outputExperiment) if self.conversionType.get() == 0: self._defineSourceRelation(self.inputIvIvC.get(), self.outputExperiment) elif self.conversionType.get() == 1: self._defineSourceRelation(self.inputLevy.get(), self.outputExperiment) def _validate(self): retval = [] if self.conversionType.get( ) == 0 and not "experimentFabs" in self.inputIvIvC.get().fnPKPD.get(): retval.append( "If the conversion is done from IVIVC, then you must take the Fabs output" ) return retval def _summary(self): retval = [] retval.append('Dose=%f' % self.inputDose.get()) retval.append('No. simulations=%d' % self.inputN.get()) retval.append(' ') self.addFileContentToMessage(retval, self._getPath("summary.txt")) return retval
class ProtPKPDInhSimulate(ProtPKPD): """ Simulate inhalation PK\n See Hartung2020. Protocol created by http://www.kinestatpharma.com\n """ _label = 'simulate inhalation' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('ptrDeposition', params.PointerParam, pointerClass='PKDepositionParameters', label="Deposition") form.addParam( 'doseMultiplier', params.FloatParam, default=1.0, label='Dose multiplier', expertLevel=LEVEL_ADVANCED, help="Multiply the dose in the deposition file by this factor") form.addParam( 'substanceMultiplier', params.StringParam, default="1 1 1 1 1 1 1 1", label='Substance multiplier', expertLevel=LEVEL_ADVANCED, help= 'Multiply a substance related parameter by this factor. This is a vector with the order: \n' '1. Solubility (br) \n' '2. Solubility (alv) \n' '3. Dissolution rate (br) \n' '4. Dissolution rate (alv) \n' '5. Permeability (br) \n' '6. Permeability (alv) \n' '7. Partition coefficient (br) \n' '8. Partition coefficient (alv)') form.addParam( 'physiologyMultiplier', params.StringParam, default="1 1 1 1 1 1 1 1 1", label='Physiology multiplier', expertLevel=LEVEL_ADVANCED, help= 'Multiply a physiology related parameter by this factor. This is a vector with the order: \n' '1. Mucociliary clearance\n' '2. Fluid volume (br)\n' '3. Fluid volume (alv)\n' '4. Tissue volume (br)\n' '5. Tissue volume (alv)\n' '6. Surface area (br)\n' '7. Surface area (alv)\n' '8. Perfusion (br)\n' '9. Perfusion (alv)\n') form.addParam('ptrPK', params.PointerParam, pointerClass='PKPDExperiment', label="PK parameters") form.addParam( 'pkMultiplier', params.StringParam, default="1 1 1 1 1 1", label='PK multiplier', expertLevel=LEVEL_ADVANCED, help= 'Multiply a substance related parameter by this factor. This is a vector with the order: \n' '1. Systemic clearance (Cl)\n' '2. Systemic apparent volume (V)\n' '3. Flow between compartments (Q)\n' '4. Peripheral apparent volume (Vp)\n' '5. Absorption (k01)\n' '6. Oral bioavailability (F)\n') form.addParam('ciliarySpeedType', params.EnumParam, choices=['Exponential', 'Fit', 'Interpolated'], default=2, label='Ciliary speed', expertLevel=LEVEL_ADVANCED) form.addParam('simulationTime', params.FloatParam, label="Simulation time (min)", default=10 * 24 * 60) form.addParam('deltaT', params.FloatParam, label='Time step (min)', default=1, expertLevel=LEVEL_ADVANCED) form.addParam( 'diameters', params.StringParam, label='Diameters (um)', default="0.1,1.1,0.1; 1.2,9.2,0.2", help= 'Diameters to analyze. Syntax: start1, stop1, step1; start2, stop2, step2; ... They will be ' 'used as arguments of numpy.arange', expertLevel=LEVEL_ADVANCED) form.addParam('volMultiplier', params.FloatParam, label='Particle volume multiplier', default=1, expertLevel=LEVEL_ADVANCED) #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('runSimulation') self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def runSimulation(self): self.deposition = PKDepositionParameters() self.deposition.setFiles(self.ptrDeposition.get().fnSubstance.get(), self.ptrDeposition.get().fnLung.get(), self.ptrDeposition.get().fnDeposition.get()) self.deposition.doseMultiplier = self.doseMultiplier.get() self.deposition.read() substanceParams = PKSubstanceLungParameters() substanceParams.multiplier = [ float(x) for x in self.substanceMultiplier.get().split() ] substanceParams.read(self.ptrDeposition.get().fnSubstance.get()) lungParams = PKPhysiologyLungParameters() lungParams.multiplier = [ float(x) for x in self.physiologyMultiplier.get().split() ] lungParams.read(self.ptrDeposition.get().fnLung.get()) pkParams = PKPDExperiment() pkParams.load(self.ptrPK.get().fnPKPD) pkLungParams = PKLung() pkLungParams.prepare( substanceParams, lungParams, pkParams, [float(x) for x in self.pkMultiplier.get().split()], self.ciliarySpeedType.get()) # diameters = np.concatenate((np.arange(0.1,1.1,0.1),np.arange(1.2,9.2,0.2))) # [um] evalStr = "np.concatenate((" + ",".join([ "np.arange(" + x.strip() + ")" for x in self.diameters.get().split(";") ]) + "))" diameters = eval(evalStr, {'np': np}) Sbnd = self.volMultiplier.get() * diam2vol(diameters) tt = np.arange(0, self.simulationTime.get() + self.deltaT.get(), self.deltaT.get()) sol = saturable_2D_upwind_IE(lungParams, pkLungParams, self.deposition, tt, Sbnd) # Postprocessing depositionData = self.deposition.getData() alvDose = np.sum(depositionData['alveolar']) bronchDose = np.sum(depositionData['bronchial']) lungDose = alvDose + bronchDose Aalvsolid = sol['A']['alv']['solid'] Aalvfluid = sol['A']['alv']['fluid'] Aalvtissue = sol['A']['alv']['tissue'] AsysGut = sol['A']['sys']['gut'] AsysPer = sol['A']['sys']['per'] AsysCtr = sol['A']['sys']['ctr'] Atisbr = sol['A']['br']['tissue'] Abrtissue = Atisbr Vtisbr = lungParams.getBronchial()['fVol'] * lungParams.getSystemic( )['OWlung'] Cavgbr = Atisbr / Vtisbr Abrcleared = sol['A']['br']['clear'] Abrcleared = np.reshape(Abrcleared, Abrcleared.size) Abrsolid = sol['A']['br']['solid'] Abrfluid = sol['A']['br']['fluid'] Acleared = sol['A']['sys']['clear'] + AsysGut - AsysGut[0] lungRetention = 100 * (lungDose - Acleared) / lungDose # in percent of lung dose Csysnmol = sol['C']['sys']['ctr'] Csys = Csysnmol * substanceParams.getData()['MW'] CsysPer = AsysPer * substanceParams.getData( )['MW'] / pkLungParams.pkData['Vp'] # Create output self.experimentLungRetention = PKPDExperiment() self.experimentLungRetention.general["title"] = "Inhalation simulate" tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit("min") Rvar = PKPDVariable() Rvar.varName = "Retention" Rvar.varType = PKPDVariable.TYPE_NUMERIC Rvar.role = PKPDVariable.ROLE_MEASUREMENT Rvar.units = createUnit("none") Rvar.comment = "Lung retention (% lung dose)" Cnmolvar = PKPDVariable() Cnmolvar.varName = "Cnmol" Cnmolvar.varType = PKPDVariable.TYPE_NUMERIC Cnmolvar.role = PKPDVariable.ROLE_MEASUREMENT Cnmolvar.units = createUnit("nmol/mL") Cnmolvar.comment = "Central compartment concentration" Cvar = PKPDVariable() Cvar.varName = "C" Cvar.varType = PKPDVariable.TYPE_NUMERIC Cvar.role = PKPDVariable.ROLE_MEASUREMENT Cvar.units = createUnit("g/mL") Cvar.comment = "Central compartment concentration" alvTissueVar = PKPDVariable() alvTissueVar.varName = "alvTissue" alvTissueVar.varType = PKPDVariable.TYPE_NUMERIC alvTissueVar.role = PKPDVariable.ROLE_MEASUREMENT alvTissueVar.units = createUnit("nmol") alvTissueVar.comment = "Amount in alveoli" alvSolidVar = PKPDVariable() alvSolidVar.varName = "alvSolid" alvSolidVar.varType = PKPDVariable.TYPE_NUMERIC alvSolidVar.role = PKPDVariable.ROLE_MEASUREMENT alvSolidVar.units = createUnit("nmol") alvSolidVar.comment = "Amount undissolved in alveoli" alvFluidVar = PKPDVariable() alvFluidVar.varName = "alvFluid" alvFluidVar.varType = PKPDVariable.TYPE_NUMERIC alvFluidVar.role = PKPDVariable.ROLE_MEASUREMENT alvFluidVar.units = createUnit("nmol") alvFluidVar.comment = "Amount in alveolar lining fluid" brTissueVar = PKPDVariable() brTissueVar.varName = "brTissue" brTissueVar.varType = PKPDVariable.TYPE_NUMERIC brTissueVar.role = PKPDVariable.ROLE_MEASUREMENT brTissueVar.units = createUnit("nmol") brTissueVar.comment = "Amount in bronchii" brSolidVar = PKPDVariable() brSolidVar.varName = "brSolid" brSolidVar.varType = PKPDVariable.TYPE_NUMERIC brSolidVar.role = PKPDVariable.ROLE_MEASUREMENT brSolidVar.units = createUnit("nmol") brSolidVar.comment = "Amount undissolved in bronchii" brFluidVar = PKPDVariable() brFluidVar.varName = "brFluid" brFluidVar.varType = PKPDVariable.TYPE_NUMERIC brFluidVar.role = PKPDVariable.ROLE_MEASUREMENT brFluidVar.units = createUnit("nmol") brFluidVar.comment = "Amount in bronchial lining fluid" brClvar = PKPDVariable() brClvar.varName = "brClear" brClvar.varType = PKPDVariable.TYPE_NUMERIC brClvar.role = PKPDVariable.ROLE_MEASUREMENT brClvar.units = createUnit("nmol") brClvar.comment = "Cumulative amount cleared by mucociliary elevator" brCTisvar = PKPDVariable() brCTisvar.varName = "CbrTis" brCTisvar.varType = PKPDVariable.TYPE_NUMERIC brCTisvar.role = PKPDVariable.ROLE_MEASUREMENT brCTisvar.units = createUnit("nmol/mL") brCTisvar.comment = "Concentration in bronchial tissue" sysGutVar = PKPDVariable() sysGutVar.varName = "sysAbsorption" sysGutVar.varType = PKPDVariable.TYPE_NUMERIC sysGutVar.role = PKPDVariable.ROLE_MEASUREMENT sysGutVar.units = createUnit("nmol") sysGutVar.comment = "Amount in absorption compartment" sysCtrVar = PKPDVariable() sysCtrVar.varName = "sysCentral" sysCtrVar.varType = PKPDVariable.TYPE_NUMERIC sysCtrVar.role = PKPDVariable.ROLE_MEASUREMENT sysCtrVar.units = createUnit("nmol") sysCtrVar.comment = "Amount in central compartment" sysPerVar = PKPDVariable() sysPerVar.varName = "sysPeripheral" sysPerVar.varType = PKPDVariable.TYPE_NUMERIC sysPerVar.role = PKPDVariable.ROLE_MEASUREMENT sysPerVar.units = createUnit("nmol") sysPerVar.comment = "Amount in peripheral compartment" CsysPerVar = PKPDVariable() CsysPerVar.varName = "Cp" CsysPerVar.varType = PKPDVariable.TYPE_NUMERIC CsysPerVar.role = PKPDVariable.ROLE_MEASUREMENT CsysPerVar.units = createUnit("g/mL") CsysPerVar.comment = "Concentration in peripheral compartment" doseNmolVar = PKPDVariable() doseNmolVar.varName = "dose_nmol" doseNmolVar.varType = PKPDVariable.TYPE_NUMERIC doseNmolVar.role = PKPDVariable.ROLE_LABEL doseNmolVar.units = createUnit("nmol") doseNmolVar.comment = "Input dose in nmol" doseThroatVar = PKPDVariable() doseThroatVar.varName = "throat_dose_nmol" doseThroatVar.varType = PKPDVariable.TYPE_NUMERIC doseThroatVar.role = PKPDVariable.ROLE_LABEL doseThroatVar.units = createUnit("nmol") doseThroatVar.comment = "Throat dose in nmol" doseLungVar = PKPDVariable() doseLungVar.varName = "lung_dose_nmol" doseLungVar.varType = PKPDVariable.TYPE_NUMERIC doseLungVar.role = PKPDVariable.ROLE_LABEL doseLungVar.units = createUnit("nmol") doseLungVar.comment = "Lung dose in nmol" doseBronchialVar = PKPDVariable() doseBronchialVar.varName = "bronchial_dose_nmol" doseBronchialVar.varType = PKPDVariable.TYPE_NUMERIC doseBronchialVar.role = PKPDVariable.ROLE_LABEL doseBronchialVar.units = createUnit("nmol") doseBronchialVar.comment = "Bronchial dose in nmol" doseAlveolarVar = PKPDVariable() doseAlveolarVar.varName = "alveolar_dose_nmol" doseAlveolarVar.varType = PKPDVariable.TYPE_NUMERIC doseAlveolarVar.role = PKPDVariable.ROLE_LABEL doseAlveolarVar.units = createUnit("nmol") doseAlveolarVar.comment = "Alveolar dose in nmol" mccClearedLungDoseFractionVar = PKPDVariable() mccClearedLungDoseFractionVar.varName = "mcc_cleared_lung_dose_fraction" mccClearedLungDoseFractionVar.varType = PKPDVariable.TYPE_NUMERIC mccClearedLungDoseFractionVar.role = PKPDVariable.ROLE_LABEL mccClearedLungDoseFractionVar.units = createUnit("None") mccClearedLungDoseFractionVar.comment = "MCC cleared lung dose fraction" self.experimentLungRetention.variables["t"] = tvar self.experimentLungRetention.variables["Retention"] = Rvar self.experimentLungRetention.variables["Cnmol"] = Cnmolvar self.experimentLungRetention.variables["C"] = Cvar self.experimentLungRetention.variables["alvTissue"] = alvTissueVar self.experimentLungRetention.variables["alvFluid"] = alvFluidVar self.experimentLungRetention.variables["alvSolid"] = alvSolidVar self.experimentLungRetention.variables["brTissue"] = brTissueVar self.experimentLungRetention.variables["brFluid"] = brFluidVar self.experimentLungRetention.variables["brSolid"] = brSolidVar self.experimentLungRetention.variables["brClear"] = brClvar self.experimentLungRetention.variables["CbrTis"] = brCTisvar self.experimentLungRetention.variables["sysCentral"] = sysCtrVar self.experimentLungRetention.variables["sysAbsoprtion"] = sysGutVar self.experimentLungRetention.variables["sysPeripheral"] = sysPerVar self.experimentLungRetention.variables["Cp"] = CsysPerVar self.experimentLungRetention.variables["dose_nmol"] = doseNmolVar self.experimentLungRetention.variables[ "throat_dose_nmol"] = doseThroatVar self.experimentLungRetention.variables["lung_dose_nmol"] = doseLungVar self.experimentLungRetention.variables[ "bronchial_dose_nmol"] = doseBronchialVar self.experimentLungRetention.variables[ "alveolar_dose_nmol"] = doseAlveolarVar self.experimentLungRetention.variables[ "mcc_cleared_lung_dose_fraction"] = mccClearedLungDoseFractionVar # Samples simulationSample = PKPDSample() simulationSample.sampleName = "simulation" simulationSample.addMeasurementColumn("t", tt) simulationSample.addMeasurementColumn("Retention", lungRetention) simulationSample.addMeasurementColumn("Cnmol", Csysnmol) simulationSample.addMeasurementColumn("C", Csys) simulationSample.addMeasurementColumn("alvFluid", Aalvfluid) simulationSample.addMeasurementColumn("alvTissue", Aalvtissue) simulationSample.addMeasurementColumn("alvSolid", Aalvsolid) simulationSample.addMeasurementColumn("brFluid", Abrfluid) simulationSample.addMeasurementColumn("brTissue", Abrtissue) simulationSample.addMeasurementColumn("brSolid", Abrsolid) simulationSample.addMeasurementColumn("brClear", Abrcleared) simulationSample.addMeasurementColumn("CbrTis", Cavgbr) simulationSample.addMeasurementColumn("sysAbsorption", AsysGut) simulationSample.addMeasurementColumn("sysCentral", AsysCtr) simulationSample.addMeasurementColumn("sysPeripheral", AsysPer) simulationSample.addMeasurementColumn("Cp", CsysPer) simulationSample.setDescriptorValue("dose_nmol", depositionData['dose_nmol']) simulationSample.setDescriptorValue("throat_dose_nmol", depositionData['throat']) lungDose = depositionData['dose_nmol'] - depositionData['throat'] simulationSample.setDescriptorValue("lung_dose_nmol", lungDose) simulationSample.setDescriptorValue("bronchial_dose_nmol", bronchDose) simulationSample.setDescriptorValue("alveolar_dose_nmol", alvDose) simulationSample.setDescriptorValue("mcc_cleared_lung_dose_fraction", Abrcleared[-1] / lungDose) self.experimentLungRetention.samples[ "simulmvarNameation"] = simulationSample self.experimentLungRetention.write(self._getPath("experiment.pkpd")) # Plots import matplotlib.pyplot as plt lungData = lungParams.getBronchial() Xbnd = np.sort([0] + lungData['end_cm'].tolist() + lungData['pos'].tolist()) Xctr = Xbnd[:-1] + np.diff(Xbnd) / 2 tvec = tt / 60 T = np.max(tvec) Cflu = sol['C']['br']['fluid'] Cs = substanceParams.getData()['Cs_br'] plt.figure(figsize=(15, 9)) plt.title('Concentration in bronchial fluid (Cs=%f [uM])' % Cs) plt.imshow(Cflu, interpolation='bilinear', aspect='auto', extent=[np.min(Xctr), np.max(Xctr), T, 0]) plt.clim(0, Cs) plt.xlim(np.min(Xctr), np.max(Xctr)) plt.ylim(0, T) plt.colorbar() plt.ylabel('Time [h]') plt.xlabel('Distance from throat [cm]') plt.savefig(self._getPath('concentrationBronchialFluid.png')) Ctis = sol['C']['br']['fluid'] plt.figure(figsize=(15, 9)) plt.title('Concentration in bronchial tissue') plt.imshow(Ctis, interpolation='bilinear', aspect='auto', extent=[np.min(Xctr), np.max(Xctr), T, 0]) plt.xlim(np.min(Xctr), np.max(Xctr)) plt.ylim(0, T) plt.colorbar() plt.ylabel('Time [h]') plt.xlabel('Distance from throat [cm]') plt.savefig(self._getPath('concentrationBronchialTissue.png')) def createOutputStep(self): self._defineOutputs(outputExperiment=self.experimentLungRetention) self._defineSourceRelation(self.ptrDeposition.get(), self.experimentLungRetention) self._defineSourceRelation(self.ptrPK.get(), self.experimentLungRetention) def _citations(self): return ['Hartung2020']
class ProtPKPDDeconvolveFourier(ProtPKPDODEBase): """ Deconvolve the drug dissolution from a compartmental model. It does the deconvolution in Fourier so that it only uses the impulse response of the compartmental model. This impulse response only depends on the distribution, metabolism and excretion (DME) part of the ADME properties, meaning that it overcomes the limitations of a poor modelling of the raise of the concentration. On the other side, it has the disadvantage of considering the noise as true fluctuations due to the absorption.""" _label = 'dissol deconv Fourier' SAME_INPUT = 0 ANOTHER_INPUT = 1 BIOAVAIL_NONE = 0 BIOAVAIL_MULT = 1 BIOAVAIL_DIV = 2 #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam('inputODE', params.PointerParam, label="Input ODE model", pointerClass='ProtPKPDMonoCompartment, ProtPKPDTwoCompartments, ProtPKPDODERefine, '\ 'ProtPKPDTwoCompartmentsClint, ProtPKPDTwoCompartmentsClintCl', help='Select a run of an ODE model') form.addParam('externalIV', params.EnumParam, choices=['Get impulse response from the same input fit', 'Get impulse response from another fit'], label='Impulse response source', default=self.SAME_INPUT, help="The impulse response is an estimate of the intravenous response") form.addParam('externalIVODE', params.PointerParam, label="External impulse response ODE model", condition='externalIV==1', pointerClass='ProtPKPDMonoCompartment, ProtPKPDTwoCompartments,ProtPKPDODERefine,' \ ' ProtPKPDTwoCompartmentsClint, ProtPKPDTwoCompartmentsClintCl', help='Select a run of an ODE model. It should be ideally the intravenous response.') form.addParam('normalize', params.BooleanParam, label="Normalize by dose", default=True, help='Normalize the output by the input dose, so that a total absorption is represented by 100.') form.addParam('considerBioaval', params.EnumParam, label="Consider bioavailability", default=self.BIOAVAIL_NONE, choices=['Do not correct','Multiply deconvolution by bioavailability','Divide deconvolution by bioavailability'], help='Take into account the bioavailability') form.addParam('saturate', params.BooleanParam, label="Saturate at 100%", default=True, condition='normalize', help='Saturate the absorption so that there cannot be values beyond 100') form.addParam('removeTlag', params.BooleanParam, label="Remove tlag effect", default=True, help='If set to True, then the deconvolution is performed ignoring the the tlag in the absorption.' 'This homogeneizes the different responses.') #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('deconvolve',self.inputODE.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addSample(self, sampleName, t, y): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.descriptors = {} newSample.addMeasurementPattern(["A"]) newSample.addMeasurementColumn("t", t) newSample.addMeasurementColumn("A",y) self.outputExperiment.samples[sampleName] = newSample def deconvolve(self, objId): self.protODE = self.inputODE.get() self.experiment = self.readExperiment(self.protODE.outputExperiment.fnPKPD) self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting) self.varNameX = self.fitting.predictor.varName self.varNameY = self.fitting.predicted.varName # Create drug source self.clearGroupParameters() self.createDrugSource() # Create output object self.outputExperiment = PKPDExperiment() tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(self.experiment.getTimeUnits().unit) Avar = PKPDVariable() Avar.varName = "A" Avar.varType = PKPDVariable.TYPE_NUMERIC Avar.role = PKPDVariable.ROLE_MEASUREMENT if self.normalize.get(): Avar.units = createUnit("none") else: Avar.units = createUnit(self.experiment.getDoseUnits()) self.outputExperiment.variables[tvar.varName] = tvar self.outputExperiment.variables[Avar.varName] = Avar self.outputExperiment.general["title"]="Deconvolution of the amount released" self.outputExperiment.general["comment"]="Amount released at any time t" # Create PK model timeRange = self.experiment.getRange(self.varNameX) deltaT = 0.5 t = np.arange(0.0,timeRange[1]*5+deltaT,deltaT) model = self.protODE.createModel() model.setExperiment(self.experiment) model.deltaT = deltaT model.setXVar(self.varNameX) model.setYVar(self.varNameY) model.x = t model.t0=0 model.tF=np.max(t) prmNames = model.getParameterNames() if len(self.experiment.samples)==0: print("Cannot find any sample in the experiment") return # Create unit dose drugSource = DrugSource() dose=None for sampleName, sample in self.experiment.samples.items(): sample.interpretDose() if len(sample.parsedDoseList)>0: dose = createDeltaDose(1.0, via=createVia("Intravenous; iv", self.experiment), dunits=sample.parsedDoseList[0].dunits) if dose is None: print("Cannot find any dose among the samples") return drugSource.setDoses([dose], 0.0, timeRange[1]) model.drugSource = drugSource # Get the input sample from another experiment if necessary sampleFrom = None if self.externalIV.get() == self.ANOTHER_INPUT: anotherExperiment = self.readExperiment(self.externalIVODE.get().outputExperiment.fnPKPD) for _, sampleFrom in anotherExperiment.samples.items(): # Take the first sample from the reference break # Simulate the different responses for sampleName, sample in self.experiment.samples.items(): self.printSection("Deconvolving "+sampleName) drugSourceSample = DrugSource() drugSourceSample.setDoses(sample.parsedDoseList, 0.0, timeRange[1]) p=[] tlag=0 for paramName in drugSourceSample.getParameterNames(): p.append(float(sample.getDescriptorValue(paramName))) if paramName.endswith('_tlag') and self.removeTlag.get(): tlag=float(sample.getDescriptorValue(paramName)) drugSourceSample.setParameters(p) if self.externalIV.get()==self.SAME_INPUT: sampleFrom = sample parameters=[] for prmName in prmNames: parameters.append(float(sampleFrom.descriptors[prmName])) model.setParameters(parameters) h = model.forwardModel(parameters, [t]*model.getResponseDimension())[0] ts,Cs = sample.getXYValues(self.varNameX,self.varNameY) ts=np.insert(ts,0,0.0) Cs=np.insert(Cs,0,0.0) ts, Cs = uniqueFloatValues(ts,Cs) B=InterpolatedUnivariateSpline(ts, Cs, k=1) C=np.clip(B(t),0.0,None) Fabs=np.clip(np.real(ifft(np.divide(fft(C),fft(h)))),0.0,None) cumulatedDose=0.0 A=t*0.0 # Allocate memory totalReleased = drugSourceSample.getAmountReleasedUpTo(10*t[-1]) # Divided by 100 to have a number between 0 and 100 print("Total amount released: %f"%totalReleased) print("t(min) A(%s)"%Avar.units._toString()) for i in range(t.size): cumulatedDose+=Fabs[i] A[i]=cumulatedDose if self.normalize.get(): A[i] *= 100.0/totalReleased print("%f %f"%(t[i],A[i])) # print("%f %f %f %f"%(t[i], A[i], drugSource.getAmountReleasedAt(t[i], 0.5), drugSource.getAmountReleasedUpTo(t[i] + 0.5))) if self.saturate.get() and self.normalize.get(): A = np.clip(A,None,100.0) if self.considerBioaval.get()==self.BIOAVAIL_DIV: A /= sample.getBioavailability() elif self.considerBioaval.get()==self.BIOAVAIL_MULT: A *= sample.getBioavailability() As, ts = uniqueFloatValues(np.clip(A,0,None),t-tlag) self.addSample(sampleName,ts,As) self.outputExperiment.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputODE.get(), self.outputExperiment) def _validate(self): return [] def _summary(self): return []
class ProtPKPDDissolutionIVIVCJoin(ProtPKPD): """ Join several IVIVCs into a single one. The strategy is to compute the average of all the plots involved in the IVIVC process: 1) tvivo -> tvitro; 2) tvitro -> Adissol; 3) Adissol->FabsPredicted. The plot tvivo-Fabs comes after the IVIVC process, while the plot tvivo-FabsOrig is the observed one in the input files. These two plots need not be exactly the same. """ _label = 'dissol ivivc join avg' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'inputIVIVCs', params.MultiPointerParam, label="IVIVCs Fabs", pointerClass='PKPDExperiment', help= 'Choose experiments with IVIV correlations (only the Fabs experiments)' ) #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('calculateAllIvIvC') self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def calculateAllIvIvC(self): L1 = [] L2 = [] L3 = [] L4 = [] L5 = [] for ptrExperiment in self.inputIVIVCs: experiment = PKPDExperiment() experiment.load(ptrExperiment.get().fnPKPD.get()) x, y = experiment.getXYMeanValues("tvivo", "tvitroReinterpolated") L1.append((x, y)) x, y = experiment.getXYMeanValues("tvivo", "Fabs") L2.append((x, y)) x, y = experiment.getXYMeanValues("AdissolReinterpolated", "FabsPredicted") L3.append((x, y)) x, y = experiment.getXYMeanValues("FabsPredicted", "Fabs") L4.append((x, y)) x, y = experiment.getXYMeanValues("tvitroReinterpolated", "AdissolReinterpolated") L5.append((x, y)) tvivo1, tvitroReinterpolatedY = computeXYmean(L1, common=True) tvivoOrig, FabsOrig = computeXYmean(L2, common=True) AdissolReinterpolatedX, FabsPredictedY = computeXYmean(L3, common=True) FabsPredictedX, Fabs = computeXYmean(L4, common=True) tvitroReinterpolatedX, AdissolReinterpolatedY = computeXYmean( L5, common=True) x, y = twoWayUniqueFloatValues(tvivo1, tvitroReinterpolatedY) Bt = InterpolatedUnivariateSpline(x, y, k=1) x, y = twoWayUniqueFloatValues(tvitroReinterpolatedX, AdissolReinterpolatedY) BtA = InterpolatedUnivariateSpline(x, y, k=1) x, y = twoWayUniqueFloatValues(tvivoOrig, FabsOrig) BtF = InterpolatedUnivariateSpline(x, y, k=1) x, y = twoWayUniqueFloatValues(AdissolReinterpolatedX, FabsPredictedY) BAF = InterpolatedUnivariateSpline(x, y, k=1) x, y = twoWayUniqueFloatValues(FabsPredictedX, Fabs) BFF = InterpolatedUnivariateSpline(x, y, k=1) vtvitroReinterpolated = np.zeros(len(tvivo1)) vAdissolReinterpolated = np.zeros(len(tvivo1)) vFabs = np.zeros(len(tvivo1)) vFabsPredicted = np.zeros(len(tvivo1)) vFabsOrig = np.zeros(len(tvivo1)) for i in range(len(tvivo1)): tvivoi = tvivo1[i] vtvitroReinterpolated[i] = Bt(tvivoi) vAdissolReinterpolated[i] = BtA(vtvitroReinterpolated[i]) vFabsPredicted[i] = BAF(vAdissolReinterpolated[i]) vFabs[i] = BFF(vFabsPredicted[i]) vFabsOrig[i] = BtF(tvivoi) tvitroReinterpolatedVar = experiment.variables["tvitroReinterpolated"] AdissolReinterpolatedVar = experiment.variables[ "AdissolReinterpolated"] tvivoVar = experiment.variables["tvivo"] FabsOrigVar = copy.copy(experiment.variables["Fabs"]) FabsOrigVar.varName = "FabsOriginal" FabsVar = experiment.variables["Fabs"] FabsVar.comment += ". After IVIVC: tvivo->tvitro->Adissol->Fabs " FabsPredictedVar = experiment.variables["FabsPredicted"] self.outputExperimentFabsSingle = PKPDExperiment() self.outputExperimentFabsSingle.variables[ tvitroReinterpolatedVar.varName] = tvitroReinterpolatedVar self.outputExperimentFabsSingle.variables[ AdissolReinterpolatedVar.varName] = AdissolReinterpolatedVar self.outputExperimentFabsSingle.variables[tvivoVar.varName] = tvivoVar self.outputExperimentFabsSingle.variables[FabsVar.varName] = FabsVar self.outputExperimentFabsSingle.variables[ FabsPredictedVar.varName] = FabsPredictedVar self.outputExperimentFabsSingle.variables[ FabsOrigVar.varName] = FabsOrigVar self.outputExperimentFabsSingle.general[ "title"] = "In-vitro In-vivo correlation" self.outputExperimentFabsSingle.general[ "comment"] = "Fabs vs Predicted Fabs" sampleName = "jointIVIVC" newSampleFabsSingle = PKPDSample() newSampleFabsSingle.sampleName = sampleName newSampleFabsSingle.variableDictPtr = self.outputExperimentFabsSingle.variables newSampleFabsSingle.descriptors = {} newSampleFabsSingle.addMeasurementColumn("tvitroReinterpolated", vtvitroReinterpolated) newSampleFabsSingle.addMeasurementColumn("AdissolReinterpolated", vAdissolReinterpolated) newSampleFabsSingle.addMeasurementColumn("tvivo", tvivo1) newSampleFabsSingle.addMeasurementColumn("FabsPredicted", vFabsPredicted) newSampleFabsSingle.addMeasurementColumn("Fabs", vFabs) newSampleFabsSingle.addMeasurementColumn("FabsOriginal", vFabsOrig) self.outputExperimentFabsSingle.samples[ sampleName] = newSampleFabsSingle self.outputExperimentFabsSingle.addLabelToSample( sampleName, "from", "individual---vesel", "AvgVivo---AvgVitro") self.outputExperimentFabsSingle.write( self._getPath("experimentFabsSingle.pkpd")) def createOutputStep(self): self._defineOutputs( outputExperimentFabsSingle=self.outputExperimentFabsSingle) for ptrExperiment in self.inputIVIVCs: self._defineSourceRelation(ptrExperiment.get(), self.outputExperimentFabsSingle) def _validate(self): retval = [] for ptrExperiment in self.inputIVIVCs: if not "experimentFabs" in ptrExperiment.get().fnPKPD.get(): retval.append("You can only take Fabs files") return retval def _summary(self): return []
class ProtPKPDDissolutionTarget(ProtPKPD): """ Given an in-vivo absorption profile (assumed to be between 0 and 100), and the IVIVC parameters specified in this protocol, the protocol calculates the target in-vitro dissolution profile""" _label = 'dissol target' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'inputInVivo', params.PointerParam, label="Dissolution profiles in vivo", pointerClass= 'ProtPKPDDeconvolve,ProtPKPDDeconvolutionWagnerNelson,ProtPKPDDeconvolutionLooRiegelman, PKPDExperiment', help='Select an experiment with dissolution profiles') ts = form.addGroup( "Time scaling (Delayed power scale (Fabs(t)=Adissol(k*(t-t0)^alpha))" ) ts.addParam( 't0', params.FloatParam, label='t0', default=0, help='Make sure it is in the same time units as the inputs') ts.addParam('k', params.FloatParam, label='k', default=1) ts.addParam('alpha', params.FloatParam, label='alpha', default=1) rs = form.addGroup( "Response scaling (Affine transformation (Fabs(t)=A*Adissol(t)+B))" ) rs.addParam('A', params.FloatParam, label='A', default=1) rs.addParam('B', params.FloatParam, label='B', default=0) rs.addParam('saturate', params.BooleanParam, label='Saturate at 100%', default=True, help='Saturate the calculated Adissol at 100%') #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('calculateTarget', self.inputInVivo.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def getInVivoProfiles(self): if hasattr(self.inputInVivo.get(), "outputExperiment"): fnPKPD = self.inputInVivo.get().outputExperiment.fnPKPD elif hasattr(self.inputInVivo.get(), "fnPKPD"): fnPKPD = self.inputInVivo.get().fnPKPD else: raise Exception( "Cannot find a suitable filename for reading the experiment") experiment = self.readExperiment(fnPKPD) allY = [] sampleNames = [] for sampleName, sample in experiment.samples.items(): t = sample.getValues("t") y = sample.getValues("A") allY.append((np.asarray(t, dtype=np.float64), np.asarray(y, dtype=np.float64))) sampleNames.append(sampleName) self.experimentInVivo = experiment return allY, sampleNames def addSample(self, sampleName): newSampleAdissol = PKPDSample() newSampleAdissol.sampleName = sampleName newSampleAdissol.variableDictPtr = self.outputExperiment.variables newSampleAdissol.descriptors = {} newSampleAdissol.addMeasurementColumn("tvitro", self.tvitroUnique) newSampleAdissol.addMeasurementColumn("Adissol", self.AdissolUnique) self.outputExperiment.samples[sampleName] = newSampleAdissol def produceAdissol(self, parameterInVitro, tmax): deltaT = np.min([(tmax + 1) / 1000, 1.0]) tvitro = np.arange(0, tmax + 1, deltaT) if self.removeInVitroTlag: i = 0 for prmName in self.protFit.model.getParameterNames(): if "tlag" in prmName: parameterInVitro[i] = 0.0 i += 1 self.protFit.model.x = tvitro Avitro = self.protFit.model.forwardModel(parameterInVitro)[0] return (tvitro, Avitro) def createOutputExperiment(self): tvitroVar = PKPDVariable() tvitroVar.varName = "tvitro" tvitroVar.varType = PKPDVariable.TYPE_NUMERIC tvitroVar.role = PKPDVariable.ROLE_TIME tvitroVar.units = createUnit(self.experimentInVivo.getTimeUnits().unit) tvitroVar.comment = "tvitro" AdissolVar = PKPDVariable() AdissolVar.varName = "Adissol" AdissolVar.varType = PKPDVariable.TYPE_NUMERIC AdissolVar.role = PKPDVariable.ROLE_MEASUREMENT AdissolVar.units = createUnit(PKPDUnit.UNIT_NONE) AdissolVar.comment = "Amount disolved in vitro" self.outputExperiment = PKPDExperiment() self.outputExperiment.variables[tvitroVar.varName] = tvitroVar self.outputExperiment.variables[AdissolVar.varName] = AdissolVar self.outputExperiment.general["title"] = "In-vitro target simulation" self.outputExperiment.general["comment"] = "" def calculateTarget(self, objId1): self.profilesInVivo, self.sampleNames = self.getInVivoProfiles() self.createOutputExperiment() # Compute all pairs for profileInVivo, sampleName in izip(self.profilesInVivo, self.sampleNames): tvivo = profileInVivo[0] Fabs = profileInVivo[1] FabsUnique, tvivoUnique = uniqueFloatValues(Fabs, tvivo) BFabs = InterpolatedUnivariateSpline(tvivoUnique, FabsUnique, k=1) tmax = np.max(tvivoUnique) deltaT = np.min([(tmax + 1) / 1000, 1.0]) tvivop = np.arange(0, tmax + 1, deltaT) Fabsp = BFabs(tvivop) tvitro = self.k.get() * np.power(tvivop - self.t0.get(), self.alpha.get()) Adissol = np.clip((Fabsp - self.B.get()) / self.A.get(), 0, None) if self.saturate: Adissol = np.clip(Adissol, None, 100.0) self.AdissolUnique, self.tvitroUnique = uniqueFloatValues( Adissol, tvitro) self.addSample("target_%s" % sampleName) self.outputExperiment.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputInVivo.get(), self.outputExperiment)
class ProtPKPDDeconvolutionLooRiegelman(ProtPKPD): """ Calculate the absorption profile of an in vivo concentration profile using the Loo-Riegelman approach. This is only valid for profiles that have been modelled with a two-compartments PK model. The formula is Fabs(t)=(Cp(t)+Cperipheral(t)+K10*AUC0t(t))/(K10*AUC0inf) where K10=Cl/V and Cperipheral(t_n)=k12*Delta Cp*Delta t/2+k12/k21 * Cp(t_n-1)(1-exp(-k21*Delta t))+Cperipheral(t_n-1)*exp(-k21*Delta t) In this implementation it is assumed that AUC0inf is the last AUC0t observed, meaning that Cp(t) has almost vanished in the last samples. This protocol is much more accurate when the input Cp(t) is reinterpolated to a small time step like 0.5 minutes. Reference: Leon Shargel, Susanna Wu-Pong, Andrew B.C. Yu. Applied Biopharmaceutics & Pharmacokinetics, 6e. McGraw Hill, 1999. Chap. 7""" _label = 'deconvolution Loo-Riegelman' SAME_INPUT = 0 ANOTHER_INPUT = 1 BIOAVAIL_NONE = 0 BIOAVAIL_MULT = 1 BIOAVAIL_DIV = 2 #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'inputExperiment', params.PointerParam, label="In-vivo profiles", pointerClass='PKPDExperiment', help= 'Make sure that it has a clearance parameter (Cl) and central volume (V)' ) form.addParam( 'externalIV', params.EnumParam, choices=[ 'Get impulse response from the same input fit', 'Get impulse response from another fit' ], label='Impulse response source', default=self.SAME_INPUT, help= "The impulse response is an estimate of the intravenous response") form.addParam('externalIVODE', params.PointerParam, label="External impulse response ODE model", condition='externalIV==1', pointerClass='ProtPKPDMonoCompartment, ProtPKPDTwoCompartments,ProtPKPDODERefine,' \ ' ProtPKPDTwoCompartmentsClint, ProtPKPDTwoCompartmentsClintCl', help='Select a run of an ODE model. It should be ideally the intravenous response.') form.addParam('timeVar', params.StringParam, label="Time variable", default="t", help='Which variable contains the time stamps.') form.addParam('concVar', params.StringParam, label="Concentration variable", default="Cp", help='Which variable contains the plasma concentration.') form.addParam( 'normalize', params.BooleanParam, label="Normalize by dose", default=True, help= 'Normalize the output by AUC0inf, so that a total absorption is represented by 100.' ) form.addParam( 'saturate', params.BooleanParam, label="Saturate at 100%", default=True, help= 'Saturate the absorption so that there cannot be values beyond 100' ) form.addParam('considerBioaval', params.EnumParam, label="Consider bioavailability", default=self.BIOAVAIL_NONE, choices=[ 'Do not correct', 'Multiply deconvolution by bioavailability', 'Divide deconvolution by bioavailability' ], help='Take into account the bioavailability') form.addParam( 'resampleT', params.FloatParam, label="Resample profiles (time step)", default=0.5, help= 'Resample the input profiles at this time step (make sure it is in the same units as the input). ' 'Leave it to -1 for no resampling') form.addParam( 'smooth', params.BooleanParam, label="Monotonic smooth", default=True, help= 'Apply a Pchip interpolation to make sure that the Adissolved is monotonically increasing' ) #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('deconvolve', self.inputExperiment.get().getObjId()) self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def addSample(self, sampleName, t, y): newSample = PKPDSample() newSample.sampleName = sampleName newSample.variableDictPtr = self.outputExperiment.variables newSample.descriptors = {} newSample.addMeasurementPattern(["A"]) newSample.addMeasurementColumn("t", t) newSample.addMeasurementColumn("A", y) self.outputExperiment.samples[sampleName] = newSample def calculateCperipheral(self, t, Cp, k12, k21): Cperipheral = np.zeros(t.shape) for n in range(1, Cperipheral.size): DeltaCp = np.abs(Cp[n] - Cp[n - 1]) DeltaT = t[n] - t[n - 1] Cperipheral[n] = k12*DeltaCp*DeltaT*0.5 + \ k12 / k21 * Cp[n-1]*(1 - np.exp(-k21 * DeltaT)) + \ Cperipheral[n-1] * np.exp(-k21 * DeltaT) if Cperipheral[n] < 0.0: Cperipheral[n] = 0.0 return Cperipheral def deconvolve(self, objId1): self.experiment = self.readExperiment( self.inputExperiment.get().fnPKPD) # Create output object self.outputExperiment = PKPDExperiment() tvar = PKPDVariable() tvar.varName = "t" tvar.varType = PKPDVariable.TYPE_NUMERIC tvar.role = PKPDVariable.ROLE_TIME tvar.units = createUnit(self.experiment.getTimeUnits().unit) Avar = PKPDVariable() Avar.varName = "A" Avar.varType = PKPDVariable.TYPE_NUMERIC Avar.role = PKPDVariable.ROLE_MEASUREMENT Avar.units = createUnit("none") self.outputExperiment.variables[tvar.varName] = tvar self.outputExperiment.variables[Avar.varName] = Avar self.outputExperiment.general[ "title"] = "Deconvolution of the amount released" self.outputExperiment.general[ "comment"] = "Amount released at any time t" # Get the input sample from another experiment if necessary sampleFrom = None if self.externalIV.get() == self.ANOTHER_INPUT: anotherExperiment = self.readExperiment( self.externalIVODE.get().outputExperiment.fnPKPD) for _, sampleFrom in anotherExperiment.samples.items( ): # Take the first sample from the reference break timeRange = self.experiment.getRange(self.timeVar.get()) for sampleName, sample in self.experiment.samples.items(): # Get t, Cp t = np.asarray(sample.getValues(self.timeVar.get()), dtype=np.float64) Cp = np.asarray(sample.getValues(self.concVar.get()), dtype=np.float64) Cp = np.clip(Cp, 0.0, None) t = np.insert(t, 0, 0) # Add (0,0) to the profile Cp = np.insert(Cp, 0, 0) t, Cp = uniqueFloatValues(t, Cp) if self.resampleT.get() > 0: B = InterpolatedUnivariateSpline(t, Cp, k=1) t = np.arange(np.min(t), np.max(t) + self.resampleT.get(), self.resampleT.get()) Cp = B(t) # Calculate AUC0t AUC0t = calculateAUC0t(t, Cp) AUC0inf = float(AUC0t[-1]) # Calculate peripheral if self.externalIV.get() == self.SAME_INPUT: sampleFrom = sample Cl = float(sampleFrom.descriptors['Cl']) V = float(sampleFrom.descriptors['V']) Clp = float(sampleFrom.descriptors['Clp']) Vp = float(sampleFrom.descriptors['Vp']) k12 = Clp / V k21 = Clp / Vp Cperipheral = self.calculateCperipheral(t, Cp, k12, k21) # Deconvolve k10 = Cl / V A = (Cp + Cperipheral + k10 * AUC0t) / k10 if self.normalize.get(): A *= 100 / AUC0inf if self.saturate.get(): A = np.clip(A, None, 100.0) A = np.clip(A, 0, None) if self.smooth: if t[0] > 0: t = np.insert(t, 0, 0) A = np.insert(A, 0, 0) if self.saturate.get() and self.normalize.get(): A = np.clip(A, None, 100.0) A = np.clip(smoothPchip(t, A), 0, None) if self.considerBioaval.get() == self.BIOAVAIL_DIV: A /= sample.getBioavailability() elif self.considerBioaval.get() == self.BIOAVAIL_MULT: A *= sample.getBioavailability() self.addSample(sampleName, t, A) self.outputExperiment.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperiment) self._defineSourceRelation(self.inputExperiment.get(), self.outputExperiment) def _validate(self): return [] def _summary(self): retval = [] return retval
class ProtPKPDDissolutionLevyPlotJoin(ProtPKPD): """ Join several Levy plots into a single one. The strategy is to compute the average of all the plots involved in the Levy plot process: 1) tvivo -> tvitro """ _label = 'dissol levyplot join avg' #--------------------------- DEFINE param functions -------------------------------------------- def _defineParams(self, form): form.addSection('Input') form.addParam( 'inputLevyplots', params.MultiPointerParam, label="Levy plots", pointerClass='PKPDExperiment', help= 'Choose experiments with IVIV correlations (only the Fabs experiments)' ) #--------------------------- INSERT steps functions -------------------------------------------- def _insertAllSteps(self): self._insertFunctionStep('calculateAllLevy') self._insertFunctionStep('createOutputStep') #--------------------------- STEPS functions -------------------------------------------- def calculateAllLevy(self): L1 = [] for ptrExperiment in self.inputLevyplots: experiment = PKPDExperiment() experiment.load(ptrExperiment.get().fnPKPD.get()) x, y = experiment.getXYMeanValues("tvivo", "tvitro") L1.append((x, y)) tvivo, tvitro = computeXYmean(L1, common=True) x, y = twoWayUniqueFloatValues(tvivo, tvitro) Bt = InterpolatedUnivariateSpline(x, y, k=1) vtvitroReinterpolated = np.zeros(len(tvivo)) for i in range(len(tvivo)): tvivoi = tvivo[i] vtvitroReinterpolated[i] = Bt(tvivoi) tvitroReinterpolatedVar = experiment.variables["tvitro"] tvivoVar = experiment.variables["tvivo"] self.outputExperimentSingle = PKPDExperiment() self.outputExperimentSingle.variables[ tvitroReinterpolatedVar.varName] = tvitroReinterpolatedVar self.outputExperimentSingle.variables[tvivoVar.varName] = tvivoVar self.outputExperimentSingle.general["title"] = "Levy plot" self.outputExperimentSingle.general["comment"] = "tvitro vs tvivo" sampleName = "jointLevyPlot" newSampleSingle = PKPDSample() newSampleSingle.sampleName = sampleName newSampleSingle.variableDictPtr = self.outputExperimentSingle.variables newSampleSingle.descriptors = {} newSampleSingle.addMeasurementColumn("tvitro", vtvitroReinterpolated) newSampleSingle.addMeasurementColumn("tvivo", tvivo) self.outputExperimentSingle.samples[sampleName] = newSampleSingle self.outputExperimentSingle.addLabelToSample(sampleName, "from", "individual---vesel", "meanVivo---meanVitro") self.outputExperimentSingle.write(self._getPath("experiment.pkpd")) def createOutputStep(self): self._defineOutputs(outputExperiment=self.outputExperimentSingle) for ptrExperiment in self.inputLevyplots: self._defineSourceRelation(ptrExperiment.get(), self.outputExperimentSingle) def _summary(self): return []