Пример #1
0
    def _generate_summary_json(self, output_directory):
        """Creates summary.json (like BSF's) if configured to do so
        """
        if vis_hysplit_config('create_summary_json'):
            d_from = d_to = None
            try:
                d_from = datetime_parsing.parse(self._start_time)
                d_to = d_from + datetime.timedelta(hours=self._num_hours)
            except:
                pass

            contents = {
                "websky_version": vis_hysplit_config("websky_version"),
                "output_version": "2.0.1",
                # TODO: populate with real values
                "dispersion_period": {
                    "from": d_from and d_from.strftime("%Y%m%d %HZ"),
                    "to": d_to and d_to.strftime("%Y%m%d %HZ")
                },
                 "width_longitude": self._grid_params.get("width_longitude"),
                 "height_latitude": self._grid_params.get("height_latitude"),
                 "center_latitude": self._grid_params.get("center_latitude"),
                 "center_longitude":  self._grid_params.get("center_longitude"),
                 "model_configuration": "HYSPLIT",
                 "carryover": (self._fires_manager.dispersion and
                    self._fires_manager.dispersion.get("carryover") or {})
            }

            contents_json = json.dumps(contents, indent=4)
            logging.debug("generating summary.json: %s", contents)
            with open(os.path.join(output_directory, 'summary.json'), 'w') as f:
                f.write(contents_json)
Пример #2
0
    def add_kml(self, kmlfile, fire, hour):
        if fire['id'] not in self.fires:
            self.fires[fire['id']] = []

        # TODO: pass in and use model start time instead ?
        fire_dt = datetime_parsing.parse(fire['start'])
        hour_delta = timedelta(hours=1)
        dt = fire_dt + hour_delta * hour
        content = '''
            <NetworkLink>
                <name>%s - %s</name>
                <visibility>1</visibility>
                <TimeSpan><begin>%s</begin><end>%s</end></TimeSpan>
                <Link><href>%s</href></Link>
                <Style>
                    <ListStyle>
                        <listItemType>checkHideChildren</listItemType>
                    </ListStyle>
                </Style>
            </NetworkLink>
            ''' % (fire['id'], dt.strftime('Hour %HZ'), dt.isoformat(),
                   (dt + hour_delta).isoformat(), kmlfile)

        self.fires[fire['id']].append(content)

        if self.min_time == '' or dt < self.min_time:
            self.min_time = dt
        if self.max_time == '' or (dt + hour_delta) > self.max_time:
            self.max_time = dt
Пример #3
0
 def _convert_keys_to_datetime(self, d):
     return {datetime_parsing.parse(k): v for k, v in d.items()}
Пример #4
0
 def _on_or_after(self, dt1, dt2):
     # make sure same type, and convert to datetimes if not
     if type(dt1) != type(dt2):
         dt1 = datetime_parsing.parse(dt1)
         dt2 = datetime_parsing.parse(dt2)
     return dt1 >= dt2
Пример #5
0
    def write(self, fires_manager):
        fires_info = fires_manager.fires
        country_process_list = ['US', 'USA', 'United States']

        ptinv = open(self._ptinv_pathname, 'w')
        ptday = open(self._ptday_pathname, 'w')
        pthour = open(self._pthour_pathname, 'w')

        ptinv.write("#IDA\n#PTINV\n#COUNTRY %s\n" % country_process_list[0])
        ptinv.write("#YEAR %d\n" % self.file_year)
        ptinv.write("#DESC POINT SOURCE BlueSky Framework Fire Emissions\n")
        ptinv.write("#DATA PM2_5 PM10 CO NH3 NOX SO2 VOC PTOP PBOT LAY1F\n")

        ptday.write("#EMS-95\n#PTDAY\n#COUNTRY %s\n" % country_process_list[0])
        ptday.write("#YEAR %d\n" % self.file_year)
        ptday.write("#DESC POINT SOURCE BlueSky Framework Fire Emissions\n")

        pthour.write("#EMS-95\n#PTHOUR\n#COUNTRY %s\n" %
                     country_process_list[0])
        pthour.write("#YEAR %d\n" % self.file_year)
        pthour.write("#DESC POINT SOURCE BlueSky Framework Fire Emissions\n")

        num_of_fires = 0
        skip_no_lat_lng = 0
        skip_no_emiss = 0
        skip_no_lat_lng = 0
        skip_no_plume = 0
        skip_bad_fips = 0
        total_skipped = 0

        for fire_info in fires_info:
            for fire_loc in fire_info.locations:
                with fires_manager.fire_failure_handler(fire_info):
                    if any([k not in fire_loc for k in ('lat', 'lng')]):
                        skip_no_lat_lng += 1
                        total_skipped += 1
                        continue

                    num_of_fires += 1
                    if "emissions" not in fire_loc.keys():
                        skip_no_emiss += 1
                        total_skipped += 1
                        continue

                    if "plumerise" not in fire_loc.keys():
                        skip_no_plume += 1
                        total_skipped += 1
                        continue

                    lat, lng = fire_loc['lat'], fire_loc['lng']

                    # try to get CYID/STID, but skip record if lat/lng invalid
                    try:
                        cyid, stid = self._get_state_county_fips(lat, lng)
                    except ValueError:
                        print("Invalid Lat:%s and/or Invalid Lng:%s" %
                              (lat, lng))
                        skip_bad_fips += 1
                        total_skipped += 1
                        continue

                    scc = self._map_scc(fire_info.type)
                    start_dt = datetime_parsing.parse(fire_loc['start'])
                    start_hour = start_dt.hour

                    # if timeprofile key has 0 values, (for flaming/resid/etc), do we
                    # ignore or still right the value.
                    num_hours = len(fire_loc['timeprofile'].keys())
                    num_days = num_hours // 24
                    if num_hours % 24 > 0: num_days += 1
                    fcid = self._generate_fcid(fire_info, num_hours, lat, lng)
                    """
        NOTE: In the old BSF runs, timezone was never
        operational, and defaulted to EST in every output I reviewed.
        Per https://www.cmascenter.org/smoke/documentation/2.7/html/ch02s09s14.html,
        the timezone field is only used if timezone cannot be determined through FIPS code.
        """
                    tzonnam = self._set_timezone_name(lat, lng, start_dt)

                    # Define fire types, defaults to total.
                    if self._separate_smolder:
                        fire_phases = ("flaming", "smoldering")
                    else:
                        fire_phases = ("total", )

                    # iterate through fire_phases
                    for fire_phase in fire_phases:
                        if fire_phase == "total":
                            ptid = '1'  # Point ID
                            skid = '1'  # Stack ID
                        elif fire_phase == "flaming":
                            ptid = '1'  # Point ID
                            skid = '1'  # Stack ID
                            scc = scc[:-2] + "F" + scc[-1]
                        elif fire_phase == "smoldering":
                            ptid = '2'  # Point ID
                            skid = '2'  # Stack ID
                            scc = scc[:-2] + "S" + scc[-1]
                        prid = ''  # Process ID

                        date = start_dt.strftime('%m/%d/%y')  # Date

                        EMISSIONS_MAPPING = [('PM2_5', "pm2.5"),
                                             ('PM10', "pm10"), ('CO', "co"),
                                             ('NH3', "nh3"), ('NOX', "nox"),
                                             ('SO2', "so2"), ('VOC', "voc")]
                        """
          PTINV
          """
                        # PTINVRecord
                        ptinv_rec = PTINVRecord()
                        ptinv_rec.STID = stid
                        ptinv_rec.CYID = cyid
                        ptinv_rec.PLANTID = fcid
                        ptinv_rec.POINTID = ptid
                        ptinv_rec.STACKID = skid
                        ptinv_rec.SCC = scc
                        ptinv_rec.LATC = lat
                        ptinv_rec.LONC = lng

                        ptinv_rec_str = str(ptinv_rec)

                        if self._write_ptinv_totals:
                            logging.debug(
                                'Writing SmokeReady PTINV File to %s',
                                self._ptinv_pathname)
                            for var, vkey in EMISSIONS_MAPPING:
                                for fuelbed in fire_loc['fuelbeds']:
                                    if vkey.upper(
                                    ) in fuelbed['emissions'][fire_phase]:
                                        if fuelbed['emissions'][fire_phase][
                                                vkey.upper()] is None:
                                            continue
                                        prec = PTINVPollutantRecord()
                                        prec.ANN = fuelbed['emissions'][
                                            fire_phase][vkey.upper()][0]
                                        prec.AVD = fuelbed['emissions'][
                                            fire_phase][vkey.upper()][0]
                                        ptinv_rec_str += str(prec)

                        ptinv.write(ptinv_rec_str + "\n")
                        """
          PTDAY
          """
                        if self._write_ptday_file:
                            logging.debug(
                                'Writing SmokeReady PTHOUR File to %s',
                                self._ptday_pathname)
                            for var, vkey in EMISSIONS_MAPPING:
                                for fuelbed in fire_loc['fuelbeds']:
                                    if vkey.upper(
                                    ) in fuelbed['emissions'][fire_phase]:
                                        if fuelbed['emissions'][fire_phase][
                                                vkey.upper()] is None:
                                            continue
                                        for day in range(num_days):
                                            dt = start_dt + timedelta(days=day)
                                            date = dt.strftime('%m/%d/%y')

                                            # PTDAYRecord
                                            ptday_rec = PTDAYRecord()
                                            ptday_rec.STID = stid
                                            ptday_rec.CYID = cyid
                                            ptday_rec.FCID = fcid
                                            ptday_rec.SKID = ptid
                                            ptday_rec.DVID = skid
                                            ptday_rec.PRID = prid
                                            ptday_rec.POLID = var
                                            ptday_rec.DATE = date
                                            ptday_rec.TZONNAM = tzonnam

                                            start_slice = max(
                                                (24 * day) - start_hour, 0)
                                            end_slice = min(
                                                (24 * (day + 1)) - start_hour,
                                                len(fuelbed['emissions'][
                                                    fire_phase][vkey.upper()]))

                                            if fire_phase == "flaming":
                                                if isinstance(
                                                        fuelbed['emissions']
                                                    [fire_phase][vkey.upper()],
                                                        tuple):
                                                    daytot = fuelbed[
                                                        'emissions'][
                                                            fire_phase][
                                                                vkey.upper(
                                                                )][0]
                                                else:
                                                    daytot = sum(
                                                        tup for tup in
                                                        fuelbed['emissions']
                                                        [fire_phase][
                                                            vkey.upper()]
                                                        [start_slice:end_slice]
                                                    )
                                            elif fire_phase == "smoldering":
                                                if isinstance(
                                                        fuelbed['emissions']
                                                    [fire_phase][vkey.upper()],
                                                        tuple):
                                                    daytot = fuelbed[
                                                        'emissions'][fire_phase][
                                                            vkey.upper(
                                                            )][1] + fuelbed[
                                                                'emissions'][
                                                                    fire_phase][
                                                                        vkey.
                                                                        upper(
                                                                        )][2]
                                                else:
                                                    # comment for Yufei
                                                    # why are we including residual here?
                                                    smoldering = sum(
                                                        fuelbed['emissions']
                                                        [fire_phase][
                                                            vkey.upper()]
                                                        [start_slice:end_slice]
                                                    )
                                                    residual = sum(
                                                        fuelbed['emissions']
                                                        ['residual'][
                                                            vkey.upper()]
                                                        [start_slice:end_slice]
                                                    )
                                                    daytot = smoldering + residual

                                            else:
                                                if isinstance(
                                                        fuelbed['emissions']
                                                    [fire_phase][vkey.upper()],
                                                        tuple):
                                                    daytot = sum(
                                                        fuelbed['emissions']
                                                        [fire_phase][
                                                            vkey.upper()])
                                                else:
                                                    daytot = sum(
                                                        sum(fuelbed[
                                                            'emissions']
                                                            [fire_phase][
                                                                vkey.upper()]
                                                            [start_slice:
                                                             end_slice]))

                                            ptday_rec.DAYTOT = daytot  # Daily total
                                            ptday_rec.SCC = scc  # Source Classification Code
                                            ptday.write(str(ptday_rec))
                        """
          PTHOUR
          """
                        PTHOUR_MAPPING = [('PTOP', "percentile_100"),
                                          ('PBOT', "percentile_000"),
                                          ('LAY1F', "smoldering_fraction"),
                                          ('PM2_5', "pm2.5"), ('PM10', "pm10"),
                                          ('CO', "co"), ('NH3', "nh3"),
                                          ('NOX', "nox"), ('SO2', "so2"),
                                          ('VOC', "voc")]

                        logging.debug('Writing SmokeReady PTHOUR File to %s',
                                      self._pthour_pathname)
                        for var, vkey in PTHOUR_MAPPING:
                            species_key = vkey.upper()

                            if var in ('PTOP', 'PBOT', 'LAY1F'):
                                if fire_loc['plumerise'] is None: continue
                            else:
                                if species_key not in fuelbed['emissions'][
                                        'total'].keys():
                                    continue

                            # collect sorted hour list
                            ordered_hours = sorted(
                                fire_loc['plumerise'].keys())

                            for day in range(num_days):
                                dt = start_dt + timedelta(days=day)
                                date = dt.strftime('%m/%d/%y')  # Date

                                # PTHOUR Record
                                pthour_rec = PTHOURRecord()
                                pthour_rec.STID = stid
                                pthour_rec.CYID = cyid
                                pthour_rec.FCID = fcid
                                pthour_rec.SKID = ptid
                                pthour_rec.DVID = skid
                                pthour_rec.PRID = prid
                                pthour_rec.POLID = var
                                pthour_rec.DATE = date
                                pthour_rec.TZONNAM = tzonnam
                                pthour_rec.SCC = scc

                                daytot = 0.0
                                for hour in range(24):
                                    h = (day * 24) + hour - start_hour
                                    if h < 0:
                                        setattr(pthour_rec,
                                                'HRVAL' + str(hour + 1), 0.0)
                                        continue
                                    try:
                                        plumerise_hour = fire_loc['plumerise'][
                                            ordered_hours[h]]
                                        timeprofile_hour = fire_loc[
                                            'timeprofile'][ordered_hours[h]]
                                        emissions_summary = fire_loc[
                                            'emissions']['summary']

                                        if var in ('PTOP', 'PBOT', 'LAY1F'):
                                            if fire_phase == "flaming":
                                                if var == 'LAY1F':
                                                    value = 0.0001
                                                elif var == 'PTOP':
                                                    value = plumerise_hour[
                                                        'heights'][-1]
                                                elif var == 'PBOT':
                                                    value = plumerise_hour[
                                                        'heights'][0]
                                                else:
                                                    value = None
                                            elif fire_phase == "smoldering":
                                                value = {
                                                    'LAY1F': 1.0,
                                                    'PTOP': 0.0,
                                                    'PBOT': 0.0
                                                }[var]
                                            else:
                                                if var == 'LAY1F':
                                                    value = plumerise_hour[
                                                        'smoldering_fraction']
                                                elif var == 'PTOP':
                                                    value = plumerise_hour[
                                                        'heights'][-1]
                                                elif var == 'PBOT':
                                                    value = plumerise_hour[
                                                        'heights'][0]
                                                else:
                                                    value == None
                                        else:
                                            if fire_phase == "flaming":
                                                flaming_total = self._phase_emissions_for_species(
                                                    fire_loc, fire_phase,
                                                    species_key)
                                                value = (timeprofile_hour[
                                                    fire_phase] *
                                                         flaming_total)
                                            elif fire_phase == "smoldering":
                                                smoldering_total = self._phase_emissions_for_species(
                                                    fire_loc, fire_phase,
                                                    species_key)
                                                residual_total = self._phase_emissions_for_species(
                                                    fire_loc, 'residual',
                                                    species_key)
                                                smoldering_value = (
                                                    timeprofile_hour[
                                                        fire_phase] *
                                                    smoldering_total)
                                                residual_value = (
                                                    timeprofile_hour[
                                                        'residual'] *
                                                    residual_total)
                                                # smoke wants smoldering + residual
                                                value = smoldering_value + residual_value
                                            else:
                                                # fallback to total
                                                if species_key in emissions_summary.keys(
                                                ):
                                                    value = emissions_summary[
                                                        species_key]
                                            daytot += value
                                        setattr(pthour_rec,
                                                'HRVAL' + str(hour + 1), value)
                                    except IndexError:
                                        self.log.debug(
                                            "IndexError on hour %d for fire" %
                                            (h))
                                        setattr(pthour_rec,
                                                'HRVAL' + str(hour + 1), 0.0)

                                if var not in ('PTOP', 'PBOT', 'LAY1F'):
                                    pthour_rec.DAYTOT = daytot
                                pthour.write(str(pthour_rec))
        # Close Files
        ptinv.close()
        if self._write_ptday_file:
            ptday.close()
        pthour.close()
        logging.debug("SmokeReady Process Complete.")
        logging.debug(" #FIRES: %s", num_of_fires)
        logging.debug(" #SKIPPED: %s", total_skipped)
        logging.debug(" #NO LAT/LNG: %s", skip_no_lat_lng)
        logging.debug(" #NO EMISS: %s", skip_no_emiss)
        logging.debug(" #NO PLUME: %s", skip_no_plume)
        logging.debug(" #BAD FIPS: %s", skip_bad_fips)
Пример #6
0
    def __init__(self, fireLoc):
        # Basic fire info
        self.fireID = fireLoc['id']
        self.alat = float(fireLoc['latitude'])
        self.along = float(fireLoc['longitude'])
        self.acres = fireLoc['area']

        # Fire Date and time information
        # TODO: pass in and use model start time instead ?
        fire_dt = datetime_parsing.parse(fireLoc['start'])
        self.iyear = fire_dt.year
        self.imo = fire_dt.month
        self.iday = fire_dt.day
        self.hrstrt = fire_dt.hour
        self.tfire = fire_dt.hour
        self.firestart = fire_dt.strftime('%H%M')

        # Title for input files
        self.title = ("'VSMOKE input for fire ID %s'" % fireLoc['id'])

        vsmoke_meta = fireLoc.meta.get('vsmoke', {})

        # Stability
        self.stability = vsmoke_meta.get("stability", None)
        if self.stability:
            self.stability = int(self.stability)
            if self.stability < INPUTVariables.MIN_STAB:
                self.stability = INPUTVariables.MIN_STAB
            elif self.stability > INPUTVariables.MAX_STAB:
                self.stability = INPUTVariables.MAX_STAB

        # Mixing Height
        self.mix_ht = vsmoke_meta.get('mixht', None)
        if self.mix_ht:
            self.mix_ht = float(self.mix_ht)
            if self.mix_ht > INPUTVariables.MAX_MIXHT:
                self.mix_ht = INPUTVariables.MAX_MIXHT

        # Wind speed
        self.ua = vsmoke_meta.get('ws', None)
        if self.ua is None:
            raise ValueError("Wind speed ('meta' > 'vsmoke' > 'ws') "
                             "required for each fire")
        else:
            self.ua = float(self.ua)
            if self.ua <= INPUTVariables.MIN_WS:
                self.ua = INPUTVariables.MIN_WS + 0.001

        # Wind direction
        self.wdir = vsmoke_meta.get("wd", None)
        if self.wdir is None:
            raise ValueError("Wind direction ('meta' > 'vsmoke' > 'wd') "
                             "required for each fire")
        else:
            self.wdir = float(self.wdir)
            if self.wdir <= INPUTVariables.MIN_DIR:
                self.wdir = INPUTVariables.MIN_DIR + 0.001
            elif self.wdir > INPUTVariables.MAX_DIR:
                self.wdir = INPUTVariables.MAX_DIR

        # Surface temperature
        self.temp_fire = vsmoke_meta.get("temp", None)
        if self.temp_fire:
            self.temp_fire = float(self.temp_fire)

        # Surface pressure
        self.pres = vsmoke_meta.get("pressure", None)
        if self.pres:
            self.pres = float(self.pres)

        # Surface relative humidity
        self.irha = vsmoke_meta.get("rh", None)
        if self.irha:
            self.irha = int(self.irha)

        # Is fire during daylight hours or nighttime
        self.ltofdy = vsmoke_meta.get("sun", None)
        if self.ltofdy:
            self.ltofdy = str(self.ltofdy)

        # Initial horizontal dispersion
        self.oyinta = vsmoke_meta.get("oyinta", None)
        if self.oyinta:
            self.oyinta = float(self.oyinta)

        # Initial vertical dispersion
        self.ozinta = vsmoke_meta.get("ozinta", None)
        if self.ozinta:
            self.ozinta = float(self.ozinta)

        # Background PM 2.5
        self.bkgpma = vsmoke_meta.get("bkgpm", None)
        if self.bkgpma:
            self.bkgpma = float(self.bkgpma)

        # Background CO
        self.bkgcoa = vsmoke_meta.get("bkgco", None)
        if self.bkgcoa:
            self.bkgcoa = float(self.bkgcoa)
Пример #7
0
#  sunrise_hour,sunset_hour,snow_month,rain_days,heat,pm25,pm10,co,co2,
#  ch4,nox,nh3,so2,voc,canopy,event_url,fccs_number,owner,sf_event_guid,
#  sf_server,sf_stream_name,timezone,veg
FIRE_LOCATIONS_CSV_FIELDS = (
    [
        ('id', lambda f, loc: f.id),
        ('event_id', lambda f, loc: f.get('event_of', {}).get('id')),
        ('latitude', lambda f, loc: locationutils.LatLng(loc).latitude),
        ('longitude', lambda f, loc: locationutils.LatLng(loc).longitude),
        ('utc_offset', lambda f, loc: loc.get('utc_offset')),
        ('source', lambda f, loc: loc.get('source')),
        # Note: We're keeping the 'type' field consistent with the csv files
        #   generated by smartfire, which use 'RX' and 'WF'
        ('type', lambda f, loc: 'RX' if f.type == 'rx' else 'WF'),
        ('date_time',
         lambda f, loc: datetime_parsing.parse(
             loc['start']).strftime(BLUESKYKML_DATE_FORMAT)),
        ('event_name', lambda f, loc: f.get('event_of', {}).get('name')),
        ('fccs_number', _pick_representative_fuelbed),
        ('fuelbed_fractions', _get_fuelbed_fractions),

        # TDOO: add 'VEG'? (Note: sf2 has 'veg' field, but
        #   it seems to be a fuelbed discription which is probably for
        #   the one fccs id in the sf2 feed. This single fccs id and its description
        #   don't necesasrily represent the entire fire area, which could have
        #   multiple fuelbeds.  we could set 'VEG' to
        #   a concatenation of the fuelbeds or the one one making up the largest
        #   fraction of the fire.)
        ('heat', _get_heat)
    ]
    # emissions
    + [(s.lower(), _get_emissions_species('PM2.5' if s is 'pm25' else s))