class BootstrapRunner(AbstractRunner): def __init__(self, runnerArgument): """ Parameters ---------- runnerArgument: RunnerArgument Notes ----- 1. Uses METHOD_LEASTSQ for fitModel iterations. """ super().__init__() # self.lastErr = "" self.fitter = runnerArgument.fitter self.numIteration = runnerArgument.numIteration self.kwargs = runnerArgument.kwargs self.synthesizerClass = runnerArgument.synthesizerClass if "logger" in self.fitter.__dict__.keys(): self.logger = self.fitter.logger else: self.logger = Logger() self._isDone = not self._fitInitial() self.columns = self.fitter.selectedColumns # Initializations for bootstrap loop if not self.isDone: fittedTS = self.fitter.fittedTS.subsetColumns(self.columns, isCopy=False) self.synthesizer = self.synthesizerClass( observedTS=self.fitter.observedTS.subsetColumns(self.columns, isCopy=False), fittedTS=fittedTS, **self.kwargs) self.numSuccessIteration = 0 if self.fitter.minimizerResult is None: self.fitter.fitModel() self.baseChisq = self.fitter.minimizerResult.redchi self.curIteration = 0 self.fd = self.logger.getFileDescriptor() self.baseFittedStatistic = TimeseriesStatistic( self.fitter.observedTS.subsetColumns( self.fitter.selectedColumns, isCopy=False)) def report(self, id=None): if True: return if id is None: self._startTime = time.time() else: elapsed = time.time() - self._startTime print("%s: %2.3f" % (id, elapsed)) @property def numWorkUnit(self): return self.numIteration @property def isDone(self): return self._isDone def run(self): """ Runs the bootstrap. Returns ------- BootstrapResult """ def mkNullResult(): fittedStatistic = TimeseriesStatistic( self.fitter.observedTS[self.fitter.selectedColumns]) return BootstrapResult(self.fitter, 0, {}, fittedStatistic) # if self.isDone: return # Set up logging for this run if self.fd is not None: sys.stderr = self.fd sys.stdout = self.fd isSuccess = False bootstrapError = 0 self.report() for _ in range(ITERATION_MULTIPLIER): newObservedTS = self.synthesizer.calculate() self.report("newObservedTS") # Update fitter to use the new observed data _ = self.fitter._updateObservedTS(newObservedTS, isCheck=False) self.report("updated fitter") # Try fitting try: self.fitter.fitModel(params=self.fitter.params) self.report("fitter.fit") except Exception as err: # Problem with the fit. msg = "modelFitterBootstrap. Fit failed on iteration %d." \ % iteration self.logger.error(msg, err) bootstrapError += 1 continue # Verify that there is a result if self.fitter.minimizerResult is None: continue # Check if the fit is of sufficient quality if self.fitter.minimizerResult.redchi > MAX_CHISQ_MULT * self.baseChisq: continue if self.fitter.params is None: continue isSuccess = True self.report("break") break # Create the result if isSuccess: self.numSuccessIteration += 1 parameterDct = { k: [v] for k, v in self.fitter.params.valuesdict().items() } fittedStatistic = self.baseFittedStatistic.copy() fittedStatistic.accumulate( self.fitter.fittedTS.subsetColumns(self.fitter.selectedColumns, isCopy=False)) bootstrapResult = BootstrapResult(self.fitter, self.numSuccessIteration, parameterDct, fittedStatistic, bootstrapError=bootstrapError) else: bootstrapResult = mkNullResult() self._isDone = True # Close the logging file if self.fd is not None: if not self.fd.closed: self.fd.close() # See if completed work if self.numSuccessIteration >= self.numIteration: self._isDone = True return bootstrapResult def _fitInitial(self): """ Do the initial fit. Returns ------- bool successful fit """ isSuccess = False for _ in range(MAX_TRIES): try: self.fitter.fitModel() # Initialize model isSuccess = True break except Exception as err: self.lastErr = err msg = "Could not do initial fit" self.logger.error(msg, err) return isSuccess
class TestLogger(unittest.TestCase): def setUp(self): self.remove() self.logger = Logger(toFile=LOG_PATH, logPerformance=True, logLevel=logs.LEVEL_MAX) def tearDown(self): self.remove() def remove(self): for ffile in FILES: if os.path.isfile(ffile): os.remove(ffile) def isFile(self): return os.path.isfile(LOG_PATH) def read(self): if not self.isFile(): raise RuntimeError("Missing log file.") with open(LOG_PATH, "r") as fd: lines = fd.readlines() return lines def testConstructor(self): if IGNORE_TEST: return self.assertFalse(self.isFile()) self.assertEqual(self.logger.logLevel, logs.LEVEL_MAX) def testFileDescriptor(self): if IGNORE_TEST: return fd = self.logger.getFileDescriptor() self.assertIsInstance(fd, io.TextIOWrapper) fd.close() def _checkMsg(self, msg): lines = self.read() true = any([MSG in t for t in lines]) self.assertTrue(true) return lines def testWrite(self): if IGNORE_TEST: return self.logger._write(MSG, 0) _ = self._checkMsg(MSG) def _testApi(self, method, logLevel): if IGNORE_TEST: return logger = Logger(toFile=LOG_PATH, logLevel=logLevel) stmt = "logger.%s(MSG)" % method exec(stmt) line1s = self._checkMsg(MSG) # logger = Logger(toFile=LOG_PATH, logLevel=0) stmt = "logger.%s(MSG)" % method exec(stmt) line2s = self.read() self.assertEqual(len(line1s), len(line2s)) def testActivity(self): if IGNORE_TEST: return self._testApi("activity", logs.LEVEL_ACTIVITY) def testResult(self): if IGNORE_TEST: return self._testApi("result", logs.LEVEL_RESULT) def testStatus(self): if IGNORE_TEST: return self._testApi("status", logs.LEVEL_STATUS) def testException(self): if IGNORE_TEST: return self._testApi("status", logs.LEVEL_EXCEPTION) def testStartBlock(self): if IGNORE_TEST: return guid = self.logger.startBlock(BLOCK1) self.assertLess(guid, BlockSpecification.guid) self.assertEqual(len(self.logger.blockDct), 1) def testEndBlock(self): if IGNORE_TEST: return guid1 = self.logger.startBlock(BLOCK1) guid2 = self.logger.startBlock(BLOCK2) self.logger.endBlock(guid2) self.logger.endBlock(guid1) self.assertGreater(self.logger.statisticDct[BLOCK1].total, self.logger.statisticDct[BLOCK2].total) def testNoLogPerformance(self): if IGNORE_TEST: return logger = Logger(toFile=LOG_PATH, logPerformance=False, logLevel=logs.LEVEL_MAX) guid = logger.startBlock(BLOCK1) self.assertEqual(len(self.logger.blockDct), 0) logger.endBlock(guid) self.assertEqual(len(self.logger.blockDct), 0) def testPerformanceReport(self): if IGNORE_TEST: return def test(numBlock, sleepTime): logger = Logger(logPerformance=True) for idx in range(numBlock): block = "blk_%d" % idx guid = logger.startBlock(block) time.sleep(sleepTime) logger.endBlock(guid) df = logger.performanceDF self.assertLess(np.abs(sleepTime - df["mean"].mean()), sleepTime) self.assertEqual(df["count"].mean(), 1.0) # test(3, 0.1) test(30, 0.1) 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) def testCopy(self): if IGNORE_TEST: return newLogger = self.logger.copy() self.assertTrue(self.logger.equals(newLogger))