def _run_fire(hourly_fractions, fire): if (hourly_fractions and len(fire.activity) > 1 and set([len(e) for p, e in hourly_fractions.items()]) != set([24])): # TODO: Support this scenario, but make sure # len(hourly_fractions) equals the total number of hours # represented by all activity objects, and pass the appropriate # slice into each instantiation of StaticTimeProfiler # (or build this into StaticProfiler???) raise BlueSkyConfigurationError( "Only 24-hour repeatable time " "profiles supported for fires with multiple activity windows") _validate_fire(fire) for a in fire.activity: tw = parse_datetimes(a, 'start', 'end') profiler = StaticTimeProfiler(tw['start'], tw['end'], hourly_fractions=hourly_fractions) # convert timeprofile to dict with dt keys a['timeprofile'] = {} fields = list(profiler.hourly_fractions.keys()) for i in range(len(list(profiler.hourly_fractions.values()) [0])): # each phase should have same len hr = profiler.start_hour + (i * profiler.ONE_HOUR) a['timeprofile'][hr.isoformat()] = { p: profiler.hourly_fractions[p][i] for p in fields }
def run(fires_manager): """Runs plumerise module Args: - fires_manager -- bluesky.models.fires.FiresManager object """ fires_manager.processed(__name__, __version__) if not fires_manager.met: raise ValueError(NO_MET_ERROR_MSG) arl_profiler = arlprofiler.ArlProfiler(fires_manager.met.get('files'), time_step=Config().get( 'localmet', 'time_step')) logging.debug("Extracting localmet data for %d fires", len(fires_manager.fires)) for fire in fires_manager.fires: with fires_manager.fire_failure_handler(fire): # Make sure fire has at least some locations, but # iterate first through activice areas and then through # locations in order to get utc_offset and time windows if not fire.locations: raise ValueError(NO_ACTIVITY_ERROR_MSG) for aa in fire.active_areas: utc_offset = parse_utc_offset(aa.get('utc_offset')) tw = parse_datetimes(aa, 'start', 'end') for loc in aa.locations: latlng = LatLng(loc) # parse_utc_offset makes sure utc offset is defined and valid loc['localmet'] = arl_profiler.profile( latlng.latitude, latlng.longitude, tw['start'], tw['end'], utc_offset)
def _infer_time_windows_from_fires(fires_manager): time_windows = [] if fires_manager.fires: logging.debug("Met time window determined from fire activity data") # Find earliest and latest datetimes that include all fire activity periods # TODO: be more intelligent with possible gaps, so that met files for times # when no fire is growing are excluded ? for fire in fires_manager.fires: with fires_manager.fire_failure_handler(fire): if 'activity' in fire: # parse_utc_offset makes sure utc offset is defined and valid for a in fire.activity: utc_offset = parse_utc_offset( a.get('location', {}).get('utc_offset')) offset = datetime.timedelta(hours=utc_offset) tw = parse_datetimes(a, 'start', 'end') if tw['start'] > tw['end']: raise ValueError( "Invalid activity time window - start: {}, end: {}" .format(tw['start'], tw['end'])) start = tw['start'] - offset end = tw['end'] - offset time_windows.append({'start': start, 'end': end}) return time_windows
def _infer_time_windows_from_fires(fires_manager): time_windows = [] if fires_manager.fires: logging.debug("Met time window determined from fire activity data") # Find earliest and latest datetimes that include all fire activity periods # TODO: be more intelligent with possible gaps, so that met files for times # when no fire is growing are excluded ? for fire in fires_manager.fires: with fires_manager.fire_failure_handler(fire): for aa in fire.active_areas: # TODO: Because of the following: # a) start, end, & utc_offset are allowed to be set # per specified point or perimeter rather than per # active area, and # b) accessing [perim|sp].[start|end|utc_offset] will fallback # on aa's values if not defined in the sp,perim, # then maybe we should iterate through the aa's locations (sp,perim) # and execute the following logic on each location. We'd need to # make sure that time window merging and other downstream logic # aren't broken or negatively affected. utc_offset = parse_utc_offset(aa.get('utc_offset')) offset = datetime.timedelta(hours=utc_offset) tw = parse_datetimes(aa, 'start', 'end') if tw['start'] > tw['end']: raise ValueError( "Invalid activity time window - start: {}, end: {}" .format(tw['start'], tw['end'])) start = tw['start'] - offset end = tw['end'] - offset time_windows.append({'start': start, 'end': end}) return time_windows
def _get_profiler(hourly_fractions, fire, active_area): tw = parse_datetimes(active_area, 'start', 'end') # Use FepsTimeProfiler for Rx fires and StaticTimeProfiler for WF, # Unless custom hourly_fractions are specified, in which case # Static Time Profiler is used for all fires. # If ignition_start and ignition_end aren't specified for Rx fires, # FepsTimeProfiler will assume 9am-12pm # TODO: add config setting to use FEPS for Rx even if custom # hourly_fractions are specified (or the converse - i.e. alwys use # FEPS for rx and add setting to turn on use of hourly_fractions, # if specified, for Rx) if fire.type == 'rx' and not hourly_fractions: ig_start = active_area.get('ignition_start') and parse_datetime( active_area['ignition_start'], k='ignition_start') ig_end = active_area.get('ignition_end') and parse_datetime( active_area['ignition_end'], k='ignition_end') # TODO: pass in duff_fuel_load, total_above_ground_consumption, # total_below_ground_consumption, moisture_category, # relative_humidity, wind_speed, and duff_moisture_content, # if defined? return FepsTimeProfiler(tw['start'], tw['end'], local_ignition_start_time=ig_start, local_ignition_end_time=ig_end, fire_type=FireType.RX) else: return StaticTimeProfiler(tw['start'], tw['end'], hourly_fractions=hourly_fractions)
def run(fires_manager): """Runs plumerise module Args: - fires_manager -- bluesky.models.fires.FiresManager object """ logging.info("Running localmet module") fires_manager.processed(__name__, __version__) if not fires_manager.met: raise ValueError("Specify met files to use in localmet") arl_profiler = ArlProfiler(fires_manager.met.get('files'), time_step=Config.get('localmet', 'time_step')) logging.debug("Extracting localmet data for %d fires", len(fires_manager.fires)) for fire in fires_manager.fires: with fires_manager.fire_failure_handler(fire): if not fire.get('activity'): raise ValueError("Missing activity data required for localmet") for a in fire['activity']: latlng = LatLng(a.get('location')) # parse_utc_offset makes sure utc offset is defined and valid utc_offset = parse_utc_offset( a.get('location', {}).get('utc_offset')) tw = parse_datetimes(a, 'start', 'end') a['localmet'] = arl_profiler.profile(latlng.latitude, latlng.longitude, tw['start'], tw['end'], utc_offset)
def _get_configured_time_windows(fires_manager): time_window = Config.get('findmetdata', 'time_window') if time_window: logging.debug("Met time window specified in the config") time_window = parse_datetimes(time_window, 'first_hour', 'last_hour') # met data finder doesn't require round hours, but .... if (not is_round_hour(time_window['first_hour']) or not is_round_hour(time_window['last_hour'])): raise BlueSkyConfigurationError( "Met first and last hours must be round hours") time_window = { 'start': time_window['first_hour'], 'end': time_window['last_hour'] # TODO: round this up to the next hour? } return time_window
def _get_profiler(hourly_fractions, fire, active_area): tw = parse_datetimes(active_area, 'start', 'end') # Use FepsTimeProfiler for Rx fires and StaticTimeProfiler for WF, # Unless custom hourly_fractions are specified, in which case # Static Time Profiler is used for all fires. # If ignition_start and ignition_end aren't specified for Rx fires, # FepsTimeProfiler will assume 9am-12pm # TODO: add config setting to use FEPS for Rx even if custom # hourly_fractions are specified (or the converse - i.e. alwys use # FEPS for rx and add setting to turn on use of hourly_fractions, # if specified, for Rx) if fire.type == 'rx' and not hourly_fractions: ig_start = active_area.get('ignition_start') and parse_datetime( active_area['ignition_start'], k='ignition_start') ig_end = active_area.get('ignition_end') and parse_datetime( active_area['ignition_end'], k='ignition_end') # TODO: pass in duff_fuel_load, total_above_ground_consumption, # total_below_ground_consumption, moisture_category, # relative_humidity, wind_speed, and duff_moisture_content, # if defined? return FepsTimeProfiler(tw['start'], tw['end'], local_ignition_start_time=ig_start, local_ignition_end_time=ig_end, fire_type=FireType.RX) else: model_name = Config().get("timeprofile", "model").lower() if model_name == "ubc-bsf-feps": wfrtConfig = Config().get('timeprofile', 'ubc-bsf-feps') working_dir = wfrtConfig.get('working_dir') delete_if_no_error = wfrtConfig.get( 'delete_working_dir_if_no_error') with osutils.create_working_dir( working_dir=working_dir, delete_if_no_error=delete_if_no_error) as wdir: fire_working_dir = os.path.join( wdir, "feps-timeprofile-{}".format(fire.id)) if not os.path.exists(fire_working_dir): os.makedirs(fire_working_dir) return ubcbsffeps.UbcBsfFEPSTimeProfiler( active_area, fire_working_dir, wfrtConfig) else: return StaticTimeProfiler(tw['start'], tw['end'], hourly_fractions=hourly_fractions)
def run(fires_manager): """Runs plumerise module Args: - fires_manager -- bluesky.models.fires.FiresManager object """ fires_manager.processed(__name__, __version__) if not fires_manager.met: raise ValueError(NO_MET_ERROR_MSG) start_utc = None end_utc = None # keep array of references to locations passed into arlprofiler, # to update with local met data after bulk profiler is called locations = [] # actual array of locations to pass into arlprofiler profiler_locations = [] for fire in fires_manager.fires: with fires_manager.fire_failure_handler(fire): # Make sure fire has at least some locations, but # iterate first through activice areas and then through # locations in order to get utc_offset and time windows if not fire.locations: raise ValueError(NO_ACTIVITY_ERROR_MSG) for aa in fire.active_areas: # parse_utc_offset makes sure utc offset is defined and valid utc_offset = parse_utc_offset(aa.get('utc_offset')) tw = parse_datetimes(aa, 'start', 'end') # subtract utc_offset, since we want to get back to utc loc_start_utc = tw['start'] - datetime.timedelta( hours=utc_offset) start_utc = min(start_utc, loc_start_utc) if start_utc else loc_start_utc loc_end_utc = tw['end'] - datetime.timedelta(hours=utc_offset) end_utc = min(end_utc, loc_end_utc) if end_utc else loc_end_utc for loc in aa.locations: latlng = LatLng(loc) p_loc = { 'latitude': latlng.latitude, 'longitude': latlng.longitude } locations.append(loc) profiler_locations.append(p_loc) if len(locations) != len(profiler_locations): raise RuntimeError(FAILED_TO_COMPILE_INPUT_ERROR_MSG) if not start_utc or not end_utc: raise RuntimeError(NO_START_OR_END_ERROR_MSG) arl_profiler = arlprofiler.ArlProfiler(fires_manager.met.get('files'), time_step=Config().get( 'localmet', 'time_step')) logging.debug("Extracting localmet data for %d locations", len(profiler_locations)) localmet = arl_profiler.profile(start_utc, end_utc, profiler_locations) if len(localmet) != len(locations): raise RuntimeError(PROFILER_RUN_ERROR_MSG) for i in range(len(localmet)): locations[i]['localmet'] = localmet[i]