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.
Files changed (50) hide show
  1. checksums.yaml +4 -4
  2. data/data/standards/OpenStudio_Standards.xlsx +0 -0
  3. data/data/standards/OpenStudio_Standards_climate_zone_sets.json +96 -0
  4. data/data/standards/OpenStudio_Standards_climate_zones.json +96 -0
  5. data/data/standards/OpenStudio_Standards_construction_properties.json +11424 -0
  6. data/data/standards/OpenStudio_Standards_construction_sets.json +1746 -24
  7. data/data/standards/OpenStudio_Standards_constructions.json +409 -0
  8. data/data/standards/OpenStudio_Standards_curve_biquadratics.json +160 -0
  9. data/data/standards/OpenStudio_Standards_curve_quadratics.json +165 -0
  10. data/data/standards/OpenStudio_Standards_entryways.json +191 -0
  11. data/data/standards/OpenStudio_Standards_exterior_lighting.json +964 -0
  12. data/data/standards/OpenStudio_Standards_exterior_lighting_assumptions.json +191 -0
  13. data/data/standards/OpenStudio_Standards_ground_temperatures.json +11424 -0
  14. data/data/standards/OpenStudio_Standards_illuminated_parking_area.json +157 -0
  15. data/data/standards/OpenStudio_Standards_materials.json +2539 -745
  16. data/data/standards/OpenStudio_Standards_motors.json +420 -0
  17. data/data/standards/OpenStudio_Standards_parking.json +157 -0
  18. data/data/standards/OpenStudio_Standards_prototype_inputs.json +4410 -10
  19. data/data/standards/OpenStudio_Standards_schedules.json +13756 -8383
  20. data/data/standards/OpenStudio_Standards_space_types.json +8593 -907
  21. data/data/standards/OpenStudio_Standards_standards.json +9 -0
  22. data/data/standards/OpenStudio_Standards_templates.json +24 -0
  23. data/data/standards/OpenStudio_Standards_unitary_acs.json +924 -0
  24. data/data/standards/manage_OpenStudio_Standards.rb +1 -1
  25. data/lib/openstudio-standards/btap/btap.rb +0 -1
  26. data/lib/openstudio-standards/btap/compliance.rb +2 -5
  27. data/lib/openstudio-standards/btap/economics.rb +16 -16
  28. data/lib/openstudio-standards/btap/envelope.rb +1 -1
  29. data/lib/openstudio-standards/btap/equest.rb +7 -7
  30. data/lib/openstudio-standards/btap/fileio.rb +2 -2
  31. data/lib/openstudio-standards/btap/geometry.rb +1 -1
  32. data/lib/openstudio-standards/btap/measures.rb +16 -16
  33. data/lib/openstudio-standards/btap/mpc.rb +18 -18
  34. data/lib/openstudio-standards/btap/schedules.rb +35 -2
  35. data/lib/openstudio-standards/btap/simmanager.rb +1 -1
  36. data/lib/openstudio-standards/btap/spaceloads.rb +1 -1
  37. data/lib/openstudio-standards/btap/vintagizer.rb +1 -1
  38. data/lib/openstudio-standards/prototypes/Prototype.Model.elevators.rb +218 -0
  39. data/lib/openstudio-standards/prototypes/Prototype.Model.exterior_lights.rb +399 -0
  40. data/lib/openstudio-standards/prototypes/Prototype.Model.hvac.rb +2 -2
  41. data/lib/openstudio-standards/prototypes/Prototype.Model.rb +237 -0
  42. data/lib/openstudio-standards/prototypes/Prototype.Model.swh.rb +536 -0
  43. data/lib/openstudio-standards/standards/Standards.AirLoopHVAC.rb +6 -0
  44. data/lib/openstudio-standards/standards/Standards.Model.rb +249 -10
  45. data/lib/openstudio-standards/standards/Standards.SpaceType.rb +5 -5
  46. data/lib/openstudio-standards/standards/Standards.ThermalZone.rb +161 -0
  47. data/lib/openstudio-standards/utilities/simulation.rb +6 -4
  48. data/lib/openstudio-standards/version.rb +1 -1
  49. metadata +223 -204
  50. 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 = OsLib_Schedules.create_timeseries_from_schedule_ruleset(model,occ_schedule)
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 OsLib_Schedules.create_schedule_variable_interval_from_time_series(model,timeseries)
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.getAttribute("name").get.valueAsString
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.getAttribute("name").get.valueAsString << ","
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.setAttribute("name",construction_id)
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