Class: AedgOfficeHvacRadiantDoas

Inherits:
OpenStudio::Measure::ModelMeasure
  • Object
show all
Defined in:
lib/measures/AedgOfficeHvacRadiantDoas/measure.rb

Overview

start the measure

Instance Method Summary collapse

Instance Method Details

#arguments(model) ⇒ Object

define the arguments that the user will input



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
64
65
66
67
# File 'lib/measures/AedgOfficeHvacRadiantDoas/measure.rb', line 33

def arguments(model)
  args = OpenStudio::Measure::OSArgumentVector.new

  # create an argument for a space type to be used in the model, to see if one should be mapped as ceiling return air plenum
  spaceTypes = model.getSpaceTypes
  usedSpaceTypes_handle = OpenStudio::StringVector.new
  usedSpaceTypes_displayName = OpenStudio::StringVector.new
  spaceTypes.each do |spaceType| # TODO: - I need to update this to use helper so GUI sorts by display name
    if !spaceType.spaces.empty? # only show space types used in the building
      usedSpaceTypes_handle << spaceType.handle.to_s
      usedSpaceTypes_displayName << spaceType.name.to_s
    end
  end

  # make an argument for space type
  ceilingReturnPlenumSpaceType = OpenStudio::Measure::OSArgument.makeChoiceArgument('ceilingReturnPlenumSpaceType', usedSpaceTypes_handle, usedSpaceTypes_displayName, false)
  ceilingReturnPlenumSpaceType.setDisplayName('This space type should be part of a ceiling return air plenum.')
  # ceilingReturnPlenumSpaceType.setDefaultValue("We don't want a default, this is an optional argument")
  args << ceilingReturnPlenumSpaceType

  # make an argument for material and installation cost
  # todo - I would like to split the costing out to the air loops weighted by area of building served vs. just sticking it on the building
  costTotalHVACSystem = OpenStudio::Measure::OSArgument.makeDoubleArgument('costTotalHVACSystem', true)
  costTotalHVACSystem.setDisplayName('Total Cost for HVAC System ($).')
  costTotalHVACSystem.setDefaultValue(0.0)
  args << costTotalHVACSystem

  # make an argument to remove existing costs
  remake_schedules = OpenStudio::Measure::OSArgument.makeBoolArgument('remake_schedules', true)
  remake_schedules.setDisplayName('Apply recommended availability and ventilation schedules for air handlers?')
  remake_schedules.setDefaultValue(true)
  args << remake_schedules

  return args
end

#nameObject

define the name that a user will see, this method may be deprecated as the display name in PAT comes from the name field in measure.xml



28
29
30
# File 'lib/measures/AedgOfficeHvacRadiantDoas/measure.rb', line 28

def name
  return 'AedgOfficeHvacRadiantDoas'
end

#run(model, runner, user_arguments) ⇒ Object

define what happens when the measure is run



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
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
136
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
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
# File 'lib/measures/AedgOfficeHvacRadiantDoas/measure.rb', line 70

def run(model, runner, user_arguments)
  super(model, runner, user_arguments)

  # use the built-in error checking
  if !runner.validateUserArguments(arguments(model), user_arguments)
    return false
  end

  ### START INPUTS
  # assign the user inputs to variables
  ceilingReturnPlenumSpaceType = runner.getOptionalWorkspaceObjectChoiceValue('ceilingReturnPlenumSpaceType', user_arguments, model)
  costTotalHVACSystem = runner.getDoubleArgumentValue('costTotalHVACSystem', user_arguments)
  remake_schedules = runner.getBoolArgumentValue('remake_schedules', user_arguments)
  # check that spaceType was chosen and exists in model
  ceilingReturnPlenumSpaceTypeCheck = OsLib_HelperMethods.checkOptionalChoiceArgFromModelObjects(ceilingReturnPlenumSpaceType, 'ceilingReturnPlenumSpaceType', 'to_SpaceType', runner, user_arguments)
  ceilingReturnPlenumSpaceTypeCheck == false ? (return false) : (ceilingReturnPlenumSpaceType = ceilingReturnPlenumSpaceTypeCheck['modelObject'])
  # default building/ secondary space types
  standardBuildingTypeTest = ['Office'] # ML Not used yet
  secondarySpaceTypeTest = [] # empty for office
  primarySpaceType = 'Office'
  primaryHVAC = { 'doas' => true, 'fan' => 'Constant', 'heat' => 'Water', 'cool' => 'SingleDX' }
  secondaryHVAC = { 'fan' => 'None', 'heat' => 'None', 'cool' => 'None' } # ML not used for office; leave or empty?
  zoneHVAC = 'Radiant'
  chillerType = 'AirCooled' # set to none if chiller not used
  radiantChillerType = 'AirCooled' # set to none if not radiant system
  allHVAC = { 'primary' => primaryHVAC, 'secondary' => secondaryHVAC, 'zone' => zoneHVAC }
  ### END INPUTS

  ### START SORT ZONES
  options = { 'standardBuildingTypeTest' => standardBuildingTypeTest, # ML Not used yet
              'secondarySpaceTypeTest' => secondarySpaceTypeTest,
              'ceilingReturnPlenumSpaceType' => ceilingReturnPlenumSpaceType }
  zonesSorted = OsLib_HVAC.sortZones(model, runner, options)
  zonesPrimary = zonesSorted['zonesPrimary']
  zonesSecondary = zonesSorted['zonesSecondary']
  zonesPlenum = zonesSorted['zonesPlenum']
  zonesUnconditioned = zonesSorted['zonesUnconditioned']
  ### END SORT ZONES

  ### START REPORT INITIAL CONDITIONS
  OsLib_HVAC.reportConditions(model, runner, 'initial')
  ### END REPORT INITIAL CONDITIONS

  ### START ASSIGN HVAC SCHEDULES
  options = { 'primarySpaceType' => primarySpaceType,
              'allHVAC' => allHVAC,
              'remake_schedules' => remake_schedules }
  schedulesHVAC = OsLib_HVAC.assignHVACSchedules(model, runner, options)
  # assign schedules
  primary_SAT_schedule = schedulesHVAC['primary_sat']
  building_HVAC_schedule = schedulesHVAC['hvac']
  building_ventilation_schedule = schedulesHVAC['ventilation']
  make_hot_water_plant = false
  unless schedulesHVAC['hot_water'].nil?
    hot_water_setpoint_schedule = schedulesHVAC['hot_water']
    make_hot_water_plant = true
  end
  make_chilled_water_plant = false
  unless schedulesHVAC['chilled_water'].nil?
    chilled_water_setpoint_schedule = schedulesHVAC['chilled_water']
    make_chilled_water_plant = true
  end
  make_radiant_hot_water_plant = false
  unless schedulesHVAC['radiant_hot_water'].nil?
    radiant_hot_water_setpoint_schedule = schedulesHVAC['radiant_hot_water']
    make_radiant_hot_water_plant = true
  end
  make_radiant_chilled_water_plant = false
  unless schedulesHVAC['radiant_chilled_water'].nil?
    radiant_chilled_water_setpoint_schedule = schedulesHVAC['radiant_chilled_water']
    make_radiant_chilled_water_plant = true
  end
  unless schedulesHVAC['hp_loop'].nil?
    heat_pump_loop_setpoint_schedule = schedulesHVAC['hp_loop']
  end
  unless schedulesHVAC['hp_loop_cooling'].nil?
    heat_pump_loop_cooling_setpoint_schedule = schedulesHVAC['hp_loop_cooling']
  end
  unless schedulesHVAC['hp_loop_heating'].nil?
    heat_pump_loop_heating_setpoint_schedule = schedulesHVAC['hp_loop_heating']
  end
  unless schedulesHVAC['mean_radiant_heating'].nil?
    mean_radiant_heating_setpoint_schedule = schedulesHVAC['mean_radiant_heating']
  end
  unless schedulesHVAC['mean_radiant_cooling'].nil?
    mean_radiant_cooling_setpoint_schedule = schedulesHVAC['mean_radiant_cooling']
  end
  ### END ASSIGN HVAC SCHEDULES

  ### START REMOVE EQUIPMENT
  OsLib_HVAC.removeEquipment(model, runner)
  ### END REMOVE EQUIPMENT

  ### START CREATE NEW PLANTS
  # create new plants
  # hot water plant
  if make_hot_water_plant
    hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, 'Hot Water')
  end
  # chilled water plant
  if make_chilled_water_plant
    chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, 'Chilled Water', chillerType)
  end
  # radiant hot water plant
  if make_radiant_hot_water_plant
    radiant_hot_water_plant = OsLib_HVAC.createHotWaterPlant(model, runner, radiant_hot_water_setpoint_schedule, 'Radiant Hot Water')
  end
  # chilled water plant
  if make_radiant_chilled_water_plant
    radiant_chilled_water_plant = OsLib_HVAC.createChilledWaterPlant(model, runner, radiant_chilled_water_setpoint_schedule, 'Radiant Chilled Water', radiantChillerType)
  end
  # condenser loop
  # need condenser loop if there is a water-cooled chiller or if there is a water source heat pump loop
  options = {}
  options['zoneHVAC'] = zoneHVAC
  if (zoneHVAC == 'WSHP') || (zoneHVAC == 'GSHP')
    options['loop_setpoint_schedule'] = heat_pump_loop_setpoint_schedule
    options['cooling_setpoint_schedule'] = heat_pump_loop_cooling_setpoint_schedule
    options['heating_setpoint_schedule'] = heat_pump_loop_heating_setpoint_schedule
  end
  condenserLoops = OsLib_HVAC.createCondenserLoop(model, runner, options)
  unless condenserLoops['condenser_loop'].nil?
    condenser_loop = condenserLoops['condenser_loop']
  end
  unless condenserLoops['heat_pump_loop'].nil?
    heat_pump_loop = condenserLoops['heat_pump_loop']
  end
  ### END CREATE NEW PLANTS

  ### START CREATE PRIMARY AIRLOOPS
  # populate inputs hash for create primary airloops method
  options = {}
  options['zonesPrimary'] = zonesPrimary
  options['primaryHVAC'] = primaryHVAC
  options['zoneHVAC'] = zoneHVAC
  if primaryHVAC['doas']
    options['hvac_schedule'] = building_ventilation_schedule
    options['ventilation_schedule'] = building_ventilation_schedule
  else
    # primary HVAC is multizone VAV
    if zoneHVAC == 'DualDuct'
      # primary system is a multizone VAV that cools only (primary system ventilation schedule is set to always off; hvac set to always on)
      options['hvac_schedule'] = model.alwaysOnDiscreteSchedule
    else
      # primary system is multizone VAV that cools and ventilates
      options['hvac_schedule'] = building_HVAC_schedule
      options['ventilation_schedule'] = building_ventilation_schedule
    end
  end
  options['primary_sat_schedule'] = primary_SAT_schedule
  if make_hot_water_plant
    options['hot_water_plant'] = hot_water_plant
  end
  if make_chilled_water_plant
    options['chilled_water_plant'] = chilled_water_plant
  end
  primary_airloops = OsLib_HVAC.createPrimaryAirLoops(model, runner, options)
  ### END CREATE PRIMARY AIRLOOPS

  ### START CREATE SECONDARY AIRLOOPS
  # populate inputs hash for create primary airloops method
  options = {}
  options['zonesSecondary'] = zonesSecondary
  options['secondaryHVAC'] = secondaryHVAC
  options['hvac_schedule'] = building_HVAC_schedule
  options['ventilation_schedule'] = building_ventilation_schedule
  if make_hot_water_plant
    options['hot_water_plant'] = hot_water_plant
  end
  if make_chilled_water_plant
    options['chilled_water_plant'] = chilled_water_plant
  end
  secondary_airloops = OsLib_HVAC.createSecondaryAirLoops(model, runner, options)
  ### END CREATE SECONDARY AIRLOOPS

  ### START ASSIGN PLENUMS
  options = { 'zonesPrimary' => zonesPrimary, 'zonesPlenum' => zonesPlenum }
  zone_plenum_hash = OsLib_HVAC.validateAndAddPlenumZonesToSystem(model, runner, options)
  ### END ASSIGN PLENUMS

  ### START CREATE PRIMARY ZONE EQUIPMENT
  options = {}
  options['zonesPrimary'] = zonesPrimary
  options['zoneHVAC'] = zoneHVAC
  if make_hot_water_plant
    options['hot_water_plant'] = hot_water_plant
  end
  if make_chilled_water_plant
    options['chilled_water_plant'] = chilled_water_plant
  end
  if (zoneHVAC == 'WSHP') || (zoneHVAC == 'GSHP')
    options['heat_pump_loop'] = heat_pump_loop
  end
  if zoneHVAC == 'DualDuct'
    options['ventilation_schedule'] = building_ventilation_schedule
  end
  if zoneHVAC == 'Radiant'
    options['radiant_hot_water_plant'] = radiant_hot_water_plant
    options['radiant_chilled_water_plant'] = radiant_chilled_water_plant
    options['mean_radiant_heating_setpoint_schedule'] = mean_radiant_heating_setpoint_schedule
    options['mean_radiant_cooling_setpoint_schedule'] = mean_radiant_cooling_setpoint_schedule
  end
  OsLib_HVAC.createPrimaryZoneEquipment(model, runner, options)
  ### END CREATE PRIMARY ZONE EQUIPMENT

  # START ADD DCV
  options = {}
  unless zoneHVAC == 'DualDuct'
    options['primary_airloops'] = primary_airloops
  end
  options['secondary_airloops'] = secondary_airloops
  options['allHVAC'] = allHVAC
  OsLib_HVAC.addDCV(model, runner, options)
  # END ADD DCV

  # TODO: - add in lifecycle costs
  expected_life = 25
  years_until_costs_start = 0
  costHVAC = costTotalHVACSystem
  lcc_mat = OpenStudio::Model::LifeCycleCost.createLifeCycleCost('HVAC System', model.getBuilding, costHVAC, 'CostPerEach', 'Construction', expected_life, years_until_costs_start).get

  # add AEDG tips
  aedgTips = ['HV09', 'HV10', 'HV12']

  # populate how to tip messages
  aedgTipsLong = OsLib_AedgMeasures.getLongHowToTips('SmMdOff', aedgTips.uniq.sort, runner)
  if !aedgTipsLong
    return false # this should only happen if measure writer passes bad values to getLongHowToTips
  end

  ### START REPORT FINAL CONDITIONS
  OsLib_HVAC.reportConditions(model, runner, 'final', aedgTipsLong)
  ### END REPORT FINAL CONDITIONS

  return true
end