diff --git a/CHANGELOG.md b/CHANGELOG.md
index e301836bd1..550d76f6a6 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,10 +12,13 @@ Code freeze date: YYYY-MM-DD
### Added
-- Better type hints and overloads signatures for ImpactFuncSet [#1250](https://github.com/CLIMADA-project/climada_python/pull/1250)
+- Better type hints and overloads signatures for `ImpactFuncSet` [#1250](https://github.com/CLIMADA-project/climada_python/pull/1250)
+- Adds `CostIncome` class and related tutorial for future new `Measure` class. [#1277](https://github.com/CLIMADA-project/climada_python/pull/1277)
+- Adds `MeasureConfig` and related dataclasses for new `Measure` object retrocompatibility and (de)serialization capabilities [#1276](https://github.com/CLIMADA-project/climada_python/pull/1276)
### Changed
- Updated Impact Calculation Tutorial (`doc.climada_engine_Impact.ipynb`) [#1095](https://github.com/CLIMADA-project/climada_python/pull/1095).
+- Makes current `measure` module a legacy module, moving it to `_legacy_measure`, to retain compatibility with `CostBenefit` class and various tests. [#1274](https://github.com/CLIMADA-project/climada_python/pull/1274)
### Fixed
diff --git a/climada/engine/test/test_cost_benefit.py b/climada/engine/test/test_cost_benefit.py
index e48afec110..8b0276c665 100644
--- a/climada/engine/test/test_cost_benefit.py
+++ b/climada/engine/test/test_cost_benefit.py
@@ -33,10 +33,10 @@
risk_rp_100,
risk_rp_250,
)
+from climada.entity._legacy_measures import Measure
+from climada.entity._legacy_measures.base import LOGGER as ILOG
from climada.entity.disc_rates import DiscRates
from climada.entity.entity_def import Entity
-from climada.entity.measures import Measure
-from climada.entity.measures.base import LOGGER as ILOG
from climada.hazard.base import Hazard
from climada.test import get_test_file
from climada.util.api_client import Client
diff --git a/climada/engine/unsequa/input_var.py b/climada/engine/unsequa/input_var.py
index 76e63d766e..9abdd8d3fa 100644
--- a/climada/engine/unsequa/input_var.py
+++ b/climada/engine/unsequa/input_var.py
@@ -518,7 +518,7 @@ def ent(
exp_list : [climada.entity.exposures.base.Exposure]
The list of base exposure. Can be one or many to uniformly sample
from.
- meas_set : climada.entity.measures.measure_set.MeasureSet
+ meas_set : climada.entity._legacy_measures.measure_set.MeasureSet
The base measures.
haz_id_dict : dict
Dictionary of the impact functions affected by uncertainty.
@@ -660,7 +660,7 @@ def entfut(
exp_list : [climada.entity.exposures.base.Exposure]
The list of base exposure. Can be one or many to uniformly sample
from.
- meas_set : climada.entity.measures.measure_set.MeasureSet
+ meas_set : climada.entity._legacy_measures.measure_set.MeasureSet
The base measures.
haz_id_dict : dict
Dictionary of the impact functions affected by uncertainty.
diff --git a/climada/entity/__init__.py b/climada/entity/__init__.py
index 7b830c2b70..ceb24ee065 100755
--- a/climada/entity/__init__.py
+++ b/climada/entity/__init__.py
@@ -19,8 +19,8 @@
init entity
"""
+from ._legacy_measures import *
from .disc_rates import *
from .entity_def import *
from .exposures import *
from .impact_funcs import *
-from .measures import *
diff --git a/climada/entity/measures/__init__.py b/climada/entity/_legacy_measures/__init__.py
similarity index 100%
rename from climada/entity/measures/__init__.py
rename to climada/entity/_legacy_measures/__init__.py
diff --git a/climada/entity/measures/base.py b/climada/entity/_legacy_measures/base.py
similarity index 100%
rename from climada/entity/measures/base.py
rename to climada/entity/_legacy_measures/base.py
diff --git a/climada/entity/measures/measure_set.py b/climada/entity/_legacy_measures/measure_set.py
similarity index 99%
rename from climada/entity/measures/measure_set.py
rename to climada/entity/_legacy_measures/measure_set.py
index 90a2bb43c2..228788ba15 100755
--- a/climada/entity/measures/measure_set.py
+++ b/climada/entity/_legacy_measures/measure_set.py
@@ -32,7 +32,8 @@
from matplotlib import colormaps as cm
import climada.util.hdf5_handler as u_hdf5
-from climada.entity.measures.base import Measure
+
+from .base import Measure
LOGGER = logging.getLogger(__name__)
diff --git a/climada/entity/measures/test/__init__.py b/climada/entity/_legacy_measures/test/__init__.py
similarity index 100%
rename from climada/entity/measures/test/__init__.py
rename to climada/entity/_legacy_measures/test/__init__.py
diff --git a/climada/entity/measures/test/data/.gitignore b/climada/entity/_legacy_measures/test/data/.gitignore
similarity index 100%
rename from climada/entity/measures/test/data/.gitignore
rename to climada/entity/_legacy_measures/test/data/.gitignore
diff --git a/climada/entity/measures/test/test_base.py b/climada/entity/_legacy_measures/test/test_base.py
similarity index 99%
rename from climada/entity/measures/test/test_base.py
rename to climada/entity/_legacy_measures/test/test_base.py
index 6f76eb7373..430ab7d44b 100644
--- a/climada/entity/measures/test/test_base.py
+++ b/climada/entity/_legacy_measures/test/test_base.py
@@ -28,12 +28,12 @@
import climada.entity.exposures.test as exposures_test
import climada.util.coordinates as u_coord
from climada import CONFIG
+from climada.entity._legacy_measures.base import IMPF_ID_FACT, Measure
+from climada.entity._legacy_measures.measure_set import MeasureSet
from climada.entity.entity_def import Entity
from climada.entity.exposures.base import Exposures
from climada.entity.impact_funcs.base import ImpactFunc
from climada.entity.impact_funcs.impact_func_set import ImpactFuncSet
-from climada.entity.measures.base import IMPF_ID_FACT, Measure
-from climada.entity.measures.measure_set import MeasureSet
from climada.hazard.base import Hazard
from climada.test import get_test_file
from climada.util.constants import HAZ_DEMO_H5
diff --git a/climada/entity/measures/test/test_meas_set.py b/climada/entity/_legacy_measures/test/test_meas_set.py
similarity index 98%
rename from climada/entity/measures/test/test_meas_set.py
rename to climada/entity/_legacy_measures/test/test_meas_set.py
index a2cbdc3f16..868510fbe8 100644
--- a/climada/entity/measures/test/test_meas_set.py
+++ b/climada/entity/_legacy_measures/test/test_meas_set.py
@@ -24,8 +24,8 @@
import numpy as np
from climada import CONFIG
-from climada.entity.measures.base import Measure
-from climada.entity.measures.measure_set import MeasureSet
+from climada.entity._legacy_measures.base import Measure
+from climada.entity._legacy_measures.measure_set import MeasureSet
from climada.util.constants import ENT_DEMO_TODAY, ENT_TEMPLATE_XLS
DATA_DIR = CONFIG.measures.test_data.dir()
@@ -58,7 +58,7 @@ def test_add_wrong_error(self):
"""Test error is raised when wrong ImpactFunc provided."""
meas = MeasureSet()
with self.assertLogs(
- "climada.entity.measures.measure_set", level="WARNING"
+ "climada.entity._legacy_measures.measure_set", level="WARNING"
) as cm:
meas.append(Measure())
self.assertIn("Input Measure's hazard type not set.", cm.output[0])
@@ -76,7 +76,9 @@ def test_remove_measure_pass(self):
def test_remove_wrong_error(self):
"""Test error is raised when invalid inputs."""
meas = MeasureSet(measure_list=[Measure(name="Mangrove", haz_type="FL")])
- with self.assertLogs("climada.entity.measures.measure_set", level="INFO") as cm:
+ with self.assertLogs(
+ "climada.entity._legacy_measures.measure_set", level="INFO"
+ ) as cm:
meas.remove_measure(name="Seawall")
self.assertIn("No Measure with name Seawall.", cm.output[0])
diff --git a/climada/entity/entity_def.py b/climada/entity/entity_def.py
index d58af9efed..c1bc3b2550 100755
--- a/climada/entity/entity_def.py
+++ b/climada/entity/entity_def.py
@@ -26,10 +26,10 @@
import pandas as pd
+from climada.entity._legacy_measures.measure_set import Measure, MeasureSet
from climada.entity.disc_rates.base import DiscRates
from climada.entity.exposures.base import Exposures
from climada.entity.impact_funcs.impact_func_set import ImpactFuncSet
-from climada.entity.measures.measure_set import MeasureSet
LOGGER = logging.getLogger(__name__)
diff --git a/climada/entity/measures/cost_income.py b/climada/entity/measures/cost_income.py
new file mode 100644
index 0000000000..33ece8de1c
--- /dev/null
+++ b/climada/entity/measures/cost_income.py
@@ -0,0 +1,568 @@
+"""
+This file is part of CLIMADA.
+
+Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.
+
+CLIMADA is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free
+Software Foundation, version 3.
+
+CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with CLIMADA. If not, see .
+
+---
+
+Define the CostIncome class to handle the cash flow of measures.
+"""
+
+from datetime import datetime
+from typing import Any, List, Optional, Tuple, cast
+
+import matplotlib.pyplot as plt
+import numpy as np
+import pandas as pd
+
+from climada.entity.disc_rates.base import DiscRates
+from climada.entity.measures.measure_config import CostIncomeConfig
+
+
+class CostIncome:
+ """
+ Manages costs and incomes related to a measure over time.
+
+ Income are stored a positive numbers and costs as negative
+ ones.
+
+ Attributes
+ ----------
+ mkt_price_year : datetime, default to today's year.
+ The reference year for market prices.
+ init_cost : float
+ Initial implementation cost (stored as negative).
+ periodic_cost : float
+ Recurring cost per period (stored as negative).
+ periodic_income : float
+ Recurring income per period.
+ cost_yearly_growth_rate : float
+ Yearly growth rate of costs.
+ income_yearly_growth_rate : float
+ Yearly growth rate of income.
+ custom_cash_flows : pd.DataFrame, optional
+ User-defined cash flows indexed by date.
+ freq : str
+ Frequency of the cash flows (e.g., 'Y', '3M', '7D').
+
+ """
+
+ def __init__(
+ self,
+ *,
+ mkt_price_year: Optional[int] = None,
+ init_cost: float = 0.0,
+ periodic_cost: float = 0.0,
+ periodic_income: float = 0.0,
+ cost_yearly_growth_rate: float = 0.0,
+ income_yearly_growth_rate: float = 0.0,
+ custom_cash_flows: Optional[pd.DataFrame] = None,
+ freq: str = "Y",
+ ):
+ """Initialize CostIncome with parameters.
+
+ Parameters
+ ----------
+ mkt_price_year : datetime, default to today's year.
+ The reference year for market prices.
+ init_cost : float
+ Initial implementation cost (stored as negative).
+ periodic_cost : float
+ Recurring cost per period (stored as negative).
+ periodic_income : float
+ Recurring income per period.
+ cost_yearly_growth_rate : float
+ Yearly growth rate of costs.
+ income_yearly_growth_rate : float
+ Yearly growth rate of income.
+ custom_cash_flows : pd.DataFrame, optional
+ User-defined cash flows indexed by date.
+ freq : str
+ Frequency of the cash flows (e.g., 'Y', '3M', '7D').
+ """
+
+ self.freq = freq
+ self.mkt_price_year = datetime(mkt_price_year or datetime.today().year, 1, 1)
+ self.cost_growth_rate = cost_yearly_growth_rate
+
+ self.init_cost = -abs(init_cost)
+ self.periodic_cost = -abs(periodic_cost)
+ self.periodic_income = abs(periodic_income)
+
+ self.income_growth_rate = income_yearly_growth_rate
+
+ if custom_cash_flows is not None:
+ self.custom_cash_flows = self._prepare_custom_flows(custom_cash_flows)
+ else:
+ self.custom_cash_flows = None
+
+ def __repr__(self) -> str:
+ lines = [
+ "CostIncome(",
+ f" mkt_price_year = {self.mkt_price_year.year}",
+ f" freq = {self.freq!r}",
+ f" init_cost = {self.init_cost:,.2f}",
+ f" periodic_cost = {self.periodic_cost:,.2f}",
+ f" periodic_income = {self.periodic_income:,.2f}",
+ f" cost_yearly_growth_rate = {self.cost_growth_rate:.2%}",
+ f" income_yearly_growth_rate = {self.income_growth_rate:.2%}",
+ f" custom_cash_flows = {None if self.custom_cash_flows is None else f'DataFrame({len(self.custom_cash_flows)} rows)'}",
+ ")",
+ ]
+ return "\n".join(lines)
+
+ def _prepare_custom_flows(self, df: pd.DataFrame) -> pd.DataFrame:
+ """Process and resample custom cash flow dataframe
+
+ Enforce costs as negative numbers and date to the correct frequency.
+
+ Parameters
+ ----------
+ df : pd.DataFrame
+ Custom cashflow
+
+ Returns
+ -------
+ pd.DataFrame
+ Processed custom cashflow
+ """
+
+ df = df.copy()
+ if "cost" in df.columns:
+ df["cost"] = -df["cost"].abs()
+ if "date" in df.columns:
+ df["date"] = pd.to_datetime(df["date"])
+ df = df.set_index("date")
+
+ freq = self._make_offset_compat(self.freq)
+ return df.resample(freq).sum()
+
+ @staticmethod
+ def _make_offset_compat(freq: str, start=True) -> str:
+ suffix = "S" if start else "E"
+ match freq:
+ case "Y":
+ return "Y" + suffix
+ case "M":
+ return "M" + suffix
+ case "Q":
+ return "Q" + suffix
+ case _:
+ return freq
+
+ @classmethod
+ def from_config(cls, config: CostIncomeConfig) -> "CostIncome":
+ """Create a `CostIncome` from a `CostIncomeConfig`.
+
+ Parameters
+ ----------
+ config : CostIncomeConfig
+
+ Returns
+ -------
+ CostIncome
+ """
+
+ df = None
+ if config.custom_cash_flows is not None:
+ df = pd.DataFrame(config.custom_cash_flows)
+ df["date"] = pd.to_datetime(df["date"])
+ return cls(
+ mkt_price_year=config.mkt_price_year,
+ init_cost=config.init_cost,
+ periodic_cost=config.periodic_cost,
+ periodic_income=config.periodic_income,
+ cost_yearly_growth_rate=config.cost_yearly_growth_rate,
+ income_yearly_growth_rate=config.income_yearly_growth_rate,
+ custom_cash_flows=df,
+ freq=config.freq,
+ )
+
+ @classmethod
+ def from_dict(cls, args_dict: dict) -> "CostIncome":
+ """Create a `CostIncome` from a dictionary.
+
+ Parameters
+ ----------
+ args_dict : dict
+
+ Returns
+ -------
+ CostIncome
+ """
+
+ return cls.from_config(
+ CostIncomeConfig(
+ mkt_price_year=args_dict.get("mkt_price_year"),
+ init_cost=args_dict.get("init_cost", 0.0),
+ periodic_cost=args_dict.get("periodic_cost", 0.0),
+ periodic_income=args_dict.get("periodic_income", 0.0),
+ cost_yearly_growth_rate=args_dict.get("cost_yearly_growth_rate", 0.0),
+ income_yearly_growth_rate=args_dict.get(
+ "income_yearly_growth_rate", 0.0
+ ),
+ freq=args_dict.get("freq", "Y"),
+ custom_cash_flows=args_dict.get("custom_cash_flows"),
+ )
+ )
+
+ @classmethod
+ def from_yaml(cls, path: str) -> "CostIncome":
+ """Create a `CostIncome` from a yaml file.
+
+ Parameters
+ ----------
+ path : str
+ Path to the yaml file.
+
+ Returns
+ -------
+ CostIncome
+ """
+
+ import yaml
+
+ with open(path) as f:
+ return cls.from_dict(yaml.safe_load(f)["cost_income"])
+
+ @classmethod
+ def _freq_to_days(cls, freq: str) -> str:
+ """
+ Convert a frequency string to the equivalent number of days.
+
+ Parameters:
+ -----------
+ freq : str
+ A frequency string (e.g., 'D' for daily, 'M' for monthly, 'Y' for yearly).
+
+ Returns:
+ --------
+ float
+ The equivalent number of days for the given frequency string.
+ """
+
+ try:
+ # Convert the frequency string to a DateOffset object
+ freq = cls._make_offset_compat(freq, start=False)
+ offset = pd.tseries.frequencies.to_offset(freq)
+
+ # Calculate the number of days by applying the offset to a base date
+ base_date = pd.Timestamp("2000-01-01")
+ end_date = base_date + offset
+
+ # Return the difference in days
+ return f"{(end_date - base_date).days}d"
+ except ValueError:
+ raise ValueError(f"Invalid frequency string: {freq}")
+
+ def _get_width_days(self) -> float:
+ """Return the number of days in the current frequency."""
+
+ ref = pd.Timestamp("2000-01-01")
+ freq = self._make_offset_compat(self.freq, start=False)
+ offset = pd.tseries.frequencies.to_offset(freq)
+ return float(((ref + offset) - ref).days)
+
+ def _calc_at_date(
+ self, impl_date: pd.Timestamp, curr_date: pd.Timestamp
+ ) -> Tuple[float, float, float]:
+ r"""Calculate cash flows for a single timestamp.
+
+ Computes the total cash flow, total cost, and total income for a given
+ evaluation date, accounting for growth rates applied to base costs and
+ incomes, as well as the custom cash flow if provided.
+
+ The calculation applies compound growth to both costs and incomes based
+ on the number of years elapsed since the market price reference date
+ (`self.mkt_price_year`).
+
+ Parameters
+ ----------
+ impl_date : pd.Timestamp
+ The implementation date that determines which cost/income regime
+ applies. Dates before this use have no cost or income; "at the date" uses
+ the implementation cost, and dates after use the initialized or
+ periodic amounts respectively.
+ curr_date : pd.Timestamp
+ The evaluation date for which cash flows are being calculated. This
+ is compared against `impl_date` to determine the applicable base
+ amounts and is also used to index into `custom_cash_flows` if present.
+
+ Returns
+ -------
+ Tuple[float, float, float]
+ A tuple containing:
+
+ * total_cash_flow : float
+ Net cash flow for the period, calculated as `total_income + total_cost`.
+ Note: Costs are typically negative values in financial contexts,
+ so this represents the net position.
+ * total_cost : float
+ Total cost amount for the period, including both standard and
+ custom cost components.
+ * total_income : float
+ Total income amount for the period, including both standard and
+ custom income components.
+
+ Notes
+ -----
+ Growth calculations use compound interest formula:
+
+ .. math::
+ factor = (1 + rate)^{years\_passed}
+
+ where `years_passed` is computed as `(curr_date - mkt_price_year).days / 365.0`.
+
+ Cost and income regimes:
+
+ - **Before impl_date**: Both base cost and income are zero
+ - **At impl_date**: Uses `init_cost` for cost
+ - **After impl_date**: Uses `periodic_cost` for cost and `periodic_income` for income
+
+ Custom cash flows (if `self.custom_cash_flows` is not None) are added
+ on top of the calculated standard amounts. Missing dates in the custom
+ cash flow DataFrame will raise a KeyError.
+ """
+ # Calculate growth factor based on years from market price reference
+ years_passed = (curr_date - self.mkt_price_year).days / 365.0
+
+ cost_factor = (1 + self.cost_growth_rate) ** years_passed
+ inc_factor = (1 + self.income_growth_rate) ** years_passed
+
+ if curr_date < impl_date:
+ cost, income = 0.0, 0.0
+ elif curr_date == impl_date:
+ cost = self.init_cost * cost_factor
+ income = 0.0
+ else:
+ cost = self.periodic_cost * cost_factor
+ income = self.periodic_income * inc_factor
+
+ if (
+ self.custom_cash_flows is not None
+ and curr_date in self.custom_cash_flows.index
+ ):
+ c_cost = cast(float, self.custom_cash_flows.loc[curr_date, "cost"])
+ c_inc = cast(float, self.custom_cash_flows.loc[curr_date, "income"])
+ else:
+ c_cost, c_inc = 0.0, 0.0
+
+ total_cost = cost + c_cost
+ total_inc = income + c_inc
+ return (total_inc + total_cost), total_cost, total_inc
+
+ def calc_cash_flows(
+ self, impl_date, start_date, end_date
+ ) -> Tuple[np.ndarray, np.ndarray, np.ndarray]:
+ """Calculate net cash flows, costs, and incomes over a period.
+
+ Computes cash flow metrics across a specified date range by iterating
+ through each period.
+
+ The method creates a period range based on the configured frequency
+ (`self.freq`) and evaluates cash flows at the start time of each period.
+ Results are returned as NumPy arrays for efficient downstream processing.
+
+ Parameters
+ ----------
+ impl_date :
+ The implementation date that determines which cost/income regime
+ applies.
+ start_date :
+ The beginning of the calculation period.
+ end_date :
+ The end of the calculation period.
+
+ Returns
+ -------
+ Tuple[np.ndarray, np.ndarray, np.ndarray]
+ A tuple containing three NumPy arrays of equal length:
+
+ * net : np.ndarray
+ Net cash flow for each period (income + cost).
+ * costs : np.ndarray
+ Total costs for each period.
+ * incomes : np.ndarray
+ Total incomes for each period.
+ """
+
+ impl_ts = pd.Timestamp(impl_date)
+ periods = pd.period_range(start=start_date, end=end_date, freq=self.freq)
+
+ results = [self._calc_at_date(impl_ts, p.start_time) for p in periods]
+ net, costs, incs = map(np.array, zip(*results))
+ return net, costs, incs
+
+ def calc_total(self, impl_date, start_date, end_date) -> Tuple[float, float, float]:
+ """
+ Calculate the total value of the cash flows over a given period.
+
+ Parameters:
+ -----------
+ impl_date:
+ The date the measure is implemented.
+ start_year:
+ The start date of the period.
+ end_year: int
+ The end year of the period.
+
+ Returns:
+ --------
+ Tuple[float, float, float]
+ the total net, cost, and income values over the given period.
+ """
+
+ net_cash_flows, costs, incomes = self.calc_cash_flows(
+ impl_date, start_date, end_date
+ )
+ return np.sum(net_cash_flows), np.sum(costs), np.sum(incomes)
+
+ def plot_cash_flows(
+ self,
+ impl_date: Any,
+ start_date: Any,
+ end_date: Any,
+ figsize: Tuple[int, int] = (12, 7),
+ title: Optional[str] = None,
+ ):
+ """Plot periodic and cumulative cash flows over a given period.
+
+ Displays a two-panel figure:
+ - Top panel: stacked bar chart of costs and incomes per period,
+ with a net cash flow line overlay.
+ - Bottom panel: cumulative net cash flow over time.
+
+ Parameters
+ ----------
+ impl_date :
+ The date the measure is implemented.
+ start_date :
+ Start of the evaluation period.
+ end_date :
+ End of the evaluation period.
+ figsize : tuple, optional
+ Figure size as (width, height). Default is (12, 7).
+ title : str, optional
+ Overall figure title. Defaults to 'Cash Flow Analysis'.
+
+ Returns
+ -------
+ plt.Figure
+ """
+ net, costs, incomes = self.calc_cash_flows(impl_date, start_date, end_date)
+ periods = pd.period_range(start=start_date, end=end_date, freq=self.freq)
+ dates = [p.start_time for p in periods]
+ cumulative_net = np.cumsum(net)
+
+ width = pd.Timedelta(days=self._get_width_days() * 0.6)
+
+ fig, (ax_bar, ax_cum) = plt.subplots(
+ 2,
+ 1,
+ figsize=figsize,
+ sharex=True,
+ gridspec_kw={"height_ratios": [3, 1], "hspace": 0.08},
+ )
+
+ # --- top panel: stacked bars + net line ---
+ ax_bar.bar(
+ dates, incomes, width=width, color="#4C9BE8", label="Income", zorder=2
+ )
+ ax_bar.bar(dates, costs, width=width, color="#E8604C", label="Cost", zorder=2)
+ ax_bar.plot(
+ dates,
+ net,
+ color="black",
+ linewidth=1.5,
+ marker="o",
+ markersize=4,
+ label="Net",
+ zorder=3,
+ )
+ ax_bar.axhline(0, color="black", linewidth=0.6, linestyle="--", zorder=1)
+
+ ax_bar.set_ylabel("Cash flow")
+ ax_bar.legend(frameon=False, fontsize=9)
+ ax_bar.spines[["top", "right"]].set_visible(False)
+ ax_bar.tick_params(axis="x", which="both", bottom=False)
+ ax_bar.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f"{x:,.0f}"))
+
+ # --- bottom panel: cumulative net ---
+ # dates = dates.append()
+ positive = np.maximum(cumulative_net, 0)
+ negative = np.minimum(cumulative_net, 0)
+ ax_cum.fill_between(dates, positive, alpha=0.25, color="#4C9BE8", step="mid")
+ ax_cum.fill_between(dates, negative, alpha=0.25, color="#E8604C", step="mid")
+ # ax_cum.plot(dates, cumulative_net, color="black", linewidth=1.5, zorder=3)
+ ax_cum.axhline(0, color="black", linewidth=0.6, linestyle="--", zorder=1)
+
+ ax_cum.set_ylabel("Cumulative net")
+ ax_cum.spines[["top", "right"]].set_visible(False)
+ ax_cum.yaxis.set_major_formatter(plt.FuncFormatter(lambda x, _: f"{x:,.0f}"))
+
+ fig.autofmt_xdate(rotation=30, ha="right")
+ fig.suptitle(title or "Cash Flow Analysis", fontsize=13, y=1.01)
+ return (ax_bar, ax_cum)
+
+ def to_dataframe(self, impl_date, start_date, end_date) -> pd.DataFrame:
+ """Return cash flows as a formatted DataFrame."""
+ net, costs, incs = self.calc_cash_flows(impl_date, start_date, end_date)
+ periods = pd.period_range(start=start_date, end=end_date, freq=self.freq)
+
+ return pd.DataFrame(
+ {"date": periods, "net": net, "cost": costs, "income": incs}
+ )
+
+ @staticmethod
+ def comb_cost_income(cost_incomes: list["CostIncome"]) -> "CostIncome":
+ """Combine multiple CostIncomes together.
+
+ Combination sums the costs and incomes from all provided CostIncome
+ objects.
+ """
+
+ first_ci = cost_incomes[0]
+
+ if not all(
+ [
+ first_ci.mkt_price_year.year == c.mkt_price_year.year
+ for c in cost_incomes
+ ]
+ ):
+ raise ValueError(
+ "Measure cost incomes have different market price years, combination is not possible."
+ )
+
+ if not all(
+ [first_ci.cost_growth_rate == c.cost_growth_rate for c in cost_incomes]
+ ):
+ raise ValueError(
+ "Measure cost incomes have different cost_growth_rate, combination is not possible."
+ )
+
+ if not all(
+ [first_ci.income_growth_rate == c.income_growth_rate for c in cost_incomes]
+ ):
+ raise ValueError(
+ "Measure cost incomes have different income_growth_rate, combination is not possible."
+ )
+
+ return CostIncome(
+ mkt_price_year=first_ci.mkt_price_year.year,
+ cost_yearly_growth_rate=first_ci.cost_growth_rate,
+ init_cost=sum(c.init_cost for c in cost_incomes),
+ periodic_cost=sum(c.periodic_cost for c in cost_incomes),
+ periodic_income=sum(c.periodic_income for c in cost_incomes),
+ income_yearly_growth_rate=first_ci.income_growth_rate,
+ )
diff --git a/climada/entity/measures/measure_config.py b/climada/entity/measures/measure_config.py
new file mode 100644
index 0000000000..59f9278bba
--- /dev/null
+++ b/climada/entity/measures/measure_config.py
@@ -0,0 +1,642 @@
+"""
+This file is part of CLIMADA.
+
+Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.
+
+CLIMADA is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free
+Software Foundation, version 3.
+
+CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with CLIMADA. If not, see .
+
+---
+
+Define configuration dataclasses for Measure reading and writing.
+"""
+
+from __future__ import annotations
+
+import logging
+import warnings
+from abc import ABC
+from dataclasses import asdict, dataclass, field, fields
+from datetime import datetime
+from typing import Dict, Optional, Tuple, Union
+
+import numpy as np
+import pandas as pd
+
+LOGGER = logging.getLogger(__name__)
+
+
+@dataclass
+class _ModifierConfig(ABC):
+ """
+ Abstract base class for all modifier configuration dataclasses.
+
+ Provides shared serialization, deserialization, and representation
+ logic for all concrete modifier config subclasses. Not intended to
+ be instantiated directly.
+ """
+
+ def _filter_out_default_fields(self):
+ """
+ Partition the instance's fields into non-default and default groups.
+
+ The ``haz_type`` field is always excluded from the output, as it
+ is managed at the ``MeasureConfig`` level.
+
+ Returns
+ -------
+ non_defaults : dict
+ Fields whose current value differs from the dataclass default.
+ defaults : dict
+ Fields whose current value equals the dataclass default.
+ """
+
+ non_defaults = {}
+ defaults = {}
+ for defined_field in fields(self):
+ val = getattr(self, defined_field.name)
+ default = defined_field.default
+ if defined_field.default_factory is not field().default_factory:
+ default = defined_field.default_factory()
+
+ if val != default:
+ non_defaults[defined_field.name] = val
+ else:
+ defaults[defined_field.name] = val
+
+ if "haz_type" in non_defaults:
+ non_defaults.pop("haz_type")
+ return non_defaults, defaults
+
+ def to_dict(self):
+ """
+ Serialize the config to a flat dictionary, omitting default values.
+
+ The ``haz_type`` field is always excluded from the output, as it
+ is managed at the ``MeasureConfig`` level.
+
+ Returns
+ -------
+ dict
+ Dictionary containing only fields whose values differ from
+ their dataclass defaults.
+ """
+ non_default, _ = self._filter_out_default_fields()
+ return non_default
+
+ @classmethod
+ def from_dict(cls, kwargs_dict: dict):
+ """
+ Instantiate a config from a dictionary, ignoring unknown keys.
+
+ Parameters
+ ----------
+ kwargs_dict : dict
+ Input dictionary. Keys not matching any dataclass field are
+ silently discarded.
+
+ Returns
+ -------
+ _ModifierConfig
+ A new instance of the calling subclass.
+ """
+
+ filtered = cls._filter_dict_to_fields(kwargs_dict)
+ return cls(**filtered)
+
+ @classmethod
+ def _filter_dict_to_fields(cls, to_filter: dict):
+ """
+ Filter a dictionary to only the keys matching the dataclass fields.
+
+ Parameters
+ ----------
+ to_filter : dict
+ Input dictionary, potentially containing extra keys.
+
+ Returns
+ -------
+ dict
+ A copy of ``to_filter`` restricted to keys that correspond to declared
+ dataclass fields on this class.
+ """
+
+ filtered = dict(
+ filter(lambda k: k[0] in [f.name for f in fields(cls)], to_filter.items())
+ )
+ return filtered
+
+ def __repr__(self) -> str:
+ """
+ Return a human-readable representation highlighting non-default fields.
+
+ Non-default fields are shown prominently; default fields are shown
+ below them. This makes it easy to see at a glance what has been
+ configured on an instance.
+
+ Returns
+ -------
+ str
+ A formatted string representation of the instance.
+ """
+
+ non_defaults, defaults = self._filter_out_default_fields()
+ ndf_fields_str = (
+ "\n\t\t\t".join(f"{k}={v!r}" for k, v in non_defaults.items())
+ if non_defaults
+ else None
+ )
+ _ = (
+ "\n\t\t\t".join(f"{k}={v!r}" for k, v in defaults.items())
+ if defaults
+ else None
+ )
+ ndf_fields = (
+ "(" "\n\t\tNon default fields:" f"\n\t\t\t{ndf_fields_str}" "\n)"
+ if ndf_fields_str
+ else "()"
+ )
+ return f"{self.__class__.__name__}{ndf_fields}"
+
+
+@dataclass(repr=False)
+class ImpfsetModifierConfig(_ModifierConfig):
+ """
+ Configuration for modifications to an impact function set.
+
+ Supports scaling or shifting MDD, PAA, and intensity curves, as well
+ as replacement of the impact function set, loaded from a file path. If
+ both a new file path and modifier values are provided, modifiers are
+ applied after the replacement (and a warning is issued).
+
+ Parameters
+ ----------
+ haz_type : str
+ Hazard type identifier (e.g. ``"TC"``) that this modifier targets.
+ impf_ids : int or str or list of int or str, optional
+ Impact function ID(s) to which modifications are applied.
+ If ``None``, all impact functions are affected.
+ impf_mdd_mult : float, optional
+ Multiplicative factor applied to the mean damage degree (MDD) curve.
+ Default is ``1.0`` (no change).
+ impf_mdd_add : float, optional
+ Additive offset applied to the MDD curve after multiplication.
+ Default is ``0.0``.
+ impf_paa_mult : float, optional
+ Multiplicative factor applied to the percentage of affected assets
+ (PAA) curve. Default is ``1.0``.
+ impf_paa_add : float, optional
+ Additive offset applied to the PAA curve after multiplication.
+ Default is ``0.0``.
+ impf_int_mult : float, optional
+ Multiplicative factor applied to the intensity axis.
+ Default is ``1.0``.
+ impf_int_add : float, optional
+ Additive offset applied to the intensity axis after multiplication.
+ Default is ``0.0``.
+ new_impfset_path : str, optional
+ Path to an Excel file containing a replacement impact function set.
+ If provided alongside modifier values, a warning is issued and
+ modifiers are applied after loading the new set.
+
+ Warns
+ -----
+ UserWarning
+ If ``new_impfset_path`` is set alongside any non-default modifier
+ values.
+ """
+
+ haz_type: str
+ impf_ids: Optional[Union[int, str, list[Union[int, str]]]] = None
+ impf_mdd_mult: float = 1.0
+ impf_mdd_add: float = 0.0
+ impf_paa_mult: float = 1.0
+ impf_paa_add: float = 0.0
+ impf_int_mult: float = 1.0
+ impf_int_add: float = 0.0
+ new_impfset_path: Optional[str] = None
+
+ def __post_init__(self):
+ config = self.to_dict()
+ if "new_impfset_path" in config and any(
+ key in config
+ for key in [
+ "impf_mdd_add",
+ "impf_mdd_mult",
+ "impf_paa_add",
+ "impf_paa_mult",
+ "impf_int_add",
+ "impf_int_mult",
+ ]
+ ):
+ warnings.warn(
+ "Both new impfset object and impfset modifiers are provided, "
+ "modifiers will be applied after changing the impfset."
+ )
+
+
+@dataclass(repr=False)
+class HazardModifierConfig(_ModifierConfig):
+ """
+ Configuration for modifications to a hazard.
+
+ Supports scaling or shifting hazard intensity, applying a return-period
+ frequency cutoff, and replacement of the hazard, loaded from a file path.
+ If both a new file path and modifier values are provided, modifiers are
+ applied after the replacement.
+
+ Parameters
+ ----------
+ haz_type : str
+ Hazard type identifier (e.g. ``"TC"``) that this modifier targets.
+ haz_int_mult : float, optional
+ Multiplicative factor applied to hazard intensity.
+ Default is ``1.0`` (no change).
+ haz_int_add : float, optional
+ Additive offset applied to hazard intensity after multiplication.
+ Default is ``0.0``.
+ new_hazard_path : str, optional
+ Path to an HDF5 file containing a replacement hazard.
+ If provided alongside modifier values, a warning is issued and
+ modifiers are applied after loading the new hazard.
+ impact_rp_cutoff : float, optional
+ Return period (in years) below which hazard events are discarded.
+ If ``None``, no cutoff is applied.
+
+ Warns
+ -----
+ UserWarning
+ If ``new_hazard_path`` is set alongside any non-default modifier
+ values or a non-``None`` ``impact_rp_cutoff``.
+ """
+
+ haz_type: str
+ haz_int_mult: Optional[float] = 1.0
+ haz_int_add: Optional[float] = 0.0
+ haz_freq_mult: Optional[float] = 1.0
+ haz_freq_add: Optional[float] = 0.0
+ new_hazard_path: Optional[str] = None
+ impact_rp_cutoff: Optional[float] = None
+
+ def __post_init__(self):
+ config = self.to_dict()
+ if "new_hazard_path" in config and any(
+ key in config
+ for key in [
+ "haz_int_mult",
+ "haz_int_add",
+ "haz_freq_mult",
+ "haz_freq_add",
+ "impact_rp_cutoff",
+ ]
+ ):
+ warnings.warn(
+ "Both new hazard object and hazard modifiers are provided, "
+ "modifiers will be applied after changing the hazard."
+ )
+
+
+@dataclass(repr=False)
+class ExposuresModifierConfig(_ModifierConfig):
+ """
+ Configuration for modifications to an exposures object.
+
+ Supports remapping impact function IDs, zeroing out selected regions,
+ and replacement of the exposures from a new file. If both a new
+ file path and modifier values are provided, modifiers are applied after
+ the replacement.
+
+ Parameters
+ ----------
+ reassign_impf_id : dict of {str: dict of {int or str: int or str}}, optional
+ Nested mapping ``{haz_type: {old_id: new_id}}`` used to reassign
+ impact function IDs in the exposures. If ``None``, no remapping
+ is performed.
+ set_to_zero : list of int, optional
+ Region IDs for which exposure values are set to zero.
+ If ``None``, no zeroing is applied.
+ new_exposures_path : str, optional
+ Path to an HDF5 file containing replacement exposures.
+ If provided alongside modifier values, a warning is issued and
+ modifiers are applied after loading the new exposures.
+
+ Warns
+ -----
+ UserWarning
+ If ``new_exposures_path`` is set alongside any non-``None``
+ modifier values.
+ """
+
+ reassign_impf_id: Optional[Dict[str, Dict[int | str, int | str]]] = None
+ set_to_zero: Optional[list[int]] = None
+ new_exposures_path: Optional[str] = None
+
+ def __post_init__(self):
+ config = self.to_dict()
+ if "new_exposures_path" in config and any(
+ key in config for key in ["reassign_impf_id", "set_to_zero"]
+ ):
+ warnings.warn(
+ "Both new exposures object and exposures modifiers are provided, "
+ "modifiers will be applied after changing the exposures."
+ )
+
+
+@dataclass(repr=False)
+class CostIncomeConfig(_ModifierConfig):
+ """
+ Serializable configuration for a ``CostIncome`` object.
+
+ Encodes all parameters required to construct a ``CostIncome`` instance,
+ including optional custom cash flow schedules.
+
+ Parameters
+ ----------
+ mkt_price_year : int, optional
+ Reference year for market prices. Defaults to the current year.
+ init_cost : float, optional
+ One-time initial investment cost (positive value). Default is ``0.0``.
+ periodic_cost : float, optional
+ Recurring cost per period (positive value). Default is ``0.0``.
+ periodic_income : float, optional
+ Recurring income per period. Default is ``0.0``.
+ cost_yearly_growth_rate : float, optional
+ Annual growth rate applied to periodic costs. Default is ``0.0``.
+ income_yearly_growth_rate : float, optional
+ Annual growth rate applied to periodic income. Default is ``0.0``.
+ freq : str, optional
+ Pandas offset alias defining the period length (e.g. ``"Y"`` for
+ yearly, ``"M"`` for monthly). Default is ``"Y"``.
+ custom_cash_flows : list of dict, optional
+ Explicit cash flow schedule as a list of records with at minimum
+ a ``"date"`` key (ISO 8601 string) and a value key. If provided,
+ overrides the periodic cost/income logic.
+ """
+
+ mkt_price_year: Optional[int] = field(default_factory=lambda: datetime.today().year)
+ init_cost: float = 0.0
+ periodic_cost: float = 0.0
+ periodic_income: float = 0.0
+ cost_yearly_growth_rate: float = 0.0
+ income_yearly_growth_rate: float = 0.0
+ freq: str = "Y"
+ custom_cash_flows: Optional[list[dict]] = None
+
+ @classmethod
+ def from_cost_income(cls, cost_income: "CostIncome") -> "CostIncomeConfig":
+ """
+ Construct a :class:`CostIncomeConfig` from a live
+ :class:`CostIncome` object.
+
+ Parameters
+ ----------
+ cost_income : CostIncome
+ The live ``CostIncome`` instance to serialise.
+
+ Returns
+ -------
+ CostIncomeConfig
+ The config instance equivalent to the ``CostIncome``.
+ """
+
+ custom = None
+ if cost_income.custom_cash_flows is not None:
+ custom = (
+ cost_income.custom_cash_flows.reset_index()
+ .rename(columns={"index": "date"})
+ .assign(date=lambda df: df["date"].dt.strftime("%Y-%m-%d"))
+ .to_dict(orient="records")
+ )
+ return cls(
+ mkt_price_year=cost_income.mkt_price_year.year, # datetime → int
+ init_cost=abs(cost_income.init_cost), # stored negative → positive
+ periodic_cost=abs(cost_income.periodic_cost),
+ periodic_income=cost_income.periodic_income,
+ cost_yearly_growth_rate=cost_income.cost_growth_rate,
+ income_yearly_growth_rate=cost_income.income_growth_rate,
+ freq=cost_income.freq,
+ custom_cash_flows=custom,
+ )
+
+
+@dataclass(repr=False)
+class MeasureConfig(_ModifierConfig):
+ """
+ Top-level serializable configuration for a single adaptation measure.
+
+ Aggregates all modifier sub-configs (hazard, impact functions, exposures,
+ cost/income) into a single object that can be round-tripped through dict,
+ YAML, or a legacy Excel row.
+
+ This class is the primary entry point for defining measures in a
+ declarative, file-based workflow and serves as the serialization
+ counterpart to :class:`~climada.entity.measures.base.Measure`.
+
+ Parameters
+ ----------
+ name : str
+ Unique name identifying this measure.
+ haz_type : str
+ Hazard type identifier (e.g. ``"TC"``) this measure is designed for.
+ impfset_modifier : ImpfsetModifierConfig
+ Configuration describing modifications to the impact function set.
+ hazard_modifier : HazardModifierConfig
+ Configuration describing modifications to the hazard.
+ exposures_modifier : ExposuresModifierConfig
+ Configuration describing modifications to the exposures.
+ cost_income : CostIncomeConfig
+ Financial parameters associated with implementing this measure.
+ implementation_duration : str, optional
+ Pandas offset alias (e.g. ``"2Y"``) representing the time before
+ the measure is fully operational. If ``None``, the measure takes
+ effect immediately.
+ color_rgb : tuple of float, optional
+ RGB colour triple in the range ``[0, 1]`` used for visualisation.
+ If ``None``, defaults to black ``(0, 0, 0)``.
+ """
+
+ name: str
+ haz_type: str
+ impfset_modifier: ImpfsetModifierConfig
+ hazard_modifier: HazardModifierConfig
+ exposures_modifier: ExposuresModifierConfig
+ cost_income: CostIncomeConfig
+ implementation_duration: Optional[str] = None
+ color_rgb: Optional[Tuple[float, float, float]] = None
+
+ def __repr__(self) -> str:
+ """
+ Return a detailed string representation of the measure configuration.
+
+ All fields are shown, including sub-configs, with each on its own
+ indented line.
+
+ Returns
+ -------
+ str
+ A formatted multi-line string representation.
+ """
+
+ fields_str = "\n\t".join(f"{k}={v!r}" for k, v in self.__dict__.items())
+ return f"{self.__class__.__name__}(\n\t{fields_str})"
+
+ def to_dict(self) -> dict:
+ """
+ Serialize the measure configuration to a flat dictionary.
+
+ Sub-config dictionaries are merged into the top-level dict (i.e.
+ their keys are inlined, not nested). ``haz_type`` is always included
+ at the top level. Fields with ``None`` values are preserved.
+
+ Returns
+ -------
+ dict
+ Flat dictionary representation suitable for YAML or Excel
+ serialization.
+ """
+
+ return {
+ "name": self.name,
+ "haz_type": self.haz_type,
+ **self.impfset_modifier.to_dict(),
+ **self.hazard_modifier.to_dict(),
+ **self.exposures_modifier.to_dict(),
+ **self.cost_income.to_dict(),
+ "implementation_duration": self.implementation_duration,
+ "color_rgb": list(self.color_rgb) if self.color_rgb is not None else None,
+ }
+
+ @classmethod
+ def from_dict(cls, kwargs_dict: dict) -> "MeasureConfig":
+ """
+ Instantiate a :class:`MeasureConfig` from a flat dictionary.
+
+ Delegates sub-config construction to the respective
+ ``from_dict`` classmethods. Unknown keys are silently discarded
+ by each sub-config parser.
+
+ Parameters
+ ----------
+ kwargs_dict : dict
+ Flat dictionary, as produced by :meth:`to_dict` or read from
+ a legacy Excel row. Must contain at minimum ``"name"`` and
+ ``"haz_type"``.
+
+ Returns
+ -------
+ MeasureConfig
+ A fully populated configuration instance.
+ """
+
+ return cls(
+ name=kwargs_dict["name"],
+ haz_type=kwargs_dict["haz_type"],
+ impfset_modifier=ImpfsetModifierConfig.from_dict(kwargs_dict),
+ hazard_modifier=HazardModifierConfig.from_dict(kwargs_dict),
+ exposures_modifier=ExposuresModifierConfig.from_dict(kwargs_dict),
+ cost_income=CostIncomeConfig.from_dict(kwargs_dict),
+ implementation_duration=kwargs_dict.get("implementation_duration"),
+ color_rgb=cls._normalize_color(kwargs_dict.get("color_rgb")),
+ )
+
+ @staticmethod
+ def _normalize_color(color_rgb):
+ # 1. Handle None and NaN (np.nan, pd.NA, float('nan'))
+ if color_rgb is None or pd.isna(color_rgb) is True:
+ return None
+
+ # 2. Convert sequence types (list, np.array, tuple) to a standard tuple
+ try:
+ # Flatten in case it's a nested numpy array, then convert to tuple
+ result = tuple(np.array(color_rgb).flatten().tolist())
+
+ # 3. Enforce the length of three
+ if len(result) != 3:
+ raise ValueError(f"Expected 3 digits, got {len(result)}")
+
+ return result
+
+ except (TypeError, ValueError) as err:
+ # Handle cases where input isn't iterable or wrong length
+ raise ValueError(f"Invalid color format: {color_rgb}.") from err
+
+ def to_yaml(self, path: str) -> None:
+ """
+ Write this configuration to a YAML file.
+
+ The file is structured as ``{"measures": []}``,
+ matching the expected format for :meth:`from_yaml`.
+
+ Parameters
+ ----------
+ path : str
+ Destination file path. Will be created or overwritten.
+ """
+
+ import yaml
+
+ with open(path, "w") as opened_file:
+ yaml.dump(
+ {"measures": [self.to_dict()]},
+ opened_file,
+ default_flow_style=False,
+ sort_keys=False,
+ )
+
+ @classmethod
+ def from_yaml(cls, path: str) -> "MeasureConfig":
+ """
+ Load a :class:`MeasureConfig` from a YAML file.
+
+ Expects the file to contain a top-level ``"measures"`` list; reads
+ only the first entry.
+
+ Parameters
+ ----------
+ path : str
+ Path to the YAML file to read.
+
+ Returns
+ -------
+ MeasureConfig
+ The configuration parsed from the first entry in
+ ``measures``.
+ """
+
+ import yaml
+
+ with open(path) as opened_file:
+ return cls.from_dict(yaml.safe_load(opened_file)["measures"][0])
+
+ @classmethod
+ def from_row(cls, row: pd.Series) -> "MeasureConfig":
+ """
+ Construct a :class:`MeasureConfig` from a legacy Excel row.
+
+ Converts the row to a dictionary and delegates to :meth:`from_dict`.
+ This is the primary migration path for measures currently stored in
+ the legacy Excel-based ``MeasureSet`` format.
+
+ Parameters
+ ----------
+ row : pd.Series
+ A single row from a legacy measures Excel sheet, with column
+ names matching the flat dictionary keys expected by
+ :meth:`from_dict`.
+
+ Returns
+ -------
+ MeasureConfig
+ A configuration instance populated from the row data.
+ """
+
+ row_dict = row.to_dict()
+ return cls.from_dict(row_dict)
diff --git a/climada/entity/measures/test/test_cost_income.py b/climada/entity/measures/test/test_cost_income.py
new file mode 100644
index 0000000000..f9d6667db3
--- /dev/null
+++ b/climada/entity/measures/test/test_cost_income.py
@@ -0,0 +1,405 @@
+"""
+This file is part of CLIMADA.
+
+Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.
+
+CLIMADA is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free
+Software Foundation, version 3.
+
+CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with CLIMADA. If not, see .
+
+---
+
+Unit tests for the CostIncome class.
+"""
+
+from datetime import datetime
+from unittest.mock import MagicMock, patch
+
+import numpy as np
+import pandas as pd
+import pytest
+
+from climada.entity.disc_rates.base import DiscRates
+from climada.entity.measures.cost_income import CostIncome
+
+# ---------------------------------------------------------------------------
+# Helpers
+# ---------------------------------------------------------------------------
+
+
+def make_disc_rates(years=None, rates=None):
+ """Build a minimal DiscRates stub."""
+ dr = MagicMock(spec=DiscRates)
+ dr.years = np.array(years or list(range(2020, 2031)))
+ dr.rates = np.array(rates or [0.05] * len(dr.years))
+ return dr
+
+
+# ---------------------------------------------------------------------------
+# __init__ / construction
+# ---------------------------------------------------------------------------
+
+
+class TestInit:
+ def test_defaults(self):
+ ci = CostIncome()
+ assert ci.init_cost == 0.0
+ assert ci.periodic_cost == 0.0
+ assert ci.periodic_income == 0.0
+ assert ci.cost_growth_rate == 0.0
+ assert ci.income_growth_rate == 0.0
+ assert ci.freq == "Y"
+ assert ci.custom_cash_flows is None
+
+ def test_costs_stored_negative(self):
+ ci = CostIncome(init_cost=100, periodic_cost=50)
+ assert ci.init_cost == -100.0
+ assert ci.periodic_cost == -50.0
+
+ def test_costs_already_negative_stay_negative(self):
+ ci = CostIncome(init_cost=-200, periodic_cost=-30)
+ assert ci.init_cost == -200.0
+ assert ci.periodic_cost == -30.0
+
+ def test_income_stored_positive(self):
+ ci = CostIncome(periodic_income=-80)
+ assert ci.periodic_income == 80.0
+
+ def test_mkt_price_year_default_is_current_year(self):
+ ci = CostIncome()
+ assert ci.mkt_price_year.year == datetime.today().year
+
+ def test_mkt_price_year_custom(self):
+ ci = CostIncome(mkt_price_year=2015)
+ assert ci.mkt_price_year.year == 2015
+
+ def test_custom_cash_flows_processed(self):
+ df = pd.DataFrame(
+ {
+ "date": ["2020-01-01", "2020-06-01"],
+ "cost": [100, 200],
+ "income": [50, 60],
+ }
+ )
+ ci = CostIncome(custom_cash_flows=df, freq="Y")
+ # After resampling to yearly, should have one row per year
+ assert isinstance(ci.custom_cash_flows, pd.DataFrame)
+ assert "cost" in ci.custom_cash_flows.columns
+ # Costs should be negative after processing
+ assert (ci.custom_cash_flows["cost"] <= 0).all()
+
+
+# ---------------------------------------------------------------------------
+# from_dict / from_config / from_yaml
+# ---------------------------------------------------------------------------
+
+
+class TestFromDict:
+ def test_basic(self):
+ d = {
+ "mkt_price_year": 2020,
+ "init_cost": 500,
+ "periodic_cost": 100,
+ "periodic_income": 200,
+ "cost_yearly_growth_rate": 0.02,
+ "income_yearly_growth_rate": 0.03,
+ "freq": "Y",
+ }
+ ci = CostIncome.from_dict(d)
+ assert ci.init_cost == -500.0
+ assert ci.periodic_income == 200.0
+ assert ci.cost_growth_rate == 0.02
+
+ def test_defaults_for_missing_keys(self):
+ ci = CostIncome.from_dict({})
+ assert ci.init_cost == 0.0
+ assert ci.freq == "Y"
+
+ def test_with_custom_cash_flows(self):
+ d = {
+ "freq": "Y",
+ "custom_cash_flows": [
+ {"date": "2021-01-01", "cost": 100, "income": 50},
+ ],
+ }
+ ci = CostIncome.from_dict(d)
+ assert ci.custom_cash_flows is not None
+
+
+class TestFromYaml:
+ def test_from_yaml(self, tmp_path):
+ yaml_content = """
+cost_income:
+ mkt_price_year: 2020
+ init_cost: 1000
+ periodic_cost: 200
+ periodic_income: 300
+ cost_yearly_growth_rate: 0.01
+ income_yearly_growth_rate: 0.02
+ freq: Y
+"""
+ p = tmp_path / "ci.yaml"
+ p.write_text(yaml_content)
+ ci = CostIncome.from_yaml(str(p))
+ assert ci.init_cost == -1000.0
+ assert ci.periodic_income == 300.0
+
+
+# ---------------------------------------------------------------------------
+# _freq_to_days
+# ---------------------------------------------------------------------------
+
+
+class TestFreqToDays:
+ def test_yearly(self):
+ result = CostIncome._freq_to_days("Y")
+ assert result == "365d"
+
+ def test_monthly(self):
+ result = CostIncome._freq_to_days("M")
+ assert result == "30d"
+
+ def test_daily(self):
+ result = CostIncome._freq_to_days("D")
+ assert result == "1d"
+
+ def test_invalid(self):
+ with pytest.raises(ValueError):
+ CostIncome._freq_to_days("INVALID_FREQ_XYZ")
+
+
+# ---------------------------------------------------------------------------
+# _get_width_days
+# ---------------------------------------------------------------------------
+
+
+class TestGetWidthDays:
+ def test_yearly(self):
+ ci = CostIncome(freq="Y")
+ assert ci._get_width_days() == 365.0
+
+ def test_3yearly(self):
+ ci = CostIncome(freq="3Y")
+ assert ci._get_width_days() == 3 * 365.0
+
+ def test_monthly(self):
+ ci = CostIncome(freq="M")
+ assert ci._get_width_days() == 30.0
+
+ def test_daily(self):
+ ci = CostIncome(freq="D")
+ assert ci._get_width_days() == 1.0
+
+
+# ---------------------------------------------------------------------------
+# _calc_at_date
+# ---------------------------------------------------------------------------
+
+
+class TestCalcAtDate:
+ def test_before_impl_date_is_zero(self):
+ ci = CostIncome(mkt_price_year=2020, init_cost=1000, periodic_income=500)
+ impl = pd.Timestamp("2021-01-01")
+ curr = pd.Timestamp("2020-01-01")
+ net, cost, inc = ci._calc_at_date(impl, curr)
+ assert net == 0.0
+ assert cost == 0.0
+ assert inc == 0.0
+
+ def test_at_impl_date_uses_init_cost(self):
+ ci = CostIncome(mkt_price_year=2021, init_cost=1000, periodic_income=0)
+ impl = pd.Timestamp("2021-01-01")
+ net, cost, inc = ci._calc_at_date(impl, impl)
+ assert cost == pytest.approx(-1000.0, rel=1e-3)
+ assert inc == pytest.approx(0.0)
+
+ def test_after_impl_date_uses_periodic_cost(self):
+ ci = CostIncome(mkt_price_year=2020, periodic_cost=200, periodic_income=0)
+ impl = pd.Timestamp("2021-01-01")
+ curr = pd.Timestamp("2022-01-01")
+ net, cost, inc = ci._calc_at_date(impl, curr)
+ assert cost < 0
+ assert abs(cost) == 200
+
+ def test_income_growth_applied(self):
+ ci = CostIncome(
+ mkt_price_year=2020, periodic_income=100, income_yearly_growth_rate=0.10
+ )
+ impl = pd.Timestamp("2020-01-01")
+ curr = pd.Timestamp("2021-01-01")
+ _, _, inc = ci._calc_at_date(impl, curr)
+ expected = 100 * (1.10**1.0)
+ assert inc == pytest.approx(expected, rel=1e-2)
+
+ def test_net_equals_income_plus_cost(self):
+ ci = CostIncome(mkt_price_year=2020, periodic_cost=100, periodic_income=150)
+ impl = pd.Timestamp("2020-01-01")
+ curr = pd.Timestamp("2021-01-01")
+ net, cost, inc = ci._calc_at_date(impl, curr)
+ assert net == pytest.approx(cost + inc)
+
+ def test_custom_cash_flows_added(self):
+ df = pd.DataFrame(
+ {
+ "date": ["2021-01-01"],
+ "cost": [500.0],
+ "income": [200.0],
+ }
+ )
+ ci = CostIncome(mkt_price_year=2021, custom_cash_flows=df, freq="Y")
+ print(ci.custom_cash_flows)
+ impl = pd.Timestamp("2021-01-01")
+ curr = pd.Timestamp("2021-01-01")
+ net, cost, inc = ci._calc_at_date(impl, curr)
+ assert inc == pytest.approx(200.0, rel=1e-3)
+ assert cost == pytest.approx(-500.0, rel=1e-3)
+
+
+# ---------------------------------------------------------------------------
+# calc_cash_flows
+# ---------------------------------------------------------------------------
+
+
+class TestCalcCashFlows:
+ def test_returns_three_arrays(self):
+ ci = CostIncome(mkt_price_year=2020, periodic_income=100)
+ net, costs, incs = ci.calc_cash_flows("2020-01-01", "2020-01-01", "2025-01-01")
+ assert isinstance(net, np.ndarray)
+ assert isinstance(costs, np.ndarray)
+ assert isinstance(incs, np.ndarray)
+
+ def test_length_matches_periods(self):
+ ci = CostIncome(freq="Y")
+ net, costs, incs = ci.calc_cash_flows("2020-01-01", "2020-01-01", "2024-01-01")
+ periods = pd.period_range("2020-01-01", "2024-01-01", freq="Y")
+ assert len(net) == len(periods)
+
+ def test_zero_cost_income(self):
+ ci = CostIncome()
+ net, costs, incs = ci.calc_cash_flows("2020-01-01", "2020-01-01", "2023-01-01")
+ np.testing.assert_array_equal(net, 0.0)
+
+ def test_nonzero_cost_income(self):
+ ci = CostIncome(
+ mkt_price_year=2020, init_cost=5000, periodic_cost=200, periodic_income=1000
+ )
+ net, cost, income = ci.calc_cash_flows(
+ impl_date="2020-01-01", start_date="2019-01-01", end_date="2025-01-01"
+ )
+ np.testing.assert_array_equal(
+ net, [0.0, -5000.0, 800.0, 800.0, 800.0, 800.0, 800.0]
+ )
+ np.testing.assert_array_equal(
+ cost, [0.0, -5000.0, -200.0, -200.0, -200.0, -200.0, -200.0]
+ )
+ np.testing.assert_array_equal(
+ income, [0.0, 0.0, 1000.0, 1000.0, 1000.0, 1000.0, 1000.0]
+ )
+
+
+# ---------------------------------------------------------------------------
+# calc_total
+# ---------------------------------------------------------------------------
+
+
+class TestCalcTotal:
+ def test_total_is_sum_of_cash_flows(self):
+ ci = CostIncome(mkt_price_year=2020, periodic_income=100, periodic_cost=50)
+ net_arr, cost_arr, inc_arr = ci.calc_cash_flows(
+ "2020-01-01", "2020-01-01", "2024-01-01"
+ )
+ total_net, total_cost, total_inc = ci.calc_total(
+ "2020-01-01", "2020-01-01", "2024-01-01"
+ )
+ assert total_net == pytest.approx(float(np.sum(net_arr)))
+ assert total_cost == pytest.approx(float(np.sum(cost_arr)))
+ assert total_inc == pytest.approx(float(np.sum(inc_arr)))
+
+ def test_returns_floats(self):
+ ci = CostIncome()
+ result = ci.calc_total("2020-01-01", "2020-01-01", "2022-01-01")
+ assert all(isinstance(v, (float, np.floating)) for v in result)
+
+
+# ---------------------------------------------------------------------------
+# to_dataframe
+# ---------------------------------------------------------------------------
+
+
+class TestToDataframe:
+ def test_columns(self):
+ ci = CostIncome(periodic_income=100)
+ df = ci.to_dataframe("2020-01-01", "2020-01-01", "2023-01-01")
+ assert set(df.columns) == {"date", "net", "cost", "income"}
+
+ def test_row_count(self):
+ ci = CostIncome(freq="Y")
+ df = ci.to_dataframe("2020-01-01", "2020-01-01", "2022-01-01")
+ expected = len(pd.period_range("2020-01-01", "2022-01-01", freq="Y"))
+ assert len(df) == expected
+
+
+# ---------------------------------------------------------------------------
+# comb_cost_income
+# ---------------------------------------------------------------------------
+
+
+class TestCombCostIncome:
+ def test_costs_are_summed(self):
+ ci1 = CostIncome(mkt_price_year=2020, init_cost=100, periodic_cost=50)
+ ci2 = CostIncome(mkt_price_year=2020, init_cost=200, periodic_cost=30)
+ combined = CostIncome.comb_cost_income([ci1, ci2])
+ assert combined.init_cost == -300.0
+ assert combined.periodic_cost == -80.0
+
+ def test_incomes_are_summed(self):
+ ci1 = CostIncome(mkt_price_year=2020, periodic_income=100)
+ ci2 = CostIncome(mkt_price_year=2020, periodic_income=200)
+ combined = CostIncome.comb_cost_income([ci1, ci2])
+ assert combined.periodic_income == 300.0
+
+ def test_mismatched_mkt_price_year_raises(self):
+ ci1 = CostIncome(mkt_price_year=2020)
+ ci2 = CostIncome(mkt_price_year=2021)
+ with pytest.raises(ValueError, match="market price years"):
+ CostIncome.comb_cost_income([ci1, ci2])
+
+ def test_mismatched_cost_growth_rate_raises(self):
+ ci1 = CostIncome(mkt_price_year=2020, cost_yearly_growth_rate=0.02)
+ ci2 = CostIncome(mkt_price_year=2020, cost_yearly_growth_rate=0.05)
+ with pytest.raises(ValueError, match="cost_growth_rate"):
+ CostIncome.comb_cost_income([ci1, ci2])
+
+ def test_mismatched_income_growth_rate_raises(self):
+ ci1 = CostIncome(mkt_price_year=2020, income_yearly_growth_rate=0.01)
+ ci2 = CostIncome(mkt_price_year=2020, income_yearly_growth_rate=0.03)
+ with pytest.raises(ValueError, match="income_growth_rate"):
+ CostIncome.comb_cost_income([ci1, ci2])
+
+ def test_single_element_list(self):
+ ci = CostIncome(mkt_price_year=2020, init_cost=500, periodic_income=100)
+ combined = CostIncome.comb_cost_income([ci])
+ assert combined.init_cost == -500.0
+ assert combined.periodic_income == 100.0
+
+ def test_preserves_growth_rates(self):
+ ci1 = CostIncome(
+ mkt_price_year=2020,
+ cost_yearly_growth_rate=0.02,
+ income_yearly_growth_rate=0.03,
+ )
+ ci2 = CostIncome(
+ mkt_price_year=2020,
+ cost_yearly_growth_rate=0.02,
+ income_yearly_growth_rate=0.03,
+ )
+ combined = CostIncome.comb_cost_income([ci1, ci2])
+ assert combined.cost_growth_rate == 0.02
+ assert combined.income_growth_rate == 0.03
diff --git a/climada/entity/measures/test/test_measure_config.py b/climada/entity/measures/test/test_measure_config.py
new file mode 100644
index 0000000000..5f0d54badb
--- /dev/null
+++ b/climada/entity/measures/test/test_measure_config.py
@@ -0,0 +1,515 @@
+"""
+This file is part of CLIMADA.
+
+Copyright (C) 2017 ETH Zurich, CLIMADA contributors listed in AUTHORS.
+
+CLIMADA is free software: you can redistribute it and/or modify it under the
+terms of the GNU General Public License as published by the Free
+Software Foundation, version 3.
+
+CLIMADA is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+PARTICULAR PURPOSE. See the GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License along
+with CLIMADA. If not, see .
+
+---
+
+Tests for MeasureConfig and related dataclasses.
+"""
+
+# tests/entity/measures/test_measure_config.py
+
+import logging
+import warnings
+from datetime import datetime
+
+import pandas as pd
+import pytest
+
+from climada.entity.measures.measure_config import (
+ CostIncomeConfig,
+ ExposuresModifierConfig,
+ HazardModifierConfig,
+ ImpfsetModifierConfig,
+ MeasureConfig,
+)
+
+# ---------------------------------------------------------------------------
+# Fixtures
+# ---------------------------------------------------------------------------
+
+
+@pytest.fixture
+def minimal_measure_dict():
+ return {"name": "seawall", "haz_type": "TC"}
+
+
+@pytest.fixture
+def full_measure_dict():
+ return {
+ "name": "seawall",
+ "haz_type": "TC",
+ "haz_int_mult": 0.8,
+ "haz_int_add": -0.1,
+ "impf_mdd_mult": 0.9,
+ "impf_paa_mult": 0.95,
+ "impf_ids": [1, 2],
+ "reassign_impf_id": {"TC": {1: 3}},
+ "set_to_zero": [10, 20],
+ "init_cost": 1000.0,
+ "periodic_cost": 50.0,
+ "color_rgb": [0.1, 0.5, 0.9],
+ "implementation_duration": "2Y",
+ }
+
+
+@pytest.fixture
+def basic_impfset_config():
+ return ImpfsetModifierConfig(haz_type="TC", impf_mdd_mult=0.9)
+
+
+@pytest.fixture
+def basic_hazard_config():
+ return HazardModifierConfig(haz_type="TC", haz_int_mult=0.8)
+
+
+@pytest.fixture
+def basic_exposures_config():
+ return ExposuresModifierConfig(reassign_impf_id={"TC": {1: 2}})
+
+
+@pytest.fixture
+def basic_cost_income_config():
+ return CostIncomeConfig(init_cost=1000.0, periodic_cost=50.0)
+
+
+@pytest.fixture
+def full_measure_config(full_measure_dict):
+ return MeasureConfig.from_dict(full_measure_dict)
+
+
+# ---------------------------------------------------------------------------
+# _ModifierConfig (via concrete subclasses)
+# ---------------------------------------------------------------------------
+
+
+def test_modifier_config_to_dict_omits_defaults():
+ config = ImpfsetModifierConfig(haz_type="TC")
+ result = config.to_dict()
+ assert result == {}
+
+
+def test_modifier_config_to_dict_includes_non_defaults():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_mdd_mult=0.5, impf_paa_add=0.1)
+ result = config.to_dict()
+ assert result["impf_mdd_mult"] == 0.5
+ assert result["impf_paa_add"] == 0.1
+
+
+def test_modifier_config_from_dict_ignores_unknown_keys():
+ d = {"haz_type": "TC", "unknown_field": 99, "another_unknown": "foo"}
+ config = ImpfsetModifierConfig.from_dict(d)
+ assert config.haz_type == "TC"
+ assert not hasattr(config, "unknown_field")
+
+
+def test_modifier_config_from_dict_roundtrip():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_mdd_mult=0.5, impf_paa_add=0.1)
+ d = {**config.to_dict(), "haz_type": "TC"}
+ recovered = ImpfsetModifierConfig.from_dict(d)
+ assert recovered.impf_mdd_mult == config.impf_mdd_mult
+ assert recovered.impf_paa_add == config.impf_paa_add
+
+
+def test_modifier_config_filter_dict_to_fields_filters_extra_keys():
+ d = {"haz_type": "TC", "impf_mdd_mult": 0.5, "not_a_field": 123}
+ filtered = ImpfsetModifierConfig._filter_dict_to_fields(d)
+ assert "not_a_field" not in filtered
+ assert "haz_type" in filtered
+ assert "impf_mdd_mult" in filtered
+ assert filtered["haz_type"] == "TC"
+ assert filtered["impf_mdd_mult"] == 0.5
+
+
+def test_modifier_config_filter_out_default_fields_partitions_correctly():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_mdd_mult=0.5)
+ non_defaults, defaults = config._filter_out_default_fields()
+ assert "impf_mdd_mult" in non_defaults
+ assert "impf_mdd_mult" not in defaults
+ assert "impf_paa_mult" in defaults
+ assert "impf_paa_mult" not in non_defaults
+ from dataclasses import fields
+
+ all_field_names = {f.name for f in fields(config) if f.name != "haz_type"}
+ assert set(non_defaults) | set(defaults) == all_field_names
+
+
+def test_modifier_config_repr_shows_non_defaults_prominently():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_mdd_mult=0.5)
+ r = repr(config)
+ assert "Non default fields" in r
+ assert "impf_mdd_mult" in r
+
+
+def test_modifier_config_repr_empty_when_all_defaults():
+ config = ImpfsetModifierConfig(haz_type="TC")
+ r = repr(config)
+ assert "Non default fields" not in r
+
+
+# ---------------------------------------------------------------------------
+# ImpfsetModifierConfig
+# ---------------------------------------------------------------------------
+
+
+def test_impfset_modifier_config_defaults():
+ config = ImpfsetModifierConfig(haz_type="TC")
+ assert config.impf_ids is None
+ assert config.impf_mdd_mult == 1.0
+ assert config.impf_mdd_add == 0.0
+ assert config.impf_paa_mult == 1.0
+ assert config.impf_paa_add == 0.0
+ assert config.impf_int_mult == 1.0
+ assert config.impf_int_add == 0.0
+ assert config.new_impfset_path is None
+
+
+def test_impfset_modifier_config_from_dict_roundtrip():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_mdd_mult=0.8, impf_ids=[1, 2])
+ d = {**config.to_dict(), "haz_type": "TC"}
+ recovered = ImpfsetModifierConfig.from_dict(d)
+ assert recovered.impf_mdd_mult == config.impf_mdd_mult
+ assert recovered.impf_ids == config.impf_ids
+
+
+def test_impfset_modifier_config_to_dict_roundtrip():
+ d = {"haz_type": "TC", "impf_mdd_mult": 0.8, "impf_paa_add": 0.05}
+ config = ImpfsetModifierConfig.from_dict(d)
+ result = {**config.to_dict(), "haz_type": "TC"}
+ assert result["impf_mdd_mult"] == d["impf_mdd_mult"]
+ assert result["impf_paa_add"] == d["impf_paa_add"]
+
+
+def test_impfset_modifier_config_warns_when_path_and_modifiers_combined():
+ with pytest.warns(UserWarning):
+ ImpfsetModifierConfig(
+ haz_type="TC",
+ new_impfset_path="path/to/file.xlsx",
+ impf_mdd_mult=0.5,
+ )
+
+
+def test_impfset_modifier_config_no_warning_when_only_path():
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+ ImpfsetModifierConfig(haz_type="TC", new_impfset_path="path/to/file.xlsx")
+
+
+def test_impfset_modifier_config_no_warning_when_only_modifiers():
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+ ImpfsetModifierConfig(haz_type="TC", impf_mdd_mult=0.5)
+
+
+def test_impfset_modifier_config_impf_ids_accepts_int():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_ids=1)
+ assert config.impf_ids == 1
+
+
+def test_impfset_modifier_config_impf_ids_accepts_str():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_ids="1")
+ assert config.impf_ids == "1"
+
+
+def test_impfset_modifier_config_impf_ids_accepts_list():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_ids=[1, 2, "3"])
+ assert config.impf_ids == [1, 2, "3"]
+
+
+def test_impfset_modifier_config_impf_ids_accepts_none():
+ config = ImpfsetModifierConfig(haz_type="TC", impf_ids=None)
+ assert config.impf_ids is None
+
+
+# ---------------------------------------------------------------------------
+# HazardModifierConfig
+# ---------------------------------------------------------------------------
+
+
+def test_hazard_modifier_config_defaults():
+ config = HazardModifierConfig(haz_type="TC")
+ assert config.haz_int_mult == 1.0
+ assert config.haz_int_add == 0.0
+ assert config.new_hazard_path is None
+ assert config.impact_rp_cutoff is None
+
+
+def test_hazard_modifier_config_from_dict_roundtrip():
+ config = HazardModifierConfig(haz_type="TC", haz_int_mult=0.8, haz_int_add=-0.1)
+ d = {**config.to_dict(), "haz_type": "TC"}
+ recovered = HazardModifierConfig.from_dict(d)
+ assert recovered.haz_int_mult == config.haz_int_mult
+ assert recovered.haz_int_add == config.haz_int_add
+
+
+def test_hazard_modifier_config_to_dict_roundtrip():
+ d = {"haz_type": "TC", "haz_int_mult": 0.7, "haz_int_add": -0.2}
+ config = HazardModifierConfig.from_dict(d)
+ result = {**config.to_dict(), "haz_type": "TC"}
+ assert result["haz_int_mult"] == d["haz_int_mult"]
+ assert result["haz_int_add"] == d["haz_int_add"]
+
+
+def test_hazard_modifier_config_warns_when_path_and_modifiers_combined():
+ with pytest.warns(UserWarning):
+ HazardModifierConfig(
+ haz_type="TC",
+ new_hazard_path="path/to/hazard.h5",
+ haz_int_mult=0.5,
+ )
+
+
+def test_hazard_modifier_config_warns_when_path_and_rp_cutoff_combined():
+ with pytest.warns(UserWarning):
+ HazardModifierConfig(
+ haz_type="TC",
+ new_hazard_path="path/to/hazard.h5",
+ impact_rp_cutoff=100.0,
+ )
+
+
+def test_hazard_modifier_config_no_warning_when_only_path():
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+ HazardModifierConfig(haz_type="TC", new_hazard_path="path/to/hazard.h5")
+
+
+def test_hazard_modifier_config_no_warning_when_only_modifiers():
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+ HazardModifierConfig(haz_type="TC", haz_int_mult=0.5)
+
+
+# ---------------------------------------------------------------------------
+# ExposuresModifierConfig
+# ---------------------------------------------------------------------------
+
+
+def test_exposures_modifier_config_defaults():
+ config = ExposuresModifierConfig()
+ assert config.reassign_impf_id is None
+ assert config.set_to_zero is None
+ assert config.new_exposures_path is None
+
+
+def test_exposures_modifier_config_from_dict_roundtrip():
+ config = ExposuresModifierConfig(
+ reassign_impf_id={"TC": {1: 2}},
+ set_to_zero=[10, 20],
+ )
+ d = config.to_dict()
+ recovered = ExposuresModifierConfig.from_dict(d)
+ assert recovered.reassign_impf_id == config.reassign_impf_id
+ assert recovered.set_to_zero == config.set_to_zero
+
+
+def test_exposures_modifier_config_to_dict_roundtrip():
+ d = {"reassign_impf_id": {"TC": {1: 2}}, "set_to_zero": [5, 6]}
+ config = ExposuresModifierConfig.from_dict(d)
+ result = config.to_dict()
+ assert result["reassign_impf_id"] == d["reassign_impf_id"]
+ assert result["set_to_zero"] == d["set_to_zero"]
+
+
+def test_exposures_modifier_config_warns_when_path_and_modifiers_combined():
+ with pytest.warns(UserWarning):
+ ExposuresModifierConfig(
+ new_exposures_path="path/to/exp.h5",
+ reassign_impf_id={"TC": {1: 2}},
+ )
+
+
+def test_exposures_modifier_config_no_warning_when_only_path():
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+ ExposuresModifierConfig(new_exposures_path="path/to/exp.h5")
+
+
+def test_exposures_modifier_config_no_warning_when_only_modifiers():
+ with warnings.catch_warnings():
+ warnings.simplefilter("error")
+ ExposuresModifierConfig(reassign_impf_id={"TC": {1: 2}})
+
+
+def test_exposures_modifier_config_reassign_impf_id_accepts_int_keys():
+ config = ExposuresModifierConfig(reassign_impf_id={"TC": {1: 2}})
+ assert config.reassign_impf_id == {"TC": {1: 2}}
+
+
+def test_exposures_modifier_config_reassign_impf_id_accepts_str_keys():
+ config = ExposuresModifierConfig(reassign_impf_id={"TC": {"1": "2"}})
+ assert config.reassign_impf_id == {"TC": {"1": "2"}}
+
+
+def test_exposures_modifier_config_set_to_zero_accepts_none():
+ config = ExposuresModifierConfig(set_to_zero=None)
+ assert config.set_to_zero is None
+
+
+def test_exposures_modifier_config_set_to_zero_accepts_list():
+ config = ExposuresModifierConfig(set_to_zero=[1, 2, 3])
+ assert config.set_to_zero == [1, 2, 3]
+
+
+# ---------------------------------------------------------------------------
+# CostIncomeConfig
+# ---------------------------------------------------------------------------
+
+
+def test_cost_income_config_defaults():
+ config = CostIncomeConfig()
+ assert config.init_cost == 0.0
+ assert config.periodic_cost == 0.0
+ assert config.periodic_income == 0.0
+ assert config.cost_yearly_growth_rate == 0.0
+ assert config.income_yearly_growth_rate == 0.0
+ assert config.freq == "Y"
+ assert config.custom_cash_flows is None
+
+
+def test_cost_income_config_default_mkt_price_year_is_current_year():
+ config = CostIncomeConfig()
+ assert config.mkt_price_year == datetime.today().year
+
+
+def test_cost_income_config_from_dict_roundtrip():
+ config = CostIncomeConfig(init_cost=1000.0, periodic_cost=50.0, freq="M")
+ d = config.to_dict()
+ recovered = CostIncomeConfig.from_dict(d)
+ assert recovered.init_cost == config.init_cost
+ assert recovered.periodic_cost == config.periodic_cost
+ assert recovered.freq == config.freq
+
+
+def test_cost_income_config_to_dict_roundtrip():
+ d = {"init_cost": 500.0, "periodic_income": 20.0, "freq": "M"}
+ config = CostIncomeConfig.from_dict(d)
+ result = config.to_dict()
+ assert result["init_cost"] == d["init_cost"]
+ assert result["periodic_income"] == d["periodic_income"]
+ assert result["freq"] == d["freq"]
+
+
+# ---------------------------------------------------------------------------
+# MeasureConfig
+# ---------------------------------------------------------------------------
+
+
+def test_measure_config_from_dict_minimal(minimal_measure_dict):
+ config = MeasureConfig.from_dict(minimal_measure_dict)
+ assert config.name == "seawall"
+ assert config.haz_type == "TC"
+ assert config.impfset_modifier == ImpfsetModifierConfig(haz_type="TC")
+ assert config.hazard_modifier == HazardModifierConfig(haz_type="TC")
+ assert config.exposures_modifier == ExposuresModifierConfig()
+ assert config.cost_income == CostIncomeConfig()
+
+
+def test_measure_config_from_dict_full(full_measure_dict):
+ config = MeasureConfig.from_dict(full_measure_dict)
+ assert config.hazard_modifier.haz_int_mult == full_measure_dict["haz_int_mult"]
+ assert config.impfset_modifier.impf_mdd_mult == full_measure_dict["impf_mdd_mult"]
+ assert config.exposures_modifier.set_to_zero == full_measure_dict["set_to_zero"]
+ assert config.cost_income.init_cost == full_measure_dict["init_cost"]
+ assert config.color_rgb == tuple(full_measure_dict["color_rgb"])
+ assert (
+ config.implementation_duration == full_measure_dict["implementation_duration"]
+ )
+
+
+def test_measure_config_from_dict_ignores_unknown_keys(minimal_measure_dict):
+ d = {**minimal_measure_dict, "completely_unknown": 42}
+ config = MeasureConfig.from_dict(d)
+ assert config.name == "seawall"
+ assert not hasattr(config, "completely_unknown")
+
+
+def test_measure_config_to_dict_roundtrip(full_measure_dict):
+ config = MeasureConfig.from_dict(full_measure_dict)
+ recovered = MeasureConfig.from_dict(config.to_dict())
+ assert recovered.name == config.name
+ assert recovered.haz_type == config.haz_type
+ assert recovered.hazard_modifier == config.hazard_modifier
+ assert recovered.impfset_modifier == config.impfset_modifier
+ assert recovered.exposures_modifier == config.exposures_modifier
+ assert recovered.color_rgb == config.color_rgb
+ assert recovered.implementation_duration == config.implementation_duration
+
+
+def test_measure_config_to_dict_color_rgb_none(minimal_measure_dict):
+ config = MeasureConfig.from_dict(minimal_measure_dict)
+ result = config.to_dict()
+ assert result["color_rgb"] is None
+
+
+def test_measure_config_to_dict_color_rgb_set(minimal_measure_dict):
+ config = MeasureConfig.from_dict(
+ {**minimal_measure_dict, "color_rgb": [0.1, 0.5, 0.9]}
+ )
+ result = config.to_dict()
+ assert result["color_rgb"] == [0.1, 0.5, 0.9]
+
+
+def test_measure_config_to_yaml_roundtrip(tmp_path, full_measure_dict):
+ path = str(tmp_path / "measure.yaml")
+ config = MeasureConfig.from_dict(full_measure_dict)
+ config.to_yaml(path)
+ recovered = MeasureConfig.from_yaml(path)
+ assert recovered.name == config.name
+ assert recovered.haz_type == config.haz_type
+ assert recovered.hazard_modifier == config.hazard_modifier
+ assert recovered.impfset_modifier == config.impfset_modifier
+ assert recovered.color_rgb == config.color_rgb
+
+
+def test_measure_config_from_yaml_reads_first_entry(tmp_path, full_measure_dict):
+ import yaml
+
+ second = {**full_measure_dict, "name": "second_measure"}
+ path = str(tmp_path / "measures.yaml")
+ with open(path, "w") as f:
+ yaml.dump({"measures": [full_measure_dict, second]}, f)
+ config = MeasureConfig.from_yaml(path)
+ assert config.name == full_measure_dict["name"]
+
+
+def test_measure_config_from_row_roundtrip(full_measure_dict):
+ config = MeasureConfig.from_dict(full_measure_dict)
+ row = pd.Series(config.to_dict())
+ recovered = MeasureConfig.from_row(row)
+ assert recovered.name == config.name
+ assert recovered.hazard_modifier == config.hazard_modifier
+ assert recovered.impfset_modifier == config.impfset_modifier
+
+
+def test_measure_config_from_row_ignores_extra_columns(full_measure_dict):
+ config = MeasureConfig.from_dict(full_measure_dict)
+ d = {**config.to_dict(), "extra_column": "garbage"}
+ row = pd.Series(d)
+ recovered = MeasureConfig.from_row(row)
+ assert recovered.name == config.name
+
+
+def test_measure_config_sub_configs_correctly_dispatched(full_measure_dict):
+ config = MeasureConfig.from_dict(full_measure_dict)
+ assert config.hazard_modifier.haz_int_mult == full_measure_dict["haz_int_mult"]
+ assert config.impfset_modifier.impf_mdd_mult == full_measure_dict["impf_mdd_mult"]
+ assert (
+ config.exposures_modifier.reassign_impf_id
+ == full_measure_dict["reassign_impf_id"]
+ )
+ assert config.cost_income.init_cost == full_measure_dict["init_cost"]
+ assert not hasattr(config.hazard_modifier, "impf_mdd_mult")
+ assert not hasattr(config.impfset_modifier, "haz_int_mult")
diff --git a/climada/entity/test/test_entity.py b/climada/entity/test/test_entity.py
index 7805a24e70..4a88fc531a 100644
--- a/climada/entity/test/test_entity.py
+++ b/climada/entity/test/test_entity.py
@@ -24,11 +24,11 @@
import numpy as np
from climada import CONFIG
+from climada.entity._legacy_measures.measure_set import MeasureSet
from climada.entity.disc_rates.base import DiscRates
from climada.entity.entity_def import Entity
from climada.entity.exposures.base import Exposures
from climada.entity.impact_funcs.impact_func_set import ImpactFuncSet
-from climada.entity.measures.measure_set import MeasureSet
from climada.util.constants import ENT_TEMPLATE_XLS
ENT_TEST_MAT = CONFIG.exposures.test_data.dir().joinpath("demo_today.mat")
diff --git a/climada/trajectories/calc_risk_metrics.py b/climada/trajectories/calc_risk_metrics.py
index 902fffc2ba..8e5ae8b150 100644
--- a/climada/trajectories/calc_risk_metrics.py
+++ b/climada/trajectories/calc_risk_metrics.py
@@ -32,7 +32,7 @@
import pandas as pd
from climada.engine.impact import Impact
-from climada.entity.measures.base import Measure
+from climada.entity._legacy_measures.base import Measure
from climada.trajectories.constants import (
AAI_METRIC_NAME,
COORD_ID_COL_NAME,
diff --git a/climada/trajectories/snapshot.py b/climada/trajectories/snapshot.py
index 1d5f778135..dbf7f1bbd6 100644
--- a/climada/trajectories/snapshot.py
+++ b/climada/trajectories/snapshot.py
@@ -31,9 +31,9 @@
import numpy as np
import pandas as pd
+from climada.entity._legacy_measures.base import Measure
from climada.entity.exposures import Exposures
from climada.entity.impact_funcs import ImpactFuncSet
-from climada.entity.measures.base import Measure
from climada.hazard import Hazard
LOGGER = logging.getLogger(__name__)
diff --git a/climada/trajectories/test/test_calc_risk_metrics.py b/climada/trajectories/test/test_calc_risk_metrics.py
index 9c75f78fb4..6fc530d065 100644
--- a/climada/trajectories/test/test_calc_risk_metrics.py
+++ b/climada/trajectories/test/test_calc_risk_metrics.py
@@ -26,10 +26,10 @@
import pandas as pd
import pytest
+from climada.entity._legacy_measures.base import Measure
from climada.entity.exposures import Exposures
from climada.entity.impact_funcs import ImpactFuncSet
from climada.entity.impact_funcs.trop_cyclone import ImpfTropCyclone
-from climada.entity.measures.base import Measure
from climada.hazard import Hazard
from climada.trajectories.calc_risk_metrics import CalcRiskMetricsPoints
from climada.trajectories.constants import (
diff --git a/climada/trajectories/test/test_snapshot.py b/climada/trajectories/test/test_snapshot.py
index 77830d3b54..0acaf148da 100644
--- a/climada/trajectories/test/test_snapshot.py
+++ b/climada/trajectories/test/test_snapshot.py
@@ -5,9 +5,9 @@
import pandas as pd
import pytest
+from climada.entity._legacy_measures.base import Measure
from climada.entity.exposures import Exposures
from climada.entity.impact_funcs import ImpactFunc, ImpactFuncSet
-from climada.entity.measures.base import Measure
from climada.hazard import Hazard
from climada.trajectories.snapshot import Snapshot
from climada.util.constants import EXP_DEMO_H5, HAZ_DEMO_H5
diff --git a/doc/api/climada/climada.entity._legacy_measures.rst b/doc/api/climada/climada.entity._legacy_measures.rst
new file mode 100644
index 0000000000..19e622c1ef
--- /dev/null
+++ b/doc/api/climada/climada.entity._legacy_measures.rst
@@ -0,0 +1,22 @@
+climada\.entity\._legacy_measures package
+=========================================
+
+.. note::
+ This package implements the legacy way of defining measures
+ and is retained for compatibility.
+
+climada\.entity\._legacy_measures\.base module
+----------------------------------------------
+
+.. automodule:: climada.entity._legacy_measures.base
+ :members:
+ :undoc-members:
+ :show-inheritance:
+
+climada\.entity\._legacy_measures\.measure\_set module
+------------------------------------------------------
+
+.. automodule:: climada.entity._legacy_measures.measure_set
+ :members:
+ :undoc-members:
+ :show-inheritance:
diff --git a/doc/api/climada/climada.entity.measures.rst b/doc/api/climada/climada.entity.measures.rst
index 8e63a2082b..82207c7a9a 100644
--- a/doc/api/climada/climada.entity.measures.rst
+++ b/doc/api/climada/climada.entity.measures.rst
@@ -1,18 +1,22 @@
climada\.entity\.measures package
=================================
-climada\.entity\.measures\.base module
---------------------------------------
+.. note::
+ This package implements the new way of defining measures.
+ For the previous way, see :ref:`climada.entity._legacy_measures`
-.. automodule:: climada.entity.measures.base
+climada\.entity\.measures\.measure_config module
+------------------------------------------------
+
+.. automodule:: climada.entity.measures.measure_config
:members:
:undoc-members:
:show-inheritance:
-climada\.entity\.measures\.measure\_set module
-----------------------------------------------
+climada\.entity\.measures\.cost_income module
+------------------------------------------------
-.. automodule:: climada.entity.measures.measure_set
+.. automodule:: climada.entity.measures.cost_income
:members:
:undoc-members:
:show-inheritance:
diff --git a/doc/api/climada/climada.entity.rst b/doc/api/climada/climada.entity.rst
index f7eac11700..f4f4df0d98 100644
--- a/doc/api/climada/climada.entity.rst
+++ b/doc/api/climada/climada.entity.rst
@@ -7,6 +7,7 @@ climada\.entity package
climada.entity.exposures
climada.entity.impact_funcs
climada.entity.measures
+ climada.entity._legacy_measures
climada\.entity\.entity\_def module
-----------------------------------
diff --git a/doc/user-guide/adaptation.rst b/doc/user-guide/adaptation.rst
new file mode 100644
index 0000000000..647eddc7ac
--- /dev/null
+++ b/doc/user-guide/adaptation.rst
@@ -0,0 +1,14 @@
+==========================
+Adapation appraisal guides
+==========================
+
+These guides show everything you need to know in order to evaluate adapation options with CLIMADA.
+
+.. toctree::
+ :maxdepth: 1
+
+ .. Adaptation measures in CLIMADA
+ Using measure configurations
+ Defining measure cash flows
+ .. Cost benefit evaluation
+ .. Adapation planning evaluation
diff --git a/doc/user-guide/climada_cost_income.ipynb b/doc/user-guide/climada_cost_income.ipynb
new file mode 100644
index 0000000000..bf1834140e
--- /dev/null
+++ b/doc/user-guide/climada_cost_income.ipynb
@@ -0,0 +1,1020 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "2147f042",
+ "metadata": {},
+ "source": [
+ "(cost-income-tutorial)=\n",
+ "# Measure cash flows with `CostIncome`\n",
+ "\n",
+ "This notebook introduces the `CostIncome` class from CLIMADA, which is used to model the financial cash flows of adaptation or risk-reduction measures over time.\n",
+ "\n",
+ "A `CostIncome` object tracks:\n",
+ "- **Initial (one-off) costs** — the upfront implementation cost\n",
+ "- **Periodic costs** — recurring expenses (e.g., maintenance)\n",
+ "- **Periodic income** — recurring revenues (e.g., insurance savings, avoided losses)\n",
+ "- **Growth rates** — how costs and incomes evolve over time\n",
+ "- **Custom cash flows** — arbitrary user-defined flows (layered on top)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "a73bc8d1",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "import pandas as pd\n",
+ "import numpy as np\n",
+ "import matplotlib.pyplot as plt\n",
+ "\n",
+ "# Adjust the import path if running outside the CLIMADA package tree\n",
+ "from climada.entity.measures.cost_income import CostIncome"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "a97e1043",
+ "metadata": {},
+ "source": [
+ "## Quickstart\n",
+ "\n",
+ "The simplest way to create a `CostIncome` is by passing keyword arguments directly.\n",
+ "\n",
+ "| Parameter | Meaning | Sign convention |\n",
+ "|---|---|---|\n",
+ "| `init_cost` | One-off implementation cost | stored negative |\n",
+ "| `periodic_cost` | Recurring cost each period | stored negative |\n",
+ "| `periodic_income` | Recurring income each period | stored positive |\n",
+ "| `mkt_price_year` | Reference year for price levels | — |\n",
+ "| `freq` | Period frequency (e.g. `'Y'`, `'M'`, `'Q'`) | — |\n",
+ "\n",
+ "```{note} **Sign convention**\n",
+ "`CostIncome` stores costs as negative numbers internally.\n",
+ "```\n",
+ "\n",
+ "```{note}\n",
+ "Financial values in `CostIncome` are currently unitless (no currency is specified)\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "4ba16743",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CostIncome(\n",
+ " mkt_price_year = 2020\n",
+ " freq = 'Y'\n",
+ " init_cost = -20,000.00\n",
+ " periodic_cost = -5,000.00\n",
+ " periodic_income = 12,000.00\n",
+ " cost_yearly_growth_rate = 0.00%\n",
+ " income_yearly_growth_rate = 0.00%\n",
+ " custom_cash_flows = None\n",
+ ")\n"
+ ]
+ }
+ ],
+ "source": [
+ "ci = CostIncome(\n",
+ " mkt_price_year=2020,\n",
+ " init_cost=20_000, # 50 000 upfront\n",
+ " periodic_cost=5_000, # 5 000 / year maintenance\n",
+ " periodic_income=12_000, # 8 000 / year in avoided losses\n",
+ " freq=\"Y\", # annual cash flows\n",
+ ")\n",
+ "\n",
+ "print(ci)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "3c9a8398",
+ "metadata": {},
+ "source": [
+ "## Calculating cash flows\n",
+ "\n",
+ "Three methods are available:\n",
+ "\n",
+ "| Method | Returns |\n",
+ "|---|---|\n",
+ "| `calc_cash_flows(impl_date, start_date, end_date)` | Three `np.ndarray`: net, costs, incomes |\n",
+ "| `calc_total(...)` | Three scalars: summed net, cost, income |\n",
+ "| `to_dataframe(...)` | A tidy `pd.DataFrame` |\n",
+ "\n",
+ "The `impl_date` is when the measure is *deployed*. Cash flows before this date are zero; the initial cost lands on `impl_date`; periodic flows start the following period."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "25bf1e1f",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Period | Net | Cost | Income\n",
+ "---------------------------------------------\n",
+ "2020 | 0 | 0 | 0\n",
+ "2021 | 0 | 0 | 0\n",
+ "2022 | -20000 | -20000 | 0\n",
+ "2023 | 7000 | -5000 | 12000\n",
+ "2024 | 7000 | -5000 | 12000\n",
+ "2025 | 7000 | -5000 | 12000\n",
+ "2026 | 7000 | -5000 | 12000\n",
+ "2027 | 7000 | -5000 | 12000\n",
+ "2028 | 7000 | -5000 | 12000\n",
+ "2029 | 7000 | -5000 | 12000\n",
+ "2030 | 7000 | -5000 | 12000\n"
+ ]
+ }
+ ],
+ "source": [
+ "impl_date = \"2022-01-01\"\n",
+ "start_date = \"2020-01-01\"\n",
+ "end_date = \"2030-01-01\"\n",
+ "\n",
+ "net, costs, incomes = ci.calc_cash_flows(impl_date, start_date, end_date)\n",
+ "\n",
+ "print(\"Period | Net | Cost | Income\")\n",
+ "print(\"-\" * 45)\n",
+ "periods = pd.period_range(start=start_date, end=end_date, freq=\"Y\")\n",
+ "for p, n, c, i in zip(periods, net, costs, incomes):\n",
+ " print(f\"{p} | {n:>9.0f} | {c:>9.0f} | {i:>6.0f}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "971ce0dd",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Total net : 36000\n",
+ "Total cost : -60000\n",
+ "Total income : 96000\n"
+ ]
+ }
+ ],
+ "source": [
+ "total_net, total_cost, total_income = ci.calc_total(impl_date, start_date, end_date)\n",
+ "print(f\"Total net : {total_net:>10.0f}\")\n",
+ "print(f\"Total cost : {total_cost:>10.0f}\")\n",
+ "print(f\"Total income : {total_income:>10.0f}\")"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "f3fd0c35",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " date | \n",
+ " net | \n",
+ " cost | \n",
+ " income | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 2020 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2021 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2022 | \n",
+ " -20000.0 | \n",
+ " -20000.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2023 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 2024 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 2025 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 2026 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 2027 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 2028 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 2029 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 2030 | \n",
+ " 7000.0 | \n",
+ " -5000.0 | \n",
+ " 12000.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " date net cost income\n",
+ "0 2020 0.0 0.0 0.0\n",
+ "1 2021 0.0 0.0 0.0\n",
+ "2 2022 -20000.0 -20000.0 0.0\n",
+ "3 2023 7000.0 -5000.0 12000.0\n",
+ "4 2024 7000.0 -5000.0 12000.0\n",
+ "5 2025 7000.0 -5000.0 12000.0\n",
+ "6 2026 7000.0 -5000.0 12000.0\n",
+ "7 2027 7000.0 -5000.0 12000.0\n",
+ "8 2028 7000.0 -5000.0 12000.0\n",
+ "9 2029 7000.0 -5000.0 12000.0\n",
+ "10 2030 7000.0 -5000.0 12000.0"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "df = ci.to_dataframe(impl_date, start_date, end_date)\n",
+ "df"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "612c0b66",
+ "metadata": {},
+ "source": [
+ "## Visualising cash flows\n",
+ "\n",
+ "`plot_cash_flows` draws a bar chart. You can choose which series to display via the `to_plot` argument."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "315fc0ac",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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juHWqJ3SuxRPPfWUk0sNT2Cva08j0JMnT7YsX748x38GuC+++8C1B29k7+8+63aAPa49pflWUl9XpUuXtkyYMIFKdiAG5MI23kwjvjpNl05ZU6tWLROhGzdunBlPO2PGDLONRpH1ofts377dTG2jdIqlXr16mTsXgLOuPY0ojxw5Utq3b8+HgBy//gBnffcBrnD96VhxwF7XntKeydbrSvfVnD6a96JQoUJUtAMRIICt239ERITpEpb8C167+9SrV09++OEH2bVr1/WLxtdXNm7caH5B69ata7oH6S/3uXPnpEiRItQonHLtFS5cmJpHlvDdB2fh2oMzcf3BXa695EOTL168aIYU6PCXe+65xwml9x4ECLzQypUr5dlnn5V3331X/vzzT9vyZs2ayYYNG+TUqVPmfWJiouTOndv8EuovqI77sdJs3TreRzPF6/F0pgJdr+OIAGdce9bMtgDffXA1/L8Lrj94o1v97tNcF4sXLzb5fKpXry6bNm2SmTNnmtk04DgECLzIyZMnTUKPhx9+2EwXoklltCu29RdWX5ctW9YkGUwetWvXrp25c3vgwAHbsQICAkz3Hp1eRKN8GvEDuPbgivjuA9cevBHffXD3a0+HFegNoL1795oggyYsrFq1Kh+sozkywQFcx+XLly39+vWz9OzZ03Lo0CHb8gYNGlj69+9vXut0NvPnzzdTw61fvz7F/g899JCldevWtveRkZE5WHq4M649cP3BG/HdB64/eCN7f/dpokzkLHoQeAkds63d/3V8T7ly5SQhIcEs79y5s+zevdu89vPzkx49epjuPYMGDZI1a9aYyJ12/9m/f7+JAlox3htce3AHfPeBaw/eiO8+eMq1Z51mEznHR6MEOXg+OJHOMapDA5R+7Nqdp0+fPhIcHCxz5syxLbt27ZrJUvv3339LnTp1zHjv0qVLyxdffGHmuQW49uBO+O4D1x68Ed994NpDdhAg8HItW7aURx55xET5NECQlJRkonqnT58209loxngdI9S7d29nFxUehmsPXH/wRnz3gesP3ojvPvdBgMCLHTp0SJo2bSpLly61JRnUbKGBgYHOLho8HNceuP7gjfjuA9cfvBHffe6FQR1eyDqqZN26dZInTx5bcGDChAny3HPPSWRkpJNLCE/FtQeuP3gjvvvA9QdvxHefe/J3dgGQ86xTiehUI/fdd5+Zo/Sxxx6TK1euyKeffipFihThYwHXHjwO333g2oM34rsPXHvICoYYeClNRFizZk05ePCgGVKgvQdGjBjh7GLBC3DtgesP3ojvPnD9wRvx3ed+CBB4sXbt2knFihVl6tSpkitXLmcXB16Eaw9cf/BGfPeB6w/eiO8+90KAwIslJiaaGQsArj14E777wLUHb8R3H7j2kBkECAAAAAAAALMYAAAAAAAAAgQAAAAAAIAAAQAAAAAAIEAAAAAAAAAM3+tPAAAAAADAmxEgAAAAAAAABAgAAAAAAAABAgAAAAAAQIAAAAAAAAAQIAAAAAAAAKL+DwDn5rGa8bABAAAAAElFTkSuQmCC",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "ci.plot_cash_flows(\n",
+ " impl_date,\n",
+ " start_date,\n",
+ " end_date,\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4bb73614",
+ "metadata": {},
+ "source": [
+ "## Growth rates\n",
+ "\n",
+ "Costs and incomes can grow year-over-year using compound-interest factors anchored to `mkt_price_year`.\n",
+ "\n",
+ "$$\\text{value}(t) = \\text{base} \\times (1 + r)^{\\frac{t - t_0}{365}}$$\n",
+ "\n",
+ "Pass `cost_yearly_growth_rate` and / or `income_yearly_growth_rate` (as decimals, e.g. `0.02` for 2 %)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "b69f1ae7",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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IN/07th//vOfTJ3+GjVqmIDAJ598cunCCrh0aemIAo0m6/BHDRoAzrj29E6Z0ju2gwcPNnfQlN61sCUrvO6668xr7mLAVdefXlu2a05HEOiQW6WjCBYvXiw9evQwo1t27drFLwFOv/b0/1btpOkoAk1S+OWXX8p///tfkwOjevXqppPGtQdX/d3XunVrad++vdx///3muy4mJsb8HahBer05dN9995mAFXAtdMreM888Y0aH2uhoFb3e6HO4kBXIo08//dRapkwZa8uWLa2NGjWyli5d2vriiy+azxISEqxjxoyx1qxZ03rixAmzLDk52Tx/+OGH1mLFitnfA8689i5evGhfLyMjwzw3b97c+u6772ZaBjjz+psyZYr5LCUlxTzffffd1uXLl5vX//nPf6zh4eHW4OBg63//+19OPFxy7an33nvParFYzP+9sbGx9uU//PCDtVy5ctZ169Zx9uGS/3vV2bNnrXv27LG2atXK+s9//tO+fMuWLdbrrrvO+vnnn3P2USBz5swx15tee3feeaf5P/Whhx4ynyUmJtLncDECBMjzP9SGDRta3377bfP+yJEj1jfffNNapEgRExxQy5Yts950003W4cOHZ+qYff/99+Y/mF9++YWzDadee/qfRFb79u0z/6ns2rXLvmzv3r3mOT09nd8AXHL93XfffdZBgwaZ70C9/v7xj39YixcvnumPZsDZ/+/u2LHD2r59e2vdunWtx44ds2+rAfmiRYta/+///o+TDpd+923evNlaq1YtE6Cy/d2ngXu+/1BQGmTXgNQ777xj3qelpZnrUYMESUlJZhl9DtdiigFyG2FinnUYY/Pmzc1wbqVzzHRYd4UKFUyiGqVzwQcOHGiqGHz11VdmG6UlbzTLfP369TnbcOq1l12FDB3arZUMdAjali1bzLaaG0Oz3tqmvgDOvP50rq3mGli4cKEp86rX3XPPPSdjx441lTX279/PCYdLvvtq164tI0aMkL1798rbb78tR44cMcvnz59v/s9t27YtZx4u/b9Xc/1oJYNDhw7Zp/Rp/otq1aqZXBhAXtmm7Ol1N3r0aFMdTQUFBcnp06flwQcflLCwMLOsVatWps+hSVnpc7iAiwMQ8FKbNm2yxsfH29+fOXMm01ButXXrVmvZsmWtp0+fti+zDfuJjIy0tmvXzj4s6K233jKfM9wbrrr2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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "ci_growth = CostIncome(\n",
+ " mkt_price_year=2020,\n",
+ " init_cost=50_000,\n",
+ " periodic_cost=5_000,\n",
+ " periodic_income=8_000,\n",
+ " cost_yearly_growth_rate=0.02, # costs grow 2% / year\n",
+ " income_yearly_growth_rate=0.03, # income grows 3% / year\n",
+ " freq=\"Y\",\n",
+ ")\n",
+ "\n",
+ "ci_growth.plot_cash_flows(impl_date, start_date, end_date)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "067c07aa",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ " No growth With growth\n",
+ "Net 36000 -19821\n",
+ "Cost -60000 -97569\n",
+ "Income 96000 77748\n"
+ ]
+ }
+ ],
+ "source": [
+ "# Compare totals with and without growth\n",
+ "no_growth = ci.calc_total(impl_date, start_date, end_date)\n",
+ "with_growth = ci_growth.calc_total(impl_date, start_date, end_date)\n",
+ "\n",
+ "labels = [\"Net\", \"Cost\", \"Income\"]\n",
+ "print(f\"{'':15s} {'No growth':>12s} {'With growth':>12s}\")\n",
+ "for label, ng, wg in zip(labels, no_growth, with_growth):\n",
+ " print(f\"{label:15s} {ng:>12.0f} {wg:>12.0f}\")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1408d2db",
+ "metadata": {},
+ "source": [
+ "## Custom cash flows\n",
+ "\n",
+ "For irregular or one-off flows, pass a `pd.DataFrame` with columns `date`, `cost`, and/or `income`.\n",
+ "\n",
+ "These are **added on top** of any periodic amounts; dates not present in the DataFrame simply contribute zero."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "c469839c-e2e2-43e9-ac33-93de7f04a6d9",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " date | \n",
+ " net | \n",
+ " cost | \n",
+ " income | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 2020 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2021 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2022 | \n",
+ " -50000.0 | \n",
+ " -50000.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2023 | \n",
+ " 3000.0 | \n",
+ " -5000.0 | \n",
+ " 8000.0 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 2024 | \n",
+ " -7000.0 | \n",
+ " -15000.0 | \n",
+ " 8000.0 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 2025 | \n",
+ " 3000.0 | \n",
+ " -5000.0 | \n",
+ " 8000.0 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 2026 | \n",
+ " 18000.0 | \n",
+ " -5000.0 | \n",
+ " 23000.0 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 2027 | \n",
+ " 3000.0 | \n",
+ " -5000.0 | \n",
+ " 8000.0 | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 2028 | \n",
+ " -17000.0 | \n",
+ " -25000.0 | \n",
+ " 8000.0 | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 2029 | \n",
+ " 3000.0 | \n",
+ " -5000.0 | \n",
+ " 8000.0 | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 2030 | \n",
+ " 3000.0 | \n",
+ " -5000.0 | \n",
+ " 8000.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " date net cost income\n",
+ "0 2020 0.0 0.0 0.0\n",
+ "1 2021 0.0 0.0 0.0\n",
+ "2 2022 -50000.0 -50000.0 0.0\n",
+ "3 2023 3000.0 -5000.0 8000.0\n",
+ "4 2024 -7000.0 -15000.0 8000.0\n",
+ "5 2025 3000.0 -5000.0 8000.0\n",
+ "6 2026 18000.0 -5000.0 23000.0\n",
+ "7 2027 3000.0 -5000.0 8000.0\n",
+ "8 2028 -17000.0 -25000.0 8000.0\n",
+ "9 2029 3000.0 -5000.0 8000.0\n",
+ "10 2030 3000.0 -5000.0 8000.0"
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "custom_flows = pd.DataFrame(\n",
+ " {\n",
+ " \"date\": [\"2024-01-01\", \"2026-01-01\", \"2028-01-01\"],\n",
+ " \"cost\": [10_000, 0, 20_000], # extra one-off costs\n",
+ " \"income\": [0, 15_000, 0], # extra one-off income\n",
+ " }\n",
+ ")\n",
+ "\n",
+ "ci_custom = CostIncome(\n",
+ " mkt_price_year=2020,\n",
+ " init_cost=50_000,\n",
+ " periodic_cost=5_000,\n",
+ " periodic_income=8_000,\n",
+ " custom_cash_flows=custom_flows,\n",
+ " freq=\"Y\",\n",
+ ")\n",
+ "ci_custom.to_dataframe(impl_date, start_date, end_date)"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "11f21296",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 10,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "ci_custom.plot_cash_flows(impl_date, start_date, end_date)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f1f011b6",
+ "metadata": {},
+ "source": [
+ "## Sub-annual frequencies\n",
+ "\n",
+ "`freq` accepts any pandas-compatible period string. Common options:\n",
+ "\n",
+ "| `freq` | Meaning |\n",
+ "|---|---|\n",
+ "| `\"Y\"` | Annual |\n",
+ "| `\"Q\"` | Quarterly |\n",
+ "| `\"M\"` | Monthly |\n",
+ "| `\"7D\"` | Every 7 days |\n",
+ "\n",
+ "```{note}\n",
+ "The periodic amounts are interpreted as **per-period** values, not annualised.\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "277e6948",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/html": [
+ "\n",
+ "\n",
+ "
\n",
+ " \n",
+ " \n",
+ " | \n",
+ " date | \n",
+ " net | \n",
+ " cost | \n",
+ " income | \n",
+ "
\n",
+ " \n",
+ " \n",
+ " \n",
+ " | 0 | \n",
+ " 2022-01 | \n",
+ " -5000.0 | \n",
+ " -5000.0 | \n",
+ " 0.0 | \n",
+ "
\n",
+ " \n",
+ " | 1 | \n",
+ " 2022-02 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 2 | \n",
+ " 2022-03 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 3 | \n",
+ " 2022-04 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 4 | \n",
+ " 2022-05 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 5 | \n",
+ " 2022-06 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 6 | \n",
+ " 2022-07 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 7 | \n",
+ " 2022-08 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 8 | \n",
+ " 2022-09 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 9 | \n",
+ " 2022-10 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 10 | \n",
+ " 2022-11 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ " | 11 | \n",
+ " 2022-12 | \n",
+ " 200.0 | \n",
+ " -500.0 | \n",
+ " 700.0 | \n",
+ "
\n",
+ " \n",
+ "
\n",
+ "
"
+ ],
+ "text/plain": [
+ " date net cost income\n",
+ "0 2022-01 -5000.0 -5000.0 0.0\n",
+ "1 2022-02 200.0 -500.0 700.0\n",
+ "2 2022-03 200.0 -500.0 700.0\n",
+ "3 2022-04 200.0 -500.0 700.0\n",
+ "4 2022-05 200.0 -500.0 700.0\n",
+ "5 2022-06 200.0 -500.0 700.0\n",
+ "6 2022-07 200.0 -500.0 700.0\n",
+ "7 2022-08 200.0 -500.0 700.0\n",
+ "8 2022-09 200.0 -500.0 700.0\n",
+ "9 2022-10 200.0 -500.0 700.0\n",
+ "10 2022-11 200.0 -500.0 700.0\n",
+ "11 2022-12 200.0 -500.0 700.0"
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "ci_monthly = CostIncome(\n",
+ " mkt_price_year=2022,\n",
+ " init_cost=5_000,\n",
+ " periodic_cost=500,\n",
+ " periodic_income=700,\n",
+ " freq=\"M\",\n",
+ ")\n",
+ "\n",
+ "df_monthly = ci_monthly.to_dataframe(\n",
+ " impl_date=\"2022-01-01\",\n",
+ " start_date=\"2022-01-01\",\n",
+ " end_date=\"2022-12-01\",\n",
+ ")\n",
+ "df_monthly"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "03a80747",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(, )"
+ ]
+ },
+ "execution_count": 12,
+ "metadata": {},
+ "output_type": "execute_result"
+ },
+ {
+ "data": {
+ "image/png": "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",
+ "text/plain": [
+ ""
+ ]
+ },
+ "metadata": {},
+ "output_type": "display_data"
+ }
+ ],
+ "source": [
+ "ci_monthly.plot_cash_flows(\n",
+ " \"2022-01-01\",\n",
+ " \"2022-01-01\",\n",
+ " \"2022-12-01\",\n",
+ ")"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "10191dfd",
+ "metadata": {},
+ "source": [
+ "## Combining multiple CostIncome objects\n",
+ "\n",
+ "`CostIncome.comb_cost_income()` aggregates a list of `CostIncome` objects into a single one by summing costs and incomes.\n",
+ "\n",
+ "```{warning}\n",
+ "All objects must share the same `mkt_price_year`, `cost_growth_rate`, and `income_growth_rate`.\n",
+ "```\n",
+ "\n",
+ "```{note}\n",
+ "`custom_cash_flows` are **not** carried over to the combined object. Merge custom flows manually beforehand if needed.\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "id": "666fd82b",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CostIncome(\n",
+ " mkt_price_year = 2020\n",
+ " freq = 'Y'\n",
+ " init_cost = -50,000.00\n",
+ " periodic_cost = -5,000.00\n",
+ " periodic_income = 8,000.00\n",
+ " cost_yearly_growth_rate = 0.00%\n",
+ " income_yearly_growth_rate = 0.00%\n",
+ " custom_cash_flows = None\n",
+ ")\n"
+ ]
+ }
+ ],
+ "source": [
+ "ci_a = CostIncome(\n",
+ " mkt_price_year=2020,\n",
+ " init_cost=30_000,\n",
+ " periodic_cost=2_000,\n",
+ " periodic_income=4_000,\n",
+ " freq=\"Y\",\n",
+ ")\n",
+ "\n",
+ "ci_b = CostIncome(\n",
+ " mkt_price_year=2020,\n",
+ " init_cost=20_000,\n",
+ " periodic_cost=3_000,\n",
+ " periodic_income=4_000,\n",
+ " freq=\"Y\",\n",
+ ")\n",
+ "\n",
+ "ci_combined = CostIncome.comb_cost_income([ci_a, ci_b])\n",
+ "\n",
+ "print(ci_combined)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8a15baaf",
+ "metadata": {},
+ "source": [
+ "## Loading from dict / YAML\n",
+ "\n",
+ "### From a Python dictionary"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "id": "eeac2088",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "CostIncome(\n",
+ " mkt_price_year = 2020\n",
+ " freq = 'Y'\n",
+ " init_cost = -50,000.00\n",
+ " periodic_cost = -5,000.00\n",
+ " periodic_income = 8,000.00\n",
+ " cost_yearly_growth_rate = 2.00%\n",
+ " income_yearly_growth_rate = 3.00%\n",
+ " custom_cash_flows = None\n",
+ ")\n"
+ ]
+ }
+ ],
+ "source": [
+ "config_dict = {\n",
+ " \"mkt_price_year\": 2020,\n",
+ " \"init_cost\": 50_000,\n",
+ " \"periodic_cost\": 5_000,\n",
+ " \"periodic_income\": 8_000,\n",
+ " \"cost_yearly_growth_rate\": 0.02,\n",
+ " \"income_yearly_growth_rate\": 0.03,\n",
+ " \"freq\": \"Y\",\n",
+ "}\n",
+ "\n",
+ "ci_from_dict = CostIncome.from_dict(config_dict)\n",
+ "print(ci_from_dict)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0b2a868e",
+ "metadata": {},
+ "source": [
+ "### From a YAML file\n",
+ "\n",
+ "Create a YAML file structured as follows, then load it with `CostIncome.from_yaml`.\n",
+ "\n",
+ "```yaml\n",
+ "# measure_cost.yaml\n",
+ "cost_income:\n",
+ " mkt_price_year: 2020\n",
+ " init_cost: 50000\n",
+ " periodic_cost: 5000\n",
+ " periodic_income: 8000\n",
+ " cost_yearly_growth_rate: 0.02\n",
+ " income_yearly_growth_rate: 0.03\n",
+ " freq: \"Y\"\n",
+ " # Optional custom flows:\n",
+ " # custom_cash_flows:\n",
+ " # - date: \"2024-01-01\"\n",
+ " # cost: 10000\n",
+ " # income: 0\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python [conda env:climada_env_dev]",
+ "language": "python",
+ "name": "conda-env-climada_env_dev-py"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/user-guide/climada_engine_CostBenefit.ipynb b/doc/user-guide/climada_engine_CostBenefit.ipynb
index de98c79260..a86fee8e3e 100644
--- a/doc/user-guide/climada_engine_CostBenefit.ipynb
+++ b/doc/user-guide/climada_engine_CostBenefit.ipynb
@@ -7,6 +7,15 @@
"# END-TO-END COST BENEFIT CALCULATION"
]
},
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "```{attention}\n",
+ "Adapation measures and cost-benefit evaluation are being completely revamped. Associated tutorials will be under their own menu \"Adaptation appraisal guides\"\n",
+ "```"
+ ]
+ },
{
"attachments": {},
"cell_type": "markdown",
@@ -1286,9 +1295,9 @@
],
"metadata": {
"kernelspec": {
- "display_name": "Python 3 (ipykernel)",
+ "display_name": "Python [conda env:climada_env_dev]",
"language": "python",
- "name": "python3"
+ "name": "conda-env-climada_env_dev-py"
},
"language_info": {
"codemirror_mode": {
@@ -1300,7 +1309,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
- "version": "3.8.10"
+ "version": "3.11.15"
},
"latex_envs": {
"LaTeX_envs_menu_present": true,
diff --git a/doc/user-guide/climada_entity_Exposures.ipynb b/doc/user-guide/climada_entity_Exposures.ipynb
index aa1b39fd38..90a0c81ebe 100644
--- a/doc/user-guide/climada_entity_Exposures.ipynb
+++ b/doc/user-guide/climada_entity_Exposures.ipynb
@@ -4,6 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "(exposure-tutorial)=\n",
"# Exposures class"
]
},
diff --git a/doc/user-guide/climada_entity_ImpactFuncSet.ipynb b/doc/user-guide/climada_entity_ImpactFuncSet.ipynb
index fd349487cd..ad1841a750 100644
--- a/doc/user-guide/climada_entity_ImpactFuncSet.ipynb
+++ b/doc/user-guide/climada_entity_ImpactFuncSet.ipynb
@@ -4,6 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "(impact-functions-tutorial)=\n",
"# Impact Functions"
]
},
diff --git a/doc/user-guide/climada_entity_MeasureSet.ipynb b/doc/user-guide/climada_entity_MeasureSet.ipynb
index 0af0b37d70..17a07036cb 100644
--- a/doc/user-guide/climada_entity_MeasureSet.ipynb
+++ b/doc/user-guide/climada_entity_MeasureSet.ipynb
@@ -6,7 +6,11 @@
"source": [
"# Adaptation Measures\n",
"\n",
- "Adaptation measures are defined by parameters that alter the exposures, hazard or impact functions. Risk transfer options are also considered. Single measures are defined in the `Measure` class, which can be aggregated to a `MeasureSet`."
+ "Adaptation measures are defined by parameters that alter the exposures, hazard or impact functions. Risk transfer options are also considered. Single measures are defined in the `Measure` class, which can be aggregated to a `MeasureSet`.\n",
+ "\n",
+ "```{attention}\n",
+ "Adapation measures and cost-benefit evaluation are being completely revamped. Associated tutorials will be under their own menu \"Adaptation appraisal guides\".\n",
+ "```"
]
},
{
diff --git a/doc/user-guide/climada_hazard_Hazard.ipynb b/doc/user-guide/climada_hazard_Hazard.ipynb
index 412346d041..0b6bd40373 100644
--- a/doc/user-guide/climada_hazard_Hazard.ipynb
+++ b/doc/user-guide/climada_hazard_Hazard.ipynb
@@ -4,6 +4,7 @@
"cell_type": "markdown",
"metadata": {},
"source": [
+ "(hazard-tutorial)=\n",
"# Hazard class\n",
"\n",
"## What is a hazard?\n",
diff --git a/doc/user-guide/climada_measure_config.ipynb b/doc/user-guide/climada_measure_config.ipynb
new file mode 100644
index 0000000000..8fa4739bac
--- /dev/null
+++ b/doc/user-guide/climada_measure_config.ipynb
@@ -0,0 +1,570 @@
+{
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "659605a5-d601-47d3-89f7-b606e3e39c93",
+ "metadata": {},
+ "source": [
+ "(measure-config-tutorial)=\n",
+ "\n",
+ "# Defining Adaptation Measures with configurations"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c68c6cf1-d0a1-40ae-ae45-838741988ac6",
+ "metadata": {},
+ "source": [
+ "## Introduction\n",
+ "\n",
+ "CLIMADA uses `Measure` objects to model the effects of adaptation measures. `Measure` objects were formerly defined declaratively (via for instance, a shifting or scaling of the hazard intensity or a change of impact function), and are now defined as python functions to enable more flexibility on the possible changes (see the [tutorial on measure objects](measure-tutorial)'). \n",
+ "\n",
+ "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",
+ "\n",
+ "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",
+ "\n",
+ "`Measure` objects can be instantiated from `MeasureConfig` objects using `Measure.from_config()`.\n",
+ "\n",
+ "### Summary of `Measure` vs `MeasureConfig`\n",
+ "\n",
+ "| `Measure` | `MeasureConfig` |\n",
+ "|-----------|--------------------|\n",
+ "| Is used for the actual computation | Is transformed into a `Measure` for actual computation |\n",
+ "| 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",
+ "| Accepts any possible effect as long as it can be defined as a python function | Is restricted to a set of defined effects |\n",
+ "| 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`) |"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6d786faa-5b8c-4ee6-83cd-5fdafc1b2c29",
+ "metadata": {},
+ "source": [
+ "### Configuration classes\n",
+ "\n",
+ "The definition of measures via `MeasureConfig` is organized into a hierarchy of specialized classes:\n",
+ "\n",
+ "- `MeasureConfig`: The top-level container for a single measure.\n",
+ "- `HazardModifierConfig`: Defines how the hazard is changed (e.g., shifting intensity).\n",
+ "- `ImpfsetModifierConfig`: Adjusts impact functions (e.g., scaling vulnerability curves).\n",
+ "- `ExposuresModifierConfig`: Modifies exposure data (e.g., reassigning IDs or zeroing regions).\n",
+ "- `CostIncomeConfig`: Handles the financial aspects, including initial costs and recurring income.\n",
+ "\n",
+ "Note that everything can be defined and accessed directly from the `MeasureConfig` container, the underlying ones are there to keep things organized.\n",
+ "\n",
+ "In the following we present each of these subclasses and the possibilities they offer."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "4887d2a6-8295-4fda-8442-cbcbd3b16fea",
+ "metadata": {},
+ "source": [
+ "## Quickstart"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "5c40640d-50a4-4102-8e45-0dc8b9a770f2",
+ "metadata": {},
+ "source": [
+ "You can directly define a `MeasureConfig` object with a dictionary, using `MeasureConfig.from_dict()`.\n",
+ "\n",
+ "Below are the possible parameters:\n",
+ "\n",
+ "| Scope | Parameter | Type | Description |\n",
+ "| :--- | :--- | :--- | :--- |\n",
+ "| **Top-Level** | `name` (required) | `str` | Unique identifier for the measure. |\n",
+ "| | `haz_type` (required) | `str` | The hazard type this measure targets (e.g., \"TC\", \"FL\"). |\n",
+ "| | `implementation_duration` | `str` | Pandas offset alias (e.g., \"2Y\") for implementation time. |\n",
+ "| | `color_rgb` | `tuple` | RGB triple (0-1 range) for plotting and visualization. |\n",
+ "| **Hazard** | `haz_int_mult` | `float` | Multiplier for hazard intensity (default: 1.0). |\n",
+ "| | `haz_int_add` | `float` | Additive offset for hazard intensity (default: 0.0). |\n",
+ "| | `new_hazard_path` | | Path to an HDF5 file to replace the current hazard. |\n",
+ "| | `impact_rp_cutoff` | `float` | Return period (years) threshold; events below this are ignored. |\n",
+ "| **Impact Function**| `impf_ids` | `list` | Specific impact function IDs to modify (None = all). |\n",
+ "| | `impf_mdd_mult` / `_add` | `float` | Scale or shift the Mean Damage Degree curve. |\n",
+ "| | `impf_paa_mult` / `_add` | `float` | Scale or shift the Percentage of Assets Affected curve. |\n",
+ "| | `impf_int_mult` / `_add` | `float` | Scale or shift the intensity axis of the function. |\n",
+ "| | `new_impfset_path` | | Path to an Excel file to replace the impact function set. |\n",
+ "| **Exposures** | `reassign_impf_id` | `dict` | Mapping `{haz_type: {old_id: new_id}}` for reclassification. |\n",
+ "| | `set_to_zero` | `list` | List of Region IDs where exposure value is set to 0. |\n",
+ "| | `new_exposures_path` | | Path to an HDF5 file to replace the current exposures. |\n",
+ "| **Cost & Income** | `init_cost` | `float` | One-time investment cost (absolute value). |\n",
+ "| | `periodic_cost` | `float` | Recurring maintenance/operational costs. |\n",
+ "| | `periodic_income` | `float` | Recurring income generated by the measure. |\n",
+ "| | `mkt_price_year` | `int` | Reference year for pricing (default: current year). |\n",
+ "| | `freq` | `str` | Frequency of cash flows (e.g., \"Y\" for yearly). |\n",
+ "| | `custom_cash_flows` | `list[dict]`| Explicit list of dates and values for complex cash flows. (See the [cost income tutorial](cost-income-tutorial)) |"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "62cf6502-7765-452c-be32-eb49a363b4a8",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "MeasureConfig(\n",
+ "\tname='Tutorial measure'\n",
+ "\thaz_type='TC'\n",
+ "\timpfset_modifier=ImpfsetModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\timpf_ids=[1, 2]\n",
+ "\t\t\timpf_mdd_mult=0.8\n",
+ ")\n",
+ "\thazard_modifier=HazardModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\tnew_hazard_path='path/to/new_hazard.h5'\n",
+ ")\n",
+ "\texposures_modifier=ExposuresModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\treassign_impf_id={'TC': {1: 2}}\n",
+ ")\n",
+ "\tcost_income=CostIncomeConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\tinit_cost=10000\n",
+ "\t\t\tperiodic_cost=500\n",
+ ")\n",
+ "\timplementation_duration=None\n",
+ "\tcolor_rgb=(0.1, 0.5, 0.3))\n"
+ ]
+ }
+ ],
+ "source": [
+ "from climada.entity.measures.measure_config import MeasureConfig\n",
+ "\n",
+ "measure_dict = {\n",
+ " \"name\": \"Tutorial measure\",\n",
+ " \"haz_type\": \"TC\",\n",
+ " \"impf_ids\": [1, 2],\n",
+ " \"impf_mdd_mult\": 0.8,\n",
+ " \"new_hazard_path\": \"path/to/new_hazard.h5\",\n",
+ " \"reassign_impf_id\": {\"TC\": {1: 2}},\n",
+ " \"color_rgb\": [0.1, 0.5, 0.3],\n",
+ " \"init_cost\": 10000,\n",
+ " \"periodic_cost\": 500,\n",
+ "}\n",
+ "\n",
+ "meas_config = MeasureConfig.from_dict(measure_dict)\n",
+ "\n",
+ "print(meas_config)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ac98393f-575f-4580-ac4a-dae578638916",
+ "metadata": {},
+ "source": [
+ "## Modifying Impact Functions: `ImpfsetModifierConfig`\n",
+ "\n",
+ "The `ImpfsetModifierConfig` is used to define how an adaptation measure changes the vulnerability (refer to the [impact functions tutorial](impact-functions-tutorial)).\n",
+ "\n",
+ "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",
+ "\n",
+ "```{note}\n",
+ "Modifications are always applied to a specific hazard type (`haz_type` parameter).\n",
+ "```\n",
+ "\n",
+ "`ImpfsetModifierConfig` allows you to modify the main components of an impact function set, as well as to replace it entirely:\n",
+ "\n",
+ "- The MDD (Mean Damage Degree) array: via `impf_mdd_mult` to scale it and `impf_mdd_add` to shift it.\n",
+ "- The PAA (Percentage of Assets Affected) array: via `impf_paa_mult` to scale it and `impf_paa_add` to shift it.\n",
+ "- The intensity array: via `impf_int_mult` to scale it and `impf_int_add` to shift it.\n",
+ "- Replacing the set: via providing the `new_impfset_path` parameter. It needs to be a valid `.xlsx` file readable by `ImpactFuncSet.from_excel()`\n",
+ "\n",
+ "See below for code examples.\n",
+ "\n",
+ "```{warning}\n",
+ "If you provide a new_impfset_path and other modifiers, CLIMADA will load the new file first and then apply the modifiers to it. (A warning will be issued to ensure this sequence is intended).\n",
+ "```\n",
+ "\n",
+ "```{note}\n",
+ "By default the changes are applied to all the impact functions in the set, but you can provide the `impf_ids` parameter to apply the changes to a selection of impact function ids.\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "5ffb447b-1b8f-4e40-9d1c-7db33a11255e",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "--- Scaling Config ---\n",
+ "ImpfsetModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\timpf_ids=[1, 2]\n",
+ "\t\t\timpf_mdd_mult=0.8\n",
+ "\t\t\timpf_int_add=5.0\n",
+ ")\n",
+ "\n",
+ "--- Replacement Config ---\n",
+ "ImpfsetModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\tnew_impfset_path='path/to/new_impact_functions.xlsx'\n",
+ ")\n"
+ ]
+ }
+ ],
+ "source": [
+ "from climada.entity.measures.measure_config import ImpfsetModifierConfig\n",
+ "\n",
+ "# 1. Scaling existing Impact Functions\n",
+ "# Let's say we want to simulate a 20% reduction in MDD\n",
+ "# and a slight shift in the intensity threshold for Hazard 'TC'.\n",
+ "impf_mod_scaling = ImpfsetModifierConfig(\n",
+ " haz_type=\"TC\",\n",
+ " impf_ids=[1, 2], # Apply only to specific function IDs\n",
+ " impf_mdd_mult=0.8, # Reduce Mean Damage Degree by 20%\n",
+ " impf_int_add=5.0, # Shift intensity axis by 5 units (e.g., higher resistance)\n",
+ ")\n",
+ "\n",
+ "print(\"--- Scaling Config ---\")\n",
+ "print(impf_mod_scaling)\n",
+ "\n",
+ "# 2. Replacing the Impact Function Set from a file\n",
+ "# Useful for measures that implement completely new building standards.\n",
+ "impf_mod_replace = ImpfsetModifierConfig(\n",
+ " haz_type=\"TC\", new_impfset_path=\"path/to/new_impact_functions.xlsx\"\n",
+ ")\n",
+ "\n",
+ "print(\"\\n--- Replacement Config ---\")\n",
+ "print(impf_mod_replace)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "234ebc89-83b0-42b1-8b97-734016306b84",
+ "metadata": {},
+ "source": [
+ "## Modifying Hazards: `HazardModifierConfig`\n",
+ "\n",
+ "The `HazardModifierConfig` is used to define how an adaptation measure changes the hazard (refer to the [hazard tutorial](hazard-tutorial)).\n",
+ "\n",
+ "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",
+ "\n",
+ "```{note}\n",
+ "Modifications are always applied to a specific hazard type (`haz_type` parameter).\n",
+ "```\n",
+ "\n",
+ "`HazardModifierConfig` allows you to modify the intensity and frequency of the hazard, to apply a cutoff on the return period of impacts, as well as to replace it entirely:\n",
+ "\n",
+ "- The intensity matrix: via `haz_int_mult` to scale it and `haz_int_add` to shift it.\n",
+ "- The frequency array: via `haz_freq_mult` to scale it and `haz_freq_add` to shift it.\n",
+ "- Replacing the hazard: via providing the `new_hazard_path` parameter. It needs to be a valid hazard HDF5 file readable by `Hazard.from_hdf5()`\n",
+ "- Applying a cutoff on frequency based on impacts: via `impact_rp_cutoff` (see the note).\n",
+ "\n",
+ "```{note}\n",
+ "Providing a value for `impact_rp_cutoff` \"removes\" (it sets their intensity to 0.) events from the hazard, for which the exceedance frequency (inverse of return period) of impacts is below the given threshold.\n",
+ "\n",
+ "For instance providing 1/20, would remove all events whose impacts have a return period below 20 years.\n",
+ "\n",
+ "In that case the function changing the hazard (`Measure.hazard_change`) will be a function with the following signature:\n",
+ "\n",
+ " f(hazard: Hazard, # The hazard to apply on\n",
+ " exposures: Exposures, # The exposure for the impact computation\n",
+ " impfset: ImpactFuncSet, # The impfset for the impact computation\n",
+ " base_hazard: Hazard, # The hazard for the impact computation\n",
+ " exposures_region_id: Optional[list[int]] = None, # Region id to filter to\n",
+ " ) -> Hazard\n",
+ "```\n",
+ "\n",
+ "```{warning}\n",
+ "If you provide a new_hazard_path and other modifiers, CLIMADA will load the new file first and then apply the modifiers to it. (A warning will be issued to ensure this sequence is intended).\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "f6061c1c-b21f-4aef-a394-c172784a25ab",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "--- Scaling Config ---\n",
+ "HazardModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\thaz_int_add=-10\n",
+ "\t\t\thaz_freq_mult=0.8\n",
+ ")\n",
+ "\n",
+ "--- Replacement Config ---\n",
+ "HazardModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\tnew_hazard_path='path/to/new_floods.h5'\n",
+ ")\n",
+ "\n",
+ "--- Cutoff Config ---\n",
+ "HazardModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\timpact_rp_cutoff=0.05\n",
+ ")\n"
+ ]
+ }
+ ],
+ "source": [
+ "from climada.entity.measures.measure_config import HazardModifierConfig\n",
+ "\n",
+ "# 1. Scaling existing hazard\n",
+ "# Let's say we want to simulate a 20% reduction in frequency\n",
+ "# and a reduction by 10m/s in the intensity for our tropical cyclones.\n",
+ "haz_mod = HazardModifierConfig(\n",
+ " haz_type=\"TC\",\n",
+ " haz_int_add=-10, # Reduce hazard intensity by 10 units\n",
+ " haz_freq_mult=0.8, # Scale hazard frequency by 20%\n",
+ ")\n",
+ "\n",
+ "print(\"--- Scaling Config ---\")\n",
+ "print(haz_mod)\n",
+ "\n",
+ "# 2. Replacing the hazard from a file\n",
+ "# Useful for measures that correspond to a different hazard modelling.\n",
+ "# E.g., a dike leading to a change in (physical) flood modelling.\n",
+ "haz_mod_new = HazardModifierConfig(\n",
+ " haz_type=\"FL\", new_hazard_path=\"path/to/new_floods.h5\"\n",
+ ")\n",
+ "\n",
+ "print(\"\\n--- Replacement Config ---\")\n",
+ "print(haz_mod_new)\n",
+ "\n",
+ "# 3. Applying a cutoff on the return period of the impacts\n",
+ "# Useful when measures are defined to avoid damage for a specific RP (exceedance frequency).\n",
+ "# Note that it looks a the distribution of the impacts, not the hazard intensity!\n",
+ "haz_mod_cutoff = HazardModifierConfig(\n",
+ " haz_type=\"TC\",\n",
+ " impact_rp_cutoff=1\n",
+ " / 20, # Set intensity to 0 for events with impacts with a return period below 20 years\n",
+ ")\n",
+ "\n",
+ "print(\"\\n--- Cutoff Config ---\")\n",
+ "print(haz_mod_cutoff)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "c7499c1a-2491-42c4-bdbb-d224090b85fb",
+ "metadata": {},
+ "source": [
+ "## Modifying Exposures: `ExposuresModifierConfig`\n",
+ "\n",
+ "The `ExposuresModifierConfig` is used to define how an adaptation measure changes the exposure (refer to the [exposure tutorial](exposure-tutorial)).\n",
+ "\n",
+ "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",
+ "\n",
+ "`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",
+ "\n",
+ "- Remapping the impact function: via `reassign_impf_id` with a dictionary of the form `{haz_type: {old_id: new_id}}`.\n",
+ "- Setting values to zero: via `set_to_zero` with a list of indices of the exposure GeoDataFrame.\n",
+ "- Replacing the exposure: via providing the `new_exposures_path` parameter. It need to be a valid HDF5 exposure file readable by `Exposures.from_hdf5()`\n",
+ "\n",
+ "```{warning}\n",
+ "If you provide a new_exposures_path and other modifiers, CLIMADA will load the new file first and then apply the modifiers to it. (A warning will be issued to ensure this sequence is intended).\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "5237930d-a18c-4498-afe5-373c5dadf882",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "--- First Config ---\n",
+ "ExposuresModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\treassign_impf_id={'TC': {1: 2}}\n",
+ "\t\t\tset_to_zero=[0, 25, 78]\n",
+ ")\n",
+ "\n",
+ "--- Replacement Config ---\n",
+ "ExposuresModifierConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\tnew_exposures_path='path/to/exposures.h5'\n",
+ ")\n"
+ ]
+ }
+ ],
+ "source": [
+ "from climada.entity.measures.measure_config import ExposuresModifierConfig\n",
+ "\n",
+ "# 1. Changing existing Exposures\n",
+ "exp_mod = ExposuresModifierConfig(\n",
+ " reassign_impf_id={\"TC\": {1: 2}}, # Remaps exposures points with impf_TC == 1 to 2.\n",
+ " set_to_zero=[\n",
+ " 0,\n",
+ " 25,\n",
+ " 78,\n",
+ " ], # Sets the value of exposure points with index 0, 25 and 78 to 0.\n",
+ ")\n",
+ "\n",
+ "print(\"--- First Config ---\")\n",
+ "print(exp_mod)\n",
+ "\n",
+ "# 2. Replacing the expoosure from a file\n",
+ "exp_mod_new = ExposuresModifierConfig(new_exposures_path=\"path/to/exposures.h5\")\n",
+ "\n",
+ "print(\"\\n--- Replacement Config ---\")\n",
+ "print(exp_mod_new)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2c2d4488-28e5-4ced-b9cf-e4d5c0cade3e",
+ "metadata": {},
+ "source": [
+ "## Defining the financial aspects of the measure\n",
+ "\n",
+ "For in depth description of CostIncome objects, refer to the [related tutorial](cost-income-tutorial).\n",
+ "\n",
+ "```{note}\n",
+ "The default for mkt_price_year if not provided is the current year.\n",
+ "```\n",
+ "\n",
+ "You can easily define the CostIncome object to be associated with the measure using `CostIncomeConfig`:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "7c107fc5-606b-4904-8b8e-059f846c2e39",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "\n",
+ "--- Growth & Income Config ---\n",
+ "CostIncomeConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\tinit_cost=500000.0\n",
+ "\t\t\tperiodic_cost=20000.0\n",
+ "\t\t\tperiodic_income=100000.0\n",
+ "\t\t\tcost_yearly_growth_rate=0.02\n",
+ "\t\t\tincome_yearly_growth_rate=0.03\n",
+ ")\n",
+ "\n",
+ "--- Custom Schedule Config ---\n",
+ "CostIncomeConfig(\n",
+ "\t\tNon default fields:\n",
+ "\t\t\tcustom_cash_flows=[{'date': '2024-01-01', 'value': -1000000}, {'date': '2029-01-01', 'value': -200000}, {'date': '2034-01-01', 'value': 500000}]\n",
+ ")\n"
+ ]
+ }
+ ],
+ "source": [
+ "from climada.entity.measures.measure_config import CostIncomeConfig\n",
+ "\n",
+ "# This models a measure where costs increase by 2% annually,\n",
+ "# but it generates 100k in yearly income which grows by 3%.\n",
+ "growth_finance = CostIncomeConfig(\n",
+ " init_cost=500_000.0,\n",
+ " periodic_cost=20_000.0,\n",
+ " cost_yearly_growth_rate=0.02,\n",
+ " periodic_income=100_000.0,\n",
+ " income_yearly_growth_rate=0.03,\n",
+ " freq=\"Y\",\n",
+ ")\n",
+ "\n",
+ "print(\"\\n--- Growth & Income Config ---\")\n",
+ "print(growth_finance)\n",
+ "\n",
+ "\n",
+ "# Custom Cash Flow\n",
+ "# If the investment isn't linear (e.g., a major retrofit in year 5),\n",
+ "# you can define a list of specific events.\n",
+ "custom_schedule = [\n",
+ " {\"date\": \"2024-01-01\", \"value\": -1000000}, # Initial cost\n",
+ " {\"date\": \"2029-01-01\", \"value\": -200000}, # Mid-term overhaul\n",
+ " {\"date\": \"2034-01-01\", \"value\": 500000}, # Terminal value\n",
+ "]\n",
+ "\n",
+ "custom_finance = CostIncomeConfig(custom_cash_flows=custom_schedule)\n",
+ "\n",
+ "print(\"\\n--- Custom Schedule Config ---\")\n",
+ "print(custom_finance)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ab4216dd-fd0b-4939-844d-56bd5ea49504",
+ "metadata": {},
+ "source": [
+ "## Reading from and writing to\n",
+ "\n",
+ "You can easily write/read measure configurations from YAML, as well as from pandas Series.\n",
+ "\n",
+ "You can also create `Measures`/`MeasureSet` directly, using the same methods (these methods first load the file as a `MeasureConfig` and convert it directly to a `Measure`)\n",
+ "Similarly you can still create `MeasureSet` from legacy Excel or matlab files using `MeasureSet.from_excel()` which takes care of remapping the legacy parameter names to the new ones.\n",
+ "See the [measure tutorial](measure-tutorial) for more details on that."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "63132690-dd6f-4f45-96a9-5519fa2dec07",
+ "metadata": {},
+ "source": [
+ "\n",
+ "```python\n",
+ "import pandas as pd\n",
+ "from climada.entity.measures.measure_config import MeasureConfig\n",
+ "\n",
+ "# 1. Exporting to YAML\n",
+ "# Assuming 'my_measure_config' is a MeasureConfig object created previously\n",
+ "my_measure_config.to_yaml(\"seawall_config.yaml\")\n",
+ "\n",
+ "# 2. Loading from YAML\n",
+ "loaded_measure_config = MeasureConfig.from_yaml(\"seawall_config.yaml\")\n",
+ "\n",
+ "# 3. Loading from Pandas\n",
+ "row_data = pd.Series({\n",
+ " \"name\": \"Mangrove_Restoration\",\n",
+ " \"haz_type\": \"TC\",\n",
+ " \"impf_mdd_mult\": 0.7,\n",
+ " \"init_cost\": 250000,\n",
+ " \"color_rgb\": (0.1, 0.8, 0.1)\n",
+ "})\n",
+ "\n",
+ "pandas_measure_config = MeasureConfig.from_row(row_data)\n",
+ "\n",
+ "# 4. Measure object directly\n",
+ "measure = Measure.from_yaml(\"seawall_config.yaml\")\n",
+ "```"
+ ]
+ }
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python [conda env:climada_env_dev]",
+ "language": "python",
+ "name": "conda-env-climada_env_dev-py"
+ },
+ "language_info": {
+ "codemirror_mode": {
+ "name": "ipython",
+ "version": 3
+ },
+ "file_extension": ".py",
+ "mimetype": "text/x-python",
+ "name": "python",
+ "nbconvert_exporter": "python",
+ "pygments_lexer": "ipython3",
+ "version": "3.11.15"
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
+}
diff --git a/doc/user-guide/index.rst b/doc/user-guide/index.rst
index a5f2f709f5..014fc43f50 100644
--- a/doc/user-guide/index.rst
+++ b/doc/user-guide/index.rst
@@ -19,6 +19,7 @@ You can then go on to more specific tutorial about `Hazard `_,
Hazard
Exposures
Impact
+ Adaptation appraisal
Local exceedance intensities
Uncertainty Quantification
climada_engine_Forecast