|
14 | 14 |
|
15 | 15 | LOGGER = logging.getLogger(__name__) |
16 | 16 |
|
| 17 | +MAX_SIZE = 1.0e8 |
| 18 | +""" Maximum matrix size for impact caluculation. If the matrix is bigger, |
| 19 | +it is chunked.""" |
| 20 | + |
17 | 21 | class ImpactFreqCurve(object): |
18 | 22 | """ Impact exceedence frequency curve. |
19 | 23 |
|
@@ -166,79 +170,79 @@ def calc(self, exposures, impact_funcs, hazard): |
166 | 170 | # Get damage functions for this hazard |
167 | 171 | haz_imp = impact_funcs.get_func(haz_type) |
168 | 172 |
|
| 173 | + # Check if deductible and cover should be applied |
| 174 | + insure_flag = False |
| 175 | + if exposures.deductible.size and exposures.cover.size: |
| 176 | + insure_flag = True |
| 177 | + num_events = hazard.intensity.shape[0] |
169 | 178 | # 3. Loop over exposures according to their impact function |
170 | 179 | # Loop over impact functions |
171 | 180 | for imp_fun in haz_imp: |
| 181 | + self.imp_fun = imp_fun |
172 | 182 | # get indices of all the exposures with this impact function |
173 | 183 | exp_iimp = np.where(exposures.impact_id[exp_idx] == imp_fun.id)[0] |
| 184 | + exp_step = int(MAX_SIZE/num_events) |
| 185 | + # separte in chunks if too many exposures |
| 186 | + i = -1 |
| 187 | + for i in range(int(exp_iimp.size/exp_step)): |
| 188 | + self._exp_impact(exp_idx[exp_iimp[i*exp_step:(i+1)*exp_step]],\ |
| 189 | + exposures, hazard, imp_fun, insure_flag) |
| 190 | + self._exp_impact(exp_idx[exp_iimp[(i+1)*exp_step:]],\ |
| 191 | + exposures, hazard, imp_fun, insure_flag) |
174 | 192 |
|
175 | | - # loop over selected exposures |
176 | | - for iexp in exp_idx[exp_iimp]: |
177 | | - # compute impact on exposure |
178 | | - event_row, impact = self._one_exposure(iexp, exposures, \ |
179 | | - hazard, imp_fun) |
| 193 | + self.aai_agg = sum(self.at_event * hazard.frequency) |
180 | 194 |
|
181 | | - # add values to impact impact |
182 | | - self.at_event[event_row] += impact |
183 | | - self.eai_exp[iexp] += np.squeeze(sum(impact * hazard. \ |
184 | | - frequency[event_row])) |
185 | | - self.tot_value += exposures.value[iexp] |
| 195 | + def _exp_impact(self, exp_iimp, exposures, hazard, imp_fun, insure_flag): |
| 196 | + """Compute impact for inpute exposure indexes and impact function. |
186 | 197 |
|
187 | | - self.aai_agg = sum(self.at_event * hazard.frequency) |
| 198 | + Parameters: |
| 199 | + exp_iimp (np.array): exposures indexes |
| 200 | + exposures (Exposures): exposures instance |
| 201 | + hazard (Hazard): hazard instance |
| 202 | + imp_fun (ImpactFunc): impact function instance |
| 203 | + insure_flag (bool): consider deductible and cover of exposures |
| 204 | + """ |
| 205 | + # get assigned centroids |
| 206 | + icens = exposures.assigned[hazard.tag.haz_type][exp_iimp] |
| 207 | + |
| 208 | + # get affected intensities |
| 209 | + inten_val = hazard.intensity[:, icens].todense() |
| 210 | + # get affected fractions |
| 211 | + fract = hazard.fraction[:, icens] |
| 212 | + impact = fract.multiply(imp_fun.calc_mdr(inten_val)). \ |
| 213 | + multiply(exposures.value[exp_iimp]) |
| 214 | + |
| 215 | + if insure_flag and impact.nonzero()[0].size: |
| 216 | + paa = np.interp(inten_val, imp_fun.intensity, imp_fun.paa) |
| 217 | + impact = np.minimum(np.maximum(impact - \ |
| 218 | + exposures.deductible[exp_iimp] * paa, 0), \ |
| 219 | + exposures.cover[exp_iimp]) |
| 220 | + self.eai_exp[exp_iimp] += np.sum(np.asarray(impact) * \ |
| 221 | + hazard.frequency.reshape(-1, 1), axis=0) |
| 222 | + else: |
| 223 | + self.eai_exp[exp_iimp] += np.squeeze(np.asarray(np.sum( \ |
| 224 | + impact.multiply(hazard.frequency.reshape(-1, 1)), axis=0))) |
| 225 | + |
| 226 | + self.at_event += np.squeeze(np.asarray(np.sum(impact, axis=1))) |
| 227 | + self.tot_value += np.sum(exposures.value[exp_iimp]) |
188 | 228 |
|
189 | | - def plot_eai_exposure(self, ignore_null=True, **kwargs): |
| 229 | + def plot_eai_exposure(self, ignore_zero=True, **kwargs): |
190 | 230 | """Plot expected annual impact of each exposure. |
191 | 231 |
|
192 | 232 | Parameters: |
193 | | - ignore_null (bool): ignore zero impact values at exposures |
| 233 | + ignore_zero (bool): ignore zero impact values at exposures |
194 | 234 | kwargs (optional): arguments for hexbin matplotlib function |
195 | 235 |
|
196 | 236 | Returns: |
197 | 237 | matplotlib.figure.Figure, cartopy.mpl.geoaxes.GeoAxesSubplot |
198 | 238 | """ |
199 | 239 | title = 'Expected annual impact' |
200 | 240 | col_name = 'Impact ' + self.unit |
201 | | - if ignore_null: |
| 241 | + if ignore_zero: |
202 | 242 | pos_vals = self.eai_exp > 0 |
203 | 243 | else: |
204 | 244 | pos_vals = np.ones((self.eai_exp.size,), dtype=bool) |
205 | 245 | if 'reduce_C_function' not in kwargs: |
206 | 246 | kwargs['reduce_C_function'] = np.sum |
207 | 247 | return plot.geo_bin_from_array(self.eai_exp[pos_vals], \ |
208 | 248 | self.coord_exp[pos_vals], col_name, title, **kwargs) |
209 | | - |
210 | | - @staticmethod |
211 | | - def _one_exposure(iexp, exposures, hazard, imp_fun): |
212 | | - """Impact to one exposures. |
213 | | -
|
214 | | - Parameters: |
215 | | - iexp (int): array index of the exposure computed |
216 | | - exposures (Exposures): exposures |
217 | | - hazard (Hazard): a hazard |
218 | | - imp_fun (ImpactFunc): an impact function |
219 | | -
|
220 | | - Returns: |
221 | | - event_row (np.array): hazard' events indices affecting exposure |
222 | | - impact (np.array): impact for each event in event_row |
223 | | - """ |
224 | | - # get assigned centroid of this exposure |
225 | | - icen = int(exposures.assigned[hazard.tag.haz_type][iexp]) |
226 | | - |
227 | | - # get intensities for this centroid |
228 | | - event_row = hazard.intensity[:, icen].nonzero()[0] |
229 | | - inten_val = np.asarray(hazard.intensity[event_row, icen].todense()). \ |
230 | | - squeeze() |
231 | | - # get affected fraction for these events |
232 | | - fract = np.squeeze(hazard.fraction[:, icen].toarray()[event_row]) |
233 | | - |
234 | | - # impact on this exposure |
235 | | - impact = exposures.value[iexp] * imp_fun.calc_mdr(inten_val) * fract |
236 | | - if np.count_nonzero(impact) > 0: |
237 | | - # TODO: if needed? |
238 | | - if (exposures.deductible[iexp] > 0) or \ |
239 | | - (exposures.cover[iexp] < exposures.value[iexp]): |
240 | | - paa = np.interp(inten_val, imp_fun.intensity, imp_fun.paa) |
241 | | - impact = np.minimum(np.maximum(impact - \ |
242 | | - exposures.deductible[iexp] * \ |
243 | | - paa, 0), exposures.cover[iexp]) |
244 | | - return event_row, impact |
|
0 commit comments