Source code for ebm.model.construction

import itertools
from typing import Union

import numpy as np
import pandas as pd

from ebm.model.building_category import BuildingCategory
from ebm.model.data_classes import YearRange
from ebm.model.database_manager import DatabaseManager


[docs] def calculate_construction(building_category: BuildingCategory, demolition_floor_area: Union[pd.Series, list], database_manager: DatabaseManager, period: YearRange) -> pd.DataFrame: """ Calculate constructed floor area for buildings based using provided demolition_floor_area and input data from database_manager. Parameters. ---------- building_category: BuildingCategory demolition_floor_area: pd.Series expects index=2010..2050 database_manager: DatabaseManager period : YearRange Raises ----- This function always raises NotImplementedError. Returns ------- calculated_construction: pd.DataFrame dataframe columns include; (building_growth) (demolished_floor_area) (constructed_floor_area) (accumulated_constructed_floor_area) (total_floor_area) (floor_area_over_population_growth) (households) (household_size) (population) (population_growth) """ msg = 'calculate_construction is no longer implemented. Use extractor.calculate_construction instead.' raise NotImplementedError(msg)
[docs] def calculate_constructed_floor_area(constructed_floor_area: pd.Series, total_floor_area: pd.Series, period: YearRange) -> pd.Series: """ Calculate the constructed floor area over a specified period. Parameters ---------- constructed_floor_area : pd.Series A pandas Series to store the constructed floor area for each previous year. total_floor_area : pd.Series A pandas Series containing the total floor area for each year. period : YearRange An object containing the start year, end year, and the range of years. Returns ------- pd.Series A pandas Series containing the constructed floor area for each year in the period. Notes ----- The constructed floor area is calculated from year 6 onwards by subtracting the previous year's floor area from the current year's floor area and adding the previous year's demolition floor area. """ # Calculate constructed floor area from year 6 by subtracting last year's floor area with current floor area # and adding last year's demolition. # Calculate constructed floor area from year 6 by substracting last years floor area with current floor area # and adding last years demolition. for year in [y for y in period if y not in constructed_floor_area.index and y > period.start]: floor_area = total_floor_area.loc[year] previous_year_floor_area = total_floor_area.loc[year - 1] constructed = floor_area - previous_year_floor_area constructed_floor_area[year] = constructed constructed_floor_area.name = 'constructed_floor_area' constructed_floor_area.index.name = 'year' return constructed_floor_area
[docs] def calculate_floor_area_growth(total_floor_area: pd.Series, period: YearRange) -> pd.Series: """ Calculate the growth of floor area over a specified period. Parameters ---------- total_floor_area : pd.Series A pandas Series containing the total floor area for each year. period : YearRange An object containing the start year, end year, and the range of years. Returns ------- pd.Series A pandas Series containing the floor area growth for each year in the period. Notes ----- The growth for the first year in the period is set to NaN. The growth for the next four years is calculated based on the change in total floor area from the previous year. Examples -------- >>> total_floor_area = pd.Series({2020: 1000, 2021: 1100, 2022: 1210, 2023: 1331, 2024: 1464}) >>> period = YearRange(2020, 2024) >>> calculate_floor_area_growth(total_floor_area, period) 2020 NaN 2021 0.1000 2022 0.1000 2023 0.1000 2024 0.1000 dtype: float64 """ floor_area_growth = pd.Series(data=itertools.repeat(0.0, len(period.year_range)), index=period.year_range) floor_area_growth.loc[period.start] = np.nan # The next 4 years of building growth is calculated from change in total_floor_area for year in range(period.start + 1, period.start + 5): if year in total_floor_area.index: floor_area_growth.loc[year] = (total_floor_area.loc[year] / total_floor_area.loc[year - 1]) - 1 return floor_area_growth
[docs] def calculate_floor_area_over_building_growth(building_growth: pd.Series, population_growth: pd.Series, years: YearRange) -> pd.Series: """ Calculate the floor area over building growth for a given range of years. Parameters ---------- building_growth : pd.Series A pandas Series representing the building growth over the years. population_growth : pd.Series A pandas Series representing the population growth over the years. years : YearRange An object representing the range of years for the calculation. Returns ------- pd.Series A pandas Series representing the floor area over building growth for each year in the specified range. Notes ----- - The first year in the range is initialized with NaN. - For the first 4 years, the floor area over building growth is calculated directly from the building and population growth. - For the next 5 years, the mean floor area over building growth is used. - From the 11th year onwards, the value is set to 1. - For the years between the 11th and 21st, the value is interpolated linearly. Examples -------- >>> building_growth = pd.Series([1.2, 1.3, 1.4, 1.5, 1.6], index=[2010, 2011, 2012, 2013, 2014]) >>> pd.Series([1.1, 1.2, 1.3, 1.4, 1.5], index=[2010, 2011, 2012, 2013, 2014]) >>> years = YearRange(start=2010, end=2050) >>> calculate_floor_area_over_building_growth(building_growth, population_growth, years) 2010 NaN 2011 1.083333 2012 1.076923 2013 1.071429 2014 1.066667 2015 1.074588 2016 1.074588 2050 1.000000 2051 1.000000 dtype: float64 """ floor_area_over_population_growth = pd.Series( data=[np.nan] + list(itertools.repeat(1, len(years) - 1)), # noqa: RUF005 index=years.to_index()) # Initialize with NaN for the first year floor_area_over_population_growth.loc[years.start] = np.nan # Calculate for the next 4 years for year in building_growth[(building_growth > 0) & (building_growth.index > years.start)].index: floor_area_over_population_growth[year] = building_growth.loc[year] / population_growth.loc[year] mean_idx = building_growth[building_growth > 0].index # If there is no growth, return 0 if not any(mean_idx): return floor_area_over_population_growth # Calculate for the next 6 years using the mean mean_floor_area_population = floor_area_over_population_growth.loc[mean_idx].mean() for year in years.subset(list(years).index(max(mean_idx) + 1), 6): floor_area_over_population_growth.loc[year] = mean_floor_area_population # Set to 1 from the 11th year onwards if len(years) > 11: # noqa: PLR2004 for year in years.subset(11): floor_area_over_population_growth.loc[year] = 1 # Interpolate linearly between the 11th and 21st years for year in years.subset(11, 10): floor_area_over_population_growth.loc[year] = \ (floor_area_over_population_growth.loc[years.start + 10] - (year - (years.start + 10)) * ( (floor_area_over_population_growth.loc[ years.start + 10] - floor_area_over_population_growth.loc[ years.start + 20]) / 10)) return floor_area_over_population_growth
[docs] def calculate_population_growth(population: pd.Series) -> pd.Series: """ Calculate the annual growth in building categories based on household changes. Parameters ---------- population : pd.Series A pandas Series representing the population indexed by year. Returns ------- pd.Series A pandas Series representing the annual growth population. """ population_growth = (population / population.shift(1)) - 1 population_growth.name = 'population_growth' return population_growth
[docs] def calculate_total_floor_area(floor_area_over_population_growth: pd.Series, population_growth: pd.Series, total_floor_area: pd.Series, period: YearRange) -> pd.Series: """ Calculate the total floor area over a given period based on population growth. Parameters ---------- floor_area_over_population_growth : pd.Series A pandas Series containing the floor area change over population growth for each year. population_growth : pd.Series A pandas Series containing the population growth for each year. total_floor_area : pd.Series A pandas Series containing the total floor area for each year. period : YearRange A named tuple containing the start and end years of the period. Returns ------- pd.Series Updated pandas Series with the total floor area for each year in the given period. Notes ----- The calculation starts from `period.start + 5` to `period.end`. For each year, the total floor area is updated based on the formula: total_floor_area[year] = ((change_ratio * pop_growth) + 1) * previous_floor_area """ calculated_total_floor_area = total_floor_area.copy() years_to_update = period.subset(offset=list(period).index(max(total_floor_area.index) + 1), length=-1) for year in years_to_update: change_ratio = floor_area_over_population_growth.loc[year] growth = population_growth.loc[year] previous_floor_area = calculated_total_floor_area.loc[year - 1] calculated_total_floor_area.loc[year] = ((change_ratio * growth) + 1) * previous_floor_area calculated_total_floor_area.name = 'total_floor_area' return calculated_total_floor_area