openstudio-ee 0.2.1 → 0.3.0

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/.rubocop.yml +1 -1
  3. data/CHANGELOG.md +7 -0
  4. data/Rakefile +0 -2
  5. data/lib/measures/GLHEProExportLoadsforGroundHeatExchangerSizing/measure.rb +1 -1
  6. data/lib/measures/GLHEProExportLoadsforGroundHeatExchangerSizing/measure.xml +3 -4
  7. data/lib/measures/nze_hvac/measure.rb +8 -6
  8. data/lib/measures/nze_hvac/measure.xml +9 -9
  9. data/lib/openstudio/ee_measures/version.rb +1 -1
  10. data/openstudio-ee.gemspec +6 -8
  11. metadata +11 -50
  12. data/lib/measures/ImproveFanTotalEfficiencybyPercentage/measure.rb +0 -333
  13. data/lib/measures/ImproveFanTotalEfficiencybyPercentage/measure.xml +0 -150
  14. data/lib/measures/ReplaceFanTotalEfficiency/measure.rb +0 -330
  15. data/lib/measures/ReplaceFanTotalEfficiency/measure.xml +0 -150
  16. data/lib/measures/add_apszhp_to_each_zone/measure.rb +0 -607
  17. data/lib/measures/add_apszhp_to_each_zone/measure.xml +0 -184
  18. data/lib/measures/add_energy_recovery_ventilator/measure.rb +0 -354
  19. data/lib/measures/add_energy_recovery_ventilator/measure.xml +0 -78
  20. data/lib/measures/improve_simple_glazing_by_percentage/measure.rb +0 -81
  21. data/lib/measures/improve_simple_glazing_by_percentage/measure.xml +0 -70
  22. data/lib/measures/reduce_water_use_by_percentage/measure.rb +0 -61
  23. data/lib/measures/reduce_water_use_by_percentage/measure.xml +0 -62
  24. data/lib/measures/replace_hvac_with_gshp_and_doas/measure.rb +0 -511
  25. data/lib/measures/replace_hvac_with_gshp_and_doas/measure.xml +0 -375
  26. data/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_AedgMeasures.rb +0 -454
  27. data/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Constructions.rb +0 -221
  28. data/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Geometry.rb +0 -41
  29. data/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HVAC.rb +0 -1682
  30. data/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_HelperMethods.rb +0 -114
  31. data/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_LightingAndEquipment.rb +0 -99
  32. data/lib/measures/replace_hvac_with_gshp_and_doas/resources/OsLib_Schedules.rb +0 -142
  33. data/lib/measures/replace_simple_glazing/measure.rb +0 -86
  34. data/lib/measures/replace_simple_glazing/measure.xml +0 -78
  35. data/lib/measures/set_boiler_thermal_efficiency/measure.rb +0 -520
  36. data/lib/measures/set_boiler_thermal_efficiency/measure.xml +0 -78
  37. data/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/measure.rb +0 -207
  38. data/lib/measures/set_water_heater_efficiency_heat_lossand_peak_water_flow_rate/measure.xml +0 -78
  39. data/lib/measures/tenant_star_internal_loads/measure.rb +0 -134
  40. data/lib/measures/tenant_star_internal_loads/measure.xml +0 -67
  41. data/lib/measures/tenant_star_internal_loads/resources/os_lib_helper_methods.rb +0 -401
  42. data/lib/measures/vr_fwith_doas/measure.rb +0 -468
  43. data/lib/measures/vr_fwith_doas/measure.xml +0 -298
  44. data/lib/measures/vr_fwith_doas/resources/OsLib_AedgMeasures.rb +0 -454
  45. data/lib/measures/vr_fwith_doas/resources/OsLib_Constructions.rb +0 -221
  46. data/lib/measures/vr_fwith_doas/resources/OsLib_Geometry.rb +0 -41
  47. data/lib/measures/vr_fwith_doas/resources/OsLib_HVAC.rb +0 -1516
  48. data/lib/measures/vr_fwith_doas/resources/OsLib_HelperMethods.rb +0 -114
  49. data/lib/measures/vr_fwith_doas/resources/OsLib_LightingAndEquipment.rb +0 -99
  50. data/lib/measures/vr_fwith_doas/resources/OsLib_Schedules.rb +0 -142
@@ -1,221 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OsLib_Constructions
4
- # infer insulation layer from a construction
5
- def self.inferInsulationLayer(construction, minThermalResistance)
6
- construction_layers = construction.layers
7
- counter = 0
8
- max_resistance = 0
9
- thermal_resistance_array = []
10
-
11
- # loop through construction layers and infer insulation layer/material
12
- construction_layers.each do |construction_layer|
13
- construction_thermal_resistance = construction_layer.to_OpaqueMaterial.get.thermalResistance
14
- if !thermal_resistance_array.empty?
15
- if construction_thermal_resistance > max_resistance
16
- thermal_resistance_array = [construction_layer, counter, construction_thermal_resistance]
17
- max_resistance = construction_thermal_resistance
18
- end
19
- else
20
- thermal_resistance_array = [construction_layer, counter, construction_thermal_resistance]
21
- end
22
- counter += 1
23
- end
24
-
25
- # test against minimum
26
- if max_resistance > minThermalResistance
27
- minTestPass = true
28
- else
29
- minTestPass = false
30
- end
31
-
32
- result = {
33
- 'construction' => construction,
34
- 'construction_layer' => thermal_resistance_array[0],
35
- 'layer_index' => thermal_resistance_array[1],
36
- 'construction_thermal_resistance' => thermal_resistance_array[2],
37
- 'insulationFound' => minTestPass
38
- }
39
-
40
- return result
41
- end
42
-
43
- # change thermal resistance of opaque materials
44
- def self.setMaterialThermalResistance(material, thermalResistance, options = {})
45
- # set defaults to use if user inputs not passed in
46
- defaults = {
47
- 'cloneMaterial' => true, # in future give user option to clone or change live material
48
- 'name' => "#{material.name} - adj"
49
- }
50
-
51
- # merge user inputs with defaults
52
- options = defaults.merge(options)
53
-
54
- # clone input material
55
- new_material = material.clone(material.model)
56
- new_material = new_material.to_OpaqueMaterial.get
57
- new_material.setName(options['name'])
58
-
59
- # edit insulation material
60
- new_material_matt = new_material.to_Material
61
- if !new_material_matt.empty?
62
- starting_thickness = new_material_matt.get.thickness
63
- target_thickness = starting_thickness * thermalResistance / material.to_OpaqueMaterial.get.thermalResistance
64
- final_thickness = new_material_matt.get.setThickness(target_thickness)
65
- end
66
- new_material_massless = new_material.to_MasslessOpaqueMaterial
67
- if !new_material_massless.empty?
68
- final_thermal_resistance = new_material_massless.get.setThermalResistance(thermalResistance)
69
- end
70
- new_material_airgap = new_material.to_AirGap
71
- if !new_material_airgap.empty?
72
- final_thermal_resistance = new_material_airgap.get.setThermalResistance(thermalResistance)
73
- end
74
-
75
- result = new_material
76
- return result
77
- end
78
-
79
- # add new material to outside of a construction
80
- def self.addNewLayerToConstruction(construction, options = {})
81
- # set defaults to use if user inputs not passed in
82
- defaults = {
83
- 'cloneConstruction' => false, # in future give user option to clone or change live construction
84
- 'layerIndex' => 0, # 0 will be outside. Measure writer should validate any non 0 layerIndex passed in.
85
- 'name' => "#{construction.name} - new material",
86
- 'roughness' => nil,
87
- 'thickness' => nil,
88
- 'conductivity' => nil,
89
- 'density' => nil,
90
- 'specificHeat' => nil,
91
- 'thermalAbsorptance' => nil,
92
- 'solarAbsorptance' => nil,
93
- 'visibleAbsorptance' => nil
94
- }
95
-
96
- # merge user inputs with defaults
97
- options = defaults.merge(options)
98
-
99
- # TODO: - would be nice to grab surface properties from previous exposed material
100
-
101
- # make new material
102
- exposedMaterialNew = OpenStudio::Model::StandardOpaqueMaterial.new(construction.model)
103
- exposedMaterialNew.setName(options['name'])
104
-
105
- # set requested material properties
106
- if !options['roughness'].nil? then exposedMaterialNew.setRoughness(options['roughness']) end
107
- if !options['thickness'].nil? then exposedMaterialNew.setThickness(options['thickness']) end
108
- if !options['conductivity'].nil? then exposedMaterialNew.setConductivity(options['conductivity']) end
109
- if !options['density'].nil? then exposedMaterialNew.setDensity(options['density']) end
110
- if !options['specificHeat'].nil? then exposedMaterialNew.setSpecificHeat(options['specificHeat']) end
111
- if !options['thermalAbsorptance'].nil? then exposedMaterialNew.setThermalAbsorptance(options['thermalAbsorptance']) end
112
- if !options['solarAbsorptance'].nil? then exposedMaterialNew.setSolarAbsorptance(options['solarAbsorptance']) end
113
- if !options['visibleAbsorptance'].nil? then exposedMaterialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end
114
-
115
- # add material to construction
116
- construction.insertLayer(options['layerIndex'], exposedMaterialNew)
117
-
118
- result = exposedMaterialNew
119
- return result
120
- end
121
-
122
- # set material surface properties for specific layer in construction. this should work on OS:Material and OS:MasslessOpaqueMaterial
123
- def self.setConstructionSurfaceProperties(construction, options = {})
124
- # set defaults to use if user inputs not passed in
125
- defaults = {
126
- 'cloneConstruction' => false, # in future give user option to clone or change live construction
127
- 'nameConstruction' => "#{construction.name} - adj", # not currently used
128
- 'cloneMaterial' => true,
129
- 'roughness' => nil,
130
- 'thermalAbsorptance' => nil,
131
- 'solarAbsorptance' => nil,
132
- 'visibleAbsorptance' => nil
133
- }
134
-
135
- # merge user inputs with defaults
136
- options = defaults.merge(options)
137
-
138
- exposedMaterial = construction.to_LayeredConstruction.get.getLayer(0)
139
- if options['cloneMaterial']
140
-
141
- # clone material
142
- exposedMaterialNew = exposedMaterial.clone(construction.model).to_StandardOpaqueMaterial.get # to_StandardOpaqueMaterial is needed to access roughness, otherwise to_OpaqueMaterial would have been fine.
143
- exposedMaterialNew.setName("#{exposedMaterial.name} - adj")
144
-
145
- # connect new material to original construction
146
- construction.eraseLayer(0)
147
- construction.insertLayer(0, exposedMaterialNew)
148
-
149
- else
150
- exposedMaterialNew = exposedMaterial.to_StandardOpaqueMaterial.get # not being cloned but still want to rename
151
- exposedMaterialNew.setName("#{exposedMaterial.name} - adj")
152
- end
153
-
154
- # TODO: - need to test with MasslessOpaqueMaterial. Add test if doesn't return anything when use to_StandardOpaqueMaterial.get
155
-
156
- # set requested material properties
157
- if !options['roughness'].nil? then exposedMaterialNew.setRoughness(options['roughness']) end
158
- if !options['thermalAbsorptance'].nil? then exposedMaterialNew.setThermalAbsorptance(options['thermalAbsorptance']) end
159
- if !options['solarAbsorptance'].nil? then exposedMaterialNew.setSolarAbsorptance(options['solarAbsorptance']) end
160
- if !options['visibleAbsorptance'].nil? then exposedMaterialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end
161
-
162
- result = { 'exposedMaterial' => exposedMaterial, 'exposedMaterialNew' => exposedMaterialNew }
163
- return result
164
- end # end of OsLib_Constructions.setMaterialSurfaceProperties
165
-
166
- # similar to setMaterialSurfaceProperties but I just pass a material in. Needed this to set material properties for interior walls and both sides of interior partitions.
167
- def self.setMaterialSurfaceProperties(material, options = {})
168
- # set defaults to use if user inputs not passed in
169
- defaults = {
170
- 'cloneMaterial' => true,
171
- 'roughness' => nil,
172
- 'thermalAbsorptance' => nil,
173
- 'solarAbsorptance' => nil,
174
- 'visibleAbsorptance' => nil
175
- }
176
-
177
- # merge user inputs with defaults
178
- options = defaults.merge(options)
179
-
180
- if options['cloneMaterial']
181
- # clone material
182
- materialNew = exposedMaterial.clone(construction.model).get
183
- materialNew.setName("#{materialNew.name} - adj")
184
- else
185
- materialNew = material # not being cloned
186
- materialNew.setName("#{materialNew.name} - adj")
187
- end
188
-
189
- # to_StandardOpaqueMaterial is needed to access roughness, otherwise to_OpaqueMaterial would have been fine.
190
- if !materialNew.to_StandardOpaqueMaterial.empty?
191
- materialNew = materialNew.to_StandardOpaqueMaterial.get
192
- elsif !materialNew.to_MasslessOpaqueMaterial.empty?
193
- materialNew = materialNew.to_MasslessOpaqueMaterial.get
194
- end
195
-
196
- # set requested material properties
197
- if !options['roughness'].nil? then materialNew.setRoughness(options['roughness']) end
198
- if !options['thermalAbsorptance'].nil? then materialNew.setThermalAbsorptance(options['thermalAbsorptance']) end
199
- if !options['solarAbsorptance'].nil? then materialNew.setSolarAbsorptance(options['solarAbsorptance']) end
200
- if !options['visibleAbsorptance'].nil? then materialNew.setVisibleAbsorptance(options['visibleAbsorptance']) end
201
-
202
- result = { 'material' => material, 'materialNew' => materialNew }
203
- return result
204
- end # end of OsLib_Constructions.setMaterialSurfaceProperties
205
-
206
- # sri of exposed surface of a construction (calculation from K-12 AEDG, derived from ASTM E1980 assuming medium wind speed)
207
- def self.getConstructionSRI(construction)
208
- exposedMaterial = construction.to_LayeredConstruction.get.getLayer(0)
209
- solarAbsorptance = exposedMaterial.to_OpaqueMaterial.get.solarAbsorptance
210
- thermalEmissivity = exposedMaterial.to_OpaqueMaterial.get.thermalAbsorptance
211
- # lines below just for testing
212
- # solarAbsorptance = 1 - 0.65
213
- # thermalEmissivity = 0.86
214
-
215
- x = (20.797 * solarAbsorptance - 0.603 * thermalEmissivity) / (9.5205 * thermalEmissivity + 12.0)
216
- sri = 123.97 - 141.35 * x + 9.6555 * x * x
217
-
218
- result = sri
219
- return result
220
- end # end of OsLib_Constructions.getConstructionSRI
221
- end
@@ -1,41 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OsLib_Geometry
4
- # lower z value of vertices with starting value above x to new value of y
5
- def self.lowerSurfaceZvalue(surfaceArray, zValueTarget)
6
- counter = 0
7
-
8
- # loop over all surfaces
9
- surfaceArray.each do |surface|
10
- # create a new set of vertices
11
- newVertices = OpenStudio::Point3dVector.new
12
-
13
- # get the existing vertices for this interior partition
14
- vertices = surface.vertices
15
- flag = false
16
- vertices.each do |vertex|
17
- # initialize new vertex to old vertex
18
- x = vertex.x
19
- y = vertex.y
20
- z = vertex.z
21
-
22
- # if this z vertex is not on the z = 0 plane
23
- if z > zValueTarget
24
- z = zValueTarget
25
- flag = true
26
- end
27
-
28
- # add point to new vertices
29
- newVertices << OpenStudio::Point3d.new(x, y, z)
30
- end
31
-
32
- # set vertices to new vertices
33
- surface.setVertices(newVertices) # todo check if this was made, and issue warning if it was not. Could happen if resulting surface not planer.
34
-
35
- if flag then counter += 1 end
36
- end # end of surfaceArray.each do
37
-
38
- result = counter
39
- return result
40
- end
41
- end
@@ -1,1682 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module OsLib_HVAC
4
- # do something
5
- def self.doSomething(input)
6
- # do something
7
- output = input
8
-
9
- result = output
10
- return result
11
- end # end of def
12
-
13
- # validate and make plenum zones
14
- def self.validateAndAddPlenumZonesToSystem(model, runner, options = {})
15
- # set defaults to use if user inputs not passed in
16
- defaults = {
17
- 'zonesPlenum' => nil,
18
- 'zonesPrimary' => nil,
19
- 'type' => 'ceilingReturn'
20
- }
21
-
22
- # merge user inputs with defaults
23
- options = defaults.merge(options)
24
-
25
- # array of valid ceiling plenums
26
- zoneSurfaceHash = {}
27
- zonePlenumHash = {}
28
-
29
- if options['zonesPlenum'].nil?
30
- runner.registerWarning('No plenum zones were passed in, validateAndAddPlenumZonesToSystem will not alter the model.')
31
- else
32
- options['zonesPlenum'].each do |zone|
33
- # get spaces in zone
34
- spaces = zone.spaces
35
- # get adjacent spaces
36
- spaces.each do |space|
37
- # get surfaces
38
- surfaces = space.surfaces
39
- # loop through surfaces looking for floors with surface boundary condition, grab zone that surface's parent space is in.
40
- surfaces.each do |surface|
41
- if (surface.outsideBoundaryCondition == 'Surface') && (surface.surfaceType == 'Floor')
42
- next unless surface.adjacentSurface.is_initialized
43
- adjacentSurface = surface.adjacentSurface.get
44
- next unless adjacentSurface.space.is_initialized
45
- adjacentSurfaceSpace = adjacentSurface.space.get
46
- next unless adjacentSurfaceSpace.thermalZone.is_initialized
47
- adjacentSurfaceSpaceZone = adjacentSurfaceSpace.thermalZone.get
48
- if options['zonesPrimary'].include? adjacentSurfaceSpaceZone
49
- if zoneSurfaceHash[adjacentSurfaceSpaceZone].nil? || (surface.grossArea > zoneSurfaceHash[adjacentSurfaceSpaceZone])
50
- adjacentSurfaceSpaceZone.setReturnPlenum(zone)
51
- zoneSurfaceHash[adjacentSurfaceSpaceZone] = surface.grossArea
52
- zonePlenumHash[adjacentSurfaceSpaceZone] = zone
53
- end
54
- end
55
- end
56
- end # end of surfaces.each do
57
- end # end of spaces.each do
58
- end # end of zonesPlenum.each do
59
- end # end of zonesPlenum == nil
60
-
61
- # report out results of zone-plenum hash
62
- zonePlenumHash.each do |zone, plenum|
63
- runner.registerInfo("#{plenum.name} has been set as a return air plenum for #{zone.name}.")
64
- end
65
-
66
- # pass back zone-plenum hash
67
- result = zonePlenumHash
68
- return result
69
- end # end of def
70
-
71
- def self.sortZones(model, runner, options = {}, space_type_to_edits_hash = {})
72
- # set defaults to use if user inputs not passed in
73
- defaults = { 'standardBuildingTypeTest' => nil, # not used for now
74
- 'secondarySpaceTypeTest' => nil,
75
- 'ceilingReturnPlenumSpaceType' => nil }
76
-
77
- # merge user inputs with defaults
78
- options = defaults.merge(options)
79
-
80
- # set up zone type arrays
81
- zonesPrimary = []
82
- zonesSecondary = []
83
- zonesPlenum = []
84
- zonesUnconditioned = []
85
-
86
- # get thermal zones
87
- zones = model.getThermalZones
88
- zones.each do |zone|
89
- # assign appropriate zones to zonesPlenum or zonesUnconditioned (those that don't have thermostats or zone HVAC equipment)
90
- # if not conditioned then add to zonesPlenum or zonesUnconditioned
91
- unless zone.thermostatSetpointDualSetpoint.is_initialized || !zone.equipment.empty?
92
- # determine if zone is a plenum zone or general unconditioned zone
93
- # assume it is a plenum if it has at least one plenum space
94
- zone.spaces.each do |space|
95
- # if a zone has already been assigned as a plenum, skip
96
- next if zonesPlenum.include? zone
97
- # if zone not assigned as a plenum, get space type if it exists
98
- # compare to plenum space type if it has been assigned
99
- if space.spaceType.is_initialized && (options['ceilingReturnPlenumSpaceType'].nil? == false)
100
- spaceType = space.spaceType.get
101
- if spaceType == options['ceilingReturnPlenumSpaceType']
102
- zonesPlenum << zone # zone has a plenum space; assign it as a plenum
103
- end
104
- end
105
- end
106
- # if zone not assigned as a plenum, assign it as unconditioned
107
- unless zonesPlenum.include? zone
108
- zonesUnconditioned << zone
109
- end
110
- end
111
- end
112
- # zone is conditioned. check if its space type is secondary or primary
113
- spaces = model.getSpaces
114
- spaces.each do |space|
115
- spaceType = space.spaceType.get
116
- if space_type_to_edits_hash[spaceType] == true
117
- zonesPrimary << space.thermalZone.get
118
- end
119
- end # end of spaces each do
120
- # if zone is conditioned and is of space type true, assign it to primary zones
121
-
122
- zonesSorted = { 'zonesPrimary' => zonesPrimary,
123
- 'zonesSecondary' => zonesSecondary,
124
- 'zonesPlenum' => zonesPlenum,
125
- 'zonesUnconditioned' => zonesUnconditioned }
126
- # pass back zonesSorted hash
127
- result = zonesSorted
128
- return result
129
- end # end of def
130
-
131
- def self.reportConditions(model, runner, condition)
132
- airloops = model.getAirLoopHVACs
133
- plantLoops = model.getPlantLoops
134
- zones = model.getThermalZones
135
-
136
- # count up zone equipment (not counting zone exhaust fans)
137
- zoneHasEquip = false
138
- zonesWithEquipCounter = 0
139
-
140
- zones.each do |zone|
141
- if !zone.equipment.empty?
142
- zone.equipment.each do |equip|
143
- unless equip.to_FanZoneExhaust.is_initialized
144
- zonesWithEquipCounter += 1
145
- break
146
- end
147
- end
148
- end
149
- end
150
-
151
- if condition == 'initial'
152
- runner.registerInitialCondition("The building started with #{airloops.size} air loops and #{plantLoops.size} plant loops. #{zonesWithEquipCounter} zones were conditioned with zone equipment.")
153
- elsif condition == 'final'
154
- runner.registerFinalCondition("The building finished with #{airloops.size} air loops and #{plantLoops.size} plant loops. #{zonesWithEquipCounter} zones are conditioned with zone equipment.")
155
- end
156
- end # end of def
157
-
158
- def self.removeEquipment(model, runner, options)
159
- airloops = model.getAirLoopHVACs
160
- plantLoops = model.getPlantLoops
161
- zones = model.getThermalZones
162
-
163
- # remove all zone equipment except zone exhaust fans
164
- zones.each do |zone|
165
- # runner.registerInfo("primary zones values are #{value.name}")
166
- if options['zonesPrimary'].include? zone
167
- zone.equipment.each do |equip|
168
- if equip.to_FanZoneExhaust.is_initialized # or (equip.to_ZoneHVACUnitHeater.is_initialized and zone.get.equipment.size == 1)
169
- else
170
- equip.remove
171
- end
172
- end
173
- end
174
- end
175
-
176
- # remove an air loop if it's empty
177
- airloops.each do |air_loop|
178
- air_loop.thermalZones.each do |airZone|
179
- if options['zonesPrimary'].include? airZone
180
- air_loop.removeBranchForZone(airZone)
181
- end
182
- end
183
- if air_loop.thermalZones.empty?
184
- air_loop.remove
185
- end
186
- end
187
-
188
- # remove plant loops
189
- plantLoops.each do |plantLoop|
190
- # get the demand components and see if water use connection, then save it
191
- # notify user with info statement if supply side of plant loop had heat exchanger for refrigeration
192
- usedForSWHOrRefrigeration = false
193
- usedForZoneHCCoils = false
194
- plantLoop.demandComponents.each do |comp| # AP code to check your comments above
195
- runner.registerInfo("plant loops component is #{comp.name}")
196
- if comp.to_WaterUseConnections.is_initialized || comp.to_CoilWaterHeatingDesuperheater.is_initialized
197
- usedForSWHOrRefrigeration = true
198
- runner.registerWarning("#{plantLoop.name} is used for SWH or refrigeration. Loop will not be deleted.")
199
- elsif comp.name.to_s.include?('Coil') && (comp.name.to_s != 'Coil Heating Water 1') && (comp.name.to_s != 'Coil Cooling Water 1') # to_CoilWaterHeatingDesuperheater.is_initialized or comp.name.to_s.include? "coil"
200
- runner.registerWarning("#{plantLoop.name} has coils used by Zone HVAC components. Loop will not be deleted.")
201
- usedForZoneHCCoils = true
202
- end
203
- end
204
- # runner.registerInfo("Used for ZoneHCCoils Value is #{usedForZoneHCCoils}")
205
- # runner.registerInfo("Used for SWH or refrigeration is #{usedForSWHOrRefrigeration}")
206
- if usedForSWHOrRefrigeration == false # and usedForZoneHCCoils == false # <-- Sang Hoon Lee: "and usedForZoneHCCoils == false" Treated as comment for BRICR Medium office to remove Coil:Heating:Water
207
- plantLoop.remove
208
- runner.registerInfo("Plant Loop #{plantLoop.name} is removed")
209
- end
210
- end # end of plantloop components
211
- end # end of def
212
-
213
- def self.assignHVACSchedules(model, runner, options = {})
214
- require "#{File.dirname(__FILE__)}/OsLib_Schedules"
215
-
216
- schedulesHVAC = {}
217
- airloops = model.getAirLoopHVACs
218
-
219
- # find airloop with most primary spaces
220
- max_primary_spaces = 0
221
- representative_airloop = false
222
- building_HVAC_schedule = false
223
- building_ventilation_schedule = false
224
- unless options['remake_schedules']
225
- # if remake schedules not selected, get relevant schedules from model if they exist
226
- airloops.each do |air_loop|
227
- primary_spaces = 0
228
- air_loop.thermalZones.each do |thermal_zone|
229
- thermal_zone.spaces.each do |space|
230
- if space.spaceType.is_initialized
231
- if space.spaceType.get.name.is_initialized
232
- if space.spaceType.get.name.get.include? options['primarySpaceType']
233
- primary_spaces += 1
234
- end
235
- end
236
- end
237
- end
238
- end
239
- if primary_spaces > max_primary_spaces
240
- max_primary_spaces = primary_spaces
241
- representative_airloop = air_loop
242
- end
243
- end
244
- end
245
- if representative_airloop
246
- building_HVAC_schedule = representative_airloop.availabilitySchedule
247
- if representative_airloop.airLoopHVACOutdoorAirSystem.is_initialized
248
- building_ventilation_schedule_optional = representative_airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.maximumFractionofOutdoorAirSchedule
249
- if building_ventilation_schedule_optional.is_initialized
250
- building_ventilation_schedule = building_ventilation_schedule.get
251
- end
252
- end
253
- end
254
- # build new airloop schedules if existing model doesn't have them
255
- if options['primarySpaceType'] == 'Classroom'
256
- # ventilation schedule
257
- unless building_ventilation_schedule
258
- runner.registerInfo('Baseline does not have minimum OA ventilation schedule. A new K-12 Ventilation schedule is created')
259
- ruleset_name = 'New K-12 Ventilation Schedule'
260
- winter_design_day = [[24, 1]]
261
- summer_design_day = [[24, 1]]
262
- default_day = ['Weekday', [6, 0], [18, 1], [24, 0]]
263
- rules = []
264
- rules << ['Weekend', '1/1-12/31', 'Sat/Sun', [24, 0]]
265
- rules << ['Summer Weekday', '7/1-8/31', 'Mon/Tue/Wed/Thu/Fri', [8, 0], [13, 1], [24, 0]]
266
- options_ventilation = { 'name' => ruleset_name,
267
- 'winter_design_day' => winter_design_day,
268
- 'summer_design_day' => summer_design_day,
269
- 'default_day' => default_day,
270
- 'rules' => rules }
271
- building_ventilation_schedule = OsLib_Schedules.createComplexSchedule(model, options_ventilation)
272
- end
273
- # HVAC availability schedule
274
- unless building_HVAC_schedule
275
- runner.registerInfo('Baseline does not have HVAC availability schedule. A new K-12 HVAC availability schedule is created')
276
- ruleset_name = 'New K-12 HVAC Availability Schedule'
277
- winter_design_day = [[24, 1]]
278
- summer_design_day = [[24, 1]]
279
- default_day = ['Weekday', [6, 0], [18, 1], [24, 0]]
280
- rules = []
281
- rules << ['Weekend', '1/1-12/31', 'Sat/Sun', [24, 0]]
282
- rules << ['Summer Weekday', '7/1-8/31', 'Mon/Tue/Wed/Thu/Fri', [8, 0], [13, 1], [24, 0]]
283
- options_hvac = { 'name' => ruleset_name,
284
- 'winter_design_day' => winter_design_day,
285
- 'summer_design_day' => summer_design_day,
286
- 'default_day' => default_day,
287
- 'rules' => rules }
288
- building_HVAC_schedule = OsLib_Schedules.createComplexSchedule(model, options_hvac)
289
- end
290
- elsif options['primarySpaceType'] == 'Office' # xf - leave as is
291
- # ventilation schedule
292
- unless building_ventilation_schedule
293
- runner.registerInfo('Baseline does not have minimum OA ventilation schedule. A new Office Ventilation schedule is created.')
294
- ruleset_name = 'New Office Ventilation Schedule'
295
- winter_design_day = [[24, 1]] # ML These are not always on in PNNL model
296
- summer_design_day = [[24, 1]] # ML These are not always on in PNNL model
297
- default_day = ['Weekday', [7, 0], [22, 1], [24, 0]] # ML PNNL has a one hour ventilation offset
298
- rules = []
299
- rules << ['Saturday', '1/1-12/31', 'Sat', [7, 0], [18, 1], [24, 0]] # ML PNNL has a one hour ventilation offset
300
- rules << ['Sunday', '1/1-12/31', 'Sun', [24, 0]]
301
- options_ventilation = { 'name' => ruleset_name,
302
- 'winter_design_day' => winter_design_day,
303
- 'summer_design_day' => summer_design_day,
304
- 'default_day' => default_day,
305
- 'rules' => rules }
306
- building_ventilation_schedule = OsLib_Schedules.createComplexSchedule(model, options_ventilation)
307
- end
308
- # HVAC availability schedule
309
- unless building_HVAC_schedule
310
- runner.registerInfo('Baseline does not have HVAC availability schedule. A new office HVAC availability schedule is created')
311
- ruleset_name = 'New Office HVAC Availability Schedule'
312
- winter_design_day = [[24, 1]] # ML These are not always on in PNNL model
313
- summer_design_day = [[24, 1]] # ML These are not always on in PNNL model
314
- default_day = ['Weekday', [6, 0], [22, 1], [24, 0]] # ML PNNL has a one hour ventilation offset
315
- rules = []
316
- rules << ['Saturday', '1/1-12/31', 'Sat', [6, 0], [18, 1], [24, 0]] # ML PNNL has a one hour ventilation offset
317
- rules << ['Sunday', '1/1-12/31', 'Sun', [24, 0]]
318
- options_hvac = { 'name' => ruleset_name,
319
- 'winter_design_day' => winter_design_day,
320
- 'summer_design_day' => summer_design_day,
321
- 'default_day' => default_day,
322
- 'rules' => rules }
323
- building_HVAC_schedule = OsLib_Schedules.createComplexSchedule(model, options_hvac)
324
- end
325
- # special loops for radiant system (different temperature setpoints)
326
- if options['allHVAC']['zone'] == 'Radiant'
327
- # create hot water schedule for radiant heating loop
328
- schedulesHVAC['radiant_hot_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HW-Radiant-Loop-Temp-Schedule',
329
- 'default_day' => ['All Days', [24, 45.0]])
330
- # create hot water schedule for radiant cooling loop
331
- schedulesHVAC['radiant_chilled_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New CW-Radiant-Loop-Temp-Schedule',
332
- 'default_day' => ['All Days', [24, 15.0]])
333
- # create mean radiant heating and cooling setpoint schedules
334
- # ML ideally, should grab schedules tied to zone thermostat and make modified versions that follow the setback pattern
335
- # for now, create new ones that match the recommended HVAC schedule
336
- # mean radiant heating setpoint schedule (PNNL values)
337
- ruleset_name = 'New Office Mean Radiant Heating Setpoint Schedule'
338
- winter_design_day = [[24, 18.8]]
339
- summer_design_day = [[6, 18.3], [22, 18.8], [24, 18.3]]
340
- default_day = ['Weekday', [6, 18.3], [22, 18.8], [24, 18.3]]
341
- rules = []
342
- rules << ['Saturday', '1/1-12/31', 'Sat', [6, 18.3], [18, 18.8], [24, 18.3]]
343
- rules << ['Sunday', '1/1-12/31', 'Sun', [24, 18.3]]
344
- options_radiant_heating = { 'name' => ruleset_name,
345
- 'winter_design_day' => winter_design_day,
346
- 'summer_design_day' => summer_design_day,
347
- 'default_day' => default_day,
348
- 'rules' => rules }
349
- mean_radiant_heating_schedule = OsLib_Schedules.createComplexSchedule(model, options_radiant_heating)
350
- schedulesHVAC['mean_radiant_heating'] = mean_radiant_heating_schedule
351
- # mean radiant cooling setpoint schedule (PNNL values)
352
- ruleset_name = 'New Office Mean Radiant Cooling Setpoint Schedule'
353
- winter_design_day = [[6, 26.7], [22, 24.0], [24, 26.7]]
354
- summer_design_day = [[24, 24.0]]
355
- default_day = ['Weekday', [6, 26.7], [22, 24.0], [24, 26.7]]
356
- rules = []
357
- rules << ['Saturday', '1/1-12/31', 'Sat', [6, 26.7], [18, 24.0], [24, 26.7]]
358
- rules << ['Sunday', '1/1-12/31', 'Sun', [24, 26.7]]
359
- options_radiant_cooling = { 'name' => ruleset_name,
360
- 'winter_design_day' => winter_design_day,
361
- 'summer_design_day' => summer_design_day,
362
- 'default_day' => default_day,
363
- 'rules' => rules }
364
- mean_radiant_cooling_schedule = OsLib_Schedules.createComplexSchedule(model, options_radiant_cooling)
365
- schedulesHVAC['mean_radiant_cooling'] = mean_radiant_cooling_schedule
366
- end
367
- end
368
- # SAT schedule
369
- if options['allHVAC']['primary']['doas']
370
- # primary airloop is DOAS
371
- schedulesHVAC['primary_sat'] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, 'name' => 'DOAS Temperature Setpoint Schedule',
372
- 'default_day' => ['All Days', [24, 21.111]])
373
- else
374
- # primary airloop is multizone VAV that cools
375
- schedulesHVAC['primary_sat'] = sch_ruleset_DOAS_setpoint = OsLib_Schedules.createComplexSchedule(model, 'name' => 'Cold Deck Temperature Setpoint Schedule',
376
- 'default_day' => ['All Days', [24, 12.8]])
377
- end
378
- schedulesHVAC['ventilation'] = building_ventilation_schedule
379
- schedulesHVAC['hvac'] = building_HVAC_schedule
380
- # build new plant schedules as needed
381
- zoneHVACHotWaterPlant = ['FanCoil', 'DualDuct', 'Baseboard'] # dual duct has fan coil and baseboard
382
- zoneHVACChilledWaterPlant = ['FanCoil', 'DualDuct'] # dual duct has fan coil
383
- # hot water
384
- if (options['allHVAC']['primary']['heat'] == 'Water') || (options['allHVAC']['secondary']['heat'] == 'Water') || zoneHVACHotWaterPlant.include?(options['allHVAC']['zone'])
385
- schedulesHVAC['hot_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'HW-Loop-Temp-Schedule',
386
- 'default_day' => ['All Days', [24, 67.0]])
387
- end
388
- # chilled water
389
- if (options['allHVAC']['primary']['cool'] == 'Water') || (options['allHVAC']['secondary']['cool'] == 'Water') || zoneHVACChilledWaterPlant.include?(options['allHVAC']['zone'])
390
- schedulesHVAC['chilled_water'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'CW-Loop-Temp-Schedule',
391
- 'default_day' => ['All Days', [24, 6.7]])
392
- end
393
- # heat pump condenser loop schedules
394
- if options['allHVAC']['zone'] == 'GSHP'
395
- # there will be a heat pump condenser loop
396
- # loop setpoint schedule
397
- schedulesHVAC['hp_loop'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Temp-Schedule',
398
- 'default_day' => ['All Days', [24, 21]])
399
- # cooling component schedule (#ML won't need this if a ground loop is actually modeled)
400
- schedulesHVAC['hp_loop_cooling'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Clg-Temp-Schedule',
401
- 'default_day' => ['All Days', [24, 21]])
402
- # heating component schedule
403
- schedulesHVAC['hp_loop_heating'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Htg-Temp-Schedule',
404
- 'default_day' => ['All Days', [24, 5]])
405
- end
406
- if options['allHVAC']['zone'] == 'WSHP'
407
- # there will be a heat pump condenser loop
408
- # loop setpoint schedule
409
- schedulesHVAC['hp_loop'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Temp-Schedule',
410
- 'default_day' => ['All Days', [24, 30]]) # PNNL
411
- # cooling component schedule (#ML won't need this if a ground loop is actually modeled)
412
- schedulesHVAC['hp_loop_cooling'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Clg-Temp-Schedule',
413
- 'default_day' => ['All Days', [24, 30]]) # PNNL
414
- # heating component schedule
415
- schedulesHVAC['hp_loop_heating'] = OsLib_Schedules.createComplexSchedule(model, 'name' => 'New HP-Loop-Htg-Temp-Schedule',
416
- 'default_day' => ['All Days', [24, 20]]) # PNNL
417
- end
418
-
419
- # pass back schedulesHVAC hash
420
- result = schedulesHVAC
421
- return result
422
- end # end of def
423
-
424
- def self.createHotWaterPlant(model, runner, hot_water_setpoint_schedule, loop_type, parameters)
425
- hot_water_plant = OpenStudio::Model::PlantLoop.new(model)
426
- hot_water_plant.setName("New #{loop_type} Loop")
427
- hot_water_plant.setMaximumLoopTemperature(100)
428
- hot_water_plant.setMinimumLoopTemperature(10)
429
- loop_sizing = hot_water_plant.sizingPlant
430
- loop_sizing.setLoopType('Heating')
431
- if loop_type == 'Hot Water'
432
- loop_sizing.setDesignLoopExitTemperature(82)
433
- elsif loop_type == 'Radiant Hot Water'
434
- loop_sizing.setDesignLoopExitTemperature(60) # ML follows convention of sizing temp being larger than supplu temp
435
- end
436
- loop_sizing.setLoopDesignTemperatureDifference(11)
437
- # create a pump
438
- pump = OpenStudio::Model::PumpVariableSpeed.new(model)
439
- pump.setRatedPumpHead(119563) # Pa
440
- pump.setMotorEfficiency(0.9)
441
- pump.setCoefficient1ofthePartLoadPerformanceCurve(0)
442
- pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216)
443
- pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325)
444
- pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095)
445
- # create a boiler
446
- boiler = OpenStudio::Model::BoilerHotWater.new(model)
447
- boiler.setNominalThermalEfficiency(0.9)
448
- # create a scheduled setpoint manager
449
- setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model, hot_water_setpoint_schedule)
450
- # create a supply bypass pipe
451
- pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
452
- # create a supply outlet pipe
453
- pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
454
- # create a demand bypass pipe
455
- pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
456
- # create a demand inlet pipe
457
- pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model)
458
- # create a demand outlet pipe
459
- pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
460
- # connect components to plant loop
461
- # supply side components
462
- hot_water_plant.addSupplyBranchForComponent(boiler)
463
- hot_water_plant.addSupplyBranchForComponent(pipe_supply_bypass)
464
- pump.addToNode(hot_water_plant.supplyInletNode)
465
- pipe_supply_outlet.addToNode(hot_water_plant.supplyOutletNode)
466
- setpoint_manager_scheduled.addToNode(hot_water_plant.supplyOutletNode)
467
- # demand side components (water coils are added as they are added to airloops and zoneHVAC)
468
- hot_water_plant.addDemandBranchForComponent(pipe_demand_bypass)
469
- pipe_demand_inlet.addToNode(hot_water_plant.demandInletNode)
470
- pipe_demand_outlet.addToNode(hot_water_plant.demandOutletNode)
471
-
472
- # pass back hot water plant
473
- result = hot_water_plant
474
- return result
475
- end # end of def
476
-
477
- def self.createChilledWaterPlant(model, runner, chilled_water_setpoint_schedule, loop_type, chillerType)
478
- # chilled water plant
479
- chilled_water_plant = OpenStudio::Model::PlantLoop.new(model)
480
- chilled_water_plant.setName("New #{loop_type} Loop")
481
- chilled_water_plant.setMaximumLoopTemperature(98)
482
- chilled_water_plant.setMinimumLoopTemperature(1)
483
- loop_sizing = chilled_water_plant.sizingPlant
484
- loop_sizing.setLoopType('Cooling')
485
- if loop_type == 'Chilled Water'
486
- loop_sizing.setDesignLoopExitTemperature(6.7)
487
- elsif loop_type == 'Radiant Chilled Water'
488
- loop_sizing.setDesignLoopExitTemperature(15)
489
- end
490
- loop_sizing.setLoopDesignTemperatureDifference(6.7)
491
- # create a pump
492
- pump = OpenStudio::Model::PumpVariableSpeed.new(model)
493
- pump.setRatedPumpHead(149453) # Pa
494
- pump.setMotorEfficiency(0.9)
495
- pump.setCoefficient1ofthePartLoadPerformanceCurve(0)
496
- pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216)
497
- pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325)
498
- pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095)
499
- # create a chiller
500
- if chillerType == 'WaterCooled'
501
- # create clgCapFuncTempCurve
502
- clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
503
- clgCapFuncTempCurve.setCoefficient1Constant(1.07E+00)
504
- clgCapFuncTempCurve.setCoefficient2x(4.29E-02)
505
- clgCapFuncTempCurve.setCoefficient3xPOW2(4.17E-04)
506
- clgCapFuncTempCurve.setCoefficient4y(-8.10E-03)
507
- clgCapFuncTempCurve.setCoefficient5yPOW2(-4.02E-05)
508
- clgCapFuncTempCurve.setCoefficient6xTIMESY(-3.86E-04)
509
- clgCapFuncTempCurve.setMinimumValueofx(0)
510
- clgCapFuncTempCurve.setMaximumValueofx(20)
511
- clgCapFuncTempCurve.setMinimumValueofy(0)
512
- clgCapFuncTempCurve.setMaximumValueofy(50)
513
- # create eirFuncTempCurve
514
- eirFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
515
- eirFuncTempCurve.setCoefficient1Constant(4.68E-01)
516
- eirFuncTempCurve.setCoefficient2x(-1.38E-02)
517
- eirFuncTempCurve.setCoefficient3xPOW2(6.98E-04)
518
- eirFuncTempCurve.setCoefficient4y(1.09E-02)
519
- eirFuncTempCurve.setCoefficient5yPOW2(4.62E-04)
520
- eirFuncTempCurve.setCoefficient6xTIMESY(-6.82E-04)
521
- eirFuncTempCurve.setMinimumValueofx(0)
522
- eirFuncTempCurve.setMaximumValueofx(20)
523
- eirFuncTempCurve.setMinimumValueofy(0)
524
- eirFuncTempCurve.setMaximumValueofy(50)
525
- # create eirFuncPlrCurve
526
- eirFuncPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
527
- eirFuncPlrCurve.setCoefficient1Constant(1.41E-01)
528
- eirFuncPlrCurve.setCoefficient2x(6.55E-01)
529
- eirFuncPlrCurve.setCoefficient3xPOW2(2.03E-01)
530
- eirFuncPlrCurve.setMinimumValueofx(0)
531
- eirFuncPlrCurve.setMaximumValueofx(1.2)
532
- # construct chiller
533
- chiller = OpenStudio::Model::ChillerElectricEIR.new(model, clgCapFuncTempCurve, eirFuncTempCurve, eirFuncPlrCurve)
534
- chiller.setReferenceCOP(6.1)
535
- chiller.setCondenserType('WaterCooled')
536
- chiller.setChillerFlowMode('ConstantFlow')
537
- elsif chillerType == 'AirCooled'
538
- # create clgCapFuncTempCurve
539
- clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
540
- clgCapFuncTempCurve.setCoefficient1Constant(1.05E+00)
541
- clgCapFuncTempCurve.setCoefficient2x(3.36E-02)
542
- clgCapFuncTempCurve.setCoefficient3xPOW2(2.15E-04)
543
- clgCapFuncTempCurve.setCoefficient4y(-5.18E-03)
544
- clgCapFuncTempCurve.setCoefficient5yPOW2(-4.42E-05)
545
- clgCapFuncTempCurve.setCoefficient6xTIMESY(-2.15E-04)
546
- clgCapFuncTempCurve.setMinimumValueofx(0)
547
- clgCapFuncTempCurve.setMaximumValueofx(20)
548
- clgCapFuncTempCurve.setMinimumValueofy(0)
549
- clgCapFuncTempCurve.setMaximumValueofy(50)
550
- # create eirFuncTempCurve
551
- eirFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
552
- eirFuncTempCurve.setCoefficient1Constant(5.83E-01)
553
- eirFuncTempCurve.setCoefficient2x(-4.04E-03)
554
- eirFuncTempCurve.setCoefficient3xPOW2(4.68E-04)
555
- eirFuncTempCurve.setCoefficient4y(-2.24E-04)
556
- eirFuncTempCurve.setCoefficient5yPOW2(4.81E-04)
557
- eirFuncTempCurve.setCoefficient6xTIMESY(-6.82E-04)
558
- eirFuncTempCurve.setMinimumValueofx(0)
559
- eirFuncTempCurve.setMaximumValueofx(20)
560
- eirFuncTempCurve.setMinimumValueofy(0)
561
- eirFuncTempCurve.setMaximumValueofy(50)
562
- # create eirFuncPlrCurve
563
- eirFuncPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
564
- eirFuncPlrCurve.setCoefficient1Constant(4.19E-02)
565
- eirFuncPlrCurve.setCoefficient2x(6.25E-01)
566
- eirFuncPlrCurve.setCoefficient3xPOW2(3.23E-01)
567
- eirFuncPlrCurve.setMinimumValueofx(0)
568
- eirFuncPlrCurve.setMaximumValueofx(1.2)
569
- # construct chiller
570
- chiller = OpenStudio::Model::ChillerElectricEIR.new(model, clgCapFuncTempCurve, eirFuncTempCurve, eirFuncPlrCurve)
571
- chiller.setReferenceCOP(2.93)
572
- chiller.setCondenserType('AirCooled')
573
- chiller.setChillerFlowMode('ConstantFlow')
574
- end
575
- # create a scheduled setpoint manager
576
- setpoint_manager_scheduled = OpenStudio::Model::SetpointManagerScheduled.new(model, chilled_water_setpoint_schedule)
577
- # create a supply bypass pipe
578
- pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
579
- # create a supply outlet pipe
580
- pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
581
- # create a demand bypass pipe
582
- pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
583
- # create a demand inlet pipe
584
- pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model)
585
- # create a demand outlet pipe
586
- pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
587
- # connect components to plant loop
588
- # supply side components
589
- chilled_water_plant.addSupplyBranchForComponent(chiller)
590
- chilled_water_plant.addSupplyBranchForComponent(pipe_supply_bypass)
591
- pump.addToNode(chilled_water_plant.supplyInletNode)
592
- pipe_supply_outlet.addToNode(chilled_water_plant.supplyOutletNode)
593
- setpoint_manager_scheduled.addToNode(chilled_water_plant.supplyOutletNode)
594
- # demand side components (water coils are added as they are added to airloops and ZoneHVAC)
595
- chilled_water_plant.addDemandBranchForComponent(pipe_demand_bypass)
596
- pipe_demand_inlet.addToNode(chilled_water_plant.demandInletNode)
597
- pipe_demand_outlet.addToNode(chilled_water_plant.demandOutletNode)
598
-
599
- # pass back chilled water plant
600
- result = chilled_water_plant
601
- return result
602
- end # end of def
603
-
604
- def self.createCondenserLoop(model, runner, options, parameters)
605
- condenserLoops = {}
606
- # condLoopCoolingTemp_si = OpenStudio::convert(condLoopCoolingTemp,"F","C").get
607
- # condLoopHeatingTemp_si = OpenStudio::convert(parameters["condLoopHeatingTemp"],"F","C").get
608
- # coolingTowerWB_si = OpenStudio::convert(coolingTowerWB,"F","C").get
609
- boilerHWST_si = OpenStudio.convert(parameters['boilerHWST'], 'F', 'C').get
610
- # check for water-cooled chillers
611
- waterCooledChiller = false
612
- model.getChillerElectricEIRs.each do |chiller|
613
- next if waterCooledChiller == true
614
- if chiller.condenserType == 'WaterCooled'
615
- waterCooledChiller = true
616
- end
617
- end
618
- # create condenser loop for water-cooled chillers
619
- if waterCooledChiller
620
- # create condenser loop for water-cooled chiller(s)
621
- condenser_loop = OpenStudio::Model::PlantLoop.new(model)
622
- condenser_loop.setName('New Condenser Loop')
623
- condenser_loop.setMaximumLoopTemperature(80)
624
- condenser_loop.setMinimumLoopTemperature(5)
625
- loop_sizing = condenser_loop.sizingPlant
626
- loop_sizing.setLoopType('Condenser')
627
- loop_sizing.setDesignLoopExitTemperature(29.4)
628
- loop_sizing.setLoopDesignTemperatureDifference(5.6)
629
- # create a pump
630
- pump = OpenStudio::Model::PumpVariableSpeed.new(model)
631
- pump.setRatedPumpHead(134508) # Pa
632
- pump.setMotorEfficiency(0.9)
633
- pump.setCoefficient1ofthePartLoadPerformanceCurve(0)
634
- pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216)
635
- pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325)
636
- pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095)
637
- # create a cooling tower
638
- tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model)
639
- # create a supply bypass pipe
640
- pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
641
- # create a supply outlet pipe
642
- pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
643
- # create a demand bypass pipe
644
- pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
645
- # create a demand inlet pipe
646
- pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model)
647
- # create a demand outlet pipe
648
- pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
649
- # create a setpoint manager
650
- setpoint_manager_follow_oa = OpenStudio::Model::SetpointManagerFollowOutdoorAirTemperature.new(model)
651
- setpoint_manager_follow_oa.setOffsetTemperatureDifference(0)
652
- setpoint_manager_follow_oa.setMaximumSetpointTemperature(80)
653
- setpoint_manager_follow_oa.setMinimumSetpointTemperature(5)
654
- # connect components to plant loop
655
- # supply side components
656
- condenser_loop.addSupplyBranchForComponent(tower)
657
- condenser_loop.addSupplyBranchForComponent(pipe_supply_bypass)
658
- pump.addToNode(condenser_loop.supplyInletNode)
659
- pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode)
660
- setpoint_manager_follow_oa.addToNode(condenser_loop.supplyOutletNode)
661
- # demand side components
662
- model.getChillerElectricEIRs.each do |chiller|
663
- if chiller.condenserType == 'WaterCooled' # works only if chillers not already connected to condenser loop(s)
664
- condenser_loop.addDemandBranchForComponent(chiller)
665
- end
666
- end
667
- condenser_loop.addDemandBranchForComponent(pipe_demand_bypass)
668
- pipe_demand_inlet.addToNode(condenser_loop.demandInletNode)
669
- pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode)
670
- condenserLoops['condenser_loop'] = condenser_loop
671
- end
672
- if (options['zoneHVAC'] == 'WSHP') || (options['zoneHVAC'] == 'GSHP') && options
673
- # create condenser loop for heat pumps
674
- condenser_loop = OpenStudio::Model::PlantLoop.new(model)
675
- condenser_loop.setName('Heat Pump Loop')
676
- condenser_loop.setMaximumLoopTemperature(80)
677
- condenser_loop.setMinimumLoopTemperature(5)
678
- loop_sizing = condenser_loop.sizingPlant
679
- loop_sizing.setLoopType('Condenser')
680
-
681
- if options['zoneHVAC'] == 'GSHP'
682
- loop_sizing.setDesignLoopExitTemperature(32.2)
683
- loop_sizing.setLoopDesignTemperatureDifference(5.5556)
684
- elsif options['zoneHVAC'] == 'WSHP'
685
- loop_sizing.setDesignLoopExitTemperature(32.2)
686
- loop_sizing.setLoopDesignTemperatureDifference(5.5556)
687
- end
688
- # create a pump
689
- pump = OpenStudio::Model::PumpVariableSpeed.new(model)
690
- pump.setRatedPumpHead(134508) # Pa
691
- pump.setMotorEfficiency(0.9)
692
- pump.setCoefficient1ofthePartLoadPerformanceCurve(0)
693
- pump.setCoefficient2ofthePartLoadPerformanceCurve(0.0216)
694
- pump.setCoefficient3ofthePartLoadPerformanceCurve(-0.0325)
695
- pump.setCoefficient4ofthePartLoadPerformanceCurve(1.0095)
696
- # create a supply bypass pipe
697
- pipe_supply_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
698
- # create a supply outlet pipe
699
- pipe_supply_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
700
- # create a demand bypass pipe
701
- pipe_demand_bypass = OpenStudio::Model::PipeAdiabatic.new(model)
702
- # create a demand inlet pipe
703
- pipe_demand_inlet = OpenStudio::Model::PipeAdiabatic.new(model)
704
- # create a demand outlet pipe
705
- pipe_demand_outlet = OpenStudio::Model::PipeAdiabatic.new(model)
706
- # create setpoint managers
707
- setpoint_manager_scheduled_loop = OpenStudio::Model::SetpointManagerScheduled.new(model, options['loop_setpoint_schedule'])
708
- setpoint_manager_scheduled_cooling = OpenStudio::Model::SetpointManagerScheduled.new(model, options['cooling_setpoint_schedule'])
709
- setpoint_manager_scheduled_heating = OpenStudio::Model::SetpointManagerScheduled.new(model, options['heating_setpoint_schedule'])
710
- # connect components to plant loop
711
- # supply side components
712
- condenser_loop.addSupplyBranchForComponent(pipe_supply_bypass)
713
- pump.addToNode(condenser_loop.supplyInletNode)
714
- pipe_supply_outlet.addToNode(condenser_loop.supplyOutletNode)
715
- setpoint_manager_scheduled_loop.addToNode(condenser_loop.supplyOutletNode)
716
- # demand side components
717
- condenser_loop.addDemandBranchForComponent(pipe_demand_bypass)
718
- pipe_demand_inlet.addToNode(condenser_loop.demandInletNode)
719
- pipe_demand_outlet.addToNode(condenser_loop.demandOutletNode)
720
- # add additional components according to specific system type
721
- if options['zoneHVAC'] == 'GSHP'
722
- # add vertical ground heat exchanger
723
- verticalGHX = OpenStudio::Model::GroundHeatExchangerVertical.new(model)
724
- boreHoleLength_si = OpenStudio.convert(parameters['boreHoleLength'], 'ft', 'm').get
725
- boreHoleRadius_si = OpenStudio.convert(parameters['boreHoleRadius'], 'in', 'm').get
726
- groundKValue_si = OpenStudio.convert(parameters['groundKValue'], 'Btu/ft*h*R', 'W/m*K').get
727
- groutKValue_si = OpenStudio.convert(parameters['groutKValue'], 'Btu/ft*h*R', 'W/m*K').get
728
- verticalGHX.setNumberofBoreHoles(parameters['boreHoleNo'])
729
- verticalGHX.setBoreHoleLength(boreHoleLength_si)
730
- verticalGHX.setBoreHoleRadius(boreHoleRadius_si)
731
- verticalGHX.setGroundThermalConductivity(groundKValue_si)
732
- verticalGHX.setGroutThermalConductivity(groutKValue_si)
733
- condenser_loop.addSupplyBranchForComponent(verticalGHX)
734
- # setpoint_manager_scheduled_heating.addToNode(verticalGHX.outletModelObject.get.to_Node.get)
735
- # add supplemental heating boiler
736
- if parameters['supplementalBoiler'] == 'Yes'
737
- boiler = OpenStudio::Model::BoilerHotWater.new(model)
738
- boiler.setNominalCapacity(parameters['boilerCap'] * 1000000)
739
- boiler.setNominalThermalEfficiency(parameters['boilerEff'])
740
- boiler.setFuelType(parameters['boilerFuelType'])
741
- boiler.setDesignWaterOutletTemperature(boilerHWST_si)
742
- boiler.addToNode(verticalGHX.outletModelObject.get.to_Node.get)
743
- # condenser_loop.addSupplyBranchForComponent(boiler)
744
- # setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get)
745
- end
746
- # add heat pumps to demand side after they get created
747
- elsif options['zoneHVAC'] == 'WSHP'
748
- # add a boiler and cooling tower to supply side
749
- # create a boiler
750
- boiler = OpenStudio::Model::BoilerHotWater.new(model)
751
- boiler.setNominalThermalEfficiency(parameters['boilerEff'])
752
- boiler.setFuelType(parameters['boilerFuelType'])
753
- boiler.setDesignWaterOutletTemperature(parameters['boilerHWST'])
754
- condenser_loop.addSupplyBranchForComponent(boiler)
755
- setpoint_manager_scheduled_heating.addToNode(boiler.outletModelObject.get.to_Node.get)
756
- # create a cooling tower
757
- tower = OpenStudio::Model::CoolingTowerVariableSpeed.new(model)
758
- # tower.setDesignInletAirWetBulbTemperature(coolingTowerWB_si)
759
- # tower.setDesignApproachTemperature(coolingTowerApproach/1.8)
760
- # tower.setDesignRangeTemperature(coolingTowerDeltaT/1.8)
761
- tower.addToNode(boiler.outletModelObject.get.to_Node.get)
762
- setpoint_manager_scheduled_cooling.addToNode(tower.outletModelObject.get.to_Node.get)
763
- end
764
- condenserLoops['heat_pump_loop'] = condenser_loop
765
- end
766
-
767
- # pass back condenser loop(s)
768
- result = condenserLoops
769
- return result
770
- end # end of def
771
-
772
- def self.createPrimaryAirLoops(model, runner, options, parameters)
773
- primary_airloops = []
774
- # create primary airloop for each story
775
- assignedThermalZones = []
776
- model.getBuildingStorys.sort.each do |building_story|
777
- # ML stories need to be reordered from the ground up
778
- thermalZonesToAdd = []
779
- building_story.spaces.each do |space|
780
- # make sure spaces are assigned to thermal zones
781
- # otherwise might want to send a warning
782
- if space.thermalZone.is_initialized
783
- thermal_zone = space.thermalZone.get
784
- # grab primary zones
785
- if options['zonesPrimary'].include? thermal_zone
786
- # make sure zone was not already assigned to another air loop
787
- unless assignedThermalZones.include? thermal_zone
788
- # make sure thermal zones are not duplicated (spaces can share thermal zones)
789
- unless thermalZonesToAdd.include? thermal_zone
790
- thermalZonesToAdd << thermal_zone
791
- end
792
- end
793
- end
794
- end
795
- end
796
- # make sure thermal zones don't get added to more than one air loop
797
- assignedThermalZones << thermalZonesToAdd
798
-
799
- # create new air loop if story contains primary zones
800
- unless thermalZonesToAdd.empty?
801
- airloop_primary = OpenStudio::Model::AirLoopHVAC.new(model)
802
- airloop_primary.setName("DOAS - #{building_story.name}")
803
- # modify system sizing properties
804
- sizing_system = airloop_primary.sizingSystem
805
- # set central heating and cooling temperatures for sizing
806
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(12.8)
807
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) # ML OS default is 16.7
808
- # load specification
809
- sizing_system.setSystemOutdoorAirMethod('VentilationRateProcedure') # ML OS default is ZoneSum
810
- if options['primaryHVAC']['doas']
811
- sizing_system.setTypeofLoadtoSizeOn('VentilationRequirement') # DOAS
812
- sizing_system.setAllOutdoorAirinCooling(true) # DOAS
813
- sizing_system.setAllOutdoorAirinHeating(true) # DOAS
814
- else
815
- sizing_system.setTypeofLoadtoSizeOn('Sensible') # VAV
816
- sizing_system.setAllOutdoorAirinCooling(false) # VAV
817
- sizing_system.setAllOutdoorAirinHeating(false) # VAV
818
- end
819
-
820
- air_loop_comps = []
821
- # set availability schedule
822
- airloop_primary.setAvailabilitySchedule(options['hvac_schedule'])
823
- # create air loop fan
824
- if options['primaryHVAC']['fan'] == 'Variable'
825
- # create variable speed fan and set system sizing accordingly
826
- sizing_system.setMinimumSystemAirFlowRatio(0.3) # DCV
827
- # variable speed fan
828
- fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule)
829
- fan.setFanEfficiency(0.69)
830
- fan.setPressureRise(1125) # Pa
831
- fan.autosizeMaximumFlowRate
832
- fan.setFanPowerMinimumFlowFraction(0.6)
833
- fan.setMotorEfficiency(0.9)
834
- fan.setMotorInAirstreamFraction(1.0)
835
- air_loop_comps << fan
836
- else
837
- sizing_system.setMinimumSystemAirFlowRatio(1.0) # No DCV
838
- # constant speed fan
839
- fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule)
840
- fan.setFanEfficiency(0.6)
841
- fan.setPressureRise(500) # Pa
842
- fan.autosizeMaximumFlowRate
843
- fan.setMotorEfficiency(0.9)
844
- fan.setMotorInAirstreamFraction(1.0)
845
- air_loop_comps << fan
846
- end
847
- # create heating coil
848
- if options['primaryHVAC']['heat'] == 'Water'
849
- # water coil
850
- heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule)
851
- air_loop_comps << heating_coil
852
- else
853
- # gas coil
854
- heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule)
855
- air_loop_comps << heating_coil
856
- end
857
- # create cooling coil
858
- if options['primaryHVAC']['cool'] == 'Water'
859
- # water coil
860
- cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule)
861
- air_loop_comps << cooling_coil
862
- elsif options['primaryHVAC']['cool'] == 'SingleDX'
863
- # single speed DX coil
864
- # create cooling coil
865
- # create clgCapFuncTempCurve
866
- clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
867
- clgCapFuncTempCurve.setCoefficient1Constant(0.42415)
868
- clgCapFuncTempCurve.setCoefficient2x(0.04426)
869
- clgCapFuncTempCurve.setCoefficient3xPOW2(-0.00042)
870
- clgCapFuncTempCurve.setCoefficient4y(0.00333)
871
- clgCapFuncTempCurve.setCoefficient5yPOW2(-0.00008)
872
- clgCapFuncTempCurve.setCoefficient6xTIMESY(-0.00021)
873
- clgCapFuncTempCurve.setMinimumValueofx(17)
874
- clgCapFuncTempCurve.setMaximumValueofx(22)
875
- clgCapFuncTempCurve.setMinimumValueofy(13)
876
- clgCapFuncTempCurve.setMaximumValueofy(46)
877
- # create clgCapFuncFlowFracCurve
878
- clgCapFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
879
- clgCapFuncFlowFracCurve.setCoefficient1Constant(0.77136)
880
- clgCapFuncFlowFracCurve.setCoefficient2x(0.34053)
881
- clgCapFuncFlowFracCurve.setCoefficient3xPOW2(-0.11088)
882
- clgCapFuncFlowFracCurve.setMinimumValueofx(0.75918)
883
- clgCapFuncFlowFracCurve.setMaximumValueofx(1.13877)
884
- # create clgEirFuncTempCurve
885
- clgEirFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
886
- clgEirFuncTempCurve.setCoefficient1Constant(1.23649)
887
- clgEirFuncTempCurve.setCoefficient2x(-0.02431)
888
- clgEirFuncTempCurve.setCoefficient3xPOW2(0.00057)
889
- clgEirFuncTempCurve.setCoefficient4y(-0.01434)
890
- clgEirFuncTempCurve.setCoefficient5yPOW2(0.00063)
891
- clgEirFuncTempCurve.setCoefficient6xTIMESY(-0.00038)
892
- clgEirFuncTempCurve.setMinimumValueofx(17)
893
- clgEirFuncTempCurve.setMaximumValueofx(22)
894
- clgEirFuncTempCurve.setMinimumValueofy(13)
895
- clgEirFuncTempCurve.setMaximumValueofy(46)
896
- # create clgEirFuncFlowFracCurve
897
- clgEirFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
898
- clgEirFuncFlowFracCurve.setCoefficient1Constant(1.20550)
899
- clgEirFuncFlowFracCurve.setCoefficient2x(-0.32953)
900
- clgEirFuncFlowFracCurve.setCoefficient3xPOW2(0.12308)
901
- clgEirFuncFlowFracCurve.setMinimumValueofx(0.75918)
902
- clgEirFuncFlowFracCurve.setMaximumValueofx(1.13877)
903
- # create clgPlrCurve
904
- clgPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
905
- clgPlrCurve.setCoefficient1Constant(0.77100)
906
- clgPlrCurve.setCoefficient2x(0.22900)
907
- clgPlrCurve.setCoefficient3xPOW2(0.0)
908
- clgPlrCurve.setMinimumValueofx(0.0)
909
- clgPlrCurve.setMaximumValueofx(1.0)
910
- # cooling coil
911
- cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model,
912
- model.alwaysOnDiscreteSchedule,
913
- clgCapFuncTempCurve,
914
- clgCapFuncFlowFracCurve,
915
- clgEirFuncTempCurve,
916
- clgEirFuncFlowFracCurve,
917
- clgPlrCurve)
918
- cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(parameters['doasDXEER'] / 3.412))
919
- air_loop_comps << cooling_coil
920
- else
921
- # two speed DX coil (PNNL curves)
922
- # create cooling coil
923
- # create clgCapFuncTempCurve
924
- clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
925
- clgCapFuncTempCurve.setCoefficient1Constant(1.39072)
926
- clgCapFuncTempCurve.setCoefficient2x(-0.0529058)
927
- clgCapFuncTempCurve.setCoefficient3xPOW2(0.0018423)
928
- clgCapFuncTempCurve.setCoefficient4y(0.00058267)
929
- clgCapFuncTempCurve.setCoefficient5yPOW2(-0.000186814)
930
- clgCapFuncTempCurve.setCoefficient6xTIMESY(0.000265159)
931
- clgCapFuncTempCurve.setMinimumValueofx(16.5556)
932
- clgCapFuncTempCurve.setMaximumValueofx(22.1111)
933
- clgCapFuncTempCurve.setMinimumValueofy(23.7778)
934
- clgCapFuncTempCurve.setMaximumValueofy(47.66)
935
- # create clgCapFuncFlowFracCurve
936
- clgCapFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
937
- clgCapFuncFlowFracCurve.setCoefficient1Constant(0.718954)
938
- clgCapFuncFlowFracCurve.setCoefficient2x(0.435436)
939
- clgCapFuncFlowFracCurve.setCoefficient3xPOW2(-0.154193)
940
- clgCapFuncFlowFracCurve.setMinimumValueofx(0.75)
941
- clgCapFuncFlowFracCurve.setMaximumValueofx(1.25)
942
- # create clgEirFuncTempCurve
943
- clgEirFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
944
- clgEirFuncTempCurve.setCoefficient1Constant(-0.536161)
945
- clgEirFuncTempCurve.setCoefficient2x(0.105138)
946
- clgEirFuncTempCurve.setCoefficient3xPOW2(-0.00172659)
947
- clgEirFuncTempCurve.setCoefficient4y(0.0149848)
948
- clgEirFuncTempCurve.setCoefficient5yPOW2(0.000659948)
949
- clgEirFuncTempCurve.setCoefficient6xTIMESY(-0.0017385)
950
- clgEirFuncTempCurve.setMinimumValueofx(16.5556)
951
- clgEirFuncTempCurve.setMaximumValueofx(22.1111)
952
- clgEirFuncTempCurve.setMinimumValueofy(23.7778)
953
- clgEirFuncTempCurve.setMaximumValueofy(47.66)
954
- # create clgEirFuncFlowFracCurve
955
- clgEirFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
956
- clgEirFuncFlowFracCurve.setCoefficient1Constant(1.19525)
957
- clgEirFuncFlowFracCurve.setCoefficient2x(-0.306138)
958
- clgEirFuncFlowFracCurve.setCoefficient3xPOW2(0.110973)
959
- clgEirFuncFlowFracCurve.setMinimumValueofx(0.75)
960
- clgEirFuncFlowFracCurve.setMaximumValueofx(1.25)
961
- # create clgPlrCurve
962
- clgPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
963
- clgPlrCurve.setCoefficient1Constant(0.77100)
964
- clgPlrCurve.setCoefficient2x(0.22900)
965
- clgPlrCurve.setCoefficient3xPOW2(0.0)
966
- clgPlrCurve.setMinimumValueofx(0.0)
967
- clgPlrCurve.setMaximumValueofx(1.0)
968
- # cooling coil
969
- cooling_coil = OpenStudio::Model::CoilCoolingDXTwoSpeed.new(model,
970
- model.alwaysOnDiscreteSchedule,
971
- clgCapFuncTempCurve,
972
- clgCapFuncFlowFracCurve,
973
- clgEirFuncTempCurve,
974
- clgEirFuncFlowFracCurve,
975
- clgPlrCurve,
976
- clgCapFuncTempCurve,
977
- clgEirFuncTempCurve)
978
- cooling_coil.setRatedHighSpeedCOP(parameters['doasDXEER'] / 3.412)
979
- cooling_coil.setRatedLowSpeedCOP(parameters['doasDXEER'] / 3.412)
980
- air_loop_comps << cooling_coil
981
- end
982
- unless options['zoneHVAC'] == 'DualDuct'
983
- # create controller outdoor air
984
- controller_OA = OpenStudio::Model::ControllerOutdoorAir.new(model)
985
- controller_OA.autosizeMinimumOutdoorAirFlowRate
986
- controller_OA.autosizeMaximumOutdoorAirFlowRate
987
- # create ventilation schedules and assign to OA controller
988
- if options['primaryHVAC']['doas']
989
- controller_OA.setMinimumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule)
990
- controller_OA.setMaximumFractionofOutdoorAirSchedule(model.alwaysOnDiscreteSchedule)
991
- else
992
- # multizone VAV that ventilates
993
- controller_OA.setMaximumFractionofOutdoorAirSchedule(options['ventilation_schedule'])
994
- controller_OA.setEconomizerControlType('DifferentialEnthalpy')
995
- # add night cycling (ML would people actually do this for a VAV system?))
996
- airloop_primary.setNightCycleControlType('CycleOnAny') # ML Does this work with variable speed fans?
997
- end
998
- controller_OA.setHeatRecoveryBypassControlType('BypassWhenOAFlowGreaterThanMinimum')
999
- # create outdoor air system
1000
- system_OA = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, controller_OA)
1001
- air_loop_comps << system_OA
1002
- # create Evaporative cooler
1003
- unless parameters['doasEvap'] == 'none'
1004
- evap_cooler = OpenStudio::Model::EvaporativeCoolerDirectResearchSpecial.new(model, model.alwaysOnDiscreteSchedule)
1005
- evap_cooler.setCoolerEffectiveness(0.85)
1006
- end
1007
- # create ERV
1008
- unless parameters['doasERV'] == 'none'
1009
- heat_exchanger = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model)
1010
- heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1011
- if parameters['doasERV'] == 'rotary wheel w/o economizer lockout'
1012
- sensible_eff = 0.75
1013
- latent_eff = 0.69
1014
- # heat_exchanger.setEconomizerLockout(false)
1015
- heat_exchanger.setString(23, 'No')
1016
- elsif parameters['doasERV'] == 'rotary wheel w/ economizer lockout'
1017
- sensible_eff = 0.75
1018
- latent_eff = 0.69
1019
- # heat_exchanger.setEconomizerLockout(true)
1020
- heat_exchanger.setString(23, 'Yes')
1021
- elsif parameters['doasERV'] == 'plate w/o economizer lockout'
1022
- sensible_eff = 0.52
1023
- latent_eff = 0.50
1024
- # heat_exchanger.setEconomizerLockout(false)
1025
- heat_exchanger.setString(23, 'No')
1026
- elsif parameters['doasERV'] == 'plate w/ economizer lockout'
1027
- sensible_eff = 0.52
1028
- latent_eff = 0.50
1029
- # heat_exchanger.setEconomizerLockout(true)
1030
- heat_exchanger.setString(23, 'Yes')
1031
- end
1032
- heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(sensible_eff)
1033
- heat_exchanger.setSensibleEffectivenessat100HeatingAirFlow(sensible_eff)
1034
- heat_exchanger.setSensibleEffectivenessat75CoolingAirFlow(sensible_eff)
1035
- heat_exchanger.setSensibleEffectivenessat75HeatingAirFlow(sensible_eff)
1036
- heat_exchanger.setLatentEffectivenessat100CoolingAirFlow(latent_eff)
1037
- heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(latent_eff)
1038
- heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(latent_eff)
1039
- heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(latent_eff)
1040
- heat_exchanger.setFrostControlType('ExhaustOnly')
1041
- heat_exchanger.setThresholdTemperature(-12.2)
1042
- heat_exchanger.setInitialDefrostTimeFraction(0.1670)
1043
- heat_exchanger.setRateofDefrostTimeFractionIncrease(0.0240)
1044
- end
1045
-
1046
- end
1047
- # create scheduled setpoint manager for airloop
1048
- if options['primaryHVAC']['doas'] || (options['zoneHVAC'] == 'DualDuct')
1049
- # DOAS or VAV for cooling and not ventilation
1050
- setpoint_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, options['primary_sat_schedule'])
1051
- else
1052
- # VAV for cooling and ventilation
1053
- setpoint_manager = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model)
1054
- setpoint_manager.setSetpointatOutdoorLowTemperature(15.6)
1055
- setpoint_manager.setOutdoorLowTemperature(14.4)
1056
- setpoint_manager.setSetpointatOutdoorHighTemperature(12.8)
1057
- setpoint_manager.setOutdoorHighTemperature(21.1)
1058
- end
1059
- # connect components to airloop
1060
- # find the supply inlet node of the airloop
1061
- airloop_supply_inlet = airloop_primary.supplyInletNode
1062
- # add the components to the airloop
1063
- air_loop_comps.each do |comp|
1064
- comp.addToNode(airloop_supply_inlet)
1065
- if comp.to_CoilHeatingWater.is_initialized
1066
- options['hot_water_plant'].addDemandBranchForComponent(comp)
1067
- comp.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1068
- elsif comp.to_CoilCoolingWater.is_initialized
1069
- options['chilled_water_plant'].addDemandBranchForComponent(comp)
1070
- comp.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1071
- end
1072
- end
1073
- unless (options['zoneHVAC'] == 'DualDuct') || (parameters['doasERV'] == 'none')
1074
- heat_exchanger.addToNode(system_OA.outboardOANode.get)
1075
- end
1076
-
1077
- unless parameters['doasEvap'] == 'none'
1078
- if parameters['doasERV'] == 'none'
1079
- evap_cooler.addToNode(system_OA.outboardOANode.get)
1080
- else
1081
- hxPrimary_outlet_node = heat_exchanger.primaryAirOutletModelObject.get.to_Node.get
1082
- evap_cooler.addToNode(hxPrimary_outlet_node)
1083
- end
1084
- end
1085
-
1086
- # add setpoint manager to supply equipment outlet node
1087
- setpoint_manager.addToNode(airloop_primary.supplyOutletNode)
1088
- # add thermal zones to airloop
1089
- thermalZonesToAdd.each do |zone|
1090
- # make an air terminal for the zone
1091
- if options['primaryHVAC']['fan'] == 'Variable'
1092
- air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule)
1093
- else
1094
- air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
1095
- end
1096
- # attach new terminal to the zone and to the airloop
1097
- airloop_primary.addBranchForZone(zone, air_terminal.to_StraightComponent)
1098
- end
1099
- primary_airloops << airloop_primary
1100
- end
1101
- end
1102
-
1103
- # pass back primary airloops
1104
- result = primary_airloops
1105
- return result
1106
- end # end of def
1107
-
1108
- def self.createSecondaryAirLoops(model, runner, options)
1109
- secondary_airloops = []
1110
- # create secondary airloop for each secondary zone
1111
- model.getThermalZones.each do |zone|
1112
- if options['zonesSecondary'].include? zone
1113
- # create secondary airloop
1114
- airloop_secondary = OpenStudio::Model::AirLoopHVAC.new(model)
1115
- airloop_secondary.setName("New Air Loop HVAC #{zone.name}")
1116
- # modify system sizing properties
1117
- sizing_system = airloop_secondary.sizingSystem
1118
- # set central heating and cooling temperatures for sizing
1119
- sizing_system.setCentralCoolingDesignSupplyAirTemperature(12.8)
1120
- sizing_system.setCentralHeatingDesignSupplyAirTemperature(40) # ML OS default is 16.7
1121
- # load specification
1122
- sizing_system.setSystemOutdoorAirMethod('VentilationRateProcedure') # ML OS default is ZoneSum
1123
- sizing_system.setTypeofLoadtoSizeOn('Sensible') # PSZ
1124
- sizing_system.setAllOutdoorAirinCooling(false) # PSZ
1125
- sizing_system.setAllOutdoorAirinHeating(false) # PSZ
1126
- sizing_system.setMinimumSystemAirFlowRatio(1.0) # Constant volume fan
1127
- air_loop_comps = []
1128
- # set availability schedule (HVAC operation schedule)
1129
- airloop_secondary.setAvailabilitySchedule(options['hvac_schedule'])
1130
- if options['secondaryHVAC']['fan'] == 'Variable'
1131
- # create variable speed fan and set system sizing accordingly
1132
- sizing_system.setMinimumSystemAirFlowRatio(0.3) # DCV
1133
- # variable speed fan
1134
- fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule)
1135
- fan.setFanEfficiency(0.69)
1136
- fan.setPressureRise(1125) # Pa
1137
- fan.autosizeMaximumFlowRate
1138
- fan.setFanPowerMinimumFlowFraction(0.6)
1139
- fan.setMotorEfficiency(0.9)
1140
- fan.setMotorInAirstreamFraction(1.0)
1141
- air_loop_comps << fan
1142
- else
1143
- sizing_system.setMinimumSystemAirFlowRatio(1.0) # No DCV
1144
- # constant speed fan
1145
- fan = OpenStudio::Model::FanConstantVolume.new(model, model.alwaysOnDiscreteSchedule)
1146
- fan.setFanEfficiency(0.6)
1147
- fan.setPressureRise(500) # Pa
1148
- fan.autosizeMaximumFlowRate
1149
- fan.setMotorEfficiency(0.9)
1150
- fan.setMotorInAirstreamFraction(1.0)
1151
- air_loop_comps << fan
1152
- end
1153
- # create cooling coil
1154
- if options['secondaryHVAC']['cool'] == 'Water'
1155
- # water coil
1156
- cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule)
1157
- air_loop_comps << cooling_coil
1158
- elsif options['secondaryHVAC']['cool'] == 'SingleDX'
1159
- # single speed DX coil
1160
- # create cooling coil
1161
- # create clgCapFuncTempCurve
1162
- clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
1163
- clgCapFuncTempCurve.setCoefficient1Constant(0.42415)
1164
- clgCapFuncTempCurve.setCoefficient2x(0.04426)
1165
- clgCapFuncTempCurve.setCoefficient3xPOW2(-0.00042)
1166
- clgCapFuncTempCurve.setCoefficient4y(0.00333)
1167
- clgCapFuncTempCurve.setCoefficient5yPOW2(-0.00008)
1168
- clgCapFuncTempCurve.setCoefficient6xTIMESY(-0.00021)
1169
- clgCapFuncTempCurve.setMinimumValueofx(17)
1170
- clgCapFuncTempCurve.setMaximumValueofx(22)
1171
- clgCapFuncTempCurve.setMinimumValueofy(13)
1172
- clgCapFuncTempCurve.setMaximumValueofy(46)
1173
- # create clgCapFuncFlowFracCurve
1174
- clgCapFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
1175
- clgCapFuncFlowFracCurve.setCoefficient1Constant(0.77136)
1176
- clgCapFuncFlowFracCurve.setCoefficient2x(0.34053)
1177
- clgCapFuncFlowFracCurve.setCoefficient3xPOW2(-0.11088)
1178
- clgCapFuncFlowFracCurve.setMinimumValueofx(0.75918)
1179
- clgCapFuncFlowFracCurve.setMaximumValueofx(1.13877)
1180
- # create clgEirFuncTempCurve
1181
- clgEirFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
1182
- clgEirFuncTempCurve.setCoefficient1Constant(1.23649)
1183
- clgEirFuncTempCurve.setCoefficient2x(-0.02431)
1184
- clgEirFuncTempCurve.setCoefficient3xPOW2(0.00057)
1185
- clgEirFuncTempCurve.setCoefficient4y(-0.01434)
1186
- clgEirFuncTempCurve.setCoefficient5yPOW2(0.00063)
1187
- clgEirFuncTempCurve.setCoefficient6xTIMESY(-0.00038)
1188
- clgEirFuncTempCurve.setMinimumValueofx(17)
1189
- clgEirFuncTempCurve.setMaximumValueofx(22)
1190
- clgEirFuncTempCurve.setMinimumValueofy(13)
1191
- clgEirFuncTempCurve.setMaximumValueofy(46)
1192
- # create clgEirFuncFlowFracCurve
1193
- clgEirFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
1194
- clgEirFuncFlowFracCurve.setCoefficient1Constant(1.20550)
1195
- clgEirFuncFlowFracCurve.setCoefficient2x(-0.32953)
1196
- clgEirFuncFlowFracCurve.setCoefficient3xPOW2(0.12308)
1197
- clgEirFuncFlowFracCurve.setMinimumValueofx(0.75918)
1198
- clgEirFuncFlowFracCurve.setMaximumValueofx(1.13877)
1199
- # create clgPlrCurve
1200
- clgPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
1201
- clgPlrCurve.setCoefficient1Constant(0.77100)
1202
- clgPlrCurve.setCoefficient2x(0.22900)
1203
- clgPlrCurve.setCoefficient3xPOW2(0.0)
1204
- clgPlrCurve.setMinimumValueofx(0.0)
1205
- clgPlrCurve.setMaximumValueofx(1.0)
1206
- # cooling coil
1207
- cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model,
1208
- model.alwaysOnDiscreteSchedule,
1209
- clgCapFuncTempCurve,
1210
- clgCapFuncFlowFracCurve,
1211
- clgEirFuncTempCurve,
1212
- clgEirFuncFlowFracCurve,
1213
- clgPlrCurve)
1214
- cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(4))
1215
- air_loop_comps << cooling_coil
1216
- else
1217
- # two speed DX coil (PNNL curves)
1218
- # create cooling coil
1219
- # create clgCapFuncTempCurve
1220
- clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
1221
- clgCapFuncTempCurve.setCoefficient1Constant(1.39072)
1222
- clgCapFuncTempCurve.setCoefficient2x(-0.0529058)
1223
- clgCapFuncTempCurve.setCoefficient3xPOW2(0.0018423)
1224
- clgCapFuncTempCurve.setCoefficient4y(0.00058267)
1225
- clgCapFuncTempCurve.setCoefficient5yPOW2(-0.000186814)
1226
- clgCapFuncTempCurve.setCoefficient6xTIMESY(0.000265159)
1227
- clgCapFuncTempCurve.setMinimumValueofx(16.5556)
1228
- clgCapFuncTempCurve.setMaximumValueofx(22.1111)
1229
- clgCapFuncTempCurve.setMinimumValueofy(23.7778)
1230
- clgCapFuncTempCurve.setMaximumValueofy(47.66)
1231
- # create clgCapFuncFlowFracCurve
1232
- clgCapFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
1233
- clgCapFuncFlowFracCurve.setCoefficient1Constant(0.718954)
1234
- clgCapFuncFlowFracCurve.setCoefficient2x(0.435436)
1235
- clgCapFuncFlowFracCurve.setCoefficient3xPOW2(-0.154193)
1236
- clgCapFuncFlowFracCurve.setMinimumValueofx(0.75)
1237
- clgCapFuncFlowFracCurve.setMaximumValueofx(1.25)
1238
- # create clgEirFuncTempCurve
1239
- clgEirFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
1240
- clgEirFuncTempCurve.setCoefficient1Constant(-0.536161)
1241
- clgEirFuncTempCurve.setCoefficient2x(0.105138)
1242
- clgEirFuncTempCurve.setCoefficient3xPOW2(-0.00172659)
1243
- clgEirFuncTempCurve.setCoefficient4y(0.0149848)
1244
- clgEirFuncTempCurve.setCoefficient5yPOW2(0.000659948)
1245
- clgEirFuncTempCurve.setCoefficient6xTIMESY(-0.0017385)
1246
- clgEirFuncTempCurve.setMinimumValueofx(16.5556)
1247
- clgEirFuncTempCurve.setMaximumValueofx(22.1111)
1248
- clgEirFuncTempCurve.setMinimumValueofy(23.7778)
1249
- clgEirFuncTempCurve.setMaximumValueofy(47.66)
1250
- # create clgEirFuncFlowFracCurve
1251
- clgEirFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
1252
- clgEirFuncFlowFracCurve.setCoefficient1Constant(1.19525)
1253
- clgEirFuncFlowFracCurve.setCoefficient2x(-0.306138)
1254
- clgEirFuncFlowFracCurve.setCoefficient3xPOW2(0.110973)
1255
- clgEirFuncFlowFracCurve.setMinimumValueofx(0.75)
1256
- clgEirFuncFlowFracCurve.setMaximumValueofx(1.25)
1257
- # create clgPlrCurve
1258
- clgPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
1259
- clgPlrCurve.setCoefficient1Constant(0.77100)
1260
- clgPlrCurve.setCoefficient2x(0.22900)
1261
- clgPlrCurve.setCoefficient3xPOW2(0.0)
1262
- clgPlrCurve.setMinimumValueofx(0.0)
1263
- clgPlrCurve.setMaximumValueofx(1.0)
1264
- # cooling coil
1265
- cooling_coil = OpenStudio::Model::CoilCoolingDXTwoSpeed.new(model,
1266
- model.alwaysOnDiscreteSchedule,
1267
- clgCapFuncTempCurve,
1268
- clgCapFuncFlowFracCurve,
1269
- clgEirFuncTempCurve,
1270
- clgEirFuncFlowFracCurve,
1271
- clgPlrCurve,
1272
- clgCapFuncTempCurve,
1273
- clgEirFuncTempCurve)
1274
- cooling_coil.setRatedHighSpeedCOP(4)
1275
- cooling_coil.setRatedLowSpeedCOP(4)
1276
- air_loop_comps << cooling_coil
1277
- end
1278
- if options['secondaryHVAC']['heat'] == 'Water'
1279
- # water coil
1280
- heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule)
1281
- air_loop_comps << heating_coil
1282
- else
1283
- # gas coil
1284
- heating_coil = OpenStudio::Model::CoilHeatingGas.new(model, model.alwaysOnDiscreteSchedule)
1285
- air_loop_comps << heating_coil
1286
- end
1287
- # create controller outdoor air
1288
- controller_OA = OpenStudio::Model::ControllerOutdoorAir.new(model)
1289
- controller_OA.autosizeMinimumOutdoorAirFlowRate
1290
- controller_OA.autosizeMaximumOutdoorAirFlowRate
1291
- controller_OA.setEconomizerControlType('DifferentialEnthalpy')
1292
- controller_OA.setMaximumFractionofOutdoorAirSchedule(options['ventilation_schedule'])
1293
- controller_OA.setHeatRecoveryBypassControlType('BypassWhenOAFlowGreaterThanMinimum')
1294
- # create outdoor air system
1295
- system_OA = OpenStudio::Model::AirLoopHVACOutdoorAirSystem.new(model, controller_OA)
1296
- air_loop_comps << system_OA
1297
- # create ERV
1298
- heat_exchanger = OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent.new(model)
1299
- heat_exchanger.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
1300
- sensible_eff = 0.75
1301
- latent_eff = 0.69
1302
- heat_exchanger.setSensibleEffectivenessat100CoolingAirFlow(sensible_eff)
1303
- heat_exchanger.setSensibleEffectivenessat100HeatingAirFlow(sensible_eff)
1304
- heat_exchanger.setSensibleEffectivenessat75CoolingAirFlow(sensible_eff)
1305
- heat_exchanger.setSensibleEffectivenessat75HeatingAirFlow(sensible_eff)
1306
- heat_exchanger.setLatentEffectivenessat100CoolingAirFlow(latent_eff)
1307
- heat_exchanger.setLatentEffectivenessat100HeatingAirFlow(latent_eff)
1308
- heat_exchanger.setLatentEffectivenessat75CoolingAirFlow(latent_eff)
1309
- heat_exchanger.setLatentEffectivenessat75HeatingAirFlow(latent_eff)
1310
- heat_exchanger.setFrostControlType('ExhaustOnly')
1311
- heat_exchanger.setThresholdTemperature(-12.2)
1312
- heat_exchanger.setInitialDefrostTimeFraction(0.1670)
1313
- heat_exchanger.setRateofDefrostTimeFractionIncrease(0.0240)
1314
- heat_exchanger.setEconomizerLockout(false)
1315
- # create setpoint manager for airloop
1316
- setpoint_manager = OpenStudio::Model::SetpointManagerSingleZoneReheat.new(model)
1317
- setpoint_manager.setMinimumSupplyAirTemperature(10)
1318
- setpoint_manager.setMaximumSupplyAirTemperature(50)
1319
- setpoint_manager.setControlZone(zone)
1320
- # connect components to airloop
1321
- # find the supply inlet node of the airloop
1322
- airloop_supply_inlet = airloop_secondary.supplyInletNode
1323
- # add the components to the airloop
1324
- air_loop_comps.each do |comp|
1325
- comp.addToNode(airloop_supply_inlet)
1326
- if comp.to_CoilHeatingWater.is_initialized
1327
- options['hot_water_plant'].addDemandBranchForComponent(comp)
1328
- comp.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1329
- elsif comp.to_CoilCoolingWater.is_initialized
1330
- options['chilled_water_plant'].addDemandBranchForComponent(comp)
1331
- comp.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1332
- end
1333
- end
1334
- # add erv to outdoor air system
1335
- heat_exchanger.addToNode(system_OA.outboardOANode.get)
1336
- # add setpoint manager to supply equipment outlet node
1337
- setpoint_manager.addToNode(airloop_secondary.supplyOutletNode)
1338
- # add thermal zone to airloop
1339
- if options['secondaryHVAC']['fan'] == 'Variable'
1340
- air_terminal = OpenStudio::Model::AirTerminalSingleDuctVAVNoReheat.new(model, model.alwaysOnDiscreteSchedule)
1341
- else
1342
- air_terminal = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
1343
- end
1344
- # attach new terminal to the zone and to the airloop
1345
- airloop_secondary.addBranchForZone(zone, air_terminal.to_StraightComponent)
1346
- # add night cycling
1347
- airloop_secondary.setNightCycleControlType('CycleOnAny') # ML Does this work with variable speed fans?
1348
- secondary_airloops << airloop_secondary
1349
- end
1350
- end
1351
-
1352
- # pass back secondary airloops
1353
- result = secondary_airloops
1354
- return result
1355
- end # end of def
1356
-
1357
- def self.createPrimaryZoneEquipment(model, runner, options, parameters)
1358
- model.getThermalZones.each do |zone|
1359
- if options['zonesPrimary'].include? zone
1360
- if options['zoneHVAC'] == 'FanCoil'
1361
- # create fan coil
1362
- # create fan
1363
- fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
1364
- fan.setFanEfficiency(0.5)
1365
- fan.setPressureRise(75) # Pa
1366
- fan.autosizeMaximumFlowRate
1367
- fan.setMotorEfficiency(0.9)
1368
- fan.setMotorInAirstreamFraction(1.0)
1369
- # create cooling coil and connect to chilled water plant
1370
- cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule)
1371
- options['chilled_water_plant'].addDemandBranchForComponent(cooling_coil)
1372
- cooling_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1373
- # create heating coil and connect to hot water plant
1374
- heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule)
1375
- options['hot_water_plant'].addDemandBranchForComponent(heating_coil)
1376
- heating_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1377
- # construct fan coil
1378
- fan_coil = OpenStudio::Model::ZoneHVACFourPipeFanCoil.new(model,
1379
- model.alwaysOnDiscreteSchedule,
1380
- fan,
1381
- cooling_coil,
1382
- heating_coil)
1383
- fan_coil.setMaximumOutdoorAirFlowRate(0)
1384
- # add fan coil to thermal zone
1385
- fan_coil.addToThermalZone(zone)
1386
- elsif (options['zoneHVAC'] == 'WSHP') || (options['zoneHVAC'] == 'GSHP')
1387
- # create water source heat pump and attach to heat pump loop
1388
- # create fan
1389
- fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
1390
- fan.setFanEfficiency(0.75)
1391
- fan_eff = fan.fanEfficiency
1392
- fan.setMotorEfficiency(0.9)
1393
- motor_eff = fan.motorEfficiency
1394
- fan.autosizeMaximumFlowRate
1395
- if parameters['gshpFanType'] == 'PSC' # use 0.3W/cfm, ECM - 0.2W/cfm
1396
- watt_per_cfm = 0.30 # W/cfm
1397
- else
1398
- watt_per_cfm = 0.20 # W/cfm
1399
- end
1400
- pres_rise = OpenStudio.convert(watt_per_cfm * fan_eff * motor_eff / 0.1175, 'inH_{2}O', 'Pa').get
1401
- fan.setPressureRise(pres_rise) # Pa
1402
- fan.setMotorInAirstreamFraction(1.0)
1403
- # create cooling coil and connect to heat pump loop
1404
- cooling_coil = OpenStudio::Model::CoilCoolingWaterToAirHeatPumpEquationFit.new(model)
1405
- cooling_coil.setRatedCoolingCoefficientofPerformance(parameters['gshpCoolingEER'] / 3.412) # xf 061014: need to change per fan power and pump power adjustment
1406
- cooling_coil.setRatedCoolingCoefficientofPerformance(6.45)
1407
- cooling_coil.setTotalCoolingCapacityCoefficient1(-9.149069561)
1408
- cooling_coil.setTotalCoolingCapacityCoefficient2(10.87814026)
1409
- cooling_coil.setTotalCoolingCapacityCoefficient3(-1.718780157)
1410
- cooling_coil.setTotalCoolingCapacityCoefficient4(0.746414818)
1411
- cooling_coil.setTotalCoolingCapacityCoefficient5(0.0)
1412
- cooling_coil.setSensibleCoolingCapacityCoefficient1(-5.462690012)
1413
- cooling_coil.setSensibleCoolingCapacityCoefficient2(17.95968138)
1414
- cooling_coil.setSensibleCoolingCapacityCoefficient3(-11.87818402)
1415
- cooling_coil.setSensibleCoolingCapacityCoefficient4(-0.980163419)
1416
- cooling_coil.setSensibleCoolingCapacityCoefficient5(0.767285761)
1417
- cooling_coil.setSensibleCoolingCapacityCoefficient6(0.0)
1418
- cooling_coil.setCoolingPowerConsumptionCoefficient1(-3.205409884)
1419
- cooling_coil.setCoolingPowerConsumptionCoefficient2(-0.976409399)
1420
- cooling_coil.setCoolingPowerConsumptionCoefficient3(3.97892546)
1421
- cooling_coil.setCoolingPowerConsumptionCoefficient4(0.938181818)
1422
- cooling_coil.setCoolingPowerConsumptionCoefficient5(0.0)
1423
- options['heat_pump_loop'].addDemandBranchForComponent(cooling_coil)
1424
- # create heating coil and connect to heat pump loop
1425
- heating_coil = OpenStudio::Model::CoilHeatingWaterToAirHeatPumpEquationFit.new(model)
1426
- heating_coil.setRatedHeatingCoefficientofPerformance(parameters['gshpHeatingCOP']) # xf 061014: need to change per fan power and pump power adjustment
1427
- heating_coil.setRatedHeatingCoefficientofPerformance(4.0)
1428
- heating_coil.setHeatingCapacityCoefficient1(-1.361311959)
1429
- heating_coil.setHeatingCapacityCoefficient2(-2.471798046)
1430
- heating_coil.setHeatingCapacityCoefficient3(4.173164514)
1431
- heating_coil.setHeatingCapacityCoefficient4(0.640757401)
1432
- heating_coil.setHeatingCapacityCoefficient5(0.0)
1433
- heating_coil.setHeatingPowerConsumptionCoefficient1(-2.176941116)
1434
- heating_coil.setHeatingPowerConsumptionCoefficient2(0.832114286)
1435
- heating_coil.setHeatingPowerConsumptionCoefficient3(1.570743399)
1436
- heating_coil.setHeatingPowerConsumptionCoefficient4(0.690793651)
1437
- heating_coil.setHeatingPowerConsumptionCoefficient5(0.0)
1438
- options['heat_pump_loop'].addDemandBranchForComponent(heating_coil)
1439
- # create supplemental heating coil
1440
- supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule)
1441
- # construct heat pump
1442
- heat_pump = OpenStudio::Model::ZoneHVACWaterToAirHeatPump.new(model,
1443
- model.alwaysOnDiscreteSchedule,
1444
- fan,
1445
- heating_coil,
1446
- cooling_coil,
1447
- supplemental_heating_coil)
1448
- heat_pump.setSupplyAirFlowRateWhenNoCoolingorHeatingisNeeded(OpenStudio::OptionalDouble.new(0))
1449
- heat_pump.setOutdoorAirFlowRateDuringCoolingOperation(OpenStudio::OptionalDouble.new(0))
1450
- heat_pump.setOutdoorAirFlowRateDuringHeatingOperation(OpenStudio::OptionalDouble.new(0))
1451
- heat_pump.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(OpenStudio::OptionalDouble.new(0))
1452
- # add heat pump to thermal zone
1453
- heat_pump.addToThermalZone(zone)
1454
- elsif options['zoneHVAC'] == 'ASHP'
1455
- # create air source heat pump
1456
- # create fan
1457
- fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
1458
- fan.setFanEfficiency(0.5)
1459
- fan.setPressureRise(75) # Pa
1460
- fan.autosizeMaximumFlowRate
1461
- fan.setMotorEfficiency(0.9)
1462
- fan.setMotorInAirstreamFraction(1.0)
1463
- # create heating coil
1464
- # create htgCapFuncTempCurve
1465
- htgCapFuncTempCurve = OpenStudio::Model::CurveCubic.new(model)
1466
- htgCapFuncTempCurve.setCoefficient1Constant(0.758746)
1467
- htgCapFuncTempCurve.setCoefficient2x(0.027626)
1468
- htgCapFuncTempCurve.setCoefficient3xPOW2(0.000148716)
1469
- htgCapFuncTempCurve.setCoefficient4xPOW3(0.0000034992)
1470
- htgCapFuncTempCurve.setMinimumValueofx(-20)
1471
- htgCapFuncTempCurve.setMaximumValueofx(20)
1472
- # create htgCapFuncFlowFracCurve
1473
- htgCapFuncFlowFracCurve = OpenStudio::Model::CurveCubic.new(model)
1474
- htgCapFuncFlowFracCurve.setCoefficient1Constant(0.84)
1475
- htgCapFuncFlowFracCurve.setCoefficient2x(0.16)
1476
- htgCapFuncFlowFracCurve.setCoefficient3xPOW2(0)
1477
- htgCapFuncFlowFracCurve.setCoefficient4xPOW3(0)
1478
- htgCapFuncFlowFracCurve.setMinimumValueofx(0.5)
1479
- htgCapFuncFlowFracCurve.setMaximumValueofx(1.5)
1480
- # create htgEirFuncTempCurve
1481
- htgEirFuncTempCurve = OpenStudio::Model::CurveCubic.new(model)
1482
- htgEirFuncTempCurve.setCoefficient1Constant(1.19248)
1483
- htgEirFuncTempCurve.setCoefficient2x(-0.0300438)
1484
- htgEirFuncTempCurve.setCoefficient3xPOW2(0.00103745)
1485
- htgEirFuncTempCurve.setCoefficient4xPOW3(-0.000023328)
1486
- htgEirFuncTempCurve.setMinimumValueofx(-20)
1487
- htgEirFuncTempCurve.setMaximumValueofx(20)
1488
- # create htgEirFuncFlowFracCurve
1489
- htgEirFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
1490
- htgEirFuncFlowFracCurve.setCoefficient1Constant(1.3824)
1491
- htgEirFuncFlowFracCurve.setCoefficient2x(-0.4336)
1492
- htgEirFuncFlowFracCurve.setCoefficient3xPOW2(0.0512)
1493
- htgEirFuncFlowFracCurve.setMinimumValueofx(0)
1494
- htgEirFuncFlowFracCurve.setMaximumValueofx(1)
1495
- # create htgPlrCurve
1496
- htgPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
1497
- htgPlrCurve.setCoefficient1Constant(0.75)
1498
- htgPlrCurve.setCoefficient2x(0.25)
1499
- htgPlrCurve.setCoefficient3xPOW2(0.0)
1500
- htgPlrCurve.setMinimumValueofx(0.0)
1501
- htgPlrCurve.setMaximumValueofx(1.0)
1502
- # heating coil
1503
- heating_coil = OpenStudio::Model::CoilHeatingDXSingleSpeed.new(model,
1504
- model.alwaysOnDiscreteSchedule,
1505
- htgCapFuncTempCurve,
1506
- htgCapFuncFlowFracCurve,
1507
- htgEirFuncTempCurve,
1508
- htgEirFuncFlowFracCurve,
1509
- htgPlrCurve)
1510
- heating_coil.setRatedCOP(3.4)
1511
- heating_coil.setCrankcaseHeaterCapacity(200)
1512
- heating_coil.setMaximumOutdoorDryBulbTemperatureforCrankcaseHeaterOperation(8)
1513
- heating_coil.autosizeResistiveDefrostHeaterCapacity
1514
- # create cooling coil
1515
- # create clgCapFuncTempCurve
1516
- clgCapFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
1517
- clgCapFuncTempCurve.setCoefficient1Constant(0.942587793)
1518
- clgCapFuncTempCurve.setCoefficient2x(0.009543347)
1519
- clgCapFuncTempCurve.setCoefficient3xPOW2(0.0018423)
1520
- clgCapFuncTempCurve.setCoefficient4y(-0.011042676)
1521
- clgCapFuncTempCurve.setCoefficient5yPOW2(0.000005249)
1522
- clgCapFuncTempCurve.setCoefficient6xTIMESY(-0.000009720)
1523
- clgCapFuncTempCurve.setMinimumValueofx(17)
1524
- clgCapFuncTempCurve.setMaximumValueofx(22)
1525
- clgCapFuncTempCurve.setMinimumValueofy(13)
1526
- clgCapFuncTempCurve.setMaximumValueofy(46)
1527
- # create clgCapFuncFlowFracCurve
1528
- clgCapFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
1529
- clgCapFuncFlowFracCurve.setCoefficient1Constant(0.718954)
1530
- clgCapFuncFlowFracCurve.setCoefficient2x(0.435436)
1531
- clgCapFuncFlowFracCurve.setCoefficient3xPOW2(-0.154193)
1532
- clgCapFuncFlowFracCurve.setMinimumValueofx(0.75)
1533
- clgCapFuncFlowFracCurve.setMaximumValueofx(1.25)
1534
- # create clgEirFuncTempCurve
1535
- clgEirFuncTempCurve = OpenStudio::Model::CurveBiquadratic.new(model)
1536
- clgEirFuncTempCurve.setCoefficient1Constant(0.342414409)
1537
- clgEirFuncTempCurve.setCoefficient2x(0.034885008)
1538
- clgEirFuncTempCurve.setCoefficient3xPOW2(-0.000623700)
1539
- clgEirFuncTempCurve.setCoefficient4y(0.004977216)
1540
- clgEirFuncTempCurve.setCoefficient5yPOW2(0.000437951)
1541
- clgEirFuncTempCurve.setCoefficient6xTIMESY(-0.000728028)
1542
- clgEirFuncTempCurve.setMinimumValueofx(17)
1543
- clgEirFuncTempCurve.setMaximumValueofx(22)
1544
- clgEirFuncTempCurve.setMinimumValueofy(13)
1545
- clgEirFuncTempCurve.setMaximumValueofy(46)
1546
- # create clgEirFuncFlowFracCurve
1547
- clgEirFuncFlowFracCurve = OpenStudio::Model::CurveQuadratic.new(model)
1548
- clgEirFuncFlowFracCurve.setCoefficient1Constant(1.1552)
1549
- clgEirFuncFlowFracCurve.setCoefficient2x(-0.1808)
1550
- clgEirFuncFlowFracCurve.setCoefficient3xPOW2(0.0256)
1551
- clgEirFuncFlowFracCurve.setMinimumValueofx(0.5)
1552
- clgEirFuncFlowFracCurve.setMaximumValueofx(1.5)
1553
- # create clgPlrCurve
1554
- clgPlrCurve = OpenStudio::Model::CurveQuadratic.new(model)
1555
- clgPlrCurve.setCoefficient1Constant(0.75)
1556
- clgPlrCurve.setCoefficient2x(0.25)
1557
- clgPlrCurve.setCoefficient3xPOW2(0.0)
1558
- clgPlrCurve.setMinimumValueofx(0.0)
1559
- clgPlrCurve.setMaximumValueofx(1.0)
1560
- # cooling coil
1561
- cooling_coil = OpenStudio::Model::CoilCoolingDXSingleSpeed.new(model,
1562
- model.alwaysOnDiscreteSchedule,
1563
- clgCapFuncTempCurve,
1564
- clgCapFuncFlowFracCurve,
1565
- clgEirFuncTempCurve,
1566
- clgEirFuncFlowFracCurve,
1567
- clgPlrCurve)
1568
- cooling_coil.setRatedCOP(OpenStudio::OptionalDouble.new(4))
1569
- # create supplemental heating coil
1570
- supplemental_heating_coil = OpenStudio::Model::CoilHeatingElectric.new(model, model.alwaysOnDiscreteSchedule)
1571
- # construct heat pump
1572
- heat_pump = OpenStudio::Model::ZoneHVACPackagedTerminalHeatPump.new(model,
1573
- model.alwaysOnDiscreteSchedule,
1574
- fan,
1575
- heating_coil,
1576
- cooling_coil,
1577
- supplemental_heating_coil)
1578
- heat_pump.setSupplyAirFlowRateWhenNoCoolingorHeatingisNeeded(0)
1579
- heat_pump.setOutdoorAirFlowRateDuringCoolingOperation(0)
1580
- heat_pump.setOutdoorAirFlowRateDuringHeatingOperation(0)
1581
- heat_pump.setOutdoorAirFlowRateWhenNoCoolingorHeatingisNeeded(0)
1582
- # add heat pump to thermal zone
1583
- heat_pump.addToThermalZone(zone)
1584
- elsif options['zoneHVAC'] == 'Baseboard'
1585
- # create baseboard heater add add to thermal zone and hot water loop
1586
- baseboard_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model)
1587
- baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule, baseboard_coil)
1588
- baseboard_heater.addToThermalZone(zone)
1589
- options['hot_water_plant'].addDemandBranchForComponent(baseboard_coil)
1590
- elsif options['zoneHVAC'] == 'Radiant'
1591
- # create low temperature radiant object and add to thermal zone and radiant plant loops
1592
- # create hot water coil and attach to radiant hot water loop
1593
- heating_coil = OpenStudio::Model::CoilHeatingLowTempRadiantVarFlow.new(model, options['mean_radiant_heating_setpoint_schedule'])
1594
- options['radiant_hot_water_plant'].addDemandBranchForComponent(heating_coil)
1595
- # create chilled water coil and attach to radiant chilled water loop
1596
- cooling_coil = OpenStudio::Model::CoilCoolingLowTempRadiantVarFlow.new(model, options['mean_radiant_cooling_setpoint_schedule'])
1597
- options['radiant_chilled_water_plant'].addDemandBranchForComponent(cooling_coil)
1598
- low_temp_radiant = OpenStudio::Model::ZoneHVACLowTempRadiantVarFlow.new(model,
1599
- model.alwaysOnDiscreteSchedule,
1600
- heating_coil,
1601
- cooling_coil)
1602
- low_temp_radiant.setRadiantSurfaceType('Floors')
1603
- low_temp_radiant.setHydronicTubingInsideDiameter(0.012)
1604
- low_temp_radiant.setTemperatureControlType('MeanRadiantTemperature')
1605
- low_temp_radiant.addToThermalZone(zone)
1606
- # create radiant floor construction and substitute for existing floor (interior or exterior) constructions
1607
- # create materials for radiant floor construction
1608
- layers = []
1609
- # ignore layer below insulation, which will depend on boundary condition
1610
- layers << rigid_insulation_1in = OpenStudio::Model::StandardOpaqueMaterial.new(model, 'Rough', 0.0254, 0.02, 56.06, 1210)
1611
- layers << concrete_2in = OpenStudio::Model::StandardOpaqueMaterial.new(model, 'MediumRough', 0.0508, 2.31, 2322, 832)
1612
- layers << concrete_2in
1613
- # create radiant floor construction from materials
1614
- radiant_floor = OpenStudio::Model::ConstructionWithInternalSource.new(layers)
1615
- radiant_floor.setSourcePresentAfterLayerNumber(2)
1616
- radiant_floor.setSourcePresentAfterLayerNumber(2)
1617
- # assign radiant construction to zone floor
1618
- zone.spaces.each do |space|
1619
- space.surfaces.each do |surface|
1620
- if surface.surfaceType == 'Floor'
1621
- surface.setConstruction(radiant_floor)
1622
- end
1623
- end
1624
- end
1625
- elsif options['zoneHVAC'] == 'DualDuct'
1626
- # create baseboard heater add add to thermal zone and hot water loop
1627
- baseboard_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model)
1628
- baseboard_heater = OpenStudio::Model::ZoneHVACBaseboardConvectiveWater.new(model, model.alwaysOnDiscreteSchedule, baseboard_coil)
1629
- baseboard_heater.addToThermalZone(zone)
1630
- options['hot_water_plant'].addDemandBranchForComponent(baseboard_coil)
1631
- # create fan coil (to mimic functionality of DOAS)
1632
- # variable speed fan
1633
- fan = OpenStudio::Model::FanVariableVolume.new(model, model.alwaysOnDiscreteSchedule)
1634
- fan.setFanEfficiency(0.69)
1635
- fan.setPressureRise(75) # Pa #ML This number is a guess; zone equipment pretending to be a DOAS
1636
- fan.autosizeMaximumFlowRate
1637
- fan.setFanPowerMinimumFlowFraction(0.6)
1638
- fan.setMotorEfficiency(0.9)
1639
- fan.setMotorInAirstreamFraction(1.0)
1640
- # create chilled water coil and attach to chilled water loop
1641
- cooling_coil = OpenStudio::Model::CoilCoolingWater.new(model, model.alwaysOnDiscreteSchedule)
1642
- options['chilled_water_plant'].addDemandBranchForComponent(cooling_coil)
1643
- cooling_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1644
- # create hot water coil and attach to hot water loop
1645
- heating_coil = OpenStudio::Model::CoilHeatingWater.new(model, model.alwaysOnDiscreteSchedule)
1646
- options['hot_water_plant'].addDemandBranchForComponent(heating_coil)
1647
- heating_coil.controllerWaterCoil.get.setMinimumActuatedFlow(0)
1648
- # construct fan coil (DOAS) and attach to thermal zone
1649
- fan_coil_doas = OpenStudio::Model::ZoneHVACFourPipeFanCoil.new(model,
1650
- options['ventilation_schedule'],
1651
- fan,
1652
- cooling_coil,
1653
- heating_coil)
1654
- fan_coil_doas.setCapacityControlMethod('VariableFanVariableFlow')
1655
- fan_coil_doas.addToThermalZone(zone)
1656
- end
1657
- end
1658
- end
1659
- end # end of def
1660
-
1661
- def self.addDCV(model, runner, options)
1662
- options['primary_airloops']&.each do |airloop|
1663
- if options['allHVAC']['primary']['fan'] == 'Variable'
1664
- if airloop.airLoopHVACOutdoorAirSystem.is_initialized
1665
- controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation
1666
- controller_mv.setDemandControlledVentilation(true)
1667
- runner.registerInfo("Enabling demand control ventilation for #{airloop.name}")
1668
- end
1669
- end
1670
- end
1671
-
1672
- options['secondary_airloops']&.each do |airloop|
1673
- if options['allHVAC']['secondary']['fan'] == 'Variable'
1674
- if airloop.airLoopHVACOutdoorAirSystem.is_initialized
1675
- controller_mv = airloop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir.controllerMechanicalVentilation
1676
- controller_mv.setDemandControlledVentilation(true)
1677
- runner.registerInfo("Enabling demand control ventilation for #{airloop.name}")
1678
- end
1679
- end
1680
- end
1681
- end # end of def
1682
- end