@@ -56,6 +56,90 @@ def coffer(policy, scenario):
56
56
return d
57
57
58
58
59
+ @orca .step ()
60
+ def preserve_affordable (year , base_year , scenario , policy , residential_units ,
61
+ taz_geography , buildings , parcels_geography ):
62
+
63
+ if scenario not in policy ["unit_preservation" ]["enable_in_scenarios" ]:
64
+ return
65
+
66
+ # join several geography columns to units table so that we can apply units
67
+ res_units = residential_units .to_frame ()
68
+ bldgs = buildings .to_frame ()
69
+ parcels_geog = parcels_geography .to_frame ()
70
+ taz_geog = taz_geography .to_frame ()
71
+
72
+ res_units = res_units .merge (bldgs [['parcel_id' ]], left_on = 'building_id' ,
73
+ right_index = True , how = 'left' ).\
74
+ merge (parcels_geog [['gg_id' , 'sesit_id' , 'tra_id' ,
75
+ 'juris' ]], left_on = 'parcel_id' , right_index = True , how = 'left' ).\
76
+ merge (taz_geog , left_on = 'zone_id' , right_index = True , how = 'left' )
77
+
78
+ s = policy ["unit_preservation" ]["settings" ]
79
+
80
+ # only preserve units that are not already deed-restricted
81
+ res_units = res_units .loc [res_units .deed_restricted != 1 ]
82
+
83
+ # initialize list of units to mark deed restricted
84
+ dr_units = []
85
+
86
+ # apply deed-restriced units by geography (county here)
87
+ for geog , value in s .items ():
88
+
89
+ # apply deed-restriced units by filters within each geography
90
+ l = ['first' , 'second' , 'third' , 'fourth' ]
91
+ for item in l :
92
+
93
+ if value [item + "_unit_filter" ] is None or \
94
+ value [item + "_unit_target" ] is None :
95
+ continue
96
+
97
+ filter_nm = value [item + "_unit_filter" ]
98
+ unit_target = value [item + "_unit_target" ]
99
+
100
+ # exclude units that have been preserved through this loop
101
+ res_units = res_units [~ res_units .index .isin (dr_units )]
102
+
103
+ # subset units to the geography
104
+ geography = policy ["unit_preservation" ]["geography" ]
105
+ geog_units = res_units .loc [res_units [geography ] == geog ]
106
+ # subset units to the filters within the geography
107
+ filter_units = geog_units .query (filter_nm )
108
+
109
+ # pull a random set of units based on the target except in cases
110
+ # where there aren't enough units in the filtered geography or
111
+ # they're already marked as deed restricted
112
+ if len (filter_units ) == 0 :
113
+ dr_units_set = []
114
+ print ("%s %s: target is %d but no units are available" %
115
+ (geog , filter_nm , unit_target ))
116
+ elif unit_target > len (filter_units ):
117
+ dr_units_set = filter_units .index
118
+ print ("%s %s: target is %d but only %d units are available" %
119
+ (geog , filter_nm , unit_target , len (filter_units )))
120
+ else :
121
+ dr_units_set = np .random .choice (filter_units .index ,
122
+ unit_target , replace = False )
123
+
124
+ dr_units .extend (dr_units_set )
125
+
126
+ # mark units as deed restriced in residential units table
127
+ residential_units = residential_units .to_frame ()
128
+ residential_units .loc [residential_units .index .isin (dr_units ),
129
+ 'deed_restricted' ] = 1
130
+ orca .add_table ("residential_units" , residential_units )
131
+
132
+ # mark units as deed restricted in buildings table
133
+ buildings = buildings .to_frame (buildings .local_columns )
134
+ new_dr_res_units = residential_units .building_id .loc [residential_units .\
135
+ index .isin (dr_units )].value_counts ()
136
+ buildings ["preserved_units" ] = (buildings ["preserved_units" ] +
137
+ buildings .index .map (new_dr_res_units ).fillna (0.0 ))
138
+ buildings ["deed_restricted_units" ] = (buildings ["deed_restricted_units" ] +
139
+ buildings .index .map (new_dr_res_units ).fillna (0.0 ))
140
+ orca .add_table ("buildings" , buildings )
141
+
142
+
59
143
@orca .injectable (cache = True )
60
144
def acct_settings (policy ):
61
145
return policy ["acct_settings" ]
0 commit comments