Ejemplo n.º 1
0
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
Ejemplo n.º 2
0
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)
Ejemplo n.º 3
0
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 []
Ejemplo n.º 4
0
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
Ejemplo n.º 5
0
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
Ejemplo n.º 6
0
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
Ejemplo n.º 7
0
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)
Ejemplo n.º 8
0
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
Ejemplo n.º 9
0
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
Ejemplo n.º 10
0
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']
Ejemplo n.º 11
0
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()]
Ejemplo n.º 12
0
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
Ejemplo n.º 13
0
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
Ejemplo n.º 14
0
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']
Ejemplo n.º 15
0
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 []
Ejemplo n.º 16
0
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 []
Ejemplo n.º 17
0
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)
Ejemplo n.º 18
0
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
Ejemplo n.º 19
0
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 []