openstudio-standards 0.1.11 → 0.1.12
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/data/standards/OpenStudio_Standards.xlsx +0 -0
- data/data/standards/OpenStudio_Standards_climate_zone_sets.json +96 -0
- data/data/standards/OpenStudio_Standards_climate_zones.json +96 -0
- data/data/standards/OpenStudio_Standards_construction_properties.json +11424 -0
- data/data/standards/OpenStudio_Standards_construction_sets.json +1746 -24
- data/data/standards/OpenStudio_Standards_constructions.json +409 -0
- data/data/standards/OpenStudio_Standards_curve_biquadratics.json +160 -0
- data/data/standards/OpenStudio_Standards_curve_quadratics.json +165 -0
- data/data/standards/OpenStudio_Standards_entryways.json +191 -0
- data/data/standards/OpenStudio_Standards_exterior_lighting.json +964 -0
- data/data/standards/OpenStudio_Standards_exterior_lighting_assumptions.json +191 -0
- data/data/standards/OpenStudio_Standards_ground_temperatures.json +11424 -0
- data/data/standards/OpenStudio_Standards_illuminated_parking_area.json +157 -0
- data/data/standards/OpenStudio_Standards_materials.json +2539 -745
- data/data/standards/OpenStudio_Standards_motors.json +420 -0
- data/data/standards/OpenStudio_Standards_parking.json +157 -0
- data/data/standards/OpenStudio_Standards_prototype_inputs.json +4410 -10
- data/data/standards/OpenStudio_Standards_schedules.json +13756 -8383
- data/data/standards/OpenStudio_Standards_space_types.json +8593 -907
- data/data/standards/OpenStudio_Standards_standards.json +9 -0
- data/data/standards/OpenStudio_Standards_templates.json +24 -0
- data/data/standards/OpenStudio_Standards_unitary_acs.json +924 -0
- data/data/standards/manage_OpenStudio_Standards.rb +1 -1
- data/lib/openstudio-standards/btap/btap.rb +0 -1
- data/lib/openstudio-standards/btap/compliance.rb +2 -5
- data/lib/openstudio-standards/btap/economics.rb +16 -16
- data/lib/openstudio-standards/btap/envelope.rb +1 -1
- data/lib/openstudio-standards/btap/equest.rb +7 -7
- data/lib/openstudio-standards/btap/fileio.rb +2 -2
- data/lib/openstudio-standards/btap/geometry.rb +1 -1
- data/lib/openstudio-standards/btap/measures.rb +16 -16
- data/lib/openstudio-standards/btap/mpc.rb +18 -18
- data/lib/openstudio-standards/btap/schedules.rb +35 -2
- data/lib/openstudio-standards/btap/simmanager.rb +1 -1
- data/lib/openstudio-standards/btap/spaceloads.rb +1 -1
- data/lib/openstudio-standards/btap/vintagizer.rb +1 -1
- data/lib/openstudio-standards/prototypes/Prototype.Model.elevators.rb +218 -0
- data/lib/openstudio-standards/prototypes/Prototype.Model.exterior_lights.rb +399 -0
- data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +2 -2
- data/lib/openstudio-standards/prototypes/Prototype.Model.rb +237 -0
- data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +536 -0
- data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +6 -0
- data/lib/openstudio-standards/standards/Standards.Model.rb +249 -10
- data/lib/openstudio-standards/standards/Standards.SpaceType.rb +5 -5
- data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +161 -0
- data/lib/openstudio-standards/utilities/simulation.rb +6 -4
- data/lib/openstudio-standards/version.rb +1 -1
- metadata +223 -204
- data/lib/openstudio-standards/btap/os_lib_schedules.rb +0 -677
@@ -318,13 +318,13 @@ module BTAP
|
|
318
318
|
#Get the occupancy schedule.
|
319
319
|
occ_schedule = people.numberofPeopleSchedule.get
|
320
320
|
#Convert schedule to timeseries and sum up timeseries objects for this space / zone.
|
321
|
-
occ_time_series =
|
321
|
+
occ_time_series = create_timeseries_from_schedule_ruleset(model,occ_schedule)
|
322
322
|
timeseries = timeseries + occ_time_series
|
323
323
|
end
|
324
324
|
end
|
325
325
|
end
|
326
326
|
#return the timeseries converted to
|
327
|
-
return
|
327
|
+
return create_schedule_variable_interval_from_time_series(model,timeseries)
|
328
328
|
end
|
329
329
|
|
330
330
|
|
@@ -897,6 +897,39 @@ module BTAP
|
|
897
897
|
return create_annual_ruleset_schedule(model, name,type, [Array.new(24){value}, Array.new(24){value},Array.new(24){value}])
|
898
898
|
end
|
899
899
|
|
900
|
+
# Creates TimeSeries from ScheduleRuleset
|
901
|
+
# @author david.goldwasser@nrel.gov
|
902
|
+
# @param model [OpenStudio::Model::Model] A model object
|
903
|
+
# @param schedule_ruleset [OpenStudio::Model::ScheduleRuleset] A schedule ruleset
|
904
|
+
# @return [OpenStudio::TimeSeries] A TimeSeries object
|
905
|
+
def self.create_timeseries_from_schedule_ruleset(model, schedule_ruleset)
|
906
|
+
yd = model.getYearDescription
|
907
|
+
start_date = yd.makeDate(1, 1)
|
908
|
+
end_date = yd.makeDate(12, 31)
|
909
|
+
|
910
|
+
values = OpenStudio::DoubleVector.new
|
911
|
+
day = OpenStudio::Time.new(1.0)
|
912
|
+
interval = OpenStudio::Time.new(1.0 / 48.0)
|
913
|
+
day_schedules = schedule_ruleset.to_ScheduleRuleset.get.getDaySchedules(start_date, end_date)
|
914
|
+
day_schedules.each do |day_schedule|
|
915
|
+
time = interval
|
916
|
+
while time < day
|
917
|
+
values << day_schedule.getValue(time)
|
918
|
+
time += interval
|
919
|
+
end
|
920
|
+
end
|
921
|
+
time_series = OpenStudio::TimeSeries.new(start_date, interval, OpenStudio.createVector(values), "")
|
922
|
+
end
|
923
|
+
|
924
|
+
# Creates ScheduleVariableInterval from TimeSeries
|
925
|
+
# @author david.goldwasser@nrel.gov
|
926
|
+
# @param model [OpenStudio::model::Model] A model object
|
927
|
+
# @param time_series [OpenStudio::TimeSeries] A TimeSeries object
|
928
|
+
# @return [OpenStudio::Model::ScheduleInterval] An interval schedule
|
929
|
+
def self.create_schedule_variable_interval_from_time_series(model, time_series)
|
930
|
+
result = OpenStudio::Model::ScheduleInterval.fromTimeSeries(time_series, model).get
|
931
|
+
end
|
932
|
+
|
900
933
|
end #module Schedules
|
901
934
|
|
902
935
|
end #module Resources
|
@@ -231,7 +231,7 @@ module BTAP
|
|
231
231
|
#@return [String] self
|
232
232
|
def addModel(model, folder = @analysisFolder )
|
233
233
|
|
234
|
-
run_name = model.building.get.
|
234
|
+
run_name = model.building.get.name.get.to_s
|
235
235
|
working_folder = OpenStudio::Path.new(folder.to_s + "\\simulations\\" + run_name )
|
236
236
|
osm_save_path = OpenStudio::Path.new(folder.to_s + "\\simulations\\" + run_name + "\\" + run_name + ".osm" )
|
237
237
|
model.save(OpenStudio::Path.new(osm_save_path), true);
|
@@ -187,7 +187,7 @@ module BTAP
|
|
187
187
|
infiltration_load.setDesignFlowRate( setDesignFlowRate ) unless setDesignFlowRate.nil?
|
188
188
|
infiltration_load.setFlowperSpaceFloorArea(setFlowperSpaceFloorArea ) unless setFlowperSpaceFloorArea.nil?
|
189
189
|
infiltration_load.setFlowperExteriorSurfaceArea(setFlowperExteriorSurfaceArea ) unless setFlowperExteriorSurfaceArea.nil?
|
190
|
-
table << infiltration_load.
|
190
|
+
table << infiltration_load.name.get.to_s << ","
|
191
191
|
table << infiltration_load.designFlowRateCalculationMethod << ","
|
192
192
|
infiltration_load.airChangesperHour.empty? ? ach = "NA" : ach = infiltration_load.airChangesperHour.get
|
193
193
|
infiltration_load.designFlowRate.empty? ? dfr = "NA" : dfr = infiltration_load.designFlowRate.get
|
@@ -96,7 +96,7 @@ class Vintagizer
|
|
96
96
|
#Remove all existing constructions from model.
|
97
97
|
BTAP::Resources::Envelope::remove_all_envelope_information( constructions_model )
|
98
98
|
#Save to model.
|
99
|
-
new_construction_set.
|
99
|
+
new_construction_set.setName(construction_id)
|
100
100
|
constructions_model.building.get.setDefaultConstructionSet( new_construction_set.clone( constructions_model ).to_DefaultConstructionSet.get )
|
101
101
|
|
102
102
|
#Give adiabatic surfaces a construction. Does not matter what. This is a bug in Openstudio that leave these surfaces unassigned by the default construction set.
|
@@ -0,0 +1,218 @@
|
|
1
|
+
# open the class to add methods to add elevators
|
2
|
+
class OpenStudio::Model::Model
|
3
|
+
|
4
|
+
# Add elevators to the model
|
5
|
+
#
|
6
|
+
# @param template [String] Valid choices are
|
7
|
+
# @return [OpenStudio::Model::ElectricEquipment] the resulting elevator
|
8
|
+
def add_elevators(template)
|
9
|
+
|
10
|
+
# determine effective number of stories
|
11
|
+
effective_num_stories = self.effective_num_stories
|
12
|
+
|
13
|
+
# determine elevator type
|
14
|
+
# todo - add logic here or upstream to have some multi-story buildings without elevators (e.g. small multi-family and small hotels)
|
15
|
+
elevator_type = nil
|
16
|
+
if effective_num_stories[:below_grade] + effective_num_stories[:above_grade] < 2
|
17
|
+
return nil # don't add elevators
|
18
|
+
elsif effective_num_stories[:below_grade] + effective_num_stories[:above_grade] < 6
|
19
|
+
elevator_type = "Hydraulic"
|
20
|
+
else
|
21
|
+
elevator_type = "Traction"
|
22
|
+
end
|
23
|
+
|
24
|
+
# determine space to put elevator load in
|
25
|
+
# largest bottom story (including basement) space that has multiplier of 1
|
26
|
+
bottom_spaces = {}
|
27
|
+
bottom_story = effective_num_stories[:story_hash].keys.first
|
28
|
+
bottom_story.spaces.each do |space|
|
29
|
+
next if space.multiplier > 1
|
30
|
+
bottom_spaces[space] = space.floorArea
|
31
|
+
end
|
32
|
+
target_space = bottom_spaces.key(bottom_spaces.values.max)
|
33
|
+
|
34
|
+
# determine number of elevators
|
35
|
+
number_of_pass_elevators = 0.0
|
36
|
+
number_of_freight_elevators = 0.0
|
37
|
+
building_type_hash = {}
|
38
|
+
|
39
|
+
# apply building type specific log to add to number of elevators based on Beyer (2009) rules of thumb
|
40
|
+
space_type_hash = self.create_space_type_hash(template)
|
41
|
+
space_type_hash.each do |space_type,hash|
|
42
|
+
|
43
|
+
# update building_type_hash
|
44
|
+
if building_type_hash.has_key?(hash[:stds_bldg_type])
|
45
|
+
building_type_hash[hash[:stds_bldg_type]] += hash[:floor_area]
|
46
|
+
else
|
47
|
+
building_type_hash[hash[:stds_bldg_type]] = hash[:floor_area]
|
48
|
+
end
|
49
|
+
|
50
|
+
# building type specific notes; prototype uses Beyer (2009) rules fo thumb
|
51
|
+
if ["Office","SmallOffice","MediumOffice","LargeOffice"].include?(hash[:stds_bldg_type])
|
52
|
+
# The office buildings have one elevator for every 45,000 ft2 (4,181 m2),
|
53
|
+
# plus one service elevator for the large office building.
|
54
|
+
pass_elevator_per_area = OpenStudio::convert(45000.0,"ft^2","m^2").get
|
55
|
+
number_of_pass_elevators += hash[:floor_area]/pass_elevator_per_area
|
56
|
+
# add freight elevators as separate step 1 if over 5k m^2 but more than one if over 50k m^2
|
57
|
+
if self.getBuilding.floorArea > 45000.0 # m^2
|
58
|
+
number_of_freight_elevators += self.getBuilding.floorArea/500000.0 # m^2
|
59
|
+
end
|
60
|
+
elsif["SmallHotel","LargeHotel"].include?(hash[:stds_bldg_type]) && hash[:stds_space_type].include?("GuestRoom")
|
61
|
+
# The hotels have one elevator for every 75 rooms, and the large hotel includes one service elevator for every two public elevators,
|
62
|
+
# plus one additional elevator for the dining and banquet facilities on the top floor.
|
63
|
+
units_per_pass_elevator = 75.0
|
64
|
+
freight_elevators_per_unit = units_per_pass_elevator/2.0
|
65
|
+
number_of_pass_elevators += hash[:num_units]/units_per_pass_elevator
|
66
|
+
number_of_freight_elevators += hash[:num_units]/freight_elevators_per_unit
|
67
|
+
elsif["LargeHotel"].include?(hash[:stds_bldg_type]) && ["Banquet","Cafe"].include?(hash[:stds_space_type])
|
68
|
+
pass_elevator_per_area = OpenStudio::convert(10000.0,"ft^2","m^2").get
|
69
|
+
number_of_pass_elevators += hash[:floor_area]/pass_elevator_per_area
|
70
|
+
elsif["MidriseApartment","HighriseApartment"].include?(hash[:stds_bldg_type]) && hash[:stds_space_type].include?("Apartment")
|
71
|
+
# The apartment building has one elevator for every 90 units
|
72
|
+
units_per_pass_elevator = 90.0
|
73
|
+
number_of_pass_elevators += hash[:num_units]/units_per_pass_elevator
|
74
|
+
elsif["Hospital"].include?(hash[:stds_bldg_type]) && ["PatRoom","ICU_PatRm","ICU_Open"].include?(hash[:stds_space_type])
|
75
|
+
# The hospital has one public and one service elevator for every 100 beds (250 total),
|
76
|
+
# plus two elevators for the offices and cafeteria on the top floor.
|
77
|
+
beds_per_pass_elevator = 100.0
|
78
|
+
number_of_pass_elevators += hash[:num_beds]/beds_per_pass_elevator
|
79
|
+
number_of_freight_elevators += hash[:num_beds]/beds_per_pass_elevator
|
80
|
+
elsif["Hospital"].include?(hash[:stds_bldg_type]) && ["Dining","Kitchen","Office"].include?(hash[:stds_space_type])
|
81
|
+
pass_elevator_per_area = OpenStudio::convert(12500.0,"ft^2","m^2").get
|
82
|
+
number_of_pass_elevators += hash[:floor_area]/pass_elevator_per_area
|
83
|
+
elsif ["PrimarySchool","SecondarySchool"].include?(hash[:stds_bldg_type])
|
84
|
+
# 210,887 ft^2 secondary school prototype has 2 elevators
|
85
|
+
pass_elevator_per_area = OpenStudio::convert(100000.0,"ft^2","m^2").get
|
86
|
+
number_of_pass_elevators += hash[:floor_area]/(pass_elevator_per_area) # freight and passenger combined
|
87
|
+
elsif ["Outpatient"].include?(hash[:stds_bldg_type])
|
88
|
+
# 210,887 ft^2 secondary school prototype has 2 elevators
|
89
|
+
#pass_elevator_per_area = OpenStudio::convert(15000.0,"ft^2","m^2").get
|
90
|
+
#number_of_pass_elevators += hash[:floor_area]/(pass_elevator_per_area) # freight and passenger combined
|
91
|
+
elsif ["Warehouse"].include?(hash[:stds_bldg_type])
|
92
|
+
freight_elevator_per_area = OpenStudio::convert(250000.0,"ft^2","m^2").get
|
93
|
+
number_of_freight_elevators += hash[:floor_area]/freight_elevator_per_area
|
94
|
+
else
|
95
|
+
# todo - improve catchall for building types without elevator data, using same value as what Outpatient would be if not already in space type
|
96
|
+
# includes RetailStandalone, RetailStripmall, QuickServiceRestaurant, FullServiceRestaurant, SuperMarket (made unique logic above for warehouse)
|
97
|
+
|
98
|
+
pass_elevator_per_area = OpenStudio::convert(15000.0,"ft^2","m^2").get
|
99
|
+
number_of_pass_elevators += hash[:floor_area]/pass_elevator_per_area
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
# adjust number of elevators (can be double but if not 0 must be at least 1.0)
|
105
|
+
if number_of_pass_elevators > 0.0 and number_of_pass_elevators < 1.0
|
106
|
+
number_of_pass_elevators = 1.0
|
107
|
+
end
|
108
|
+
if number_of_freight_elevators > 0.0 and number_of_freight_elevators < 1.0
|
109
|
+
number_of_freight_elevators = 1.0
|
110
|
+
end
|
111
|
+
number_of_elevators = number_of_pass_elevators + number_of_freight_elevators
|
112
|
+
|
113
|
+
|
114
|
+
building_type = building_type_hash.key(building_type_hash.values.max)
|
115
|
+
# rename space types as needed
|
116
|
+
if building_type == "Office"
|
117
|
+
building_type = self.remap_office(building_type_hash["Office"])
|
118
|
+
end
|
119
|
+
if building_type == "SmallHotel" then building_type = "LargeHotel" end # no elevator schedules for SmallHotel
|
120
|
+
if building_type == "PrimarySchool" then building_type = "SecondarySchool" end # no elevator schedules for PrimarySchool
|
121
|
+
if building_type == "Retail" then building_type = "RetailStandalone" end # no elevator schedules for PrimarySchool
|
122
|
+
if building_type == "StripMall" then building_type = "RetailStripmall" end # no elevator schedules for PrimarySchool
|
123
|
+
if building_type == "Outpatient"
|
124
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.elevators', "Outpatient ElevatorPumpRoom plug loads contain the elevator loads. Not adding extra elevator loads on top of it.")
|
125
|
+
end
|
126
|
+
|
127
|
+
# Retrieve the Prototype Inputs from JSON
|
128
|
+
search_criteria = {
|
129
|
+
'template' => template,
|
130
|
+
'building_type' => building_type
|
131
|
+
}
|
132
|
+
|
133
|
+
prototype_input = find_object($os_standards['prototype_inputs'], search_criteria, nil)
|
134
|
+
if prototype_input.nil?
|
135
|
+
OpenStudio.logFree(OpenStudio::Error, 'Prototype.Model.elevators', "Could not find prototype inputs for #{search_criteria}.")
|
136
|
+
return false
|
137
|
+
end
|
138
|
+
|
139
|
+
# assign schedules
|
140
|
+
if ["Office","SmallOffice","MediumOffice","LargeOffice","MidriseApartment","HighriseApartment","SecondarySchool"].include?(building_type)
|
141
|
+
elevator_schedule = prototype_input['elevator_schedule']
|
142
|
+
elevator_fan_schedule = prototype_input['elevator_fan_schedule']
|
143
|
+
elevator_lights_schedule = prototype_input['elevator_fan_schedule']
|
144
|
+
elsif ["LargeHotel","Hospital"].include?(building_type)
|
145
|
+
elevator_schedule = prototype_input['exterior_fuel_equipment1_schedule']
|
146
|
+
elevator_fan_schedule = prototype_input['exterior_fuel_equipment2_schedule']
|
147
|
+
elevator_lights_schedule = prototype_input['exterior_fuel_equipment2_schedule']
|
148
|
+
else
|
149
|
+
|
150
|
+
# identify occupancy schedule from largest space type of this building type
|
151
|
+
space_type_size = {}
|
152
|
+
space_type_hash.each do |space_type,hash|
|
153
|
+
next if not building_type.include?(hash[:stds_bldg_type])
|
154
|
+
space_type_size[space_type] = hash[:floor_area]
|
155
|
+
end
|
156
|
+
occ_sch = space_type_size.key(space_type_size.values.max).defaultScheduleSet.get.numberofPeopleSchedule.get
|
157
|
+
|
158
|
+
# clone and assign to elevator
|
159
|
+
elev_sch = occ_sch.clone(self)
|
160
|
+
elevator_schedule = elev_sch.name.to_s
|
161
|
+
elevator_fan_schedule = elev_sch.name.to_s
|
162
|
+
elevator_lights_schedule = elev_sch.name.to_s
|
163
|
+
|
164
|
+
# todo - scale down peak value based on building type lookup, or make parametric schedule based on hours of operation
|
165
|
+
# includes RetailStandalone, RetailStripmall, QuickServiceRestaurant, FullServiceRestaurant, SuperMarket (made unique logic above for warehouse)
|
166
|
+
|
167
|
+
if building_type == "Warehouse"
|
168
|
+
# alter default profile, summer, winter, and rules
|
169
|
+
max_value = 0.2
|
170
|
+
elev_sch = elev_sch.to_ScheduleRuleset.get
|
171
|
+
day_schedules = []
|
172
|
+
elev_sch.scheduleRules.each do |rule|
|
173
|
+
day_schedules << rule.daySchedule
|
174
|
+
end
|
175
|
+
day_schedules << elev_sch.defaultDaySchedule
|
176
|
+
day_schedules << elev_sch.summerDesignDaySchedule
|
177
|
+
day_schedules << elev_sch.winterDesignDaySchedule
|
178
|
+
|
179
|
+
day_schedules.each do |day_schedule|
|
180
|
+
values = day_schedule.values
|
181
|
+
times = day_schedule.times
|
182
|
+
values.each_with_index do |value,i|
|
183
|
+
if value > max_value
|
184
|
+
day_schedule.addValue(times[i],max_value)
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
|
192
|
+
# todo - currently add elevator doesn't allow me to choose the size of the elevator?
|
193
|
+
# ref bldg pdf has formula for motor hp based on weight, speed, counterweight fraction and mech eff (in 5.1.4)
|
194
|
+
|
195
|
+
# todo - should schedules change based on traction vs. hydraulic vs. just taking what is in prototype.
|
196
|
+
|
197
|
+
# call add_elevator in Prototype.hvac_systems.rb to create elevator objects
|
198
|
+
elevator = self.add_elevator(template,
|
199
|
+
target_space,
|
200
|
+
number_of_elevators,
|
201
|
+
elevator_type,
|
202
|
+
elevator_schedule,
|
203
|
+
elevator_fan_schedule,
|
204
|
+
elevator_lights_schedule,
|
205
|
+
building_type)
|
206
|
+
|
207
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.elevators', "Adding #{elevator.multiplier} #{elevator_type} elevators to the model in #{target_space.name}.")
|
208
|
+
|
209
|
+
# check fraction lost on heat from elevator if traction, change to 100% lost if not setup that way.
|
210
|
+
if elevator_type == "Traction"
|
211
|
+
elevator.definition.to_ElectricEquipmentDefinition.get.setFractionLost(1.0)
|
212
|
+
end
|
213
|
+
|
214
|
+
return elevator
|
215
|
+
|
216
|
+
end
|
217
|
+
|
218
|
+
end
|
@@ -0,0 +1,399 @@
|
|
1
|
+
# open the class to add methods to add exterior lighting
|
2
|
+
class OpenStudio::Model::Model
|
3
|
+
|
4
|
+
# Add exterior lighting to the model
|
5
|
+
#
|
6
|
+
# @param template [String] Valid choices are
|
7
|
+
# @param exterior_lighting_zone_number [Integer] Valid choices are
|
8
|
+
# @return [Hash] the resulting exterior lights
|
9
|
+
# @todo - would be nice to add argument for some building types (SmallHotel, MidriseApartment, PrimarySchool, SecondarySchool, RetailStripmall) if it has interior or exterior circulation.
|
10
|
+
def add_typical_exterior_lights(template,exterior_lighting_zone_number,onsite_parking_fraction = 1.0, add_base_site_allowance = false, use_model_for_entries_and_canopies = false)
|
11
|
+
|
12
|
+
exterior_lights = {}
|
13
|
+
installed_power = 0.0
|
14
|
+
|
15
|
+
# populate search hash
|
16
|
+
search_criteria = {
|
17
|
+
'template' => template,
|
18
|
+
'exterior_lighting_zone_number' => exterior_lighting_zone_number,
|
19
|
+
}
|
20
|
+
|
21
|
+
# load exterior_lighting_properties
|
22
|
+
exterior_lighting_properties = self.find_object($os_standards['exterior_lighting'], search_criteria)
|
23
|
+
|
24
|
+
# get building types and ratio (needed to get correct schedules, parking area, entries, canopies, and drive throughs)
|
25
|
+
space_type_hash = self.create_space_type_hash(template)
|
26
|
+
|
27
|
+
# get model specific values to map to exterior_lighting_properties
|
28
|
+
area_length_count_hash = self.create_exterior_lighting_area_length_count_hash(template,space_type_hash,use_model_for_entries_and_canopies)
|
29
|
+
|
30
|
+
# using midnight to 6am setback or shutdown
|
31
|
+
start_setback_shutoff = {:hr => 24, :min => 0}
|
32
|
+
end_setback_shutoff = {:hr => 6, :min => 0}
|
33
|
+
shuttoff = false
|
34
|
+
setback = false
|
35
|
+
if exterior_lighting_properties["building_facade_and_landscape_automatic_shut_off"] == 1
|
36
|
+
ext_lights_sch_facade_and_landscape = OpenStudio::Model::ScheduleRuleset.new(self)
|
37
|
+
default_day = ext_lights_sch_facade_and_landscape.defaultDaySchedule
|
38
|
+
default_day.addValue(OpenStudio::Time.new(0, end_setback_shutoff[:hr], end_setback_shutoff[:min], 0), 0.0)
|
39
|
+
default_day.addValue(OpenStudio::Time.new(0, start_setback_shutoff[:hr], start_setback_shutoff[:min], 0), 1.0)
|
40
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Facade and Landscape exterior lights shut off from #{start_setback_shutoff} to #{end_setback_shutoff}")
|
41
|
+
else
|
42
|
+
ext_lights_sch_facade_and_landscape = self.alwaysOnDiscreteSchedule
|
43
|
+
end
|
44
|
+
if not exterior_lighting_properties["occupancy_setback_reduction"].nil? and exterior_lighting_properties["occupancy_setback_reduction"] > 0.0
|
45
|
+
ext_lights_sch_other = OpenStudio::Model::ScheduleRuleset.new(self)
|
46
|
+
setback_value = 1.0 - exterior_lighting_properties["occupancy_setback_reduction"]
|
47
|
+
default_day = ext_lights_sch_other.defaultDaySchedule
|
48
|
+
default_day.addValue(OpenStudio::Time.new(0, end_setback_shutoff[:hr], end_setback_shutoff[:min], 0), setback_value)
|
49
|
+
default_day.addValue(OpenStudio::Time.new(0, start_setback_shutoff[:hr], start_setback_shutoff[:min], 0), 1.0)
|
50
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Non Facade and Landscape lights reduce by #{exterior_lighting_properties["occupancy_setback_reduction"]*100} % from #{start_setback_shutoff} to #{end_setback_shutoff}")
|
51
|
+
else
|
52
|
+
ext_lights_sch_other = self.alwaysOnDiscreteSchedule
|
53
|
+
end
|
54
|
+
|
55
|
+
# add exterior lights for parking area
|
56
|
+
if area_length_count_hash[:parking_area_and_drives_area] > 0
|
57
|
+
|
58
|
+
# lighting values
|
59
|
+
multiplier = area_length_count_hash[:parking_area_and_drives_area] * onsite_parking_fraction
|
60
|
+
power = exterior_lighting_properties["parking_areas_and_drives"]
|
61
|
+
name_prefix = "Parking Areas and Drives"
|
62
|
+
|
63
|
+
# create ext light def
|
64
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W/ft^2 of lighting for #{multiplier} ft^2 of parking area.")
|
65
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
66
|
+
ext_lights_def.setName("#{name_prefix} Def (W/ft^2)")
|
67
|
+
ext_lights_def.setDesignLevel(power)
|
68
|
+
|
69
|
+
# create ext light inst
|
70
|
+
#creating exterior lights object
|
71
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_other)
|
72
|
+
ext_lights.setMultiplier(multiplier)
|
73
|
+
ext_lights.setName(name_prefix)
|
74
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
75
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
76
|
+
exterior_lights[name_prefix] = ext_lights
|
77
|
+
|
78
|
+
# update installed power
|
79
|
+
installed_power += power * multiplier
|
80
|
+
end
|
81
|
+
|
82
|
+
# add exterior lights for facades
|
83
|
+
if area_length_count_hash[:building_facades] > 0
|
84
|
+
|
85
|
+
# lighting values
|
86
|
+
multiplier = area_length_count_hash[:building_facades]
|
87
|
+
power = exterior_lighting_properties["building_facades"]
|
88
|
+
name_prefix = "Building Facades"
|
89
|
+
|
90
|
+
# create ext light def
|
91
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W/ft^2 of lighting for #{multiplier} ft^2 of building facade area.")
|
92
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
93
|
+
ext_lights_def.setName("#{name_prefix} Def (W/ft^2)")
|
94
|
+
ext_lights_def.setDesignLevel(power)
|
95
|
+
|
96
|
+
# create ext light inst
|
97
|
+
#creating exterior lights object
|
98
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_facade_and_landscape)
|
99
|
+
ext_lights.setMultiplier(multiplier)
|
100
|
+
ext_lights.setName(name_prefix)
|
101
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
102
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
103
|
+
exterior_lights[name_prefix] = ext_lights
|
104
|
+
|
105
|
+
# update installed power
|
106
|
+
installed_power += power * multiplier
|
107
|
+
end
|
108
|
+
|
109
|
+
# add exterior lights for main entries
|
110
|
+
if area_length_count_hash[:main_entries] > 0
|
111
|
+
|
112
|
+
# lighting values
|
113
|
+
multiplier = area_length_count_hash[:main_entries]
|
114
|
+
power = exterior_lighting_properties["main_entries"]
|
115
|
+
name_prefix = "Main Entries"
|
116
|
+
|
117
|
+
# create ext light def
|
118
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W/ft of lighting for #{multiplier} ft of main entry length.")
|
119
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
120
|
+
ext_lights_def.setName("#{name_prefix} Def (W/ft)")
|
121
|
+
ext_lights_def.setDesignLevel(power)
|
122
|
+
|
123
|
+
# create ext light inst
|
124
|
+
#creating exterior lights object
|
125
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_other)
|
126
|
+
ext_lights.setMultiplier(multiplier)
|
127
|
+
ext_lights.setName(name_prefix)
|
128
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
129
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
130
|
+
exterior_lights[name_prefix] = ext_lights
|
131
|
+
|
132
|
+
# update installed power
|
133
|
+
installed_power += power * multiplier
|
134
|
+
end
|
135
|
+
|
136
|
+
# add exterior lights for other doors
|
137
|
+
if area_length_count_hash[:other_doors] > 0
|
138
|
+
|
139
|
+
# lighting values
|
140
|
+
multiplier = area_length_count_hash[:other_doors]
|
141
|
+
power = exterior_lighting_properties["other_doors"]
|
142
|
+
name_prefix = "Other Doors"
|
143
|
+
|
144
|
+
# create ext light def
|
145
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W/ft of lighting for #{multiplier} ft of other doors.")
|
146
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
147
|
+
ext_lights_def.setName("#{name_prefix} Def (W/ft)")
|
148
|
+
ext_lights_def.setDesignLevel(power)
|
149
|
+
|
150
|
+
# create ext light inst
|
151
|
+
#creating exterior lights object
|
152
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_other)
|
153
|
+
ext_lights.setMultiplier(multiplier)
|
154
|
+
ext_lights.setName(name_prefix)
|
155
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
156
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
157
|
+
exterior_lights[name_prefix] = ext_lights
|
158
|
+
|
159
|
+
# update installed power
|
160
|
+
installed_power += power * multiplier
|
161
|
+
end
|
162
|
+
|
163
|
+
# add exterior lights for entry canopies
|
164
|
+
if area_length_count_hash[:canopy_entry_area] > 0
|
165
|
+
|
166
|
+
# lighting values
|
167
|
+
multiplier = area_length_count_hash[:canopy_entry_area]
|
168
|
+
power = exterior_lighting_properties["entry_canopies"]
|
169
|
+
name_prefix = "Entry Canopies"
|
170
|
+
|
171
|
+
# create ext light def
|
172
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W/ft^2 of lighting for #{multiplier} ft^2 of building entry canopies.")
|
173
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
174
|
+
ext_lights_def.setName("#{name_prefix} Def (W/ft^2)")
|
175
|
+
ext_lights_def.setDesignLevel(power)
|
176
|
+
|
177
|
+
# create ext light inst
|
178
|
+
#creating exterior lights object
|
179
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_other)
|
180
|
+
ext_lights.setMultiplier(multiplier)
|
181
|
+
ext_lights.setName(name_prefix)
|
182
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
183
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
184
|
+
exterior_lights[name_prefix] = ext_lights
|
185
|
+
|
186
|
+
# update installed power
|
187
|
+
installed_power += power * multiplier
|
188
|
+
end
|
189
|
+
|
190
|
+
# add exterior lights for emergency canopies
|
191
|
+
if area_length_count_hash[:canopy_emergency_area] > 0
|
192
|
+
|
193
|
+
# lighting values
|
194
|
+
multiplier = area_length_count_hash[:canopy_emergency_area]
|
195
|
+
power = exterior_lighting_properties["loading_areas_for_emergency_vehicles"]
|
196
|
+
name_prefix = "Emergency Canopies"
|
197
|
+
|
198
|
+
# create ext light def
|
199
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W/ft^2 of lighting for #{multiplier} ft^2 of building emergency canopies.")
|
200
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
201
|
+
ext_lights_def.setName("#{name_prefix} Def (W/ft^2)")
|
202
|
+
ext_lights_def.setDesignLevel(power)
|
203
|
+
|
204
|
+
# create ext light inst
|
205
|
+
#creating exterior lights object
|
206
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_other)
|
207
|
+
ext_lights.setMultiplier(multiplier)
|
208
|
+
ext_lights.setName(name_prefix)
|
209
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
210
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
211
|
+
exterior_lights[name_prefix] = ext_lights
|
212
|
+
|
213
|
+
# update installed power
|
214
|
+
installed_power += power * multiplier
|
215
|
+
end
|
216
|
+
|
217
|
+
# add exterior lights for drive through windows
|
218
|
+
if area_length_count_hash[:drive_through_windows] > 0
|
219
|
+
|
220
|
+
# lighting values
|
221
|
+
multiplier = area_length_count_hash[:drive_through_windows]
|
222
|
+
power = exterior_lighting_properties["drive_through_windows_and_doors"]
|
223
|
+
name_prefix = "Drive Through Windows"
|
224
|
+
|
225
|
+
# create ext light def
|
226
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W/drive through window of lighting for #{multiplier} drie through windows.")
|
227
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
228
|
+
ext_lights_def.setName("#{name_prefix} Def (W/ft^2)")
|
229
|
+
ext_lights_def.setDesignLevel(power)
|
230
|
+
|
231
|
+
# create ext light inst
|
232
|
+
#creating exterior lights object
|
233
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_other)
|
234
|
+
ext_lights.setMultiplier(multiplier)
|
235
|
+
ext_lights.setName(name_prefix)
|
236
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
237
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
238
|
+
exterior_lights[name_prefix] = ext_lights
|
239
|
+
|
240
|
+
# update installed power
|
241
|
+
installed_power += power * multiplier
|
242
|
+
end
|
243
|
+
|
244
|
+
# todo - add_base_site_lighting_allowance (non landscaping tradable lighting)
|
245
|
+
# add exterior lights for drive through windows
|
246
|
+
if add_base_site_allowance
|
247
|
+
|
248
|
+
# lighting values
|
249
|
+
if not exterior_lighting_properties["base_site_allowance_power"].nil?
|
250
|
+
power = exterior_lighting_properties["base_site_allowance_power"]
|
251
|
+
elsif not exterior_lighting_properties["base_site_allowance_fraction"].nil?
|
252
|
+
power = exterior_lighting_properties["base_site_allowance_fraction"] * installed_power # shold be of allowed vs. installed, but hard to calculate
|
253
|
+
else
|
254
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Cannot determine target base site allowance power, will set to 0 W.")
|
255
|
+
power = 0.0
|
256
|
+
end
|
257
|
+
name_prefix = "Base Site Allowance"
|
258
|
+
|
259
|
+
# create ext light def
|
260
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Added #{power} W of non landscape tradable exterior lighting. Wil follow occupancy setback reduction.")
|
261
|
+
ext_lights_def = OpenStudio::Model::ExteriorLightsDefinition.new(self)
|
262
|
+
ext_lights_def.setName("#{name_prefix} Def (W)")
|
263
|
+
ext_lights_def.setDesignLevel(power)
|
264
|
+
|
265
|
+
# create ext light inst
|
266
|
+
#creating exterior lights object
|
267
|
+
ext_lights = OpenStudio::Model::ExteriorLights.new(ext_lights_def,ext_lights_sch_other)
|
268
|
+
ext_lights.setName(name_prefix)
|
269
|
+
ext_lights.setControlOption(exterior_lighting_properties["control_option"])
|
270
|
+
ext_lights.setEndUseSubcategory(name_prefix)
|
271
|
+
exterior_lights[name_prefix] = ext_lights
|
272
|
+
|
273
|
+
# don't need to update installed power for this
|
274
|
+
end
|
275
|
+
|
276
|
+
return exterior_lights
|
277
|
+
|
278
|
+
end
|
279
|
+
|
280
|
+
# get exterior lighting area's, distances, and counts
|
281
|
+
#
|
282
|
+
# @return [hash] hash of exterior lighting value types and building type and model specific values
|
283
|
+
# @todo - add code in to determine number of entries and canopy area from model geoemtry
|
284
|
+
# @todo - come up with better logic for entry widths
|
285
|
+
def create_exterior_lighting_area_length_count_hash(template,space_type_hash,use_model_for_entries_and_canopies)
|
286
|
+
|
287
|
+
area_length_count_hash = {}
|
288
|
+
|
289
|
+
# populate building_type_hash, used to remap office
|
290
|
+
building_type_hash = {}
|
291
|
+
space_type_hash.each do |space_type,hash|
|
292
|
+
|
293
|
+
# update building_type_hash
|
294
|
+
if building_type_hash.has_key?(hash[:stds_bldg_type])
|
295
|
+
building_type_hash[hash[:stds_bldg_type]] += hash[:floor_area]
|
296
|
+
else
|
297
|
+
building_type_hash[hash[:stds_bldg_type]] = hash[:floor_area]
|
298
|
+
end
|
299
|
+
end
|
300
|
+
# rename Office to SmallOffice MediumOffice or LargeOffice
|
301
|
+
office_type = nil
|
302
|
+
if building_type_hash.has_key?("Office")
|
303
|
+
office_type = self.remap_office(building_type_hash["Office"])
|
304
|
+
end
|
305
|
+
|
306
|
+
# parking areas and drives area
|
307
|
+
parking_area_and_drives_area = 0.0
|
308
|
+
main_entries = 0.0
|
309
|
+
other_doors = 0.0
|
310
|
+
canopy_entry_area = 0.0
|
311
|
+
canopy_emergency_area = 0.0
|
312
|
+
drive_through_windows = 0.0
|
313
|
+
# run space_type_hash to get number of students and units and building type floor area totals
|
314
|
+
space_type_hash.each do |space_type,hash|
|
315
|
+
|
316
|
+
# rename space types as needed
|
317
|
+
if hash[:stds_bldg_type] == "Office"
|
318
|
+
building_type = office_type
|
319
|
+
else
|
320
|
+
building_type = hash[:stds_bldg_type]
|
321
|
+
end
|
322
|
+
|
323
|
+
# store floor area ip
|
324
|
+
floor_area_ip = OpenStudio::convert(hash[:floor_area],"m^2","ft^2").get
|
325
|
+
num_spots = 0.0
|
326
|
+
|
327
|
+
# load illuminated_parking_area_properties
|
328
|
+
search_criteria = {'building_type' => building_type}
|
329
|
+
illuminated_parking_area_lookup = self.find_object($os_standards['parking'], search_criteria)
|
330
|
+
if not illuminated_parking_area_lookup["building_area_per_spot"].nil?
|
331
|
+
num_spots += floor_area_ip / illuminated_parking_area_lookup["building_area_per_spot"].to_f
|
332
|
+
elsif not illuminated_parking_area_lookup["units_per_spot"].nil?
|
333
|
+
num_spots += hash[:num_units] / illuminated_parking_area_lookup["units_per_spot"].to_f
|
334
|
+
elsif not illuminated_parking_area_lookup["students_per_spot"].nil?
|
335
|
+
num_spots += hash[:num_students] / illuminated_parking_area_lookup["students_per_spot"].to_f
|
336
|
+
elsif not illuminated_parking_area_lookup["beds_per_spot"].nil?
|
337
|
+
num_spots += hash[:num_beds] / illuminated_parking_area_lookup["beds_per_spot"].to_f
|
338
|
+
else
|
339
|
+
OpenStudio.logFree(OpenStudio::Info, 'Prototype.Model.exterior_lights', "Unexpected key, can't calculate number of parking spots from #{illuminated_parking_area_lookup.keys.first}.")
|
340
|
+
end
|
341
|
+
parking_area_and_drives_area += num_spots * illuminated_parking_area_lookup["parking_area_per_spot"]
|
342
|
+
|
343
|
+
# load illuninated_parking_area_properties
|
344
|
+
search_criteria = {'building_type' => building_type}
|
345
|
+
exterior_lighting_assumptions_lookup = self.find_object($os_standards['entryways'], search_criteria)
|
346
|
+
|
347
|
+
# lookup doors
|
348
|
+
if use_model_for_entries_and_canopies
|
349
|
+
# todo - get number of entries and canopy size from model geometry
|
350
|
+
else
|
351
|
+
|
352
|
+
# no source for width of different entry types
|
353
|
+
main_entry_width_ip = 8 # ft
|
354
|
+
other_doors_width_ip = 4 # ft
|
355
|
+
|
356
|
+
# rollup not used
|
357
|
+
main_entries += (floor_area_ip/10000.0) * exterior_lighting_assumptions_lookup["entrance_doors_per_10,000"] * main_entry_width_ip
|
358
|
+
other_doors += (floor_area_ip/10000.0) * exterior_lighting_assumptions_lookup["others_doors_per_10,000"] * other_doors_width_ip
|
359
|
+
if not exterior_lighting_assumptions_lookup["floor_area_per_drive_through_window"].nil?
|
360
|
+
drive_through_windows += floor_area_ip / exterior_lighting_assumptions_lookup["floor_area_per_drive_through_window"].to_f
|
361
|
+
end
|
362
|
+
|
363
|
+
|
364
|
+
# if any space types of building type that has canopy, then use that value, don't add to count for additional space types
|
365
|
+
if not exterior_lighting_assumptions_lookup["entrance_canopies"].nil? and not exterior_lighting_assumptions_lookup["canopy_size"].nil?
|
366
|
+
canopy_entry_area = exterior_lighting_assumptions_lookup["entrance_canopies"] * exterior_lighting_assumptions_lookup["canopy_size"]
|
367
|
+
end
|
368
|
+
if not exterior_lighting_assumptions_lookup["emergency_canopies"].nil? and not exterior_lighting_assumptions_lookup["canopy_size"].nil?
|
369
|
+
canopy_emergency_area = exterior_lighting_assumptions_lookup["emergency_canopies"]* exterior_lighting_assumptions_lookup["canopy_size"]
|
370
|
+
end
|
371
|
+
|
372
|
+
end
|
373
|
+
|
374
|
+
end
|
375
|
+
|
376
|
+
# populate hash
|
377
|
+
area_length_count_hash[:parking_area_and_drives_area] = parking_area_and_drives_area
|
378
|
+
area_length_count_hash[:main_entries] = main_entries
|
379
|
+
area_length_count_hash[:other_doors] = other_doors
|
380
|
+
area_length_count_hash[:canopy_entry_area] = canopy_entry_area
|
381
|
+
area_length_count_hash[:canopy_emergency_area] = canopy_emergency_area
|
382
|
+
area_length_count_hash[:drive_through_windows] = drive_through_windows
|
383
|
+
|
384
|
+
# determine effective number of stories to find first above grade story exterior wall area
|
385
|
+
effective_num_stories = self.effective_num_stories
|
386
|
+
ground_story = effective_num_stories[:story_hash].keys[effective_num_stories[:below_grade]]
|
387
|
+
ground_story_ext_wall_area_si = effective_num_stories[:story_hash][ground_story][:ext_wall_area]
|
388
|
+
ground_story_ext_wall_area_ip = OpenStudio::convert(ground_story_ext_wall_area_si,"m^2","ft^2").get
|
389
|
+
|
390
|
+
# building_facades
|
391
|
+
# reference buildings uses first story and plenum area all around
|
392
|
+
# prototype uses Table 4.19 by building type lit facde vs. total facade.
|
393
|
+
area_length_count_hash[:building_facades] = ground_story_ext_wall_area_ip
|
394
|
+
|
395
|
+
return area_length_count_hash
|
396
|
+
|
397
|
+
end
|
398
|
+
|
399
|
+
end
|