Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 54 additions & 0 deletions pepsico/app_calc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import xarray as xr
import operator as op


#This is what we should need for the app
Expand Down Expand Up @@ -143,3 +144,56 @@ def strftimeb2int(strftimeb):
}
strftimebint = strftimeb_all[strftimeb]
return strftimebint


def number_extreme_events_within_days(
daily_data, operator, threshold, window, dim="T"
):
"""Count extreme events

Extreme events constitute cumulative `daily_data` over `window` -day
(or shorther) verifying the `operator` `threshold`

Parameters
----------
daily_data : DataArray
Array of daily data
operator : str
"lt", "le", "gt", "ge"
determines the condition to meet with respect to `threshold`
threshold : float
threshold to meet in `daily_data` units
window : int
maximum length of days to cumulate over to constitute an event
dim : str, optional
name of `daily_data` time dimension

Returns
-------
DataArray
Array of count of extreme events

Notes
-----
Is meant to be used to produce yearly seasonal time series

Examples
--------
Number of rain events of >80mm in 2 days or less:
number_extreme_events_within_days(rain_daily_data_in_mm, "gt", 80, 2)
"""
count = 0
#Start with shortest events
for w in range(1, window+1):
for t in range(len(daily_data[dim])-(w-1)):
#Assert new event
new_event = getattr(op, operator)(
daily_data.isel({dim: slice(t, t+w)}).sum(dim), threshold
)
#Mask days having formed a new event so that they won't account again
#for following events (t loop) or longer events (w loop)
daily_data[{dim: slice(t, t+w)}] = (
daily_data[{dim: slice(t, t+w)}].where(~new_event)
)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just to confirm that I understood the method... this means that, for example, if the threshold is 100 mm over 3 days and I reach that accumulation on days [1st, 2nd, 3rd] (which would be detected as an extreme), and assuming the event continues, then the next extreme should be detected on [4th, 5th, 6th] instead of [2nd, 3rd, 4th]?

If above is correct, how is [2nd, 3rd, 4th] classified — which also has 100 mm in 3 days but isn't detected because days 2 and 3 are masked? Would this be considered a 'false extreme alert' and therefore discarded?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's correct, [2nd, 3rd, 4th] is not an extreme event because [1st, 2nd, 3rd]. Similarly, if all the rain fell in 1st, then [1st, 2nd, 3rd] is not an event, but [2nd, 3rd, 4th] could be. That's why I had to use loops rather than rolling or something alike.

count = count + new_event
return count
14 changes: 14 additions & 0 deletions pepsico/test/test_app_calc.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

import numpy as np
import pandas as pd
import xarray as xr
import app_calc

def test_number_extreme_events_within_days():
t = pd.date_range(start="2000-05-01", end="2000-05-10", freq="1D")
values = 1 + 0*np.arange(t.size)
precip = xr.DataArray(values, coords={"T": t})
count = app_calc.number_extreme_events_within_days(precip, "gt", 2, 3)

np.testing.assert_array_equal(count, [3])

Loading