|
21 | 21 | "\n", |
22 | 22 | "The caveat of defining measure effects as python functions is that it cannot be serialized (written to a file), and also makes reading from a file a challenge.\n", |
23 | 23 | "\n", |
24 | | - "In order to retain close that gap, the `measure` module now ships `MeasureConfig` objects, which handle the reading, writing and \"declarative\" defining of `Measure` objects.\n", |
| 24 | + "In order to close that gap, the `measure` module now ships `MeasureConfig` objects which can be read from and written to files, and which enable \"declarative\" defining of `Measure` objects.\n", |
| 25 | + "As such `MeasureConfig` objects re-implement and improve the workflow from the old `Measure` objects and handle the translation to the new `Measure` objects:\n", |
25 | 26 | "\n", |
26 | 27 | "`Measure` objects can be instantiated from `MeasureConfig` objects using `Measure.from_config(<MeasureConfig object>)`.\n", |
27 | 28 | "\n", |
|
30 | 31 | "| `Measure` | `MeasureConfig` |\n", |
31 | 32 | "|-----------|--------------------|\n", |
32 | 33 | "| Is used for the actual computation | Is transformed into a `Measure` for actual computation |\n", |
33 | | - "| Uses python function to define what change to apply to the `Exposures`, `ImpactFuncSet`, `Hazard` objects | Define the changes (functions) to apply via the former way (scaling/shifting effect, alternate file loading, etc.) |\n", |
| 34 | + "| Uses python functions to define what change to apply to the `Exposures`, `ImpactFuncSet`, `Hazard` objects | Defines the changes to apply using the (former) declarative way (scaling/shifting effect, alternate file loading, etc.) |\n", |
34 | 35 | "| Accepts any possible effect as long as it can be defined as a python function | Is restricted to a set of defined effects |\n", |
35 | 36 | "| Cannot be written to a file (unless it was created by a `MeasureConfig`) | Can easily be read from/written to a file (`.xlsx` or `.yaml`) |" |
36 | 37 | ] |
|
50 | 51 | "- `ExposuresModifierConfig`: Modifies exposure data (e.g., reassigning IDs or zeroing regions).\n", |
51 | 52 | "- `CostIncomeConfig`: Handles the financial aspects, including initial costs and recurring income.\n", |
52 | 53 | "\n", |
53 | | - "Note that everything can be defined and accessed directly from the `MeasureConfig` container, the underlying ones are there to keep things organized.\n", |
| 54 | + "Note that all effects of a `MeasureConfig` can be directly defined from the `MeasureConfig` container (with `from_dict()`, the underlying ones are there to keep things organized.\n", |
54 | 55 | "\n", |
55 | 56 | "In the following we present each of these subclasses and the possibilities they offer." |
56 | 57 | ] |
|
81 | 82 | "| **Hazard** | `haz_int_mult` | `float` | Multiplier for hazard intensity (default: 1.0). |\n", |
82 | 83 | "| | `haz_int_add` | `float` | Additive offset for hazard intensity (default: 0.0). |\n", |
83 | 84 | "| | `new_hazard_path` | | Path to an HDF5 file to replace the current hazard. |\n", |
84 | | - "| | `impact_rp_cutoff` | `float` | Return period (years) threshold; events below this are ignored. |\n", |
| 85 | + "| | `impact_rp_cutoff` | `float` | Return period (years) threshold; events with impacts below this threshold are ignored. |\n", |
85 | 86 | "| **Impact Function**| `impf_ids` | `list` | Specific impact function IDs to modify (None = all). |\n", |
86 | 87 | "| | `impf_mdd_mult` / `_add` | `float` | Scale or shift the Mean Damage Degree curve. |\n", |
87 | 88 | "| | `impf_paa_mult` / `_add` | `float` | Scale or shift the Percentage of Assets Affected curve. |\n", |
88 | 89 | "| | `impf_int_mult` / `_add` | `float` | Scale or shift the intensity axis of the function. |\n", |
89 | 90 | "| | `new_impfset_path` | | Path to an Excel file to replace the impact function set. |\n", |
90 | 91 | "| **Exposures** | `reassign_impf_id` | `dict` | Mapping `{haz_type: {old_id: new_id}}` for reclassification. |\n", |
91 | | - "| | `set_to_zero` | `list` | List of Region IDs where exposure value is set to 0. |\n", |
| 92 | + "| | `set_to_zero` | `list` | List of exposures IDs where exposure value is set to 0. |\n", |
92 | 93 | "| | `new_exposures_path` | | Path to an HDF5 file to replace the current exposures. |\n", |
93 | 94 | "| **Cost & Income** | `init_cost` | `float` | One-time investment cost (absolute value). |\n", |
94 | 95 | "| | `periodic_cost` | `float` | Recurring maintenance/operational costs. |\n", |
|
154 | 155 | "print(meas_config)" |
155 | 156 | ] |
156 | 157 | }, |
| 158 | + { |
| 159 | + "cell_type": "markdown", |
| 160 | + "id": "37a913e2-6517-45ee-b011-58de8d740d77", |
| 161 | + "metadata": {}, |
| 162 | + "source": [ |
| 163 | + "```{note}\n", |
| 164 | + "The string representation of a `MeasureConfig` object filters out the default values to avoid clutter.\n", |
| 165 | + "\n", |
| 166 | + "You can see all fields using `MeasureConfig.to_dict(omit_default=False)`\n", |
| 167 | + "```" |
| 168 | + ] |
| 169 | + }, |
157 | 170 | { |
158 | 171 | "cell_type": "markdown", |
159 | 172 | "id": "ac98393f-575f-4580-ac4a-dae578638916", |
|
163 | 176 | "\n", |
164 | 177 | "The `ImpfsetModifierConfig` is used to define how an adaptation measure changes the vulnerability (refer to the [impact functions tutorial](impact-functions-tutorial)).\n", |
165 | 178 | "\n", |
166 | | - "When \"translated\" to a `Measure` object the `ImpfsetModifierConfig` populates the `impfset_change` attribute with a function that takes an `ImpactFuncSet` and returns a modified one, according to the specifications.\n", |
| 179 | + "When \"translated\" to a `Measure` object, the `ImpfsetModifierConfig` populates the `impfset_change` attribute with a function that takes an `ImpactFuncSet` and returns a modified one, according to the specifications.\n", |
167 | 180 | "\n", |
168 | 181 | "```{note}\n", |
169 | 182 | "Modifications are always applied to a specific hazard type (`haz_type` parameter).\n", |
|
218 | 231 | "\n", |
219 | 232 | "# 1. Scaling existing Impact Functions\n", |
220 | 233 | "# Let's say we want to simulate a 20% reduction in MDD\n", |
221 | | - "# and a slight shift in the intensity threshold for Hazard 'TC'.\n", |
| 234 | + "# and a horziontal translation of the impact function for Hazard 'TC'.\n", |
222 | 235 | "impf_mod_scaling = ImpfsetModifierConfig(\n", |
223 | 236 | " haz_type=\"TC\",\n", |
224 | 237 | " impf_ids=[1, 2], # Apply only to specific function IDs\n", |
225 | 238 | " impf_mdd_mult=0.8, # Reduce Mean Damage Degree by 20%\n", |
226 | | - " impf_int_add=5.0, # Shift intensity axis by 5 units (e.g., higher resistance)\n", |
| 239 | + " impf_int_add=5.0, # Shift intensity array by 5 units, i.e. move impact function by 5 units to the right (e.g., higher resistance)\n", |
227 | 240 | ")\n", |
228 | 241 | "\n", |
229 | 242 | "print(\"--- Scaling Config ---\")\n", |
|
248 | 261 | "\n", |
249 | 262 | "The `HazardModifierConfig` is used to define how an adaptation measure changes the hazard (refer to the [hazard tutorial](hazard-tutorial)).\n", |
250 | 263 | "\n", |
251 | | - "When \"translated\" to a `Measure` object the `HazardModifierConfig` populates the `hazard_change` attribute with a function that takes a `Hazard` (possibly additional arguments, see below) and returns a modified one, according to the specifications.\n", |
| 264 | + "When \"translated\" to a `Measure` object, the `HazardModifierConfig` populates the `hazard_change` attribute with a function that takes a `Hazard` (possibly additional arguments, see below) and returns a modified one, according to the specifications.\n", |
252 | 265 | "\n", |
253 | 266 | "```{note}\n", |
254 | 267 | "Modifications are always applied to a specific hazard type (`haz_type` parameter).\n", |
|
268 | 281 | "\n", |
269 | 282 | "In that case the function changing the hazard (`Measure.hazard_change`) will be a function with the following signature:\n", |
270 | 283 | "\n", |
271 | | - " f(hazard: Hazard, # The hazard to apply on\n", |
272 | | - " exposures: Exposures, # The exposure for the impact computation\n", |
273 | | - " impfset: ImpactFuncSet, # The impfset for the impact computation\n", |
274 | | - " base_hazard: Hazard, # The hazard for the impact computation\n", |
275 | | - " exposures_region_id: Optional[list[int]] = None, # Region id to filter to\n", |
276 | | - " ) -> Hazard\n", |
| 284 | + " def hazard_change(\n", |
| 285 | + " hazard: Hazard, # Hazard to apply change to\n", |
| 286 | + " base_exposures: Exposures, # Exposure to use for impact computation\n", |
| 287 | + " base_impfset: ImpactFuncSet, # Impfset to use for impact computation\n", |
| 288 | + " base_hazard: Hazard, # Hazard to use for impact computation\n", |
| 289 | + " exposures_region_id: Optional[list[int]] = None, # Exposures id to restrict the effect to\n", |
| 290 | + " ) -> Hazard\n", |
| 291 | + "\n", |
| 292 | + "The base_<> triplet is provided by default when the measure is applied so you are not required to supply them if they should indeed be the base triplet before the measure is applied.\n", |
277 | 293 | "```\n", |
278 | 294 | "\n", |
279 | 295 | "```{warning}\n", |
|
359 | 375 | "\n", |
360 | 376 | "The `ExposuresModifierConfig` is used to define how an adaptation measure changes the exposure (refer to the [exposure tutorial](exposure-tutorial)).\n", |
361 | 377 | "\n", |
362 | | - "When \"translated\" to a `Measure` object the `ExposuresModifierConfig` populates the `exposures_change` attribute with a function that takes an `Exposures` and returns a modified one, according to the specifications.\n", |
| 378 | + "When \"translated\" to a `Measure` object, the `ExposuresModifierConfig` populates the `exposures_change` attribute with a function that takes an `Exposures` and returns a modified one, according to the specifications.\n", |
363 | 379 | "\n", |
364 | 380 | "`ExposuresModifierConfig` allows you to modify the impact function assigned to different hazard, to set a list of points to 0 value, or to load a different Exposures:\n", |
365 | 381 | "\n", |
|
402 | 418 | "\n", |
403 | 419 | "# 1. Changing existing Exposures\n", |
404 | 420 | "exp_mod = ExposuresModifierConfig(\n", |
405 | | - " reassign_impf_id={\"TC\": {1: 2}}, # Remaps exposures points with impf_TC == 1 to 2.\n", |
| 421 | + " reassign_impf_id={\n", |
| 422 | + " \"TC\": {1: 2}\n", |
| 423 | + " }, # Reassigns exposures points with impact function id impf_TC == 1 to 2.\n", |
406 | 424 | " set_to_zero=[\n", |
407 | 425 | " 0,\n", |
408 | 426 | " 25,\n", |
|
427 | 445 | "source": [ |
428 | 446 | "## Defining the financial aspects of the measure\n", |
429 | 447 | "\n", |
430 | | - "For in depth description of CostIncome objects, refer to the [related tutorial](cost-income-tutorial).\n", |
| 448 | + "For in depth description of `CostIncome` objects, refer to the [related tutorial](cost-income-tutorial).\n", |
431 | 449 | "\n", |
432 | 450 | "```{note}\n", |
433 | 451 | "The default for mkt_price_year if not provided is the current year.\n", |
|
460 | 478 | "--- Custom Schedule Config ---\n", |
461 | 479 | "CostIncomeConfig(\n", |
462 | 480 | "\t\tNon default fields:\n", |
463 | | - "\t\t\tcustom_cash_flows=[{'date': '2024-01-01', 'value': -1000000}, {'date': '2029-01-01', 'value': -200000}, {'date': '2034-01-01', 'value': 500000}]\n", |
| 481 | + "\t\t\tcustom_cash_flows=[{'date': '2024-01-01', 'cost': 1000000.0, 'income': 0.0}, {'date': '2029-01-01', 'cost': 200000.0, 'income': 0.0}, {'date': '2034-01-01', 'cost': 10000.0, 'income': 500000}]\n", |
464 | 482 | ")\n" |
465 | 483 | ] |
466 | 484 | } |
|
470 | 488 | "\n", |
471 | 489 | "# This models a measure where costs increase by 2% annually,\n", |
472 | 490 | "# but it generates 100k in yearly income which grows by 3%.\n", |
| 491 | + "# By default, the periodicity of costs and income is yearly.\n", |
473 | 492 | "growth_finance = CostIncomeConfig(\n", |
474 | 493 | " init_cost=500_000.0,\n", |
475 | 494 | " periodic_cost=20_000.0,\n", |
476 | 495 | " cost_yearly_growth_rate=0.02,\n", |
477 | 496 | " periodic_income=100_000.0,\n", |
478 | 497 | " income_yearly_growth_rate=0.03,\n", |
479 | | - " freq=\"Y\",\n", |
480 | 498 | ")\n", |
481 | 499 | "\n", |
482 | 500 | "print(\"\\n--- Growth & Income Config ---\")\n", |
|
485 | 503 | "\n", |
486 | 504 | "# Custom Cash Flow\n", |
487 | 505 | "# If the investment isn't linear (e.g., a major retrofit in year 5),\n", |
488 | | - "# you can define a list of specific events.\n", |
| 506 | + "# you can define a custom cash flow, with negative values representing\n", |
| 507 | + "# net costs and positive ones net benefits.\n", |
489 | 508 | "custom_schedule = [\n", |
490 | | - " {\"date\": \"2024-01-01\", \"value\": -1000000}, # Initial cost\n", |
491 | | - " {\"date\": \"2029-01-01\", \"value\": -200000}, # Mid-term overhaul\n", |
492 | | - " {\"date\": \"2034-01-01\", \"value\": 500000}, # Terminal value\n", |
| 509 | + " {\"date\": \"2024-01-01\", \"cost\": 1000000.0, \"income\": 0.0},\n", |
| 510 | + " {\"date\": \"2029-01-01\", \"cost\": 200000.0, \"income\": 0.0},\n", |
| 511 | + " {\"date\": \"2034-01-01\", \"cost\": 10000.0, \"income\": 500000},\n", |
493 | 512 | "]\n", |
494 | 513 | "\n", |
495 | 514 | "custom_finance = CostIncomeConfig(custom_cash_flows=custom_schedule)\n", |
|
0 commit comments