Skip to content

Commit 78b6d3f

Browse files
committed
chunked _loc_return_inten
1 parent b45a1c0 commit 78b6d3f

File tree

2 files changed

+61
-32
lines changed

2 files changed

+61
-32
lines changed

climada/hazard/base.py

Lines changed: 60 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,9 @@
99
import copy
1010
import logging
1111
import datetime as dt
12-
import itertools
1312
import warnings
1413
import numpy as np
1514
from scipy import sparse
16-
from pathos.multiprocessing import ProcessingPool as Pool
1715

1816
from climada.hazard.tag import Tag as TagHazard
1917
from climada.hazard.centroids.base import Centroids
@@ -22,6 +20,7 @@
2220
import climada.util.plot as u_plot
2321
import climada.util.checker as check
2422
import climada.util.dates_times as u_dt
23+
from climada.util.config import CONFIG
2524

2625
LOGGER = logging.getLogger(__name__)
2726

@@ -237,13 +236,23 @@ def local_exceedance_inten(self, return_periods=(25, 50, 100, 250)):
237236
"""
238237
LOGGER.info('Computing exceedance intenstiy map for return periods: %s',
239238
return_periods)
240-
cen_pos = range(self.intensity.shape[1])
241-
inten_stats = np.zeros((len(return_periods), len(cen_pos)))
242-
chunksize = min(len(cen_pos), 1000)
243-
for cen_idx, inten_loc in enumerate(Pool().map(self._loc_return_inten,\
244-
itertools.repeat(np.array(return_periods), len(cen_pos)), cen_pos,\
245-
chunksize=chunksize)):
246-
inten_stats[:, cen_idx] = inten_loc
239+
num_cen = self.intensity.shape[1]
240+
inten_stats = np.zeros((len(return_periods), num_cen))
241+
cen_step = int(CONFIG['impact']['max_matrix_size']/self.intensity.shape[0])
242+
if not cen_step:
243+
LOGGER.error('Increase max_matrix_size configuration parameter to'\
244+
' > %s', str(self.intensity.shape[0]))
245+
raise ValueError
246+
# separte in chunks
247+
chk = -1
248+
for chk in range(int(num_cen/cen_step)):
249+
self._loc_return_inten(np.array(return_periods), \
250+
self.intensity[:, chk*cen_step:(chk+1)*cen_step].todense(), \
251+
inten_stats[:, chk*cen_step:(chk+1)*cen_step])
252+
self._loc_return_inten(np.array(return_periods), \
253+
self.intensity[:, (chk+1)*cen_step:].todense(), \
254+
inten_stats[:, (chk+1)*cen_step:])
255+
247256
return inten_stats
248257

249258
def plot_rp_intensity(self, return_periods=(25, 50, 100, 250), **kwargs):
@@ -725,41 +734,61 @@ def _centr_plot(self, centr_id, mat_var, col_name):
725734
graph.set_x_lim(range(len(array_val)))
726735
return graph.get_elems()
727736

728-
def _loc_return_inten(self, return_periods, cen_pos):
737+
def _loc_return_inten(self, return_periods, inten, exc_inten):
729738
""" Compute local exceedence intensity for given return period.
730739
731740
Parameters:
732741
return_periods (np.array): return periods to consider
733742
cen_pos (int): centroid position
743+
734744
Returns:
735745
np.array
736746
"""
737-
inten_pos = np.argwhere(self.intensity[:, cen_pos] >
738-
self.intensity_thres)[:, 0]
739-
if inten_pos.size == 0:
740-
return np.zeros((return_periods.size, ))
741-
inten_nz = np.asarray(self.intensity[inten_pos, cen_pos].todense()). \
742-
squeeze()
743-
sort_pos = inten_nz.argsort()[::-1]
744-
try:
745-
inten_sort = inten_nz[sort_pos]
746-
except IndexError as err:
747-
if inten_nz.shape == () and inten_nz.size == 1:
748-
inten_sort = np.array([inten_nz])
749-
else:
750-
raise err
751-
freq_sort = self.frequency[inten_pos[sort_pos]]
752-
np.cumsum(freq_sort, out=freq_sort)
747+
# sorted intensity
748+
sort_pos = np.argsort(inten, axis=0)[::-1, :]
749+
columns = np.ones(inten.shape, int)
750+
columns *= np.arange(columns.shape[1])
751+
inten_sort = inten[sort_pos, columns]
752+
# cummulative frequency at sorted intensity
753+
freq_sort = self.frequency[sort_pos]
754+
np.cumsum(freq_sort, axis=0, out=freq_sort)
755+
756+
for cen_idx in range(inten.shape[1]):
757+
exc_inten[:, cen_idx] = self._cen_return_inten(
758+
inten_sort[:, cen_idx], freq_sort[:, cen_idx],
759+
self.intensity_thres, return_periods)
760+
761+
@staticmethod
762+
def _cen_return_inten(inten, freq, inten_th, return_periods):
763+
"""From ordered intensity and cummulative frequency at centroid, get
764+
exceedance intensity at input return periods.
765+
766+
Parameters:
767+
inten (np.array): sorted intensity at centroid
768+
freq (np.array): cummulative frequency at centroid
769+
inten_th (float): intensity threshold
770+
return_periods (np.array): return periods
771+
772+
Returns:
773+
np.array
774+
"""
775+
inten_th = np.asarray(inten > inten_th).squeeze()
776+
inten_cen = inten[inten_th]
777+
freq_cen = freq[inten_th]
778+
if not inten_cen.size:
779+
return np.zeros((return_periods.size,))
753780
try:
754781
with warnings.catch_warnings():
755782
warnings.simplefilter("ignore")
756-
pol_coef = np.polyfit(np.log(freq_sort), inten_sort, deg=1)
783+
pol_coef = np.polyfit(np.log(freq_cen), inten_cen, deg=1)
757784
except ValueError:
758-
pol_coef = np.polyfit(np.log(freq_sort), inten_sort, deg=0)
785+
pol_coef = np.polyfit(np.log(freq_cen), inten_cen, deg=0)
759786
inten_fit = np.polyval(pol_coef, np.log(1/return_periods))
760-
wrong_inten = np.logical_and(return_periods > np.max(1/freq_sort), \
761-
np.isnan(inten_fit))
762-
return inten_fit[np.logical_not(wrong_inten)]
787+
wrong_inten = np.logical_and(return_periods > np.max(1/freq_cen), \
788+
np.isnan(inten_fit))
789+
inten_fit[wrong_inten] = 0.
790+
791+
return inten_fit
763792

764793
def __str__(self):
765794
return self.tag.__str__()

climada/hazard/test/test_base.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -807,7 +807,7 @@ def test_degenerate_pass(self):
807807
""" Test degenerate call. """
808808
haz = Hazard('TC', HAZ_TEST_MAT)
809809
return_period = np.array([25, 50, 100, 250])
810-
haz.intensity = np.zeros(haz.intensity.shape)
810+
haz.intensity = sparse.csr.csr_matrix(np.zeros(haz.intensity.shape))
811811
inten_stats = haz.local_exceedance_inten(return_period)
812812
self.assertTrue(np.array_equal(inten_stats, np.zeros((4, 100))))
813813

0 commit comments

Comments
 (0)