ebm.areaforecast.s_curve module
- original_condition(s_curve_cumulative_demolition, s_curve_renovation, s_curve_renovation_and_small_measure, s_curve_small_measure)[source]
Calculates buildings remaining as original condition by subtracting every other condition
Parameters
s_curve_cumulative_demolition : pandas.Series s_curve_renovation : pandas.Series s_curve_renovation_and_small_measure : pandas.Series s_curve_small_measure : pandas.Series
Returns
- pandas.Series
buildings remaining as original condition
- small_measure(s_curve_renovation_and_small_measure: Series, s_curve_small_measure_total: Series) Series[source]
Calculates the remaining small measure share by subtracting renovation and small measure values from the total small measure curve.
Parameters
s_curve_renovation_and_small_measure : Series s_curve_small_measure_total : Series
Returns
- Series
s_curve_small_measure
Notes
This function currently does not implement logic to zero out values before the building year.
Assumes both input Series are aligned on the index year.
- renovation_and_small_measure(s_curve_renovation: Series, s_curve_renovation_total: Series) Series[source]
Calculates the remaining renovation_and_small_measure share by subtracting renovation from the total renovation total curve.
Parameters
- s_curve_renovationpandas.Series
A time series representing the S-curve of exclusive renovation condition.
- s_curve_renovation_totalpandas.Series
A time series representing the total S-curve for the total renovation condition.
Returns
- pandas.Series
A time series representing the difference between the total and renovation-only S-curves. Values before the building year should be set to 0 (not yet implemented).
Notes
This function currently does not implement logic to zero out values before the building year.
Assumes both input Series are aligned on index year.
- trim_renovation_from_renovation_total(s_curve_renovation: Series, s_curve_renovation_max: Series, s_curve_renovation_total: Series, scurve_total: Series) Series[source]
Adjust the renovation S-curve by incorporating values from the total renovation curve where the total share is less than the maximum renovation share.
This function identifies time points where the total S-curve (scurve_total) is less than the maximum renovation S-curve (s_curve_renovation_max). For those points, it replaces the corresponding values in s_curve_renovation with values from s_curve_renovation_total.
Parameters
- s_curve_renovationpandas.Series
The original renovation S-curve to be adjusted.
- s_curve_renovation_maxpandas.Series
The maximum allowed values for the renovation S-curve.
- s_curve_renovation_totalpandas.Series
The total renovation S-curve including all measures.
- scurve_totalpandas.Series
The actual total S-curve values to compare against the max renovation curve.
Returns
- pandas.Series
The adjusted renovation S-curve with values merged from the total renovation curve where the total share is less than the maximum renovation share.
Notes
Assumes all input Series are aligned on the index year.
- renovation_from_small_measure(s_curve_renovation_max: Series, s_curve_small_measure_total: Series) Series[source]
Calculate the renovation S-curve by subtracting small measures from the max renovation curve.
Parameters
- s_curve_renovation_maxpandas.Series
The maximum yearly values for the renovation S-curve.
- s_curve_small_measure_totalpandas.Series
The yearly total S-curve for small measures.
Returns
- pandas.Series
The resulting renovation S-curve with values clipped at 0
- total(s_curve_renovation_total: Series, s_curve_small_measure_total: Series) Series[source]
Calculates the yearly sum of renovation and small_measure
Parameters
s_curve_renovation_total : pandas.Series s_curve_small_measure_total : pandas.Series
Returns
- pandas.Series
yearly sum of renovation and small_measure
- trim_max_value(s_curve_cumulative_small_measure: Series, s_curve_small_measure_max: Series) Series[source]
- small_measure_max(s_curve_cumulative_demolition: Series, s_curve_small_measure_never_share: Series)[source]
Calculates the maximum possible value for small_measure condition
Parameters
s_curve_cumulative_demolition : pandas.Series s_curve_small_measure_never_share : pandas.Series
Returns
- pandas.Series
Yearly maximum possible value for small_measure
- renovation_max(s_curve_cumulative_demolition: Series, s_curve_renovation_never_share: Series)[source]
Calculates the maximum possible value for renovation condition
Parameters
s_curve_cumulative_demolition : pandas.Series s_curve_renovation_never_share : pandas.Series
Returns
- pandas.Series
Yearly maximum possible value for renovation
- cumulative_renovation(s_curves_with_building_code: Series, years: YearRange) Series[source]
Return the yearly cumulative sum of renovation condition.
Parameters
s_curves_with_building_code : pandas.Series years : pandas.Series
Returns
- pandas.Series
cumulative sum of renovation
Notes
NaN values are replaced by float 0.0
- cumulative_small_measure(s_curves_with_building_code: Series, years: YearRange) Series[source]
Return the yearly cumulative sum of small_measure condition.
Parameters
s_curves_with_building_code : pandas.Series years : YearRange
Returns
- pandas.Series
cumulative sum of small_measure
Notes
NaN values are replaced by float 0.0
- transform_demolition(demolition: Series, years: YearRange) Series[source]
Filter yearly demolition for years Parameters ———- demolition : pandas.Series years : YearRange
Returns
demolition for years
- transform_to_cumulative_demolition(cumulative_demolition: DataFrame, years: YearRange) Series[source]
Filter yearly cumulative demolition for years Parameters ———- cumulative_demolition : pandas.DataFrame years : YearRange
Returns
- pandas.Series
cumulative demolition for years
- pad_s_curve_age(s_curves: DataFrame, scurve_parameters: DataFrame) DataFrame[source]
Transform scurve_parameters with s_curve to never_share. Parameters ———- s_curves : pandas.DataFrame scurve_parameters : pandas.DataFrame
Returns
pandas.DataFrame
Notes
Age is padded from -max age to 0
- scurve_from_s_curve_parameters(scurve_parameters: DataFrame) DataFrame[source]
- Create scurve new dataframe from scurve_parameters using ebm.model.area.building_condition_scurves and
ebm.model.area.building_condition_accumulated_scurves
Each row represent a building_category and building_condition at a certain age.
Parameters
scurve_parameters : pandas.DataFrame
Notes
Filters out age greater than 130 when last_age is not 150 for backwards compatability. Subject to change.
Returns
pandas.DataFrame
- accumulate_demolition(s_curves_long: DataFrame, years: YearRange) DataFrame[source]
Sets demolition in year 0 (2020) to 0.0 and sums up the yearly demolition using years
Parameters
s_curves_long : pandas.DataFrame years : YearRange
Returns
pandas.DataFrame
- merge_s_curves_and_building_code(s_curves: DataFrame, df_never_share: DataFrame, building_code_parameters: DataFrame) DataFrame[source]
Cross merge s_curves and df_never_share with all building_code in building_code_parameters
Parameters
s_curves : pandas.DataFrame df_never_share : pandas.DataFrame building_code_parameters : pandas.DataFrame
Returns
pandas.DataFrame
- transform_to_dataframe(s_curve_cumulative_demolition: Series, s_curve_original_condition: Series, s_curve_renovation: Series, s_curve_renovation_and_small_measure: Series, s_curve_small_measure: Series, s_curve_demolition: Series) DataFrame[source]
Creates a pandas DataFrame from the parameters
Parameters
s_curve_cumulative_demolition : pandas.Series s_curve_original_condition : pandas.Series s_curve_renovation : pandas.Series s_curve_renovation_and_small_measure : pandas.Series s_curve_small_measure : pandas.Series s_curve_demolition : pandas.Series
Returns
pandas.DataFrame
- transform_to_long(s_curves_by_condition: DataFrame) DataFrame[source]
Parameters
s_curves_by_condition : pandas.DataFrame
Returns
- pandas.DataFrame
transformed to long, on condition for each row
- calculate_s_curves(scurve_parameters: DataFrame, building_code_parameters: DataFrame, years: YearRange, **kwargs: DataFrame | Series) DataFrame[source]
- calculate_scurves_with_building_code(building_code_parameters, scurve_parameters, years, **kwargs)[source]
- make_s_curve_parameters(earliest_age: int | None = None, average_age: int | None = None, last_age: int | None = None, rush_years: int | None = None, rush_share: float | None = None, never_share: float | None = None, building_lifetime: int = 130, building_category: str | None = 'unknown', condition: str | None = 'unknown') DataFrame[source]
- scurve_rates(s_curve_parameters: DataFrame) DataFrame[source]
Calculate s-curve rate from dataframe.
Parameters
- s_curve_parameterspd.DataFrame
A pandas dataframe with average_age, earliest_age, rush_period, last_age, rush_share and never_share
Returns
- pd.DataFrame
With columns rate, total_share indexed by building_category, building_condition and age
- pause_building_condition_rates(s_curve_building_code: DataFrame, period: YearRange | tuple[int, int] | int, conditions: list[str] | None = None) DataFrame[source]
Apply a pause (deferral) to selected building condition rates and accumulate the results.
This function is a convenience wrapper that first shifts the specified building condition rate columns forward in time for a given pause period—simulating a deferral of activity—and then recomputes cumulative (running) totals using
accumulate_building_condition_rates.Internally, it applies two operations:
shift_building_condition_rates: Shifts selected condition rate columns forward by the length of the pause period for all years greater than or equal toperiod.start, within each group of the first two index levels.accumulate_building_condition_rates: Recomputes cumulative totals for the condition rate columns and their corresponding accumulator columns.
Parameters
- s_curve_building_codepandas.DataFrame
A DataFrame indexed by a MultiIndex with at least three levels, where index level 2 represents the year. Must contain the condition rate columns referenced in
conditionsand the accumulator columns required byaccumulate_building_condition_rates.- periodYearRange | tuple[int, int] | int
The period defining the pause: - If a
tuple[int, int]: interpreted as (start_year, end_year), inclusive. - If anint: treated as the pause start year, with the end year takenas the maximum year present in the DataFrame.
If a
YearRange: used directly.
The pause length is determined as the number of years in
period.- conditionslist[str] or None, default None
Column names representing the building condition rates to pause. If
None, defaults to:['small_measure', 'renovation', 'demolition'].
Returns
- pandas.DataFrame
A DataFrame where: - Values in the selected condition columns have been shifted forward
according to the pause period.
Accumulator columns have been updated to reflect the new running totals.
The presence and structure of the columns match the output of
accumulate_building_condition_rates.
Notes
This function does not mutate the input DataFrame; it returns a new one.
All shifting is done within each group of the first two index levels.
Years are expected to be integers.
See
shift_building_condition_ratesandaccumulate_building_condition_ratesfor detailed behavior of the underlying operations.
Examples
Pause condition rates starting from 2028 and recompute accumulations:
>>> out = pause_building_condition_rates(df, period=2028)
Pause explicitly from 2026 through 2029:
>>> out = pause_building_condition_rates(df, period=YearRange(2026, 2029))
Pause only renovation rates:
>>> out = pause_building_condition_rates( ... df, period=(2025, 2027), conditions=['renovation'] ... )
- shift_building_condition_rates(s_curve_building_code: DataFrame, period: YearRange | tuple[int, int] | int, conditions: list[str] | None = None) DataFrame[source]
Shift building condition rates over a given period forward in time.
This function takes a copy of the input DataFrame and, for the specified building conditions, shifts values occurring from period.start onwards by the length of the period (i.e., the number of years in period). The shift is done within each group defined by the first two levels of the index. Newly created gaps are filled with 0.
The intended use is to simulate a pause (deferral) in certain building-related condition rates (e.g., small measures, renovation, demolition) for a span of years, and resume them after the pause by moving the corresponding values forward.
Parameters
- s_curve_building_codepandas.DataFrame
A DataFrame indexed by a MultiIndex with at least three levels where the third level (index level number 2) is an integer year. The DataFrame must contain columns whose names match those provided in conditions. The function operates on a copy of this DataFrame and does not mutate the original.
- periodYearRange | tuple[int, int] | int
The pause period: - If a tuple[int, int], it is interpreted as (start_year, end_year) inclusive.
The start will be clamped up to the minimum year present in the DataFrame.
If an int, it is treated as the start year; the end year is set to the maximum year present in the DataFrame. The start will be clamped up to the minimum year present in the DataFrame.
- conditionslist[str] | None, default None
Column names representing the building condition rates to pause. If None, defaults to [‘small_measure’, ‘renovation’, ‘demolition’].
Returns
- pandas.DataFrame
A new DataFrame (copy of the input) where, for rows with year >= period.start and columns listed in conditions, values are shifted forward by the pause length within each group of the first two index levels. Any values shifted beyond the available years are dropped by the shift operation, and any newly introduced gaps in the target slice are filled with 0.
Raises
- ValueError
If period is not a YearRange, an int, or a valid (start_year, end_year) tuple where start_year <= end_year.
Notes
The function assumes: * The DataFrame index has a third level (at position 2) representing the year. * Years are integers and sortable. * The columns listed in conditions exist in the DataFrame.
The operation: 1. Determines the effective YearRange for the pause, clamping the start
to the minimum year in the data if needed.
Computes pause_length = len(period).
For year >= period.start, shifts the conditions columns by pause_length within each group of the first two index levels.
Fills NaN introduced by the shift with 0 in the affected slice.
Examples
Suppose df has a MultiIndex (region, building_code, year) and includes columns ‘small_measure’, ‘renovation’, and ‘demolition’.
Pause from 2028 through the max available year: >>> out = shift_building_condition_rates(df, period=2028)
Pause explicitly from 2026 to 2029 (inclusive): >>> out = shift_building_condition_rates(df, period=(2026, 2029))
Using a custom set of conditions: >>> out = shift_building_condition_rates(df, period=(2025, 2027), … conditions=[‘renovation’])
- accumulate_building_condition_rates(building_condition_rates: DataFrame) DataFrame[source]
Accumulate annual building condition rates into running totals per building category and code.
This function takes a DataFrame indexed by a MultiIndex with at least three levels, where the third level (index level 2) represents the year. For three predefined condition columns—
small_measure,renovation, anddemolition—it computes cumulative sums across years within each group of the first two index levels.The accumulation uses temporary columns: - For the first year (hard‑coded as 2020), values are taken from the corresponding
*_accaccumulator columns (defaulting to 0 where missing).For all later years (from 2021 onward), values are taken from the annual condition rate columns.
These temporary values are cumulatively summed per group, and the resulting running totals populate the
*_acccolumns.Parameters
- building_condition_ratespandas.DataFrame
Input DataFrame with a MultiIndex where index level 2 is an integer year. Must contain the columns:
'small_measure','renovation','demolition', and their accumulator counterparts:'small_measure_acc','renovation_acc','demolition_acc'.
Returns
- pandas.DataFrame
A DataFrame containing only the six columns: ``[‘small_measure’, ‘renovation’, ‘demolition’,
‘small_measure_acc’, ‘renovation_acc’, ‘demolition_acc’]``.
The accumulator columns contain cumulative sums over years within each group of index levels 0 and 1.
Notes
The function does not modify the input DataFrame; it works on a copy.
The first year is assumed to be 2020.
Accumulators for 2020 come from the existing
*_acccolumns.From 2021 onward, annual values from the condition columns are used for accumulation.
Examples
Given a MultiIndex of (region, building_code, year):
>>> out = accumulate_building_condition_rates(df) >>> out.columns Index(['small_measure', 'renovation', 'demolition', 'small_measure_acc', 'renovation_acc', 'demolition_acc'], dtype='object')
The returned accumulator columns represent cumulative totals per (region, building_code) across increasing years.
- freeze_scurves_from_year(s_curves: DataFrame, years: int | YearRange | tuple[int, int], condition_columns: list[str] | None = None) DataFrame[source]
Freeze building condition rate columns over a specified year range and resume the original trajectory after the freeze with a forward time shift.
This function operates on a MultiIndex DataFrame where the year is at index level 2. For the specified freeze period (inclusive), the values of the condition columns (as defined by
list(BuildingCondition)) are set equal to their values at the first freeze year (start). For the years following the freeze period, the original (unfrozen) time series is continued but shifted forward by the length of the freeze, preserving the trajectory shape while delaying it in time.Parameters
condition_columns : s_curves : pandas.DataFrame
Input DataFrame with a MultiIndex row index. The year must be at level 2 of the index. The DataFrame must contain one column for each member of
BuildingCondition(e.g., an Enum listing condition rate columns).- yearsint or YearRange or tuple of (int, int)
Specification of the freeze period.
If
YearRange: uses[years.start, years.end](inclusive).startis clamped to the minimum year present in the DataFrame.If
int: interpreted asstart=years(clamped to the minimum year) andend = max_yearpresent in the DataFrame.If
(start, end)tuple: uses the inclusive range after validating thatstart <= endand clampingstartto the minimum year.
Returns
- pandas.DataFrame
A copy of
s_curveswhere: - For all index keys, the condition columns in[start, end]are set totheir values at
year == start(i.e., frozen).For years
> end, the original (unfrozen) values are applied but shifted forward by(end - start)years to avoid a discontinuity.
Raises
- ValueError
If
yearsis not a supported type (YearRange,int, or 2-tuple ofintwithstart <= end).
Notes
The function assumes the year is at index level 2 and uses
pd.IndexSlice[:, :, ...]to select by year range.Only columns listed in
list(BuildingCondition)are modified; other columns remain unchanged.The freezing is inclusive of both
startandendyears.Post-freeze continuation uses:
post_freeze_rates.shift(end - start).iloc[1:]to align the shifted series; this implicitly drops the first shifted row to guard against misalignment. If you require stricter alignment guarantees, consider reindexing by explicit year keys instead of relying on
.iloc[1:].
Examples
Freeze from a specific year to the end of the dataset:
>>> df_frozen = freeze_scurves_from_year(s_curves, 2022)
Freeze across an explicit range:
>>> df_frozen = freeze_scurves_from_year(s_curves, (2021, 2023))
Freeze using a YearRange object:
>>> rng = YearRange(start=2020, end=2022) >>> df_frozen = freeze_scurves_from_year(s_curves, rng)