Class: OpenStudio::Model::ThermalZone
- Inherits:
-
Object
- Object
- OpenStudio::Model::ThermalZone
- Defined in:
- lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb,
lib/openstudio-standards/standards/Standards.ThermalZone.rb
Overview
Reopen the OpenStudio class to add methods to apply standards to this object
Instance Method Summary collapse
-
#applySizingValues ⇒ Object
Takes the values calculated by the EnergyPlus sizing routines and puts them into this object model in place of the autosized fields.
-
#autosize ⇒ Object
Sets all auto-sizeable fields to autosize.
-
#autosizedCoolingDesignAirFlowRate ⇒ Object
returns the autosized cooling design air flow rate as an optional double.
-
#autosizedHeatingDesignAirFlowRate ⇒ Object
returns the autosized heating design air flow rate as an optional double.
-
#autosizedMaximumOutdoorAirFlowRate ⇒ Object
returns the autosized maximum outdoor air flow rate as an optional double.
-
#autosizedMinimumOutdoorAirFlowRate ⇒ Object
returns the autosized minimum outdoor air flow rate as an optional double.
-
#cooling_fuels ⇒ Object
Determine the zone cooling fuels, including any fuels used by zone equipment, reheat terminals, the air loops serving the zone, and any plant loops serving those air loops.
-
#coolingDesignLoad ⇒ Object
returns the calculated cooling design load as an optional double.
-
#get_net_area ⇒ Double
Determine the net area of the zone Loops on each space, and checks if part of total floor area or not If not part of total floor area, it is not added to the zone floor area Will multiply it by the ZONE MULTIPLIER as well!.
-
#get_occupancy_schedule(occupied_percentage_threshold = 0.05) ⇒ ScheduleRuleset
This method creates a schedule where the value is zero when the overall occupancy for 1 zone is below the specified threshold, and one when the overall occupancy is greater than or equal to the threshold.
-
#heating_fuels ⇒ Object
Determine the zone heating fuels, including any fuels used by zone equipment, reheat terminals, the air loops serving the zone, and any plant loops serving those air loops.
-
#heatingDesignLoad ⇒ Object
returns the calculated heating design load as an optional double.
-
#infer_system_type ⇒ String
Infers the baseline system type based on the equipment serving the zone and their heating/cooling fuels.
-
#is_fossil_hybrid_or_purchased_heat ⇒ Object
Determine if the thermal zone is a Fossil Fuel, Fossil/Electric Hybrid, and Purchased Heat zone.
-
#is_residential(standard) ⇒ Object
Determine if the thermal zone is residential based on the space type properties for the spaces in the zone.
-
#outdoor_airflow_rate ⇒ Double
Calculates the zone outdoor airflow requirement (Voz) based on the inputs in the DesignSpecification:OutdoorAir obects in all spaces in the zone.
-
#outdoor_airflow_rate_per_area ⇒ Double
Calculates the zone outdoor airflow requirement and divides by the zone area.
Instance Method Details
#applySizingValues ⇒ Object
Takes the values calculated by the EnergyPlus sizing routines and puts them into this object model in place of the autosized fields. Must have previously completed a run with sql output for this to work.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 13 def applySizingValues # In OpenStudio, the design OA flow rates are calculated by the # Controller:OutdoorAir object associated with this system. # Therefore, this property will be retrieved from that object's sizing values air_loop = self.airLoopHVAC if air_loop.airLoopHVACOutdoorAirSystem.is_initialized controller_oa = air_loop.airLoopHVACOutdoorAirSystem.get.getControllerOutdoorAir # get the max oa flow rate from the controller:outdoor air sizing maximum_outdoor_air_flow_rate = controller_oa.autosizedMaximumOutdoorAirFlowRate if maximum_outdoor_air_flow_rate.is_initialized self.setDesignOutdoorAirFlowRate(maximum_outdoor_air_flow_rate.get) # Set the OA flow method to "ZoneSum" to avoid severe errors # in the fully hard-sized model. self.setSystemOutdoorAirMethod("ZoneSum") end end end |
#autosize ⇒ Object
Sets all auto-sizeable fields to autosize
6 7 8 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 6 def autosize self.autosizeDesignOutdoorAirFlowRate end |
#autosizedCoolingDesignAirFlowRate ⇒ Object
returns the autosized cooling design air flow rate as an optional double
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 48 def autosizedCoolingDesignAirFlowRate result = OpenStudio::OptionalDouble.new name = self.name.get.upcase sql = self.model.sqlFile if sql.is_initialized sql = sql.get # In E+ 8.4, (OS 1.9.3 onward) the table name changed table_name = nil if self.model.version < OpenStudio::VersionString.new('1.9.3') table_name = 'Zone Cooling' else table_name = 'Zone Sensible Cooling' end query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='HVACSizingSummary' AND ReportForString='Entire Facility' AND TableName='#{table_name}' AND ColumnName='User Design Air Flow' AND RowName='#{name}' AND Units='m3/s'" val = sql.execAndReturnFirstDouble(query) if val.is_initialized result = OpenStudio::OptionalDouble.new(val.get) else #OpenStudio::logFree(OpenStudio::Warn, "openstudio.model.Model", "Data not found for query: #{query}") end else OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Model has no sql file containing results, cannot lookup data.') end return result end |
#autosizedHeatingDesignAirFlowRate ⇒ Object
returns the autosized heating design air flow rate as an optional double
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 93 def autosizedHeatingDesignAirFlowRate result = OpenStudio::OptionalDouble.new name = self.name.get.upcase sql = self.model.sqlFile if sql.is_initialized sql = sql.get # In E+ 8.4, (OS 1.9.3 onward) the table name changed table_name = nil if self.model.version < OpenStudio::VersionString.new('1.9.3') table_name = 'Zone Heating' else table_name = 'Zone Sensible Heating' end query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='HVACSizingSummary' AND ReportForString='Entire Facility' AND TableName='#{table_name}' AND ColumnName='User Design Air Flow' AND RowName='#{name}' AND Units='m3/s'" val = sql.execAndReturnFirstDouble(query) if val.is_initialized result = OpenStudio::OptionalDouble.new(val.get) else #OpenStudio::logFree(OpenStudio::Warn, "openstudio.model.Model", "Data not found for query: #{query}") end else OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Model has no sql file containing results, cannot lookup data.') end return result end |
#autosizedMaximumOutdoorAirFlowRate ⇒ Object
returns the autosized maximum outdoor air flow rate as an optional double
34 35 36 37 38 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 34 def autosizedMaximumOutdoorAirFlowRate return self.model.getAutosizedValue(self, 'Maximum Outdoor Air Flow Rate', 'm3/s') end |
#autosizedMinimumOutdoorAirFlowRate ⇒ Object
returns the autosized minimum outdoor air flow rate as an optional double
41 42 43 44 45 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 41 def autosizedMinimumOutdoorAirFlowRate return self.model.getAutosizedValue(self, 'Minimum Outdoor Air Flow Rate', 'm3/s') end |
#cooling_fuels ⇒ Object
Determine the zone cooling fuels, including any fuels used by zone equipment, reheat terminals, the air loops serving the zone, and any plant loops serving those air loops.
return [Array<String>] An array. Possible values are Electricity, NaturalGas, PropaneGas, FuelOil#1, FuelOil#2, Coal, Diesel, Gasoline, DistrictCooling, DistrictHeating, and SolarEnergy.
259 260 261 262 263 264 265 266 267 268 269 270 271 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 259 def cooling_fuels fuels = [] # Check the zone hvac cooling fuels fuels += self.model.zone_equipment_cooling_fuels(self) # Check the zone airloop cooling fuels fuels += self.model.zone_airloop_cooling_fuels(self) return fuels.uniq.sort end |
#coolingDesignLoad ⇒ Object
returns the calculated cooling design load as an optional double
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 138 def coolingDesignLoad result = OpenStudio::OptionalDouble.new name = self.name.get.upcase sql = self.model.sqlFile if sql.is_initialized sql = sql.get # In E+ 8.4, (OS 1.9.3 onward) the table name changed table_name = nil if self.model.version < OpenStudio::VersionString.new('1.9.3') table_name = 'Zone Cooling' else table_name = 'Zone Sensible Cooling' end query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='HVACSizingSummary' AND ReportForString='Entire Facility' AND TableName='#{table_name}' AND ColumnName='User Design Load per Area' AND RowName='#{name}' AND Units='W/m2'" val = sql.execAndReturnFirstDouble(query) if val.is_initialized result = OpenStudio::OptionalDouble.new(val.get) else #OpenStudio::logFree(OpenStudio::Warn, "openstudio.model.Model", "Data not found for query: #{query}") end else OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Model has no sql file containing results, cannot lookup data.') end return result end |
#get_net_area ⇒ Double
Determine the net area of the zone Loops on each space, and checks if part of total floor area or not If not part of total floor area, it is not added to the zone floor area Will multiply it by the ZONE MULTIPLIER as well!
411 412 413 414 415 416 417 418 419 420 421 422 |
# File 'lib/openstudio-standards/standards/Standards.ThermalZone.rb', line 411 def get_net_area area_m2 = 0 zone_mult = self.multiplier self.spaces.each do |space| # If space is not part of floor area, we don't add it next if !space.partofTotalFloorArea area_m2 += space.floorArea end return area_m2 * zone_mult end |
#get_occupancy_schedule(occupied_percentage_threshold = 0.05) ⇒ ScheduleRuleset
Speed up this method. Bottleneck is ScheduleRule.getDaySchedules
This method creates a schedule where the value is zero when the overall occupancy for 1 zone is below the specified threshold, and one when the overall occupancy is greater than or equal to the threshold. This method is designed to use the total number of people in the zone.
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
# File 'lib/openstudio-standards/standards/Standards.ThermalZone.rb', line 112 def get_occupancy_schedule(occupied_percentage_threshold = 0.05) # Get all the occupancy schedules in every space in the zone # Include people added via the SpaceType # in addition to people hard-assigned to the Space itself. occ_schedules_num_occ = {} max_occ_on_thermal_zone = 0 # Get the people objects self.spaces.each do |space| # From the space type if space.spaceType.is_initialized space.spaceType.get.people.each do |people| num_ppl_sch = people.numberofPeopleSchedule if num_ppl_sch.is_initialized num_ppl_sch = num_ppl_sch.get num_ppl_sch = num_ppl_sch.to_ScheduleRuleset next if num_ppl_sch.empty? # Skip non-ruleset schedules num_ppl_sch = num_ppl_sch.get num_ppl = people.getNumberOfPeople(space.floorArea) if occ_schedules_num_occ[num_ppl_sch].nil? occ_schedules_num_occ[num_ppl_sch] = num_ppl max_occ_on_thermal_zone += num_ppl else occ_schedules_num_occ[num_ppl_sch] += num_ppl max_occ_on_thermal_zone += num_ppl end end end end # From the space space.people.each do |people| num_ppl_sch = people.numberofPeopleSchedule if num_ppl_sch.is_initialized num_ppl_sch = num_ppl_sch.get num_ppl_sch = num_ppl_sch.to_ScheduleRuleset next if num_ppl_sch.empty? # Skip non-ruleset schedules num_ppl_sch = num_ppl_sch.get num_ppl = people.getNumberOfPeople(space.floorArea) if occ_schedules_num_occ[num_ppl_sch].nil? occ_schedules_num_occ[num_ppl_sch] = num_ppl max_occ_on_thermal_zone += num_ppl else occ_schedules_num_occ[num_ppl_sch] += num_ppl max_occ_on_thermal_zone += num_ppl end end end end # For each day of the year, determine #time_value_pairs = [] year = self.model.getYearDescription yearly_data = [] yearly_times = OpenStudio::DateTimeVector.new yearly_values = [] for i in 1..365 times_on_this_day = [] os_date = year.makeDate(i) day_of_week = os_date.dayOfWeek.valueName # Get the unique time indices and corresponding day schedules occ_schedules_day_schs = {} day_sch_num_occ = {} occ_schedules_num_occ.each do |occ_sch, num_occ| # Get the day schedules for this day # (there should only be one) day_schs = occ_sch.getDaySchedules(os_date, os_date) day_schs[0].times.each do |time| times_on_this_day << time.toString end day_sch_num_occ[day_schs[0]] = num_occ end # Determine the total fraction for the airloop at each time daily_times = [] daily_os_times = [] daily_values = [] daily_occs = [] times_on_this_day.uniq.sort.each do |time| os_time = OpenStudio::Time.new(time) os_date_time = OpenStudio::DateTime.new(os_date, os_time) # Total number of people at each time tot_occ_at_time = 0 day_sch_num_occ.each do |day_sch, num_occ| occ_frac = day_sch.getValue(os_time) tot_occ_at_time += occ_frac * num_occ end # Total fraction for the airloop at each time thermal_zone_occ_frac = tot_occ_at_time / max_occ_on_thermal_zone occ_status = 0 # unoccupied if thermal_zone_occ_frac >= occupied_percentage_threshold occ_status = 1 end # Add this data to the daily arrays daily_times << time daily_os_times << os_time daily_values << occ_status daily_occs << thermal_zone_occ_frac.round(2) end # Simplify the daily times to eliminate intermediate # points with the same value as the following point. simple_daily_times = [] simple_daily_os_times = [] simple_daily_values = [] simple_daily_occs = [] daily_values.each_with_index do |value, i| next if value == daily_values[i+1] simple_daily_times << daily_times[i] simple_daily_os_times << daily_os_times[i] simple_daily_values << daily_values[i] simple_daily_occs << daily_occs[i] end # Store the daily values yearly_data << {'date'=>os_date,'day_of_week'=>day_of_week,'times'=>simple_daily_times,'values'=>simple_daily_values,'daily_os_times'=>simple_daily_os_times, 'daily_occs'=>simple_daily_occs} end # Create a TimeSeries from the data #time_series = OpenStudio::TimeSeries.new(times, values, 'unitless') # Make a schedule ruleset sch_name = "#{self.name} Occ Sch" sch_ruleset = OpenStudio::Model::ScheduleRuleset.new(self.model) sch_ruleset.setName("#{sch_name}") # Default - All Occupied day_sch = sch_ruleset.defaultDaySchedule day_sch.setName("#{sch_name} Default") day_sch.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1) # Winter Design Day - All Occupied day_sch = OpenStudio::Model::ScheduleDay.new(self.model) sch_ruleset.setWinterDesignDaySchedule(day_sch) day_sch = sch_ruleset.winterDesignDaySchedule day_sch.setName("#{sch_name} Winter Design Day") day_sch.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1) # Summer Design Day - All Occupied day_sch = OpenStudio::Model::ScheduleDay.new(self.model) sch_ruleset.setSummerDesignDaySchedule(day_sch) day_sch = sch_ruleset.summerDesignDaySchedule day_sch.setName("#{sch_name} Summer Design Day") day_sch.addValue(OpenStudio::Time.new(0, 24, 0, 0), 1) # Create ruleset schedules, attempting to create # the minimum number of unique rules. ['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'].each do |day_of_week| end_of_prev_rule = yearly_data[0]['date'] yearly_data.each_with_index do |daily_data, i| # Skip unless it is the day of week # currently under inspection day = daily_data['day_of_week'] next unless day == day_of_week date = daily_data['date'] times = daily_data['times'] values = daily_data['values'] daily_occs = daily_data['daily_occs'] # If the next (Monday, Tuesday, etc.) # is the same as today, keep going. # If the next is different, or if # we've reached the end of the year, # create a new rule if !yearly_data[i+7].nil? next_day_times = yearly_data[i+7]['times'] next_day_values = yearly_data[i+7]['values'] next if times == next_day_times && values == next_day_values end daily_os_times = daily_data['daily_os_times'] daily_occs = daily_data['daily_occs'] # If here, we need to make a rule to cover from the previous # rule to today sch_rule = OpenStudio::Model::ScheduleRule.new(sch_ruleset) sch_rule.setName("#{sch_name} #{day_of_week} Rule") day_sch = sch_rule.daySchedule day_sch.setName("#{sch_name} #{day_of_week}") daily_os_times.each_with_index do |time, i| value = values[i] next if value == values[i+1] # Don't add breaks if same value day_sch.addValue(time, value) end # Set the dates when the rule applies sch_rule.setStartDate(end_of_prev_rule) sch_rule.setEndDate(date) # Individual Days sch_rule.setApplyMonday(true) if day_of_week == 'Monday' sch_rule.setApplyTuesday(true) if day_of_week == 'Tuesday' sch_rule.setApplyWednesday(true) if day_of_week == 'Wednesday' sch_rule.setApplyThursday(true) if day_of_week == 'Thursday' sch_rule.setApplyFriday(true) if day_of_week == 'Friday' sch_rule.setApplySaturday(true) if day_of_week == 'Saturday' sch_rule.setApplySunday(true) if day_of_week == 'Sunday' # Reset the previous rule end date end_of_prev_rule = date + OpenStudio::Time.new(0, 24, 0, 0) end end return sch_ruleset end |
#heating_fuels ⇒ Object
Determine the zone heating fuels, including any fuels used by zone equipment, reheat terminals, the air loops serving the zone, and any plant loops serving those air loops.
return [Array<String>] An array. Possible values are Electricity, NaturalGas, PropaneGas, FuelOil#1, FuelOil#2, Coal, Diesel, Gasoline, DistrictCooling, DistrictHeating, and SolarEnergy.
236 237 238 239 240 241 242 243 244 245 246 247 248 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 236 def heating_fuels fuels = [] # Check the zone hvac heating fuels fuels += self.model.zone_equipment_heating_fuels(self) # Check the zone airloop heating fuels fuels += self.model.zone_airloop_heating_fuels(self) return fuels.uniq.sort end |
#heatingDesignLoad ⇒ Object
returns the calculated heating design load as an optional double
183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 |
# File 'lib/openstudio-standards/hvac_sizing/HVACSizing.ThermalZone.rb', line 183 def heatingDesignLoad result = OpenStudio::OptionalDouble.new name = self.name.get.upcase sql = self.model.sqlFile if sql.is_initialized sql = sql.get # In E+ 8.4, (OS 1.9.3 onward) the table name changed table_name = nil if self.model.version < OpenStudio::VersionString.new('1.9.3') table_name = 'Zone Heating' else table_name = 'Zone Sensible Heating' end query = "SELECT Value FROM tabulardatawithstrings WHERE ReportName='HVACSizingSummary' AND ReportForString='Entire Facility' AND TableName='#{table_name}' AND ColumnName='User Design Load per Area' AND RowName='#{name}' AND Units='W/m2'" val = sql.execAndReturnFirstDouble(query) if val.is_initialized result = OpenStudio::OptionalDouble.new(val.get) else #OpenStudio::logFree(OpenStudio::Warn, "openstudio.model.Model", "Data not found for query: #{query}") end else OpenStudio::logFree(OpenStudio::Error, 'openstudio.model.Model', 'Model has no sql file containing results, cannot lookup data.') end return result end |
#infer_system_type ⇒ String
Infers the baseline system type based on the equipment serving the zone and their heating/cooling fuels. Only does a high-level inference; does not look for the presence/absence of required controls, etc.
PTHP, PTAC, PSZ_AC, PSZ_HP, PVAV_Reheat, PVAV_PFP_Boxes, VAV_Reheat, VAV_PFP_Boxes, Gas_Furnace, Electric_Furnace
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
# File 'lib/openstudio-standards/standards/Standards.ThermalZone.rb', line 432 def infer_system_type # Determine the characteristics # of the equipment serving the zone has_air_loop = false air_loop_num_zones = 0 air_loop_is_vav = false air_loop_has_chw = false has_ptac = false has_pthp = false has_unitheater = false self.equipment.each do |equip| # Skip HVAC components next unless equip.to_HVACComponent.is_initialized equip = equip.to_HVACComponent.get if equip.airLoopHVAC.is_initialized has_air_loop = true air_loop = equip.airLoopHVAC.get air_loop_num_zones = air_loop.thermalZones.size air_loop.supplyComponents.each do |sc| if sc.to_FanVariableVolume.is_initialized air_loop_is_vav = true elsif sc.to_CoilCoolingWater.is_initialized air_loop_has_chw = true end end elsif equip.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized has_ptac = true elsif equip.to_ZoneHVACPackagedTerminalHeatPump.is_initialized has_pthp = true elsif equip.to_ZoneHVACUnitHeater.is_initialized has_unitheater = true end end # Get the zone heating and cooling fuels htg_fuels = self.heating_fuels clg_fuels = self.cooling_fuels is_fossil = self.is_fossil_hybrid_or_purchased_heat # Infer the HVAC type sys_type = 'Unknown' # Single zone if air_loop_num_zones < 2 # Gas if is_fossil # Air Loop if has_air_loop # Gas_Furnace (as air loop) if cooling_fuels.size == 0 sys_type = 'Gas_Furnace' # PSZ_AC else sys_type = 'PSZ_AC' end # Zone Equipment else # Gas_Furnace (as unit heater) if has_unitheater sys_type = 'Gas_Furnace' end # PTAC if has_ptac sys_type = 'PTAC' end end # Electric else # Air Loop if has_air_loop # Electric_Furnace (as air loop) if cooling_fuels.size == 0 sys_type = 'Electric_Furnace' # PSZ_HP else sys_type = 'PSZ_HP' end # Zone Equipment else # Electric_Furnace (as unit heater) if has_unitheater sys_type = 'Electric_Furnace' end # PTHP if has_pthp sys_type = 'PTHP' end end end # Multi-zone else # Gas if is_fossil # VAV_Reheat if air_loop_has_chw && air_loop_is_vav sys_type = 'VAV_Reheat' end # PVAV_Reheat if !air_loop_has_chw && air_loop_is_vav sys_type = 'PVAV_Reheat' end # Electric else # VAV_PFP_Boxes if air_loop_has_chw && air_loop_is_vav sys_type = 'VAV_PFP_Boxes' end # PVAV_PFP_Boxes if !air_loop_has_chw && air_loop_is_vav sys_type = 'PVAV_PFP_Boxes' end end end # Report out the characteristics for debugging if # the system type cannot be inferred. if sys_type == 'Unknown' OpenStudio::logFree(OpenStudio::Warn, "openstudio.Standards.ThermalZone", "For #{self.name}, the baseline system type could not be inferred.") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "***#{self.name}***") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "system type = #{sys_type}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "has_air_loop = #{has_air_loop}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "air_loop_num_zones = #{air_loop_num_zones}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "air_loop_is_vav = #{air_loop_is_vav}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "air_loop_has_chw = #{air_loop_has_chw}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "has_ptac = #{has_ptac}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "has_pthp = #{has_pthp}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "has_unitheater = #{has_unitheater}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "htg_fuels = #{htg_fuels}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "clg_fuels = #{clg_fuels}") OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.ThermalZone", "is_fossil = #{is_fossil}") end return sys_type end |
#is_fossil_hybrid_or_purchased_heat ⇒ Object
Determine if the thermal zone is a Fossil Fuel, Fossil/Electric Hybrid, and Purchased Heat zone. If not, it is an Electric or Other Zone. This is as-defined by 90.1 Appendix G.
return [Bool] true if Fossil Fuel, Fossil/Electric Hybrid, and Purchased Heat zone, false if Electric or Other. To-do: It’s not doing it properly right now. If you have a zone with a VRF + a DOAS (via an ATU SingleDUct Uncontrolled) it’ll pick up both natural gas and electricity and classify it as fossil fuel, when I would definitely classify it as electricity
375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 |
# File 'lib/openstudio-standards/standards/Standards.ThermalZone.rb', line 375 def is_fossil_hybrid_or_purchased_heat is_fossil = false # Get an array of the heating fuels # used by the zone. Possible values are # Electricity, NaturalGas, PropaneGas, FuelOil#1, FuelOil#2, # Coal, Diesel, Gasoline, DistrictHeating, # and SolarEnergy. htg_fuels = self.heating_fuels if htg_fuels.include?('NaturalGas') || htg_fuels.include?('PropaneGas') || htg_fuels.include?('FuelOil#1') || htg_fuels.include?('FuelOil#2') || htg_fuels.include?('Coal') || htg_fuels.include?('Diesel') || htg_fuels.include?('Gasoline') || htg_fuels.include?('DistrictHeating') is_fossil = true end #OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.Model", "For #{self.name}, heating fuels = #{htg_fuels.join(', ')}; is_fossil_hybrid_or_purchased_heat = #{is_fossil}.") return is_fossil end |
#is_residential(standard) ⇒ Object
Determine if the thermal zone is residential based on the space type properties for the spaces in the zone. If there are both residential and nonresidential spaces in the zone, the result will be whichever type has more floor area. In the event that they are equal, it will be assumed nonresidential.
return [Bool] true if residential, false if nonresidential
340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/openstudio-standards/standards/Standards.ThermalZone.rb', line 340 def is_residential(standard) # Determine the respective areas res_area_m2 = 0 nonres_area_m2 = 0 self.spaces.each do |space| # Ignore space if not part of total area next if !space.partofTotalFloorArea if space.is_residential(standard) res_area_m2 += space.floorArea else nonres_area_m2 += space.floorArea end end # Determine which is larger is_res = false if res_area_m2 > nonres_area_m2 is_res = true end return is_res end |
#outdoor_airflow_rate ⇒ Double
Calculates the zone outdoor airflow requirement (Voz) based on the inputs in the DesignSpecification:OutdoorAir obects in all spaces in the zone.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
# File 'lib/openstudio-standards/standards/Standards.ThermalZone.rb', line 11 def outdoor_airflow_rate tot_oa_flow_rate = 0.0 spaces = self.spaces.sort sum_floor_area = 0.0 sum_number_of_people = 0.0 sum_volume = 0.0 # Variables for merging outdoor air any_max_oa_method = false sum_oa_for_people = 0.0 sum_oa_for_floor_area = 0.0 sum_oa_rate = 0.0 sum_oa_for_volume = 0.0 # Find common variables for the new space spaces.each do |space| floor_area = space.floorArea sum_floor_area += floor_area number_of_people = space.numberOfPeople sum_number_of_people += number_of_people volume = space.volume sum_volume += volume dsn_oa = space.designSpecificationOutdoorAir next if dsn_oa.empty? dsn_oa = dsn_oa.get # compute outdoor air rates in case we need them oa_for_people = number_of_people * dsn_oa.outdoorAirFlowperPerson oa_for_floor_area = floorArea * dsn_oa.outdoorAirFlowperFloorArea oa_rate = dsn_oa.outdoorAirFlowRate oa_for_volume = volume * dsn_oa.outdoorAirFlowAirChangesperHour # First check if this space uses the Maximum method and other spaces do not if dsn_oa.outdoorAirMethod == 'Maximum' sum_oa_rate += [oa_for_people, oa_for_floor_area, oa_rate, oa_for_volume].max elsif dsn_oa.outdoorAirMethod == 'Sum' sum_oa_for_people += oa_for_people sum_oa_for_floor_area += oa_for_floor_area sum_oa_rate += oa_rate sum_oa_for_volume += oa_for_volume end end tot_oa_flow_rate += sum_oa_for_people tot_oa_flow_rate += sum_oa_for_floor_area tot_oa_flow_rate += sum_oa_rate tot_oa_flow_rate += sum_oa_for_volume # Convert to cfm tot_oa_flow_rate_cfm = OpenStudio.convert(tot_oa_flow_rate,'m^3/s','cfm').get OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.Model", "For #{self.name}, design min OA = #{tot_oa_flow_rate_cfm.round} cfm.") return tot_oa_flow_rate end |
#outdoor_airflow_rate_per_area ⇒ Double
Calculates the zone outdoor airflow requirement and divides by the zone area.
81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/openstudio-standards/standards/Standards.ThermalZone.rb', line 81 def outdoor_airflow_rate_per_area() tot_oa_flow_rate_per_area = 0.0 # Find total area of the zone sum_floor_area = 0.0 self.spaces.sort.each do |space| sum_floor_area += space.floorArea end # Get the OA flow rate tot_oa_flow_rate = outdoor_airflow_rate # Calculate the per-area value tot_oa_flow_rate_per_area = tot_oa_flow_rate / sum_floor_area # OpenStudio::logFree(OpenStudio::Debug, "openstudio.Standards.Model", "For #{self.name}, OA per area = #{tot_oa_flow_rate_per_area.round(8)} m^3/s*m^2.") return tot_oa_flow_rate_per_area end |