module OpenstudioStandards::ThermalZone
The ThermalZone
module provides methods get information about model thermal zones
Public Class Methods
Adds a thermostat that heats the space to 0 F and cools to 120 F. These numbers are outside of the threshold that is considered heated or cooled by thermal_zone_cooled?() and thermal_zone_heated?()
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] returns true if successful, false if not
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 476 def self.thermal_zone_add_unconditioned_thermostat(thermal_zone) # Heated to 0F (below thermal_zone_heated?(thermal_zone) threshold) htg_t_f = 0 htg_t_c = OpenStudio.convert(htg_t_f, 'F', 'C').get htg_stpt_sch = OpenStudio::Model::ScheduleRuleset.new(thermal_zone.model) htg_stpt_sch.setName('Unconditioned Minimal Heating') htg_stpt_sch.defaultDaySchedule.setName('Unconditioned Minimal Heating Default') htg_stpt_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), htg_t_c) # Cooled to 120F (above thermal_zone_cooled?(thermal_zone) threshold) clg_t_f = 120 clg_t_c = OpenStudio.convert(clg_t_f, 'F', 'C').get clg_stpt_sch = OpenStudio::Model::ScheduleRuleset.new(thermal_zone.model) clg_stpt_sch.setName('Unconditioned Minimal Heating') clg_stpt_sch.defaultDaySchedule.setName('Unconditioned Minimal Heating Default') clg_stpt_sch.defaultDaySchedule.addValue(OpenStudio::Time.new(0, 24, 0, 0), clg_t_c) # Thermostat thermostat = OpenStudio::Model::ThermostatSetpointDualSetpoint.new(thermal_zone.model) thermostat.setName("#{thermal_zone.name} Unconditioned Thermostat") thermostat.setHeatingSetpointTemperatureSchedule(htg_stpt_sch) thermostat.setCoolingSetpointTemperatureSchedule(clg_stpt_sch) thermal_zone.setThermostatSetpointDualSetpoint(thermostat) return true end
Convert total minimum OA requirement to a per-area value.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] returns true if successful, false if not
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 723 def self.thermal_zone_convert_outdoor_air_to_per_area(thermal_zone) # For each space in the zone, convert # all design OA to per-area # unless the "Outdoor Air Method" is "Maximum" thermal_zone.spaces.each do |space| # Find the design OA, which may be assigned at either the # SpaceType or directly at the Space dsn_oa = space.designSpecificationOutdoorAir next if dsn_oa.empty? dsn_oa = dsn_oa.get next if dsn_oa.outdoorAirMethod == 'Maximum' # Get the space properties floor_area = space.floorArea number_of_people = space.numberOfPeople volume = space.volume # Sum up the total OA from all sources oa_for_people = number_of_people * dsn_oa.outdoorAirFlowperPerson oa_for_floor_area = floor_area * dsn_oa.outdoorAirFlowperFloorArea oa_rate = dsn_oa.outdoorAirFlowRate oa_for_volume = volume * dsn_oa.outdoorAirFlowAirChangesperHour / 3600 tot_oa = oa_for_people + oa_for_floor_area + oa_rate + oa_for_volume # Convert total to per-area tot_oa_per_area = tot_oa / floor_area # Check if there is another design OA object that has already # been converted from per-person to per-area that matches. # If so, reuse that instead of creating a duplicate. new_dsn_oa_name = "#{dsn_oa.name} to per-area" if thermal_zone.model.getDesignSpecificationOutdoorAirByName(new_dsn_oa_name).is_initialized new_dsn_oa = thermal_zone.model.getDesignSpecificationOutdoorAirByName(new_dsn_oa_name).get else new_dsn_oa = OpenStudio::Model::DesignSpecificationOutdoorAir.new(thermal_zone.model) new_dsn_oa.setName(new_dsn_oa_name) end # Assign this new design OA to the space space.setDesignSpecificationOutdoorAir(new_dsn_oa) # Set the method new_dsn_oa.setOutdoorAirMethod('Sum') # Set the per-area requirement new_dsn_oa.setOutdoorAirFlowperFloorArea(tot_oa_per_area) # Zero-out the per-person, ACH, and flow requirements new_dsn_oa.setOutdoorAirFlowperPerson(0.0) new_dsn_oa.setOutdoorAirFlowAirChangesperHour(0.0) new_dsn_oa.setOutdoorAirFlowRate(0.0) # Copy the orignal OA schedule, if any if dsn_oa.outdoorAirFlowRateFractionSchedule.is_initialized oa_sch = dsn_oa.outdoorAirFlowRateFractionSchedule.get new_dsn_oa.setOutdoorAirFlowRateFractionSchedule(oa_sch) end OpenStudio.logFree(OpenStudio::Info, 'openstudio.Standards.ThermalZone', "For #{thermal_zone.name}: Converted total ventilation requirements to per-area value.") end return true end
Determines cooling status. If the zone has a thermostat with a minimum cooling setpoint below 33C (91F), counts as cooled. Plenums are also assumed to be cooled.
@author Andrew Parker, Julien Marrec @param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] returns true if cooled, false if not
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 243 def self.thermal_zone_cooled?(thermal_zone) temp_f = 91.0 temp_c = OpenStudio.convert(temp_f, 'F', 'C').get cld = false # Consider plenum zones cooled area_plenum = 0 area_non_plenum = 0 thermal_zone.spaces.each do |space| if OpenstudioStandards::Space.space_plenum?(space) area_plenum += space.floorArea else area_non_plenum += space.floorArea end end # Majority if area_plenum > area_non_plenum cld = true return cld end # Check if the zone has radiant cooling, # and if it does, get cooling setpoint schedule # directly from the radiant system to check. thermal_zone.equipment.each do |equip| clg_sch = nil if equip.to_ZoneHVACLowTempRadiantConstFlow.is_initialized equip = equip.to_ZoneHVACLowTempRadiantConstFlow.get clg_coil = equip.coolingCoil if clg_coil.to_CoilCoolingLowTempRadiantConstFlow.is_initialized clg_coil = clg_coil.to_CoilCoolingLowTempRadiantConstFlow.get if clg_coil.coolingLowControlTemperatureSchedule.is_initialized clg_sch = clg_coil.coolingLowControlTemperatureSchedule.get end end elsif equip.to_ZoneHVACLowTempRadiantVarFlow.is_initialized equip = equip.to_ZoneHVACLowTempRadiantVarFlow.get clg_coil = equip.coolingCoil if equip.model.version > OpenStudio::VersionString.new('3.1.0') if clg_coil.is_initialized clg_coil = clg_coil.get else clg_coil = nil end end if !clg_coil.nil? && clg_coil.to_CoilCoolingLowTempRadiantVarFlow.is_initialized clg_coil = clg_coil.to_CoilCoolingLowTempRadiantVarFlow.get if clg_coil.coolingControlTemperatureSchedule.is_initialized clg_sch = clg_coil.coolingControlTemperatureSchedule.get end end end # Move on if no cooling schedule was found next if clg_sch.nil? # Get the setpoint from the schedule if clg_sch.to_ScheduleRuleset.is_initialized clg_sch = clg_sch.to_ScheduleRuleset.get min_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(clg_sch)['min'] if min_c < temp_c cld = true end elsif clg_sch.to_ScheduleConstant.is_initialized clg_sch = clg_sch.to_ScheduleConstant.get min_c = OpenstudioStandards::Schedules.schedule_constant_get_min_max(clg_sch)['min'] if min_c < temp_c cld = true end elsif clg_sch.to_ScheduleCompact.is_initialized clg_sch = clg_sch.to_ScheduleCompact.get min_c = OpenstudioStandards::Schedules.schedule_compact_get_min_max(clg_sch)['min'] if min_c < temp_c cld = true end else OpenStudio.logFree(OpenStudio::Debug, 'OpenstudioStandards::ThermalZone', "Zone #{thermal_zone.name} used an unknown schedule type for the cooling setpoint; assuming cooled.") cld = true end end # Unheated if no thermostat present if thermal_zone.thermostat.empty? return cld end # Check the cooling setpoint tstat = thermal_zone.thermostat.get if tstat.to_ThermostatSetpointDualSetpoint tstat = tstat.to_ThermostatSetpointDualSetpoint.get clg_sch = tstat.getCoolingSchedule if clg_sch.is_initialized clg_sch = clg_sch.get if clg_sch.to_ScheduleRuleset.is_initialized clg_sch = clg_sch.to_ScheduleRuleset.get min_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(clg_sch)['min'] if min_c < temp_c cld = true end elsif clg_sch.to_ScheduleConstant.is_initialized clg_sch = clg_sch.to_ScheduleConstant.get min_c = OpenstudioStandards::Schedules.schedule_constant_get_min_max(clg_sch)['min'] if min_c < temp_c cld = true end elsif clg_sch.to_ScheduleCompact.is_initialized clg_sch = clg_sch.to_ScheduleCompact.get min_c = OpenstudioStandards::Schedules.schedule_compact_get_min_max(clg_sch)['min'] if min_c < temp_c cld = true end else OpenStudio.logFree(OpenStudio::Debug, 'OpenstudioStandards::ThermalZone', "Zone #{thermal_zone.name} used an unknown schedule type for the cooling setpoint; assuming cooled.") cld = true end end elsif tstat.to_ZoneControlThermostatStagedDualSetpoint tstat = tstat.to_ZoneControlThermostatStagedDualSetpoint.get clg_sch = tstat.coolingTemperatureSetpointSchedule if clg_sch.is_initialized clg_sch = clg_sch.get if clg_sch.to_ScheduleRuleset.is_initialized clg_sch = clg_sch.to_ScheduleRuleset.get min_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(clg_sch)['min'] if min_c < temp_c cld = true end end end elsif tstat.to_ThermostatSetpointSingleHeating cld = false end return cld end
Determine if the thermal zone is heated by district or purchased heat. This will return true if there is any fossil heat, even if not the primary heating source. As an example, a zone served by a VRF + DOAS system will show as district heated if the DOAS ventilation air is heated by a district system
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] true if heated by district heat, false if electric or other.
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 438 def self.thermal_zone_district_heat?(thermal_zone) # error if HVACComponent heating fuels method is not available if thermal_zone.model.version < OpenStudio::VersionString.new('3.6.0') OpenStudio.logFree(OpenStudio::Error, 'OpenstudioStandards::ThermalZone', 'Required HVACComponent method .heatingFuelTypes is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.') end is_district = false # Get an array of the heating fuels used by the zone htg_fuels = thermal_zone.heatingFuelTypes.map(&:valueName) if htg_fuels.include?('DistrictHeating') || htg_fuels.include?('DistrictHeatingWater') || htg_fuels.include?('DistrictHeatingSteam') is_district = true end return is_district end
Determine if the thermal zone is heated by electricity. This will return true if there is any electric heat, even if not the primary heating source.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] true if heated by electricity, false if fossil fuel or other.
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 384 def self.thermal_zone_electric_heat?(thermal_zone) # error if HVACComponent heating fuels method is not available if thermal_zone.model.version < OpenStudio::VersionString.new('3.6.0') OpenStudio.logFree(OpenStudio::Error, 'OpenstudioStandards::ThermalZone', 'Required HVACComponent method .heatingFuelTypes is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.') end # Get an array of the heating fuels used by the zone htg_fuels = thermal_zone.heatingFuelTypes.map(&:valueName) is_electric = htg_fuels.include?('Electricity') return is_electric end
Determine if the thermal zone is heated by a fossil fuel. This will return true if there is any fossil heat, even if not the primary heating source. As an example, a zone served by a VRF + DOAS system will show as fossil heated if the DOAS ventilation air is fossil heated
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] true if heated by fossil fuel, false if electric or other.
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 404 def self.thermal_zone_fossil_heat?(thermal_zone) # error if HVACComponent heating fuels method is not available if thermal_zone.model.version < OpenStudio::VersionString.new('3.6.0') OpenStudio.logFree(OpenStudio::Error, 'OpenstudioStandards::ThermalZone', 'Required HVACComponent method .heatingFuelTypes is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.') end is_fossil = false # Get an array of the heating fuels used by the zone htg_fuels = thermal_zone.heatingFuelTypes.map(&:valueName) if htg_fuels.include?('Gas') || htg_fuels.include?('NaturalGas') || htg_fuels.include?('Propane') || htg_fuels.include?('PropaneGas') || htg_fuels.include?('FuelOil_1') || htg_fuels.include?('FuelOilNo1') || htg_fuels.include?('FuelOil_2') || htg_fuels.include?('FuelOilNo2') || htg_fuels.include?('Coal') || htg_fuels.include?('Diesel') || htg_fuels.include?('Gasoline') is_fossil = true end return is_fossil end
Returns the standards building type that represents the majority of floor area.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [String] the standards building type
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 548 def self.thermal_zone_get_building_type(thermal_zone) # determine areas of each building type building_type_areas = {} thermal_zone.spaces.each do |space| # ignore space if not part of total area next unless space.partofTotalFloorArea if space.spaceType.is_initialized space_type = space.spaceType.get if space_type.standardsBuildingType.is_initialized building_type = space_type.standardsBuildingType.get if building_type_areas[building_type].nil? building_type_areas[building_type] = space.floorArea else building_type_areas[building_type] += space.floorArea end end end end # return largest building type area building_type = building_type_areas.key(building_type_areas.values.max) if building_type.nil? OpenStudio.logFree(OpenStudio::Info, 'OpenstudioStandards::ThermalZone', "Thermal zone #{thermal_zone.name} does not have standards building type.") end return building_type end
Determine the design internal load (W) for this zone without space multipliers. This include People, Lights, Electric Equipment, and Gas Equipment in all spaces in this zone. It assumes 100% of the wattage is converted to heat, and that the design peak schedule value is 1 (100%).
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Double] the design internal load, in watts
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 509 def self.thermal_zone_get_design_internal_load(thermal_zone) load_w = 0.0 thermal_zone.spaces.each do |space| load_w += OpenstudioStandards::Space.space_get_design_internal_load(space) end return load_w end
This method creates a new fractional schedule ruleset. If occupied_percentage_threshold is set, this method will return a discrete on/off fractional schedule with a value of one when occupancy across all spaces is greater than or equal to the occupied_percentage_threshold, and zero all other times. Otherwise the method will return the weighted fractional occupancy schedule.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @param sch_name [String] the name of the generated occupancy schedule @param occupied_percentage_threshold [Double] the minimum fraction (0 to 1) that counts as occupied
if this parameter is set, the returned ScheduleRuleset will be 0 = unoccupied, 1 = occupied otherwise the ScheduleRuleset will be the weighted fractional occupancy schedule
@return [<OpenStudio::Model::ScheduleRuleset>] OpenStudio ScheduleRuleset of fractional or discrete occupancy
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 589 def self.thermal_zone_get_occupancy_schedule(thermal_zone, sch_name: nil, occupied_percentage_threshold: nil) if sch_name.nil? sch_name = "#{thermal_zone.name} Occ Sch" end # Get the occupancy schedule for all spaces in thermal_zone sch_ruleset = OpenstudioStandards::Space.spaces_get_occupancy_schedule(thermal_zone.spaces, sch_name: sch_name, occupied_percentage_threshold: occupied_percentage_threshold) return sch_ruleset end
Calculates the zone outdoor airflow requirement (Voz) based on the inputs in the DesignSpecification:OutdoorAir objects in all spaces in the zone.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Double] the zone outdoor air flow rate in cubic meters per second (m^3/s)
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 633 def self.thermal_zone_get_outdoor_airflow_rate(thermal_zone) tot_oa_flow_rate = 0.0 spaces = thermal_zone.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 = floor_area * dsn_oa.outdoorAirFlowperFloorArea oa_rate = dsn_oa.outdoorAirFlowRate oa_for_volume = volume * dsn_oa.outdoorAirFlowAirChangesperHour / 3600 # 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.ThermalZone', "For #{thermal_zone.name}, design min OA = #{tot_oa_flow_rate_cfm.round} cfm.") return tot_oa_flow_rate end
Calculates the zone outdoor airflow requirement and divides by the zone area.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Double] the zone outdoor air flow rate per area in cubic meters per second (m^3/s)
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 699 def self.thermal_zone_get_outdoor_airflow_rate_per_area(thermal_zone) tot_oa_flow_rate_per_area = 0.0 # Find total area of the zone sum_floor_area = 0.0 thermal_zone.spaces.sort.each do |space| sum_floor_area += space.floorArea end # Get the OA flow rate tot_oa_flow_rate = OpenstudioStandards::ThermalZone.thermal_zone_get_outdoor_airflow_rate(thermal_zone) # 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
Returns the space type that represents a majority of the floor area.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boost::Optional<OpenStudio::Model::SpaceType>] An OptionalSpaceType
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 523 def self.thermal_zone_get_space_type(thermal_zone) space_type_to_area = Hash.new(0.0) thermal_zone.spaces.each do |space| if space.spaceType.is_initialized space_type = space.spaceType.get space_type_to_area[space_type] += space.floorArea end end # If no space types, return empty optional SpaceType if space_type_to_area.empty? return OpenStudio::Model::OptionalSpaceType.new end # Sort by area biggest_space_type = space_type_to_area.sort_by { |st, area| area }.reverse[0][0] return OpenStudio::Model::OptionalSpaceType.new(biggest_space_type) end
Determines heating status. If the zone has a thermostat with a maximum heating setpoint above 5C (41F), counts as heated. Plenums are also assumed to be heated.
@author Andrew Parker, Julien Marrec @param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] returns true if heated, false if not
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 94 def self.thermal_zone_heated?(thermal_zone) temp_f = 41.0 temp_c = OpenStudio.convert(temp_f, 'F', 'C').get htd = false # Consider plenum zones heated area_plenum = 0 area_non_plenum = 0 thermal_zone.spaces.each do |space| if OpenstudioStandards::Space.space_plenum?(space) area_plenum += space.floorArea else area_non_plenum += space.floorArea end end # Majority if area_plenum > area_non_plenum htd = true return htd end # Check if the zone has radiant heating, # and if it does, get heating setpoint schedule # directly from the radiant system to check. thermal_zone.equipment.each do |equip| htg_sch = nil if equip.to_ZoneHVACHighTemperatureRadiant.is_initialized equip = equip.to_ZoneHVACHighTemperatureRadiant.get if equip.heatingSetpointTemperatureSchedule.is_initialized htg_sch = equip.heatingSetpointTemperatureSchedule.get end elsif equip.to_ZoneHVACLowTemperatureRadiantElectric.is_initialized equip = equip.to_ZoneHVACLowTemperatureRadiantElectric.get htg_sch = equip.heatingSetpointTemperatureSchedule elsif equip.to_ZoneHVACLowTempRadiantConstFlow.is_initialized equip = equip.to_ZoneHVACLowTempRadiantConstFlow.get htg_coil = equip.heatingCoil if htg_coil.to_CoilHeatingLowTempRadiantConstFlow.is_initialized htg_coil = htg_coil.to_CoilHeatingLowTempRadiantConstFlow.get if htg_coil.heatingHighControlTemperatureSchedule.is_initialized htg_sch = htg_coil.heatingHighControlTemperatureSchedule.get end end elsif equip.to_ZoneHVACLowTempRadiantVarFlow.is_initialized equip = equip.to_ZoneHVACLowTempRadiantVarFlow.get htg_coil = equip.heatingCoil if equip.model.version > OpenStudio::VersionString.new('3.1.0') if htg_coil.is_initialized htg_coil = htg_coil.get else htg_coil = nil end end if !htg_coil.nil? && htg_coil.to_CoilHeatingLowTempRadiantVarFlow.is_initialized htg_coil = htg_coil.to_CoilHeatingLowTempRadiantVarFlow.get if htg_coil.heatingControlTemperatureSchedule.is_initialized htg_sch = htg_coil.heatingControlTemperatureSchedule.get end end end # Move on if no heating schedule was found next if htg_sch.nil? # Get the setpoint from the schedule if htg_sch.to_ScheduleRuleset.is_initialized htg_sch = htg_sch.to_ScheduleRuleset.get max_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end elsif htg_sch.to_ScheduleConstant.is_initialized htg_sch = htg_sch.to_ScheduleConstant.get max_c = OpenstudioStandards::Schedules.schedule_constant_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end elsif htg_sch.to_ScheduleCompact.is_initialized htg_sch = htg_sch.to_ScheduleCompact.get max_c = OpenstudioStandards::Schedules.schedule_compact_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end else OpenStudio.logFree(OpenStudio::Debug, 'OpenstudioStandards::ThermalZone', "Zone #{thermal_zone.name} used an unknown schedule type for the heating setpoint; assuming heated.") htd = true end end # Unheated if no thermostat present if thermal_zone.thermostat.empty? return htd end # Check the heating setpoint tstat = thermal_zone.thermostat.get if tstat.to_ThermostatSetpointDualSetpoint tstat = tstat.to_ThermostatSetpointDualSetpoint.get htg_sch = tstat.getHeatingSchedule if htg_sch.is_initialized htg_sch = htg_sch.get if htg_sch.to_ScheduleRuleset.is_initialized htg_sch = htg_sch.to_ScheduleRuleset.get max_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end elsif htg_sch.to_ScheduleConstant.is_initialized htg_sch = htg_sch.to_ScheduleConstant.get max_c = OpenstudioStandards::Schedules.schedule_constant_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end elsif htg_sch.to_ScheduleCompact.is_initialized htg_sch = htg_sch.to_ScheduleCompact.get max_c = OpenstudioStandards::Schedules.schedule_compact_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end else OpenStudio.logFree(OpenStudio::Debug, 'OpenstudioStandards::ThermalZone', "Zone #{thermal_zone.name} used an unknown schedule type for the heating setpoint; assuming heated.") htd = true end end elsif tstat.to_ZoneControlThermostatStagedDualSetpoint tstat = tstat.to_ZoneControlThermostatStagedDualSetpoint.get htg_sch = tstat.heatingTemperatureSetpointSchedule if htg_sch.is_initialized htg_sch = htg_sch.get if htg_sch.to_ScheduleRuleset.is_initialized htg_sch = htg_sch.to_ScheduleRuleset.get max_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end end end end return htd end
Determine if the thermal zone is heated by two or more of electricity, fossil fuel, and district or purchased heat.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] true if mixed fossil, electric, and district/purchased heat, false if not
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 461 def self.thermal_zone_mixed_heat?(thermal_zone) electric_heat = OpenstudioStandards::ThermalZone.thermal_zone_electric_heat?(thermal_zone) fossil_heat = OpenstudioStandards::ThermalZone.thermal_zone_fossil_heat?(thermal_zone) district_heat = OpenstudioStandards::ThermalZone.thermal_zone_district_heat?(thermal_zone) is_mixed = [electric_heat, fossil_heat, district_heat].count(true) > 1 return is_mixed end
Determine if the thermal zone is a plenum based on whether a majority of the spaces in the zone are plenums or not.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] returns true if majority plenum, false if not
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 8 def self.thermal_zone_plenum?(thermal_zone) plenum_status = false area_plenum = 0 area_non_plenum = 0 thermal_zone.spaces.each do |space| if OpenstudioStandards::Space.space_plenum?(space) area_plenum += space.floorArea else area_non_plenum += space.floorArea end end # Majority if area_plenum > area_non_plenum plenum_status = true end return plenum_status end
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.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object return [Boolean] true if residential, false if nonresidential
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 36 def self.thermal_zone_residential?(thermal_zone) # Determine the respective areas res_area_m2 = 0 nonres_area_m2 = 0 thermal_zone.spaces.each do |space| # Ignore space if not part of total area next unless space.partofTotalFloorArea if OpenstudioStandards::Space.space_residential?(space) 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
Determine if this zone is a vestibule. Zone must be less than 200 ft^2 and also have an infiltration object specified using Flow/Zone.
@param thermal_zone [OpenStudio::Model::ThermalZone] OpenStudio ThermalZone
object @return [Boolean] returns true if vestibule, false if not
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 65 def self.thermal_zone_vestibule?(thermal_zone) is_vest = false # Check area unless thermal_zone.floorArea < OpenStudio.convert(200, 'ft^2', 'm^2').get return is_vest end # Check presence of infiltration thermal_zone.spaces.each do |space| space.spaceInfiltrationDesignFlowRates.each do |infil| if infil.designFlowRate.is_initialized is_vest = true OpenStudio.logFree(OpenStudio::Info, 'OpenstudioStandards::ThermalZone', "For #{thermal_zone.name}: This zone is considered a vestibule.") break end end end return is_vest end
This method creates a new fractional schedule ruleset. If occupied_percentage_threshold is set, this method will return a discrete on/off fractional schedule with a value of one when occupancy across all spaces is greater than or equal to the occupied_percentage_threshold, and zero all other times. Otherwise the method will return the weighted fractional occupancy schedule.
@param thermal_zones [Array<OpenStudio::Model::ThermalZone>] Array
of OpenStudio ThermalZone
objects @param sch_name [String] the name of the generated occupancy schedule @param occupied_percentage_threshold [Double] the minimum fraction (0 to 1) that counts as occupied
if this parameter is set, the returned ScheduleRuleset will be 0 = unoccupied, 1 = occupied otherwise the ScheduleRuleset will be the weighted fractional occupancy schedule
@return [<OpenStudio::Model::ScheduleRuleset>] OpenStudio ScheduleRuleset of fractional or discrete occupancy
# File lib/openstudio-standards/thermal_zone/thermal_zone.rb, line 611 def self.thermal_zones_get_occupancy_schedule(thermal_zones, sch_name: nil, occupied_percentage_threshold: nil) if sch_name.nil? sch_name = "#{thermal_zones.size} zone Occ Sch" end # Get the occupancy schedule for all spaces in thermal_zones spaces = [] thermal_zones.each do |thermal_zone| thermal_zone.spaces.each do |space| spaces << space end end sch_ruleset = OpenstudioStandards::Space.spaces_get_occupancy_schedule(spaces, sch_name: sch_name, occupied_percentage_threshold: occupied_percentage_threshold) return sch_ruleset end