|
24 | 24 | from typing import Union |
25 | 25 |
|
26 | 26 | import numpy as np |
| 27 | +import scipy.sparse as sparse |
27 | 28 |
|
28 | 29 | from ..util import log_level |
29 | 30 | from ..util.checker import size |
@@ -242,3 +243,172 @@ def _check_sizes(self): |
242 | 243 | num_entries = len(self.event_id) |
243 | 244 | size(exp_len=num_entries, var=self.member, var_name="Forecast.member") |
244 | 245 | size(exp_len=num_entries, var=self.lead_time, var_name="Forecast.lead_time") |
| 246 | + |
| 247 | + def _reduce_attrs(self, event_name: str): |
| 248 | + """ |
| 249 | + Reduce the attributes of an ImpactForecast to a single value. |
| 250 | +
|
| 251 | + Attributes are modified as follows: |
| 252 | + - lead_time: set to NaT |
| 253 | + - member: set to -1 |
| 254 | + - event_id: set to 0 |
| 255 | + - event_name: set to the name of the reduction method (default) |
| 256 | + - date: set to 0 |
| 257 | + - frequency: set to 1 |
| 258 | +
|
| 259 | + Parameters |
| 260 | + ---------- |
| 261 | + event_name : str |
| 262 | + The event name given to the reduced data. |
| 263 | + """ |
| 264 | + reduced_attrs = { |
| 265 | + "lead_time": np.array([np.timedelta64("NaT")]), |
| 266 | + "member": np.array([-1]), |
| 267 | + "event_id": np.array([0]), |
| 268 | + "event_name": np.array([event_name]), |
| 269 | + "date": np.array([0]), |
| 270 | + "frequency": np.array([1]), |
| 271 | + } |
| 272 | + |
| 273 | + return reduced_attrs |
| 274 | + |
| 275 | + def min(self): |
| 276 | + """ |
| 277 | + Reduce the impact matrix and at_event of an ImpactForecast to the minimum |
| 278 | + value. |
| 279 | +
|
| 280 | + Parameters |
| 281 | + ---------- |
| 282 | + None |
| 283 | +
|
| 284 | + Returns |
| 285 | + ------- |
| 286 | + ImpactForecast |
| 287 | + An ImpactForecast object with the min impact matrix and at_event. |
| 288 | + """ |
| 289 | + red_imp_mat = self.imp_mat.min(axis=0).tocsr() |
| 290 | + red_at_event = np.array([red_imp_mat.sum()]) |
| 291 | + return ImpactForecast( |
| 292 | + frequency_unit=self.frequency_unit, |
| 293 | + coord_exp=self.coord_exp, |
| 294 | + crs=self.crs, |
| 295 | + eai_exp=self.eai_exp, |
| 296 | + at_event=red_at_event, |
| 297 | + tot_value=self.tot_value, |
| 298 | + aai_agg=self.aai_agg, |
| 299 | + unit=self.unit, |
| 300 | + imp_mat=red_imp_mat, |
| 301 | + haz_type=self.haz_type, |
| 302 | + **self._reduce_attrs("min"), |
| 303 | + ) |
| 304 | + |
| 305 | + def max(self): |
| 306 | + """ |
| 307 | + Reduce the impact matrix and at_event of an ImpactForecast to the maximum |
| 308 | + value. |
| 309 | +
|
| 310 | + Parameters |
| 311 | + ---------- |
| 312 | + None |
| 313 | +
|
| 314 | + Returns |
| 315 | + ------- |
| 316 | + ImpactForecast |
| 317 | + An ImpactForecast object with the max impact matrix and at_event. |
| 318 | + """ |
| 319 | + red_imp_mat = self.imp_mat.max(axis=0).tocsr() |
| 320 | + red_at_event = np.array([red_imp_mat.sum()]) |
| 321 | + return ImpactForecast( |
| 322 | + frequency_unit=self.frequency_unit, |
| 323 | + coord_exp=self.coord_exp, |
| 324 | + crs=self.crs, |
| 325 | + eai_exp=self.eai_exp, |
| 326 | + at_event=red_at_event, |
| 327 | + tot_value=self.tot_value, |
| 328 | + aai_agg=self.aai_agg, |
| 329 | + unit=self.unit, |
| 330 | + imp_mat=red_imp_mat, |
| 331 | + haz_type=self.haz_type, |
| 332 | + **self._reduce_attrs("max"), |
| 333 | + ) |
| 334 | + |
| 335 | + def mean(self): |
| 336 | + """ |
| 337 | + Reduce the impact matrix and at_event of an ImpactForecast to the mean value. |
| 338 | +
|
| 339 | + Parameters |
| 340 | + ---------- |
| 341 | + None |
| 342 | +
|
| 343 | + Returns |
| 344 | + ------- |
| 345 | + ImpactForecast |
| 346 | + An ImpactForecast object with the mean impact matrix and at_event. |
| 347 | + """ |
| 348 | + red_imp_mat = sparse.csr_matrix(self.imp_mat.mean(axis=0)) |
| 349 | + red_at_event = np.array([red_imp_mat.sum()]) |
| 350 | + return ImpactForecast( |
| 351 | + frequency_unit=self.frequency_unit, |
| 352 | + coord_exp=self.coord_exp, |
| 353 | + crs=self.crs, |
| 354 | + eai_exp=self.eai_exp, |
| 355 | + at_event=red_at_event, |
| 356 | + tot_value=self.tot_value, |
| 357 | + aai_agg=self.aai_agg, |
| 358 | + unit=self.unit, |
| 359 | + imp_mat=red_imp_mat, |
| 360 | + haz_type=self.haz_type, |
| 361 | + **self._reduce_attrs("mean"), |
| 362 | + ) |
| 363 | + |
| 364 | + def select( |
| 365 | + self, |
| 366 | + event_ids=None, |
| 367 | + event_names=None, |
| 368 | + dates=None, |
| 369 | + coord_exp=None, |
| 370 | + reset_frequency=False, |
| 371 | + member=None, |
| 372 | + lead_time=None, |
| 373 | + ): |
| 374 | + """Select entries based on the parameters and return a new instance. |
| 375 | + The selection will contain the intersection of all given parameters. |
| 376 | +
|
| 377 | + Parameters |
| 378 | + ---------- |
| 379 | + member : Sequence of ints |
| 380 | + Ensemble members to select |
| 381 | + lead_time : Sequence of numpy.timedelta64 |
| 382 | + Lead times to select |
| 383 | +
|
| 384 | + See Also |
| 385 | + -------- |
| 386 | + :py:meth:`~climada.engine.impact.Impact.select` |
| 387 | + """ |
| 388 | + if member is not None or lead_time is not None: |
| 389 | + mask_member = ( |
| 390 | + self.idx_member(member) |
| 391 | + if member is not None |
| 392 | + else np.full_like(self.member, True, dtype=bool) |
| 393 | + ) |
| 394 | + mask_lead_time = ( |
| 395 | + self.idx_lead_time(lead_time) |
| 396 | + if lead_time is not None |
| 397 | + else np.full_like(self.lead_time, True, dtype=bool) |
| 398 | + ) |
| 399 | + event_id_from_forecast_mask = np.asarray(self.event_id)[ |
| 400 | + (mask_member & mask_lead_time) |
| 401 | + ] |
| 402 | + event_ids = ( |
| 403 | + np.intersect1d(event_ids, event_id_from_forecast_mask) |
| 404 | + if event_ids is not None |
| 405 | + else event_id_from_forecast_mask |
| 406 | + ) |
| 407 | + |
| 408 | + return super().select( |
| 409 | + event_ids=event_ids, |
| 410 | + event_names=event_names, |
| 411 | + dates=dates, |
| 412 | + coord_exp=coord_exp, |
| 413 | + reset_frequency=reset_frequency, |
| 414 | + ) |
0 commit comments