Skip to content

Commit

Permalink
Buyout Model Implementation (#553)
Browse files Browse the repository at this point in the history
* Buyout Model Implementation

* Update CHANGELOG.md

* Suggested fixes

* add to sphinx doc and pep8 reformat

---------

Co-authored-by: Chen Wang <cwang138@illinois.edu>
  • Loading branch information
Vismayak and longshuicy authored Jun 5, 2024
1 parent 5fe7f6a commit 16932f8
Show file tree
Hide file tree
Showing 5 changed files with 236 additions and 0 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
### Added
- Gas Facility Damage Analysis [#568](https://github.com/IN-CORE/pyincore/issues/568)
- Copyrights to transportation recovery analysis [#579](https://github.com/IN-CORE/pyincore/issues/579)
- Buyout Model Analyses [#539](https://github.com/IN-CORE/pyincore/issues/539)

### Fixed
- Permission error in clearing cache process [#563](https://github.com/IN-CORE/pyincore/issues/563)
Expand Down
5 changes: 5 additions & 0 deletions docs/source/modules.rst
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,11 @@ analyses/buildingportfolio
.. autoclass:: pyincore.analyses.buildingportfolio.recovery.BuildingData
:members:

analyses/buyoutdecision
=======================
.. autoclass:: buyoutdecision.buyoutdecision.BuyoutDecision
:members:

analyses/capitalshocks
======================

Expand Down
7 changes: 7 additions & 0 deletions pyincore/analyses/buyoutdecision/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# Copyright (c) 2024 University of Illinois and others. All rights reserved.
#
# This program and the accompanying materials are made available under the
# terms of the Mozilla Public License v2.0 which accompanies this distribution,
# and is available at https://www.mozilla.org/en-US/MPL/2.0/

from pyincore.analyses.buyoutdecision.buyoutdecision import BuyoutDecision
177 changes: 177 additions & 0 deletions pyincore/analyses/buyoutdecision/buyoutdecision.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
# Copyright (c) 2024 University of Illinois and others. All rights reserved.

# This program and the accompanying materials are made available under the
# terms of the Mozilla Public License v2.0 which accompanies this distribution,
# and is available at https://www.mozilla.org/en-US/MPL/2.0/

import pandas as pd
from pyincore import BaseAnalysis
from pyincore.utils.dataprocessutil import DataProcessUtil


class BuyoutDecision(BaseAnalysis):
"""A framework to select households for buyout based on past and future flood damaged.
Args:
incore_client(IncoreClient): Service authentication.
"""

def __init__(self, incore_client):
super(BuyoutDecision, self).__init__(incore_client)

def run(self):
# Get input parameters
fema_buyout_cap = self.get_parameter('fema_buyout_cap')
residential_archetypes = self.get_parameter('residential_archetypes')

# Get input datasets
past_building_damage = self.get_input_dataset('past_building_damage').get_dataframe_from_csv(low_memory=False)
future_building_damage = self.get_input_dataset('future_building_damage').get_dataframe_from_csv(
low_memory=False)

building_inventory = self.get_input_dataset('buildings').get_dataframe_from_shapefile()

hua = (self.get_input_dataset('housing_unit_allocation').get_dataframe_from_csv(low_memory=False))
pop_dislocation = self.get_input_dataset('population_dislocation').get_dataframe_from_csv(low_memory=False)

buyout_decision_df = self.buyout_decision(past_building_damage, future_building_damage, building_inventory, hua,
pop_dislocation, fema_buyout_cap, residential_archetypes)
# Create the result dataset
self.set_result_csv_data("result", buyout_decision_df, self.get_parameter("result_name") + "_loss",
"dataframe")

def buyout_decision(self, past_building_damage, future_building_damage, building_inventory, hua, pop_dislocation,
fema_buyout_cap, residential_archetpyes):
"""Select households for buyout based on past and future flood damaged.
Args:
past_building_damage (DataFrame): Past building damage.
future_building_damage (DataFrame): Future event building damage.
building_inventory (DataFrame): Building inventory.
hua (DataFrame): Housing unit allocation.
pop_dislocation (DataFrame): Population dislocation from past hazard event.
fema_buyout_cap (float): FEMA buyout cap.
residential_archetpyes (list): Residential archetypes.
Returns:
buyout_decision_df (DataFrame): A dataframe with buyout decision for each household.
"""

past_building_max_damage = DataProcessUtil.get_max_damage_state(past_building_damage)
future_building_max_damage = DataProcessUtil.get_max_damage_state(future_building_damage)

# Criterion 1: Filter only residential buildings with damage state DS3 from past building damage
buyout_inventory = pd.merge(building_inventory, past_building_max_damage, on='guid', how='outer')
buyout_inventory = buyout_inventory[buyout_inventory['arch_wind'].isin(residential_archetpyes)
& (buyout_inventory['max_state'] == 'DS_3')]
buyout_inventory.rename(columns={'max_state': 'max_state_past_damage'}, inplace=True)

# Criterion 2: Filter only residential buildings with damage state DS3 from predicted future building damage
buyout_inventory = pd.merge(buyout_inventory, future_building_max_damage, on='guid', how='inner')
buyout_inventory = buyout_inventory[buyout_inventory['max_state'] == 'DS_3']
buyout_inventory.rename(columns={'max_state': 'max_state_future_damage'}, inplace=True)

# Criterion 3: Fall within the FEMA buyout cap
buyout_inventory = buyout_inventory[buyout_inventory['appr_bldg'] <= fema_buyout_cap]
buyout_inventory = buyout_inventory[
["guid", "appr_bldg", "max_state_future_damage", "max_state_past_damage", "geometry"]]

# Criterion 4: Use HUA to filter out buildings with 0 occupants
buyout_inventory = pd.merge(buyout_inventory, hua, on='guid', how='left')
buyout_inventory = buyout_inventory[(buyout_inventory['numprec'] != 0) & (~buyout_inventory['numprec'].isna())]

# Removing any rows with NAN values in column "Race"
buyout_inventory = buyout_inventory.dropna(subset=['race'])

# Merging with population dislocation
buyout_inventory = pd.merge(buyout_inventory, pop_dislocation[['huid', 'dislocated']], on='huid', how='left')

# Create a new column showing the appraisal value of each building ('appr_bldg' divided by the number of times
# a guid is repeated)
# For the instances that a structure has more than one housing units.
buyout_inventory['count'] = buyout_inventory.groupby('guid')['guid'].transform('count')
buyout_inventory['housing_unit_appraisal_value'] = buyout_inventory['appr_bldg'] / buyout_inventory['count']

# Cleaning the dataframe
buyout_inventory.drop(['blockid', 'bgid', 'tractid', 'FIPScounty',
'gqtype', 'BLOCKID10_str', 'placeNAME10', 'geometry_y'], axis=1, inplace=True)
buyout_inventory.rename(columns={'appr_bldg': 'building_appraisal_value', 'ownershp': 'ownership',
'dislocated_combined_dmg': 'dislocated', 'count': 'number_of_housing_units',
'geometry_x': 'geometry'},
inplace=True)
buyout_inventory = buyout_inventory[
['guid', 'huid', 'building_appraisal_value', 'housing_unit_appraisal_value', 'geometry',
'number_of_housing_units', 'numprec', 'ownership', 'race', 'hispan', 'family', 'vacancy', 'incomegroup',
'hhinc', 'randincome', 'poverty', 'huestimate', 'dislocated', 'max_state_future_damage',
'max_state_past_damage', 'x', 'y', ]]

return buyout_inventory

def get_spec(self):
return {
"name": "buyout-decision",
"description": "Buyout decision framework",
"input_parameters": [
{
'id': 'fema_buyout_cap',
'required': True,
'description': 'FEMA buyout cap',
'type': float,
},
{
'id': 'residential_archetypes',
'required': True,
'description': 'Residential archetypes',
'type': list,
},
{
'id': 'result_name',
'required': True,
'description': 'Result name',
'type': str,
}
],
"input_datasets": [
{
'id': 'past_building_damage',
'required': True,
'description': 'Building Damage Results',
'type': ['ergo:buildingDamageVer6'],
},
{
'id': 'future_building_damage',
'required': True,
'description': 'Building Damage Results',
'type': ['ergo:buildingDamageVer6'],
},
{
'id': 'buildings',
'required': True,
'description': 'Building Inventory',
'type': ['ergo:buildingInventoryVer4', 'ergo:buildingInventoryVer5',
'ergo:buildingInventoryVer6', 'ergo:buildingInventoryVer7'],
},
{
'id': 'housing_unit_allocation',
'required': True,
'description': 'A csv file with the merged dataset of the inputs, aka Probabilistic'
'House Unit Allocation',
'type': ['incore:housingUnitAllocation']
},
{
'id': 'population_dislocation',
'required': True,
'description': 'Population Dislocation from past hazard event',
'type': ['incore:popDislocation']
}
],
"output_datasets": [
{
'id': 'result',
'label': 'Buyout Decision Results',
'description': 'Buyout Decision Results',
'type': ['incore:buyoutDecision']
}
]
}
46 changes: 46 additions & 0 deletions tests/pyincore/analyses/buyoutdecision/test_buyoutdecision.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# This program and the accompanying materials are made available under the
# terms of the Mozilla Public License v2.0 which accompanies this distribution,
# and is available at https://www.mozilla.org/en-US/MPL/2.0/


from pyincore.analyses.buyoutdecision import BuyoutDecision
from pyincore import IncoreClient, Dataset
import pyincore.globals as pyglobals
import pandas as pd


def BuyoutDecisionTest():
client = IncoreClient(pyglobals.INCORE_API_DEV_URL)

past_building_damage_id = "6632d2605da5fd22b268511f"
future_building_damage_id = "6632d45b5da5fd22b2685136"
past_pop_dislocation_id = "6632d5205da5fd22b26878bb"

hua_id = "64227016b18d026e7c80d2bc"

buildings_id = "63ff69a96d3b2a308baaca12"

fema_buyout_cap = 321291.600
residential_archetypes = [1, 2, 3, 4, 5, 17]

buyout_decision = BuyoutDecision(client)
buyout_decision.set_parameter("fema_buyout_cap", fema_buyout_cap)
buyout_decision.set_parameter("residential_archetypes", residential_archetypes)
buyout_decision.set_parameter("result_name", "galveston_buyout")

buyout_decision.load_remote_input_dataset("buildings", buildings_id)
buyout_decision.load_remote_input_dataset("housing_unit_allocation", hua_id)
buyout_decision.load_remote_input_dataset("past_building_damage", past_building_damage_id)
buyout_decision.load_remote_input_dataset("future_building_damage", future_building_damage_id)
buyout_decision.load_remote_input_dataset("population_dislocation", past_pop_dislocation_id)

buyout_decision.run_analysis()

result = buyout_decision.get_output_dataset("result")
result_df = result.get_dataframe_from_csv()
print(result_df.head())
print(len(result_df))


if __name__ == "__main__":
BuyoutDecisionTest()

0 comments on commit 16932f8

Please sign in to comment.