Exemplo n.º 1
0
    def _residuals(self, params) -> np.ndarray:
        """
        Compute the residuals between objective and experimental data
        Handle nan values in observedTS. This internal-only method
        is implemented to maximize efficieency.

        Parameters
        ----------
        kwargs: dict
            arguments for simulation

        Instance Variables Updated
        --------------------------
        self.residualsTS

        Returns
        -------
        1-d ndarray of residuals
        """
        block = Logger.join(self._loggerPrefix, "fitModel._residuals")
        guid = self.logger.startBlock(block)
        ##V
        self.roadrunnerModel.reset()
        self._setupModel(params)
        #
        roadrunnerBlock = Logger.join(block, "roadrunner")
        roadrunnerGuid = self.logger.startBlock(roadrunnerBlock)
        ## V
        #
        data = self.roadrunnerModel.simulate(self.observedTS.start,
                                             self.observedTS.end,
                                             len(self.observedTS),
                                             self.selectedColumns)
        ## ^
        self.logger.endBlock(roadrunnerGuid)
        #
        tailBlock = Logger.join(block, "tail")
        tailGuid = self.logger.startBlock(tailBlock)
        ## V
        residualsArr = self._observedArr - data.flatten()
        residualsArr = np.nan_to_num(residualsArr)
        ## ^
        self.logger.endBlock(tailGuid)
        ##^
        self.logger.endBlock(guid)
        #
        # Used for detailed debugging
        if False:
            self.logger.details("_residuals/std(residuals): %f" %
                                np.std(residualsArr))
            self.logger.details("_residuals/params: %s" % str(params))
        return residualsArr
Exemplo n.º 2
0
 def testJoin(self):
     if IGNORE_TEST:
         return
     NAMES = ["aa", "bbb", "z"]
     result = Logger.join(*NAMES)
     for name in NAMES:
         self.assertGreaterEqual(result.index(name), 0)
Exemplo n.º 3
0
    def fitModel(self, params: lmfit.Parameters = None, max_nfev: int = 100):
        """
        Fits the model by adjusting values of parameters based on
        differences between simulated and provided values of
        floating species.

        Parameters
        ----------
        params: starting values of parameters
        max_nfev: maximum number of function evaluations

        Example
        -------
        f.fitModel()
        """
        ParameterDescriptor = collections.namedtuple(
            "ParameterDescriptor",
            "params method std minimizer minimizerResult")
        block = Logger.join(self._loggerPrefix, "fitModel")
        guid = self.logger.startBlock(block)
        self._initializeRoadrunnerModel()
        if self.parametersToFit is None:
            # Compute fit and residuals for base model
            self.params = None
        else:
            if params is None:
                params = self.mkParams()
            # Fit the model to the data using one or more methods.
            # Choose the result with the lowest residual standard deviation
            paramDct = {}
            for method in self._fitterMethods:
                for _ in range(self._numFitRepeat):
                    minimizer = lmfit.Minimizer(self._residuals,
                                                params,
                                                max_nfev=max_nfev)
                    try:
                        minimizerResult = minimizer.minimize(method=method,
                                                             max_nfev=max_nfev)
                    except Exception as excp:
                        msg = "Error minimizing for method: %s" % method
                        self.logger.error(msg, excp)
                        continue
                    params = minimizerResult.params
                    std = np.std(self._residuals(params))
                    if method in paramDct.keys():
                        if std >= paramDct[method].std:
                            continue
                    paramDct[method] = ParameterDescriptor(
                        params=params.copy(),
                        method=method,
                        std=std,
                        minimizer=minimizer,
                        minimizerResult=minimizerResult,
                    )
            if len(paramDct) == 0:
                msg = "*** Minimizer failed for this model and data."
                raise ValueError(msg)
            # Select the result that has the smallest residuals
            sortedMethods = sorted(paramDct.keys(),
                                   key=lambda m: paramDct[m].std)
            bestMethod = sortedMethods[0]
            self.params = paramDct[bestMethod].params
            self.minimizer = paramDct[bestMethod].minimizer
            self.minimizerResult = paramDct[bestMethod].minimizerResult
        # Ensure that residualsTS and fittedTS match the parameters
        self.updateFittedAndResiduals(params=self.params)
        self.logger.endBlock(guid)
Exemplo n.º 4
0
    def simulate(self,
                 params=None,
                 startTime=None,
                 endTime=None,
                 numPoint=None):
        """
        Runs a simulation. Defaults to parameter values in the simulation.

        Parameters
       ----------
        params: lmfit.Parameters
        startTime: float
        endTime: float
        numPoint: int

        Return
        ------
        NamedTimeseries
        """
        def set(default, parameter):
            # Sets to default if parameter unspecified
            if parameter is None:
                return default
            else:
                return parameter

        ##V
        block = Logger.join(self._loggerPrefix, "fitModel.simulate")
        guid = self.logger.startBlock(block)
        ## V
        sub1Block = Logger.join(block, "sub1")
        sub1Guid = self.logger.startBlock(sub1Block)
        startTime = set(self.observedTS.start, startTime)
        endTime = set(self.observedTS.end, endTime)
        numPoint = set(len(self.observedTS), numPoint)
        ##  V
        sub1aBlock = Logger.join(sub1Block, "sub1a")
        sub1aGuid = self.logger.startBlock(sub1aBlock)
        if self.roadrunnerModel is None:
            self._initializeRoadrunnerModel()
        self.roadrunnerModel.reset()
        ##  ^
        self.logger.endBlock(sub1aGuid)
        ##  V
        sub1bBlock = Logger.join(sub1Block, "sub1b")
        sub1bGuid = self.logger.startBlock(sub1bBlock)
        if params is not None:
            # Parameters have been specified
            self._setupModel(params)
        ##  ^
        self.logger.endBlock(sub1bGuid)
        # Do the simulation
        selectedColumns = list(self.selectedColumns)
        if not TIME in selectedColumns:
            selectedColumns.insert(0, TIME)
        ## ^
        self.logger.endBlock(sub1Guid)
        ## V
        roadrunnerBlock = Logger.join(block, "roadrunner")
        roadrunnerGuid = self.logger.startBlock(roadrunnerBlock)
        data = self.roadrunnerModel.simulate(startTime, endTime, numPoint,
                                             selectedColumns)
        self.logger.endBlock(roadrunnerGuid)
        ## ^
        # Select the required columns
        ## V
        sub2Block = Logger.join(block, "sub2")
        sub2Guid = self.logger.startBlock(sub2Block)
        fittedTS = NamedTimeseries(namedArray=data)
        self.logger.endBlock(sub2Guid)
        ## ^
        self.logger.endBlock(guid)
        ##^
        return fittedTS
Exemplo n.º 5
0
def _runBootstrap(arguments: _Arguments, queue=None) -> BootstrapResult:
    """
    Executes bootstrapping.

    Parameters
    ----------
    arguments: inputs to bootstrap
    queue: multiprocessing.Queue

    Notes
    -----
    1. Only the first process generates progress reports.
    2. Uses METHOD_LEASTSQ for fitModel iterations.
    """
    fitter = arguments.fitter
    logger = fitter.logger
    mainBlock = Logger.join(arguments._loggerPrefix, "_runBootstrap")
    mainGuid = logger.startBlock(mainBlock)
    # Unapack arguments
    isSuccess = False
    lastErr = ""
    # Do an initial fit
    for _ in range(MAX_TRIES):
        try:
            fitter.fitModel()  # Initialize model
            isSuccess = True
            break
        except Exception as err:
            lastErr = err
    # Set up logging for this process
    fd = logger.getFileDescriptor()
    processIdx = arguments.processIdx
    if fd is not None:
        sys.stderr = logger.getFileDescriptor()
        sys.stdout = logger.getFileDescriptor()
    iterationGuid = None
    if not isSuccess:
        msg = "Process %d/modelFitterBootstrip/_runBootstrap" % processIdx
        logger.error(msg, lastErr)
        fittedStatistic = TimeseriesStatistic(fitter.observedTS,
                                              percentiles=[])
        bootstrapResult = BootstrapResult(fitter, 0, {}, fittedStatistic)
    else:
        numIteration = arguments.numIteration
        reportInterval = arguments.reportInterval
        processingRate = min(arguments.numProcess, multiprocessing.cpu_count())
        cols = fitter.selectedColumns
        synthesizer = arguments.synthesizerClass(
            observedTS=fitter.observedTS.subsetColumns(cols),
            fittedTS=fitter.fittedTS.subsetColumns(cols),
            **arguments.kwargs)
        # Initialize
        parameterDct = {p: [] for p in fitter.parametersToFit}
        numSuccessIteration = 0
        lastReport = 0
        if fitter.minimizerResult is None:
            fitter.fitModel()
        baseChisq = fitter.minimizerResult.redchi
        # Do the bootstrap iterations
        bootstrapError = 0
        iterationBlock = Logger.join(mainBlock, "Iteration")
        for iteration in range(numIteration * ITERATION_MULTIPLIER):
            if iterationGuid is not None:
                logger.endBlock(iterationGuid)
            iterationGuid = logger.startBlock(iterationBlock)
            newObservedTS = synthesizer.calculate()
            fittingSetupBlock = Logger.join(iterationBlock, "fittingSetup")
            fittingSetupGuid = logger.startBlock(fittingSetupBlock)
            newFitter = ModelFitterBootstrap(
                fitter.roadrunnerModel,
                newObservedTS,
                fitter.parametersToFit,
                selectedColumns=fitter.selectedColumns,
                # Use bootstrap methods for fitting
                fitterMethods=fitter._bootstrapMethods,
                parameterLowerBound=fitter.lowerBound,
                parameterUpperBound=fitter.upperBound,
                fittedDataTransformDct=fitter.fittedDataTransformDct,
                logger=logger,
                _loggerPrefix=iterationBlock,
                isPlot=fitter._isPlot)
            fittedStatistic = TimeseriesStatistic(newFitter.observedTS,
                                                  percentiles=[])
            logger.endBlock(fittingSetupGuid)
            try:
                if (iteration > 0) and (iteration != lastReport)  \
                        and (processIdx == 0):
                    totalSuccessIteration = numSuccessIteration * processingRate
                    totalIteration = iteration * processingRate
                    if totalIteration % reportInterval == 0:
                        msg = "Bootstrap completed %d total iterations "
                        msg += "with %d successes."
                        msg = msg % (totalIteration, totalSuccessIteration)
                        fitter.logger.status(msg)
                        lastReport = numSuccessIteration
                if numSuccessIteration >= numIteration:
                    # Performed the iterations
                    break
                tryBlock = Logger.join(iterationBlock, "try")
                tryGuid = logger.startBlock(tryBlock)
                try:
                    tryFitterBlock = Logger.join(tryBlock, "Fitter")
                    tryFitterGuid = logger.startBlock(tryFitterBlock)
                    newFitter.fitModel(params=fitter.params)
                    logger.endBlock(tryFitterGuid)
                except Exception as err:
                    # Problem with the fit. Don't numSuccessIteration it.
                    msg = "Process %d/modelFitterBootstrap" % processIdx
                    msg += " Fit failed on iteration %d." % iteration
                    fitter.logger.error(msg, err)
                    logger.endBlock(tryGuid)
                    continue
                if newFitter.minimizerResult.redchi > MAX_CHISQ_MULT * baseChisq:
                    if IS_REPORT:
                        msg = "Process %d: Fit has high chisq: %2.2f on iteration %d."
                        fitter.logger.exception(
                            msg %
                            (processIdx, newFitter.minimizerResult.redchi,
                             iteration))
                    logger.endBlock(tryGuid)
                    continue
                if newFitter.params is None:
                    continue
                numSuccessIteration += 1
                dct = newFitter.params.valuesdict()
                [
                    parameterDct[p].append(dct[p])
                    for p in fitter.parametersToFit
                ]
                cols = newFitter.fittedTS.colnames
                fittedStatistic.accumulate(newFitter.fittedTS)
                newFitter.observedTS = synthesizer.calculate()
                logger.endBlock(tryGuid)
            except Exception as err:
                msg = "Process %d/modelFitterBootstrap" % processIdx
                msg += " Error on iteration %d." % iteration
                fitter.logger.error(msg, err)
                bootstrapError += 1
        fitter.logger.status("Process %d: completed bootstrap." %
                             (processIdx + 1))
        bootstrapResult = BootstrapResult(fitter,
                                          numSuccessIteration,
                                          parameterDct,
                                          fittedStatistic,
                                          bootstrapError=bootstrapError)
    if iterationGuid is not None:
        logger.endBlock(iterationGuid)
    logger.endBlock(mainGuid)
    if fd is not None:
        if not fd.closed:
            fd.close()
    if queue is None:
        return bootstrapResult
    else:
        queue.put(bootstrapResult)
Exemplo n.º 6
0
    def fitModel(self, params: lmfit.Parameters = None, max_nfev=100):
        """
        Fits the model by adjusting values of parameters based on
        differences between simulated and provided values of
        floating species.

        Parameters
        ----------
        params: starting values of parameters

        Example
        -------
        f.fitModel()
        """
        ParameterDescriptor = collections.namedtuple(
            "ParameterDescriptor",
            "params method rssq kwargs minimizer minimizerResult")
        MAX_NFEV = "max_nfev"
        block = Logger.join(self._loggerPrefix, "fitModel")
        guid = self.logger.startBlock(block)
        self.initializeRoadRunnerModel()
        self.params = None
        if self.parametersToFit is not None:
            if params is None:
                params = self.mkParams()
            # Fit the model to the data using one or more methods.
            # Choose the result with the lowest residual standard deviation
            paramResults = []
            lastExcp = None
            for idx, optimizerMethod in enumerate(self._fitterMethods):
                method = optimizerMethod.method
                kwargs = optimizerMethod.kwargs
                if MAX_NFEV not in kwargs:
                    kwargs[MAX_NFEV] = max_nfev
                for _ in range(self._numFitRepeat):
                    self._bestParameters = _BestParameters(params=None,
                                                           rssq=None)
                    minimizer = lmfit.Minimizer(self._residuals, params)
                    try:
                        minimizerResult = minimizer.minimize(method=method,
                                                             **kwargs)
                    except Exception as excp:
                        lastExcp = excp
                        msg = "Error minimizing for method: %s" % method
                        self.logger.error(msg, excp)
                        continue
                    params = self._bestParameters.params.copy()
                    rssq = np.sum(self._residuals(params)**2)
                    if len(paramResults) > idx:
                        if rssq >= paramResults[idx].rssq:
                            continue
                    parameterDescriptor = ParameterDescriptor(
                        params=params,
                        method=method,
                        rssq=rssq,
                        kwargs=dict(kwargs),
                        minimizer=minimizer,
                        minimizerResult=minimizerResult,
                    )
                    paramResults.append(parameterDescriptor)
            if len(paramResults) == 0:
                msg = "*** Minimizer failed for this model and data."
                self.logger.error(msg, lastExcp)
            else:
                # Select the result that has the smallest residuals
                sortedMethods = sorted(paramResults, key=lambda r: r.rssq)
                bestMethod = sortedMethods[0]
                self.params = bestMethod.params
                self.minimizer = bestMethod.minimizer
                self.minimizerResult = bestMethod.minimizerResult
        # Ensure that residualsTS and fittedTS match the parameters
        self.updateFittedAndResiduals(params=self.params)
        self.logger.endBlock(guid)