Source code for traveltimes_prediction.interface.prediction_manager
import datetime as dt
import logging
import time
import pytz
import collections
from copy import deepcopy
from ..configs import all_models, sections_settings, prediction_interval_seconds, sections_to_maintain
from . import SectionInterface
from ..data_processing import DBInterface
from ..support_files import ExtrapolatingCache
from ..support_files import MessageCodes
logger = logging.getLogger('traveltimes_prediction')
[docs]class PredictionManager:
"""
Class managing the prediction routine for all allowed sections.
"""
def __init__(self):
"""
Constructor.
"""
self.db_interface = DBInterface()
self.training_manager_process = None # reserved
self.maintained_sections = dict()
self.buffer = dict() # storage of past traveltime values for individual sections (queue)
self.max_traveltime = 7200
# @profile
[docs] def launch_prediction(self, sections=sections_to_maintain, prediction_interval_s=prediction_interval_seconds,
test_dtime=None):
"""
Method for looped prediction of traveltime.
:param list sections: list of all sections for which the prediction should be executed.
:param number prediction_interval_s: how often should the manager execute prediction.
:param datetime test_dtime: For TESTING PURPOSES -- artificial "now" datetime.
"""
self._initialize_prediction(sections=sections)
dt_now = test_dtime if test_dtime is not None else dt.datetime.now()
last_day = None
while True:
tick = time.time()
# Prepare interval for data retrieval
dt_now = (dt_now + dt.timedelta(seconds=60)) if test_dtime else dt.datetime.now()
dt_delta_future = dt.timedelta(seconds=30)
dt_delta_past = dt.timedelta(seconds=600)
interval_now = {'from': dt_now - dt_delta_past,
'to': dt_now + dt_delta_future}
results = []
for section in sections: # For each section execute prediction
prediction_result = self.maintained_sections[section].predict(time_interval=interval_now,
db_interface=self.db_interface)
for model_prediction in prediction_result:
pred_val = model_prediction['predicted_value']
if self.max_traveltime > pred_val > -1: # In case of valid prediction
tmp_res = model_prediction
self.buffer[section][model_prediction['model_type']].put(pred_val)
logger.info("[%s] Prediction by model - %s: %s -- %s "
% (section, model_prediction['model_type'], pred_val, dt_now.strftime("%Y-%m-%d %H:%M:%S")))
else: # In case of invalid prediction try to use cached values and extrapolate
tmp_res = deepcopy(model_prediction)
if model_prediction['model_type'] != -1:
res = self.buffer[section][model_prediction['model_type']].get() \
if not self.buffer[section][model_prediction['model_type']].empty() else -1
tmp_res['messages'].append(MessageCodes.RESULT_EXTRAPOLATED)
else:
res = -1
tmp_res['predicted_value'] = res
if pred_val > self.max_traveltime:
tmp_res['messages'].append(MessageCodes.TOO_HIGH_TRAVELTIME)
logger.warning("[%s] Too high traveltime predicted by model -- %s!! ",
section, model_prediction['model_type'])
logger.info("[%s] Result of prediction by model - %s - invalid, extrapolating and producing %s -- %s",
section, model_prediction['model_type'], str(res), dt_now.strftime("%Y-%m-%d %H:%M:%S"))
# Localize timezone -> for calculation_time (from calculation_time_local taken from BCK prediction)
tzone = pytz.timezone(sections_settings[section]['timezone'])
local_dt = tzone.localize(dt_now)
utc_dt = local_dt.astimezone(pytz.utc)
# Gave the tuple correct structure and order -> will be saved to DB
rr = (section, utc_dt.strftime('%Y-%m-%d %H:%M:00'), dt_now.strftime('%Y-%m-%d %H:%M:00'),
float(tmp_res['predicted_value'][0]) if isinstance(tmp_res['predicted_value'],
collections.Iterable) else float(tmp_res['predicted_value']),
tmp_res['model_type'], tmp_res['confidence'], str(tmp_res['messages']), tmp_res['delay'])
results.append(rr)
# Save prediction for all models and sections to DB.
self.db_interface.save_prediction_result(rows=results)
tock = time.time()
logger.info("Results successfully saved to DB. Prediction loop took %.2f seconds", (tock-tick))
if prediction_interval_s - (tock - tick) > 0:
time.sleep(prediction_interval_s - (tock - tick))
def _initialize_prediction(self, sections):
"""
Method for initializing the SerialManager`s attributes.
:param list sections: list of sections for which the SectionInterfaces should be initialized
"""
for section in sections:
models = list(all_models - sections_settings[section]['forbidden_models'])
self.maintained_sections[section] = SectionInterface(section=section, models=models)
self.buffer[section] = {model.name: ExtrapolatingCache() for model in models}