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