Module: Outpatient

Defined in:
lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb

Overview

Custom changes for the Outpatient prototype. These are changes that are inconsistent with other prototype building types.

Instance Method Summary collapse

Instance Method Details

#add_door_infiltration(climate_zone, model) ⇒ Object


137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 137

def add_door_infiltration(climate_zone, model)
  # add extra infiltration for vestibule door
  case template
    when 'DOE Ref 1980-2004', 'DOE Ref Pre-1980'
      return true
    else
      vestibule_space = model.getSpaceByName('Floor 1 Vestibule').get
      infiltration_vestibule_door = OpenStudio::Model::SpaceInfiltrationDesignFlowRate.new(model)
      infiltration_vestibule_door.setName('Vestibule door Infiltration')
      infiltration_rate_vestibule_door = 0
      case template
        when '90.1-2004'
          infiltration_rate_vestibule_door = 1.186002811
          infiltration_vestibule_door.setSchedule(model_add_schedule(model, 'OutPatientHealthCare INFIL_Door_Opening_SCH_0.144'))
        when '90.1-2007', '90.1-2010', '90.1-2013'
          case climate_zone
            when 'ASHRAE 169-2006-1A', 'ASHRAE 169-2006-2A', 'ASHRAE 169-2006-2B'
              infiltration_rate_vestibule_door = 1.186002811
              infiltration_vestibule_door.setSchedule(model_add_schedule(model, 'OutPatientHealthCare INFIL_Door_Opening_SCH_0.144'))
            else
              infiltration_rate_vestibule_door = 0.776824762
              infiltration_vestibule_door.setSchedule(model_add_schedule(model, 'OutPatientHealthCare INFIL_Door_Opening_SCH_0.131'))
          end
      end
      infiltration_vestibule_door.setDesignFlowRate(infiltration_rate_vestibule_door)
      infiltration_vestibule_door.setSpace(vestibule_space)
  end
end

#add_extra_equip_elevator_pump_room(model) ⇒ Object


65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 65

def add_extra_equip_elevator_pump_room(model)
  elevator_pump_room = model.getSpaceByName('Floor 1 Elevator Pump Room').get
  elec_equip_def = OpenStudio::Model::ElectricEquipmentDefinition.new(model)
  elec_equip_def.setName('Elevator Pump Room Electric Equipment Definition')
  elec_equip_def.setFractionLatent(0)
  elec_equip_def.setFractionRadiant(0.1)
  elec_equip_def.setFractionLost(0.9)
  elec_equip_def.setDesignLevel(48_165)
  elec_equip = OpenStudio::Model::ElectricEquipment.new(elec_equip_def)
  elec_equip.setName('Elevator Pump Room Elevator Equipment')
  elec_equip.setSpace(elevator_pump_room)
  case template
    when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
      elec_equip.setSchedule(model_add_schedule(model, 'OutPatientHealthCare BLDG_ELEVATORS'))
    when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
      elec_equip.setSchedule(model_add_schedule(model, 'OutPatientHealthCare BLDG_ELEVATORS_Pre2004'))
  end
  return true
end

#add_humidifier(hot_water_loop, model) ⇒ Object

add humidifier to AHU1 (contains operating room1)


182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 182

def add_humidifier(hot_water_loop, model)
  operatingroom1_space = model.getSpaceByName('Floor 1 Operating Room 1').get
  operatingroom1_zone = operatingroom1_space.thermalZone.get
  humidistat = OpenStudio::Model::ZoneControlHumidistat.new(model)
  humidistat.setHumidifyingRelativeHumiditySetpointSchedule(model_add_schedule(model, 'OutPatientHealthCare MinRelHumSetSch'))
  humidistat.setDehumidifyingRelativeHumiditySetpointSchedule(model_add_schedule(model, 'OutPatientHealthCare MaxRelHumSetSch'))
  operatingroom1_zone.setZoneControlHumidistat(humidistat)
  model.getAirLoopHVACs.sort.each do |air_loop|
    if air_loop.thermalZones.include? operatingroom1_zone
      humidifier = OpenStudio::Model::HumidifierSteamElectric.new(model)
      humidifier.setRatedCapacity(3.72E-5)
      humidifier.setRatedPower(100_000)
      humidifier.setName("#{air_loop.name.get} Electric Steam Humidifier")      # get the water heating coil and add humidifier to the outlet of heating coil (right before fan)

      htg_coil = nil
      air_loop.supplyComponents.each do |equip|
        if equip.to_CoilHeatingWater.is_initialized
          htg_coil = equip.to_CoilHeatingWater.get
        end
      end
      heating_coil_outlet_node = htg_coil.airOutletModelObject.get.to_Node.get
      supply_outlet_node = air_loop.supplyOutletNode
      humidifier.addToNode(heating_coil_outlet_node)
      humidity_spm = OpenStudio::Model::SetpointManagerSingleZoneHumidityMinimum.new(model)
      case template
        when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
          extra_elec_htg_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule)
          extra_elec_htg_coil.setName('AHU1 extra Electric Htg Coil')
          extra_water_htg_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule)
          extra_water_htg_coil.setName('AHU1 extra Water Htg Coil')
          hot_water_loop.addDemandBranchForComponent(extra_water_htg_coil)
          extra_elec_htg_coil.addToNode(supply_outlet_node)
          extra_water_htg_coil.addToNode(supply_outlet_node)
      end      # humidity_spm.addToNode(supply_outlet_node)

      humidity_spm.addToNode(humidifier.outletModelObject.get.to_Node.get)
      humidity_spm.setControlZone(operatingroom1_zone)
    end
  end
end

#adjust_clg_setpoint(climate_zone, model) ⇒ Object


85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 85

def adjust_clg_setpoint(climate_zone, model)
  model.getSpaceTypes.sort.each do |space_type|
    space_type_name = space_type.name.get
    thermostat_name = space_type_name + ' Thermostat'
    thermostat = model.getThermostatSetpointDualSetpointByName(thermostat_name).get
    case template
      when '90.1-2004', '90.1-2007', '90.1-2010'
        case climate_zone
          when 'ASHRAE 169-2006-2B', 'ASHRAE 169-2006-1B', 'ASHRAE 169-2006-3B'
            thermostat.setCoolingSetpointTemperatureSchedule(model_add_schedule(model, 'OutPatientHealthCare CLGSETP_SCH_YES_OPTIMUM'))
        end
    end
  end
  return true
end

#adjust_infiltration(model) ⇒ Object


101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 101

def adjust_infiltration(model)
  case template
    when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
      model.getSpaces.sort.each do |space|
        space_type = space.spaceType.get        # Skip interior spaces

        next if space_exterior_wall_and_window_area(space) <= 0        # Skip spaces that have no infiltration objects to adjust

        next if space_type.spaceInfiltrationDesignFlowRates.size <= 0

        # get the infiltration information from the space type infiltration
        infiltration_space_type = space_type.spaceInfiltrationDesignFlowRates[0]
        infil_sch = infiltration_space_type.schedule.get
        infil_rate = nil
        infil_ach = nil
        if infiltration_space_type.flowperExteriorWallArea.is_initialized
          infil_rate = infiltration_space_type.flowperExteriorWallArea.get
        elsif infiltration_space_type.airChangesperHour.is_initialized
          infil_ach = infiltration_space_type.airChangesperHour.get
        end        # Create an infiltration rate object for this space

        infiltration = OpenStudio::Model::SpaceInfiltrationDesignFlowRate.new(model)
        infiltration.setName("#{space.name} Infiltration")
        infiltration.setFlowperExteriorSurfaceArea(infil_rate) unless infil_rate.nil? || infil_rate.to_f.zero?
        infiltration.setAirChangesperHour(infil_ach) unless infil_ach.nil? || infil_ach.to_f.zero?
        infiltration.setSchedule(infil_sch)
        infiltration.setSpace(space)
      end
      model.getSpaceTypes.sort.each do |space_type|
        space_type.spaceInfiltrationDesignFlowRates.each(&:remove)
      end
    else
      return true
  end
end

#apply_minimum_total_ach(building_type, model) ⇒ Object

assign the minimum total air changes to the cooling minimum air flow in Sizing:Zone


289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 289

def apply_minimum_total_ach(building_type, model)
  model.getSpaces.sort.each do |space|
    space_type_name = space.spaceType.get.standardsSpaceType.get
    search_criteria = {
        'template' => template,
        'building_type' => building_type,
        'space_type' => space_type_name
    }
    data = model_find_object(standards_data['space_types'], search_criteria)

    if data.nil? ###
      OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', "Could not find data for #{search_criteria}")
      next
    end

    # skip space type without minimum total air changes
    next if data['minimum_total_air_changes'].nil?

    # calculate the minimum total air flow
    minimum_total_ach = data['minimum_total_air_changes'].to_f
    space_volume = space.volume
    space_area = space.floorArea
    minimum_airflow_per_zone = minimum_total_ach * space_volume / 3600
    minimum_airflow_per_zone_floor_area = minimum_airflow_per_zone / space_area    # add minimum total air flow limit to sizing:zone

    zone = space.thermalZone.get
    sizingzone = zone.sizingZone
    sizingzone.setCoolingDesignAirFlowMethod('DesignDayWithLimit')
    case template
      when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
        sizingzone.setCoolingMinimumAirFlow(minimum_airflow_per_zone)
      when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
        sizingzone.setCoolingMinimumAirFlowperZoneFloorArea(minimum_airflow_per_zone_floor_area)
    end
  end
end

#model_custom_hvac_tweaks(building_type, climate_zone, prototype_input, model) ⇒ Object


6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 6

def model_custom_hvac_tweaks(building_type, climate_zone, prototype_input, model)
  OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Started Adding HVAC')

  system_to_space_map = define_hvac_system_map(building_type, climate_zone)

  # add elevator for the elevator pump room (the fan&lights are already added via standard spreadsheet)
  add_extra_equip_elevator_pump_room(model)  # adjust cooling setpoint at vintages 1B,2B,3B

  adjust_clg_setpoint(climate_zone, model)  # Get the hot water loop

  hot_water_loop = nil
  model.getPlantLoops.sort.each do |loop|
    # If it has a boiler:hotwater, it is the correct loop
    unless loop.supplyComponents('OS:Boiler:HotWater'.to_IddObjectType).empty?
      hot_water_loop = loop
    end
  end  # add humidifier to AHU1 (contains operating room 1)

  if hot_water_loop
    add_humidifier(hot_water_loop, model)
  else
    OpenStudio.logFree(OpenStudio::Warn, 'openstudio.model.Model', 'Could not find hot water loop to attach humidifier to.')
  end  # adjust infiltration for vintages 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'

  adjust_infiltration(model)  # add door infiltration for vertibule

  add_door_infiltration(climate_zone, model)  # reset boiler sizing factor to 0.3 (default 1)

  reset_boiler_sizing_factor(model)  # assign the minimum total air changes to the cooling minimum air flow in Sizing:Zone

  apply_minimum_total_ach(building_type, model)

  # Some exceptions for the Outpatient
  # TODO Refactor: not sure if this is actually enabled in the original code
  #     if sys_name.include? 'PVAV Outpatient F1'
  #       # Outpatient two AHU1 and AHU2 have different HVAC schedule
  #       hvac_op_sch = model_add_schedule(model, 'OutPatientHealthCare AHU1-Fan_Pre2004')
  #       # Outpatient has different temperature settings for sizing
  #       clg_sa_temp_f = 52 # for AHU1 in Outpatient, SAT is 52F
  #       sys_dsn_clg_sa_temp_f = if template == 'DOE Ref 1980-2004' || template == 'DOE Ref Pre-1980'
  #                                 52
  #                               else
  #                                 45
  #                               end
  #       zn_dsn_clg_sa_temp_f = 52 # zone cooling design SAT
  #       zn_dsn_htg_sa_temp_f = 104 # zone heating design SAT
  #     elsif sys_name.include? 'PVAV Outpatient F2 F3'
  #       hvac_op_sch = model_add_schedule(model, 'OutPatientHealthCare AHU2-Fan_Pre2004')
  #       clg_sa_temp_f = 55 # for AHU2 in Outpatient, SAT is 55F
  #       sys_dsn_clg_sa_temp_f = 52
  #       zn_dsn_clg_sa_temp_f = 55 # zone cooling design SAT
  #       zn_dsn_htg_sa_temp_f = 104 # zone heating design SAT
  #     end

  OpenStudio.logFree(OpenStudio::Info, 'openstudio.model.Model', 'Finished adding HVAC')

  return true
end

#model_custom_swh_tweaks(model, building_type, climate_zone, prototype_input) ⇒ Object


326
327
328
329
330
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 326

def model_custom_swh_tweaks(model, building_type, climate_zone, prototype_input)
  update_waterheater_loss_coefficient(model)

  return true
end

#model_modify_oa_controller(model) ⇒ Object

for 90.1-2010 Outpatient, AHU2 set minimum outdoor air flow rate as 0 AHU1 doesn't have economizer


225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 225

def model_modify_oa_controller(model)
  model.getAirLoopHVACs.sort.each do |air_loop|
    oa_system = air_loop.airLoopHVACOutdoorAirSystem.get
    controller_oa = oa_system.getControllerOutdoorAir
    controller_mv = controller_oa.controllerMechanicalVentilation    # AHU1 OA doesn't have controller:mechanicalventilation

    if air_loop.name.to_s.include? 'Outpatient F1'
      controller_mv.setAvailabilitySchedule(model.alwaysOffDiscreteSchedule)      # add minimum fraction of outdoor air schedule to AHU1

      controller_oa.setMinimumFractionofOutdoorAirSchedule(model_add_schedule(model, 'OutPatientHealthCare AHU-1_OAminOAFracSchedule'))      # for AHU2, at vintages '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013', the minimum OA schedule is not the same as
      # airloop availability schedule, but separately assigned.

    elsif template == '90.1-2004' || template == '90.1-2007' || template == '90.1-2010' || template == '90.1-2013'
      controller_oa.setMinimumOutdoorAirSchedule(model_add_schedule(model, 'OutPatientHealthCare BLDG_OA_SCH'))      # add minimum fraction of outdoor air schedule to AHU2

      controller_oa.setMinimumFractionofOutdoorAirSchedule(model_add_schedule(model, 'OutPatientHealthCare BLDG_OA_FRAC_SCH'))
    end
  end
end

#model_reset_or_room_vav_minimum_damper(prototype_input, model) ⇒ Object

For operating room 1&2 in 2010 and 2013, VAV minimum air flow is set by schedule


246
247
248
249
250
251
252
253
254
255
256
257
258
259
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 246

def model_reset_or_room_vav_minimum_damper(prototype_input, model)
  case template
    when '90.1-2004', '90.1-2007'
      return true
    when '90.1-2010', '90.1-2013'
      model.getAirTerminalSingleDuctVAVReheats.sort.each do |airterminal|
        airterminal_name = airterminal.name.get
        if airterminal_name.include?('Floor 1 Operating Room 1') || airterminal_name.include?('Floor 1 Operating Room 2')
          airterminal.setZoneMinimumAirFlowMethod('Scheduled')
          airterminal.setMinimumAirFlowFractionSchedule(model_add_schedule(model, 'OutPatientHealthCare OR_MinSA_Sched'))
        end
      end
  end
end

#model_update_exhaust_fan_efficiency(model) ⇒ Object


267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 267

def model_update_exhaust_fan_efficiency(model)
  case template
    when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013'
      model.getFanZoneExhausts.sort.each do |exhaust_fan|
        fan_name = exhaust_fan.name.to_s
        if (fan_name.include? 'X-Ray') || (fan_name.include? 'MRI Room')
          exhaust_fan.setFanEfficiency(0.16)
          exhaust_fan.setPressureRise(125)
        else
          exhaust_fan.setFanEfficiency(0.31)
          exhaust_fan.setPressureRise(249)
        end
      end
    when 'DOE Ref Pre-1980', 'DOE Ref 1980-2004'
      model.getFanZoneExhausts.sort.each do |exhaust_fan|
        exhaust_fan.setFanEfficiency(0.338)
        exhaust_fan.setPressureRise(125)
      end
  end
end

#reset_boiler_sizing_factor(model) ⇒ Object


261
262
263
264
265
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 261

def reset_boiler_sizing_factor(model)
  model.getBoilerHotWaters.sort.each do |boiler|
    boiler.setSizingFactor(0.3)
  end
end

#update_waterheater_loss_coefficient(model) ⇒ Object


166
167
168
169
170
171
172
173
174
175
176
177
178
179
# File 'lib/openstudio-standards/prototypes/common/buildings/Prototype.Outpatient.rb', line 166

def update_waterheater_loss_coefficient(model)
  case template
    when '90.1-2004', '90.1-2007', '90.1-2010', '90.1-2013', 'NECB2011'
      model.getWaterHeaterMixeds.sort.each do |water_heater|
        if water_heater.name.to_s.include?('Booster')
          water_heater.setOffCycleLossCoefficienttoAmbientTemperature(1.053159296)
          water_heater.setOnCycleLossCoefficienttoAmbientTemperature(1.053159296)
        else
          water_heater.setOffCycleLossCoefficienttoAmbientTemperature(9.643286505)
          water_heater.setOnCycleLossCoefficienttoAmbientTemperature(9.643286505)
        end
      end
  end
end