Beispiel #1
0
    def _createOutputStep(self):
        # New Output would be an Integer
        boxSize = Integer(10)

        if self.iBoxSize.hasValue():
            boxSize.set(2 * int(self.iBoxSize.get()))

        self._defineOutputs(oBoxSize=boxSize)
Beispiel #2
0
class ProtPKPDExponentialFit(ProtPKPDFitBase):
    """ Fit a set of exponentials. The observed measurement is modelled as Y=sum_{i=1}^N c_i exp(-lambda_i * X).\n
Confidence intervals calculated by this fitting may be pessimistic because it assumes that all model parameters
are independent, which are not. Use Bootstrap estimates instead.\n
        Protocol created by http://www.kinestatpharma.com\n"""
    _label = 'fit exponentials'

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams(self, form, fullForm=True):
        self._defineParams1(form,"t","Cp")
        if fullForm:
            form.addParam('fitType', params.EnumParam, choices=["Linear","Logarithmic","Relative"], label="Fit mode", default=1,
                          help='Linear: sum (Cobserved-Cpredicted)^2\nLogarithmic: sum(log10(Cobserved)-log10(Cpredicted))^2\n'\
                               "Relative: sum ((Cobserved-Cpredicted)/Cobserved)^2")
            form.addParam('Nexp', params.IntParam, label="Number of exponentials", default=1,
                          help='Number of exponentials to fit')
        else:
            self.fitType=Integer()
            self.fitType.set(1)
            self.Nexp=Integer()
            self.Nexp.set(1)
        form.addParam('bounds', params.StringParam, label="Amplitude and time constant bounds", default="", expertLevel=LEVEL_ADVANCED,
                      help='Bounds for the c_i amplitudes and lambdas.\nExample 1: (0,10);(0,1e-2) -> c1 in (0,10), lambda1 in (0,1e-2)\n'\
                           'Example 2: (0,10);(0,1e-2);(0,1);(0,1e-1) -> c1 in (0,10), lambda1 in (0,1e-2), c2 in (0,1), lambda2 in (0,1e-1)')
        form.addParam('confidenceInterval', params.FloatParam, label="Confidence interval=", default=95, expertLevel=LEVEL_ADVANCED,
                      help='Confidence interval for the fitted parameters')
        if fullForm:
            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')
        else:
            self.reportX=String()
            self.reportX.set("")

    def getListOfFormDependencies(self):
        return [self.predictor.get(), self.predicted.get(), self.fitType.get(), self.bounds.get()]

    def createModel(self):
        return PKPDExponentialModel()

    def setupFromFormParameters(self):
        self.model.Nexp=self.Nexp.get()

    #--------------------------- INFO functions --------------------------------------------
    def _warnings(self):
        warnings = []
        experiment = self.readExperiment(self.getInputExperiment().fnPKPD,show=False)
        incorrectList = experiment.getNonBolusDoses()
        if len(incorrectList)>0:
            warnings.append("This protocol is meant only for intravenous bolus regimens. Check the doses for %s"%(','.join(incorrectList)))
        return warnings

    def _validate(self):
        errors=ProtPKPDFitBase._validate(self)
        if self.Nexp.get()<1:
            errors.append("The number of exponentials has to be larger than 0")
        return errors
Beispiel #3
0
class PKInhalationDissolution(EMObject):
    # Hartung2020_MATLAB/functions/get_disol.m
    # All implemented dissolution models are based on an adapted version of
    # the Noyes - Whitney equation, but differ in whether they
    # 1) describe saturable or unsaturable dissolution
    # 2) truncate or not the dissolution speed for small particles (for  numeric stability)
    # 3) truncate or not the dissolution speed for large particles
    #    (based on the assumption that only a part of the particle surface
    #    is in contact with the dissolution medium)

    UNSAT       = 0
    TRUNC_UNSAT = 1
    SAT         = 2 # Only this one is implemented
    TRUNC_SAT   = 3
    TRUNC2_SAT  = 4
    CAP         = 5
    XCAP        = 6
    UNSOL       = 7

    def __init__(self, **args):
        EMObject.__init__(self, **args)
        self.type = Integer()
        self.type.set(self.SAT)
        self.substanceParams = None

    def prepare(self, substanceParams, part):
        self.substanceParams = substanceParams
        substanceData = substanceParams.getData()

        if part=="bronchi":
            self.kdiss = substanceData['kdiss_br']
            self.Cs = substanceData['Cs_br']
        else:
            self.kdiss = substanceData['kdiss_alv']
            self.Cs = substanceData['Cs_alv']
        self.rho = substanceData['rho']

        print("Substance in %s ==================="%part)
        print("Maximum dissolution rate [nmol/(cm*min)]",self.kdiss)
        print("Solubility in [nmol/cm3]=[uM]",self.Cs)
        print("Density in [nmol/cm3]",self.rho)

        D = self.kdiss / self.Cs
        K = 4 * math.pi * D / (self.rho * np.power(4.0/3.0 * math.pi, 1.0/3.0))

        if self.type.get()==self.SAT:
            self.dissol = lambda s, Cf: np.multiply(np.reshape(K*(self.Cs-Cf),(Cf.size,1)),
                                                    np.reshape(np.where(s>0, np.power(s,1.0/3.0), 0.0),(1,s.size)))
                          # [cm^3/min]

    def getDissolution(self, s, Cf, h):
        return self.dissol(s,Cf)
Beispiel #4
0
class PKCiliarySpeed(EMObject):
    # Hartung2020_MATLAB/functions/get_cilspeed.m
    # Only 'interp' model is implemented here

    EXPON = 0
    FIT = 1
    INTERP = 2

    def __init__(self, **args):
        EMObject.__init__(self, **args)
        self.type = Integer()
        self.type.set(self.INTERP)

        self.lungParams = None

    def prepare(self, lungParams, ciliarySpeedType):
        self.type.set(ciliarySpeedType)

        self.lungParams = lungParams
        lungData = lungParams.getBronchial()

        self.Lx = np.sum(lungData['length_cm'])
        self.pos = lungData['pos']
        self.diam_cm = lungData['diam_cm']

        print("Ciliary speed ================")
        print("Total length of the lung [cm]",self.Lx)
        print("Location of branches [cm]",self.pos)
        print("Diameter of the branches [cm]",self.diam_cm)

        if self.type.get()==self.EXPON:
            # Exponentially increasing ciliary speed
            self.cilspeed = lambda x: np.where(x>self.Lx, 0.0, np.exp(np.log(4e-3) + x * (np.log(50) - np.log(4e-3))))
        elif self.type.get()==self.FIT:
            # Simple fitted empirical ciliary transport model
            self.cilspeed = lambda x: np.where(x<0.0, 0.0, np.exp(5*np.divide(self.Lx-x-3,np.power(3+self.Lx-x,0.92)))/200)
        elif self.type.get()==self.INTERP:
            # Hofmann - Sturm model for mucociliary transport velocity
            # Reference: Hofmann / Sturm (2004) J Aerosol Med, Vol 17(1)
            self.v = 0.1 * 1.2553 * np.power(lungData['diam_cm'],2.808) # in [cm / min]
            self.cilspeed = interp1d(self.pos, self.v, bounds_error=False, fill_value=(self.v[0], self.v[-1]))
class QueueConfig(OrderedObject):
    def __init__(self, **kwargs):
        OrderedObject.__init__(self, **kwargs)
        self.name = String('default')
        self.maxCores = Integer()
        self.allowMPI = Boolean()
        self.allowThreads = Boolean()
        self.maxHours = Integer()

    def getName(self):
        return self.name.get()

    def getMaxCores(self):
        return self.maxCores.get()

    def getAllowMPI(self):
        return self.allowMPI.get()

    def getAllowThreads(self):
        return self.allowThreads.get()

    def getMaxHours(self):
        return self.maxHours.get()

    def setName(self, name):
        self.name.set(name)

    def setMaxCores(self, maxCores):
        self.maxCores.set(maxCores)

    def setAllowMPI(self, allowMPI):
        self.allowMPI.set(allowMPI)

    def setAllowThreads(self, allowThreads):
        self.allowThreads.set(allowThreads)

    def setMaxHours(self, maxHours):
        self.maxHours.set(maxHours)
class XmippProtProjMatch(ProtRefine3D, ProtClassify3D):
    """ 3D reconstruction and classification using multireference projection matching"""

    _label = 'projection matching'
    
    FILENAMENUMBERLENGTH = 6

    def __init__(self, **args):        
        ProtRefine3D.__init__(self, **args)
        ProtClassify3D.__init__(self, **args)
        self.numberOfCtfGroups = Integer(1)
        self._lastIter = Integer(0)
        
    def _initialize(self):
        """ This function is mean to be called after the 
        working dir for the protocol have been set. (maybe after recovery from mapper)
        """
        self._loadInputInfo()
        # Setup the dictionary with filenames templates to 
        # be used by _getFileName
        createFilenameTemplates(self)
        # Load the values from several params generating a list
        # of values per iteration or references
        initializeLists(self)

    def _loadInputInfo(self):
        from pyworkflow.em.packages.xmipp3 import getImageLocation
        
        reference = self.input3DReferences.get() # Input can be either a single volume or a set of volumes.
        
        if isinstance(reference, Volume): # Treat the case of a single volume
            self.referenceFileNames = [getImageLocation(reference)]
        else:
            self.referenceFileNames = [getImageLocation(vol) for vol in reference]
            
        self.numberOfReferences = len(self.referenceFileNames)
        self.resolSam = reference.getSamplingRate()

        
    #--------------------------- DEFINE param functions --------------------------------------------   
        
    def _defineParams(self, form):
        """ Since the form definition is very very large,
        we have do it in a separated function.
        """
        _defineProjectionMatchingParams(self, form)
         
         
    #--------------------------- INSERT steps functions --------------------------------------------  
    
    def _insertAllSteps(self):
        self._initialize()
        # Insert initial steps
        self._insertFunctionStep('convertInputStep')
        self._insertFunctionStep('executeCtfGroupsStep')
#         insertExecuteCtfGroupsStep(self)
#         insertInitAngularReferenceFileStep(self)
        self._insertFunctionStep('initAngularReferenceFileStep')
        # Steps per iteration
        self._insertItersSteps()
        # Final steps
        self._insertFunctionStep('createOutputStep')
        
    def _insertItersSteps(self):
        """ Insert several steps needed per iteration. """
        
        for iterN in self.allIters():
            dirsStep = self._insertFunctionStep('createIterDirsStep', iterN)
            # Insert some steps per reference volume
            projMatchSteps = []
            for refN in self.allRefs():
                # Mask the references in the iteration
                insertMaskReferenceStep(self, iterN, refN, prerequisites=[dirsStep])
                # Create the library of projections
                insertAngularProjectLibraryStep(self, iterN, refN)
                # Projection matching steps
                projMatchStep = self._insertProjectionMatchingStep(iterN, refN)
                projMatchSteps.append(projMatchStep)
                
            # Select the reference that best fits each image
            self._insertFunctionStep('assignImagesToReferencesStep', iterN, prerequisites=projMatchSteps)
            
            insertAngularClassAverageStep(self, iterN, refN)
    
            # Reconstruct each reference with new averages
            for refN in self.allRefs():
                # Create new class averages with images assigned
                insertReconstructionStep(self, iterN, refN)
                
                if self.doComputeResolution and self._doSplitReferenceImages[iterN]:
                    # Reconstruct two halves of the data
                    insertReconstructionStep(self, iterN, refN, 'Split1')
                    insertReconstructionStep(self, iterN, refN, 'Split2')
                    # Compute the resolution
                    insertComputeResolutionStep(self, iterN, refN)
                    
                insertFilterVolumeStep(self, iterN, refN)

            # Calculate both angles and shifts devitations for this iteration
            self._insertFunctionStep('calculateDeviationsStep', iterN)

    
    def _insertProjectionMatchingStep(self, iterN, refN):
        args = getProjectionMatchingArgs(self, iterN)
        return self._insertFunctionStep('projectionMatchingStep', iterN, refN, args)
    
    #--------------------------- STEPS functions --------------------------------------------       

    def convertInputStep(self):
        """ Generated the input particles metadata expected 
        by projection matching. And copy the generated file to be
        used as initial docfile for further iterations.
        """
        from pyworkflow.em.packages.xmipp3 import writeSetOfParticles
        writeSetOfParticles(self.inputParticles.get(), self.selFileName, 
                            blockName=self.blockWithAllExpImages)
        #copyFile(self.selFileName, self._getFileName('inputParticlesDoc'))
        
    def createIterDirsStep(self, iterN):
        """ Create the necessary directory for a given iteration. """
        iterDirs = [self._getFileName(k, iter=iterN) for k in ['iterDir', 'projMatchDirs', 'libraryDirs']]
    
        for d in iterDirs:
            makePath(d)
            
        return iterDirs
    
    def volumeConvertStep(self, reconstructedFilteredVolume, maskedFileName):
        runVolumeConvertStep(self, reconstructedFilteredVolume, maskedFileName)
    
    def executeCtfGroupsStep(self, **kwargs):
        runExecuteCtfGroupsStep(self, **kwargs)
    
    def transformMaskStep(self, args, **kwargs):
        runTransformMaskStep(self, args, **kwargs)
    
    def angularProjectLibraryStep(self, iterN, refN, args, stepParams, **kwargs):
        runAngularProjectLibraryStep(self, iterN, refN, args, stepParams, **kwargs)
        
    def initAngularReferenceFileStep(self):
        runInitAngularReferenceFileStep(self)
        
    def projectionMatchingStep(self, iterN, refN, args):
        runProjectionMatching(self, iterN, refN, args)
    
    def assignImagesToReferencesStep(self, iterN):
        runAssignImagesToReferences(self, iterN)
        
    def cleanVolumeStep(self, vol1, vol2):
        cleanPath(vol1, vol2)
    
    def reconstructionStep(self, iterN, refN, program, method, args, suffix, mpi, threads, **kwargs):
        runReconstructionStep(self, iterN, refN, program, method, args, suffix, mpi, threads, **kwargs)
    
    def storeResolutionStep(self, resolIterMd, resolIterMaxMd, sampling):
        runStoreResolutionStep(self, resolIterMd, resolIterMaxMd, sampling)
    
    def calculateFscStep(self, iterN, refN, args, constantToAdd, **kwargs):
        runCalculateFscStep(self, iterN, refN, args, constantToAdd, **kwargs)
    
    def filterVolumeStep(self, iterN, refN, constantToAddToFiltration, **kwargs):
        runFilterVolumeStep(self, iterN, refN, constantToAddToFiltration, **kwargs)
    
    def createOutputStep(self):
        runCreateOutputStep(self)

    #--------------------------- INFO functions -------------------------------------------- 
    
    def _validate(self):
        errors = []
        if self.doCTFCorrection and not self.doAutoCTFGroup and not exists(self.setOfDefocus.get()):
            errors.append("Error: for non-automated ctf grouping, please provide a docfile!")
        if self.numberOfMpi<=1:
            errors.append("The number of MPI processes has to be larger than 1")
        
        xDimImg = self.inputParticles.get().getXDim()
        xDimVol, _, _ = self.input3DReferences.get().getDim()
        if xDimImg != xDimVol:
            errors.append("The dimensions of the volume(s) and particles must be equal!!!!")
        return errors
    
    def _citations(self):
        cites = []
        return cites
    
    def _summary(self):
        summary = []
        return summary
    
    def _methods(self):
        return self._summary()  # summary is quite explicit and serve as methods
    
    #--------------------------- UTILS functions --------------------------------------------
    
    def allIters(self):
        """ Iterate over all iterations. """
        for i in range(1, self.numberOfIterations.get()+1):
            yield i
            
    def allRefs(self):
        """ Iterate over all references. """
        for i in range(1, self.numberOfReferences+1):
            yield i
            
    def allCtfGroups(self):
        """ Iterate over all CTF groups. """
        for i in range(1, self.numberOfCtfGroups.get() + 1):
            yield i
            
    def itersFloatValues(self, attributeName, firstValue=-1):
        """ Take the string of a given attribute and
        create a list of floats that will be used by 
        the iteratioins. An special first value will be
        added to the list for iteration 0.
        """
        valuesStr = self.getAttributeValue(attributeName)
        if valuesStr is None:
            raise Exception('None value for attribute: %s' % attributeName)
        return [firstValue] + getFloatListFromValues(valuesStr, length=self.numberOfIterations.get())
    
    def itersBoolValues(self, attributeName, firstValue=False):
        """ Take the string of a given attribute and
        create a list of booleans that will be used by 
        the iteratioins. An special first value will be
        added to the list for iteration 0.
        """
        valuesStr = self.getAttributeValue(attributeName)
        if valuesStr is None:
            raise Exception('None value for attribute: %s' % attributeName)
        return [firstValue] + getBoolListFromValues(valuesStr, length=self.numberOfIterations.get())
        
    def itersStringValues(self, attributeName, firstValue='c1'):
        """ Take the string of a given attribute and
        create a list of strings that will be used by 
        the iteratioins. An special first value will be
        added to the list for iteration 0.
        """
        valuesStr = self.getAttributeValue(attributeName)
        if valuesStr is None:
            raise Exception('None value for attribute: %s' % attributeName)
        return [firstValue] + getStringListFromValues(valuesStr, length=self.numberOfIterations.get())
        
    def _getBlockFileName(self, blockName, blockNumber, filename, length=None):
        l = length or self.FILENAMENUMBERLENGTH
        
        return blockName + str(blockNumber).zfill(l) + '@' + filename
    
    def _getExpImagesFileName(self, filename):
        return self.blockWithAllExpImages + '@' + filename
    
    def _getRefBlockFileName(self, ctfBlName, ctfBlNumber, refBlName, refBlNumber, filename, length=None):
        l = length or self.FILENAMENUMBERLENGTH
        
        return ctfBlName + str(ctfBlNumber).zfill(l) + '_' + refBlName + str(refBlNumber).zfill(l) + '@' + filename

    def _getFourierMaxFrequencyOfInterest(self, iterN, refN):
        """ Read the corresponding resolution metadata and return the
        desired resolution.
        """
        md = xmipp.MetaData(self._getFileName('resolutionXmdMax', iter=iterN, ref=refN))
        return md.getValue(xmipp.MDL_RESOLUTION_FREQREAL, md.firstObject())
    
    def calculateDeviationsStep(self, it):
        """ Calculate both angles and shifts devitations for all iterations
        """
    
        SL = xmipp.SymList()
        mdIter = xmipp.MetaData()
        #for it in self.allIters():
        mdIter.clear()
        SL.readSymmetryFile(self._symmetry[it])
        md1 = xmipp.MetaData(self.docFileInputAngles[it])
        md2 = xmipp.MetaData(self.docFileInputAngles[it-1])
        #ignore disabled,
        md1.removeDisabled()
        md2.removeDisabled()

        #first metadata file may not have shiftx and shifty
        if not md2.containsLabel(xmipp.MDL_SHIFT_X):
            md2.addLabel(xmipp.MDL_SHIFT_X)
            md2.addLabel(xmipp.MDL_SHIFT_Y)
            md2.fillConstant(xmipp.MDL_SHIFT_X,0.)
            md2.fillConstant(xmipp.MDL_SHIFT_Y,0.)
        oldLabels=[xmipp.MDL_ANGLE_ROT,
                   xmipp.MDL_ANGLE_TILT,
                   xmipp.MDL_ANGLE_PSI,
                   xmipp.MDL_SHIFT_X,
                   xmipp.MDL_SHIFT_Y]
        newLabels=[xmipp.MDL_ANGLE_ROT2,
                   xmipp.MDL_ANGLE_TILT2,
                   xmipp.MDL_ANGLE_PSI2,
                   xmipp.MDL_SHIFT_X2,
                   xmipp.MDL_SHIFT_Y2]
        md2.renameColumn(oldLabels,newLabels)
        md2.addLabel(xmipp.MDL_SHIFT_X_DIFF)
        md2.addLabel(xmipp.MDL_SHIFT_Y_DIFF)
        md2.addLabel(xmipp.MDL_SHIFT_DIFF)
        mdIter.join1(md1, md2, xmipp.MDL_IMAGE, xmipp.INNER_JOIN)
        SL.computeDistance(mdIter,False,False,False)
        xmipp.activateMathExtensions()
        #operate in sqlite
        shiftXLabel     = xmipp.label2Str(xmipp.MDL_SHIFT_X)
        shiftX2Label    = xmipp.label2Str(xmipp.MDL_SHIFT_X2)
        shiftXDiff      = xmipp.label2Str(xmipp.MDL_SHIFT_X_DIFF)
        shiftYLabel     = xmipp.label2Str(xmipp.MDL_SHIFT_Y)
        shiftY2Label    = xmipp.label2Str(xmipp.MDL_SHIFT_Y2)
        shiftYDiff      = xmipp.label2Str(xmipp.MDL_SHIFT_Y_DIFF)
        shiftDiff       = xmipp.label2Str(xmipp.MDL_SHIFT_DIFF)
        #timeStr = str(dtBegin)
        operateString   =       shiftXDiff+"="+shiftXLabel+"-"+shiftX2Label
        operateString  += "," + shiftYDiff+"="+shiftYLabel+"-"+shiftY2Label
        mdIter.operate(operateString)
        operateString  =  shiftDiff+"=sqrt(" \
                          +shiftXDiff+"*"+shiftXDiff+"+" \
                          +shiftYDiff+"*"+shiftYDiff+");"
        mdIter.operate(operateString)
        iterFile = self._mdDevitationsFn(it)
        mdIter.write(iterFile,xmipp.MD_APPEND)

        self._setLastIter(it)

    
    def _mdDevitationsFn(self, it):
        mdFn = self._getPath('deviations.xmd')
        return "iter_%03d@" % it + mdFn

    def _setLastIter(self, iterN):
        self._lastIter.set(iterN)
        self._store(self._lastIter)

    def getLastIter(self):
        return self._lastIter.get()
    
    def _createItemMatrix(self, item, row):
        from pyworkflow.em.packages.xmipp3.convert import createItemMatrix
        import pyworkflow.em as em
        
        createItemMatrix(item, row, align=em.ALIGN_PROJ)
Beispiel #7
0
class ProtPKPDAbsorptionRate(ProtPKPDFitBase):
    """ Estimation of the absorption rate for a non-intravenous route. The estimation is performed after estimating
        the elimination rate. The experiment is determined by the\n
        Protocol created by http://www.kinestatpharma.com\n.
        See the theory at http://www.pharmpress.com/files/docs/Basic%20Pharmacokinetics%20sample.pdf"""
    _label = 'absorption rate'

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam('inputExperiment',
                      params.PointerParam,
                      label="Input experiment",
                      pointerClass='PKPDExperiment',
                      help='Select an experiment with samples')
        form.addParam(
            'protElimination',
            params.PointerParam,
            label="Elimination rate",
            pointerClass='ProtPKPDEliminationRate',
            help=
            'Select an execution of a protocol estimating the elimination rate'
        )
        form.addParam(
            "absorptionF",
            params.FloatParam,
            label="Absorption fraction",
            default=1,
            help="Between 0 (=no absorption) and 1 (=full absorption)")

        form.addParam(
            'bounds',
            params.StringParam,
            label="Ka, V, [tlag] bounds",
            default="",
            expertLevel=LEVEL_ADVANCED,
            help=
            'Bounds for Ka (absorption constant), V (distribution volume) and optionally tlag.\nExample 1: (0,1e-3);(30,50);(0.1,0.5) -> Ka in (0,1e-3), V in (30,50) and tlag in (0.1,0.5)\n'
        )
        form.addParam('confidenceInterval',
                      params.FloatParam,
                      label="Confidence interval",
                      default=95,
                      expertLevel=LEVEL_ADVANCED,
                      help='Confidence interval for the fitted parameters')
        form.addParam(
            'includeTlag',
            params.BooleanParam,
            label="Include tlag",
            default=True,
            expertLevel=LEVEL_ADVANCED,
            help='Calculate the delay between administration and absorption')
        self.fitType = Integer()  # Logarithmic fit
        self.fitType.set(1)

    def getListOfFormDependencies(self):
        return [
            self.protElimination.get().getObjId(),
            self.absorptionF.get(),
            self.bounds.get(),
            self.confidenceInterval.get()
        ]

    #--------------------------- STEPS functions --------------------------------------------
    def setupFromFormParameters(self):
        self.eliminationFitting = self.readFitting(
            self.protElimination.get().outputFitting.fnFitting.get())
        self.model.F = self.absorptionF.get()

    def getXYvars(self):
        self.varNameX = self.protElimination.get().predictor.get()
        self.varNameY = self.protElimination.get().predicted.get()

    def createModel(self):
        return PKPDSimpleEVModel(self.includeTlag.get())

    def prepareForSampleAnalysis(self, sampleName):
        sample = self.experiment.samples[sampleName]
        sampleFit = self.eliminationFitting.getSampleFit(sampleName)
        sample.interpretDose()
        self.model.D = sample.getDoseAt(0.0)
        self.model.Dunits = sample.getDoseUnits()
        if sampleFit == None:
            print(
                "  Cannot process %s because its elimination rate cannot be found\n\n"
                % sampleName)
            return False
        self.model.C0 = sampleFit.parameters[0]
        self.model.C0units = self.eliminationFitting.modelParameterUnits[0]
        self.model.Ke = sampleFit.parameters[1]
        self.model.KeUnits = self.eliminationFitting.modelParameterUnits[1]
        print("Concentration at t=0 = %f [%s]" %
              (self.model.C0, strUnit(self.model.C0units)))
        print("Elimination rate = %f [%s]" %
              (self.model.Ke, strUnit(self.model.KeUnits)))

        self.experiment.addParameterToSample(
            sampleName, "Ke", self.model.KeUnits,
            "Automatically estimated elimination rate", self.model.Ke)

        return True

    def postSampleAnalysis(self, sampleName):
        xunits = self.experiment.getVarUnits(self.varNameX)
        Cunits = self.experiment.getVarUnits(self.varNameY)
        Ka = self.model.parameters[0]
        Ke = self.model.Ke
        tmax = math.log(Ka / Ke) / (Ka - Ke)

        self.experiment.addParameterToSample(
            sampleName, "tmax", xunits,
            "Estimated time of the Maximum of the non-iv peak", tmax)
        Cmax = self.model.forwardModel(self.model.parameters,
                                       x=[np.atleast_1d(np.array(tmax))])[0][0]
        self.experiment.addParameterToSample(
            sampleName, "Cmax", Cunits,
            "Estimated concentration of the Maximum of the non-iv peak", Cmax)
        print("tmax = %f [%s]" % (tmax, strUnit(xunits)))
        print("Cmax = %f [%s]" % (Cmax, strUnit(Cunits)))

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg = []
        msg.append(
            "Non-compartmental analysis for the observations of the variable %s"
            % self.protElimination.get().predicted.get())
        return msg

    def _warnings(self):
        msg = []
        experiment = self.readExperiment(self.getInputExperiment().fnPKPD,
                                         show=False)
        incorrectList = experiment.getNonBolusDoses()
        if len(incorrectList) != 0:
            msg.append(
                "This protocol is meant only for bolus regimens. Check the doses for %s"
                % (','.join(incorrectList)))

        return msg
class XmippProtProjMatch(ProtRefine3D, ProtClassify3D):
    """ 3D reconstruction and classification using multireference projection matching"""

    _label = 'projection matching'

    FILENAMENUMBERLENGTH = 6

    def __init__(self, **args):
        ProtRefine3D.__init__(self, **args)
        ProtClassify3D.__init__(self, **args)
        self.numberOfCtfGroups = Integer(1)
        self._lastIter = Integer(0)

    def _initialize(self):
        """ This function is mean to be called after the 
        working dir for the protocol have been set. (maybe after recovery from mapper)
        """
        self._loadInputInfo()
        # Setup the dictionary with filenames templates to
        # be used by _getFileName
        createFilenameTemplates(self)
        # Load the values from several params generating a list
        # of values per iteration or references
        initializeLists(self)

    def _loadInputInfo(self):
        from pyworkflow.em.packages.xmipp3 import getImageLocation

        reference = self.input3DReferences.get(
        )  # Input can be either a single volume or a set of volumes.

        if isinstance(reference, Volume):  # Treat the case of a single volume
            self.referenceFileNames = [getImageLocation(reference)]
        else:
            self.referenceFileNames = [
                getImageLocation(vol) for vol in reference
            ]

        self.numberOfReferences = len(self.referenceFileNames)
        self.resolSam = reference.getSamplingRate()

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

    def _defineParams(self, form):
        """ Since the form definition is very very large,
        we have do it in a separated function.
        """
        _defineProjectionMatchingParams(self, form)

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

    def _insertAllSteps(self):
        self._initialize()
        # Insert initial steps
        self._insertFunctionStep('convertInputStep')
        self._insertFunctionStep('executeCtfGroupsStep')
        #         insertExecuteCtfGroupsStep(self)
        #         insertInitAngularReferenceFileStep(self)
        self._insertFunctionStep('initAngularReferenceFileStep')
        # Steps per iteration
        self._insertItersSteps()
        # Final steps
        self._insertFunctionStep('createOutputStep')

    def _insertItersSteps(self):
        """ Insert several steps needed per iteration. """

        for iterN in self.allIters():
            dirsStep = self._insertFunctionStep('createIterDirsStep', iterN)
            # Insert some steps per reference volume
            projMatchSteps = []
            for refN in self.allRefs():
                # Mask the references in the iteration
                insertMaskReferenceStep(self,
                                        iterN,
                                        refN,
                                        prerequisites=[dirsStep])
                # Create the library of projections
                insertAngularProjectLibraryStep(self, iterN, refN)
                # Projection matching steps
                projMatchStep = self._insertProjectionMatchingStep(iterN, refN)
                projMatchSteps.append(projMatchStep)

            # Select the reference that best fits each image
            self._insertFunctionStep('assignImagesToReferencesStep',
                                     iterN,
                                     prerequisites=projMatchSteps)

            insertAngularClassAverageStep(self, iterN, refN)

            # Reconstruct each reference with new averages
            for refN in self.allRefs():
                # Create new class averages with images assigned
                insertReconstructionStep(self, iterN, refN)

                if self.doComputeResolution and self._doSplitReferenceImages[
                        iterN]:
                    # Reconstruct two halves of the data
                    insertReconstructionStep(self, iterN, refN, 'Split1')
                    insertReconstructionStep(self, iterN, refN, 'Split2')
                    # Compute the resolution
                    insertComputeResolutionStep(self, iterN, refN)

                insertFilterVolumeStep(self, iterN, refN)

            # Calculate both angles and shifts devitations for this iteration
            self._insertFunctionStep('calculateDeviationsStep', iterN)

    def _insertProjectionMatchingStep(self, iterN, refN):
        args = getProjectionMatchingArgs(self, iterN)
        return self._insertFunctionStep('projectionMatchingStep', iterN, refN,
                                        args)

    #--------------------------- STEPS functions --------------------------------------------

    def convertInputStep(self):
        """ Generated the input particles metadata expected 
        by projection matching. And copy the generated file to be
        used as initial docfile for further iterations.
        """
        from pyworkflow.em.packages.xmipp3 import writeSetOfParticles
        writeSetOfParticles(self.inputParticles.get(),
                            self.selFileName,
                            blockName=self.blockWithAllExpImages)
        #copyFile(self.selFileName, self._getFileName('inputParticlesDoc'))

    def createIterDirsStep(self, iterN):
        """ Create the necessary directory for a given iteration. """
        iterDirs = [
            self._getFileName(k, iter=iterN)
            for k in ['iterDir', 'projMatchDirs', 'libraryDirs']
        ]

        for d in iterDirs:
            makePath(d)

        return iterDirs

    def volumeConvertStep(self, reconstructedFilteredVolume, maskedFileName):
        runVolumeConvertStep(self, reconstructedFilteredVolume, maskedFileName)

    def executeCtfGroupsStep(self, **kwargs):
        runExecuteCtfGroupsStep(self, **kwargs)

    def transformMaskStep(self, program, args, **kwargs):
        runTransformMaskStep(self, program, args, **kwargs)

    def angularProjectLibraryStep(self, iterN, refN, args, stepParams,
                                  **kwargs):
        runAngularProjectLibraryStep(self, iterN, refN, args, stepParams,
                                     **kwargs)

    def initAngularReferenceFileStep(self):
        runInitAngularReferenceFileStep(self)

    def projectionMatchingStep(self, iterN, refN, args):
        runProjectionMatching(self, iterN, refN, args)

    def assignImagesToReferencesStep(self, iterN):
        runAssignImagesToReferences(self, iterN)

    def cleanVolumeStep(self, vol1, vol2):
        cleanPath(vol1, vol2)

    def reconstructionStep(self, iterN, refN, program, method, args, suffix,
                           **kwargs):
        runReconstructionStep(self, iterN, refN, program, method, args, suffix,
                              **kwargs)

    def storeResolutionStep(self, resolIterMd, resolIterMaxMd, sampling):
        runStoreResolutionStep(self, resolIterMd, resolIterMaxMd, sampling)

    def calculateFscStep(self, iterN, refN, args, constantToAdd, **kwargs):
        runCalculateFscStep(self, iterN, refN, args, constantToAdd, **kwargs)

    def filterVolumeStep(self, iterN, refN, constantToAddToFiltration,
                         **kwargs):
        runFilterVolumeStep(self, iterN, refN, constantToAddToFiltration,
                            **kwargs)

    def createOutputStep(self):
        runCreateOutputStep(self)

    #--------------------------- INFO functions --------------------------------------------

    def _validate(self):
        errors = []

        if self.doCTFCorrection:

            if not self.doAutoCTFGroup and not exists(self.setOfDefocus.get()):
                errors.append("Error: for non-automated ctf grouping, "
                              "please provide a docfile!")

            if not self.inputParticles.get().hasCTF():
                errors.append("Error: for doing CTF correction the input "
                              "particles should have CTF information.")

        if self.numberOfMpi <= 1:
            errors.append(
                "The number of MPI processes has to be larger than 1")

        self._validateDim(self.inputParticles.get(),
                          self.input3DReferences.get(), errors,
                          'Input particles', 'Reference volume')

        return errors

    def _citations(self):
        cites = []
        return cites

    def _summary(self):
        summary = []
        return summary

    def _methods(self):
        return self._summary(
        )  # summary is quite explicit and serve as methods

    #--------------------------- UTILS functions --------------------------------------------

    def allIters(self):
        """ Iterate over all iterations. """
        for i in range(1, self.numberOfIterations.get() + 1):
            yield i

    def allRefs(self):
        """ Iterate over all references. """
        for i in range(1, self.numberOfReferences + 1):
            yield i

    def allCtfGroups(self):
        """ Iterate over all CTF groups. """
        for i in range(1, self.numberOfCtfGroups.get() + 1):
            yield i

    def itersFloatValues(self, attributeName, firstValue=-1):
        """ Take the string of a given attribute and
        create a list of floats that will be used by 
        the iteratioins. An special first value will be
        added to the list for iteration 0.
        """
        valuesStr = self.getAttributeValue(attributeName)
        if valuesStr is None:
            raise Exception('None value for attribute: %s' % attributeName)
        return [firstValue] + getFloatListFromValues(
            valuesStr, length=self.numberOfIterations.get())

    def itersBoolValues(self, attributeName, firstValue=False):
        """ Take the string of a given attribute and
        create a list of booleans that will be used by 
        the iteratioins. An special first value will be
        added to the list for iteration 0.
        """
        valuesStr = self.getAttributeValue(attributeName)
        if valuesStr is None:
            raise Exception('None value for attribute: %s' % attributeName)
        return [firstValue] + getBoolListFromValues(
            valuesStr, length=self.numberOfIterations.get())

    def itersStringValues(self, attributeName, firstValue='c1'):
        """ Take the string of a given attribute and
        create a list of strings that will be used by 
        the iteratioins. An special first value will be
        added to the list for iteration 0.
        """
        valuesStr = self.getAttributeValue(attributeName)
        if valuesStr is None:
            raise Exception('None value for attribute: %s' % attributeName)
        return [firstValue] + getStringListFromValues(
            valuesStr, length=self.numberOfIterations.get())

    def _getBlockFileName(self, blockName, blockNumber, filename, length=None):
        l = length or self.FILENAMENUMBERLENGTH

        return blockName + str(blockNumber).zfill(l) + '@' + filename

    def _getExpImagesFileName(self, filename):
        return self.blockWithAllExpImages + '@' + filename

    def _getRefBlockFileName(self,
                             ctfBlName,
                             ctfBlNumber,
                             refBlName,
                             refBlNumber,
                             filename,
                             length=None):
        l = length or self.FILENAMENUMBERLENGTH

        return ctfBlName + str(ctfBlNumber).zfill(l) + '_' + refBlName + str(
            refBlNumber).zfill(l) + '@' + filename

    def _getFourierMaxFrequencyOfInterest(self, iterN, refN):
        """ Read the corresponding resolution metadata and return the
        desired resolution.
        """
        md = xmipp.MetaData(
            self._getFileName('resolutionXmdMax', iter=iterN, ref=refN))
        return md.getValue(xmipp.MDL_RESOLUTION_FREQREAL, md.firstObject())

    def calculateDeviationsStep(self, it):
        """ Calculate both angles and shifts devitations for all iterations
        """

        SL = xmipp.SymList()
        mdIter = xmipp.MetaData()
        #for it in self.allIters():
        mdIter.clear()
        SL.readSymmetryFile(self._symmetry[it])
        md1 = xmipp.MetaData(self.docFileInputAngles[it])
        md2 = xmipp.MetaData(self.docFileInputAngles[it - 1])
        #ignore disabled,
        md1.removeDisabled()
        md2.removeDisabled()

        #first metadata file may not have shiftx and shifty
        if not md2.containsLabel(xmipp.MDL_SHIFT_X):
            md2.addLabel(xmipp.MDL_SHIFT_X)
            md2.addLabel(xmipp.MDL_SHIFT_Y)
            md2.fillConstant(xmipp.MDL_SHIFT_X, 0.)
            md2.fillConstant(xmipp.MDL_SHIFT_Y, 0.)
        oldLabels = [
            xmipp.MDL_ANGLE_ROT, xmipp.MDL_ANGLE_TILT, xmipp.MDL_ANGLE_PSI,
            xmipp.MDL_SHIFT_X, xmipp.MDL_SHIFT_Y
        ]
        newLabels = [
            xmipp.MDL_ANGLE_ROT2, xmipp.MDL_ANGLE_TILT2, xmipp.MDL_ANGLE_PSI2,
            xmipp.MDL_SHIFT_X2, xmipp.MDL_SHIFT_Y2
        ]
        md2.renameColumn(oldLabels, newLabels)
        md2.addLabel(xmipp.MDL_SHIFT_X_DIFF)
        md2.addLabel(xmipp.MDL_SHIFT_Y_DIFF)
        md2.addLabel(xmipp.MDL_SHIFT_DIFF)
        mdIter.join1(md1, md2, xmipp.MDL_IMAGE, xmipp.INNER_JOIN)
        SL.computeDistance(mdIter, False, False, False)
        xmipp.activateMathExtensions()
        #operate in sqlite
        shiftXLabel = xmipp.label2Str(xmipp.MDL_SHIFT_X)
        shiftX2Label = xmipp.label2Str(xmipp.MDL_SHIFT_X2)
        shiftXDiff = xmipp.label2Str(xmipp.MDL_SHIFT_X_DIFF)
        shiftYLabel = xmipp.label2Str(xmipp.MDL_SHIFT_Y)
        shiftY2Label = xmipp.label2Str(xmipp.MDL_SHIFT_Y2)
        shiftYDiff = xmipp.label2Str(xmipp.MDL_SHIFT_Y_DIFF)
        shiftDiff = xmipp.label2Str(xmipp.MDL_SHIFT_DIFF)
        #timeStr = str(dtBegin)
        operateString = shiftXDiff + "=" + shiftXLabel + "-" + shiftX2Label
        operateString += "," + shiftYDiff + "=" + shiftYLabel + "-" + shiftY2Label
        mdIter.operate(operateString)
        operateString  =  shiftDiff+"=sqrt(" \
                          +shiftXDiff+"*"+shiftXDiff+"+" \
                          +shiftYDiff+"*"+shiftYDiff+");"
        mdIter.operate(operateString)
        iterFile = self._mdDevitationsFn(it)
        mdIter.write(iterFile, xmipp.MD_APPEND)

        self._setLastIter(it)

    def _mdDevitationsFn(self, it):
        mdFn = self._getPath('deviations.xmd')
        return "iter_%03d@" % it + mdFn

    def _setLastIter(self, iterN):
        self._lastIter.set(iterN)
        self._store(self._lastIter)

    def getLastIter(self):
        return self._lastIter.get()

    def _fillParticlesFromIter(self, partSet, iteration):
        print("_fillParticlesFromIter")
        import pyworkflow.em.metadata as md

        imgSet = self.inputParticles.get()
        imgFn = "all_exp_images@" + self._getFileName(
            'docfileInputAnglesIters', iter=iteration, ref=1)
        partSet.copyInfo(imgSet)
        partSet.setAlignmentProj()

        partSet.copyItems(imgSet,
                          updateItemCallback=self._createItemMatrix,
                          itemDataIterator=md.iterRows(
                              imgFn, sortByLabel=md.MDL_ITEM_ID))

    def _createItemMatrix(self, item, row):
        from pyworkflow.em.packages.xmipp3.convert import createItemMatrix
        import pyworkflow.em as em

        createItemMatrix(item, row, align=em.ALIGN_PROJ)

    def _getIterParticles(self, it, clean=False):
        import pyworkflow.em as em
        """ Return a classes .sqlite file for this iteration.
        If the file doesn't exists, it will be created by 
        converting from this iteration data.star file.
        """

        dataParticles = self._getFileName('particlesScipion', iter=it)

        if clean:
            cleanPath(dataParticles)

        if not exists(dataParticles):
            partSet = em.SetOfParticles(filename=dataParticles)
            self._fillParticlesFromIter(partSet, it)
            partSet.write()
            partSet.close()
        else:
            partSet = em.SetOfParticles(filename=dataParticles)
            imgSet = self.inputParticles.get()
            partSet.copyInfo(imgSet)
            partSet.setAlignmentProj()

        return partSet
class QueueSystemConfig(OrderedObject):
    def __init__(self, **kwargs):
        OrderedObject.__init__(self, **kwargs)
        self.name = String()
        # Number of cores from which the queue is mandatory
        # 0 means no mandatory at all
        # 1 will force to launch all jobs through the queue
        self.mandatory = Integer()
        self.queues = None  # List for queue configurations
        self.submitCommand = String()
        # Allow to change the prefix of submission scripts
        # we used by default the ID.job, but in some clusters
        # the job script should start by a letter
        self.submitPrefix = String()
        self.checkCommand = String()
        self.cancelCommand = String()
        self.submitTemplate = String()
        self.jobDoneRegex = String()

    def hasName(self):
        return self.name.hasValue()

    def hasValue(self):
        return self.hasName() and len(self.queues)

    def getName(self):
        return self.name.get()

    def getMandatory(self):
        return self.mandatory.get()

    def getSubmitTemplate(self):
        return self.submitTemplate.get()

    def getSubmitCommand(self):
        return self.submitCommand.get()

    def getCheckCommand(self):
        return self.checkCommand.get()

    def getCancelCommand(self):
        return self.cancelCommand.get()

    def getQueues(self):
        return self.queues

    def setName(self, name):
        self.name.set(name)

    def setMandatory(self, mandatory):
        # This condition is to be backward compatible
        # when mandatory was a boolean
        # now it should use the number of CPU
        # that should force to use the queue
        if mandatory in ['False', 'false']:
            mandatory = 0
        elif mandatory in ['True', 'true']:
            mandatory = 1

        self.mandatory.set(mandatory)

    def setSubmitTemplate(self, submitTemplate):
        self.submitTemplate.set(submitTemplate)

    def setSubmitCommand(self, submitCommand):
        self.submitCommand.set(submitCommand)

    def setCheckCommand(self, checkCommand):
        self.checkCommand.set(checkCommand)

    def setCancelCommand(self, cancelCommand):
        self.cancelCommand.set(cancelCommand)

    def setJobDoneRegex(self, jobDoneRegex):
        self.jobDoneRegex.set(jobDoneRegex)

    def setQueues(self, queues):
        self.queues = queues

    def getQueueConfig(self, objId):
        if objId is not None and self.queues is not None:
            for queueConfig in self.queues:
                if objId == queueConfig.getObjId():
                    return queueConfig
        return None
class ProtAnnotateMembranes(EMProtocol):
    """ Manual annotation tool for segmented membranes
    """
    _label = 'annotate segmented membranes'
    _devStatus = BETA

    def __init__(self, **kwargs):
        EMProtocol.__init__(self, **kwargs)
        self._objectsToGo = Integer()
        self._provider = None
        self._tomoList = None

    def _defineParams(self, form):

        form.addSection(label='Input')
        form.addParam(
            'inputTomoMasks',
            PointerParam,
            label="Input Tomo Masks",
            important=True,
            pointerClass='SetOfTomoMasks',
            allowsNull=False,
            help=
            'Select the Tomogram Masks (segmented tomograms) for the membrane annotation.'
        )

    # --------------------------- INSERT steps functions ----------------------
    def _insertAllSteps(self):
        self._initialize()
        self._insertFunctionStep(self.runMembraneAnnotator, interactive=True)

    # --------------------------- STEPS functions -----------------------------

    def runMembraneAnnotator(self):
        # There are still some objects which haven't been annotated --> launch GUI
        self._getAnnotationStatus()
        if self._objectsToGo.get() > 0:
            MembAnnotatorDialog(None,
                                self._getExtraPath(),
                                provider=self._provider,
                                prot=self)

        # All the objetcs have been annotated --> create output objects
        self._getAnnotationStatus()
        if self._objectsToGo.get() == 0:
            print("\n==> Generating the outputs")
            labelledSet = self._genOutputSetOfTomoMasks()
            self._defineOutputs(outputSetofTomoMasks=labelledSet)

        self._store()

    # --------------------------- INFO functions -----------------------------------
    def _summary(self):
        summary = []
        objects2go = self._objectsToGo.get()
        if objects2go is not None:
            if objects2go > 0:
                summary.append(
                    '*%i* remaining segmentations to be annotated.' %
                    objects2go)
            else:
                summary.append(
                    'All segmentations have been already annotated.')
        return summary

    # --------------------------- UTIL functions -----------------------------------

    def _initialize(self):
        self._tomoList = [
            tomo.clone() for tomo in self.inputTomoMasks.get().iterItems()
        ]
        self._provider = MembAnnotatorProvider(self._tomoList,
                                               self._getExtraPath(),
                                               'membAnnotator')
        self._getAnnotationStatus()

    def _getAnnotationStatus(self):
        """Check if all the tomo masks have been annotated and store current status in a text file"""
        doneTomes = [
            self._provider.getObjectInfo(tomo)['tags'] == 'done'
            for tomo in self._tomoList
        ]
        self._objectsToGo.set(len(self._tomoList) - sum(doneTomes))

    def _getCurrentTomoMaskFile(self, inTomoFile):
        baseName = removeBaseExt(inTomoFile)
        return glob.glob(self._getExtraPath(baseName + '_materials.mrc'))[0]

    def _genOutputSetOfTomoMasks(self):
        tomoMaskSet = SetOfTomoMasks.create(self._getPath(),
                                            template='tomomasks%s.sqlite',
                                            suffix='annotated')
        inTomoSet = self.inputTomoMasks.get()
        tomoMaskSet.copyInfo(inTomoSet)
        counter = 1
        for inTomo in inTomoSet.iterItems():
            tomoMask = TomoMask()
            inTomoFile = inTomo.getVolName()
            tomoMask.copyInfo(inTomo)
            tomoMask.setLocation(
                (counter, self._getCurrentTomoMaskFile(inTomoFile)))
            tomoMask.setVolName(inTomoFile)
            tomoMaskSet.append(tomoMask)
            counter += 1

        return tomoMaskSet
class ProtPKPDAbsorptionRate(ProtPKPDFitBase):
    """ Estimation of the absorption rate for a non-intravenous route. The estimation is performed after estimating
        the elimination rate. The experiment is determined by the\n
        Protocol created by http://www.kinestatpharma.com\n.
        See the theory at http://www.pharmpress.com/files/docs/Basic%20Pharmacokinetics%20sample.pdf"""
    _label = 'absorption rate'

    #--------------------------- DEFINE param functions --------------------------------------------
    def _defineParams(self, form):
        form.addSection('Input')
        form.addParam('inputExperiment', params.PointerParam, label="Input experiment",
                      pointerClass='PKPDExperiment',
                      help='Select an experiment with samples')
        form.addParam('protElimination', params.PointerParam, label="Elimination rate",
                      pointerClass='ProtPKPDEliminationRate',
                      help='Select an execution of a protocol estimating the elimination rate')
        form.addParam("absorptionF", params.FloatParam, label="Absorption fraction", default=1,
                      help="Between 0 (=no absorption) and 1 (=full absorption)")

        form.addParam('bounds', params.StringParam, label="Ka, V, [tlag] bounds", default="", expertLevel=LEVEL_ADVANCED,
                      help='Bounds for Ka (absorption constant), V (distribution volume) and optionally tlag.\nExample 1: (0,1e-3);(30,50);(0.1,0.5) -> Ka in (0,1e-3), V in (30,50) and tlag in (0.1,0.5)\n')
        form.addParam('confidenceInterval', params.FloatParam, label="Confidence interval", default=95, expertLevel=LEVEL_ADVANCED,
                      help='Confidence interval for the fitted parameters')
        form.addParam('includeTlag', params.BooleanParam, label="Include tlag", default=True, expertLevel=LEVEL_ADVANCED,
                      help='Calculate the delay between administration and absorption')
        self.fitType=Integer() # Logarithmic fit
        self.fitType.set(1)

    def getListOfFormDependencies(self):
        return [self.protElimination.get().getObjId(), self.absorptionF.get(), self.bounds.get(), self.confidenceInterval.get()]

    #--------------------------- STEPS functions --------------------------------------------
    def setupFromFormParameters(self):
        self.eliminationFitting = self.readFitting(self.protElimination.get().outputFitting.fnFitting.get())
        self.model.F = self.absorptionF.get()

    def getXYvars(self):
        self.varNameX = self.protElimination.get().predictor.get()
        self.varNameY = self.protElimination.get().predicted.get()

    def createModel(self):
        return PKPDSimpleEVModel(self.includeTlag.get())

    def prepareForSampleAnalysis(self, sampleName):
        sample = self.experiment.samples[sampleName]
        sampleFit = self.eliminationFitting.getSampleFit(sampleName)
        sample.interpretDose()
        self.model.D = sample.getDoseAt(0.0)
        self.model.Dunits = sample.getDoseUnits()
        if sampleFit == None:
            print("  Cannot process %s because its elimination rate cannot be found\n\n"%sampleName)
            return False
        self.model.C0 = sampleFit.parameters[0]
        self.model.C0units = self.eliminationFitting.modelParameterUnits[0]
        self.model.Ke = sampleFit.parameters[1]
        self.model.KeUnits = self.eliminationFitting.modelParameterUnits[1]
        print("Concentration at t=0 = %f [%s]"%(self.model.C0,strUnit(self.model.C0units)))
        print("Elimination rate = %f [%s]"%(self.model.Ke,strUnit(self.model.KeUnits)))

        self.experiment.addParameterToSample(sampleName, "Ke", self.model.KeUnits, "Automatically estimated elimination rate", self.model.Ke)

        return True

    def postSampleAnalysis(self, sampleName):
        xunits = self.experiment.getVarUnits(self.varNameX)
        Cunits = self.experiment.getVarUnits(self.varNameY)
        Ka = self.model.parameters[0]
        Ke = self.model.Ke
        tmax = math.log(Ka/Ke)/(Ka-Ke)

        self.experiment.addParameterToSample(sampleName, "tmax", xunits, "Estimated time of the Maximum of the non-iv peak", tmax)
        Cmax = self.model.forwardModel(self.model.parameters,x=[np.atleast_1d(np.array(tmax))])[0][0]
        self.experiment.addParameterToSample(sampleName, "Cmax", Cunits, "Estimated concentration of the Maximum of the non-iv peak", Cmax)
        print("tmax = %f [%s]"%(tmax,strUnit(xunits)))
        print("Cmax = %f [%s]"%(Cmax,strUnit(Cunits)))

    #--------------------------- INFO functions --------------------------------------------
    def _summary(self):
        msg=[]
        msg.append("Non-compartmental analysis for the observations of the variable %s"%self.protElimination.get().predicted.get())
        return msg

    def _warnings(self):
        msg = []
        experiment = self.readExperiment(self.getInputExperiment().fnPKPD,show=False)
        incorrectList = experiment.getNonBolusDoses()
        if len(incorrectList)!=0:
            msg.append("This protocol is meant only for bolus regimens. Check the doses for %s"%(','.join(incorrectList)))

        return msg