Skip to content

Commit c65d6c1

Browse files
committed
correct pylint. add select function. rename compute_stats and make it public. use classmethod for read_one.
1 parent 1b025fd commit c65d6c1

File tree

2 files changed

+246
-92
lines changed

2 files changed

+246
-92
lines changed

climada/hazard/base.py

Lines changed: 122 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,19 @@
99
import copy
1010
import logging
1111
import datetime as dt
12+
import itertools
13+
import warnings
1214
import numpy as np
1315
from scipy import sparse
16+
from pathos.multiprocessing import ProcessingPool as Pool
1417

1518
from climada.hazard.tag import Tag as TagHazard
1619
from climada.hazard.centroids.base import Centroids
1720
from climada.hazard.source import READ_SET
1821
from climada.util.files_handler import to_list, get_file_names
19-
import climada.util.plot as plot
22+
import climada.util.plot as u_plot
2023
import climada.util.checker as check
24+
import climada.util.dates_times as u_dt
2125

2226
LOGGER = logging.getLogger(__name__)
2327

@@ -27,7 +31,7 @@
2731
}
2832
""" Supported files format to read from """
2933

30-
class Hazard(object):
34+
class Hazard():
3135
"""Contains events of some hazard type defined at centroids. Loads from
3236
files with format defined in FILE_EXT.
3337
@@ -107,7 +111,19 @@ def __init__(self, haz_type='NA', file_name='', description='', \
107111
>>> centr = Centroids(HAZ_DEMO_MAT, 'Centroids demo')
108112
>>> haz = Hazard('TC', HAZ_DEMO_MAT, 'Demo hazard.', centr)
109113
"""
110-
self.clear()
114+
self.tag = TagHazard()
115+
self.units = 'NA'
116+
self.centroids = Centroids()
117+
# following values are defined for each event
118+
self.event_id = np.array([], int)
119+
self.frequency = np.array([], float)
120+
self.event_name = list()
121+
self.date = np.array([], int)
122+
self.orig = np.array([], bool)
123+
# following values are defined for each event and centroid
124+
self.intensity = sparse.csr_matrix(np.empty((0, 0))) # events x centroids
125+
self.fraction = sparse.csr_matrix(np.empty((0, 0))) # events x centroids
126+
111127
if '.' in haz_type and file_name == '':
112128
LOGGER.error("Provide hazard type.")
113129
raise ValueError
@@ -121,16 +137,14 @@ def clear(self):
121137
"""Reinitialize attributes."""
122138
self.tag = TagHazard()
123139
self.units = 'NA'
124-
# following values are defined for each event
125140
self.centroids = Centroids()
126-
self.event_id = np.array([], int)
127-
self.frequency = np.array([])
128-
self.event_name = list()
129-
self.date = np.array([], int)
130-
self.orig = np.array([], bool)
131-
# following values are defined for each event and centroid
132-
self.intensity = sparse.csr_matrix(np.empty((0, 0))) # events x centroids
133-
self.fraction = sparse.csr_matrix(np.empty((0, 0))) # events x centroids
141+
for (var_name, var_val) in self.__dict__.items():
142+
if isinstance(var_val, np.ndarray) and var_val.ndim == 1:
143+
setattr(self, var_name, np.array([]))
144+
elif isinstance(var_val, sparse.csr_matrix):
145+
setattr(self, var_name, sparse.csr_matrix(np.empty((0, 0))))
146+
elif isinstance(var_val, list):
147+
setattr(self, var_name, list())
134148

135149
def check(self):
136150
"""Check if the attributes contain consistent data.
@@ -167,27 +181,93 @@ def read(self, files, description='', centroids=None, var_names=None):
167181
var_list):
168182
self.append(self._read_one(file, haz_type, desc, centr, var))
169183

170-
def plot_rp_intensity(self, return_periods=(25, 50, 100, 250), orig=False,
171-
**kwargs):
172-
"""Compute and plot hazard intensity maps for different return periods.
184+
def select(self, date=None, orig=None):
185+
"""Select events within provided date and/or historical or synthetical.
186+
Frequency of the events may need to be recomputed!
187+
188+
Parameters:
189+
date (tuple(str or int), optional): (initial date, final date) in
190+
string ISO format or datetime ordinal integer
191+
orig (bool, optional): select only historical (True) or only
192+
synthetic (False)
193+
194+
Returns:
195+
Hazard or children
196+
"""
197+
haz = self.__class__()
198+
sel_idx = np.ones(self.event_id.size, bool)
199+
200+
if isinstance(date, tuple):
201+
date_ini, date_end = date[0], date[1]
202+
if isinstance(date_ini, str):
203+
date_ini = u_dt.str_to_date(date[0])
204+
date_end = u_dt.str_to_date(date[1])
205+
206+
sel_idx = np.logical_and(date_ini <= self.date,
207+
self.date <= date_end)
208+
if not np.any(sel_idx):
209+
LOGGER.info('No hazard in date range %s.', date)
210+
return None
211+
212+
if isinstance(orig, bool):
213+
sel_idx = np.logical_and(sel_idx, self.orig.astype(bool) == orig)
214+
if not np.any(sel_idx):
215+
LOGGER.info('No hazard with %s tracks.', str(orig))
216+
return None
217+
218+
sel_idx = np.argwhere(sel_idx).squeeze()
219+
for (var_name, var_val) in self.__dict__.items():
220+
if isinstance(var_val, np.ndarray) and var_val.ndim == 1:
221+
setattr(haz, var_name, var_val[sel_idx])
222+
elif isinstance(var_val, sparse.csr_matrix):
223+
setattr(haz, var_name, var_val[sel_idx, :])
224+
elif isinstance(var_val, list):
225+
setattr(haz, var_name, [var_val[idx] for idx in sel_idx])
226+
else:
227+
setattr(haz, var_name, var_val)
228+
229+
return haz
230+
231+
def local_exceedance_inten(self, return_periods=(25, 50, 100, 250)):
232+
""" Compute exceedance intensity map for given return periods.
233+
234+
Parameters:
235+
return_periods (np.array): return periods to consider
236+
237+
Returns:
238+
np.array
239+
"""
240+
LOGGER.info('Computing exceedance intenstiy map for return periods: %s',
241+
return_periods)
242+
cen_pos = range(self.intensity.shape[1])
243+
inten_stats = np.zeros((len(return_periods), len(cen_pos)))
244+
chunksize = min(len(cen_pos), 1000)
245+
for cen_idx, inten_loc in enumerate(Pool().map(self._loc_return_inten,\
246+
itertools.repeat(return_periods, len(cen_pos)), cen_pos, \
247+
chunksize=chunksize)):
248+
inten_stats[:, cen_idx] = inten_loc
249+
return inten_stats
250+
251+
def plot_rp_intensity(self, return_periods=(25, 50, 100, 250), **kwargs):
252+
"""Compute and plot hazard exceedance intensity maps for different
253+
return periods. Calls local_exceedance_inten.
173254
174255
Parameters:
175256
return_periods (tuple(int), optional): return periods to consider
176-
orig (bool, optional): if true, only historical events considered
177257
kwargs (optional): arguments for pcolormesh matplotlib function
178258
used in event plots
179259
180260
Returns:
181261
matplotlib.figure.Figure, matplotlib.axes._subplots.AxesSubplot,
182262
np.ndarray (return_periods.size x num_centroids)
183263
"""
184-
inten_stats = self._compute_stats(np.array(return_periods), orig)
264+
inten_stats = self.local_exceedance_inten(np.array(return_periods))
185265
colbar_name = 'Wind intensity (' + self.units + ')'
186266
title = list()
187267
for ret in return_periods:
188268
title.append('Return period: ' + str(ret) + ' years')
189-
fig, axis = plot.geo_im_from_array(inten_stats, self.centroids.coord, \
190-
colbar_name, title, **kwargs)
269+
fig, axis = u_plot.geo_im_from_array(inten_stats, self.centroids.coord,
270+
colbar_name, title, **kwargs)
191271
return fig, axis, inten_stats
192272

193273
def plot_intensity(self, event=None, centr=None, **kwargs):
@@ -218,7 +298,7 @@ def plot_intensity(self, event=None, centr=None, **kwargs):
218298
if isinstance(event, str):
219299
event = self.get_event_id(event)
220300
return self._event_plot(event, self.intensity, col_label, **kwargs)
221-
elif centr is not None:
301+
if centr is not None:
222302
if isinstance(centr, tuple):
223303
centr = self.centroids.get_nearest_id(centr[0], centr[1])
224304
return self._centr_plot(centr, self.intensity, col_label)
@@ -254,7 +334,7 @@ def plot_fraction(self, event=None, centr=None, **kwargs):
254334
if isinstance(event, str):
255335
event = self.get_event_id(event)
256336
return self._event_plot(event, self.fraction, col_label, **kwargs)
257-
elif centr is not None:
337+
if centr is not None:
258338
if isinstance(centr, tuple):
259339
centr = self.centroids.get_nearest_id(centr[0], centr[1])
260340
return self._centr_plot(centr, self.fraction, col_label)
@@ -283,7 +363,7 @@ def get_event_name(self, event_id):
283363
""""Get the name of an event id.
284364
285365
Parameters:
286-
event_id (id): id of the event
366+
event_id (int): id of the event
287367
288368
Returns:
289369
str
@@ -309,15 +389,15 @@ def get_event_date(self, event=None):
309389
list(str)
310390
"""
311391
if event is None:
312-
l_dates = [self._date_to_str(date) for date in self.date]
392+
l_dates = [u_dt.date_to_str(date) for date in self.date]
313393
elif isinstance(event, str):
314394
ev_ids = self.get_event_id(event)
315-
l_dates = [self._date_to_str(self.date[ \
395+
l_dates = [u_dt.date_to_str(self.date[ \
316396
np.argwhere(self.event_id == ev_id)[0][0]]) \
317397
for ev_id in ev_ids]
318398
else:
319399
ev_idx = np.argwhere(self.event_id == event)[0][0]
320-
l_dates = [self._date_to_str(self.date[ev_idx])]
400+
l_dates = [u_dt.date_to_str(self.date[ev_idx])]
321401
return l_dates
322402

323403
def calc_year_set(self):
@@ -357,8 +437,8 @@ def append(self, hazard):
357437
elif hazard.units == 'NA':
358438
LOGGER.info("Appended hazard does not have units.")
359439
elif self.units != hazard.units:
360-
LOGGER.error("Hazards with different units can't be appended"\
361-
+ ": %s != %s.", self.units, hazard.units)
440+
LOGGER.error("Hazards with different units can't be appended: "
441+
"%s != %s.", self.units, hazard.units)
362442
raise ValueError
363443

364444
self.tag.append(hazard.tag)
@@ -483,13 +563,8 @@ def _append_haz_cent(self, centroids):
483563
cen_self = cen_self_sort[cen_self]
484564
return cen_self, cen_haz
485565

486-
@staticmethod
487-
def _date_to_str(date):
488-
""" Compute date string from input datetime ordinal int. """
489-
return dt.date.fromordinal(date).isoformat()
490-
491-
@staticmethod
492-
def _read_one(file_name, haz_type, description='', centroids=None, \
566+
@classmethod
567+
def _read_one(cls, file_name, haz_type, description='', centroids=None, \
493568
var_names=None):
494569
""" Read hazard, and centroids if not provided, from input file.
495570
@@ -504,10 +579,10 @@ def _read_one(file_name, haz_type, description='', centroids=None, \
504579
ValueError, KeyError
505580
506581
Returns:
507-
Hazard
582+
Hazard or children
508583
"""
509584
LOGGER.info('Reading file: %s', file_name)
510-
new_haz = Hazard()
585+
new_haz = cls()
511586
new_haz.tag = TagHazard(haz_type, file_name, description)
512587

513588
extension = os.path.splitext(file_name)[1]
@@ -597,8 +672,8 @@ def _event_plot(self, event_id, mat_var, col_name, **kwargs):
597672
array_val.append(im_val)
598673
l_title.append(title)
599674

600-
return plot.geo_im_from_array(array_val, self.centroids.coord,
601-
col_name, l_title, **kwargs)
675+
return u_plot.geo_im_from_array(array_val, self.centroids.coord,
676+
col_name, l_title, **kwargs)
602677

603678
def _centr_plot(self, centr_id, mat_var, col_name):
604679
""""Plot a centroid of the input matrix.
@@ -639,51 +714,27 @@ def _centr_plot(self, centr_id, mat_var, col_name):
639714
array_val = np.max(mat_var, axis=1).todense()
640715
title = '%s max intensity at each event' % self.tag.haz_type
641716

642-
graph = plot.Graph2D(title)
717+
graph = u_plot.Graph2D(title)
643718
graph.add_subplot('Event number', col_name)
644719
graph.add_curve(range(len(array_val)), array_val, 'b')
645720
graph.set_x_lim(range(len(array_val)))
646721
return graph.get_elems()
647722

648-
def _compute_stats(self, return_periods, orig=False):
649-
""" Compute intensity map for given return periods.
650-
651-
Parameters:
652-
return_periods (np.array): return periods to consider
653-
orig (bool, optional): if true, only historical events considered
654-
655-
Returns:
656-
np.array
657-
"""
658-
inten_stats = np.zeros((len(return_periods), self.intensity.shape[1]))
659-
inten = self.intensity
660-
freq = self.frequency
661-
if orig:
662-
inten = inten[self.orig, :]
663-
freq = freq[self.orig] * self.event_id.size / \
664-
self.orig.nonzero()[0].size
665-
for cen_pos in range(self.intensity.shape[1]):
666-
inten_loc = self._loc_return_inten(return_periods, cen_pos,
667-
inten, freq)
668-
inten_stats[:, cen_pos] = inten_loc
669-
return inten_stats
670-
671-
def _loc_return_inten(self, return_periods, cen_pos, inten, freq):
723+
def _loc_return_inten(self, return_periods, cen_pos):
672724
""" Compute local exceedence intensity for given return period.
673725
674726
Parameters:
675727
return_periods (np.array): return periods to consider
676728
cen_pos (int): centroid position
677-
inten (sparse.csr_matrix): intensity of the events at centroids
678-
freq (np.array): events frequncy
679729
Returns:
680730
np.array
681731
"""
682-
inten_pos = np.argwhere(inten[:, cen_pos] >
732+
inten_pos = np.argwhere(self.intensity[:, cen_pos] >
683733
self.intensity_thres)[:, 0]
684734
if inten_pos.size == 0:
685735
return np.zeros((return_periods.size, ))
686-
inten_nz = np.asarray(inten[inten_pos, cen_pos].todense()).squeeze()
736+
inten_nz = np.asarray(self.intensity[inten_pos, cen_pos].todense()). \
737+
squeeze()
687738
sort_pos = inten_nz.argsort()[::-1]
688739
try:
689740
inten_sort = inten_nz[sort_pos]
@@ -692,10 +743,12 @@ def _loc_return_inten(self, return_periods, cen_pos, inten, freq):
692743
inten_sort = np.array([inten_nz])
693744
else:
694745
raise err
695-
freq_sort = freq[inten_pos[sort_pos]]
746+
freq_sort = self.frequency[inten_pos[sort_pos]]
696747
np.cumsum(freq_sort, out=freq_sort)
697748
try:
698-
pol_coef = np.polyfit(np.log(freq_sort), inten_sort, deg=1)
749+
with warnings.catch_warnings():
750+
warnings.simplefilter("ignore")
751+
pol_coef = np.polyfit(np.log(freq_sort), inten_sort, deg=1)
699752
except ValueError:
700753
pol_coef = np.polyfit(np.log(freq_sort), inten_sort, deg=0)
701754
inten_fit = np.polyval(pol_coef, np.log(1/return_periods))

0 commit comments

Comments
 (0)