diff --git a/HPXMLtoOpenStudio/measure.xml b/HPXMLtoOpenStudio/measure.xml
index 365d339980..023d3777e5 100644
--- a/HPXMLtoOpenStudio/measure.xml
+++ b/HPXMLtoOpenStudio/measure.xml
@@ -3,8 +3,8 @@
3.1
hpxm_lto_openstudio
b1543b30-9465-45ff-ba04-1d1f85e763bc
- c80e402f-4c82-4eae-9336-698bde0e09c3
- 2024-10-11T18:59:49Z
+ 72c688f5-e64c-48f3-b1e4-062d4e53586c
+ 2024-10-11T22:49:23Z
D8922A73
HPXMLtoOpenStudio
HPXML to OpenStudio Translator
@@ -357,7 +357,7 @@
hpxml.rb
rb
resource
- AF9C179B
+ 10F59ACC
hpxml_schema/HPXML.xsd
@@ -387,7 +387,7 @@
hvac.rb
rb
resource
- CEDAF4B3
+ 96EEE054
hvac_sizing.rb
@@ -405,7 +405,7 @@
lighting.rb
rb
resource
- E8D2508C
+ 9B17C563
location.rb
@@ -441,7 +441,7 @@
misc_loads.rb
rb
resource
- ABD35A7F
+ 2DCA8614
model.rb
@@ -639,7 +639,7 @@
xmlhelper.rb
rb
resource
- D1BB113E
+ DA4456A1
xmlvalidator.rb
@@ -647,12 +647,6 @@
resource
93120E27
-
- in.schedules.csv
- csv
- test
- C8EBFF38
-
test_airflow.rb
rb
diff --git a/HPXMLtoOpenStudio/resources/hpxml.rb b/HPXMLtoOpenStudio/resources/hpxml.rb
index 2bfe50af41..cb6eb32629 100644
--- a/HPXMLtoOpenStudio/resources/hpxml.rb
+++ b/HPXMLtoOpenStudio/resources/hpxml.rb
@@ -11184,7 +11184,7 @@ def from_doc(performance_data_point)
#
# @return [Oga::XML::Document] The HPXML document
def _create_hpxml_document
- doc = XMLHelper.create_doc('1.0', 'UTF-8')
+ doc = XMLHelper.create_doc()
hpxml = XMLHelper.add_element(doc, 'HPXML')
XMLHelper.add_attribute(hpxml, 'xmlns', NameSpace)
XMLHelper.add_attribute(hpxml, 'schemaVersion', Version::HPXML_Version)
diff --git a/HPXMLtoOpenStudio/resources/hvac.rb b/HPXMLtoOpenStudio/resources/hvac.rb
index a690a86e4c..846da1e163 100644
--- a/HPXMLtoOpenStudio/resources/hvac.rb
+++ b/HPXMLtoOpenStudio/resources/hvac.rb
@@ -266,7 +266,7 @@ def self.apply_heat_pump(runner, model, weather, spaces, hpxml_bldg, hpxml_heade
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
# @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file)
- # @return [TODO] TODO
+ # @return [OpenStudio::Model::AirLoopHVAC] The newly created air loop hvac object
def self.apply_air_source_hvac_systems(model, runner, weather, cooling_system, heating_system, hvac_sequential_load_fracs,
control_zone, hvac_unavailable_periods, schedules_file, hpxml_bldg, hpxml_header)
is_heatpump = false
@@ -433,23 +433,23 @@ def self.apply_air_source_hvac_systems(model, runner, weather, cooling_system, h
fan = create_supply_fan(model, obj_name, fan_watts_per_cfm, fan_cfms)
if heating_system.is_a?(HPXML::HeatPump) && (not heating_system.backup_system.nil?) && (not htg_ap.hp_min_temp.nil?)
# Disable blower fan power below compressor lockout temperature if separate backup heating system
- set_fan_power_ems_program(model, fan, htg_ap.hp_min_temp)
+ add_fan_power_ems_program(model, fan, htg_ap.hp_min_temp)
end
if (not cooling_system.nil?) && (not heating_system.nil?) && (cooling_system == heating_system)
- disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, htg_supp_coil, cooling_system)
+ add_fan_pump_disaggregation_ems_program(model, fan, htg_coil, clg_coil, htg_supp_coil, cooling_system)
else
if not cooling_system.nil?
if cooling_system.has_integrated_heating
- disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, nil, cooling_system)
+ add_fan_pump_disaggregation_ems_program(model, fan, htg_coil, clg_coil, nil, cooling_system)
else
- disaggregate_fan_or_pump(model, fan, nil, clg_coil, nil, cooling_system)
+ add_fan_pump_disaggregation_ems_program(model, fan, nil, clg_coil, nil, cooling_system)
end
end
if not heating_system.nil?
if heating_system.is_heat_pump_backup_system
- disaggregate_fan_or_pump(model, fan, nil, nil, htg_coil, heating_system)
+ add_fan_pump_disaggregation_ems_program(model, fan, nil, nil, htg_coil, heating_system)
else
- disaggregate_fan_or_pump(model, fan, htg_coil, nil, htg_supp_coil, heating_system)
+ add_fan_pump_disaggregation_ems_program(model, fan, htg_coil, nil, htg_supp_coil, heating_system)
end
end
end
@@ -475,15 +475,15 @@ def self.apply_air_source_hvac_systems(model, runner, weather, cooling_system, h
# Air Loop
air_loop = create_air_loop(model, obj_name, air_loop_unitary, control_zone, hvac_sequential_load_fracs, [htg_cfm.to_f, clg_cfm.to_f].max, heating_system, hvac_unavailable_periods)
- add_backup_staging_EMS(model, air_loop_unitary, htg_supp_coil, control_zone, htg_coil)
+ add_backup_staging_ems_program(model, air_loop_unitary, htg_supp_coil, control_zone, htg_coil)
apply_installation_quality(model, heating_system, cooling_system, air_loop_unitary, htg_coil, clg_coil, control_zone)
# supp coil control in staging EMS
- apply_two_speed_realistic_staging_EMS(model, air_loop_unitary, htg_supp_coil, control_zone, is_onoff_thermostat_ddb, cooling_system)
+ add_two_speed_staging_ems_program(model, air_loop_unitary, htg_supp_coil, control_zone, is_onoff_thermostat_ddb, cooling_system)
- apply_supp_coil_EMS_for_ddb_thermostat(model, htg_supp_coil, control_zone, htg_coil, is_onoff_thermostat_ddb, cooling_system)
+ add_supplemental_coil_ems_program(model, htg_supp_coil, control_zone, htg_coil, is_onoff_thermostat_ddb, cooling_system)
- apply_max_power_EMS(model, runner, air_loop_unitary, control_zone, heating_system, cooling_system, htg_supp_coil, clg_coil, htg_coil, schedules_file)
+ add_variable_speed_power_ems_program(model, runner, air_loop_unitary, control_zone, heating_system, cooling_system, htg_supp_coil, clg_coil, htg_coil, schedules_file)
if is_heatpump && hpxml_header.defrost_model_type == HPXML::AdvancedResearchDefrostModelTypeAdvanced
apply_advanced_defrost(model, htg_coil, air_loop_unitary, control_zone.spaces[0], htg_supp_coil, cooling_system, q_dot_defrost)
@@ -500,7 +500,7 @@ def self.apply_air_source_hvac_systems(model, runner, weather, cooling_system, h
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
# @param hvac_unavailable_periods [Hash] Map of htg/clg => HPXML::UnavailablePeriods for heating/cooling
# @param unit_multiplier [Integer] Number of similar dwelling units
- # @return [TODO] TODO
+ # @return [OpenStudio::Model::AirLoopHVAC] The newly created air loop hvac object
def self.apply_evaporative_cooler(model, cooling_system, hvac_sequential_load_fracs, control_zone,
hvac_unavailable_periods, unit_multiplier)
@@ -526,7 +526,7 @@ def self.apply_evaporative_cooler(model, cooling_system, hvac_sequential_load_fr
fan_watts_per_cfm = [2.79 * (clg_cfm / unit_multiplier)**-0.29, 0.6].min # W/cfm; fit of efficacy to air flow from the CEC listed equipment
fan = create_supply_fan(model, obj_name, fan_watts_per_cfm, [clg_cfm])
fan.addToNode(air_loop.supplyInletNode)
- disaggregate_fan_or_pump(model, fan, nil, evap_cooler, nil, cooling_system)
+ add_fan_pump_disaggregation_ems_program(model, fan, nil, evap_cooler, nil, cooling_system)
# Outdoor air intake system
oa_intake_controller = OpenStudio::Model::ControllerOutdoorAir.new(model)
@@ -563,7 +563,7 @@ def self.apply_evaporative_cooler(model, cooling_system, hvac_sequential_load_fr
# @param ground_diffusivity [TODO] TODO
# @param hvac_unavailable_periods [Hash] Map of htg/clg => HPXML::UnavailablePeriods for heating/cooling
# @param unit_multiplier [Integer] Number of similar dwelling units
- # @return [TODO] TODO
+ # @return [OpenStudio::Model::AirLoopHVAC] The newly created air loop hvac object
def self.apply_ground_to_air_heat_pump(model, runner, weather, heat_pump, hvac_sequential_load_fracs,
control_zone, ground_conductivity, ground_diffusivity,
hvac_unavailable_periods, unit_multiplier)
@@ -722,7 +722,7 @@ def self.apply_ground_to_air_heat_pump(model, runner, weather, heat_pump, hvac_s
rated_power: pump_w
)
pump.addToNode(plant_loop.supplyInletNode)
- disaggregate_fan_or_pump(model, pump, htg_coil, clg_coil, htg_supp_coil, heat_pump)
+ add_fan_pump_disaggregation_ems_program(model, pump, htg_coil, clg_coil, htg_supp_coil, heat_pump)
# Pipes
chiller_bypass_pipe = Model.add_pipe_adiabatic(model)
@@ -738,11 +738,11 @@ def self.apply_ground_to_air_heat_pump(model, runner, weather, heat_pump, hvac_s
# Fan
fan = create_supply_fan(model, obj_name, heat_pump.fan_watts_per_cfm, [htg_cfm, clg_cfm])
- disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, htg_supp_coil, heat_pump)
+ add_fan_pump_disaggregation_ems_program(model, fan, htg_coil, clg_coil, htg_supp_coil, heat_pump)
# Unitary System
air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, clg_cfm, 40.0)
- set_pump_power_ems_program(model, pump_w, pump, air_loop_unitary)
+ add_pump_power_ems_program(model, pump_w, pump, air_loop_unitary)
if heat_pump.is_shared_system
# Shared pump power per ANSI/RESNET/ICC 301-2019 Section 4.4.5.1 (pump runs 8760)
@@ -778,7 +778,7 @@ def self.apply_ground_to_air_heat_pump(model, runner, weather, heat_pump, hvac_s
# @param hvac_sequential_load_fracs [Array] Array of daily fractions of remaining heating/cooling load to bet met by the HVAC system
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
# @param hvac_unavailable_periods [Hash] Map of htg/clg => HPXML::UnavailablePeriods for heating/cooling
- # @return [TODO] TODO
+ # @return [OpenStudio::Model::AirLoopHVAC] The newly created air loop hvac object
def self.apply_water_loop_to_air_heat_pump(model, heat_pump, hvac_sequential_load_fracs, control_zone, hvac_unavailable_periods)
if heat_pump.fraction_cool_load_served > 0
# WLHPs connected to chillers or cooling towers should have already been converted to
@@ -819,7 +819,7 @@ def self.apply_water_loop_to_air_heat_pump(model, heat_pump, hvac_sequential_loa
# Fan
fan_power_installed = 0.0 # Use provided net COP
fan = create_supply_fan(model, obj_name, fan_power_installed, [htg_cfm])
- disaggregate_fan_or_pump(model, fan, htg_coil, clg_coil, htg_supp_coil, heat_pump)
+ add_fan_pump_disaggregation_ems_program(model, fan, htg_coil, clg_coil, htg_supp_coil, heat_pump)
# Unitary System
air_loop_unitary = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, clg_coil, htg_supp_coil, htg_cfm, nil)
@@ -838,7 +838,7 @@ def self.apply_water_loop_to_air_heat_pump(model, heat_pump, hvac_sequential_loa
# @param hvac_sequential_load_fracs [Array] Array of daily fractions of remaining heating/cooling load to bet met by the HVAC system
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
# @param hvac_unavailable_periods [Hash] Map of htg/clg => HPXML::UnavailablePeriods for heating/cooling
- # @return [TODO] TODO
+ # @return [OpenStudio::Model::ZoneHVACFourPipeFanCoil or OpenStudio::Model::ZoneHVACBaseboardConvectiveWater] The newly created zone hvac object
def self.apply_boiler(model, runner, heating_system, hvac_sequential_load_fracs, control_zone, hvac_unavailable_periods)
obj_name = Constants::ObjectTypeBoiler
is_condensing = false # FUTURE: Expose as input; default based on AFUE
@@ -924,7 +924,7 @@ def self.apply_boiler(model, runner, heating_system, hvac_sequential_load_fracs,
plant_loop.addSupplyBranchForComponent(boiler)
boiler.additionalProperties.setFeature('HPXML_ID', heating_system.id) # Used by reporting measure
boiler.additionalProperties.setFeature('IsHeatPumpBackup', heating_system.is_heat_pump_backup_system) # Used by reporting measure
- set_pump_power_ems_program(model, pump_w, pump, boiler)
+ add_pump_power_ems_program(model, pump_w, pump, boiler)
if is_condensing && oat_reset_enabled
setpoint_manager_oar = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model)
@@ -1002,7 +1002,7 @@ def self.apply_boiler(model, runner, heating_system, hvac_sequential_load_fracs,
zone_hvac.setMaximumSupplyAirFlowRate(UnitConversions.convert(fan_cfm, 'cfm', 'm^3/s'))
zone_hvac.setMaximumHotWaterFlowRate(max_water_flow)
zone_hvac.addToThermalZone(control_zone)
- disaggregate_fan_or_pump(model, pump, zone_hvac, nil, nil, heating_system)
+ add_fan_pump_disaggregation_ems_program(model, pump, zone_hvac, nil, nil, heating_system)
else
# Heating Coil
htg_coil = OpenStudio::Model::CoilHeatingWaterBaseboard.new(model)
@@ -1020,9 +1020,9 @@ def self.apply_boiler(model, runner, heating_system, hvac_sequential_load_fracs,
zone_hvac.addToThermalZone(control_zone)
zone_hvac.additionalProperties.setFeature('IsHeatPumpBackup', heating_system.is_heat_pump_backup_system) # Used by reporting measure
if heating_system.is_heat_pump_backup_system
- disaggregate_fan_or_pump(model, pump, nil, nil, zone_hvac, heating_system)
+ add_fan_pump_disaggregation_ems_program(model, pump, nil, nil, zone_hvac, heating_system)
else
- disaggregate_fan_or_pump(model, pump, zone_hvac, nil, nil, heating_system)
+ add_fan_pump_disaggregation_ems_program(model, pump, zone_hvac, nil, nil, heating_system)
end
end
@@ -1061,7 +1061,7 @@ def self.apply_electric_baseboard(model, heating_system, hvac_sequential_load_fr
# @param hvac_sequential_load_fracs [Array] Array of daily fractions of remaining heating/cooling load to bet met by the HVAC system
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
# @param hvac_unavailable_periods [Hash] Map of htg/clg => HPXML::UnavailablePeriods for heating/cooling
- # @return [TODO] TODO
+ # @return [nil]
def self.apply_unit_heater(model, heating_system, hvac_sequential_load_fracs, control_zone, hvac_unavailable_periods)
obj_name = Constants::ObjectTypeUnitHeater
@@ -1083,7 +1083,7 @@ def self.apply_unit_heater(model, heating_system, hvac_sequential_load_fracs, co
htg_cfm = heating_system.heating_airflow_cfm
fan_watts_per_cfm = heating_system.fan_watts / htg_cfm
fan = create_supply_fan(model, obj_name, fan_watts_per_cfm, [htg_cfm])
- disaggregate_fan_or_pump(model, fan, htg_coil, nil, nil, heating_system)
+ add_fan_pump_disaggregation_ems_program(model, fan, htg_coil, nil, nil, heating_system)
# Unitary System
unitary_system = create_air_loop_unitary_system(model, obj_name, fan, htg_coil, nil, nil, htg_cfm, nil)
@@ -1291,7 +1291,7 @@ def self.apply_dehumidifiers(runner, model, spaces, hpxml_bldg, hpxml_header)
zone_hvac.additionalProperties.setFeature('HPXML_ID', dehumidifier_id) # Used by reporting measure
if total_fraction_served < 1.0
- adjust_dehumidifier_load_EMS(total_fraction_served, zone_hvac, model, conditioned_space)
+ add_dehumidifier_load_adjustment_ems_program(total_fraction_served, zone_hvac, model, conditioned_space)
end
end
@@ -1678,7 +1678,7 @@ def self.get_heat_cap_eir_fflow_spec(compressor_type)
#
# @param cooling_system [TODO] TODO
# @param use_eer [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_cool_curves_central_air_source(cooling_system, use_eer = false)
clg_ap = cooling_system.additional_properties
clg_ap.cool_rated_cfm_per_ton = get_cool_cfm_per_ton(cooling_system.compressor_type, use_eer)
@@ -1744,7 +1744,7 @@ def self.get_cool_capacity_ratios(hvac_system)
#
# @param heating_system [TODO] TODO
# @param use_cop [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_heat_curves_central_air_source(heating_system, use_cop = false)
htg_ap = heating_system.additional_properties
htg_ap.heat_rated_cfm_per_ton = get_heat_cfm_per_ton(heating_system.compressor_type, use_cop)
@@ -1782,7 +1782,7 @@ def self.set_heat_curves_central_air_source(heating_system, use_cop = false)
# TODO
#
# @param heat_pump [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_heat_detailed_performance_data(heat_pump)
hp_ap = heat_pump.additional_properties
is_ducted = !heat_pump.distribution_system_idref.nil?
@@ -1837,7 +1837,7 @@ def self.set_heat_detailed_performance_data(heat_pump)
# TODO
#
# @param heat_pump [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_cool_detailed_performance_data(heat_pump)
hp_ap = heat_pump.additional_properties
is_ducted = !heat_pump.distribution_system_idref.nil?
@@ -1918,7 +1918,7 @@ def self.get_heat_capacity_ratios(heat_pump)
# TODO
#
# @param hvac_system [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.drop_intermediate_speeds(hvac_system)
# For variable-speed systems, we only want to model min/max speeds in E+.
# Here we drop any intermediate speeds that we may have added for other purposes (e.g. hvac sizing).
@@ -1993,7 +1993,7 @@ def self.get_heat_cfm_per_ton(compressor_type, use_cop_or_htg_sys = false)
# TODO
#
# @param heat_pump [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_curves_gshp(heat_pump)
hp_ap = heat_pump.additional_properties
@@ -2105,8 +2105,8 @@ def self.get_building_america_hvac_seasons(weather, latitude)
# @param model [OpenStudio::Model::Model] OpenStudio Model object
# @param fan [TODO] TODO
# @param hp_min_temp [TODO] TODO
- # @return [TODO] TODO
- def self.set_fan_power_ems_program(model, fan, hp_min_temp)
+ # @return [nil]
+ def self.add_fan_power_ems_program(model, fan, hp_min_temp)
# EMS is used to disable the fan power below the hp_min_temp; the backup heating
# system will be operating instead.
@@ -2159,8 +2159,8 @@ def self.set_fan_power_ems_program(model, fan, hp_min_temp)
# @param pump_w [TODO] TODO
# @param pump [TODO] TODO
# @param heating_object [TODO] TODO
- # @return [TODO] TODO
- def self.set_pump_power_ems_program(model, pump_w, pump, heating_object)
+ # @return [nil]
+ def self.add_pump_power_ems_program(model, pump_w, pump, heating_object)
# EMS is used to set the pump power.
# Without EMS, the pump power will vary according to the plant loop part load ratio
# (based on flow rate) rather than the boiler part load ratio (based on load).
@@ -2236,8 +2236,8 @@ def self.set_pump_power_ems_program(model, pump_w, pump, heating_object)
# @param clg_object [TODO] TODO
# @param backup_htg_object [TODO] TODO
# @param hpxml_object [TODO] TODO
- # @return [TODO] TODO
- def self.disaggregate_fan_or_pump(model, fan_or_pump, htg_object, clg_object, backup_htg_object, hpxml_object)
+ # @return [nil]
+ def self.add_fan_pump_disaggregation_ems_program(model, fan_or_pump, htg_object, clg_object, backup_htg_object, hpxml_object)
# Disaggregate into heating/cooling output energy use.
sys_id = hpxml_object.id
@@ -2385,16 +2385,15 @@ def self.disaggregate_fan_or_pump(model, fan_or_pump, htg_object, clg_object, ba
end
end
- # TODO
+ # Adjusts the HVAC load to the space when a dehumidifier serves less than 100% dehumidification load, since
+ # the EnergyPlus dehumidifier object can only model 100% dehumidification.
#
# @param fraction_served [TODO] TODO
# @param zone_hvac [TODO] TODO
# @param model [OpenStudio::Model::Model] OpenStudio Model object
# @param conditioned_space [TODO] TODO
- # @return [TODO] TODO
- def self.adjust_dehumidifier_load_EMS(fraction_served, zone_hvac, model, conditioned_space)
- # adjust hvac load to space when dehumidifier serves less than 100% dehumidification load. (With E+ dehumidifier object, it can only model 100%)
-
+ # @return [nil]
+ def self.add_dehumidifier_load_adjustment_ems_program(fraction_served, zone_hvac, model, conditioned_space)
# sensor
dehumidifier_sens_htg = Model.add_ems_sensor(
model,
@@ -2819,7 +2818,7 @@ def self.convert_net_to_gross_capacity_cop(net_cap, fan_power, mode, net_cop = n
# @param max_rated_fan_cfm [TODO] TODO
# @param weather_temp [TODO] TODO
# @param compressor_lockout_temp [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.process_neep_detailed_performance(detailed_performance_data, hvac_ap, mode, max_rated_fan_cfm, weather_temp, compressor_lockout_temp = nil)
data_array = Array.new(2) { Array.new }
detailed_performance_data.sort_by { |dp| dp.outdoor_temperature }.each do |data_point|
@@ -2868,7 +2867,7 @@ def self.process_neep_detailed_performance(detailed_performance_data, hvac_ap, m
# @param mode [TODO] TODO
# @param compressor_lockout_temp [TODO] TODO
# @param weather_temp [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.interpolate_to_odb_table_points(data_array, mode, compressor_lockout_temp, weather_temp)
# Set of data used for table lookup
data_array.each do |data|
@@ -2990,7 +2989,7 @@ def self.interpolate_to_odb_table_point(detailed_performance_data, capacity_desc
# @param data_array [TODO] TODO
# @param mode [TODO] TODO
# @param tol [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.add_data_point_adaptive_step_size(data_array, mode, tol = 0.1)
data_array.each do |data|
data_sorted = data.sort_by { |dp| dp.outdoor_temperature }
@@ -3030,7 +3029,7 @@ def self.add_data_point_adaptive_step_size(data_array, mode, tol = 0.1)
#
# @param data_array [TODO] TODO
# @param mode [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.correct_ft_cap_eir(data_array, mode)
# Add sensitivity to indoor conditions
# single speed cutler curve coefficients
@@ -3247,7 +3246,7 @@ def self.create_dx_cooling_coil(model, obj_name, cooling_system, max_rated_fan_c
clg_coil.additionalProperties.setFeature('HPXML_ID', cooling_system.id) # Used by reporting measure
if has_deadband_control
# Apply startup capacity degradation
- apply_capacity_degradation_EMS(model, clg_ap, clg_coil.name.get, true, cap_fff_curve_0, eir_fff_curve_0)
+ add_capacity_degradation_ems_proram(model, clg_ap, clg_coil.name.get, true, cap_fff_curve_0, eir_fff_curve_0)
end
return clg_coil
@@ -3413,7 +3412,7 @@ def self.create_dx_heating_coil(model, obj_name, heating_system, max_rated_fan_c
htg_coil.additionalProperties.setFeature('HPXML_ID', heating_system.id) # Used by reporting measure
if has_deadband_control
# Apply startup capacity degradation
- apply_capacity_degradation_EMS(model, htg_ap, htg_coil.name.get, false, cap_fff_curve_0, eir_fff_curve_0)
+ add_capacity_degradation_ems_proram(model, htg_ap, htg_coil.name.get, false, cap_fff_curve_0, eir_fff_curve_0)
end
return htg_coil
@@ -3422,7 +3421,7 @@ def self.create_dx_heating_coil(model, obj_name, heating_system, max_rated_fan_c
# TODO
#
# @param cooling_system [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_cool_rated_shrs_gross(cooling_system)
clg_ap = cooling_system.additional_properties
@@ -3525,9 +3524,9 @@ def self.get_supp_coil_avail_sch_actuator(model, htg_supp_coil)
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
# @param htg_coil [OpenStudio::Model::CoilHeatingDXSingleSpeed or OpenStudio::Model::CoilHeatingDXMultiSpeed] OpenStudio Heating Coil object
# @param is_onoff_thermostat_ddb [Boolean] Whether to apply on off thermostat deadband
- # @param cooling_system [HPXML::CoolingSystem or HPXML::HeatPump] HPXML Cooling System or HPXML Heat Pump object
+ # @param cooling_system [HPXML::CoolingSystem or HPXML::HeatPump] The HPXML cooling system or heat pump of interest
# @return [nil]
- def self.apply_supp_coil_EMS_for_ddb_thermostat(model, htg_supp_coil, control_zone, htg_coil, is_onoff_thermostat_ddb, cooling_system)
+ def self.add_supplemental_coil_ems_program(model, htg_supp_coil, control_zone, htg_coil, is_onoff_thermostat_ddb, cooling_system)
return if htg_supp_coil.nil?
return unless cooling_system.compressor_type == HPXML::HVACCompressorTypeSingleStage
return unless is_onoff_thermostat_ddb
@@ -3639,7 +3638,7 @@ def self.apply_supp_coil_EMS_for_ddb_thermostat(model, htg_supp_coil, control_zo
# @param cap_fff_curve [OpenStudio::Model::CurveQuadratic] OpenStudio CurveQuadratic object for heat pump capacity function of air flow rates
# @param eir_fff_curve [OpenStudio::Model::CurveQuadratic] OpenStudio CurveQuadratic object for heat pump eir function of air flow rates
# @return [nil]
- def self.apply_capacity_degradation_EMS(model, system_ap, coil_name, is_cooling, cap_fff_curve, eir_fff_curve)
+ def self.add_capacity_degradation_ems_proram(model, system_ap, coil_name, is_cooling, cap_fff_curve, eir_fff_curve)
# Note: Currently only available in 1 min time step
if is_cooling
c_d = system_ap.cool_c_d
@@ -3776,9 +3775,9 @@ def self.apply_capacity_degradation_EMS(model, system_ap, coil_name, is_cooling,
# @param htg_supp_coil [OpenStudio::Model::CoilHeatingElectric or OpenStudio::Model::CoilHeatingElectricMultiStage] OpenStudio Supplemental Heating Coil object
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
# @param is_onoff_thermostat_ddb [Boolean] Whether to apply on off thermostat deadband
- # @param cooling_system [HPXML::CoolingSystem or HPXML::HeatPump] HPXML Cooling System or HPXML Heat Pump object
+ # @param cooling_system [HPXML::CoolingSystem or HPXML::HeatPump] The HPXML cooling system or heat pump of interest
# @return [nil]
- def self.apply_two_speed_realistic_staging_EMS(model, unitary_system, htg_supp_coil, control_zone, is_onoff_thermostat_ddb, cooling_system)
+ def self.add_two_speed_staging_ems_program(model, unitary_system, htg_supp_coil, control_zone, is_onoff_thermostat_ddb, cooling_system)
# Note: Currently only available in 1 min time step
return unless is_onoff_thermostat_ddb
return unless cooling_system.compressor_type == HPXML::HVACCompressorTypeTwoStage
@@ -3930,14 +3929,14 @@ def self.apply_two_speed_realistic_staging_EMS(model, unitary_system, htg_supp_c
# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings
# @param air_loop_unitary [OpenStudio::Model::AirLoopHVACUnitarySystem] Air loop for the HVAC system
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
- # @param heating_system [HPXML::HeatingSystem or HPXML::HeatPump] HPXML Heating System or HPXML Heat Pump object
- # @param cooling_system [HPXML::CoolingSystem or HPXML::HeatPump] HPXML Cooling System or HPXML Heat Pump object
+ # @param heating_system [HPXML::HeatingSystem or HPXML::HeatPump] The HPXML heating system or heat pump of interest
+ # @param cooling_system [HPXML::CoolingSystem or HPXML::HeatPump] The HPXML cooling system or heat pump of interest
# @param htg_supp_coil [OpenStudio::Model::CoilHeatingElectric or CoilHeatingElectricMultiStage] OpenStudio Supplemental Heating Coil object
# @param clg_coil [OpenStudio::Model::CoilCoolingDXMultiSpeed] OpenStudio MultiStage Cooling Coil object
# @param htg_coil [OpenStudio::Model::CoilHeatingDXMultiSpeed] OpenStudio MultiStage Heating Coil object
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
# @return [nil]
- def self.apply_max_power_EMS(model, runner, air_loop_unitary, control_zone, heating_system, cooling_system, htg_supp_coil, clg_coil, htg_coil, schedules_file)
+ def self.add_variable_speed_power_ems_program(model, runner, air_loop_unitary, control_zone, heating_system, cooling_system, htg_supp_coil, clg_coil, htg_coil, schedules_file)
return if schedules_file.nil?
return if clg_coil.nil? && htg_coil.nil?
@@ -4264,7 +4263,7 @@ def self.apply_max_power_EMS(model, runner, air_loop_unitary, control_zone, heat
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
# @param htg_coil [OpenStudio::Model::CoilHeatingDXSingleSpeed or OpenStudio::Model::CoilHeatingDXMultiSpeed] OpenStudio Heating Coil object
# @return [nil]
- def self.add_backup_staging_EMS(model, unitary_system, htg_supp_coil, control_zone, htg_coil)
+ def self.add_backup_staging_ems_program(model, unitary_system, htg_supp_coil, control_zone, htg_coil)
return unless htg_supp_coil.is_a? OpenStudio::Model::CoilHeatingElectricMultiStage
# Note: Currently only available in 1 min time step
@@ -4420,7 +4419,7 @@ def self.calc_plr_coefficients(c_d)
# TODO
#
# @param cooling_system [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_cool_c_d(cooling_system)
clg_ap = cooling_system.additional_properties
@@ -4448,7 +4447,7 @@ def self.set_cool_c_d(cooling_system)
# TODO
#
# @param heating_system [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_heat_c_d(heating_system)
htg_ap = heating_system.additional_properties
@@ -4472,12 +4471,13 @@ def self.set_heat_c_d(heating_system)
htg_ap.heat_plf_fplr_spec = [calc_plr_coefficients(htg_ap.heat_c_d)] * num_speeds
end
- # TODO
+ # Calculates rated CEER (newer metric) from rated EER (older metric).
#
- # @param cooling_system [TODO] TODO
- # @return [TODO] TODO
+ # Source: http://documents.dps.ny.gov/public/Common/ViewDoc.aspx?DocRefId=%7BB6A57FC0-6376-4401-92BD-D66EC1930DCF%7D
+ #
+ # @param cooling_system [HPXML::CoolingSystem or HPXML::HeatPump] The HPXML cooling system or heat pump of interest
+ # @return [Double] The CEER value (Btu/Wh)
def self.calc_ceer_from_eer(cooling_system)
- # Reference: http://documents.dps.ny.gov/public/Common/ViewDoc.aspx?DocRefId=%7BB6A57FC0-6376-4401-92BD-D66EC1930DCF%7D
return cooling_system.cooling_efficiency_eer / 1.01
end
@@ -4485,7 +4485,7 @@ def self.calc_ceer_from_eer(cooling_system)
#
# @param hvac_system [TODO] TODO
# @param use_eer_cop [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_fan_power_rated(hvac_system, use_eer_cop)
hvac_ap = hvac_system.additional_properties
@@ -4525,7 +4525,7 @@ def self.get_unitary_system_from_air_loop_hvac(air_loop)
#
# @param heat_pump [TODO] TODO
# @param weather [WeatherFile] Weather object containing EPW information
- # @return [TODO] TODO
+ # @return [nil]
def self.set_gshp_assumptions(heat_pump, weather)
hp_ap = heat_pump.additional_properties
geothermal_loop = heat_pump.geothermal_loop
@@ -4619,7 +4619,7 @@ def self.get_sequential_load_schedule(model, fractions, unavailable_periods)
# @param hvac_sequential_load_fracs [Array] Array of daily fractions of remaining heating/cooling load to bet met by the HVAC system
# @param hvac_unavailable_periods [Hash] Map of htg/clg => HPXML::UnavailablePeriods for heating/cooling
# @param heating_system [TODO] TODO
- # @return [TODO] TODO
+ # @return [nil]
def self.set_sequential_load_fractions(model, control_zone, hvac_object, hvac_sequential_load_fracs, hvac_unavailable_periods, heating_system = nil)
heating_sch = get_sequential_load_schedule(model, hvac_sequential_load_fracs[:htg], hvac_unavailable_periods[:htg])
cooling_sch = get_sequential_load_schedule(model, hvac_sequential_load_fracs[:clg], hvac_unavailable_periods[:clg])
@@ -4679,7 +4679,7 @@ def self.set_sequential_load_fractions(model, control_zone, hvac_object, hvac_se
#
# @param heat_pump [TODO] TODO
# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings
- # @return [TODO] TODO
+ # @return [nil]
def self.set_heat_pump_temperatures(heat_pump, runner = nil)
hp_ap = heat_pump.additional_properties
@@ -4757,8 +4757,8 @@ def self.get_charge_fault_heating_coeff(f_chg)
# @param mode [TODO] TODO
# @param defect_ratio [TODO] TODO
# @param hvac_ap [TODO] TODO
- # @return [TODO] TODO
- def self.add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, airflow_rated_defect_ratio, clg_or_htg_coil, model, f_chg, obj_name, mode, defect_ratio, hvac_ap)
+ # @return [nil]
+ def self.add_installation_quality_program(fault_program, tin_sensor, tout_sensor, airflow_rated_defect_ratio, clg_or_htg_coil, model, f_chg, obj_name, mode, defect_ratio, hvac_ap)
if mode == :clg
if clg_or_htg_coil.is_a? OpenStudio::Model::CoilCoolingDXSingleSpeed
num_speeds = 1
@@ -4969,7 +4969,7 @@ def self.add_install_quality_calculations(fault_program, tin_sensor, tout_sensor
# @param htg_coil [TODO] TODO
# @param clg_coil [TODO] TODO
# @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone
- # @return [TODO] TODO
+ # @return [nil]
def self.apply_installation_quality(model, heating_system, cooling_system, unitary_system, htg_coil, clg_coil, control_zone)
if not cooling_system.nil?
charge_defect_ratio = cooling_system.charge_defect_ratio
@@ -5031,11 +5031,11 @@ def self.apply_installation_quality(model, heating_system, cooling_system, unita
fault_program.addLine("Set F_CH = #{f_chg.round(3)}")
if not cool_airflow_rated_defect_ratio.empty?
- add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, cool_airflow_rated_defect_ratio, clg_coil, model, f_chg, obj_name, :clg, cool_airflow_defect_ratio, clg_ap)
+ add_installation_quality_program(fault_program, tin_sensor, tout_sensor, cool_airflow_rated_defect_ratio, clg_coil, model, f_chg, obj_name, :clg, cool_airflow_defect_ratio, clg_ap)
end
if not heat_airflow_rated_defect_ratio.empty?
- add_install_quality_calculations(fault_program, tin_sensor, tout_sensor, heat_airflow_rated_defect_ratio, htg_coil, model, f_chg, obj_name, :htg, heat_airflow_defect_ratio, htg_ap)
+ add_installation_quality_program(fault_program, tin_sensor, tout_sensor, heat_airflow_rated_defect_ratio, htg_coil, model, f_chg, obj_name, :htg, heat_airflow_defect_ratio, htg_ap)
end
Model.add_ems_program_calling_manager(
@@ -5217,7 +5217,7 @@ def self.apply_advanced_defrost(model, htg_coil, air_loop_unitary, conditioned_s
# TODO
#
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
- # @return [TODO] TODO
+ # @return [nil]
def self.apply_shared_systems(hpxml_bldg)
applied_clg = apply_shared_cooling_systems(hpxml_bldg)
applied_htg = apply_shared_heating_systems(hpxml_bldg)
@@ -5484,7 +5484,7 @@ def self.get_hpxml_hvac_systems(hpxml_bldg)
# Ensure that no capacities/airflows are zero in order to prevent potential E+ errors.
#
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
- # @return [TODO] TODO
+ # @return [nil]
def self.ensure_nonzero_sizing_values(hpxml_bldg)
min_capacity = 1.0 # Btuh
min_airflow = 3.0 # cfm; E+ min airflow is 0.001 m3/s
@@ -5535,7 +5535,7 @@ def self.ensure_nonzero_sizing_values(hpxml_bldg)
#
# @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit
# @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file)
- # @return [TODO] TODO
+ # @return [nil]
def self.apply_unit_multiplier(hpxml_bldg, hpxml_header)
unit_multiplier = hpxml_bldg.building_construction.number_of_units
hpxml_bldg.heating_systems.each do |htg_sys|
@@ -5577,13 +5577,15 @@ def self.apply_unit_multiplier(hpxml_bldg, hpxml_header)
end
end
- # TODO
+ # Calculates rated SEER (older metric) from rated SEER2 (newer metric).
#
- # @param seer2 [TODO] TODO
- # @param is_ducted [TODO] TODO
- # @return [TODO] TODO
+ # Source: ANSI/RESNET/ICC 301 Table 4.4.4.1(1) SEER2/HSPF2 Conversion Factors
+ # This is based on a regression of products, not a translation.
+ #
+ # @param seer2 [Double] Cooling efficiency (Btu/Wh)
+ # @param is_ducted [Boolean] True if a ducted HVAC system
+ # @return [Double] SEER value (Btu/Wh)
def self.calc_seer_from_seer2(seer2, is_ducted)
- # ANSI/RESNET/ICC 301 Table 4.4.4.1(1) SEER2/HSPF2 Conversion Factors
# Note: There are less common system types (packaged, small duct high velocity,
# and space-constrained) that we don't handle here.
if is_ducted # Ducted split system
@@ -5593,13 +5595,15 @@ def self.calc_seer_from_seer2(seer2, is_ducted)
end
end
- # TODO
+ # Calculates rated HSPF (older metric) from rated HSPF2 (newer metric).
#
- # @param hspf2 [TODO] TODO
- # @param is_ducted [TODO] TODO
- # @return [TODO] TODO
+ # Source: ANSI/RESNET/ICC 301 Table 4.4.4.1(1) SEER2/HSPF2 Conversion Factors
+ # This is based on a regression of products, not a translation.
+ #
+ # @param hspf2 [Double] Heating efficiency (Btu/Wh)
+ # @param is_ducted [Boolean] True if a ducted HVAC system
+ # @return [Double] HSPF value (Btu/Wh)
def self.calc_hspf_from_hspf2(hspf2, is_ducted)
- # ANSI/RESNET/ICC 301 Table 4.4.4.1(1) SEER2/HSPF2 Conversion Factors
# Note: There are less common system types (packaged, small duct high velocity,
# and space-constrained) that we don't handle here.
if is_ducted # Ducted split system
diff --git a/HPXMLtoOpenStudio/resources/lighting.rb b/HPXMLtoOpenStudio/resources/lighting.rb
index 585b239246..53a0dfec1f 100644
--- a/HPXMLtoOpenStudio/resources/lighting.rb
+++ b/HPXMLtoOpenStudio/resources/lighting.rb
@@ -205,14 +205,14 @@ def self.apply(runner, model, spaces, hpxml_bldg, hpxml_header, schedules_file)
end
end
- # TODO
+ # Calculates the annual interior lighting energy use based on the conditioned floor area and types of lamps.
#
# @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions
# @param cfa [Double] Conditioned floor area in the dwelling unit (ft2)
- # @param f_int_cfl [TODO] TODO
- # @param f_int_lfl [TODO] TODO
- # @param f_int_led [TODO] TODO
- # @return [TODO] TODO
+ # @param f_int_cfl [Double] Fraction of interior lighting that is compact fluorescent (CFL)
+ # @param f_int_lfl [Double] Fraction of interior lighting that is linear fluorescent (LFL)
+ # @param f_int_led [Double] Fraction of interior lighting that is light-emitting diode (LED)
+ # @return [Double or nil] Annual interior lighting energy use (kWh/yr)
def self.calc_interior_energy(eri_version, cfa, f_int_cfl, f_int_lfl, f_int_led)
return if f_int_cfl.nil? || f_int_lfl.nil? || f_int_led.nil?
@@ -249,14 +249,14 @@ def self.calc_interior_energy(eri_version, cfa, f_int_cfl, f_int_lfl, f_int_led)
return int_kwh
end
- # TODO
+ # Calculates the annual exterior lighting energy use based on the conditioned floor area and types of lamps.
#
# @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions
# @param cfa [Double] Conditioned floor area in the dwelling unit (ft2)
- # @param f_ext_cfl [TODO] TODO
- # @param f_ext_lfl [TODO] TODO
- # @param f_ext_led [TODO] TODO
- # @return [TODO] TODO
+ # @param f_ext_cfl [Double] Fraction of exterior lighting that is compact fluorescent (CFL)
+ # @param f_ext_lfl [Double] Fraction of exterior lighting that is linear fluorescent (LFL)
+ # @param f_ext_led [Double] Fraction of exterior lighting that is light-emitting diode (LED)
+ # @return [Double or nil] Annual exterior lighting energy use (kWh/yr)
def self.calc_exterior_energy(eri_version, cfa, f_ext_cfl, f_ext_lfl, f_ext_led)
return if f_ext_cfl.nil? || f_ext_lfl.nil? || f_ext_led.nil?
@@ -293,14 +293,14 @@ def self.calc_exterior_energy(eri_version, cfa, f_ext_cfl, f_ext_lfl, f_ext_led)
return ext_kwh
end
- # TODO
+ # Calculates the annual garage lighting energy use based on the garage area and types of lamps.
#
# @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions
- # @param gfa [TODO] TODO
- # @param f_grg_cfl [TODO] TODO
- # @param f_grg_lfl [TODO] TODO
- # @param f_grg_led [TODO] TODO
- # @return [TODO] TODO
+ # @param gfa [Double] Garage floor area (ft2)
+ # @param f_grg_cfl [Double] Fraction of garage lighting that is compact fluorescent (CFL)
+ # @param f_grg_lfl [Double] Fraction of garage lighting that is linear fluorescent (LFL)
+ # @param f_grg_led [Double] Fraction of garage lighting that is light-emitting diode (LED)
+ # @return [Double or nil] Annual garage lighting energy use (kWh/yr)
def self.calc_garage_energy(eri_version, gfa, f_grg_cfl, f_grg_lfl, f_grg_led)
return if f_grg_cfl.nil? || f_grg_lfl.nil? || f_grg_led.nil?
diff --git a/HPXMLtoOpenStudio/resources/misc_loads.rb b/HPXMLtoOpenStudio/resources/misc_loads.rb
index 6c972f5a1b..2e31b90403 100644
--- a/HPXMLtoOpenStudio/resources/misc_loads.rb
+++ b/HPXMLtoOpenStudio/resources/misc_loads.rb
@@ -36,12 +36,12 @@ def self.apply_plug_loads(runner, model, spaces, hpxml_bldg, hpxml_header, sched
#
# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings
# @param model [OpenStudio::Model::Model] OpenStudio Model object
- # @param plug_load [TODO] TODO
+ # @param plug_load [HPXML::PlugLoad] The HPXML plug load of interest
# @param obj_name [String] Name for the OpenStudio object
# @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
# @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies
- # @param apply_ashrae140_assumptions [TODO] TODO
+ # @param apply_ashrae140_assumptions [Boolean] True if an ASHRAE 140 test case where we want to override our normal assumptions
# @return [nil]
def self.apply_plug_load(runner, model, plug_load, obj_name, spaces, schedules_file, unavailable_periods, apply_ashrae140_assumptions)
kwh = 0
@@ -132,7 +132,7 @@ def self.apply_fuel_loads(runner, model, spaces, hpxml_bldg, hpxml_header, sched
#
# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings
# @param model [OpenStudio::Model::Model] OpenStudio Model object
- # @param fuel_load [TODO] TODO
+ # @param fuel_load [HPXML::FuelLoad] The HPXML fuel load of interest
# @param obj_name [String] Name for the OpenStudio object
# @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
@@ -213,7 +213,7 @@ def self.apply_pools_and_permanent_spas(runner, model, spaces, hpxml_bldg, hpxml
#
# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings
# @param model [OpenStudio::Model::Model] OpenStudio Model object
- # @param pool_or_spa [TODO] TODO
+ # @param pool_or_spa [HPXML::Pool or HPXML::PermanentSpa] The HPXML pool or permanent space of interest
# @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
# @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies
@@ -303,7 +303,7 @@ def self.apply_pool_or_permanent_spa_heater(runner, model, pool_or_spa, spaces,
#
# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings
# @param model [OpenStudio::Model::Model] OpenStudio Model object
- # @param pool_or_spa [TODO] TODO
+ # @param pool_or_spa [HPXML::Pool or HPXML::PermanentSpa] The HPXML pool or permanent space of interest
# @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects
# @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files
# @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies
diff --git a/HPXMLtoOpenStudio/resources/xmlhelper.rb b/HPXMLtoOpenStudio/resources/xmlhelper.rb
index bcbf52284b..05b66f4b7a 100644
--- a/HPXMLtoOpenStudio/resources/xmlhelper.rb
+++ b/HPXMLtoOpenStudio/resources/xmlhelper.rb
@@ -2,30 +2,32 @@
# Collection of helper methods related to XML reading/writing.
module XMLHelper
- # Adds the child element with 'element_name' and sets its value. Returns the
- # child element.
+ # Adds the child element with 'element_name' and sets its value. If the value
+ # has been defaulted, the dataSource='software' attribute will be assigned to
+ # the element.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @param value [TODO] TODO
- # @param datatype [TODO] TODO
- # @param defaulted [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the addition
+ # @param element_name [String] Name of the element to add
+ # @param value [*] The value for the element (could be a string, float, boolean, etc.)
+ # @param datatype [Symbol] Datatype of the element (:integer, :float, :boolean, or :string)
+ # @param defaulted [Boolean] Whether the value has been defaulted by OS-HPXML
+ # @return [Oga::XML::Element] The added element
def self.add_element(parent, element_name, value = nil, datatype = nil, defaulted = false)
added = XMLHelper.insert_element(parent, element_name, -1, value, datatype, defaulted)
return added
end
- # Inserts the child element with 'element_name' and sets its value. Returns the
- # child element.
+ # Inserts the child element with 'element_name' and sets its value. If the value
+ # has been defaulted, the dataSource='software' attribute will be assigned to
+ # the element.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @param index [TODO] TODO
- # @param value [TODO] TODO
- # @param datatype [TODO] TODO
- # @param defaulted [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the element to insert
+ # @param index [Integer] The position of the element to be inserted
+ # @param value [*] The value for the element (could be a string, float, boolean, etc.)
+ # @param datatype [Symbol] Datatype of the element (:integer, :float, :boolean, or :string)
+ # @param defaulted [Boolean] Whether the value has been defaulted by OS-HPXML
+ # @return [Oga::XML::Element] The inserted element
def self.insert_element(parent, element_name, index = 0, value = nil, datatype = nil, defaulted = false)
added = Oga::XML::Element.new(name: element_name)
if index == -1
@@ -53,14 +55,14 @@ def self.insert_element(parent, element_name, index = 0, value = nil, datatype =
end
# Adds the child element with 'element_name' to a single extension element and
- # sets its value. Returns the extension element.
+ # sets its value. If the extension element already exists, it will be reused.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @param value [TODO] TODO
- # @param datatype [TODO] TODO
- # @param defaulted [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the extension element to add
+ # @param value [*] The value for the element (could be a string, float, boolean, etc.)
+ # @param datatype [Symbol] Datatype of the element (:integer, :float, :boolean, or :string)
+ # @param defaulted [Boolean] Whether the value has been defaulted by OS-HPXML
+ # @return [Oga::XML::Element] The added extension element
def self.add_extension(parent, element_name, value = nil, datatype = nil, defaulted = false)
extension = XMLHelper.create_elements_as_needed(parent, ['extension'])
return XMLHelper.add_element(extension, element_name, value, datatype, defaulted)
@@ -68,11 +70,10 @@ def self.add_extension(parent, element_name, value = nil, datatype = nil, defaul
# Creates a hierarchy of elements under the parent element based on the supplied
# list of element names. If a given child element already exists, it is reused.
- # Returns the final element.
#
- # @param parent [TODO] TODO
- # @param element_names [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_names element_name [String] Name of the element to add
+ # @return [Oga::XML::Element] The final created element
def self.create_elements_as_needed(parent, element_names)
this_parent = parent
element_names.each do |element_name|
@@ -84,11 +85,11 @@ def self.create_elements_as_needed(parent, element_names)
return this_parent
end
- # Deletes the child element with element_name. Returns the deleted element.
+ # Deletes the child element with element_name.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the element to delete
+ # @return [Oga::XML::Element] The deleted element
def self.delete_element(parent, element_name)
element = nil
while !parent.at_xpath(element_name).nil?
@@ -98,12 +99,12 @@ def self.delete_element(parent, element_name)
return last_element
end
- # Returns the value of 'element_name' in the parent element or nil.
+ # Gets the value of 'element_name' in the parent element or nil.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @param datatype [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the element to get the value of
+ # @param datatype [Symbol] Datatype of the element (:integer, :float, :boolean, or :string)
+ # @return [* or nil] The value of the element in the specified datatype
def self.get_value(parent, element_name, datatype)
element = parent.at_xpath(element_name)
if element.nil?
@@ -125,12 +126,13 @@ def self.get_value(parent, element_name, datatype)
return value
end
- # Returns the value(s) of 'element_name' in the parent element or [].
+ # Gets the value(s) of 'element_name' in the parent element or [].
+ # Use for elements that can occur multiple times.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @param datatype [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the element to get the values of
+ # @param datatype [Symbol] Datatype of the element (:integer, :float, :boolean, or :string)
+ # @return [Array<*>] Array of values in the specified datatype
def self.get_values(parent, element_name, datatype)
values = []
parent.xpath(element_name).each do |value|
@@ -152,30 +154,31 @@ def self.get_values(parent, element_name, datatype)
return values
end
- # Returns the element in the parent element.
+ # Gets the element with 'element_name' in the parent element.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the element to get
+ # @return [Oga::XML::Element] The element of interest
def self.get_element(parent, element_name)
return parent.at_xpath(element_name)
end
- # Returns the element in the parent element.
+ # Gets the elements with 'element_name' in the parent element.
+ # Use for elements that can occur multiple times.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the elements to get
+ # @return [Array] The elements of interest
def self.get_elements(parent, element_name)
return parent.xpath(element_name)
end
- # Returns the name of the first child element of the 'element_name'
+ # Gets the name of the first child element of the 'element_name'
# element on the parent element.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the element with the child element to get
+ # @return [String or nil] Name of the child element, or nil if no child element
def self.get_child_name(parent, element_name)
element = parent.at_xpath(element_name)
return if element.nil? || element.children.nil?
@@ -187,76 +190,73 @@ def self.get_child_name(parent, element_name)
end
end
- # Returns true if the element exists.
+ # Checks whether the element has a child element with 'element_name'.
#
- # @param parent [TODO] TODO
- # @param element_name [TODO] TODO
- # @return [TODO] TODO
+ # @param parent [Oga::XML::Element] Parent element for the insertion
+ # @param element_name [String] Name of the element to check for the presence of
+ # @return [Boolean] True if the element exists
def self.has_element(parent, element_name)
element = parent.at_xpath(element_name)
return !element.nil?
end
- # Returns the attribute added
+ # Adds an attribute to the specified element.
#
- # @param element [TODO] TODO
- # @param attr_name [TODO] TODO
- # @param attr_val [TODO] TODO
- # @return [TODO] TODO
+ # @param element [Oga::XML::Element] Element to add the attribute to
+ # @param attr_name [String] Name of the attribute
+ # @param attr_val [*] Value for the attribute
+ # @return [nil]
def self.add_attribute(element, attr_name, attr_val)
- added = element.set(attr_name, attr_val)
- return added
+ element.set(attr_name, attr_val)
end
- # Returns the value of the attribute
+ # Gets the value of the specified attribute for the given element.
#
- # @param element [TODO] TODO
- # @param attr_name [TODO] TODO
- # @return [TODO] TODO
+ # @param element [Oga::XML::Element] Element with the attribute whose value we want
+ # @param attr_name [String] Name of the attribute
+ # @return [String or nil] The value of the attribute, or nil if not found
def self.get_attribute_value(element, attr_name)
return if element.nil?
return element.get(attr_name)
end
- # TODO
+ # Deletes the specified attribute for the given element.
#
- # @param element [TODO] TODO
- # @param attr_name [TODO] TODO
- # @return [TODO] TODO
+ # @param element [Oga::XML::Element] Element with the attribute we want to delete
+ # @param attr_name [String] Name of the attribute
+ # @return [nil]
def self.delete_attribute(element, attr_name)
return if element.nil?
element.unset(attr_name)
end
- # TODO
+ # Creates an empty XML document.
#
- # @param version [TODO] TODO
- # @param encoding [TODO] TODO
- # @param standalone [TODO] TODO
- # @return [TODO] TODO
- def self.create_doc(version = nil, encoding = nil, standalone = nil)
- doc = Oga::XML::Document.new(xml_declaration: Oga::XML::XmlDeclaration.new(version: version, encoding: encoding, standalone: standalone)) # Oga.parse_xml
+ # @return [Oga::XML::Document] The new XML document
+ def self.create_doc()
+ xml_declaration = Oga::XML::XmlDeclaration.new(version: '1.0', encoding: 'UTF-8')
+ doc = Oga::XML::Document.new(xml_declaration: xml_declaration) # Oga.parse_xml
return doc
end
- # TODO
+ # Obtains the XML document for the XML file at the specified path.
#
# @param hpxml_path [String] Path to the HPXML file
- # @return [TODO] TODO
+ # @return [Oga::XML::Document] The XML document
def self.parse_file(hpxml_path)
file_read = File.read(hpxml_path)
hpxml_doc = Oga.parse_xml(file_read)
return hpxml_doc
end
- # TODO
+ # Writes the XML file for the given XML document.
#
# @param doc [Oga::XML::Document] Oga XML Document object
- # @param out_path [TODO] TODO
- # @return [TODO] TODO
- def self.write_file(doc, out_path)
+ # @param hpxml_path [String] Path to the HPXML file
+ # @return [String] The written XML file as a string
+ def self.write_file(doc, hpxml_path)
doc_s = doc.to_xml.delete("\r")
# Manually apply pretty-printing (indentation and newlines)
@@ -298,10 +298,10 @@ def self.write_file(doc, out_path)
doc_s.gsub!('"', '"')
# Write XML file
- if not Dir.exist? File.dirname(out_path)
- FileUtils.mkdir_p(File.dirname(out_path))
+ if not Dir.exist? File.dirname(hpxml_path)
+ FileUtils.mkdir_p(File.dirname(hpxml_path))
end
- File.open(out_path, 'w', newline: :crlf) do |f|
+ File.open(hpxml_path, 'w', newline: :crlf) do |f|
f << doc_s
end
@@ -309,12 +309,12 @@ def self.write_file(doc, out_path)
end
end
-# TODO
+# Converts a value to float; throws an error if it can't be converted.
#
-# @param value [TODO] TODO
-# @param parent [TODO] TODO
-# @param element_name [TODO] TODO
-# @return [TODO] TODO
+# @param value [*] The value in any datatype (float, integer, string)
+# @param parent [Oga::XML::Element] Parent element for the error message
+# @param element_name [String] Name of the element for the error message
+# @return [Double] The value converted to double
def to_float(value, parent, element_name)
begin
return Float(value)
@@ -323,12 +323,12 @@ def to_float(value, parent, element_name)
end
end
-# TODO
+# Converts a value to integer; throws an error if it can't be converted.
#
-# @param value [TODO] TODO
-# @param parent [TODO] TODO
-# @param element_name [TODO] TODO
-# @return [TODO] TODO
+# @param value [*] The value in any datatype (float, integer, string)
+# @param parent [Oga::XML::Element] Parent element for the error message
+# @param element_name [String] Name of the element for the error message
+# @return [Integer] The value converted to integer
def to_integer(value, parent, element_name)
begin
value = Float(value)
@@ -342,12 +342,12 @@ def to_integer(value, parent, element_name)
end
end
-# TODO
+# Converts a value to boolean; throws an error if it can't be converted.
#
-# @param value [TODO] TODO
-# @param parent [TODO] TODO
-# @param element_name [TODO] TODO
-# @return [TODO] TODO
+# @param value [*] The value in any datatype (float, integer, string)
+# @param parent [Oga::XML::Element] Parent element for the error message
+# @param element_name [String] Name of the element for the error message
+# @return [Boolean] The value converted to boolean
def to_boolean(value, parent, element_name)
if value.is_a? TrueClass
return true
@@ -362,36 +362,36 @@ def to_boolean(value, parent, element_name)
fail "Cannot convert '#{value}' to boolean for #{parent.name}/#{element_name}."
end
-# TODO
+# Converts a value to float or returns nil if nil provided; throws an error if it can't be converted.
#
-# @param value [TODO] TODO
-# @param parent [TODO] TODO
-# @param element_name [TODO] TODO
-# @return [TODO] TODO
+# @param value [*] The value in any datatype (float, integer, string)
+# @param parent [Oga::XML::Element] Parent element for the error message
+# @param element_name [String] Name of the element for the error message
+# @return [Double or nil] The value converted to double, or nil
def to_float_or_nil(value, parent, element_name)
return if value.nil?
return to_float(value, parent, element_name)
end
-# TODO
+# Converts a value to integer or returns nil if nil provided; throws an error if it can't be converted.
#
-# @param value [TODO] TODO
-# @param parent [TODO] TODO
-# @param element_name [TODO] TODO
-# @return [TODO] TODO
+# @param value [*] The value in any datatype (float, integer, string)
+# @param parent [Oga::XML::Element] Parent element for the error message
+# @param element_name [String] Name of the element for the error message
+# @return [Integer] The value converted to integer, or nil
def to_integer_or_nil(value, parent, element_name)
return if value.nil?
return to_integer(value, parent, element_name)
end
-# TODO
+# Converts a value to boolean or returns nil if nil provided; throws an error if it can't be converted.
#
-# @param value [TODO] TODO
-# @param parent [TODO] TODO
-# @param element_name [TODO] TODO
-# @return [TODO] TODO
+# @param value [*] The value in any datatype (float, integer, string)
+# @param parent [Oga::XML::Element] Parent element for the error message
+# @param element_name [String] Name of the element for the error message
+# @return [Boolean] The value converted to boolean
def to_boolean_or_nil(value, parent, element_name)
return if value.nil?
diff --git a/docs/source/workflow_inputs.rst b/docs/source/workflow_inputs.rst
index ed22ed8844..31cfa0fd0e 100644
--- a/docs/source/workflow_inputs.rst
+++ b/docs/source/workflow_inputs.rst
@@ -2442,7 +2442,7 @@ Each central air conditioner is entered as a ``/HPXML/Building/BuildingDetails/S
``CoolingCapacity`` double Btu/hr >= 0 No autosized [#]_ Cooling output capacity
``CompressorType`` string See [#]_ No See [#]_ Type of compressor
``FractionCoolLoadServed`` double frac >= 0, <= 1 [#]_ Yes Fraction of cooling load served
- ``AnnualCoolingEfficiency[Units="SEER" or Units="SEER2"]/Value`` double Btu/Wh or # > 0 Yes Rated efficiency [#]_
+ ``AnnualCoolingEfficiency[Units="SEER" or Units="SEER2"]/Value`` double Btu/Wh > 0 Yes Rated efficiency [#]_
``SensibleHeatFraction`` double frac > 0.5, <= 1 No See [#]_ Sensible heat fraction
``CoolingDetailedPerformanceData`` element No Cooling detailed performance data [#]_
``extension/FanPowerWattsPerCFM`` double W/cfm >= 0 No See [#]_ Blower fan efficiency at maximum fan speed [#]_