Skip to content

Commit a4876fb

Browse files
committed
fix: new function > add_max_intensities_to_events
1 parent 195bf70 commit a4876fb

File tree

3 files changed

+69
-23
lines changed

3 files changed

+69
-23
lines changed

idf_analysis/event_series_analysis.py

Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,7 @@ def partial_series(rolling_sum_values, measurement_period):
9090

9191

9292
def _lin_regress2(x, y):
93+
# based on math - custom function
9394
sample_size = len(x)
9495
x_mean = np.mean(x)
9596
y_mean = np.mean(y)
@@ -102,6 +103,7 @@ def _lin_regress2(x, y):
102103

103104

104105
def _lin_regress(x, y):
106+
# using scipy
105107
res = linregress(x, y)
106108
return {PARAM.U: res.intercept, PARAM.W: res.slope}
107109

@@ -128,42 +130,27 @@ def _improve_factor(interval):
128130
list(improve_factor.values()))
129131

130132

131-
def calculate_u_w(file_input, duration_steps, series_kind):
133+
def iter_event_series(file_input, duration_steps):
132134
"""
133135
Statistical analysis for each duration step.
134136
135137
acc. to DWA-A 531 chap. 5.1
136138
137139
Save the parameters of the distribution function as interim results.
138140
139-
acc. to DWA-A 531 chap. 4.4: use the annual series only for measurement periods over 20 years
140-
141-
142141
Args:
143142
file_input (pandas.Series): precipitation data
144143
duration_steps (list[int] | numpy.ndarray): in minutes
145-
series_kind (str): 'annual' or 'partial'
146144
147-
Returns:
148-
dict[int, dict]: with key=durations and values=dict(u, w)
145+
Yields:
146+
series: max rainfall intensity per event for each duration step
149147
"""
150148
ts = file_input.copy()
151-
# -------------------------------
152-
# measuring time in years
153-
measurement_start, measurement_end = ts.index[[0, -1]]
154-
measurement_period = (measurement_end - measurement_start) / year_delta(years=1)
155-
if round(measurement_period, 1) < 10:
156-
warnings.warn("The measurement period is too short. The results may be inaccurate! "
157-
"It is recommended to use at least ten years. "
158-
"(-> Currently {}a used)".format(measurement_period))
159149

160150
# -------------------------------
161151
base_frequency = guess_freq(ts.index) # DateOffset/Timedelta
162152

163153
# ------------------------------------------------------------------------------------------------------------------
164-
interim_results = {}
165-
166-
# -------------------------------
167154
# acc. to DWA-A 531 chap. 4.2:
168155
# The values must be independent of each other for the statistical evaluations.
169156
# estimated four hours acc. (Schilling, 1984)
@@ -202,11 +189,47 @@ def calculate_u_w(file_input, duration_steps, series_kind):
202189

203190
roll_sum = ts.rolling(duration).sum()
204191

192+
year_index = events[COL.START].dt.year.values
193+
205194
# events[COL.rolling_sum_valuesAX_OVERLAPPING_SUM] = agg_events(events, roll_sum, 'max') * improve
206-
rolling_sum_values = agg_events(events, roll_sum, 'max') * improve
195+
yield agg_events(events, roll_sum, 'max') * improve, duration_integer, year_index
196+
197+
198+
def calculate_u_w(file_input, duration_steps, series_kind):
199+
"""
200+
Statistical analysis for each duration step.
201+
202+
acc. to DWA-A 531 chap. 5.1
203+
204+
Save the parameters of the distribution function as interim results.
205+
206+
acc. to DWA-A 531 chap. 4.4: use the annual series only for measurement periods over 20 years
207+
208+
209+
Args:
210+
file_input (pandas.Series): precipitation data
211+
duration_steps (list[int] | numpy.ndarray): in minutes
212+
series_kind (str): 'annual' or 'partial'
213+
214+
Returns:
215+
dict[int, dict]: with key=durations and values=dict(u, w)
216+
"""
217+
# -------------------------------
218+
# measuring time in years
219+
measurement_start, measurement_end = file_input.index[[0, -1]]
220+
measurement_period = (measurement_end - measurement_start) / year_delta(years=1)
221+
if round(measurement_period, 1) < 10:
222+
warnings.warn("The measurement period is too short. The results may be inaccurate! "
223+
"It is recommended to use at least ten years. "
224+
"(-> Currently {}a used)".format(measurement_period))
225+
226+
# -------------------------------
227+
interim_results = {}
228+
229+
for rolling_sum_values, duration_integer, year_index in iter_event_series(file_input, duration_steps):
207230

208231
if series_kind == SERIES.ANNUAL:
209-
interim_results[duration_integer] = annual_series(rolling_sum_values, events[COL.START].dt.year.values)
232+
interim_results[duration_integer] = annual_series(rolling_sum_values, year_index)
210233
elif series_kind == SERIES.PARTIAL:
211234
interim_results[duration_integer] = partial_series(rolling_sum_values, measurement_period)
212235
else:

idf_analysis/idf_backend.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
from pathlib import Path
1313

1414
from .definitions import *
15-
from .event_series_analysis import calculate_u_w
15+
from .event_series_analysis import calculate_u_w, iter_event_series
1616
from .in_out import write_yaml, read_yaml
1717
from .parameter_formulation_class import FORMULATION_REGISTER, _Formulation, register_formulations_to_yaml
1818

@@ -39,6 +39,13 @@ def calc_from_series(self, series):
3939
self.parameters_series[p] = np.array([d[p] for d in u_w.values()])
4040
self._calc_params()
4141

42+
# def get_event_max_series(self, series): # TODO
43+
# interim_results = {}
44+
#
45+
# for rolling_sum_values, duration_integer, _ in iter_event_series(series, self.durations):
46+
# interim_results[duration_integer] = rolling_sum_values
47+
# return interim_results
48+
4249
def reverse_engineering(self, idf_table, linear_interpolation=False):
4350
durations = idf_table.index.values
4451
u = idf_table[1].values

idf_analysis/idf_class.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,7 @@ def result_table(self, durations=None, return_periods=None, add_names=False):
326326

327327
####################################################################################################################
328328
def result_figure(self, min_duration=5.0, max_duration=720.0, logx=False, return_periods=None, color=True, ax=None,
329-
linestyle=None, add_interim=False):
329+
linestyle=None, add_interim=False, alpha=1):
330330
"""
331331
Create a plot with the idf-curves with duration on the x-axis and rainfall depth on the y-axis.
332332
@@ -340,6 +340,7 @@ def result_figure(self, min_duration=5.0, max_duration=720.0, logx=False, return
340340
ax (plt.Axes): Axes to plot on. Default = create new one.
341341
linestyle (str): Line-style for the plotted lines.
342342
add_interim (bool): Add interim results from the series analysis as scatter points.
343+
alpha (float): Alpha of the idf-lines in the plot.
343344
344345
Returns:
345346
(plt.Figure, plt.Axes): figure and axes of the plot.
@@ -352,7 +353,7 @@ def result_figure(self, min_duration=5.0, max_duration=720.0, logx=False, return
352353
table = self.result_table(durations=duration_steps, return_periods=return_periods)
353354
if color:
354355
table.columns.name = 'T$\\mathsf{_N}$ in a'
355-
ax = table.plot(color=(None if color else 'black'), logx=logx, legend=color, ax=ax, ls=linestyle)
356+
ax = table.plot(color=(None if color else 'black'), logx=logx, legend=color, ax=ax, ls=linestyle, alpha=alpha)
356357

357358
for _, return_time in enumerate(return_periods):
358359
if add_interim:
@@ -633,6 +634,21 @@ def add_max_return_periods_to_events(self, events):
633634

634635
events[COL.MAX_PERIOD_DURATION] = return_periods_frame.loc[datetime_max].idxmax(axis=1, skipna=True).values
635636

637+
def add_max_intensities_to_events(self, events):
638+
"""
639+
Add the maximum intensities for all duration steps to the events table.
640+
641+
Args:
642+
events (pandas.DataFrame): events table
643+
644+
Returns:
645+
pandas.DataFrame: events table including the columns with the maximum intensities
646+
"""
647+
sum_frame = self.rainfall_sum_frame
648+
for duration in self.duration_steps:
649+
events[f'max_sum_{duration:0.0f}'] = agg_events(events, sum_frame[duration], 'max').round(2)
650+
return events
651+
636652
####################################################################################################################
637653
def event_report(self, filename, min_event_rain_sum=25, min_return_period=0.5, durations=None):
638654
"""

0 commit comments

Comments
 (0)