Example #1
0
 def readFitting(self, fnIn, show=True, cls=""):
     fitting = PKPDFitting(cls)
     fitting.load(fnIn)
     if show:
         self.printSection("Reading %s"%fnIn)
         fitting._printToStream(sys.stdout)
     return fitting
Example #2
0
    def visualize(self, obj, **kwargs):
        if hasattr(obj, "outputPopulation"):
            population = PKPDFitting("PKPDSampleFitBootstrap")
            population.load(obj.outputPopulation.fnFitting)

            self.populationWindow = self.tkWindow(PopulationWindow,
                                                  title='Population Viewer',
                                                  population=population)
            self.populationWindow.show()
Example #3
0
    def visualize(self, obj, **kwargs):
        if hasattr(obj,"outputPopulation"):
            population = PKPDFitting("PKPDSampleFitBootstrap")
            population.load(obj.outputPopulation.fnFitting)

            self.populationWindow = self.tkWindow(PopulationWindow,
                                                  title='Population Viewer',
                                                  population=population)
            self.populationWindow.show()
Example #4
0
    def runMerge(self, objId1, objId2):
        self.population1 = self.readFitting(
            self.inputPopulation1.get().fnFitting,
            cls="PKPDSampleFitBootstrap")
        self.population2 = self.readFitting(
            self.inputPopulation2.get().fnFitting,
            cls="PKPDSampleFitBootstrap")
        self.printSection("Merging populations")

        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.population1.fnExperiment)
        self.fitting.predictor = self.population1.predictor
        self.fitting.predicted = self.population1.predicted
        self.fitting.modelParameterUnits = self.population1.modelParameterUnits
        self.fitting.modelParameters = self.population1.modelParameters
        self.fitting.modelDescription = self.population1.modelDescription

        newSampleFit = PKPDSampleFitBootstrap()
        newSampleFit.sampleName = "Merged population"
        newSampleFit.parameters = None
        for sampleFit in self.population1.sampleFits:
            if newSampleFit.parameters == None:
                newSampleFit.parameters = np.copy(sampleFit.parameters)
                newSampleFit.xB = copy.copy(sampleFit.xB)
                newSampleFit.yB = copy.copy(sampleFit.yB)
                newSampleFit.R2 = copy.copy(sampleFit.R2)
                newSampleFit.R2adj = copy.copy(sampleFit.R2adj)
                newSampleFit.AIC = copy.copy(sampleFit.AIC)
                newSampleFit.AICc = copy.copy(sampleFit.AICc)
                newSampleFit.BIC = copy.copy(sampleFit.BIC)
            else:
                newSampleFit.parameters = np.vstack(
                    [newSampleFit.parameters, sampleFit.parameters])
                newSampleFit.xB += sampleFit.xB
                newSampleFit.yB += sampleFit.yB
                newSampleFit.R2 += sampleFit.R2
                newSampleFit.R2adj += sampleFit.R2adj
                newSampleFit.AIC += sampleFit.AIC
                newSampleFit.AICc += sampleFit.AICc
                newSampleFit.BIC += sampleFit.BIC
        for sampleFit in self.population2.sampleFits:
            newSampleFit.parameters = np.vstack(
                [newSampleFit.parameters, sampleFit.parameters])
            print(type(newSampleFit.xB))
            print(type(sampleFit.xB))
            newSampleFit.xB += sampleFit.xB
            newSampleFit.yB += sampleFit.yB
            newSampleFit.R2 += sampleFit.R2
            newSampleFit.R2adj += sampleFit.R2adj
            newSampleFit.AIC += sampleFit.AIC
            newSampleFit.AICc += sampleFit.AICc
            newSampleFit.BIC += sampleFit.BIC
        self.fitting.sampleFits.append(newSampleFit)

        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))
Example #5
0
 def readFitting(self, fnIn, show=True, cls=""):
     fitting = PKPDFitting(cls)
     fitting.load(fnIn)
     if show:
         self.printSection("Reading %s" % fnIn)
         fitting._printToStream(sys.stdout)
     return fitting
    def runMerge(self, objId1, objId2):
        self.population1 = self.readFitting(self.inputPopulation1.get().fnFitting,cls="PKPDSampleFitBootstrap")
        self.population2 = self.readFitting(self.inputPopulation2.get().fnFitting,cls="PKPDSampleFitBootstrap")
        self.printSection("Merging populations")

        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.population1.fnExperiment)
        self.fitting.predictor=self.population1.predictor
        self.fitting.predicted=self.population1.predicted
        self.fitting.modelParameterUnits = self.population1.modelParameterUnits
        self.fitting.modelParameters = self.population1.modelParameters
        self.fitting.modelDescription = self.population1.modelDescription

        newSampleFit = PKPDSampleFitBootstrap()
        newSampleFit.sampleName = "Merged population"
        newSampleFit.parameters = None
        for sampleFit in self.population1.sampleFits:
            if newSampleFit.parameters == None:
                newSampleFit.parameters = np.copy(sampleFit.parameters)
                newSampleFit.xB = copy.copy(sampleFit.xB)
                newSampleFit.yB = copy.copy(sampleFit.yB)
                newSampleFit.R2 = copy.copy(sampleFit.R2)
                newSampleFit.R2adj = copy.copy(sampleFit.R2adj)
                newSampleFit.AIC = copy.copy(sampleFit.AIC)
                newSampleFit.AICc = copy.copy(sampleFit.AICc)
                newSampleFit.BIC = copy.copy(sampleFit.BIC)
            else:
                newSampleFit.parameters = np.vstack([newSampleFit.parameters, sampleFit.parameters])
                newSampleFit.xB += sampleFit.xB
                newSampleFit.yB += sampleFit.yB
                newSampleFit.R2 += sampleFit.R2
                newSampleFit.R2adj += sampleFit.R2adj
                newSampleFit.AIC += sampleFit.AIC
                newSampleFit.AICc += sampleFit.AICc
                newSampleFit.BIC += sampleFit.BIC
        for sampleFit in self.population2.sampleFits:
            newSampleFit.parameters = np.vstack([newSampleFit.parameters, sampleFit.parameters])
            print(type(newSampleFit.xB))
            print(type(sampleFit.xB))
            newSampleFit.xB += sampleFit.xB
            newSampleFit.yB += sampleFit.yB
            newSampleFit.R2 += sampleFit.R2
            newSampleFit.R2adj += sampleFit.R2adj
            newSampleFit.AIC += sampleFit.AIC
            newSampleFit.AICc += sampleFit.AICc
            newSampleFit.BIC += sampleFit.BIC
        self.fitting.sampleFits.append(newSampleFit)

        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))
Example #7
0
 def createFitting(self, prot, experiment, suffix):
     # Create output object
     fitting = PKPDFitting()
     fitting.fnExperiment.set(self._getPath("experiment%d.pkpd"%suffix))
     fitting.predictor=experiment.variables[prot.varNameX]
     if type(prot.varNameY)==list:
         fitting.predicted=[]
         for y in prot.varNameY:
             fitting.predicted.append(experiment.variables[y])
     else:
         fitting.predicted=experiment.variables[prot.varNameY]
     fitting.modelParameterUnits = None
     return fitting
Example #8
0
    def runFilter(self, objId, filterType, condition):
        self.population = self.readFitting(self.inputPopulation.get().fnFitting,cls="PKPDSampleFitBootstrap")
        self.printSection("Filtering population")

        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.population.fnExperiment)
        self.fitting.predictor=self.population.predictor
        self.fitting.predicted=self.population.predicted
        self.fitting.modelParameterUnits = self.population.modelParameterUnits
        self.fitting.modelParameters = self.population.modelParameters
        self.fitting.modelDescription = self.population.modelDescription

        newSampleFit = PKPDSampleFitBootstrap()
        newSampleFit.parameters = None
        filterType = self.filterType.get()
        for sampleFit in self.population.sampleFits:
            newSampleFit.sampleName = sampleFit.sampleName
            if newSampleFit.parameters == None:
                newSampleFit.parameters = np.empty((0,sampleFit.parameters.shape[1]))
                newSampleFit.xB = []
                newSampleFit.yB = []
                newSampleFit.R2 = []
                newSampleFit.R2adj = []
                newSampleFit.AIC = []
                newSampleFit.AICc = []
                newSampleFit.BIC = []

            if filterType<=1:
                conditionToEvaluate = self.condition.get()
            else:
                tokens=self.condition.get().strip().split(' ')
                variable = tokens[0][2:-1]
                confidenceLevel = float(tokens[1])
                columnIdx = -1
                for j in range(len(self.population.modelParameters)):
                    if self.population.modelParameters[j]==variable:
                        columnIdx = j
                        break
                if columnIdx==-1:
                    raise Exception("Cannot find %s amongst the model variables"%variable)
                values=sampleFit.parameters[:,columnIdx]
                alpha_2 = (100-confidenceLevel)/2
                limits = np.percentile(values,[alpha_2,100-alpha_2])
                conditionToEvaluate = "%s>=%f and %s<=%f"%(tokens[0],limits[0],tokens[0],limits[1])
                print("Condition to evaluate: %s"%conditionToEvaluate)

            for n in range(0,len(sampleFit.R2)):
                evaluatedCondition = copy.copy(conditionToEvaluate)
                evaluatedCondition = evaluatedCondition.replace('$(R2)',"(%f)"%sampleFit.R2[n])
                evaluatedCondition = evaluatedCondition.replace('$(R2adj)',"(%f)"%sampleFit.R2adj[n])
                evaluatedCondition = evaluatedCondition.replace('$(AIC)',"(%f)"%sampleFit.AIC[n])
                evaluatedCondition = evaluatedCondition.replace('$(AICc)',"(%f)"%sampleFit.AICc[n])
                evaluatedCondition = evaluatedCondition.replace('$(BIC)',"(%f)"%sampleFit.BIC[n])

                for j in range(len(self.population.modelParameters)):
                    evaluatedCondition = evaluatedCondition.replace('$(%s)'%self.population.modelParameters[j],"(%f)"%sampleFit.parameters[n,j])
                evaluatedCondition = eval(evaluatedCondition)
                if (filterType==0 and not evaluatedCondition) or (filterType>=1 and evaluatedCondition):
                    newSampleFit.parameters = np.vstack([newSampleFit.parameters, sampleFit.parameters[n,:]])
                    newSampleFit.xB += sampleFit.xB
                    newSampleFit.yB += sampleFit.yB
                    newSampleFit.R2.append(sampleFit.R2[n])
                    newSampleFit.R2adj.append(sampleFit.R2adj[n])
                    newSampleFit.AIC.append(sampleFit.AIC[n])
                    newSampleFit.AICc.append(sampleFit.AICc[n])
                    newSampleFit.BIC.append(sampleFit.BIC[n])

        self.fitting.sampleFits.append(newSampleFit)
        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))
class ProtPKPDFitBase(ProtPKPD):
    """ Base fit protocol"""

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams1(self, form, defaultPredictor, defaultPredicted):
        form.addSection('Input')
        form.addParam('inputExperiment', params.PointerParam, label="Input experiment",
                      pointerClass='PKPDExperiment',
                      help='Select an experiment with samples')
        form.addParam('predictor', params.StringParam, label="Predictor variable (X)", default=defaultPredictor,
                      help='Y is predicted as an exponential function of X, Y=f(X)')
        form.addParam('predicted', params.StringParam, label="Predicted variable (Y)", default=defaultPredicted,
                      help='Y is predicted as an exponential function of X, Y=f(X)')

    #--------------------------- INSERT steps functions --------------------------------------------
    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',self.getInputExperiment().getObjId(),self.getListOfFormDependencies())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def getInputExperiment(self):
        if hasattr(self,"inputExperiment"):
            return self.inputExperiment.get()
        else:
            return None

    def getXYvars(self):
        if hasattr(self,"predictor"):
            self.varNameX=self.predictor.get()
        else:
            self.varNameX=None

        if hasattr(self,"predicted"):
            self.varNameY=self.predicted.get()
        else:
            self.varNameY=None

    def setExperiment(self, experiment):
        self.experiment = experiment
        if experiment!=None:
            self.fnExperiment = experiment.fnPKPD

    def setSample(self, sample):
        self.sample = sample
        self.model.setSample(sample)

    def createModel(self):
        pass

    def parseBounds(self, boundsString):
        self.boundsList = []

        if boundsString!="" and boundsString!=None:
            tokens = boundsString.split(';')
            if len(tokens)!=self.getNumberOfParameters():
                raise Exception("The number of bound intervals does not match the number of parameters")

            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append((float(values[0][1:]),float(values[1][:-1])))

    def getBounds(self):
        return self.boundsList

    def getParameterBounds(self):
        """ Return a dictionary where the parameter name is the key
        and the bounds are its values. """
        boundsDict = OrderedDict()
        self.parseBounds(self.bounds.get()) # after this we have boundsList
        parameterNames = self.model.getParameterNames()

        for paramName, bound in izip(parameterNames, self.getBounds()):
            boundsDict[paramName] = bound

        # Set None as bound for parameters not matched
        for paramName in parameterNames:
            if paramName not in boundsDict:
                boundsDict[paramName] = None

        return boundsDict

    def setupModel(self):
        # Setup model
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.setupFromFormParameters()
        self.getXYvars()
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)

    def calculateParameterUnits(self,sample):
        self.parameterUnits = self.model.calculateParameterUnits(sample)

    def getParameterNames(self):
        return self.model.getParameterNames()

    def getNumberOfParameters(self):
        return len(self.getParameterNames())

    def setParameters(self,prm):
        self.model.setParameters(prm)

    def forwardModel(self,prm,xValues):
        return self.model.forwardModel(prm,xValues)

    def setupFromFormParameters(self):
        pass

    def prepareForSampleAnalysis(self, sampleName):
        pass

    def postSampleAnalysis(self, sampleName):
        pass

    def runFit(self, objId, otherDependencies):
        self.getXYvars()
        if hasattr(self,"reportX"):
            reportX = parseRange(self.reportX.get())
        else:
            reportX = None
        self.experiment = self.readExperiment(self.getInputExperiment().fnPKPD)

        # Setup model
        self.printSection("Model setup")
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)
        self.setupFromFormParameters()
        self.model.printSetup()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.getInputExperiment().fnPKPD.get())
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelDescription=self.model.getDescription()
        self.fitting.modelParameters = self.model.getParameterNames()
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get()==0:
            fitType = "linear"
        elif self.fitType.get()==1:
            fitType = "log"
        elif self.fitType.get()==2:
            fitType = "relative"

        for sampleName, sample in self.experiment.samples.iteritems():
            self.printSection("Fitting "+sampleName)
            x, y = sample.getXYValues(self.varNameX,self.varNameY)
            print("X= "+str(x))
            print("Y= "+str(y))
            print(" ")
            self.model.setBounds(self.bounds.get())
            self.model.setXYValues(x, y)
            self.prepareForSampleAnalysis(sampleName)
            self.model.calculateParameterUnits(sample)
            if self.fitting.modelParameterUnits==None:
                self.fitting.modelParameterUnits = self.model.parameterUnits
            self.model.prepare()
            if self.model.bounds == None:
                continue
            print(" ")

            optimizer1 = PKPDDEOptimizer(self.model,fitType)
            optimizer1.optimize()
            optimizer2 = PKPDLSOptimizer(self.model,fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            # Keep this result
            sampleFit = PKPDSampleFit()
            sampleFit.sampleName = sample.sampleName
            sampleFit.x = self.model.x
            sampleFit.y = self.model.y
            sampleFit.yp = self.model.yPredicted
            sampleFit.yl = self.model.yPredictedLower
            sampleFit.yu = self.model.yPredictedUpper
            sampleFit.parameters = self.model.parameters
            sampleFit.modelEquation = self.model.getEquation()
            sampleFit.copyFromOptimizer(optimizer2)
            self.fitting.sampleFits.append(sampleFit)

            # Add the parameters to the sample and experiment
            for varName, varUnits, description, varValue in izip(self.model.getParameterNames(), self.model.parameterUnits, self.model.getParameterDescriptions(), self.model.parameters):
                self.experiment.addParameterToSample(sampleName, varName, varUnits, description, varValue)

            self.postSampleAnalysis(sampleName)

            if reportX!=None:
                print("Evaluation of the model at specified time points")
                yreportX = self.model.forwardModel(self.model.parameters, reportX)
                print("==========================================")
                print("X     Ypredicted     log10(Ypredicted)")
                print("==========================================")
                for n in range(0,reportX.shape[0]):
                    print("%f %f %f"%(reportX[n],yreportX[n],math.log10(yreportX[n])))
                print(' ')

        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputFitting=self.fitting)
        self._defineOutputs(outputExperiment=self.experiment)
        self._defineSourceRelation(self.getInputExperiment(), self.fitting)
        self._defineSourceRelation(self.getInputExperiment(), self.experiment)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        self.getXYvars()
        msg=['Predicting %s from %s'%(self.varNameX,self.varNameY)]
        return msg

    def _validate(self):
        self.getXYvars()
        errors=[]
        experiment = self.readExperiment(self.getInputExperiment().fnPKPD, False)
        if not self.varNameX in experiment.variables:
            errors.append("Cannot find %s as variable"%self.varNameX)
        if not self.varNameY in experiment.variables:
            errors.append("Cannot find %s as variable"%self.varNameY)
        return errors

    def _citations(self):
        return ['Spiess2010']

    def filterVarForWizard(self, v):
        """ Define the type of variables required (used in wizard). """
        return v.isNumeric() and (v.isMeasurement() or v.isTime())
Example #10
0
class ProtPKPDMergePopulations(ProtPKPD):
    """ Merge two populations. Both populations must have the same labels\n
        Protocol created by http://www.kinestatpharma.com\n """
    _label = 'merge populations'

    #--------------------------- DEFINE param functions --------------------------------------------

    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam(
            'inputPopulation1',
            params.PointerParam,
            label="Population 1",
            important=True,
            pointerClass='PKPDFitting',
            pointerCondition="isPopulation",
            help='It must be a fitting coming from a bootstrap sample')
        form.addParam(
            'inputPopulation2',
            params.PointerParam,
            label="Population 2",
            important=True,
            pointerClass='PKPDFitting',
            pointerCondition="isPopulation",
            help='It must be a fitting coming from a bootstrap sample')

    #--------------------------- INSERT steps functions --------------------------------------------

    def _insertAllSteps(self):
        self._insertFunctionStep('runMerge',
                                 self.inputPopulation1.get().getObjId(),
                                 self.inputPopulation2.getObjId())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def runMerge(self, objId1, objId2):
        self.population1 = self.readFitting(
            self.inputPopulation1.get().fnFitting,
            cls="PKPDSampleFitBootstrap")
        self.population2 = self.readFitting(
            self.inputPopulation2.get().fnFitting,
            cls="PKPDSampleFitBootstrap")
        self.printSection("Merging populations")

        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.population1.fnExperiment)
        self.fitting.predictor = self.population1.predictor
        self.fitting.predicted = self.population1.predicted
        self.fitting.modelParameterUnits = self.population1.modelParameterUnits
        self.fitting.modelParameters = self.population1.modelParameters
        self.fitting.modelDescription = self.population1.modelDescription

        newSampleFit = PKPDSampleFitBootstrap()
        newSampleFit.sampleName = "Merged population"
        newSampleFit.parameters = None
        for sampleFit in self.population1.sampleFits:
            if newSampleFit.parameters == None:
                newSampleFit.parameters = np.copy(sampleFit.parameters)
                newSampleFit.xB = copy.copy(sampleFit.xB)
                newSampleFit.yB = copy.copy(sampleFit.yB)
                newSampleFit.R2 = copy.copy(sampleFit.R2)
                newSampleFit.R2adj = copy.copy(sampleFit.R2adj)
                newSampleFit.AIC = copy.copy(sampleFit.AIC)
                newSampleFit.AICc = copy.copy(sampleFit.AICc)
                newSampleFit.BIC = copy.copy(sampleFit.BIC)
            else:
                newSampleFit.parameters = np.vstack(
                    [newSampleFit.parameters, sampleFit.parameters])
                newSampleFit.xB += sampleFit.xB
                newSampleFit.yB += sampleFit.yB
                newSampleFit.R2 += sampleFit.R2
                newSampleFit.R2adj += sampleFit.R2adj
                newSampleFit.AIC += sampleFit.AIC
                newSampleFit.AICc += sampleFit.AICc
                newSampleFit.BIC += sampleFit.BIC
        for sampleFit in self.population2.sampleFits:
            newSampleFit.parameters = np.vstack(
                [newSampleFit.parameters, sampleFit.parameters])
            print(type(newSampleFit.xB))
            print(type(sampleFit.xB))
            newSampleFit.xB += sampleFit.xB
            newSampleFit.yB += sampleFit.yB
            newSampleFit.R2 += sampleFit.R2
            newSampleFit.R2adj += sampleFit.R2adj
            newSampleFit.AIC += sampleFit.AIC
            newSampleFit.AICc += sampleFit.AICc
            newSampleFit.BIC += sampleFit.BIC
        self.fitting.sampleFits.append(newSampleFit)

        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputPopulation=self.fitting)
        self._defineSourceRelation(self.inputPopulation1, self.fitting)
        self._defineSourceRelation(self.inputPopulation2, self.fitting)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = [
            "Populations %s and %s were merged" %
            (self.getObjectTag(self.inputPopulation1.get()),
             self.getObjectTag(self.inputPopulation2.get()))
        ]
        return msg

    def _validate(self):
        msg = []
        if not self.inputPopulation1.get().fnFitting.get().endswith(
                "bootstrapPopulation.pkpd"):
            msg.append("Population 1 must be a bootstrap sample")
        if not self.inputPopulation2.get().fnFitting.get().endswith(
                "bootstrapPopulation.pkpd"):
            msg.append("Population 2 must be a bootstrap sample")
        return msg
Example #11
0
class ProtPKPDODEBase(ProtPKPD, PKPDModelBase2):
    """ Base ODE protocol"""
    def __init__(self, **kwargs):
        ProtPKPD.__init__(self, **kwargs)
        self.boundsList = None

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams1(self,
                       form,
                       addXY=False,
                       defaultPredictor="",
                       defaultPredicted=""):
        form.addSection('Input')
        form.addParam('inputExperiment',
                      params.PointerParam,
                      label="Input experiment",
                      pointerClass='PKPDExperiment',
                      help='Select an experiment with samples')
        if addXY:
            form.addParam(
                'predictor',
                params.StringParam,
                label="Predictor variable (X)",
                default=defaultPredictor,
                help='Y is predicted as an exponential function of X, Y=f(X)')
            form.addParam(
                'predicted',
                params.StringParam,
                label="Predicted variable (Y)",
                default=defaultPredicted,
                help='Y is predicted as an exponential function of X, Y=f(X)')

        fromTo = form.addLine(
            'Simulation length',
            expertLevel=LEVEL_ADVANCED,
            help=
            'Minimum and maximum time (in hours) and step size (in minutes). '
            'If minimum and maximum are not given (set to -1), they are estimated from the sample'
        )
        fromTo.addParam('t0', params.StringParam, default="", label='Min (h)')
        fromTo.addParam('tF', params.StringParam, default="", label='Max (h)')
        fromTo.addParam('deltaT',
                        params.FloatParam,
                        default=0.5,
                        label='Step (min)')

        form.addParam('fitType', params.EnumParam, choices=["Linear","Logarithmic","Relative"], label="Fit mode", default=1,
                      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('confidenceInterval',
                      params.FloatParam,
                      label="Confidence interval",
                      default=95,
                      expertLevel=LEVEL_ADVANCED,
                      help='Confidence interval for the fitted parameters')
        form.addParam(
            'reportX',
            params.StringParam,
            label="Evaluate at X",
            default="",
            expertLevel=LEVEL_ADVANCED,
            help=
            'Evaluate the model at these X values\nExample 1: [0,5,10,20,40,100]\nExample 2: 0:0.55:10, from 0 to 10 in steps of 0.5'
        )
        form.addParam(
            'globalSearch',
            params.BooleanParam,
            label="Global search",
            default=True,
            expertLevel=LEVEL_ADVANCED,
            help=
            'Global search looks for the best parameters within bounds. If it is not performed, the '
            'middle of the bounding box is used as initial parameter for a local optimization'
        )

    #--------------------------- INSERT steps functions --------------------------------------------
    def getListOfFormDependencies(self):
        retval = [
            self.fitType.get(),
            self.confidenceInterval.get(),
            self.reportX.get()
        ]
        if hasattr(self, "predictor"):
            retval.append(self.predictor.get())
            retval.append(self.predicted.get())
        if hasattr(self, "bounds"):
            retval.append(self.bounds.get())
        return retval

    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',
                                 self.getInputExperiment().getObjId(),
                                 self.getListOfFormDependencies())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def getInputExperiment(self):
        if hasattr(self, "inputExperiment"):
            return self.inputExperiment.get()
        else:
            return None

    def getXYvars(self):
        if hasattr(self, "predictor"):
            self.varNameX = self.predictor.get()
        else:
            self.varNameX = None

        if hasattr(self, "predicted"):
            self.varNameY = self.predicted.get()
        else:
            self.varNameY = None

    def configureSource(self, drugSource):
        pass

    def createModel(self):
        pass

    def setupModel(self):
        # Setup model
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)
        self.modelList.append(self.model)

    def getResponseDimension(self):
        return self.model.getResponseDimension()

    def getStateDimension(self):
        return self.model.getStateDimension()

    def setBounds(self, sample):
        if hasattr(self, "bounds"):
            self.model.setBounds(self.bounds.get())

    def prepareForSampleAnalysis(self, sampleName):
        pass

    def postSampleAnalysis(self, sampleName):
        pass

    def setTimeRange(self, sample):
        if self.t0.get() == "" or self.tF.get() == "":
            tmin, tmax = sample.getRange(self.varNameX)
        else:
            tmin = self.t0.get()
            tmax = self.tF.get()
        if self.tmin == None:
            self.tmin = tmin
        else:
            self.tmin = min(tmin, self.tmin)
        if self.tmax == None:
            self.tmax = tmax
        else:
            self.tmax = max(tmax, self.tmax)

        if self.t0.get() == "":
            self.model.t0 = min(-10, self.tmin - 10)  # 10 minutes before
        else:
            self.model.t0 = min(-10, float(self.t0.get()) * 60)

        if self.tF.get() == "":
            self.model.tF = self.tmax + 10  # 10 minutes later
        else:
            self.model.tF = float(self.tF.get()) * 60

        if hasattr(self, "deltaT"):
            self.model.deltaT = self.deltaT.get()

    # As model --------------------------------------------
    def clearGroupParameters(self):
        self.tmin = None
        self.tmax = None
        self.sampleList = []
        self.modelList = []
        self.drugSourceList = []
        self.clearXYLists()

    def clearXYLists(self):
        self.XList = []
        self.YList = []

    def parseBounds(self, boundsString):
        self.boundsList = []

        if boundsString != "" and boundsString != None:
            tokens = boundsString.split(';')
            if len(tokens) != self.getNumberOfParameters():
                raise Exception(
                    "The number of bound intervals does not match the number of parameters"
                )

            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append(
                    (float(values[0][1:]), float(values[1][:-1])))

    def setBounds(self, sample):
        self.parseBounds(self.bounds.get())
        self.setBoundsFromBoundsList()

    def setBoundsFromBoundsList(self):
        Nbounds = len(self.boundsList)
        Nsource = self.drugSource.getNumberOfParameters()
        Nmodel = self.model.getNumberOfParameters()
        if Nbounds != Nsource + Nmodel:
            raise Exception(
                "The number of parameters (%d) and bounds (%d) are different" %
                (Nsource + Nmodel, Nbounds))
        self.boundsSource = self.boundsList[0:Nsource]
        self.boundsPK = self.boundsList[Nsource:]
        self.model.bounds = self.boundsPK

    def getBounds(self):
        return self.boundsList

    def getParameterBounds(self):
        """ Return a dictionary where the parameter name is the key
        and the bounds are its values. """
        boundsDict = OrderedDict()
        self.parseBounds(self.bounds.get())  # after this we have boundsList
        parameterNames = self.getParameterNames()

        for paramName, bound in izip(parameterNames, self.getBounds()):
            boundsDict[paramName] = bound

        # Set None as bound for parameters not matched
        for paramName in parameterNames:
            if paramName not in boundsDict:
                boundsDict[paramName] = None

        return boundsDict

    def setParameters(self, parameters):
        self.parameters = parameters
        self.parametersPK = self.parameters[-self.NparametersModel:]

        for n in range(len(self.modelList)):
            if self.NparametersSource > 0:
                self.drugSourceList[n].setParameters(
                    self.parameters[0:self.NparametersSource])
            self.modelList[n].setParameters(self.parametersPK)

    def setXYValues(self, x, y):
        PKPDModelBase.setXYValues(self, x, y)
        self.model.setXYValues(x, y)
        self.XList.append(x)
        self.YList.append(y)

    def mergeLists(self, iny):
        if len(self.XList) > 1:
            outy = []
            for m in range(len(iny[0])):
                outy.append(np.empty(shape=[0]))
            for m in range(len(outy)):
                for n in range(len(iny)):
                    outy[m] = np.concatenate((outy[m], iny[n][m]))
            return outy
        else:
            return iny[0]

    def separateLists(self, iny):
        outy = []
        Nsamples = len(self.YList)
        if Nsamples == 0:
            return
        Nmeasurements = self.model.getResponseDimension()
        idx = [0] * Nmeasurements
        for n in range(Nsamples):
            yn = self.YList[n]
            perSampleIn = []
            for j in range(Nmeasurements):
                ynDim = yn[j].size
                ysample = iny[j][idx[j]:(idx[j] + ynDim)]
                perSampleIn.append(ysample)
                idx[j] += ynDim
            outy.append(perSampleIn)
        return outy

    def addSample(self, sample):
        self.sampleList.append(sample)
        self.model.setSample(sample)

    def forwardModel(self, parameters, x=None):
        self.setParameters(parameters)

        yPredictedList = []
        for n in range(len(self.modelList)):
            self.modelList[n].forwardModel(self.parametersPK, x)
            yPredictedList.append(self.modelList[n].yPredicted)
        self.yPredicted = self.mergeLists(yPredictedList)
        return copy.copy(self.yPredicted)

    def imposeConstraints(self, yt):
        self.model.imposeConstraints(yt)

    def getEquation(self):
        return self.drugSource.getEquation(
        ) + " and " + self.model.getEquation()

    def getModelEquation(self):
        return self.drugSource.getModelEquation(
        ) + " and " + self.model.getModelEquation()

    def getDescription(self):
        return self.drugSource.getDescription(
        ) + "; " + self.model.getDescription()

    def getParameterNames(self):
        retval = []
        parametersSource = self.drugSource.getParameterNames()
        self.NparametersSource = len(parametersSource)
        retval += parametersSource
        parametersModel = self.model.getParameterNames()
        self.NparametersModel = len(parametersModel)
        retval += parametersModel
        return retval

    def calculateParameterUnits(self, sample):
        retval = []
        retval += self.drugSource.calculateParameterUnits(sample)
        retval += self.model.calculateParameterUnits(sample)
        self.parameterUnits = retval

    def areParametersSignificant(self, lowerBound, upperBound):
        retval = []
        idx = 0
        if len(self.boundsSource) > 0:
            retval += self.drugSource.areParametersSignificant(
                lowerBound[idx:len(self.boundsSource)],
                upperBound[idx:len(self.boundsSource)])
        retval += self.model.areParametersSignificant(
            lowerBound[len(self.boundsSource):],
            upperBound[len(self.boundsSource):])
        return retval

    def areParametersValid(self, p):
        return self.drugSource.areParametersValid(p[0:len(self.boundsSource)]) and \
               self.model.areParametersValid(p[len(self.boundsSource):])

    def createDrugSource(self):
        self.drugSource = DrugSource()
        self.drugSourceList.append(self.drugSource)

        return self.drugSource

    # Really fit ---------------------------------------------------------
    def runFit(self, objId, otherDependencies):
        reportX = parseRange(self.reportX.get())
        self.setInputExperiment()

        # Setup model
        self.getXYvars()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self._getPath("experiment.pkpd"))
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        if type(self.varNameY) == list:
            self.fitting.predicted = []
            for y in self.varNameY:
                self.fitting.predicted.append(self.experiment.variables[y])
        else:
            self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get() == 0:
            fitType = "linear"
        elif self.fitType.get() == 1:
            fitType = "log"
        elif self.fitType.get() == 2:
            fitType = "relative"

        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting " + groupName)
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample " + sampleName)
                sample = self.experiment.samples[sampleName]

                self.createDrugSource()
                self.setupModel()

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX, self.varNameY)
                print("X= " + str(x))
                print("Y= " + str(y))
                print(" ")

                # Interpret the dose
                self.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0,
                                         self.model.tF)
                self.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.addSample(sample)
                self.prepareForSampleAnalysis(sampleName)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits == None:
                    self.fitting.modelParameterUnits = self.parameterUnits

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            if self.globalSearch:
                optimizer1 = PKPDDEOptimizer(self, fitType)
                optimizer1.optimize()
            else:
                self.parameters = np.zeros(len(self.boundsList), np.double)
                n = 0
                for bound in self.boundsList:
                    self.parameters[n] = 0.5 * (bound[0] + bound[1])
                    n += 1
            try:
                optimizer2 = PKPDLSOptimizer(self, fitType)
                optimizer2.optimize()
            except Exception as e:
                msg = str(e)
                msg += "Errors in the local optimizer may be caused by starting from a bad initial guess\n"
                msg += "Try performing a global search first or changing the bounding box"
                raise Exception("Error in the local optimizer\n" + msg)
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            self.yPredictedList = self.separateLists(self.yPredicted)
            self.yPredictedLowerList = self.separateLists(self.yPredictedLower)
            self.yPredictedUpperList = self.separateLists(self.yPredictedUpper)

            n = 0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = self.XList[n]
                sampleFit.y = self.YList[n]
                sampleFit.yp = self.yPredictedList[n]
                sampleFit.yl = self.yPredictedLowerList[n]
                sampleFit.yu = self.yPredictedUpperList[n]
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(
                        self.getParameterNames(), self.parameterUnits,
                        self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(
                        sampleName, varName, varUnits, description, varValue)

                self.postSampleAnalysis(sampleName)

                if reportX != None:
                    print("Evaluation of the model at specified time points")
                    self.model.tF = np.max(reportX)
                    yreportX = self.model.forwardModel(self.model.parameters,
                                                       reportX)
                    print("==========================================")
                    print("X     Ypredicted     log10(Ypredicted)")
                    print("==========================================")
                    for n in range(0, reportX.shape[0]):
                        aux = 0
                        if yreportX[n] > 0:
                            aux = math.log10(yreportX[n])
                        print("%f %f %f" % (reportX[n], yreportX[n], aux))
                    print(' ')

                n += 1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputFitting=self.fitting)
        self._defineOutputs(outputExperiment=self.experiment)
        self._defineSourceRelation(self.getInputExperiment(), self.fitting)
        self._defineSourceRelation(self.getInputExperiment(), self.experiment)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = []
        self.getXYvars()
        if self.varNameX != None:
            msg.append('Predicting %s from %s' %
                       (self.varNameX, self.varNameY))
        return msg

    def _validate(self):
        self.getXYvars()
        errors = []
        if self.varNameX != None:
            experiment = self.readExperiment(self.getInputExperiment().fnPKPD,
                                             False)
            if not self.varNameX in experiment.variables:
                errors.append("Cannot find %s as variable" % self.varNameX)
            if type(self.varNameY) == list:
                for y in self.varNameY:
                    if not y in experiment.variables:
                        errors.append("Cannot find %s as variable" % y)
            else:
                if not self.varNameY in experiment.variables:
                    errors.append("Cannot find %s as variable" % self.varNameY)
        if self.bounds.get() == "":
            errors.append("Bounds are required")
        return errors

    def _citations(self):
        return ['Spiess2010']

    def filterVarForWizard(self, v):
        """ Define the type of variables required (used in wizard). """
        return v.isNumeric() and (v.isTime() or v.isMeasurement())
    def runFit(self, objId, otherDependencies):
        self.getXYvars()
        if hasattr(self,"reportX"):
            reportX = parseRange(self.reportX.get())
        else:
            reportX = None
        self.experiment = self.readExperiment(self.getInputExperiment().fnPKPD)

        # Setup model
        self.printSection("Model setup")
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)
        self.setupFromFormParameters()
        self.model.printSetup()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.getInputExperiment().fnPKPD.get())
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelDescription=self.model.getDescription()
        self.fitting.modelParameters = self.model.getParameterNames()
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get()==0:
            fitType = "linear"
        elif self.fitType.get()==1:
            fitType = "log"
        elif self.fitType.get()==2:
            fitType = "relative"

        for sampleName, sample in self.experiment.samples.iteritems():
            self.printSection("Fitting "+sampleName)
            x, y = sample.getXYValues(self.varNameX,self.varNameY)
            print("X= "+str(x))
            print("Y= "+str(y))
            print(" ")
            self.model.setBounds(self.bounds.get())
            self.model.setXYValues(x, y)
            self.prepareForSampleAnalysis(sampleName)
            self.model.calculateParameterUnits(sample)
            if self.fitting.modelParameterUnits==None:
                self.fitting.modelParameterUnits = self.model.parameterUnits
            self.model.prepare()
            if self.model.bounds == None:
                continue
            print(" ")

            optimizer1 = PKPDDEOptimizer(self.model,fitType)
            optimizer1.optimize()
            optimizer2 = PKPDLSOptimizer(self.model,fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            # Keep this result
            sampleFit = PKPDSampleFit()
            sampleFit.sampleName = sample.sampleName
            sampleFit.x = self.model.x
            sampleFit.y = self.model.y
            sampleFit.yp = self.model.yPredicted
            sampleFit.yl = self.model.yPredictedLower
            sampleFit.yu = self.model.yPredictedUpper
            sampleFit.parameters = self.model.parameters
            sampleFit.modelEquation = self.model.getEquation()
            sampleFit.copyFromOptimizer(optimizer2)
            self.fitting.sampleFits.append(sampleFit)

            # Add the parameters to the sample and experiment
            for varName, varUnits, description, varValue in izip(self.model.getParameterNames(), self.model.parameterUnits, self.model.getParameterDescriptions(), self.model.parameters):
                self.experiment.addParameterToSample(sampleName, varName, varUnits, description, varValue)

            self.postSampleAnalysis(sampleName)

            if reportX!=None:
                print("Evaluation of the model at specified time points")
                yreportX = self.model.forwardModel(self.model.parameters, reportX)
                print("==========================================")
                print("X     Ypredicted     log10(Ypredicted)")
                print("==========================================")
                for n in range(0,reportX.shape[0]):
                    print("%f %f %f"%(reportX[n],yreportX[n],math.log10(yreportX[n])))
                print(' ')

        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))
    def runFit(self, objId, otherDependencies):
        reportX = parseRange(self.reportX.get())
        self.setInputExperiment()

        # Setup model
        self.getXYvars()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self._getPath("experiment.pkpd"))
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        if type(self.varNameY)==list:
            self.fitting.predicted=[]
            for y in self.varNameY:
                self.fitting.predicted.append(self.experiment.variables[y])
        else:
            self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get()==0:
            fitType = "linear"
        elif self.fitType.get()==1:
            fitType = "log"
        elif self.fitType.get()==2:
            fitType = "relative"

        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting "+groupName)
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample "+sampleName)
                sample = self.experiment.samples[sampleName]

                self.createDrugSource()
                self.setupModel()

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX,self.varNameY)
                print("X= "+str(x))
                print("Y= "+str(y))
                print(" ")

                # Interpret the dose
                self.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0, self.model.tF)
                self.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.addSample(sample)
                self.prepareForSampleAnalysis(sampleName)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits==None:
                    self.fitting.modelParameterUnits = self.parameterUnits

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            if self.globalSearch:
                optimizer1 = PKPDDEOptimizer(self,fitType)
                optimizer1.optimize()
            else:
                self.parameters = np.zeros(len(self.boundsList),np.double)
                n = 0
                for bound in self.boundsList:
                    self.parameters[n] = 0.5*(bound[0]+bound[1])
                    n += 1
            try:
                optimizer2 = PKPDLSOptimizer(self,fitType)
                optimizer2.optimize()
            except Exception as e:
                msg=str(e)
                msg+="Errors in the local optimizer may be caused by starting from a bad initial guess\n"
                msg+="Try performing a global search first or changing the bounding box"
                raise Exception("Error in the local optimizer\n"+msg)
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            self.yPredictedList=self.separateLists(self.yPredicted)
            self.yPredictedLowerList=self.separateLists(self.yPredictedLower)
            self.yPredictedUpperList=self.separateLists(self.yPredictedUpper)

            n=0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = self.XList[n]
                sampleFit.y = self.YList[n]
                sampleFit.yp = self.yPredictedList[n]
                sampleFit.yl = self.yPredictedLowerList[n]
                sampleFit.yu = self.yPredictedUpperList[n]
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(self.getParameterNames(), self.parameterUnits, self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(sampleName, varName, varUnits, description, varValue)

                self.postSampleAnalysis(sampleName)

                if reportX!=None:
                    print("Evaluation of the model at specified time points")
                    self.model.tF = np.max(reportX)
                    yreportX = self.model.forwardModel(self.model.parameters, reportX)
                    print("==========================================")
                    print("X     Ypredicted     log10(Ypredicted)")
                    print("==========================================")
                    for n in range(0,reportX.shape[0]):
                        aux = 0
                        if yreportX[n]>0:
                            aux = math.log10(yreportX[n])
                        print("%f %f %f"%(reportX[n],yreportX[n],aux))
                    print(' ')

                n+=1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription=self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))
Example #14
0
    def runFit(self, objId, otherDependencies):
        reportX = parseRange(self.reportX.get())
        self.setInputExperiment()

        # Setup model
        self.getXYvars()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self._getPath("experiment.pkpd"))
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        if type(self.varNameY) == list:
            self.fitting.predicted = []
            for y in self.varNameY:
                self.fitting.predicted.append(self.experiment.variables[y])
        else:
            self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get() == 0:
            fitType = "linear"
        elif self.fitType.get() == 1:
            fitType = "log"
        elif self.fitType.get() == 2:
            fitType = "relative"

        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting " + groupName)
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample " + sampleName)
                sample = self.experiment.samples[sampleName]

                self.createDrugSource()
                self.setupModel()

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX, self.varNameY)
                print("X= " + str(x))
                print("Y= " + str(y))
                print(" ")

                # Interpret the dose
                self.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0,
                                         self.model.tF)
                self.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.addSample(sample)
                self.prepareForSampleAnalysis(sampleName)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits == None:
                    self.fitting.modelParameterUnits = self.parameterUnits

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            if self.globalSearch:
                optimizer1 = PKPDDEOptimizer(self, fitType)
                optimizer1.optimize()
            else:
                self.parameters = np.zeros(len(self.boundsList), np.double)
                n = 0
                for bound in self.boundsList:
                    self.parameters[n] = 0.5 * (bound[0] + bound[1])
                    n += 1
            try:
                optimizer2 = PKPDLSOptimizer(self, fitType)
                optimizer2.optimize()
            except Exception as e:
                msg = str(e)
                msg += "Errors in the local optimizer may be caused by starting from a bad initial guess\n"
                msg += "Try performing a global search first or changing the bounding box"
                raise Exception("Error in the local optimizer\n" + msg)
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            self.yPredictedList = self.separateLists(self.yPredicted)
            self.yPredictedLowerList = self.separateLists(self.yPredictedLower)
            self.yPredictedUpperList = self.separateLists(self.yPredictedUpper)

            n = 0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = self.XList[n]
                sampleFit.y = self.YList[n]
                sampleFit.yp = self.yPredictedList[n]
                sampleFit.yl = self.yPredictedLowerList[n]
                sampleFit.yu = self.yPredictedUpperList[n]
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(
                        self.getParameterNames(), self.parameterUnits,
                        self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(
                        sampleName, varName, varUnits, description, varValue)

                self.postSampleAnalysis(sampleName)

                if reportX != None:
                    print("Evaluation of the model at specified time points")
                    self.model.tF = np.max(reportX)
                    yreportX = self.model.forwardModel(self.model.parameters,
                                                       reportX)
                    print("==========================================")
                    print("X     Ypredicted     log10(Ypredicted)")
                    print("==========================================")
                    for n in range(0, reportX.shape[0]):
                        aux = 0
                        if yreportX[n] > 0:
                            aux = math.log10(yreportX[n])
                        print("%f %f %f" % (reportX[n], yreportX[n], aux))
                    print(' ')

                n += 1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))
Example #15
0
    def runFit(self, objId, Nbootstrap, confidenceInterval):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(
            self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted) == list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        if type(self.varNameY) == list:
            self.fitting.predicted = [
                self.experiment.variables[v] for v in self.varNameY
            ]
        else:
            self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get() == 0:
            fitType = "linear"
        elif self.protODE.fitType.get() == 1:
            fitType = "log"
        elif self.protODE.fitType.get() == 2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting " + groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample " + sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX, self.varNameY)
                print("X= " + str(x))
                print("Y= " + str(y))
                firstX = x[0]  # From [array(...)] to array(...)
                firstY = y[0]  # From [array(...)] to array(...)

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0,
                                         self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits == None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames == None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(
                        sample.descriptors[parameterName]))
                print("Initial solution: %s" % str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)

                # Output object
                sampleFit = PKPDSampleFitBootstrap()
                sampleFit.sampleName = sample.sampleName
                sampleFit.parameters = np.zeros(
                    (self.Nbootstrap.get(), len(parameters0)), np.double)
                sampleFit.xB = []
                sampleFit.yB = []

                # Bootstrap samples
                idx = [k for k in range(0, len(firstX))]
                for n in range(0, self.Nbootstrap.get()):
                    ok = False
                    while not ok:
                        if self.sampleLength.get() > 0:
                            lenToUse = self.sampleLength.get()
                        else:
                            lenToUse = len(idx)
                        idxB = sorted(np.random.choice(idx, lenToUse))
                        xB = [np.asarray([firstX[i] for i in idxB])]
                        yB = [np.asarray([firstY[i] for i in idxB])]

                        print("Bootstrap sample %d" % n)
                        print("X= " + str(xB))
                        print("Y= " + str(yB))
                        self.clearXYLists()
                        self.setXYValues(xB, yB)
                        self.parameters = parameters0

                        optimizer2 = PKPDLSOptimizer(self, fitType)
                        optimizer2.verbose = 0
                        try:
                            optimizer2.optimize()
                            ok = True
                        except Exception as e:
                            print(e)
                            raise (e)
                            ok = False

                    # Evaluate the quality on the whole data set
                    self.clearXYLists()
                    self.setXYValues(x, y)
                    optimizer2.evaluateQuality()
                    print(optimizer2.optimum)
                    print("   R2 = %f R2Adj=%f AIC=%f AICc=%f BIC=%f"%(optimizer2.R2,optimizer2.R2adj,optimizer2.AIC,\
                                                                       optimizer2.AICc,optimizer2.BIC))

                    # Keep this result
                    sampleFit.parameters[n, :] = optimizer2.optimum
                    sampleFit.xB.append(str(xB[0]))
                    sampleFit.yB.append(str(yB[0]))
                    sampleFit.copyFromOptimizer(optimizer2)

                self.fitting.sampleFits.append(sampleFit)

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))
Example #16
0
class ProtPKPDODEBootstrap(ProtPKPDODEBase):
    """ Bootstrap of an ODE protocol"""

    _label = 'ODE bootstrap'

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam('inputODE', params.PointerParam, label="Input ODE model",
                      pointerClass='ProtPKPDMonoCompartment, ProtPKPDMonoCompartmentUrine, ProtPKPDTwoCompartments, '\
                                   'ProtPKPDTwoCompartmentsAutoinduction, ProtPKPDTwoCompartmentsClint, '\
                                   'ProtPKPDTwoCompartmentsClintMetabolite, ProtPKPDTwoCompartmentsUrine',
                      help='Select a run of an ODE model')
        form.addParam('Nbootstrap',
                      params.IntParam,
                      label="Bootstrap samples",
                      default=200,
                      expertLevel=LEVEL_ADVANCED,
                      help='Number of bootstrap realizations for each sample')
        form.addParam('sampleLength', params.IntParam, label="Sample length", default=-1, expertLevel=LEVEL_ADVANCED,
                      help='If the input experiment represents a population, the bootstrap sample is so overdetermined '\
                           'that the bootstrap parameter estimate seldom moves from the original values. In this case, '\
                           'you may use the sample length to generate bootstrap samples of the same length as the indiviudals '\
                           'taking part of the population. If this value is set to -1, then the length of the bootstrap sample '\
                           'will be the same as the one in the input experiment. If set to any other value, e.g. 8, then '\
                           'each bootstrap sample will have this length')
        form.addParam('confidenceInterval',
                      params.FloatParam,
                      label="Confidence interval",
                      default=95,
                      expertLevel=LEVEL_ADVANCED,
                      help='Confidence interval for the fitted parameters')
        form.addParam('deltaT',
                      params.FloatParam,
                      default=2,
                      label='Step (min)',
                      expertLevel=LEVEL_ADVANCED)

    #--------------------------- INSERT steps functions --------------------------------------------
    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',
                                 self.inputODE.get().getObjId(),
                                 self.Nbootstrap.get(),
                                 self.confidenceInterval.get())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def parseBounds(self, boundsString):
        if boundsString != "" and boundsString != None:
            tokens = boundsString.split(';')
            if len(tokens) != self.getNumberOfParameters():
                raise Exception(
                    "The number of bound intervals does not match the number of parameters"
                )
            self.boundsList = []
            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append(
                    (float(values[0][1:]), float(values[1][:-1])))

    def setBounds(self, sample):
        self.parseBounds(self.protODE.bounds.get())
        self.setBoundsFromBoundsList()

    def setBoundsFromBoundsList(self):
        Nbounds = len(self.boundsList)
        Nsource = self.drugSource.getNumberOfParameters()
        Nmodel = self.model.getNumberOfParameters()
        if Nbounds != Nsource + Nmodel:
            raise "The number of parameters (%d) and bounds (%d) are different" % (
                Nsource + Nmodel, Nbounds)
        self.boundsSource = self.boundsList[0:Nsource]
        self.boundsPK = self.boundsList[Nsource:]
        self.model.bounds = self.boundsPK

    def getBounds(self):
        return self.boundsList

    def runFit(self, objId, Nbootstrap, confidenceInterval):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(
            self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted) == list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        if type(self.varNameY) == list:
            self.fitting.predicted = [
                self.experiment.variables[v] for v in self.varNameY
            ]
        else:
            self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get() == 0:
            fitType = "linear"
        elif self.protODE.fitType.get() == 1:
            fitType = "log"
        elif self.protODE.fitType.get() == 2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting " + groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample " + sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX, self.varNameY)
                print("X= " + str(x))
                print("Y= " + str(y))
                firstX = x[0]  # From [array(...)] to array(...)
                firstY = y[0]  # From [array(...)] to array(...)

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0,
                                         self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits == None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames == None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(
                        sample.descriptors[parameterName]))
                print("Initial solution: %s" % str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)

                # Output object
                sampleFit = PKPDSampleFitBootstrap()
                sampleFit.sampleName = sample.sampleName
                sampleFit.parameters = np.zeros(
                    (self.Nbootstrap.get(), len(parameters0)), np.double)
                sampleFit.xB = []
                sampleFit.yB = []

                # Bootstrap samples
                idx = [k for k in range(0, len(firstX))]
                for n in range(0, self.Nbootstrap.get()):
                    ok = False
                    while not ok:
                        if self.sampleLength.get() > 0:
                            lenToUse = self.sampleLength.get()
                        else:
                            lenToUse = len(idx)
                        idxB = sorted(np.random.choice(idx, lenToUse))
                        xB = [np.asarray([firstX[i] for i in idxB])]
                        yB = [np.asarray([firstY[i] for i in idxB])]

                        print("Bootstrap sample %d" % n)
                        print("X= " + str(xB))
                        print("Y= " + str(yB))
                        self.clearXYLists()
                        self.setXYValues(xB, yB)
                        self.parameters = parameters0

                        optimizer2 = PKPDLSOptimizer(self, fitType)
                        optimizer2.verbose = 0
                        try:
                            optimizer2.optimize()
                            ok = True
                        except Exception as e:
                            print(e)
                            raise (e)
                            ok = False

                    # Evaluate the quality on the whole data set
                    self.clearXYLists()
                    self.setXYValues(x, y)
                    optimizer2.evaluateQuality()
                    print(optimizer2.optimum)
                    print("   R2 = %f R2Adj=%f AIC=%f AICc=%f BIC=%f"%(optimizer2.R2,optimizer2.R2adj,optimizer2.AIC,\
                                                                       optimizer2.AICc,optimizer2.BIC))

                    # Keep this result
                    sampleFit.parameters[n, :] = optimizer2.optimum
                    sampleFit.xB.append(str(xB[0]))
                    sampleFit.yB.append(str(yB[0]))
                    sampleFit.copyFromOptimizer(optimizer2)

                self.fitting.sampleFits.append(sampleFit)

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputPopulation=self.fitting)
        self._defineSourceRelation(self.inputODE.get(), self.fitting)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = []
        msg.append("Number of bootstrap realizations: %d" %
                   self.Nbootstrap.get())
        msg.append("Confidence interval: %f" % self.confidenceInterval.get())
        return msg

    def _validate(self):
        return []
Example #17
0
class ProtPKPDODERefine(ProtPKPDODEBase):
    """ Refinement of an ODE protocol. The parameters are reestimated with a finer sampling rate.
    """

    _label = 'ODE refinement'

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam(
            'inputODE',
            params.PointerParam,
            label="Input ODE model",
            pointerClass=
            'ProtPKPDMonoCompartment, ProtPKPDMonoCompartmentUrine, ProtPKPDTwoCompartments',
            help='Select a run of an ODE model')
        form.addParam('deltaT',
                      params.FloatParam,
                      default=0.5,
                      label='Step (min)',
                      expertLevel=LEVEL_ADVANCED)

    #--------------------------- INSERT steps functions --------------------------------------------
    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',
                                 self.inputODE.get().getObjId(),
                                 self.deltaT.get())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def parseBounds(self, boundsString):
        if boundsString != "" and boundsString != None:
            tokens = boundsString.split(';')
            if len(tokens) != self.getNumberOfParameters():
                raise Exception(
                    "The number of bound intervals does not match the number of parameters"
                )
            self.boundsList = []
            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append(
                    (float(values[0][1:]), float(values[1][:-1])))

    def setBounds(self, sample):
        self.parseBounds(self.protODE.bounds.get())
        self.setBoundsFromBoundsList()

    def setBoundsFromBoundsList(self):
        Nbounds = len(self.boundsList)
        Nsource = self.drugSource.getNumberOfParameters()
        Nmodel = self.model.getNumberOfParameters()
        if Nbounds != Nsource + Nmodel:
            raise "The number of parameters (%d) and bounds (%d) are different" % (
                Nsource + Nmodel, Nbounds)
        self.boundsSource = self.boundsList[0:Nsource]
        self.boundsPK = self.boundsList[Nsource:]
        self.model.bounds = self.boundsPK

    def getBounds(self):
        return self.boundsList

    def runFit(self, objId, deltaT):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(
            self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted) == list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get() == 0:
            fitType = "linear"
        elif self.protODE.fitType.get() == 1:
            fitType = "log"
        elif self.protODE.fitType.get() == 2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting " + groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample " + sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX, self.varNameY)
                print("X= " + str(x))
                print("Y= " + str(y))

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0,
                                         self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits == None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames == None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(
                        sample.descriptors[parameterName]))
                print("Initial solution: %s" % str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.parameters = parameters0

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            optimizer2 = PKPDLSOptimizer(self, fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(
                self.protODE.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)

            n = 0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = x
                sampleFit.y = y
                sampleFit.yp = self.yPredicted
                sampleFit.yl = self.yPredictedLower
                sampleFit.yu = self.yPredictedUpper
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(
                        self.getParameterNames(), self.parameterUnits,
                        self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(
                        sampleName, varName, varUnits, description, varValue)

                n += 1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputFitting=self.fitting)
        self._defineOutputs(outputExperiment=self.experiment)
        self._defineSourceRelation(self.inputODE.get(), self.fitting)
        self._defineSourceRelation(self.inputODE.get(), self.experiment)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = []
        msg.append("New sampling rate: %f" % self.deltaT.get())
        return msg

    def _validate(self):
        return []
Example #18
0
class ProtPKPDFilterPopulation(ProtPKPD):
    """ Filter a population by some criterion\n
        Protocol created by http://www.kinestatpharma.com\n """
    _label = 'filter population'

    #--------------------------- DEFINE param functions --------------------------------------------

    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam('inputPopulation', params.PointerParam, label="Population", important=True,
                      pointerClass='PKPDFitting',
                      help='It must be a fitting coming from a bootstrap sample')
        form.addParam('filterType', params.EnumParam, choices=["Exclude","Keep","Keep confidence interval"], label="Filter mode", default=0,
                      help='Exclude or keep samples meeting the following condition\n')
        form.addParam('condition', params.StringParam, label="Condition", default="$(AICc)>-10 or $(R2)<0.7",
                      help='Example: $(Cl)>0.25 and $(tlag)>0\n'\
                           'Example for the confidence interval: $(Cl) 95 (keep the central 95% of clearance).\n'\
                           'The variables R2, R2adj, AIC, AICc, and BIC can be used, \n'\
                           'e.g., $(AICc)>-10 selects those elements with suspicious fitting.\n'\
                           'Confidence intervals cannot be placed on the quality parameters (R2, R2adj, ...)')

    #--------------------------- INSERT steps functions --------------------------------------------
    def _insertAllSteps(self):
        self._insertFunctionStep('runFilter',self.inputPopulation.get().getObjId(), self.filterType.get(), self.condition.get())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def runFilter(self, objId, filterType, condition):
        self.population = self.readFitting(self.inputPopulation.get().fnFitting,cls="PKPDSampleFitBootstrap")
        self.printSection("Filtering population")

        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.population.fnExperiment)
        self.fitting.predictor=self.population.predictor
        self.fitting.predicted=self.population.predicted
        self.fitting.modelParameterUnits = self.population.modelParameterUnits
        self.fitting.modelParameters = self.population.modelParameters
        self.fitting.modelDescription = self.population.modelDescription

        newSampleFit = PKPDSampleFitBootstrap()
        newSampleFit.parameters = None
        filterType = self.filterType.get()
        for sampleFit in self.population.sampleFits:
            newSampleFit.sampleName = sampleFit.sampleName
            if newSampleFit.parameters == None:
                newSampleFit.parameters = np.empty((0,sampleFit.parameters.shape[1]))
                newSampleFit.xB = []
                newSampleFit.yB = []
                newSampleFit.R2 = []
                newSampleFit.R2adj = []
                newSampleFit.AIC = []
                newSampleFit.AICc = []
                newSampleFit.BIC = []

            if filterType<=1:
                conditionToEvaluate = self.condition.get()
            else:
                tokens=self.condition.get().strip().split(' ')
                variable = tokens[0][2:-1]
                confidenceLevel = float(tokens[1])
                columnIdx = -1
                for j in range(len(self.population.modelParameters)):
                    if self.population.modelParameters[j]==variable:
                        columnIdx = j
                        break
                if columnIdx==-1:
                    raise Exception("Cannot find %s amongst the model variables"%variable)
                values=sampleFit.parameters[:,columnIdx]
                alpha_2 = (100-confidenceLevel)/2
                limits = np.percentile(values,[alpha_2,100-alpha_2])
                conditionToEvaluate = "%s>=%f and %s<=%f"%(tokens[0],limits[0],tokens[0],limits[1])
                print("Condition to evaluate: %s"%conditionToEvaluate)

            for n in range(0,len(sampleFit.R2)):
                evaluatedCondition = copy.copy(conditionToEvaluate)
                evaluatedCondition = evaluatedCondition.replace('$(R2)',"(%f)"%sampleFit.R2[n])
                evaluatedCondition = evaluatedCondition.replace('$(R2adj)',"(%f)"%sampleFit.R2adj[n])
                evaluatedCondition = evaluatedCondition.replace('$(AIC)',"(%f)"%sampleFit.AIC[n])
                evaluatedCondition = evaluatedCondition.replace('$(AICc)',"(%f)"%sampleFit.AICc[n])
                evaluatedCondition = evaluatedCondition.replace('$(BIC)',"(%f)"%sampleFit.BIC[n])

                for j in range(len(self.population.modelParameters)):
                    evaluatedCondition = evaluatedCondition.replace('$(%s)'%self.population.modelParameters[j],"(%f)"%sampleFit.parameters[n,j])
                evaluatedCondition = eval(evaluatedCondition)
                if (filterType==0 and not evaluatedCondition) or (filterType>=1 and evaluatedCondition):
                    newSampleFit.parameters = np.vstack([newSampleFit.parameters, sampleFit.parameters[n,:]])
                    newSampleFit.xB += sampleFit.xB
                    newSampleFit.yB += sampleFit.yB
                    newSampleFit.R2.append(sampleFit.R2[n])
                    newSampleFit.R2adj.append(sampleFit.R2adj[n])
                    newSampleFit.AIC.append(sampleFit.AIC[n])
                    newSampleFit.AICc.append(sampleFit.AICc[n])
                    newSampleFit.BIC.append(sampleFit.BIC[n])

        self.fitting.sampleFits.append(newSampleFit)
        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputPopulation=self.fitting)
        self._defineSourceRelation(self.inputPopulation, self.fitting)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        if self.filterType.get()==0:
            filterType = "Exclude"
        elif self.filterType.get()==1:
            filterType = "Keep"
        elif self.filterType.get()==2:
            filterType = "Keep confidence interval"
        msg=["Filter type: %s"%filterType]
        msg.append("Condition: %s"%self.condition.get())
        return msg

    def _validate(self):
        msg=[]
        if not self.inputPopulation.get().fnFitting.get().endswith("bootstrapPopulation.pkpd"):
            msg.append("Population must be a bootstrap sample")
        return msg
Example #19
0
class ProtPKPDFitBase(ProtPKPD):
    """ Base fit protocol"""

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams1(self, form, defaultPredictor, defaultPredicted):
        form.addSection('Input')
        form.addParam('inputExperiment',
                      params.PointerParam,
                      label="Input experiment",
                      pointerClass='PKPDExperiment',
                      help='Select an experiment with samples')
        form.addParam(
            'predictor',
            params.StringParam,
            label="Predictor variable (X)",
            default=defaultPredictor,
            help='Y is predicted as an exponential function of X, Y=f(X)')
        form.addParam(
            'predicted',
            params.StringParam,
            label="Predicted variable (Y)",
            default=defaultPredicted,
            help='Y is predicted as an exponential function of X, Y=f(X)')

    #--------------------------- INSERT steps functions --------------------------------------------
    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',
                                 self.getInputExperiment().getObjId(),
                                 self.getListOfFormDependencies())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def getInputExperiment(self):
        if hasattr(self, "inputExperiment"):
            return self.inputExperiment.get()
        else:
            return None

    def getXYvars(self):
        if hasattr(self, "predictor"):
            self.varNameX = self.predictor.get()
        else:
            self.varNameX = None

        if hasattr(self, "predicted"):
            self.varNameY = self.predicted.get()
        else:
            self.varNameY = None

    def setExperiment(self, experiment):
        self.experiment = experiment
        if experiment != None:
            self.fnExperiment = experiment.fnPKPD

    def setSample(self, sample):
        self.sample = sample
        self.model.setSample(sample)

    def createModel(self):
        pass

    def parseBounds(self, boundsString):
        self.boundsList = []

        if boundsString != "" and boundsString != None:
            tokens = boundsString.split(';')
            if len(tokens) != self.getNumberOfParameters():
                raise Exception(
                    "The number of bound intervals does not match the number of parameters"
                )

            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append(
                    (float(values[0][1:]), float(values[1][:-1])))

    def getBounds(self):
        return self.boundsList

    def getParameterBounds(self):
        """ Return a dictionary where the parameter name is the key
        and the bounds are its values. """
        boundsDict = OrderedDict()
        self.parseBounds(self.bounds.get())  # after this we have boundsList
        parameterNames = self.model.getParameterNames()

        for paramName, bound in izip(parameterNames, self.getBounds()):
            boundsDict[paramName] = bound

        # Set None as bound for parameters not matched
        for paramName in parameterNames:
            if paramName not in boundsDict:
                boundsDict[paramName] = None

        return boundsDict

    def setupModel(self):
        # Setup model
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.setupFromFormParameters()
        self.getXYvars()
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)

    def calculateParameterUnits(self, sample):
        self.parameterUnits = self.model.calculateParameterUnits(sample)

    def getParameterNames(self):
        return self.model.getParameterNames()

    def getNumberOfParameters(self):
        return len(self.getParameterNames())

    def setParameters(self, prm):
        self.model.setParameters(prm)

    def forwardModel(self, prm, xValues):
        return self.model.forwardModel(prm, xValues)

    def setupFromFormParameters(self):
        pass

    def prepareForSampleAnalysis(self, sampleName):
        pass

    def postSampleAnalysis(self, sampleName):
        pass

    def runFit(self, objId, otherDependencies):
        self.getXYvars()
        if hasattr(self, "reportX"):
            reportX = parseRange(self.reportX.get())
        else:
            reportX = None
        self.experiment = self.readExperiment(self.getInputExperiment().fnPKPD)

        # Setup model
        self.printSection("Model setup")
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)
        self.setupFromFormParameters()
        self.model.printSetup()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.getInputExperiment().fnPKPD.get())
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelDescription = self.model.getDescription()
        self.fitting.modelParameters = self.model.getParameterNames()
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get() == 0:
            fitType = "linear"
        elif self.fitType.get() == 1:
            fitType = "log"
        elif self.fitType.get() == 2:
            fitType = "relative"

        for sampleName, sample in self.experiment.samples.iteritems():
            self.printSection("Fitting " + sampleName)
            x, y = sample.getXYValues(self.varNameX, self.varNameY)
            print("X= " + str(x))
            print("Y= " + str(y))
            print(" ")
            self.model.setBounds(self.bounds.get())
            self.model.setXYValues(x, y)
            self.prepareForSampleAnalysis(sampleName)
            self.model.calculateParameterUnits(sample)
            if self.fitting.modelParameterUnits == None:
                self.fitting.modelParameterUnits = self.model.parameterUnits
            self.model.prepare()
            if self.model.bounds == None:
                continue
            print(" ")

            optimizer1 = PKPDDEOptimizer(self.model, fitType)
            optimizer1.optimize()
            optimizer2 = PKPDLSOptimizer(self.model, fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            # Keep this result
            sampleFit = PKPDSampleFit()
            sampleFit.sampleName = sample.sampleName
            sampleFit.x = self.model.x
            sampleFit.y = self.model.y
            sampleFit.yp = self.model.yPredicted
            sampleFit.yl = self.model.yPredictedLower
            sampleFit.yu = self.model.yPredictedUpper
            sampleFit.parameters = self.model.parameters
            sampleFit.modelEquation = self.model.getEquation()
            sampleFit.copyFromOptimizer(optimizer2)
            self.fitting.sampleFits.append(sampleFit)

            # Add the parameters to the sample and experiment
            for varName, varUnits, description, varValue in izip(
                    self.model.getParameterNames(), self.model.parameterUnits,
                    self.model.getParameterDescriptions(),
                    self.model.parameters):
                self.experiment.addParameterToSample(sampleName, varName,
                                                     varUnits, description,
                                                     varValue)

            self.postSampleAnalysis(sampleName)

            if reportX != None:
                print("Evaluation of the model at specified time points")
                yreportX = self.model.forwardModel(self.model.parameters,
                                                   reportX)
                print("==========================================")
                print("X     Ypredicted     log10(Ypredicted)")
                print("==========================================")
                for n in range(0, reportX.shape[0]):
                    print("%f %f %f" %
                          (reportX[n], yreportX[n], math.log10(yreportX[n])))
                print(' ')

        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputFitting=self.fitting)
        self._defineOutputs(outputExperiment=self.experiment)
        self._defineSourceRelation(self.getInputExperiment(), self.fitting)
        self._defineSourceRelation(self.getInputExperiment(), self.experiment)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        self.getXYvars()
        msg = ['Predicting %s from %s' % (self.varNameX, self.varNameY)]
        return msg

    def _validate(self):
        self.getXYvars()
        errors = []
        experiment = self.readExperiment(self.getInputExperiment().fnPKPD,
                                         False)
        if not self.varNameX in experiment.variables:
            errors.append("Cannot find %s as variable" % self.varNameX)
        if not self.varNameY in experiment.variables:
            errors.append("Cannot find %s as variable" % self.varNameY)
        return errors

    def _citations(self):
        return ['Spiess2010']

    def filterVarForWizard(self, v):
        """ Define the type of variables required (used in wizard). """
        return v.isNumeric() and (v.isMeasurement() or v.isTime())
    def runFit(self, objId, deltaT):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted)==list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get()==0:
            fitType = "linear"
        elif self.protODE.fitType.get()==1:
            fitType = "log"
        elif self.protODE.fitType.get()==2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting "+groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample "+sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX,self.varNameY)
                print("X= "+str(x))
                print("Y= "+str(y))

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0, self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits==None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames==None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(sample.descriptors[parameterName]))
                print("Initial solution: %s"%str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.parameters = parameters0

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            optimizer2 = PKPDLSOptimizer(self,fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(self.protODE.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)

            n=0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = x
                sampleFit.y = y
                sampleFit.yp = self.yPredicted
                sampleFit.yl = self.yPredictedLower
                sampleFit.yu = self.yPredictedUpper
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(self.getParameterNames(), self.parameterUnits, self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(sampleName, varName, varUnits, description, varValue)

                n+=1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))
class ProtPKPDODERefine(ProtPKPDODEBase):
    """ Refinement of an ODE protocol. The parameters are reestimated with a finer sampling rate.
    """

    _label = 'ODE refinement'

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam('inputODE', params.PointerParam, label="Input ODE model",
                      pointerClass='ProtPKPDMonoCompartment, ProtPKPDMonoCompartmentUrine, ProtPKPDTwoCompartments', help='Select a run of an ODE model')
        form.addParam('deltaT', params.FloatParam, default=0.5, label='Step (min)', expertLevel=LEVEL_ADVANCED)

    #--------------------------- INSERT steps functions --------------------------------------------
    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',self.inputODE.get().getObjId(), self.deltaT.get())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def parseBounds(self, boundsString):
        if boundsString!="" and boundsString!=None:
            tokens=boundsString.split(';')
            if len(tokens)!=self.getNumberOfParameters():
                raise Exception("The number of bound intervals does not match the number of parameters")
            self.boundsList=[]
            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append((float(values[0][1:]),float(values[1][:-1])))

    def setBounds(self,sample):
        self.parseBounds(self.protODE.bounds.get())
        self.setBoundsFromBoundsList()

    def setBoundsFromBoundsList(self):
        Nbounds = len(self.boundsList)
        Nsource = self.drugSource.getNumberOfParameters()
        Nmodel = self.model.getNumberOfParameters()
        if Nbounds!=Nsource+Nmodel:
            raise "The number of parameters (%d) and bounds (%d) are different"%(Nsource+Nmodel,Nbounds)
        self.boundsSource = self.boundsList[0:Nsource]
        self.boundsPK = self.boundsList[Nsource:]
        self.model.bounds = self.boundsPK

    def getBounds(self):
        return self.boundsList

    def runFit(self, objId, deltaT):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted)==list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get()==0:
            fitType = "linear"
        elif self.protODE.fitType.get()==1:
            fitType = "log"
        elif self.protODE.fitType.get()==2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting "+groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample "+sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX,self.varNameY)
                print("X= "+str(x))
                print("Y= "+str(y))

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0, self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits==None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames==None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(sample.descriptors[parameterName]))
                print("Initial solution: %s"%str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.parameters = parameters0

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            optimizer2 = PKPDLSOptimizer(self,fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(self.protODE.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)

            n=0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = x
                sampleFit.y = y
                sampleFit.yp = self.yPredicted
                sampleFit.yl = self.yPredictedLower
                sampleFit.yu = self.yPredictedUpper
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(self.getParameterNames(), self.parameterUnits, self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(sampleName, varName, varUnits, description, varValue)

                n+=1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputFitting=self.fitting)
        self._defineOutputs(outputExperiment=self.experiment)
        self._defineSourceRelation(self.inputODE.get(), self.fitting)
        self._defineSourceRelation(self.inputODE.get(), self.experiment)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = []
        msg.append("New sampling rate: %f"%self.deltaT.get())
        return msg

    def _validate(self):
        return []
class ProtPKPDMergePopulations(ProtPKPD):
    """ Merge two populations. Both populations must have the same labels\n
        Protocol created by http://www.kinestatpharma.com\n """
    _label = 'merge populations'

    #--------------------------- DEFINE param functions --------------------------------------------

    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam('inputPopulation1', params.PointerParam, label="Population 1", important=True,
                      pointerClass='PKPDFitting', pointerCondition="isPopulation",
                      help='It must be a fitting coming from a bootstrap sample')
        form.addParam('inputPopulation2', params.PointerParam, label="Population 2", important=True,
                      pointerClass='PKPDFitting', pointerCondition="isPopulation",
                      help='It must be a fitting coming from a bootstrap sample')

    #--------------------------- INSERT steps functions --------------------------------------------

    def _insertAllSteps(self):
        self._insertFunctionStep('runMerge',self.inputPopulation1.get().getObjId(), self.inputPopulation2.getObjId())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def runMerge(self, objId1, objId2):
        self.population1 = self.readFitting(self.inputPopulation1.get().fnFitting,cls="PKPDSampleFitBootstrap")
        self.population2 = self.readFitting(self.inputPopulation2.get().fnFitting,cls="PKPDSampleFitBootstrap")
        self.printSection("Merging populations")

        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.population1.fnExperiment)
        self.fitting.predictor=self.population1.predictor
        self.fitting.predicted=self.population1.predicted
        self.fitting.modelParameterUnits = self.population1.modelParameterUnits
        self.fitting.modelParameters = self.population1.modelParameters
        self.fitting.modelDescription = self.population1.modelDescription

        newSampleFit = PKPDSampleFitBootstrap()
        newSampleFit.sampleName = "Merged population"
        newSampleFit.parameters = None
        for sampleFit in self.population1.sampleFits:
            if newSampleFit.parameters == None:
                newSampleFit.parameters = np.copy(sampleFit.parameters)
                newSampleFit.xB = copy.copy(sampleFit.xB)
                newSampleFit.yB = copy.copy(sampleFit.yB)
                newSampleFit.R2 = copy.copy(sampleFit.R2)
                newSampleFit.R2adj = copy.copy(sampleFit.R2adj)
                newSampleFit.AIC = copy.copy(sampleFit.AIC)
                newSampleFit.AICc = copy.copy(sampleFit.AICc)
                newSampleFit.BIC = copy.copy(sampleFit.BIC)
            else:
                newSampleFit.parameters = np.vstack([newSampleFit.parameters, sampleFit.parameters])
                newSampleFit.xB += sampleFit.xB
                newSampleFit.yB += sampleFit.yB
                newSampleFit.R2 += sampleFit.R2
                newSampleFit.R2adj += sampleFit.R2adj
                newSampleFit.AIC += sampleFit.AIC
                newSampleFit.AICc += sampleFit.AICc
                newSampleFit.BIC += sampleFit.BIC
        for sampleFit in self.population2.sampleFits:
            newSampleFit.parameters = np.vstack([newSampleFit.parameters, sampleFit.parameters])
            print(type(newSampleFit.xB))
            print(type(sampleFit.xB))
            newSampleFit.xB += sampleFit.xB
            newSampleFit.yB += sampleFit.yB
            newSampleFit.R2 += sampleFit.R2
            newSampleFit.R2adj += sampleFit.R2adj
            newSampleFit.AIC += sampleFit.AIC
            newSampleFit.AICc += sampleFit.AICc
            newSampleFit.BIC += sampleFit.BIC
        self.fitting.sampleFits.append(newSampleFit)

        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputPopulation=self.fitting)
        self._defineSourceRelation(self.inputPopulation1, self.fitting)
        self._defineSourceRelation(self.inputPopulation2, self.fitting)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg=["Populations %s and %s were merged"%(self.getObjectTag(self.inputPopulation1.get()),
                                                  self.getObjectTag(self.inputPopulation2.get()))]
        return msg

    def _validate(self):
        msg=[]
        if not self.inputPopulation1.get().fnFitting.get().endswith("bootstrapPopulation.pkpd"):
            msg.append("Population 1 must be a bootstrap sample")
        if not self.inputPopulation2.get().fnFitting.get().endswith("bootstrapPopulation.pkpd"):
            msg.append("Population 2 must be a bootstrap sample")
        return msg
Example #23
0
    def runFit(self, objId, otherDependencies):
        self.getXYvars()
        if hasattr(self, "reportX"):
            reportX = parseRange(self.reportX.get())
        else:
            reportX = None
        self.experiment = self.readExperiment(self.getInputExperiment().fnPKPD)

        # Setup model
        self.printSection("Model setup")
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)
        self.setupFromFormParameters()
        self.model.printSetup()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.getInputExperiment().fnPKPD.get())
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelDescription = self.model.getDescription()
        self.fitting.modelParameters = self.model.getParameterNames()
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get() == 0:
            fitType = "linear"
        elif self.fitType.get() == 1:
            fitType = "log"
        elif self.fitType.get() == 2:
            fitType = "relative"

        for sampleName, sample in self.experiment.samples.iteritems():
            self.printSection("Fitting " + sampleName)
            x, y = sample.getXYValues(self.varNameX, self.varNameY)
            print("X= " + str(x))
            print("Y= " + str(y))
            print(" ")
            self.model.setBounds(self.bounds.get())
            self.model.setXYValues(x, y)
            self.prepareForSampleAnalysis(sampleName)
            self.model.calculateParameterUnits(sample)
            if self.fitting.modelParameterUnits == None:
                self.fitting.modelParameterUnits = self.model.parameterUnits
            self.model.prepare()
            if self.model.bounds == None:
                continue
            print(" ")

            optimizer1 = PKPDDEOptimizer(self.model, fitType)
            optimizer1.optimize()
            optimizer2 = PKPDLSOptimizer(self.model, fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            # Keep this result
            sampleFit = PKPDSampleFit()
            sampleFit.sampleName = sample.sampleName
            sampleFit.x = self.model.x
            sampleFit.y = self.model.y
            sampleFit.yp = self.model.yPredicted
            sampleFit.yl = self.model.yPredictedLower
            sampleFit.yu = self.model.yPredictedUpper
            sampleFit.parameters = self.model.parameters
            sampleFit.modelEquation = self.model.getEquation()
            sampleFit.copyFromOptimizer(optimizer2)
            self.fitting.sampleFits.append(sampleFit)

            # Add the parameters to the sample and experiment
            for varName, varUnits, description, varValue in izip(
                    self.model.getParameterNames(), self.model.parameterUnits,
                    self.model.getParameterDescriptions(),
                    self.model.parameters):
                self.experiment.addParameterToSample(sampleName, varName,
                                                     varUnits, description,
                                                     varValue)

            self.postSampleAnalysis(sampleName)

            if reportX != None:
                print("Evaluation of the model at specified time points")
                yreportX = self.model.forwardModel(self.model.parameters,
                                                   reportX)
                print("==========================================")
                print("X     Ypredicted     log10(Ypredicted)")
                print("==========================================")
                for n in range(0, reportX.shape[0]):
                    print("%f %f %f" %
                          (reportX[n], yreportX[n], math.log10(yreportX[n])))
                print(' ')

        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))
class ProtPKPDODEBootstrap(ProtPKPDODEBase):
    """ Bootstrap of an ODE protocol"""

    _label = 'ODE bootstrap'

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam('inputODE', params.PointerParam, label="Input ODE model",
                      pointerClass='ProtPKPDMonoCompartment, ProtPKPDMonoCompartmentUrine, ProtPKPDTwoCompartments, '\
                                   'ProtPKPDTwoCompartmentsAutoinduction, ProtPKPDTwoCompartmentsClint, '\
                                   'ProtPKPDTwoCompartmentsClintMetabolite, ProtPKPDTwoCompartmentsUrine',
                      help='Select a run of an ODE model')
        form.addParam('Nbootstrap', params.IntParam, label="Bootstrap samples", default=200, expertLevel=LEVEL_ADVANCED,
                      help='Number of bootstrap realizations for each sample')
        form.addParam('sampleLength', params.IntParam, label="Sample length", default=-1, expertLevel=LEVEL_ADVANCED,
                      help='If the input experiment represents a population, the bootstrap sample is so overdetermined '\
                           'that the bootstrap parameter estimate seldom moves from the original values. In this case, '\
                           'you may use the sample length to generate bootstrap samples of the same length as the indiviudals '\
                           'taking part of the population. If this value is set to -1, then the length of the bootstrap sample '\
                           'will be the same as the one in the input experiment. If set to any other value, e.g. 8, then '\
                           'each bootstrap sample will have this length')
        form.addParam('confidenceInterval', params.FloatParam, label="Confidence interval", default=95, expertLevel=LEVEL_ADVANCED,
                      help='Confidence interval for the fitted parameters')
        form.addParam('deltaT', params.FloatParam, default=2, label='Step (min)', expertLevel=LEVEL_ADVANCED)

    #--------------------------- INSERT steps functions --------------------------------------------
    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',self.inputODE.get().getObjId(), self.Nbootstrap.get(), self.confidenceInterval.get())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def parseBounds(self, boundsString):
        if boundsString!="" and boundsString!=None:
            tokens=boundsString.split(';')
            if len(tokens)!=self.getNumberOfParameters():
                raise Exception("The number of bound intervals does not match the number of parameters")
            self.boundsList=[]
            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append((float(values[0][1:]),float(values[1][:-1])))

    def setBounds(self,sample):
        self.parseBounds(self.protODE.bounds.get())
        self.setBoundsFromBoundsList()

    def setBoundsFromBoundsList(self):
        Nbounds = len(self.boundsList)
        Nsource = self.drugSource.getNumberOfParameters()
        Nmodel = self.model.getNumberOfParameters()
        if Nbounds!=Nsource+Nmodel:
            raise "The number of parameters (%d) and bounds (%d) are different"%(Nsource+Nmodel,Nbounds)
        self.boundsSource = self.boundsList[0:Nsource]
        self.boundsPK = self.boundsList[Nsource:]
        self.model.bounds = self.boundsPK

    def getBounds(self):
        return self.boundsList

    def runFit(self, objId, Nbootstrap, confidenceInterval):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted)==list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        if type(self.varNameY)==list:
            self.fitting.predicted=[self.experiment.variables[v] for v in self.varNameY]
        else:
            self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get()==0:
            fitType = "linear"
        elif self.protODE.fitType.get()==1:
            fitType = "log"
        elif self.protODE.fitType.get()==2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting "+groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample "+sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX,self.varNameY)
                print("X= "+str(x))
                print("Y= "+str(y))
                firstX=x[0] # From [array(...)] to array(...)
                firstY=y[0] # From [array(...)] to array(...)

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0, self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits==None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames==None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(sample.descriptors[parameterName]))
                print("Initial solution: %s"%str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)

                # Output object
                sampleFit = PKPDSampleFitBootstrap()
                sampleFit.sampleName = sample.sampleName
                sampleFit.parameters = np.zeros((self.Nbootstrap.get(),len(parameters0)),np.double)
                sampleFit.xB = []
                sampleFit.yB = []

                # Bootstrap samples
                idx = [k for k in range(0,len(firstX))]
                for n in range(0,self.Nbootstrap.get()):
                    ok = False
                    while not ok:
                        if self.sampleLength.get()>0:
                            lenToUse = self.sampleLength.get()
                        else:
                            lenToUse = len(idx)
                        idxB = sorted(np.random.choice(idx,lenToUse))
                        xB = [np.asarray([firstX[i] for i in idxB])]
                        yB = [np.asarray([firstY[i] for i in idxB])]

                        print("Bootstrap sample %d"%n)
                        print("X= "+str(xB))
                        print("Y= "+str(yB))
                        self.clearXYLists()
                        self.setXYValues(xB, yB)
                        self.parameters = parameters0

                        optimizer2 = PKPDLSOptimizer(self,fitType)
                        optimizer2.verbose = 0
                        try:
                            optimizer2.optimize()
                            ok=True
                        except Exception as e:
                            print(e)
                            raise(e)
                            ok=False

                    # Evaluate the quality on the whole data set
                    self.clearXYLists()
                    self.setXYValues(x, y)
                    optimizer2.evaluateQuality()
                    print(optimizer2.optimum)
                    print("   R2 = %f R2Adj=%f AIC=%f AICc=%f BIC=%f"%(optimizer2.R2,optimizer2.R2adj,optimizer2.AIC,\
                                                                       optimizer2.AICc,optimizer2.BIC))

                    # Keep this result
                    sampleFit.parameters[n,:] = optimizer2.optimum
                    sampleFit.xB.append(str(xB[0]))
                    sampleFit.yB.append(str(yB[0]))
                    sampleFit.copyFromOptimizer(optimizer2)

                self.fitting.sampleFits.append(sampleFit)

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputPopulation=self.fitting)
        self._defineSourceRelation(self.inputODE.get(), self.fitting)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = []
        msg.append("Number of bootstrap realizations: %d"%self.Nbootstrap.get())
        msg.append("Confidence interval: %f"%self.confidenceInterval.get())
        return msg

    def _validate(self):
        return []
class ProtPKPDODEBase(ProtPKPD,PKPDModelBase2):
    """ Base ODE protocol"""

    def __init__(self,**kwargs):
        ProtPKPD.__init__(self,**kwargs)
        self.boundsList = None

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams1(self, form, addXY=False, defaultPredictor="", defaultPredicted=""):
        form.addSection('Input')
        form.addParam('inputExperiment', params.PointerParam, label="Input experiment",
                      pointerClass='PKPDExperiment',
                      help='Select an experiment with samples')
        if addXY:
            form.addParam('predictor', params.StringParam, label="Predictor variable (X)", default=defaultPredictor,
                          help='Y is predicted as an exponential function of X, Y=f(X)')
            form.addParam('predicted', params.StringParam, label="Predicted variable (Y)", default=defaultPredicted,
                          help='Y is predicted as an exponential function of X, Y=f(X)')

        fromTo = form.addLine('Simulation length', expertLevel = LEVEL_ADVANCED,
                           help='Minimum and maximum time (in hours) and step size (in minutes). '
                                'If minimum and maximum are not given (set to -1), they are estimated from the sample')
        fromTo.addParam('t0', params.StringParam, default="", label='Min (h)')
        fromTo.addParam('tF', params.StringParam, default="", label='Max (h)')
        fromTo.addParam('deltaT', params.FloatParam, default=0.5, label='Step (min)')

        form.addParam('fitType', params.EnumParam, choices=["Linear","Logarithmic","Relative"], label="Fit mode", default=1,
                      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('confidenceInterval', params.FloatParam, label="Confidence interval", default=95, expertLevel=LEVEL_ADVANCED,
                      help='Confidence interval for the fitted parameters')
        form.addParam('reportX', params.StringParam, label="Evaluate at X", default="", expertLevel=LEVEL_ADVANCED,
                      help='Evaluate the model at these X values\nExample 1: [0,5,10,20,40,100]\nExample 2: 0:0.55:10, from 0 to 10 in steps of 0.5')
        form.addParam('globalSearch', params.BooleanParam, label="Global search", default=True, expertLevel=LEVEL_ADVANCED,
                      help='Global search looks for the best parameters within bounds. If it is not performed, the '
                           'middle of the bounding box is used as initial parameter for a local optimization')

    #--------------------------- INSERT steps functions --------------------------------------------
    def getListOfFormDependencies(self):
        retval = [self.fitType.get(), self.confidenceInterval.get(), self.reportX.get()]
        if hasattr(self,"predictor"):
            retval.append(self.predictor.get())
            retval.append(self.predicted.get())
        if hasattr(self,"bounds"):
            retval.append(self.bounds.get())
        return retval

    def _insertAllSteps(self):
        self._insertFunctionStep('runFit',self.getInputExperiment().getObjId(),self.getListOfFormDependencies())
        self._insertFunctionStep('createOutputStep')

    #--------------------------- STEPS functions --------------------------------------------
    def getInputExperiment(self):
        if hasattr(self,"inputExperiment"):
            return self.inputExperiment.get()
        else:
            return None

    def getXYvars(self):
        if hasattr(self,"predictor"):
            self.varNameX=self.predictor.get()
        else:
            self.varNameX=None

        if hasattr(self,"predicted"):
            self.varNameY=self.predicted.get()
        else:
            self.varNameY=None

    def configureSource(self, drugSource):
        pass

    def createModel(self):
        pass

    def setupModel(self):
        # Setup model
        self.model = self.createModel()
        self.model.setExperiment(self.experiment)
        self.model.setXVar(self.varNameX)
        self.model.setYVar(self.varNameY)
        self.modelList.append(self.model)

    def getResponseDimension(self):
        return self.model.getResponseDimension()

    def getStateDimension(self):
        return self.model.getStateDimension()

    def setBounds(self, sample):
        if hasattr(self,"bounds"):
            self.model.setBounds(self.bounds.get())

    def prepareForSampleAnalysis(self, sampleName):
        pass

    def postSampleAnalysis(self, sampleName):
        pass

    def setTimeRange(self, sample):
        if self.t0.get()=="" or self.tF.get()=="":
            tmin, tmax = sample.getRange(self.varNameX)
        else:
            tmin = self.t0.get()
            tmax = self.tF.get()
        if self.tmin==None:
            self.tmin=tmin
        else:
            self.tmin=min(tmin,self.tmin)
        if self.tmax==None:
            self.tmax=tmax
        else:
            self.tmax=max(tmax,self.tmax)

        if self.t0.get()=="":
            self.model.t0 = min(-10,self.tmin-10) # 10 minutes before
        else:
            self.model.t0 = min(-10,float(self.t0.get())*60)

        if self.tF.get()=="":
            self.model.tF = self.tmax+10 # 10 minutes later
        else:
            self.model.tF = float(self.tF.get())*60

        if hasattr(self,"deltaT"):
            self.model.deltaT = self.deltaT.get()

    # As model --------------------------------------------
    def clearGroupParameters(self):
        self.tmin = None
        self.tmax = None
        self.sampleList = []
        self.modelList = []
        self.drugSourceList = []
        self.clearXYLists()

    def clearXYLists(self):
        self.XList = []
        self.YList = []

    def parseBounds(self, boundsString):
        self.boundsList = []

        if boundsString!="" and boundsString!=None:
            tokens = boundsString.split(';')
            if len(tokens)!=self.getNumberOfParameters():
                raise Exception("The number of bound intervals does not match the number of parameters")

            for token in tokens:
                values = token.strip().split(',')
                self.boundsList.append((float(values[0][1:]),float(values[1][:-1])))

    def setBounds(self, sample):
        self.parseBounds(self.bounds.get())
        self.setBoundsFromBoundsList()

    def setBoundsFromBoundsList(self):
        Nbounds = len(self.boundsList)
        Nsource = self.drugSource.getNumberOfParameters()
        Nmodel = self.model.getNumberOfParameters()
        if Nbounds!=Nsource+Nmodel:
            raise Exception("The number of parameters (%d) and bounds (%d) are different"%(Nsource+Nmodel,Nbounds))
        self.boundsSource = self.boundsList[0:Nsource]
        self.boundsPK = self.boundsList[Nsource:]
        self.model.bounds = self.boundsPK

    def getBounds(self):
        return self.boundsList

    def getParameterBounds(self):
        """ Return a dictionary where the parameter name is the key
        and the bounds are its values. """
        boundsDict = OrderedDict()
        self.parseBounds(self.bounds.get()) # after this we have boundsList
        parameterNames = self.getParameterNames()

        for paramName, bound in izip(parameterNames, self.getBounds()):
            boundsDict[paramName] = bound

        # Set None as bound for parameters not matched
        for paramName in parameterNames:
            if paramName not in boundsDict:
                boundsDict[paramName] = None

        return boundsDict

    def setParameters(self, parameters):
        self.parameters = parameters
        self.parametersPK = self.parameters[-self.NparametersModel:]

        for n in range(len(self.modelList)):
            if self.NparametersSource>0:
                self.drugSourceList[n].setParameters(self.parameters[0:self.NparametersSource])
            self.modelList[n].setParameters(self.parametersPK)

    def setXYValues(self, x, y):
        PKPDModelBase.setXYValues(self,x,y)
        self.model.setXYValues(x, y)
        self.XList.append(x)
        self.YList.append(y)

    def mergeLists(self, iny):
        if len(self.XList)>1:
            outy=[]
            for m in range(len(iny[0])):
                outy.append(np.empty(shape=[0]))
            for m in range(len(outy)):
                for n in range(len(iny)):
                    outy[m]=np.concatenate((outy[m],iny[n][m]))
            return outy
        else:
            return iny[0]

    def separateLists(self,iny):
        outy=[]
        Nsamples=len(self.YList)
        if Nsamples==0:
            return
        Nmeasurements = self.model.getResponseDimension()
        idx=[0]*Nmeasurements
        for n in range(Nsamples):
            yn=self.YList[n]
            perSampleIn = []
            for j in range(Nmeasurements):
                ynDim = yn[j].size
                ysample = iny[j][idx[j]:(idx[j]+ynDim)]
                perSampleIn.append(ysample)
                idx[j]+=ynDim
            outy.append(perSampleIn)
        return outy

    def addSample(self, sample):
        self.sampleList.append(sample)
        self.model.setSample(sample)

    def forwardModel(self, parameters, x=None):
        self.setParameters(parameters)

        yPredictedList = []
        for n in range(len(self.modelList)):
            self.modelList[n].forwardModel(self.parametersPK,x)
            yPredictedList.append(self.modelList[n].yPredicted)
        self.yPredicted = self.mergeLists(yPredictedList)
        return copy.copy(self.yPredicted)

    def imposeConstraints(self,yt):
        self.model.imposeConstraints(yt)

    def getEquation(self):
        return self.drugSource.getEquation()+" and "+self.model.getEquation()

    def getModelEquation(self):
        return self.drugSource.getModelEquation()+" and "+self.model.getModelEquation()

    def getDescription(self):
        return self.drugSource.getDescription()+"; "+self.model.getDescription()

    def getParameterNames(self):
        retval = []
        parametersSource = self.drugSource.getParameterNames()
        self.NparametersSource = len(parametersSource)
        retval += parametersSource
        parametersModel = self.model.getParameterNames()
        self.NparametersModel = len(parametersModel)
        retval += parametersModel
        return retval

    def calculateParameterUnits(self,sample):
        retval = []
        retval += self.drugSource.calculateParameterUnits(sample)
        retval += self.model.calculateParameterUnits(sample)
        self.parameterUnits = retval

    def areParametersSignificant(self, lowerBound, upperBound):
        retval = []
        idx=0
        if len(self.boundsSource)>0:
            retval+=self.drugSource.areParametersSignificant(lowerBound[idx:len(self.boundsSource)],
                                                             upperBound[idx:len(self.boundsSource)])
        retval+=self.model.areParametersSignificant(lowerBound[len(self.boundsSource):],
                                                    upperBound[len(self.boundsSource):])
        return retval

    def areParametersValid(self, p):
        return self.drugSource.areParametersValid(p[0:len(self.boundsSource)]) and \
               self.model.areParametersValid(p[len(self.boundsSource):])

    def createDrugSource(self):
        self.drugSource = DrugSource()
        self.drugSourceList.append(self.drugSource)

        return self.drugSource

    # Really fit ---------------------------------------------------------
    def runFit(self, objId, otherDependencies):
        reportX = parseRange(self.reportX.get())
        self.setInputExperiment()

        # Setup model
        self.getXYvars()

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self._getPath("experiment.pkpd"))
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        if type(self.varNameY)==list:
            self.fitting.predicted=[]
            for y in self.varNameY:
                self.fitting.predicted.append(self.experiment.variables[y])
        else:
            self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.fitType.get()==0:
            fitType = "linear"
        elif self.fitType.get()==1:
            fitType = "log"
        elif self.fitType.get()==2:
            fitType = "relative"

        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting "+groupName)
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample "+sampleName)
                sample = self.experiment.samples[sampleName]

                self.createDrugSource()
                self.setupModel()

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX,self.varNameY)
                print("X= "+str(x))
                print("Y= "+str(y))
                print(" ")

                # Interpret the dose
                self.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0, self.model.tF)
                self.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.addSample(sample)
                self.prepareForSampleAnalysis(sampleName)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits==None:
                    self.fitting.modelParameterUnits = self.parameterUnits

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            if self.globalSearch:
                optimizer1 = PKPDDEOptimizer(self,fitType)
                optimizer1.optimize()
            else:
                self.parameters = np.zeros(len(self.boundsList),np.double)
                n = 0
                for bound in self.boundsList:
                    self.parameters[n] = 0.5*(bound[0]+bound[1])
                    n += 1
            try:
                optimizer2 = PKPDLSOptimizer(self,fitType)
                optimizer2.optimize()
            except Exception as e:
                msg=str(e)
                msg+="Errors in the local optimizer may be caused by starting from a bad initial guess\n"
                msg+="Try performing a global search first or changing the bounding box"
                raise Exception("Error in the local optimizer\n"+msg)
            optimizer2.setConfidenceInterval(self.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)
            optimizer2.evaluateQuality()

            self.yPredictedList=self.separateLists(self.yPredicted)
            self.yPredictedLowerList=self.separateLists(self.yPredictedLower)
            self.yPredictedUpperList=self.separateLists(self.yPredictedUpper)

            n=0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = self.XList[n]
                sampleFit.y = self.YList[n]
                sampleFit.yp = self.yPredictedList[n]
                sampleFit.yl = self.yPredictedLowerList[n]
                sampleFit.yu = self.yPredictedUpperList[n]
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(self.getParameterNames(), self.parameterUnits, self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(sampleName, varName, varUnits, description, varValue)

                self.postSampleAnalysis(sampleName)

                if reportX!=None:
                    print("Evaluation of the model at specified time points")
                    self.model.tF = np.max(reportX)
                    yreportX = self.model.forwardModel(self.model.parameters, reportX)
                    print("==========================================")
                    print("X     Ypredicted     log10(Ypredicted)")
                    print("==========================================")
                    for n in range(0,reportX.shape[0]):
                        aux = 0
                        if yreportX[n]>0:
                            aux = math.log10(yreportX[n])
                        print("%f %f %f"%(reportX[n],yreportX[n],aux))
                    print(' ')

                n+=1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription=self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))

    def createOutputStep(self):
        self._defineOutputs(outputFitting=self.fitting)
        self._defineOutputs(outputExperiment=self.experiment)
        self._defineSourceRelation(self.getInputExperiment(), self.fitting)
        self._defineSourceRelation(self.getInputExperiment(), self.experiment)

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = []
        self.getXYvars()
        if self.varNameX!=None:
            msg.append('Predicting %s from %s'%(self.varNameX,self.varNameY))
        return msg

    def _validate(self):
        self.getXYvars()
        errors=[]
        if self.varNameX!=None:
            experiment = self.readExperiment(self.getInputExperiment().fnPKPD, False)
            if not self.varNameX in experiment.variables:
                errors.append("Cannot find %s as variable"%self.varNameX)
            if type(self.varNameY)==list:
                for y in self.varNameY:
                    if not y in experiment.variables:
                        errors.append("Cannot find %s as variable"%y)
            else:
                if not self.varNameY in experiment.variables:
                    errors.append("Cannot find %s as variable"%self.varNameY)
        if self.bounds.get()=="":
            errors.append("Bounds are required")
        return errors

    def _citations(self):
        return ['Spiess2010']

    def filterVarForWizard(self, v):
        """ Define the type of variables required (used in wizard). """
        return v.isNumeric() and (v.isTime() or v.isMeasurement())
Example #26
0
    def runFit(self, objId, deltaT):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(
            self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted) == list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting()
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor = self.experiment.variables[self.varNameX]
        self.fitting.predicted = self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get() == 0:
            fitType = "linear"
        elif self.protODE.fitType.get() == 1:
            fitType = "log"
        elif self.protODE.fitType.get() == 2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting " + groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample " + sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX, self.varNameY)
                print("X= " + str(x))
                print("Y= " + str(y))

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0,
                                         self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits == None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames == None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(
                        sample.descriptors[parameterName]))
                print("Initial solution: %s" % str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)
                self.setXYValues(x, y)
                self.parameters = parameters0

            self.printSetup()
            self.x = self.mergeLists(self.XList)
            self.y = self.mergeLists(self.YList)

            optimizer2 = PKPDLSOptimizer(self, fitType)
            optimizer2.optimize()
            optimizer2.setConfidenceInterval(
                self.protODE.confidenceInterval.get())
            self.setParameters(optimizer2.optimum)

            n = 0
            for sampleName in group.sampleList:
                sample = self.experiment.samples[sampleName]

                # Keep this result
                sampleFit = PKPDSampleFit()
                sampleFit.sampleName = sample.sampleName
                sampleFit.x = x
                sampleFit.y = y
                sampleFit.yp = self.yPredicted
                sampleFit.yl = self.yPredictedLower
                sampleFit.yu = self.yPredictedUpper
                sampleFit.parameters = self.parameters
                sampleFit.modelEquation = self.getEquation()
                sampleFit.copyFromOptimizer(optimizer2)
                self.fitting.sampleFits.append(sampleFit)

                # Add the parameters to the sample and experiment
                for varName, varUnits, description, varValue in izip(
                        self.getParameterNames(), self.parameterUnits,
                        self.getParameterDescriptions(), self.parameters):
                    self.experiment.addParameterToSample(
                        sampleName, varName, varUnits, description, varValue)

                n += 1

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("fitting.pkpd"))
        self.experiment.write(self._getPath("experiment.pkpd"))
    def runFit(self, objId, Nbootstrap, confidenceInterval):
        self.protODE = self.inputODE.get()
        self.experiment = self.readExperiment(self.protODE.outputExperiment.fnPKPD)
        self.fitting = self.readFitting(self.protODE.outputFitting.fnFitting)

        # Get the X and Y variable names
        self.varNameX = self.fitting.predictor.varName
        if type(self.fitting.predicted)==list:
            self.varNameY = [v.varName for v in self.fitting.predicted]
        else:
            self.varNameY = self.fitting.predicted.varName
        self.protODE.experiment = self.experiment
        self.protODE.varNameX = self.varNameX
        self.protODE.varNameY = self.varNameY

        # Create output object
        self.fitting = PKPDFitting("PKPDSampleFitBootstrap")
        self.fitting.fnExperiment.set(self.experiment.fnPKPD.get())
        self.fitting.predictor=self.experiment.variables[self.varNameX]
        if type(self.varNameY)==list:
            self.fitting.predicted=[self.experiment.variables[v] for v in self.varNameY]
        else:
            self.fitting.predicted=self.experiment.variables[self.varNameY]
        self.fitting.modelParameterUnits = None

        # Actual fitting
        if self.protODE.fitType.get()==0:
            fitType = "linear"
        elif self.protODE.fitType.get()==1:
            fitType = "log"
        elif self.protODE.fitType.get()==2:
            fitType = "relative"

        parameterNames = None
        for groupName, group in self.experiment.groups.iteritems():
            self.printSection("Fitting "+groupName)
            self.protODE.clearGroupParameters()
            self.clearGroupParameters()

            for sampleName in group.sampleList:
                print("   Sample "+sampleName)
                sample = self.experiment.samples[sampleName]

                self.protODE.createDrugSource()
                self.protODE.setupModel()

                # Setup self model
                self.drugSource = self.protODE.drugSource
                self.drugSourceList = self.protODE.drugSourceList
                self.model = self.protODE.model
                self.modelList = self.protODE.modelList
                self.model.deltaT = self.deltaT.get()
                self.model.setXVar(self.varNameX)
                self.model.setYVar(self.varNameY)

                # Get the values to fit
                x, y = sample.getXYValues(self.varNameX,self.varNameY)
                print("X= "+str(x))
                print("Y= "+str(y))
                firstX=x[0] # From [array(...)] to array(...)
                firstY=y[0] # From [array(...)] to array(...)

                # Interpret the dose
                self.protODE.varNameX = self.varNameX
                self.protODE.varNameY = self.varNameY
                self.protODE.model = self.model
                self.protODE.setTimeRange(sample)
                sample.interpretDose()

                self.drugSource.setDoses(sample.parsedDoseList, self.model.t0, self.model.tF)
                self.protODE.configureSource(self.drugSource)
                self.model.drugSource = self.drugSource

                # Prepare the model
                self.model.setSample(sample)
                self.calculateParameterUnits(sample)
                if self.fitting.modelParameterUnits==None:
                    self.fitting.modelParameterUnits = self.parameterUnits

                # Get the initial parameters
                if parameterNames==None:
                    parameterNames = self.getParameterNames()
                parameters0 = []
                for parameterName in parameterNames:
                    parameters0.append(float(sample.descriptors[parameterName]))
                print("Initial solution: %s"%str(parameters0))
                print(" ")

                # Set bounds
                self.setBounds(sample)

                # Output object
                sampleFit = PKPDSampleFitBootstrap()
                sampleFit.sampleName = sample.sampleName
                sampleFit.parameters = np.zeros((self.Nbootstrap.get(),len(parameters0)),np.double)
                sampleFit.xB = []
                sampleFit.yB = []

                # Bootstrap samples
                idx = [k for k in range(0,len(firstX))]
                for n in range(0,self.Nbootstrap.get()):
                    ok = False
                    while not ok:
                        if self.sampleLength.get()>0:
                            lenToUse = self.sampleLength.get()
                        else:
                            lenToUse = len(idx)
                        idxB = sorted(np.random.choice(idx,lenToUse))
                        xB = [np.asarray([firstX[i] for i in idxB])]
                        yB = [np.asarray([firstY[i] for i in idxB])]

                        print("Bootstrap sample %d"%n)
                        print("X= "+str(xB))
                        print("Y= "+str(yB))
                        self.clearXYLists()
                        self.setXYValues(xB, yB)
                        self.parameters = parameters0

                        optimizer2 = PKPDLSOptimizer(self,fitType)
                        optimizer2.verbose = 0
                        try:
                            optimizer2.optimize()
                            ok=True
                        except Exception as e:
                            print(e)
                            raise(e)
                            ok=False

                    # Evaluate the quality on the whole data set
                    self.clearXYLists()
                    self.setXYValues(x, y)
                    optimizer2.evaluateQuality()
                    print(optimizer2.optimum)
                    print("   R2 = %f R2Adj=%f AIC=%f AICc=%f BIC=%f"%(optimizer2.R2,optimizer2.R2adj,optimizer2.AIC,\
                                                                       optimizer2.AICc,optimizer2.BIC))

                    # Keep this result
                    sampleFit.parameters[n,:] = optimizer2.optimum
                    sampleFit.xB.append(str(xB[0]))
                    sampleFit.yB.append(str(yB[0]))
                    sampleFit.copyFromOptimizer(optimizer2)

                self.fitting.sampleFits.append(sampleFit)

        self.fitting.modelParameters = self.getParameterNames()
        self.fitting.modelDescription = self.getDescription()
        self.fitting.write(self._getPath("bootstrapPopulation.pkpd"))