Example #1
0
def test_fire_weather_ufunc_overwintering():
    ds = open_dataset("ERA5/daily_surface_cancities_1990-1993.nc")
    ds = ds.assign(
        rh=atmos.relative_humidity_from_dewpoint(ds=ds),
        ws=convert_units_to(atmos.wind_speed_from_vector(ds=ds)[0], "km/h"),
        tas=convert_units_to(ds.tas, "degC"),
        pr=convert_units_to(ds.pr, "mm/d"),
    )
    season_mask_all = fire_season(ds.tas,
                                  method="WF93",
                                  temp_end_thresh="4 degC")
    season_mask_all_LA08 = fire_season(ds.tas, snd=ds.swe, method="LA08")
    season_mask_yr = fire_season(ds.tas, method="WF93", freq="YS")

    # Mask is computed correctly and parameters are passed
    # season not passed so computed on the fly
    out1 = fire_weather_ufunc(
        tas=ds.tas,
        pr=ds.pr,
        lat=ds.lat,
        season_method="WF93",
        overwintering=False,
        temp_end_thresh=4,
        indexes=["DC"],
    )
    np.testing.assert_array_equal(out1["season_mask"], season_mask_all)

    out2 = fire_weather_ufunc(
        tas=ds.tas,
        pr=ds.pr,
        snd=ds.swe,
        lat=ds.lat,
        season_method="LA08",
        overwintering=True,
        indexes=["DC"],
    )
    np.testing.assert_array_equal(out2["season_mask"], season_mask_all_LA08)

    # Overwintering
    # Get last season's DC (from previous comp) and mask Saskatoon and Victoria
    dc0 = out2["DC"].ffill("time").isel(time=-1).where(
        [True, True, True, False, False])
    winter_pr = out2["winter_pr"]

    out3 = fire_weather_ufunc(
        tas=ds.tas,
        pr=ds.pr,
        lat=ds.lat,
        winter_pr=winter_pr,
        season_mask=season_mask_yr,
        dc0=dc0,
        overwintering=True,
        indexes=["DC"],
    )
    np.testing.assert_allclose(out3["winter_pr"].isel(location=0),
                               261.27353647,
                               rtol=1e-6)
    np.testing.assert_array_equal(out3["DC"].notnull(), season_mask_yr)
Example #2
0
def test_fire_weather_ufunc_drystart(atmosds):
    # This test is very shallow only tests if it runs.
    ds = atmosds.assign(
        tas=convert_units_to(atmosds.tas, "degC"),
        pr=convert_units_to(atmosds.pr, "mm/d"),
    )
    season_mask_yr = fire_season(ds.tas, method="WF93", freq="YS")

    out_ds = fire_weather_ufunc(
        tas=ds.tas,
        pr=ds.pr,
        hurs=ds.hurs,
        lat=ds.lat,
        season_mask=season_mask_yr,
        overwintering=False,
        dry_start="CFS",
        indexes=["DC", "DMC"],
        dmc_dry_factor=5,
    )
    out_no = fire_weather_ufunc(
        tas=ds.tas,
        pr=ds.pr,
        hurs=ds.hurs,
        lat=ds.lat,
        season_mask=season_mask_yr,
        overwintering=False,
        dry_start=None,
        indexes=["DC", "DMC"],
    )

    # I know season of 1992 is a "wet" start.
    xr.testing.assert_identical(
        out_ds["DC"].sel(location="Montréal", time="1992"),
        out_no["DC"].sel(location="Montréal", time="1992"),
    )
    xr.testing.assert_identical(
        out_ds["DMC"].sel(location="Montréal", time="1992"),
        out_no["DMC"].sel(location="Montréal", time="1992"),
    )
Example #3
0
def test_fire_weather_ufunc_errors(tas_series, pr_series, rh_series, ws_series):
    tas = tas_series(np.ones(100), start="2017-01-01")
    pr = pr_series(np.ones(100), start="2017-01-01")
    rh = rh_series(np.ones(100), start="2017-01-01")
    ws = ws_series(np.ones(100), start="2017-01-01")

    snd = xr.full_like(tas, 0)
    lat = xr.full_like(tas.isel(time=0), 45)
    DC0 = xr.full_like(tas.isel(time=0), np.nan)
    DMC0 = xr.full_like(tas.isel(time=0), np.nan)
    FFMC0 = xr.full_like(tas.isel(time=0), np.nan)

    # Test invalid combination
    with pytest.raises(TypeError):
        fire_weather_ufunc(
            tas=tas,
            pr=pr,
            rh=rh,
            ws=ws,
            lat=lat,
            dc0=DC0,
            indexes=["DC", "ISI"],
        )

    # Test missing arguments
    with pytest.raises(TypeError):
        fire_weather_ufunc(
            tas=tas,
            pr=pr,
            dc0=DC0,
            indexes=["DC"],  # lat=lat,
        )

    with pytest.raises(TypeError):
        fire_weather_ufunc(
            tas=tas,
            pr=pr,
            lat=lat,
            dc0=DC0,
            indexes=["DC"],
            start_up_mode="snow_depth",
        )

    # Test starting too early
    with pytest.raises(ValueError):
        fire_weather_ufunc(
            tas=tas,
            pr=pr,
            lat=lat,
            dc0=DC0,
            snd=snd,
            indexes=["DC"],
            start_date="2017-01-01",
            start_up_mode="snow_depth",
        )

    # Test output is complete
    out = fire_weather_ufunc(
        tas=tas,
        pr=pr,
        lat=lat,
        dc0=DC0,
        indexes=["DC"],
        start_date="2017-03-03",
    )

    assert len(out.keys()) == 1

    out = fire_weather_ufunc(
        tas=tas,
        pr=pr,
        rh=rh,
        ws=ws,
        lat=lat,
        snd=snd,
        dc0=DC0,
        dmc0=DMC0,
        ffmc0=FFMC0,
        indexes=["DSR"],
        start_date="2017-01-01",
    )

    assert len(out.keys()) == 7
Example #4
0
def test_fire_weather_ufunc_errors(tas_series, pr_series, hurs_series,
                                   sfcWind_series):
    tas = tas_series(np.ones(100), start="2017-01-01")
    pr = pr_series(np.ones(100), start="2017-01-01")
    hurs = hurs_series(np.ones(100), start="2017-01-01")
    sfcWind = sfcWind_series(np.ones(100), start="2017-01-01")

    snd = xr.full_like(tas, 0)
    lat = xr.full_like(tas.isel(time=0), 45)
    DC0 = xr.full_like(tas.isel(time=0), np.nan)  # noqa
    DMC0 = xr.full_like(tas.isel(time=0), np.nan)  # noqa
    FFMC0 = xr.full_like(tas.isel(time=0), np.nan)  # noqa

    # Test invalid combination
    with pytest.raises(TypeError):
        fire_weather_ufunc(
            tas=tas,
            pr=pr,
            hurs=hurs,
            lat=lat,
            dc0=DC0,
            indexes=["DC", "ISI"],
        )

    # Test missing arguments
    with pytest.raises(TypeError):
        fire_weather_ufunc(
            tas=tas,
            pr=pr,
            dc0=DC0,
            indexes=["DC"],  # lat=lat,
        )

    with pytest.raises(TypeError):
        fire_weather_ufunc(
            tas=tas,
            pr=pr,
            lat=lat,
            dc0=DC0,
            indexes=["DC"],
            season_method="LA08",
        )

    # Test output is complete + dask
    out = fire_weather_ufunc(
        tas=tas.chunk(),
        pr=pr.chunk(),
        lat=lat.chunk(),
        dc0=DC0,
        indexes=["DC"],
    )
    assert len(out.keys()) == 1
    out["DC"].load()

    out = fire_weather_ufunc(
        tas=tas,
        pr=pr,
        hurs=hurs,
        sfcWind=sfcWind,
        lat=lat,
        snd=snd,
        dc0=DC0,
        dmc0=DMC0,
        ffmc0=FFMC0,
        indexes=["DSR"],
    )

    assert len(out.keys()) == 7
Example #5
0
def drought_code(
    tas: xarray.DataArray,
    pr: xarray.DataArray,
    lat: xarray.DataArray,
    snd: xarray.DataArray = None,
    dc0: xarray.DataArray = None,
    start_date: str = None,
    start_up_mode: str = None,
    shut_down_mode: str = "snow_depth",
    **params,
):
    r"""The daily drought code (FWI component)

    The drought code is part of the Canadian Forest Fire Weather Index System.
    It is a numeric rating of the average moisture content of organic layers.

    Parameters
    ----------
    tas : xarray.DataArray
      Noon temperature.
    pr : xarray.DataArray
      Rain fall in open over previous 24 hours, at noon.
    lat : xarray.DataArray
      Latitude coordinate
    snd : xarray.DataArray
      Noon snow depth.
    dc0 : xarray.DataArray
      Initial values of the drought code.
    start_date : str, datetime.datetime
      Date at which to start the computation, dc0/dmc0/ffcm0 should be given at the day before.
    start_up_mode : {None, "snow_depth"}
      How to compute start up. Mode "snow_depth" requires the additional "snd" array. See the FWI submodule doc for valid values.
    shut_down_mode : {"temperature", "snow_depth"}
      How to compute shut down. Mode "snow_depth" requires the additional "snd" array. See the FWI submodule doc for valid values.
    params :
      Any other keyword parameters as defined in `xclim.indices.fwi.fire_weather_ufunc`.

    Returns
    -------
    Drought code [-]

    Notes
    -----
    See https://cwfis.cfs.nrcan.gc.ca/background/dsm/fwi

    References
    ----------
    Y. Wang, K.R. Anderson, and R.M. Suddaby, INFORMATION REPORT NOR-X-424, 2015.
    """
    tas = convert_units_to(tas, "C")
    pr = convert_units_to(pr, "mm/day")
    if snd is not None:
        snd = convert_units_to(snd, "m")

    if dc0 is None:
        dc0 = xarray.full_like(tas.isel(time=0), np.nan)

    params["start_date"] = start_date
    params["start_up_mode"] = start_up_mode

    out = fwi.fire_weather_ufunc(tas=tas,
                                 pr=pr,
                                 lat=lat,
                                 dc0=dc0,
                                 snd=snd,
                                 indexes=["DC"],
                                 **params)
    return out["DC"]
Example #6
0
def fire_weather_indexes(
    tas: xarray.DataArray,
    pr: xarray.DataArray,
    ws: xarray.DataArray,
    rh: xarray.DataArray,
    lat: xarray.DataArray,
    snd: xarray.DataArray = None,
    ffmc0: xarray.DataArray = None,
    dmc0: xarray.DataArray = None,
    dc0: xarray.DataArray = None,
    start_date: str = None,
    **params,
):
    r"""Return the six daily fire weather indexes.

    Computes the 6 fire weather indexes as defined by the Canadian Forest Service:
    the Drought Code, the Duff-Moisture Code, the Fine Fuel Moisture Code,
    the Initial Spread Index, the Build Up Index and the Fire Weather Index.

    Parameters
    ----------
    tas : xarray.DataArray
      Noon temperature.
    pr : xarray.DataArray
      Rain fall in open over previous 24 hours, at noon.
    ws : xarray.DataArray
      Noon wind speed.
    rh : xarray.DataArray
      Noon relative humidity.
    lat : xarray.DataArray
      Latitude coordinate
    snd : xarray.DataArray
      Noon snow depth.
    ffmc0 : xarray.DataArray
      Initial values of the fine fuel moisture code.
    dmc0 : xarray.DataArray
      Initial values of the Duff moisture code.
    dc0 : xarray.DataArray
      Initial values of the drought code.
    start_date : str, datetime.datetime
      Date at which to start the computation, dc0/dmc0/ffcm0 should be given at the day before.
    params :
        Any other keyword parameters as defined in `xclim.indices.fwi.fire_weather_ufunc`.

    Returns
    -------
    DC, DMC, FFMC, ISI, BUI, FWI

    Notes
    -----
    See https://cwfis.cfs.nrcan.gc.ca/background/dsm/fwi

    References
    ----------
    Y. Wang, K.R. Anderson, and R.M. Suddaby, INFORMATION REPORT NOR-X-424, 2015.
    """
    tas = convert_units_to(tas, "C")
    pr = convert_units_to(pr, "mm/day")
    ws = convert_units_to(ws, "km/h")
    rh = convert_units_to(rh, "pct")
    if snd is not None:
        snd = convert_units_to(snd, "m")

    if dc0 is None:
        dc0 = xarray.full_like(tas.isel(time=0), np.nan)
    if dmc0 is None:
        dmc0 = xarray.full_like(tas.isel(time=0), np.nan)
    if ffmc0 is None:
        ffmc0 = xarray.full_like(tas.isel(time=0), np.nan)

    params["start_date"] = start_date

    out = fwi.fire_weather_ufunc(
        tas=tas,
        pr=pr,
        rh=rh,
        ws=ws,
        lat=lat,
        dc0=dc0,
        dmc0=dmc0,
        ffmc0=ffmc0,
        snd=snd,
        indices=["DC", "DMC", "FFMC", "ISI", "BUI", "FWI"],
        **params,
    )
    return out["DC"], out["DMC"], out["FFMC"], out["ISI"], out["BUI"], out[
        "FWI"]