Source code for pkpd.protocols.protocol_pkpd_dissolution_fit

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

import pyworkflow.protocol.params as params
from pyworkflow.protocol.constants import LEVEL_ADVANCED
from .protocol_pkpd_fit_base import ProtPKPDFitBase
from pkpd.models.dissolution_models import *
from pkpd.objects import PKPDExperiment, PKPDSample

# Tested by test_workflow_dissolution
# Tested by test_workflow_levyplot
# Tested by test_workflow_deconvolution2
# Tested in test_workflow_ivivc.py
# Tested in test_workflow_ivivc2.py

[docs]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.')
[docs] def getListOfFormDependencies(self): return [self.allowTlag.get(), self.modelType.get(), self.bounds.get(), self.confidenceInterval.get()]
#--------------------------- STEPS functions --------------------------------------------
[docs] 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()
[docs] def setupFromFormParameters(self): self.model.allowTlag = self.allowTlag.get()
[docs] 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"
[docs] 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
[docs] def postAnalysis(self): if self.resampleT.get()>0: self.experimentSimulated.write(self._getPath("experimentSimulated.pkpd"))
[docs] def createOutputStep(self): ProtPKPDFitBase.createOutputStep(self) if self.resampleT.get()>0: self._defineOutputs(outputExperimentSimulated=self.experimentSimulated) self._defineSourceRelation(self.getInputExperiment(), self.experimentSimulated)