diff --git a/BuildResidentialHPXML/measure.rb b/BuildResidentialHPXML/measure.rb index 933e208f99..2e0fde15a4 100644 --- a/BuildResidentialHPXML/measure.rb +++ b/BuildResidentialHPXML/measure.rb @@ -2366,7 +2366,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument solar_thermal_system_type_choices = OpenStudio::StringVector.new solar_thermal_system_type_choices << 'none' - solar_thermal_system_type_choices << HPXML::SolarThermalSystemType + solar_thermal_system_type_choices << HPXML::SolarThermalSystemTypeHotWater solar_thermal_collector_loop_type_choices = OpenStudio::StringVector.new solar_thermal_collector_loop_type_choices << HPXML::SolarThermalLoopTypeDirect @@ -2374,10 +2374,10 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument solar_thermal_collector_loop_type_choices << HPXML::SolarThermalLoopTypeThermosyphon solar_thermal_collector_type_choices = OpenStudio::StringVector.new - solar_thermal_collector_type_choices << HPXML::SolarThermalTypeEvacuatedTube - solar_thermal_collector_type_choices << HPXML::SolarThermalTypeSingleGlazing - solar_thermal_collector_type_choices << HPXML::SolarThermalTypeDoubleGlazing - solar_thermal_collector_type_choices << HPXML::SolarThermalTypeICS + solar_thermal_collector_type_choices << HPXML::SolarThermalCollectorTypeEvacuatedTube + solar_thermal_collector_type_choices << HPXML::SolarThermalCollectorTypeSingleGlazing + solar_thermal_collector_type_choices << HPXML::SolarThermalCollectorTypeDoubleGlazing + solar_thermal_collector_type_choices << HPXML::SolarThermalCollectorTypeICS arg = OpenStudio::Measure::OSArgument::makeChoiceArgument('solar_thermal_system_type', solar_thermal_system_type_choices, true) arg.setDisplayName('Solar Thermal: System Type') @@ -2401,7 +2401,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument arg = OpenStudio::Measure::OSArgument::makeChoiceArgument('solar_thermal_collector_type', solar_thermal_collector_type_choices, true) arg.setDisplayName('Solar Thermal: Collector Type') arg.setDescription('The collector type of the solar thermal system.') - arg.setDefaultValue(HPXML::SolarThermalTypeEvacuatedTube) + arg.setDefaultValue(HPXML::SolarThermalCollectorTypeEvacuatedTube) args << arg arg = OpenStudio::Measure::OSArgument::makeDoubleArgument('solar_thermal_collector_azimuth', true) @@ -3471,7 +3471,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument # Define what happens when the measure is run. # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [Boolean] true if successful def run(model, runner, user_arguments) @@ -3794,7 +3794,7 @@ def argument_errors(args) module HPXMLFile # Create the closed-form geometry, and then call individual set_xxx methods # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param args [Hash] Map of :argument_name => value # @param epw_path [String] Path to the EPW weather file @@ -3923,7 +3923,7 @@ def self.need_weather_based_on_args(args) # Check for errors in hpxml, and validate hpxml_doc against hpxml_path # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml [HPXML] HPXML object # @param hpxml_doc [Oga::XML::Element] Root XML element of the HPXML document # @param hpxml_path [TODO] TODO @@ -3964,7 +3964,7 @@ def self.validate_hpxml(runner, hpxml, hpxml_doc, hpxml_path) # Create 3D geometry (surface, subsurfaces) for a given unit type # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param args [Hash] Map of :argument_name => value # @return [Boolean] True if successful @@ -4058,7 +4058,7 @@ def self.unavailable_period_exists(hpxml, column_name, begin_month, begin_day, b # - emissions scenarios # - utility bill scenarios # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml [HPXML] HPXML object # @param args [Hash] Map of :argument_name => value # @return [Boolean] true if no errors, otherwise false @@ -6571,7 +6571,7 @@ def self.set_hot_water_distribution(hpxml_bldg, args) standard_piping_length = args[:hot_water_distribution_standard_piping_length] else recirculation_control_type = args[:hot_water_distribution_recirc_control_type] - recirculation_piping_length = args[:hot_water_distribution_recirc_piping_length] + recirculation_piping_loop_length = args[:hot_water_distribution_recirc_piping_length] recirculation_branch_piping_length = args[:hot_water_distribution_recirc_branch_piping_length] recirculation_pump_power = args[:hot_water_distribution_recirc_pump_power] end @@ -6580,7 +6580,7 @@ def self.set_hot_water_distribution(hpxml_bldg, args) system_type: args[:hot_water_distribution_system_type], standard_piping_length: standard_piping_length, recirculation_control_type: recirculation_control_type, - recirculation_piping_length: recirculation_piping_length, + recirculation_piping_loop_length: recirculation_piping_loop_length, recirculation_branch_piping_length: recirculation_branch_piping_length, recirculation_pump_power: recirculation_pump_power, pipe_r_value: args[:hot_water_distribution_pipe_r], @@ -6632,8 +6632,8 @@ def self.set_solar_thermal(hpxml_bldg, args, weather) collector_azimuth = args[:solar_thermal_collector_azimuth] latitude = HPXMLDefaults.get_default_latitude(args[:site_latitude], weather) unless weather.nil? collector_tilt = Geometry.get_absolute_tilt(tilt_str: args[:solar_thermal_collector_tilt], roof_pitch: args[:geometry_roof_pitch], latitude: latitude) - collector_frta = args[:solar_thermal_collector_rated_optical_efficiency] - collector_frul = args[:solar_thermal_collector_rated_thermal_losses] + collector_rated_optical_efficiency = args[:solar_thermal_collector_rated_optical_efficiency] + collector_rated_thermal_losses = args[:solar_thermal_collector_rated_thermal_losses] storage_volume = args[:solar_thermal_storage_volume] end @@ -6648,8 +6648,8 @@ def self.set_solar_thermal(hpxml_bldg, args, weather) collector_type: collector_type, collector_azimuth: collector_azimuth, collector_tilt: collector_tilt, - collector_frta: collector_frta, - collector_frul: collector_frul, + collector_rated_optical_efficiency: collector_rated_optical_efficiency, + collector_rated_thermal_losses: collector_rated_thermal_losses, storage_volume: storage_volume, water_heating_system_idref: hpxml_bldg.water_heating_systems[0].id, solar_fraction: solar_fraction) diff --git a/BuildResidentialHPXML/measure.xml b/BuildResidentialHPXML/measure.xml index 4b8041af35..c84f5c3f18 100644 --- a/BuildResidentialHPXML/measure.xml +++ b/BuildResidentialHPXML/measure.xml @@ -3,8 +3,8 @@ 3.1 build_residential_hpxml a13a8983-2b01-4930-8af2-42030b6e4233 - 635a8ab6-45f1-4969-b2c5-f308519438f8 - 2024-07-11T16:09:59Z + c4dd5a2c-b6ac-467e-b914-ad2f0d59cf23 + 2024-07-17T17:04:58Z 2C38F48B BuildResidentialHPXML HPXML Builder @@ -7406,19 +7406,19 @@ measure.rb rb script - F41033B3 + 09586CC1 geometry.rb rb resource - 8E4E4C7F + 3BCF34D6 test_build_residential_hpxml.rb rb test - C0AF4CE1 + 4924B90F diff --git a/BuildResidentialHPXML/resources/geometry.rb b/BuildResidentialHPXML/resources/geometry.rb index 78a215984a..1df8b3cf3c 100644 --- a/BuildResidentialHPXML/resources/geometry.rb +++ b/BuildResidentialHPXML/resources/geometry.rb @@ -4,7 +4,7 @@ module Geometry # Create a 3D representation of a single-family detached home using the following arguments. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param geometry_unit_cfa [Double] conditioned floor area (ft2) # @param geometry_average_ceiling_height [Double] average ceiling height (ft) @@ -1237,7 +1237,7 @@ def self.create_apartment(model:, # Place a door subsurface on an exterior wall surface (with enough area) prioritized by front, then back, then left, then right, and lowest story. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param door_area [Double] the area of the opaque door(s) (ft2) # @return [Boolean] true if successful @@ -1373,7 +1373,7 @@ def self.create_doors(runner:, # Place window subsurfaces on exterior wall surfaces (or skylight subsurfaces on roof surfaces) using target facade areas based on either window to wall area ratios or window areas. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param window_front_wwr [Double] ratio of window to wall area for the unit's front facade (frac) # @param window_back_wwr [Double] ratio of window to wall area for the unit's back facade (frac) @@ -2279,7 +2279,7 @@ def self.get_wall_area_for_windows(surface:, # @param max_single_window_area [Double] maximum area for a single window (ft2) # @param facade [String] front, back, left, or right # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [Boolean] true if successful def self.add_windows_to_wall(surface:, window_area:, diff --git a/BuildResidentialHPXML/tests/test_build_residential_hpxml.rb b/BuildResidentialHPXML/tests/test_build_residential_hpxml.rb index 54c6c2cb92..4bf22bc2e6 100644 --- a/BuildResidentialHPXML/tests/test_build_residential_hpxml.rb +++ b/BuildResidentialHPXML/tests/test_build_residential_hpxml.rb @@ -579,7 +579,7 @@ def _set_measure_argument_values(hpxml_file, args) args['solar_thermal_system_type'] = 'none' args['solar_thermal_collector_area'] = 40.0 args['solar_thermal_collector_loop_type'] = HPXML::SolarThermalLoopTypeDirect - args['solar_thermal_collector_type'] = HPXML::SolarThermalTypeEvacuatedTube + args['solar_thermal_collector_type'] = HPXML::SolarThermalCollectorTypeEvacuatedTube args['solar_thermal_collector_azimuth'] = 180 args['solar_thermal_collector_tilt'] = 20 args['solar_thermal_collector_rated_optical_efficiency'] = 0.5 @@ -764,7 +764,7 @@ def _set_measure_argument_values(hpxml_file, args) args['pv_system_array_tilt'] = 'roofpitch' args['pv_system_2_array_tilt'] = 'roofpitch+15' elsif ['extra-dhw-solar-latitude.xml'].include? hpxml_file - args['solar_thermal_system_type'] = HPXML::SolarThermalSystemType + args['solar_thermal_system_type'] = HPXML::SolarThermalSystemTypeHotWater args['solar_thermal_collector_tilt'] = 'Latitude-15' elsif ['extra-second-refrigerator.xml'].include? hpxml_file args['extra_refrigerator_location'] = HPXML::LocationConditionedSpace diff --git a/BuildResidentialScheduleFile/measure.rb b/BuildResidentialScheduleFile/measure.rb index 04097c0411..da1fd23a86 100644 --- a/BuildResidentialScheduleFile/measure.rb +++ b/BuildResidentialScheduleFile/measure.rb @@ -88,7 +88,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument # Define what happens when the measure is run. # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [Boolean] true if successful def run(model, runner, user_arguments) @@ -176,7 +176,7 @@ def run(model, runner, user_arguments) # Write out the HPXML file with the output CSV path containing occupancy schedules. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param doc [Oga::XML::Document] Oga XML Document object # @param hpxml_path [String] path of the input HPXML file # @param hpxml_output_path [String] path of the output HPXML file @@ -192,7 +192,7 @@ def write_modified_hpxml(runner, doc, hpxml_path, hpxml_output_path, schedules_f # Create and export the occupancy schedules. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml [HPXML] HPXML object # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param weather [WeatherFile] Weather object containing EPW information diff --git a/BuildResidentialScheduleFile/measure.xml b/BuildResidentialScheduleFile/measure.xml index bb6a98776c..4e420e58e0 100644 --- a/BuildResidentialScheduleFile/measure.xml +++ b/BuildResidentialScheduleFile/measure.xml @@ -3,8 +3,8 @@ 3.1 build_residential_schedule_file f770b2db-1a9f-4e99-99a7-7f3161a594b1 - b471ba87-0ebb-4a48-a305-9a4f6a16e1c5 - 2024-07-11T02:46:37Z + 82cc5cf7-51fc-435c-9ea1-429bf4b72080 + 2024-07-15T21:48:21Z 03F02484 BuildResidentialScheduleFile Schedule File Builder @@ -133,13 +133,13 @@ measure.rb rb script - 3ECB9FB5 + D2B0EB5F README.md md resource - C8528AAA + 08194138 clothes_dryer_consumption_dist.csv @@ -223,7 +223,7 @@ schedules.rb rb resource - BBF55F85 + A0CC250C schedules_config.md diff --git a/BuildResidentialScheduleFile/resources/README.md b/BuildResidentialScheduleFile/resources/README.md index bbe58d1552..08326521c9 100644 --- a/BuildResidentialScheduleFile/resources/README.md +++ b/BuildResidentialScheduleFile/resources/README.md @@ -18,12 +18,12 @@ The schedule CSV file contains the following columns: * `hot_water_dishwasher` * `hot_water_clothes_washer` * `hot_water_fixtures` -* `sleep` (exported only when "debug" mode is enabled) +* `sleeping` (exported only when "debug" mode is enabled) Each of the columns, except `occupants`, represent schedule values (kW for power schedules, and gallons per minute for water schedules) normalized using universal maximum values found in `constants.rb`. The `occupants` column represents the fractional percent of occupants present out of the total number of occupants assigned to the unit. -The `sleep` column represents the fractional percent of the total number of occupants who are sleeping. +The `sleeping` column represents the fractional percent of the total number of occupants who are sleeping. There are the same number of rows as the total simulation time-step (e.g., 35040 if 15-min, 8760 if hourly [8784, if leap year]). diff --git a/BuildResidentialScheduleFile/resources/schedules.rb b/BuildResidentialScheduleFile/resources/schedules.rb index 1d2f27312e..935b267ffd 100644 --- a/BuildResidentialScheduleFile/resources/schedules.rb +++ b/BuildResidentialScheduleFile/resources/schedules.rb @@ -3,21 +3,21 @@ require 'csv' require 'matrix' -# TODO +# Collection of methods related to the generation of stochastic occupancy schedules. class ScheduleGenerator - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object - # @param state [TODO] TODO - # @param column_names [TODO] TODO - # @param random_seed [TODO] TODO - # @param minutes_per_step [TODO] TODO - # @param steps_in_day [TODO] TODO - # @param mkc_ts_per_day [TODO] TODO - # @param mkc_ts_per_hour [TODO] TODO - # @param total_days_in_year [TODO] TODO - # @param sim_year [TODO] TODO - # @param sim_start_day [TODO] TODO - # @param debug [TODO] TODO - # @param append_output [TODO] TODO + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings + # @param state [String] State code from the HPXML file + # @param column_names [Array] list of the schedule column names to generate + # @param random_seed [Integer] the seed for the random number generator + # @param minutes_per_step [Integer] the simulation timestep (minutes) + # @param steps_in_day [Integer] the number of steps in a 24-hour day + # @param mkc_ts_per_day [Integer] Markov chain timesteps per day + # @param mkc_ts_per_hour [Integer] Markov chain timesteps per hour + # @param total_days_in_year [Integer] number of days in the calendar year + # @param sim_year [Integer] the calendar year + # @param sim_start_day [DateTime] the DateTime object corresponding to Jan 1 of the calendar year + # @param debug [Boolean] If true, writes extra column(s) (e.g., sleeping) for informational purposes. + # @param append_output [Boolean] If true and the output CSV file already exists, appends columns to the file rather than overwriting it. The existing output CSV file must have the same number of rows (i.e., timeseries frequency) as the new columns being appended. def initialize(runner:, state:, column_names: nil, @@ -49,18 +49,18 @@ def initialize(runner:, attr_accessor(:schedules) - # TODO + # Get the subset of schedule column names that the stochastic schedule generator supports. # - # @return [TODO] TODO + # @return [Array] list of all schedule column names whose schedules can be stochastically generated def self.export_columns return SchedulesFile::Columns.values.select { |c| c.can_be_stochastic }.map { |c| c.name } end - # TODO + # The top-level method for initializing the schedules hash just before calling the main stochastic schedules method. # - # @param args [TODO] TODO + # @param args [Hash] Map of :argument_name => value # @param weather [WeatherFile] Weather object containing EPW information - # @return [TODO] TODO + # @return [Boolean] true if successful def create(args:, weather:) @schedules = {} @@ -85,11 +85,11 @@ def create(args:, return true end - # TODO + # The main method for creating stochastic schedules. # - # @param args [TODO] TODO + # @param args [Hash] Map of :argument_name => value # @param weather [WeatherFile] Weather object containing EPW information - # @return [TODO] TODO + # @return [Boolean] true if successful def create_stochastic_schedules(args:, weather:) # initialize a random number generator diff --git a/HPXMLtoOpenStudio/measure.rb b/HPXMLtoOpenStudio/measure.rb index 373cf9bb40..8407fd3b2b 100644 --- a/HPXMLtoOpenStudio/measure.rb +++ b/HPXMLtoOpenStudio/measure.rb @@ -97,7 +97,7 @@ def arguments(model) # rubocop:disable Lint/UnusedMethodArgument # Define what happens when the measure is run. # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [Boolean] true if successful def run(model, runner, user_arguments) @@ -468,7 +468,7 @@ def make_variable_name(obj_name, unit_number) # # @param hpxml [HPXML] HPXML object # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param epw_path [String] Path to the EPW weather file # @param weather [WeatherFile] Weather object containing EPW information @@ -659,7 +659,7 @@ def add_simulation_params(model) # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [TODO] TODO def add_num_occupants(model, runner, spaces) @@ -686,7 +686,7 @@ def create_or_get_space(model, spaces, location) # Adds any HPXML Roofs to the OpenStudio model. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [void] @@ -804,7 +804,7 @@ def add_roofs(runner, model, spaces) # Adds any HPXML Walls to the OpenStudio model. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [void] @@ -882,7 +882,7 @@ def add_walls(runner, model, spaces) # Adds any HPXML RimJoists to the OpenStudio model. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [void] @@ -960,7 +960,7 @@ def add_rim_joists(runner, model, spaces) # Adds any HPXML Floors to the OpenStudio model. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [void] @@ -1046,7 +1046,7 @@ def add_floors(runner, model, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -1170,7 +1170,7 @@ def add_foundation_walls_slabs(runner, model, weather, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @param foundation_wall [TODO] TODO @@ -1727,7 +1727,7 @@ def apply_adiabatic_construction(model, surfaces, type) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -1811,7 +1811,7 @@ def add_hot_water_and_appliances(runner, model, weather, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -1866,7 +1866,7 @@ def add_cooling_system(model, runner, weather, spaces, airloop_map) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -1939,7 +1939,7 @@ def add_heating_system(runner, model, weather, spaces, airloop_map) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -2048,7 +2048,7 @@ def add_ideal_system(model, spaces, epw_path) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -2065,7 +2065,7 @@ def add_setpoints(runner, model, weather, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -2080,7 +2080,7 @@ def add_ceiling_fans(runner, model, weather, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [TODO] TODO @@ -2116,7 +2116,7 @@ def check_distribution_system(hvac_distribution, system_type) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [TODO] TODO @@ -2144,7 +2144,7 @@ def add_mels(runner, model, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [TODO] TODO @@ -2170,7 +2170,7 @@ def add_mfls(runner, model, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [TODO] TODO @@ -2181,7 +2181,7 @@ def add_lighting(runner, model, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [TODO] TODO @@ -2200,7 +2200,7 @@ def add_pools_and_permanent_spas(runner, model, spaces) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects @@ -2392,7 +2392,7 @@ def add_generators(model) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] Map of HPXML locations => OpenStudio Space objects # @return [TODO] TODO @@ -3450,7 +3450,7 @@ def set_foundation_and_walls_top() # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [void] def set_heating_and_cooling_seasons(runner) return if @hpxml_bldg.hvac_controls.size == 0 diff --git a/HPXMLtoOpenStudio/measure.xml b/HPXMLtoOpenStudio/measure.xml index 5318823c54..c4fc77065b 100644 --- a/HPXMLtoOpenStudio/measure.xml +++ b/HPXMLtoOpenStudio/measure.xml @@ -3,8 +3,8 @@ 3.1 hpxm_lto_openstudio b1543b30-9465-45ff-ba04-1d1f85e763bc - 7d48e13e-9c50-42a9-ac2d-1b75a6d9bcf2 - 2024-07-12T20:19:53Z + 89e00e9c-fcb6-44d2-828f-5e1cc365cc7d + 2024-07-17T23:48:54Z D8922A73 HPXMLtoOpenStudio HPXML to OpenStudio Translator @@ -183,19 +183,19 @@ measure.rb rb script - 4B9F6763 + 2CD1EC85 airflow.rb rb resource - 2CB8E5D6 + 4A81F203 battery.rb rb resource - A293ECCD + CE2C1767 constants.rb @@ -207,7 +207,7 @@ constructions.rb rb resource - 5D04BA3F + 79CD24DB data/Xing_okstate_0664D_13659_Table_A-3.csv @@ -333,25 +333,25 @@ geometry.rb rb resource - 0B533CFA + E606A192 hotwater_appliances.rb rb resource - BA199BAE + DD6E04DC hpxml.rb rb resource - B559442B + 34D315BD hpxml_defaults.rb rb resource - 6EC41272 + CCAD07C4 hpxml_schema/HPXML.xsd @@ -381,37 +381,43 @@ hvac.rb rb resource - F2757039 + 5C9B0A1C hvac_sizing.rb rb resource - 6A032378 + DCBC4530 lighting.rb rb resource - FB57C5C9 + 4F32AFD6 location.rb rb resource - 5D9993FD + 73069528 materials.rb rb resource - 85FA948A + 5E87EDAD + + + math.rb + rb + resource + 1BACCFF8 meta_measure.rb rb resource - 576F5D3F + 89DE861C minitest_helper.rb @@ -423,7 +429,7 @@ misc_loads.rb rb resource - 4AD1A145 + 7E224297 output.rb @@ -435,7 +441,7 @@ psychrometrics.rb rb resource - 77A4589A + 86A74352 pv.rb @@ -567,7 +573,7 @@ schedules.rb rb resource - 14748738 + C1B88015 simcontrols.rb @@ -585,13 +591,13 @@ util.rb rb resource - C41CBB4D + 1F7CD2A3 utility_bills.rb rb resource - 6DD11F52 + C81B6427 version.rb @@ -603,13 +609,13 @@ waterheater.rb rb resource - 8C128200 + E3E0625C weather.rb rb resource - EF67FCF4 + 8A390166 xmlhelper.rb @@ -621,13 +627,13 @@ xmlvalidator.rb rb resource - E12E2D75 + 93120E27 test_airflow.rb rb test - F3EC678C + 1204D4D0 test_battery.rb @@ -639,7 +645,7 @@ test_defaults.rb rb test - 018D40ED + 853CC6A0 test_enclosure.rb @@ -711,13 +717,13 @@ test_validation.rb rb test - 90CBA9D0 + CFDFF5FB test_water_heater.rb rb test - 485EE23B + 16B0EA4F test_weather.rb diff --git a/HPXMLtoOpenStudio/resources/airflow.rb b/HPXMLtoOpenStudio/resources/airflow.rb index a7e89ea6e6..ef27efd3e6 100644 --- a/HPXMLtoOpenStudio/resources/airflow.rb +++ b/HPXMLtoOpenStudio/resources/airflow.rb @@ -8,7 +8,7 @@ module Airflow # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param weather [WeatherFile] Weather object containing EPW information # @param spaces [Hash] keys are locations and values are OpenStudio::Model::Space objects # @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file) @@ -21,7 +21,7 @@ module Airflow # @param frac_windows_operable [TODO] TODO # @param apply_ashrae140_assumptions [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param hvac_availability_sensor [TODO] TODO # @return [TODO] TODO def self.apply(model, runner, weather, spaces, hpxml_header, hpxml_bldg, cfa, @@ -79,7 +79,7 @@ def self.apply(model, runner, weather, spaces, hpxml_header, hpxml_bldg, cfa, next unless vent_fan.hours_in_operation.nil? || vent_fan.hours_in_operation > 0 if vent_fan.used_for_whole_building_ventilation - if not vent_fan.is_cfis_supplemental_fan? + if not vent_fan.is_cfis_supplemental_fan vent_fans_mech << vent_fan else vent_fans_cfis_suppl << vent_fan @@ -429,7 +429,7 @@ def self.get_default_mech_vent_flow_rate(hpxml_bldg, vent_fan, weather, cfa, nbe nl = get_infiltration_NL_from_SLA(infil_values[:sla], infil_values[:height]) q_inf = get_infiltration_Qinf_from_NL(nl, weather, cfa) q_tot = get_mech_vent_qtot_cfm(nbeds, cfa) - if vent_fan.is_balanced? + if vent_fan.is_balanced is_balanced, frac_imbal = true, 0.0 else is_balanced, frac_imbal = false, 1.0 @@ -569,7 +569,7 @@ def self.apply_infiltration_to_unconditioned_space(model, space, ach, ela, c_w_S # @param natvent_days_per_week [TODO] TODO # @param infil_volume [Double] Volume of space most impacted by the blower door test (ft3) # @param infil_height [Double] Vertical distance between the lowest and highest above-grade points within the pressure boundary, per ASHRAE 62.2 (ft2) - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_natural_ventilation_and_whole_house_fan(model, site, vent_fans_whf, open_window_area, nv_clg_ssn_sensor, natvent_days_per_week, infil_volume, infil_height, unavailable_periods) @@ -765,7 +765,7 @@ def self.create_timeseries_flowrate_ems_output_var(model, ems_var_name, ems_prog # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param obj_name [String] Name for the OpenStudio object # @param num_days_per_week [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.create_nv_and_whf_avail_sch(model, obj_name, num_days_per_week, unavailable_periods = []) avail_sch = OpenStudio::Model::ScheduleRuleset.new(model) @@ -877,7 +877,7 @@ def self.create_other_equipment_object_and_actuator(model:, name:, space:, frac_ # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param vent_fans_mech [TODO] TODO # @param airloop_map [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.initialize_cfis(model, vent_fans_mech, airloop_map, unavailable_periods) # Get AirLoop associated with CFIS @@ -1669,7 +1669,7 @@ def self.apply_infiltration_to_unvented_attic(model, duct_lk_imbals) # @param vent_object [TODO] TODO # @param obj_type_name [TODO] TODO # @param index [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_local_ventilation(model, vent_object, obj_type_name, index, unavailable_periods) daily_sch = [0.0] * 24 @@ -1709,7 +1709,7 @@ def self.apply_local_ventilation(model, vent_object, obj_type_name, index, unava # @param vented_dryer [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files # @param index [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_dryer_exhaust(model, vented_dryer, schedules_file, index, unavailable_periods) obj_name = "#{Constants.ObjectNameClothesDryer} exhaust #{index}" @@ -1881,8 +1881,8 @@ def self.apply_cfis(infil_program, vent_mech_fans, cfis_fan_actuator, cfis_suppl # Air handler meets additional runtime requirement infil_program.addLine(" Set #{cfis_fan_actuator.name} = #{cfis_fan_actuator.name} + cfis_fan_w * #{@cfis_f_damper_extra_open_var[vent_mech.id].name}") elsif vent_mech.cfis_addtl_runtime_operating_mode == HPXML::CFISModeSupplementalFan - if vent_mech.cfis_supplemental_fan.oa_unit_flow_rate < vent_mech.average_total_unit_flow_rate - @runner.registerWarning("CFIS supplemental fan '#{vent_mech.cfis_supplemental_fan.id}' is undersized (#{vent_mech.cfis_supplemental_fan.oa_unit_flow_rate} cfm) compared to the target hourly ventilation rate (#{vent_mech.average_total_unit_flow_rate} cfm).") + if vent_mech.cfis_supplemental_fan.oa_unit_flow_rate < vent_mech.average_unit_flow_rate + @runner.registerWarning("CFIS supplemental fan '#{vent_mech.cfis_supplemental_fan.id}' is undersized (#{vent_mech.cfis_supplemental_fan.oa_unit_flow_rate} cfm) compared to the target hourly ventilation rate (#{vent_mech.average_unit_flow_rate} cfm).") end infil_program.addLine(" Set cfis_suppl_Q_oa = #{UnitConversions.convert(vent_mech.cfis_supplemental_fan.oa_unit_flow_rate, 'cfm', 'm^3/s')}") if vent_mech.cfis_supplemental_fan.oa_unit_flow_rate > 0 @@ -1929,7 +1929,7 @@ def self.apply_cfis(infil_program, vent_mech_fans, cfis_fan_actuator, cfis_suppl # @param exh_fans [TODO] TODO # @param bal_fans [TODO] TODO # @param erv_hrv_fans [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.add_ee_for_vent_fan_power(model, obj_name, sup_fans = [], exh_fans = [], bal_fans = [], erv_hrv_fans = [], unavailable_periods = []) # Calculate fan heat fraction @@ -2028,15 +2028,15 @@ def self.setup_mech_vent_vars_actuators(model:, program:) # @param vent_mech_erv_hrv_tot [TODO] TODO # @param infil_flow_actuator [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_infiltration_adjustment_to_conditioned(model, infil_program, vent_fans_kitchen, vent_fans_bath, vented_dryers, duct_lk_imbals, vent_mech_sup_tot, vent_mech_exh_tot, vent_mech_bal_tot, vent_mech_erv_hrv_tot, infil_flow_actuator, schedules_file, unavailable_periods) # Average in-unit CFMs (include recirculation from in unit CFMs for shared systems) - sup_cfm_tot = vent_mech_sup_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) - exh_cfm_tot = vent_mech_exh_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) - bal_cfm_tot = vent_mech_bal_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) - erv_hrv_cfm_tot = vent_mech_erv_hrv_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) + sup_cfm_tot = vent_mech_sup_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) + exh_cfm_tot = vent_mech_exh_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) + bal_cfm_tot = vent_mech_bal_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) + erv_hrv_cfm_tot = vent_mech_erv_hrv_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) infil_program.addLine('Set Qrange = 0') vent_fans_kitchen.each_with_index do |vent_kitchen, index| @@ -2281,7 +2281,7 @@ def self.calculate_precond_loads(model, infil_program, vent_mech_preheat, vent_m # @param clg_ssn_sensor [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files # @param vent_fans_cfis_suppl [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param elevation [Double] Elevation of the building site (ft) # @param duct_lk_imbals [TODO] TODO # @return [TODO] TODO @@ -2351,7 +2351,7 @@ def self.apply_infiltration_ventilation_to_conditioned(model, site, vent_fans_me # Qload as variable for tracking outdoor air flow rate, excluding recirculation infil_program.addLine('Set Qload = Qfan') vent_fans_mech.each do |f| - recirc_flow_rate = f.average_total_unit_flow_rate - f.average_oa_unit_flow_rate + recirc_flow_rate = f.average_unit_flow_rate - f.average_oa_unit_flow_rate next unless recirc_flow_rate > 0 # Subtract recirculation air flow rate from Qfan, only come from supply side as exhaust is not allowed to have recirculation @@ -2388,7 +2388,7 @@ def self.apply_infiltration_ventilation_to_conditioned(model, site, vent_fans_me # @param clg_ssn_sensor [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files # @param vent_fans_cfis_suppl [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param elevation [Double] Elevation of the building site (ft) # @return [TODO] TODO def self.apply_infiltration_and_ventilation_fans(model, weather, site, vent_fans_mech, vent_fans_kitchen, vent_fans_bath, vented_dryers, duct_lk_imbals, diff --git a/HPXMLtoOpenStudio/resources/battery.rb b/HPXMLtoOpenStudio/resources/battery.rb index 1a021e786e..f5a5f8465a 100644 --- a/HPXMLtoOpenStudio/resources/battery.rb +++ b/HPXMLtoOpenStudio/resources/battery.rb @@ -4,7 +4,7 @@ module Battery # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param nbeds [Integer] Number of bedrooms in the dwelling unit # @param pv_systems [TODO] TODO diff --git a/HPXMLtoOpenStudio/resources/constructions.rb b/HPXMLtoOpenStudio/resources/constructions.rb index e550a4c518..714ddbdc4a 100644 --- a/HPXMLtoOpenStudio/resources/constructions.rb +++ b/HPXMLtoOpenStudio/resources/constructions.rb @@ -2370,7 +2370,7 @@ def self.calc_non_cavity_r(film_r, constr_set) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param surfaces [Array] array of OpenStudio::Model::Surface objects # @param wall_id [TODO] TODO @@ -2584,7 +2584,7 @@ def self.apply_wall_construction(runner, # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param surface [OpenStudio::Model::Surface] an OpenStudio::Model::Surface object # @param floor_id [TODO] TODO @@ -2933,7 +2933,7 @@ def self.pick_generic_construction_set(assembly_r, constr_sets, inside_film, out # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param surfaces [Array] array of OpenStudio::Model::Surface objects # @param inside_film [TODO] TODO # @param outside_film [TODO] TODO diff --git a/HPXMLtoOpenStudio/resources/geometry.rb b/HPXMLtoOpenStudio/resources/geometry.rb index cad15b979f..6d767b5e20 100644 --- a/HPXMLtoOpenStudio/resources/geometry.rb +++ b/HPXMLtoOpenStudio/resources/geometry.rb @@ -5,7 +5,7 @@ module Geometry # Tear down the existing model if it exists. # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def self.tear_down_model(model:, runner:) @@ -489,12 +489,12 @@ def self.explode_surfaces(model:, # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param num_occ [TODO] TODO # @param space [OpenStudio::Model::Space] an OpenStudio::Model::Space object # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [void] def self.apply_occupants(model, runner, hpxml_bldg, num_occ, space, schedules_file, unavailable_periods) occ_gain, _hrs_per_day, sens_frac, _lat_frac = get_occupancy_default_values() diff --git a/HPXMLtoOpenStudio/resources/hotwater_appliances.rb b/HPXMLtoOpenStudio/resources/hotwater_appliances.rb index b20b2f3a96..ee8c13bb32 100644 --- a/HPXMLtoOpenStudio/resources/hotwater_appliances.rb +++ b/HPXMLtoOpenStudio/resources/hotwater_appliances.rb @@ -5,7 +5,7 @@ module HotWaterAndAppliances # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file) # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param weather [WeatherFile] Weather object containing EPW information @@ -15,7 +15,7 @@ module HotWaterAndAppliances # @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files # @param plantloop_map [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @param apply_ashrae140_assumptions [TODO] TODO # @return [TODO] TODO @@ -891,7 +891,7 @@ def self.calc_refrigerator_or_freezer_energy(refrigerator_or_freezer, is_outside # @param col_name [TODO] TODO # @param obj_name [String] Name for the OpenStudio object # @param refrigerator_or_freezer [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.refrigerator_or_freezer_coefficients_schedule(model, col_name, obj_name, refrigerator_or_freezer, unavailable_periods) # Create availability sensor @@ -977,7 +977,7 @@ def self.get_dist_energy_consumption_adjustment(has_uncond_bsmnt, has_cond_bsmnt pe_ratio = hot_water_distribution.standard_piping_length / ref_pipe_l elsif hot_water_distribution.system_type == HPXML::DHWDistTypeRecirc ref_loop_l = get_default_recirc_loop_length(ref_pipe_l) - pe_ratio = hot_water_distribution.recirculation_piping_length / ref_loop_l + pe_ratio = hot_water_distribution.recirculation_piping_loop_length / ref_loop_l end e_waste = oew_fact * (1.0 - ocd_eff) + sew_fact * pe_ratio return (e_waste + 128.0) / 160.0 diff --git a/HPXMLtoOpenStudio/resources/hpxml.rb b/HPXMLtoOpenStudio/resources/hpxml.rb index d0b8bf4afc..9aaa17ecd2 100644 --- a/HPXMLtoOpenStudio/resources/hpxml.rb +++ b/HPXMLtoOpenStudio/resources/hpxml.rb @@ -3,58 +3,56 @@ require 'ostruct' require 'tempfile' -''' -Example Usage: +# Object that reflects the inputs/elements of a given HPXML file. +class HPXML < Object + ''' + Example Usage: ------------------ -Reading from file ------------------ + ----------------- + Reading from file + ----------------- -hpxml = HPXML.new(hpxml_path: ...) + hpxml = HPXML.new(hpxml_path: ...) -# Singleton elements -puts hpxml.building_construction.number_of_bedrooms + # Singleton elements + puts hpxml.building_construction.number_of_bedrooms -# Array elements -hpxml.walls.each do |wall| - wall.windows.each do |window| - puts window.area + # Array elements + hpxml.walls.each do |wall| + wall.windows.each do |window| + puts window.area + end end -end ---------------------- -Creating from scratch ---------------------- + --------------------- + Creating from scratch + --------------------- -hpxml = HPXML.new() + hpxml = HPXML.new() -# Singleton elements -hpxml.building_construction.number_of_bedrooms = 3 -hpxml.building_construction.conditioned_floor_area = 2400 + # Singleton elements + hpxml.building_construction.number_of_bedrooms = 3 + hpxml.building_construction.conditioned_floor_area = 2400 -# Array elements -hpxml.walls.clear -hpxml.walls.add(id: "WallNorth", area: 500) -hpxml.walls.add(id: "WallSouth", area: 500) -hpxml.walls.add -hpxml.walls[-1].id = "WallEastWest" -hpxml.walls[-1].area = 1000 + # Array elements + hpxml.walls.clear + hpxml.walls.add(id: "WallNorth", area: 500) + hpxml.walls.add(id: "WallSouth", area: 500) + hpxml.walls.add + hpxml.walls[-1].id = "WallEastWest" + hpxml.walls[-1].area = 1000 -# Write file -XMLHelper.write_file(hpxml.to_doc, "out.xml") + # Write file + XMLHelper.write_file(hpxml.to_doc, "out.xml") + + ''' -''' -# TODO -class HPXML < Object HPXML_ATTRS = [:header, :buildings] attr_reader(*HPXML_ATTRS, :doc, :errors, :warnings, :hpxml_path) NameSpace = 'http://hpxmlonline.com/2023/09' # Constants - FuelElementNames = ['HeatingSystemFuel', 'CoolingSystemFuel', 'HeatPumpFuel', 'BackupSystemFuel', 'FuelType', 'IntegratedHeatingSystemFuel', 'Heater/Type'] - - # FUTURE: Move some of these to within child classes (e.g., HPXML::Attic class) AddressTypeMailing = 'mailing' AddressTypeStreet = 'street' AdvancedResearchDefrostModelTypeStandard = 'standard' @@ -384,14 +382,14 @@ class HPXML < Object SiteTypeUrban = 'urban' SiteTypeSuburban = 'suburban' SiteTypeRural = 'rural' + SolarThermalCollectorTypeDoubleGlazing = 'double glazing black' + SolarThermalCollectorTypeEvacuatedTube = 'evacuated tube' + SolarThermalCollectorTypeICS = 'integrated collector storage' + SolarThermalCollectorTypeSingleGlazing = 'single glazing black' SolarThermalLoopTypeDirect = 'liquid direct' SolarThermalLoopTypeIndirect = 'liquid indirect' SolarThermalLoopTypeThermosyphon = 'passive thermosyphon' - SolarThermalSystemType = 'hot water' - SolarThermalTypeDoubleGlazing = 'double glazing black' - SolarThermalTypeEvacuatedTube = 'evacuated tube' - SolarThermalTypeICS = 'integrated collector storage' - SolarThermalTypeSingleGlazing = 'single glazing black' + SolarThermalSystemTypeHotWater = 'hot water' SpaceFenestrationLoadProcedureStandard = 'standard' SpaceFenestrationLoadProcedurePeak = 'peak' SurroundingsOneSide = 'attached on one side' @@ -526,14 +524,13 @@ class HPXML < Object cdl_lat_vent: 'Ventilation', cdl_lat_intgains: 'InternalLoads' } - # TODO def initialize(hpxml_path: nil, schema_validator: nil, schematron_validator: nil, building_id: nil) @hpxml_path = hpxml_path @errors = [] @warnings = [] building_id = nil if building_id.to_s.empty? - hpxml_doc = nil + hpxml_element = nil if not hpxml_path.nil? doc = XMLHelper.parse_file(hpxml_path) @@ -546,13 +543,13 @@ def initialize(hpxml_path: nil, schema_validator: nil, schematron_validator: nil end # Check HPXML version - hpxml_doc = XMLHelper.get_element(doc, '/HPXML') - Version.check_hpxml_version(XMLHelper.get_attribute_value(hpxml_doc, 'schemaVersion')) + hpxml_element = XMLHelper.get_element(doc, '/HPXML') + Version.check_hpxml_version(XMLHelper.get_attribute_value(hpxml_element, 'schemaVersion')) # Get value of WholeSFAorMFBuildingSimulation element - whole_sfa_or_mf_building_sim = XMLHelper.get_value(hpxml_doc, 'SoftwareInfo/extension/WholeSFAorMFBuildingSimulation', :boolean) + whole_sfa_or_mf_building_sim = XMLHelper.get_value(hpxml_element, 'SoftwareInfo/extension/WholeSFAorMFBuildingSimulation', :boolean) whole_sfa_or_mf_building_sim = false if whole_sfa_or_mf_building_sim.nil? - has_mult_building_elements = XMLHelper.get_elements(hpxml_doc, 'Building').size > 1 + has_mult_building_elements = XMLHelper.get_elements(hpxml_element, 'Building').size > 1 if has_mult_building_elements if building_id.nil? && !whole_sfa_or_mf_building_sim @errors << 'Multiple Building elements defined in HPXML file; provide Building ID argument or set WholeSFAorMFBuildingSimulation=true.' @@ -569,24 +566,24 @@ def initialize(hpxml_path: nil, schema_validator: nil, schematron_validator: nil # 2. The schematron validation occurs faster (as we're only validating one Building). if has_mult_building_elements && (not building_id.nil?) # Discard all Building elements except the one of interest - XMLHelper.get_elements(hpxml_doc, 'Building').reverse_each do |building| + XMLHelper.get_elements(hpxml_element, 'Building').reverse_each do |building| next if XMLHelper.get_attribute_value(XMLHelper.get_element(building, 'BuildingID'), 'id') == building_id building.remove end - if XMLHelper.get_elements(hpxml_doc, 'Building').size == 0 + if XMLHelper.get_elements(hpxml_element, 'Building').size == 0 @errors << "Could not find Building element with ID '#{building_id}'." return unless @errors.empty? end # Write new HPXML file with all other Building elements removed hpxml_path = Tempfile.new(['hpxml', '.xml']).path.to_s - XMLHelper.write_file(hpxml_doc, hpxml_path) + XMLHelper.write_file(hpxml_element, hpxml_path) end # Validate against Schematron if not schematron_validator.nil? - sct_errors, sct_warnings = XMLValidator.validate_against_schematron(hpxml_path, schematron_validator, hpxml_doc) + sct_errors, sct_warnings = XMLValidator.validate_against_schematron(hpxml_path, schematron_validator, hpxml_element) @errors += sct_errors @warnings += sct_warnings return unless @errors.empty? @@ -594,7 +591,7 @@ def initialize(hpxml_path: nil, schema_validator: nil, schematron_validator: nil end # Create/populate child objects - from_doc(hpxml_doc) + from_doc(hpxml_element) # Check for additional errors (those hard to check via Schematron) @errors += header.check_for_errors @@ -605,25 +602,30 @@ def initialize(hpxml_path: nil, schema_validator: nil, schematron_validator: nil return unless @errors.empty? end - # TODO - def to_doc() - doc = _create_hpxml_document() - @header.to_doc(doc) - @buildings.to_doc(doc) - return doc + # Returns the HPXML object converted to an Oga XML Document. + # + # @return [Oga::XML::Document] HPXML object as an XML document + def to_doc + hpxml_doc = _create_hpxml_document() + @header.to_doc(hpxml_doc) + @buildings.to_doc(hpxml_doc) + return hpxml_doc end - # TODO - def from_doc(hpxml) - @header = Header.new(self, hpxml) - @buildings = Buildings.new(self, hpxml) + # Populates the HPXML object(s) from the XML document. + # + # @param hpxml_element [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def from_doc(hpxml_element) + @header = Header.new(self, hpxml_element) + @buildings = Buildings.new(self, hpxml_element) end - # Make all IDs unique so the HPXML is valid + # Make all IDs unique so the HPXML is valid. # - # @param hpxml_doc [TODO] TODO - # @param last_building_only [TODO] TODO - # @return [TODO] TODO + # @param hpxml_doc [Oga::XML::Document] HPXML object as an XML document + # @param last_building_only [Boolean] Whether to update IDs for all Building elements or only the last Building element + # @return [void] def set_unique_hpxml_ids(hpxml_doc, last_building_only = false) buildings = XMLHelper.get_elements(hpxml_doc, '/HPXML/Building') @@ -645,13 +647,23 @@ def set_unique_hpxml_ids(hpxml_doc, last_building_only = false) # Returns a hash with whether each fuel exists in the HPXML Building or Buildings # - # @param hpxml_doc [TODO] TODO - # @return [TODO] TODO + # @param hpxml_doc [Oga::XML::Document] HPXML object as an XML document + # @param building_id [String] If provided, only search the single HPXML Building with the given ID + # @return [Hash] Map of HPXML::FuelTypeXXX => boolean def has_fuels(hpxml_doc, building_id = nil) has_fuels = {} + + fuel_element_names = ['HeatingSystemFuel', + 'CoolingSystemFuel', + 'HeatPumpFuel', + 'BackupSystemFuel', + 'FuelType', + 'IntegratedHeatingSystemFuel', + 'Heater/Type'] + HPXML::fossil_fuels.each do |fuel| has_fuels[fuel] = false - FuelElementNames.each do |fuel_element_name| + fuel_element_names.each do |fuel_element_name| if fuel_element_name == 'Heater/Type' && fuel == HPXML::FuelTypeNaturalGas fuel_element_value = HPXML::HeaterTypeGas else @@ -675,16 +687,16 @@ def has_fuels(hpxml_doc, building_id = nil) # to end up in the HPXML file. For example, you can store the OpenStudio::Model::Space # object for an appliance. class AdditionalProperties < OpenStruct - # TODO - def method_missing(meth, *args, **kwargs) - # Complain if no value has been set rather than just returning nil - raise NoMethodError, "undefined method '#{meth}' for #{self}" unless meth.to_s.end_with?('=') + # Throw an error if no value has been set for a given additional property + # rather than just returning nil. + def method_missing(method_name, *args, **kwargs) + raise NoMethodError, "undefined method '#{method_name}' for #{self}" unless method_name.to_s.end_with?('=') super end end - # HPXML Standard Element (e.g., Roof) + # HPXML Standard Element (e.g., used for Roof) class BaseElement attr_accessor(:parent_object, :additional_properties) @@ -715,18 +727,20 @@ def initialize(parent_object, hpxml_element = nil, **kwargs) end end - # TODO + # Used to create _isdefaulted attributes on the fly that correspond to every defined attribute. def create_method(name, &block) self.class.send(:define_method, name, &block) end - # TODO + # Used to create _isdefaulted attributes on the fly that correspond to every defined attribute. def create_attr(name) create_method("#{name}=".to_sym) { |val| instance_variable_set('@' + name, val) } create_method(name.to_sym) { instance_variable_get('@' + name) } end - # TODO + # Creates a hash out of the object properties. + # + # @return [Hash] Map of attribute name => value def to_h h = {} self.class::ATTRS.each do |attribute| @@ -735,12 +749,14 @@ def to_h return h end - # TODO + # Returns how the object is formatted when using .to_s. def to_s return to_h.to_s end - # Returns true if all attributes are nil + # Returns whether all attributes are nil + # + # @return [Boolean] True if all attributes are nil def nil? to_h.each do |k, v| next if k.to_s.end_with? '_isdefaulted' @@ -750,7 +766,7 @@ def nil? end end - # HPXML Array Element (e.g., Roofs) + # HPXML Array Element (e.g., used for Roofs) class BaseArrayElement < Array attr_accessor(:parent_object, :additional_properties) @@ -764,7 +780,9 @@ def initialize(parent_object, hpxml_element = nil) end end - # TODO + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages across all objects in the array def check_for_errors errors = [] each do |child| @@ -777,66 +795,90 @@ def check_for_errors return errors end - # TODO - def to_doc(doc) + # Adds each object in the array to the provided Oga XML element. + # + # @param xml_element [Oga::XML::Element] XML element + # @return [void] + def to_doc(xml_element) each do |child| - child.to_doc(doc) + child.to_doc(xml_element) end end - # TODO + # Returns how the object is formatted when using .to_s. def to_s return map { |x| x.to_s } end end - # TODO + # Object for high-level HPXML header information. + # Applies to all Buildings (i.e., outside the Building elements). class Header < BaseElement - def initialize(hpxml_object, *args, **kwargs) - @emissions_scenarios = EmissionsScenarios.new(hpxml_object) - @utility_bill_scenarios = UtilityBillScenarios.new(hpxml_object) - @unavailable_periods = UnavailablePeriods.new(hpxml_object) - super(hpxml_object, *args, **kwargs) - end - ATTRS = [:xml_type, :xml_generated_by, :created_date_and_time, :transaction, :software_program_used, - :software_program_version, :apply_ashrae140_assumptions, :temperature_capacitance_multiplier, :timestep, - :sim_begin_month, :sim_begin_day, :sim_end_month, :sim_end_day, :sim_calendar_year, - :eri_calculation_version, :co2index_calculation_version, :energystar_calculation_version, - :iecc_eri_calculation_version, :zerh_calculation_version, :whole_sfa_or_mf_building_sim, - :defrost_model_type, :hvac_onoff_thermostat_deadband, :heat_pump_backup_heating_capacity_increment] + def initialize(hpxml_element, *args, **kwargs) + @emissions_scenarios = EmissionsScenarios.new(hpxml_element) + @utility_bill_scenarios = UtilityBillScenarios.new(hpxml_element) + @unavailable_periods = UnavailablePeriods.new(hpxml_element) + super(hpxml_element, *args, **kwargs) + end + CLASS_ATTRS = [:emissions_scenarios, # [HPXML::EmissionSenarios] + :utility_bill_scenarios, # [HPXML::UtilityBillScenarios] + :unavailable_periods] # [HPXML::UnavailablePeriods] + ATTRS = [:xml_type, # [String] XMLTransactionHeaderInformation/XMLType + :xml_generated_by, # [String] XMLTransactionHeaderInformation/XMLGeneratedBy + :created_date_and_time, # [String] XMLTransactionHeaderInformation/CreatedDateAndTime + :transaction, # [String] XMLTransactionHeaderInformation/Transaction + :software_program_used, # [String] SoftwareInfo/SoftwareProgramUsed + :software_program_version, # [String] SoftwareInfo/SoftwareProgramVersion + :apply_ashrae140_assumptions, # [Boolean] SoftwareInfo/extension/ApplyASHRAE140Assumptions + :whole_sfa_or_mf_building_sim, # [Boolean] SoftwareInfo/extension/WholeSFAorMFBuildingSimulation + :eri_calculation_version, # [String] SoftwareInfo/extension/ERICalculation/Version + :co2index_calculation_version, # [String] SoftwareInfo/extension/CO2IndexCalculation/Version + :energystar_calculation_version, # [String] SoftwareInfo/extension/EnergyStarCalculation/Version + :iecc_eri_calculation_version, # [String] SoftwareInfo/extension/IECCERICalculation/Version + :zerh_calculation_version, # [String] SoftwareInfo/extension/ZERHCalculation/Version + :timestep, # [Integer] SoftwareInfo/extension/SimulationControl/Timestep (minutes) + :sim_begin_month, # [Integer] SoftwareInfo/extension/SimulationControl/BeginMonth + :sim_begin_day, # [Integer] SoftwareInfo/extension/SimulationControl/BeginDayOfMonth + :sim_end_month, # [Integer] SoftwareInfo/extension/SimulationControl/EndMonth + :sim_end_day, # [Integer] SoftwareInfo/extension/SimulationControl/EndDayOfMonth + :sim_calendar_year, # [Integer] SoftwareInfo/extension/SimulationControl/CalendarYear + :temperature_capacitance_multiplier, # [Double] SoftwareInfo/extension/SimulationControl/AdvancedResearchFeatures/TemperatureCapacitanceMultiplier + :defrost_model_type, # [String] SoftwareInfo/extension/SimulationControl/AdvancedResearchFeatures/DefrostModelType (HPXML::AdvancedResearchDefrostModelTypeXXX) + :hvac_onoff_thermostat_deadband, # [Double] SoftwareInfo/extension/SimulationControl/AdvancedResearchFeatures/OnOffThermostatDeadbandTemperature (F) + :heat_pump_backup_heating_capacity_increment] # [Double] SoftwareInfo/extension/SimulationControl/AdvancedResearchFeatures/HeatPumpBackupCapacityIncrement (Btu/hr) + attr_reader(*CLASS_ATTRS) attr_accessor(*ATTRS) - attr_reader(:emissions_scenarios) - attr_reader(:utility_bill_scenarios) - attr_reader(:unavailable_periods) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] - errors += HPXML::check_dates('Run Period', @sim_begin_month, @sim_begin_day, @sim_end_month, @sim_end_day) - if (not @sim_begin_month.nil?) && (not @sim_end_month.nil?) if @sim_begin_month > @sim_end_month errors << "Run Period Begin Month (#{@sim_begin_month}) cannot come after Run Period End Month (#{@sim_end_month})." end - if (not @sim_begin_day.nil?) && (not @sim_end_day.nil?) if @sim_begin_month == @sim_end_month && @sim_begin_day > @sim_end_day errors << "Run Period Begin Day of Month (#{@sim_begin_day}) cannot come after Run Period End Day of Month (#{@sim_end_day}) for the same month (#{begin_month})." end end end - errors += @emissions_scenarios.check_for_errors errors += @utility_bill_scenarios.check_for_errors errors += @unavailable_periods.check_for_errors - return errors end - def to_doc(doc) # rubocop:disable Style/DocumentationMethod + # Adds this object to the Oga XML document. + # + # @param hpxml_doc [Oga::XML::Document] HPXML object as an XML document + # @return [void] + def to_doc(hpxml_doc) return if nil? - hpxml = XMLHelper.get_element(doc, '/HPXML') + hpxml = XMLHelper.get_element(hpxml_doc, '/HPXML') header = XMLHelper.add_element(hpxml, 'XMLTransactionHeaderInformation') XMLHelper.add_element(header, 'XMLType', @xml_type, :string) XMLHelper.add_element(header, 'XMLGeneratedBy', @xml_generated_by, :string) @@ -880,12 +922,16 @@ def to_doc(doc) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(advanced_research_features, 'HeatPumpBackupCapacityIncrement', @heat_pump_backup_heating_capacity_increment, :float, @heat_pump_backup_heating_capacity_increment_isdefaulted) unless @heat_pump_backup_heating_capacity_increment.nil? end end - @emissions_scenarios.to_doc(software_info) - @utility_bill_scenarios.to_doc(software_info) - @unavailable_periods.to_doc(software_info) + @emissions_scenarios.to_doc(hpxml) + @utility_bill_scenarios.to_doc(hpxml) + @unavailable_periods.to_doc(hpxml) end - def from_doc(hpxml) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def from_doc(hpxml) return if hpxml.nil? @xml_type = XMLHelper.get_value(hpxml, 'XMLTransactionHeaderInformation/XMLType', :string) @@ -911,52 +957,83 @@ def from_doc(hpxml) # rubocop:disable Style/DocumentationMethod @heat_pump_backup_heating_capacity_increment = XMLHelper.get_value(hpxml, 'SoftwareInfo/extension/SimulationControl/AdvancedResearchFeatures/HeatPumpBackupCapacityIncrement', :float) @apply_ashrae140_assumptions = XMLHelper.get_value(hpxml, 'SoftwareInfo/extension/ApplyASHRAE140Assumptions', :boolean) @whole_sfa_or_mf_building_sim = XMLHelper.get_value(hpxml, 'SoftwareInfo/extension/WholeSFAorMFBuildingSimulation', :boolean) - @emissions_scenarios.from_doc(XMLHelper.get_element(hpxml, 'SoftwareInfo')) - @utility_bill_scenarios.from_doc(XMLHelper.get_element(hpxml, 'SoftwareInfo')) - @unavailable_periods.from_doc(XMLHelper.get_element(hpxml, 'SoftwareInfo')) + @emissions_scenarios.from_doc(hpxml) + @utility_bill_scenarios.from_doc(hpxml) + @unavailable_periods.from_doc(hpxml) end end - # TODO + # Array of HPXML::EmissionSenario objects. class EmissionsScenarios < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << EmissionsScenario.new(@parent_object, **kwargs) end - def from_doc(software_info) # rubocop:disable Style/DocumentationMethod - return if software_info.nil? + # Populates the HPXML object(s) from the XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def from_doc(hpxml) + return if hpxml.nil? - XMLHelper.get_elements(software_info, 'extension/EmissionsScenarios/EmissionsScenario').each do |emissions_scenario| + XMLHelper.get_elements(hpxml, 'SoftwareInfo/extension/EmissionsScenarios/EmissionsScenario').each do |emissions_scenario| self << EmissionsScenario.new(@parent_object, emissions_scenario) end end end - # TODO + # Object for /HPXML/SoftwareInfo/extension/EmissionsScenarios/EmissionsScenario. class EmissionsScenario < BaseElement UnitsKgPerMWh = 'kg/MWh' UnitsKgPerMBtu = 'kg/MBtu' UnitsLbPerMWh = 'lb/MWh' UnitsLbPerMBtu = 'lb/MBtu' - ATTRS = [:name, :emissions_type, :elec_units, :elec_value, :elec_schedule_filepath, - :elec_schedule_number_of_header_rows, :elec_schedule_column_number, - :natural_gas_units, :natural_gas_value, :propane_units, :propane_value, - :fuel_oil_units, :fuel_oil_value, :coal_units, :coal_value, - :wood_units, :wood_value, :wood_pellets_units, :wood_pellets_value] + ATTRS = [:name, # [String] Name + :emissions_type, # [String] EmissionsType + :elec_units, # [String] EmissionsFactor[FuelType="electricity"]/Units + :elec_value, # [Double] EmissionsFactor[FuelType="electricity"]/Value + :elec_schedule_filepath, # [String] EmissionsFactor[FuelType="electricity"]/ScheduleFilePath + :elec_schedule_number_of_header_rows, # [Integer] EmissionsFactor[FuelType="electricity"]/NumberofHeaderRows + :elec_schedule_column_number, # [Integer] EmissionsFactor[FuelType="electricity"]/ColumnNumber + :natural_gas_units, # [String] EmissionsFactor[FuelType="natural gas"]/Units + :natural_gas_value, # [Double] EmissionsFactor[FuelType="natural gas"]/Value + :propane_units, # [String] EmissionsFactor[FuelType="propane"]/Units + :propane_value, # [Double] EmissionsFactor[FuelType="propane"]/Value + :fuel_oil_units, # [String] EmissionsFactor[FuelType="fuel oil"]/Units + :fuel_oil_value, # [Double] EmissionsFactor[FuelType="fuel oil"]/Value + :coal_units, # [String] EmissionsFactor[FuelType="coal"]/Units + :coal_value, # [Double] EmissionsFactor[FuelType="coal"]/Value + :wood_units, # [String] EmissionsFactor[FuelType="wood"]/Units + :wood_value, # [Double] EmissionsFactor[FuelType="wood"]/Value + :wood_pellets_units, # [String] EmissionsFactor[FuelType="wood pellets"]/Units + :wood_pellets_value] # [Double] EmissionsFactor[FuelType="wood pellets"]/Value attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.header.emissions_scenarios.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(software_info) # rubocop:disable Style/DocumentationMethod - emissions_scenarios = XMLHelper.create_elements_as_needed(software_info, ['extension', 'EmissionsScenarios']) + # Adds this object to the Oga XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def to_doc(hpxml) + emissions_scenarios = XMLHelper.create_elements_as_needed(hpxml, ['SoftwareInfo', 'extension', 'EmissionsScenarios']) emissions_scenario = XMLHelper.add_element(emissions_scenarios, 'EmissionsScenario') XMLHelper.add_element(emissions_scenario, 'Name', @name, :string) unless @name.nil? XMLHelper.add_element(emissions_scenario, 'EmissionsType', @emissions_type, :string) unless @emissions_type.nil? @@ -992,7 +1069,11 @@ def to_doc(software_info) # rubocop:disable Style/DocumentationMethod end end - def from_doc(emissions_scenario) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param emissions_scenario [Oga::XML::Element] The current EmissionsScenario XML element + # @return [void] + def from_doc(emissions_scenario) return if emissions_scenario.nil? @name = XMLHelper.get_value(emissions_scenario, 'Name', :string) @@ -1017,56 +1098,89 @@ def from_doc(emissions_scenario) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::UtilityBillScenario objects. class UtilityBillScenarios < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << UtilityBillScenario.new(@parent_object, **kwargs) end - def from_doc(software_info) # rubocop:disable Style/DocumentationMethod - return if software_info.nil? + # Populates the HPXML object(s) from the XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def from_doc(hpxml) + return if hpxml.nil? - XMLHelper.get_elements(software_info, 'extension/UtilityBillScenarios/UtilityBillScenario').each do |utility_bill_scenario| + XMLHelper.get_elements(hpxml, 'SoftwareInfo/extension/UtilityBillScenarios/UtilityBillScenario').each do |utility_bill_scenario| self << UtilityBillScenario.new(@parent_object, utility_bill_scenario) end end - # TODO + # Checks whether the utility bill scenario has simple (vs detailed) electric rates + # + # @return [Boolean] true if simple electric rates def has_simple_electric_rates any? { |bill_scen| !bill_scen.elec_fixed_charge.nil? || !bill_scen.elec_marginal_rate.nil? } end - # TODO + # Checks whether the utility bill scenario has detailed (vs simple) electric rates + # + # @return [Boolean] true if detailed electric rates def has_detailed_electric_rates any? { |bill_scen| !bill_scen.elec_tariff_filepath.nil? } end end - # TODO + # Object for /HPXML/SoftwareInfo/extension/UtilityBillScenarios/UtilityBillScenario. class UtilityBillScenario < BaseElement - ATTRS = [:name, - :elec_tariff_filepath, - :elec_fixed_charge, :natural_gas_fixed_charge, :propane_fixed_charge, :fuel_oil_fixed_charge, - :coal_fixed_charge, :wood_fixed_charge, :wood_pellets_fixed_charge, - :elec_marginal_rate, :natural_gas_marginal_rate, :propane_marginal_rate, :fuel_oil_marginal_rate, - :coal_marginal_rate, :wood_marginal_rate, :wood_pellets_marginal_rate, - :pv_compensation_type, - :pv_net_metering_annual_excess_sellback_rate_type, :pv_net_metering_annual_excess_sellback_rate, - :pv_feed_in_tariff_rate, - :pv_monthly_grid_connection_fee_dollars_per_kw, :pv_monthly_grid_connection_fee_dollars] + ATTRS = [:name, # [String] Name + :elec_tariff_filepath, # [String] UtilityRate[FuelType="electricity"]/TariffFilePath + :elec_fixed_charge, # [Double] UtilityRate[FuelType="electricity"]/FixedCharge ($/month) + :elec_marginal_rate, # [Double] UtilityRate[FuelType="electricity"]/MarginalRate ($/kWh) + :natural_gas_fixed_charge, # [Double] UtilityRate[FuelType="natural gas"]/FixedCharge ($/month) + :natural_gas_marginal_rate, # [Double] UtilityRate[FuelType="natural gas"]/MarginalRate ($/therm) + :propane_fixed_charge, # [Double] UtilityRate[FuelType="propane"]/FixedCharge ($/month) + :propane_marginal_rate, # [Double] UtilityRate[FuelType="propane"]/MarginalRate ($/gallon) + :fuel_oil_fixed_charge, # [Double] UtilityRate[FuelType="fuel oil"]/FixedCharge ($/month) + :fuel_oil_marginal_rate, # [Double] UtilityRate[FuelType="fuel oil"]/MarginalRate ($/gallon) + :coal_fixed_charge, # [Double] UtilityRate[FuelType="coal"]/FixedCharge ($/month) + :coal_marginal_rate, # [Double] UtilityRate[FuelType="coal"]/MarginalRate ($/kBtu) + :wood_fixed_charge, # [Double] UtilityRate[FuelType="wood"]/FixedCharge ($/month) + :wood_marginal_rate, # [Double] UtilityRate[FuelType="wood"]/MarginalRate ($/kBtu) + :wood_pellets_fixed_charge, # [Double] UtilityRate[FuelType="wood pellets"]/FixedCharge ($/month) + :wood_pellets_marginal_rate, # [Double] UtilityRate[FuelType="wood pellets"]/MarginalRate ($/kBtu) + :pv_compensation_type, # [String] PVCompensation/CompensationType/* + :pv_net_metering_annual_excess_sellback_rate_type, # [String] PVCompensation/CompensationType/NetMetering/AnnualExcessSellbackRateType (HPXML::PVAnnualExcessSellbackRateTypeXXX) + :pv_net_metering_annual_excess_sellback_rate, # [Double] PVCompensation/CompensationType/NetMetering/AnnualExcessSellbackRate ($/kWh) + :pv_feed_in_tariff_rate, # [Double] PVCompensation/CompensationType/FeedInTariff/FeedInTariffRate ($/kWh) + :pv_monthly_grid_connection_fee_dollars_per_kw, # [Double] PVCompensation/MonthlyGridConnectionFee[Units="$/kW"]/Value ($/kW) + :pv_monthly_grid_connection_fee_dollars] # [Double] PVCompensation/MonthlyGridConnectionFee[Units="$"]/Value ($) attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.header.utility_bill_scenarios.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(software_info) # rubocop:disable Style/DocumentationMethod - utility_bill_scenarios = XMLHelper.create_elements_as_needed(software_info, ['extension', 'UtilityBillScenarios']) + # Adds this object to the Oga XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def to_doc(hpxml) + utility_bill_scenarios = XMLHelper.create_elements_as_needed(hpxml, ['SoftwareInfo', 'extension', 'UtilityBillScenarios']) utility_bill_scenario = XMLHelper.add_element(utility_bill_scenarios, 'UtilityBillScenario') XMLHelper.add_element(utility_bill_scenario, 'Name', @name, :string) unless @name.nil? { HPXML::FuelTypeElectricity => [@elec_fixed_charge, @elec_fixed_charge_isdefaulted, @elec_marginal_rate, @elec_marginal_rate_isdefaulted, @elec_tariff_filepath], @@ -1110,7 +1224,11 @@ def to_doc(software_info) # rubocop:disable Style/DocumentationMethod end end - def from_doc(utility_bill_scenario) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param utility_bill_scenario [Oga::XML::Element] The current UtilityBillScenario XML element + # @return [void] + def from_doc(utility_bill_scenario) return if utility_bill_scenario.nil? @name = XMLHelper.get_value(utility_bill_scenario, 'Name', :string) @@ -1143,38 +1261,62 @@ def from_doc(utility_bill_scenario) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::UnavailablePeriod objects. class UnavailablePeriods < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << UnavailablePeriod.new(@parent_object, **kwargs) end - def from_doc(software_info) # rubocop:disable Style/DocumentationMethod - return if software_info.nil? + # Populates the HPXML object(s) from the XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def from_doc(hpxml) + return if hpxml.nil? - XMLHelper.get_elements(software_info, 'extension/UnavailablePeriods/UnavailablePeriod').each do |unavailable_period| + XMLHelper.get_elements(hpxml, 'SoftwareInfo/extension/UnavailablePeriods/UnavailablePeriod').each do |unavailable_period| self << UnavailablePeriod.new(@parent_object, unavailable_period) end end end - # TODO + # Object for /HPXML/SoftwareInfo/extension/UnavailablePeriods/UnavailablePeriod. class UnavailablePeriod < BaseElement - ATTRS = [:column_name, :begin_month, :begin_day, :begin_hour, :end_month, :end_day, :end_hour, :natvent_availability] + ATTRS = [:column_name, # [String] ColumnName + :begin_month, # [Integer] BeginMonth + :begin_day, # [Integer] BeginDayOfMonth + :begin_hour, # [Integer] BeginHourOfDay + :end_month, # [Integer] EndMonth + :end_day, # [Integer] EndDayOfMonth + :end_hour, # [Integer] EndHourOfDay + :natvent_availability] # [String] NaturalVentilation (HPXML::ScheduleXXX) attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.header.unavailable_periods.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] errors += HPXML::check_dates('Unavailable Period', @begin_month, @begin_day, @end_month, @end_day) return errors end - def to_doc(software_info) # rubocop:disable Style/DocumentationMethod - unavailable_periods = XMLHelper.create_elements_as_needed(software_info, ['extension', 'UnavailablePeriods']) + # Adds this object to the Oga XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def to_doc(hpxml) + unavailable_periods = XMLHelper.create_elements_as_needed(hpxml, ['SoftwareInfo', 'extension', 'UnavailablePeriods']) unavailable_period = XMLHelper.add_element(unavailable_periods, 'UnavailablePeriod') XMLHelper.add_element(unavailable_period, 'ColumnName', @column_name, :string) unless @column_name.nil? XMLHelper.add_element(unavailable_period, 'BeginMonth', @begin_month, :integer, @begin_month_isdefaulted) unless @begin_month.nil? @@ -1186,7 +1328,11 @@ def to_doc(software_info) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(unavailable_period, 'NaturalVentilation', @natvent_availability, :string, @natvent_availability_isdefaulted) unless @natvent_availability.nil? end - def from_doc(unavailable_period) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param unavailable_period [Oga::XML::Element] The current UnavailablePeriod XML element + # @return [void] + def from_doc(unavailable_period) return if unavailable_period.nil? @column_name = XMLHelper.get_value(unavailable_period, 'ColumnName', :string) @@ -1200,13 +1346,20 @@ def from_doc(unavailable_period) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Building objects. class Buildings < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Building.new(@parent_object, **kwargs) end - def from_doc(hpxml) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hpxml [Oga::XML::Element] Root XML element of the HPXML document + # @return [void] + def from_doc(hpxml) return if hpxml.nil? XMLHelper.get_elements(hpxml, 'Building').each do |building| @@ -1215,24 +1368,85 @@ def from_doc(hpxml) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building. class Building < BaseElement - CLASS_ATTRS = [:site, :neighbor_buildings, :building_occupancy, :building_construction, :header, - :climate_and_risk_zones, :zones, :air_infiltration, :air_infiltration_measurements, :attics, - :foundations, :roofs, :rim_joists, :walls, :foundation_walls, :floors, :slabs, :windows, - :skylights, :doors, :partition_wall_mass, :furniture_mass, :heating_systems, - :cooling_systems, :heat_pumps, :geothermal_loops, :hvac_plant, :hvac_controls, :hvac_distributions, - :ventilation_fans, :water_heating_systems, :hot_water_distributions, :water_fixtures, - :water_heating, :solar_thermal_systems, :pv_systems, :inverters, :generators, - :batteries, :clothes_washers, :clothes_dryers, :dishwashers, :refrigerators, - :freezers, :dehumidifiers, :cooking_ranges, :ovens, :lighting_groups, :lighting, - :ceiling_fans, :pools, :permanent_spas, :portable_spas, :plug_loads, :fuel_loads] - ATTRS = [:building_id, :site_id, :address_type, :address1, :address2, :city, :state_code, :zip_code, - :time_zone_utc_offset, :egrid_region, :egrid_subregion, :cambium_region_gea, - :dst_enabled, :dst_begin_month, :dst_begin_day, :dst_end_month, :dst_end_day, :event_type, - :elevation, :latitude, :longitude] - - attr_accessor(*CLASS_ATTRS) + CLASS_ATTRS = [:site, # [HPXML::Site] + :neighbor_buildings, # [HPXML::NeighborBuildings] + :building_occupancy, # [HPXML::BuildingOccupancy] + :building_construction, # [HPXML::BuildingConstruction] + :header, # [HPXML::BuildingHeader] + :climate_and_risk_zones, # [HPXML::ClimateandRiskZones] + :zones, # [HPXML::Zones] + :air_infiltration, # [HPXML::AirInfiltration] + :air_infiltration_measurements, # [HPXML::AirInfiltrationMeasurements] + :attics, # [HPXML::Attics] + :foundations, # [HPXML::Foundations] + :roofs, # [HPXML::Roofs] + :rim_joists, # [HPXML::RimJoists] + :walls, # [HPXML::Walls] + :foundation_walls, # [HPXML::FoundationWalls] + :floors, # [HPXML::Floors] + :slabs, # [HPXML::Slabs] + :windows, # [HPXML::Windows] + :skylights, # [HPXML::Skylights] + :doors, # [HPXML::Doors] + :partition_wall_mass, # [HPXML::PartitionWallMass] + :furniture_mass, # [HPXML::FurnitureMass] + :heating_systems, # [HPXML::HeatingSystems] + :cooling_systems, # [HPXML::CoolingSystems] + :heat_pumps, # [HPXML::HeatPumps] + :geothermal_loops, # [HPXML::GeothermalLoops] + :hvac_plant, # [HPXML::HVACPlant] + :hvac_controls, # [HPXML::HVACControls] + :hvac_distributions, # [HPXML::HVACDistributions] + :ventilation_fans, # [HPXML::VentilationFans] + :water_heating_systems, # [HPXML::WaterHeatingSystems] + :hot_water_distributions, # [HPXML::HotWaterDistributions] + :water_fixtures, # [HPXML::WaterFixtures] + :water_heating, # [HPXML::WaterHeating] + :solar_thermal_systems, # [HPXML::SolarThermalSystems] + :pv_systems, # [HPXML::PVSystems] + :inverters, # [HPXML::Inverters] + :batteries, # [HPXML::Batteries] + :generators, # [HPXML::Generators] + :clothes_washers, # [HPXML::ClothesWashers] + :clothes_dryers, # [HPXML::ClothesDryers] + :dishwashers, # [HPXML::Dishwashers] + :refrigerators, # [HPXML::Refrigerators] + :freezers, # [HPXML::Freezers] + :dehumidifiers, # [HPXML::Dehumidifiers] + :cooking_ranges, # [HPXML::CookingRanges] + :ovens, # [HPXML::Ovens] + :lighting_groups, # [HPXML::LightingGroups] + :ceiling_fans, # [HPXML::CeilingFans] + :lighting, # [HPXML::Lighting] + :pools, # [HPXML::Pools] + :permanent_spas, # [HPXML::PermanentSpas] + :portable_spas, # [HPXML::PortableSpas] + :plug_loads, # [HPXML::PlugLoads] + :fuel_loads] # [HPXML::FuelLoads] + ATTRS = [:building_id, # [String] BuildingID/@id + :site_id, # [String] Site/SiteID/@id + :address_type, # [String] Site/Address/AddressType (HPXML::AddressTypeXXX) + :address1, # [String] Site/Address/Address1 + :address2, # [String] Site/Address/Address2 + :city, # [String] Site/Address/CityMunicipality + :state_code, # [String] Site/Address/StateCode + :zip_code, # [String] Site/Address/ZipCode + :latitude, # [Double] Site/GeoLocation/Latitude (deg) + :longitude, # [Double] Site/GeoLocation/Longitude (deg) + :elevation, # [Double] Site/Elevation (ft) + :egrid_region, # [String] Site/eGridRegion + :egrid_subregion, # [String] Site/eGridSubregion + :cambium_region_gea, # [String] Site/CambiumRegionGEA + :time_zone_utc_offset, # [Double] TimeZone/UTCOffset + :dst_enabled, # [Boolean] TimeZone/DSTObserved + :dst_begin_month, # [Integer] TimeZone/extension/DSTBeginMonth + :dst_begin_day, # [Integer] TimeZone/extension/DSTBeginDayOfMonth + :dst_end_month, # [Integer] TimeZone/extension/DSTEndMonth + :dst_end_day, # [Integer] TimeZone/extension/DSTEndDayOfMonth + :event_type] # [String] ProjectStatus/EventType + attr_reader(*CLASS_ATTRS) attr_accessor(*ATTRS) def initialize(*args, **kwargs) @@ -1240,10 +1454,14 @@ def initialize(*args, **kwargs) super(*args, **kwargs) end - def to_doc(doc) # rubocop:disable Style/DocumentationMethod + # Adds this object to the Oga XML document. + # + # @param hpxml_doc [Oga::XML::Document] HPXML object as an XML document + # @return [void] + def to_doc(hpxml_doc) return if nil? - hpxml = XMLHelper.create_elements_as_needed(doc, ['HPXML']) + hpxml = XMLHelper.create_elements_as_needed(hpxml_doc, ['HPXML']) building = XMLHelper.add_element(hpxml, 'Building') building_building_id = XMLHelper.add_element(building, 'BuildingID') XMLHelper.add_attribute(building_building_id, 'id', @building_id) @@ -1275,15 +1493,9 @@ def to_doc(doc) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(geo_location, 'Longitude', @longitude, :float, @longitude_isdefaulted) unless @longitude.nil? end XMLHelper.add_element(building_site, 'Elevation', @elevation, :float, @elevation_isdefaulted) unless @elevation.nil? - if not @egrid_region.nil? - XMLHelper.add_element(building_site, 'eGridRegion', @egrid_region, :string, @egrid_region_isdefaulted) - end - if not @egrid_subregion.nil? - XMLHelper.add_element(building_site, 'eGridSubregion', @egrid_subregion, :string, @egrid_subregion_isdefaulted) - end - if not @cambium_region_gea.nil? - XMLHelper.add_element(building_site, 'CambiumRegionGEA', @cambium_region_gea, :string, @cambium_region_gea_isdefaulted) - end + XMLHelper.add_element(building_site, 'eGridRegion', @egrid_region, :string, @egrid_region_isdefaulted) unless @egrid_region.nil? + XMLHelper.add_element(building_site, 'eGridSubregion', @egrid_subregion, :string, @egrid_subregion_isdefaulted) unless @egrid_subregion.nil? + XMLHelper.add_element(building_site, 'CambiumRegionGEA', @cambium_region_gea, :string, @cambium_region_gea_isdefaulted) unless @cambium_region_gea.nil? if (not @time_zone_utc_offset.nil?) || (not @dst_enabled.nil?) || (not @dst_begin_month.nil?) || (not @dst_begin_day.nil?) || (not @dst_end_month.nil?) || (not @dst_end_day.nil?) time_zone = XMLHelper.add_element(building_site, 'TimeZone') XMLHelper.add_element(time_zone, 'UTCOffset', @time_zone_utc_offset, :float, @time_zone_utc_offset_isdefaulted) unless @time_zone_utc_offset.nil? @@ -1354,7 +1566,11 @@ def to_doc(doc) # rubocop:disable Style/DocumentationMethod @fuel_loads.to_doc(building) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) if not building.nil? @building_id = HPXML::get_id(building, 'BuildingID') @event_type = XMLHelper.get_value(building, 'ProjectStatus/EventType', :string) @@ -1436,22 +1652,31 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod @fuel_loads = FuelLoads.new(self, building) end - # TODO + # Returns all HPXML enclosure surfaces. + # + # @return [Array] List of surface objects def surfaces return (@roofs + @rim_joists + @walls + @foundation_walls + @floors + @slabs) end - # TODO + # Returns all HPXML enclosure sub-surfaces. + # + # @return [Array] List of sub-surface objects def subsurfaces return (@windows + @skylights + @doors) end - # TODO + # Returns all HPXML HVAC systems. + # + # @return [Array] List of HVAC system objects def hvac_systems return (@heating_systems + @cooling_systems + @heat_pumps) end - # TODO + # Returns whether the building has a given location. + # + # @param location [String] Location (HPXML::LocationXXX) + # @return [Boolean] True if location is used by the building def has_location(location) # Search for surfaces attached to this location surfaces.each do |surface| @@ -1461,9 +1686,12 @@ def has_location(location) return false end - # TODO + # Returns whether the building has access to non-electric fuels + # (e.g., natural gas, propane, etc.). + # + # @return [Boolean] True if building has access to fuels def has_fuel_access - @site.fuels.each do |fuel| + @site.available_fuels.each do |fuel| if fuel != FuelTypeElectricity return true end @@ -1471,13 +1699,19 @@ def has_fuel_access return false end - # TODO + # Returns a hash with whether each fuel exists in the HPXML Building. + # + # @param hpxml_doc [Oga::XML::Document] HPXML object as an XML document + # @return [Hash] Map of HPXML::FuelTypeXXX => boolean def has_fuels(hpxml_doc) # Returns a hash with whether each fuel exists in the HPXML Building return @parent_object.has_fuels(hpxml_doc, @building_id) end - # TODO + # Returns the predominant heating fuel type (weighted by fraction of + # heating load served). + # + # @return [String] Predominant heating fuel (HPXML::FuelTypeXXX) def predominant_heating_fuel fuel_fracs = {} @heating_systems.each do |heating_system| @@ -1498,7 +1732,10 @@ def predominant_heating_fuel return fuel_fracs.key(fuel_fracs.values.max) end - # TODO + # Returns the predominant water heating fuel type (weighted by fraction of + # DHW load served). + # + # @return [String] Predominant water heating fuel (HPXML::FuelTypeXXX) def predominant_water_heating_fuel fuel_fracs = {} @water_heating_systems.each do |water_heating_system| @@ -1517,10 +1754,11 @@ def predominant_water_heating_fuel return fuel_fracs.key(fuel_fracs.values.max) end - # TODO - def fraction_of_windows_operable() - # Calculates the fraction of windows that are operable. - # Since we don't have count available, we use area as an approximation. + # Calculates the fraction of windows that are operable. + # Since we don't have count available, we use area as an approximation. + # + # @return [Double] Total fraction of window area that is window area of operable windows + def fraction_of_windows_operable window_area_total = @windows.map { |w| w.area }.sum(0.0) window_area_operable = @windows.map { |w| w.fraction_operable * w.area }.sum(0.0) if window_area_total <= 0 @@ -1530,43 +1768,65 @@ def fraction_of_windows_operable() return window_area_operable / window_area_total end - # TODO - def conditioned_zones() + # Returns all HPXML zones that are conditioned. + # + # @return [Array] Conditioned zones + def conditioned_zones return zones.select { |z| z.zone_type == ZoneTypeConditioned } end - # TODO - def conditioned_spaces() + # Returns all HPXML spaces that are conditioned. + # + # @return [Array] Conditioned spaces + def conditioned_spaces return conditioned_zones.map { |z| z.spaces }.flatten end - # TODO - def primary_hvac_systems() + # Returns all HVAC systems that are labeled as primary systems. + # + # @return [Array] List of primary HVAC systems + def primary_hvac_systems return hvac_systems.select { |h| h.primary_system } end - # TODO - def total_fraction_cool_load_served() + # Returns the total fraction of building's cooling load served by HVAC systems. + # + # @return [Double] Total fraction of building's cooling load served + def total_fraction_cool_load_served return @cooling_systems.total_fraction_cool_load_served + @heat_pumps.total_fraction_cool_load_served end - # TODO - def total_fraction_heat_load_served() + # Returns the total fraction of building's heating load served by HVAC systems. + # + # @return [Double] Total fraction of building's heating load served + def total_fraction_heat_load_served return @heating_systems.total_fraction_heat_load_served + @heat_pumps.total_fraction_heat_load_served + @cooling_systems.total_fraction_heat_load_served end - # TODO - def has_walkout_basement() + # Estimates whether the building has a walkout basement based on its foundation + # type and the number of conditioned floors (total and above-grade). + # + # return [Boolean] True if the building has a walkout basement + def has_walkout_basement has_conditioned_basement = has_location(LocationBasementConditioned) ncfl = @building_construction.number_of_conditioned_floors ncfl_ag = @building_construction.number_of_conditioned_floors_above_grade return (has_conditioned_basement && (ncfl == ncfl_ag)) end - # TODO - def thermal_boundary_wall_areas() - ag_wall_area = 0.0 # Thermal boundary walls not in contact with soil - bg_wall_area = 0.0 # Thermal boundary walls in contact with soil + # Calculates above-grade and below-grade thermal boundary wall areas. + # Used to calculate the window area in the ERI Reference Home per ANSI 301. + # + # Thermal boundary wall is any wall that separates conditioned space from + # unconditioned space, outside, or soil. Above-grade thermal boundary + # wall is any portion of a thermal boundary wall not in contact with soil. + # Below-grade thermal boundary wall is any portion of a thermal boundary + # wall in contact with soil. + # + # @return [Array] Above-grade and below-grade thermal boundary wall areas (ft2) + def thermal_boundary_wall_areas + ag_wall_area = 0.0 + bg_wall_area = 0.0 (@walls + @rim_joists).each do |wall| next unless wall.is_thermal_boundary @@ -1586,19 +1846,24 @@ def thermal_boundary_wall_areas() return ag_wall_area, bg_wall_area end - # TODO - def above_grade_conditioned_volume() + # Estimates the above-grade conditioned volume. + # + # @return [Double] Above-grade conditioned volume (ft3) + def above_grade_conditioned_volume ag_wall_area, bg_wall_area = thermal_boundary_wall_areas() ag_ratio = ag_wall_area / (ag_wall_area + bg_wall_area) return @building_construction.conditioned_building_volume * ag_ratio end - # TODO - def common_wall_area() - # Wall area for walls adjacent to Unrated Conditioned Space, not including - # foundation walls. + # Calculates common wall area. + # Used to calculate the window area in the ERI Reference Home per ANSI 301. + # + # Common wall is the total wall area of walls adjacent to other unit's + # conditioned space, not including foundation walls. + # + # @return [Double] Common wall area (ft2) + def common_wall_area area = 0.0 - (@walls + @rim_joists).each do |wall| next unless HPXML::conditioned_locations_this_unit.include? wall.interior_adjacent_to @@ -1608,13 +1873,15 @@ def common_wall_area() area += wall.area end end - return area end - # TODO - def compartmentalization_boundary_areas() - # Returns the infiltration compartmentalization boundary areas + # Returns the total and exterior compartmentalization boundary area. + # Used to convert between total infiltration and exterior infiltration for + # SFA/MF dwelling units per ANSI 301. + # + # @return [Array] Total and exterior compartmentalization areas (ft2) + def compartmentalization_boundary_areas total_area = 0.0 # Total surface area that bounds the Infiltration Volume exterior_area = 0.0 # Same as above excluding surfaces attached to garage, other housing units, or other multifamily spaces (see 301-2019 Addendum B) @@ -1662,11 +1929,15 @@ def compartmentalization_boundary_areas() return total_area, exterior_area end - # TODO + # Calculates the inferred infiltration height. + # Infiltration height is the vertical distance between lowest and highest + # above-grade points within the pressure boundary. + # + # Note: The WithinInfiltrationVolume properties are intentionally ignored for now. + # + # @param infil_volume [Double] Volume of space most impacted by the blower door test (ft3) + # @return [Double] Inferred infiltration height (ft) def inferred_infiltration_height(infil_volume) - # Infiltration height: vertical distance between lowest and highest above-grade points within the pressure boundary. - # Height is inferred from available HPXML properties. - # The WithinInfiltrationVolume properties are intentionally ignored for now. cfa = @building_construction.conditioned_floor_area ncfl_ag = @building_construction.number_of_conditioned_floors_above_grade @@ -1699,7 +1970,9 @@ def inferred_infiltration_height(infil_volume) return infil_height end - # TODO + # Calculates the inferred conditioned crawlspace volume. + # + # @return [Double] Inferred conditioned crawlspace volume (ft3) def inferred_conditioned_crawlspace_volume if has_location(HPXML::LocationCrawlspaceConditioned) conditioned_crawl_area = @slabs.select { |s| s.interior_adjacent_to == HPXML::LocationCrawlspaceConditioned }.map { |s| s.area }.sum @@ -1709,8 +1982,10 @@ def inferred_conditioned_crawlspace_volume return 0.0 end - # TODO - def delete_adiabatic_subsurfaces() + # Deletes any adiabatic sub-surfaces since EnergyPlus does not allow it. + # + # @return [void] + def delete_adiabatic_subsurfaces @doors.reverse_each do |door| next if door.wall.nil? next if door.wall.exterior_adjacent_to != HPXML::LocationOtherHousingUnit @@ -1725,8 +2000,12 @@ def delete_adiabatic_subsurfaces() end end - # TODO - def check_for_errors() + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # It's preferred to check for errors in the validators, but that is not always + # easy or possible, so additional checking occurs here. + # + # @return [Array] List of error messages + def check_for_errors errors = [] errors += HPXML::check_dates('Daylight Saving', @dst_begin_month, @dst_begin_day, @dst_end_month, @dst_end_day) @@ -1848,12 +2127,13 @@ def check_for_errors() return errors end - # TODO + # Collapses like surfaces into a single surface with, e.g., aggregate surface area. + # This can significantly speed up performance for HPXML files with lots of individual + # surfaces (e.g., windows). + # + # @param surf_types_of_interest [Array] Subset of surface types (e.g., :roofs, :walls, etc.) to collapse + # @return [void] def collapse_enclosure_surfaces(surf_types_of_interest = nil) - # Collapses like surfaces into a single surface with, e.g., aggregate surface area. - # This can significantly speed up performance for HPXML files with lots of individual - # surfaces (e.g., windows). - surf_types = { roofs: @roofs, walls: @walls, rim_joists: @rim_joists, @@ -1948,18 +2228,34 @@ def collapse_enclosure_surfaces(surf_types_of_interest = nil) end end - # TODO + # Object for /HPXML/Building/BuildingDetails/BuildingSummary/Site. class Site < BaseElement - ATTRS = [:site_type, :surroundings, :vertical_surroundings, :shielding_of_home, :orientation_of_front_of_home, :azimuth_of_front_of_home, :fuels, - :soil_type, :moisture_type, :ground_conductivity, :ground_diffusivity] + ATTRS = [:site_type, # [String] SiteType (HPXML::SiteTypeXXX) + :surroundings, # [String] Surroundings (HPXML::SurroundingsXXX) + :vertical_surroundings, # [String] VerticalSurroundings (HPXML::VerticalSurroundingsXXX) + :shielding_of_home, # [String] ShieldingofHome (HPXML::ShieldingXXX) + :orientation_of_front_of_home, # [String] OrientationOfFrontOfHome (HPXML::OrientationXXX) + :azimuth_of_front_of_home, # [Integer] AzimuthOfFrontOfHome (deg) + :available_fuels, # [Array] FuelTypesAvailable/Fuel (HPXML::FuelTypeXXX) + :soil_type, # [String] Soil/SoilType (HPXML::SiteSoilTypeXXX) + :moisture_type, # [String] Soil/MoistureType (HPXML::SiteSoilMoistureTypeXXX) + :ground_conductivity, # [Double] Soil/Conductivity (Btu/hr-ft-F) + :ground_diffusivity] # [Double] Soil/extension/Diffusivity (ft2/hr) attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? site = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'BuildingSummary', 'Site']) @@ -1969,9 +2265,9 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(site, 'ShieldingofHome', @shielding_of_home, :string, @shielding_of_home_isdefaulted) unless @shielding_of_home.nil? XMLHelper.add_element(site, 'OrientationOfFrontOfHome', @orientation_of_front_of_home, :string) unless @orientation_of_front_of_home.nil? XMLHelper.add_element(site, 'AzimuthOfFrontOfHome', @azimuth_of_front_of_home, :integer) unless @azimuth_of_front_of_home.nil? - if (not @fuels.nil?) && (not @fuels.empty?) + if (not @available_fuels.nil?) && (not @available_fuels.empty?) fuel_types_available = XMLHelper.add_element(site, 'FuelTypesAvailable') - @fuels.each do |fuel| + @available_fuels.each do |fuel| XMLHelper.add_element(fuel_types_available, 'Fuel', fuel, :string) end end @@ -1992,7 +2288,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? site = XMLHelper.get_element(building, 'BuildingDetails/BuildingSummary/Site') @@ -2004,7 +2304,7 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod @shielding_of_home = XMLHelper.get_value(site, 'ShieldingofHome', :string) @orientation_of_front_of_home = XMLHelper.get_value(site, 'OrientationOfFrontOfHome', :string) @azimuth_of_front_of_home = XMLHelper.get_value(site, 'AzimuthOfFrontOfHome', :integer) - @fuels = XMLHelper.get_values(site, 'FuelTypesAvailable/Fuel', :string) + @available_fuels = XMLHelper.get_values(site, 'FuelTypesAvailable/Fuel', :string) @soil_type = XMLHelper.get_value(site, 'Soil/SoilType', :string) @moisture_type = XMLHelper.get_value(site, 'Soil/MoistureType', :string) @ground_conductivity = XMLHelper.get_value(site, 'Soil/Conductivity', :float) @@ -2012,13 +2312,20 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::NeighborBuilding objects. class NeighborBuildings < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << NeighborBuilding.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/BuildingSummary/Site/extension/Neighbors/NeighborBuilding').each do |neighbor_building| @@ -2027,17 +2334,27 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/BuildingSummary/Site/extension/Neighbors/NeighborBuilding. class NeighborBuilding < BaseElement - ATTRS = [:azimuth, :orientation, :distance, :height] + ATTRS = [:orientation, # [String] Orientation (HPXML::OrientationXXX) + :azimuth, # [Integer] Azimuth (deg) + :distance, # [Double] Distance (ft) + :height] # [Double] Height (ft) attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? neighbors = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'BuildingSummary', 'Site', 'extension', 'Neighbors']) @@ -2048,7 +2365,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(neighbor_building, 'Height', @height, :float) unless @height.nil? end - def from_doc(neighbor_building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param neighbor_building [Oga::XML::Element] The current NeighborBuilding XML element + # @return [void] + def from_doc(neighbor_building) return if neighbor_building.nil? @orientation = XMLHelper.get_value(neighbor_building, 'Orientation', :string) @@ -2058,18 +2379,31 @@ def from_doc(neighbor_building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/BuildingSummary/BuildingOccupancy. class BuildingOccupancy < BaseElement - ATTRS = [:number_of_residents, :weekday_fractions, :weekend_fractions, :monthly_multipliers, :general_water_use_usage_multiplier, - :general_water_use_weekday_fractions, :general_water_use_weekend_fractions, :general_water_use_monthly_multipliers] + ATTRS = [:number_of_residents, # [Double] NumberofResidents + :weekday_fractions, # [String] extension/WeekdayScheduleFractions + :weekend_fractions, # [String] extension/WeekendScheduleFractions + :monthly_multipliers, # [String] extension/MonthlyScheduleMultipliers + :general_water_use_usage_multiplier, # [Double] extension/GeneralWaterUseUsageMultiplier + :general_water_use_weekday_fractions, # [String] extension/GeneralWaterUseWeekdayScheduleFractions + :general_water_use_weekend_fractions, # [String] extension/GeneralWaterUseWeekendScheduleFractions + :general_water_use_monthly_multipliers] # [String] extension/GeneralWaterUseMonthlyScheduleMultipliers attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? building_occupancy = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'BuildingSummary', 'BuildingOccupancy']) @@ -2083,7 +2417,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(building_occupancy, 'GeneralWaterUseMonthlyScheduleMultipliers', @general_water_use_monthly_multipliers, :string, @general_water_use_monthly_multipliers_isdefaulted) unless @general_water_use_monthly_multipliers.nil? end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? building_occupancy = XMLHelper.get_element(building, 'BuildingDetails/BuildingSummary/BuildingOccupancy') @@ -2100,21 +2438,36 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/BuildingSummary/BuildingConstruction. class BuildingConstruction < BaseElement - ATTRS = [:year_built, :number_of_conditioned_floors, :number_of_conditioned_floors_above_grade, - :average_ceiling_height, :number_of_bedrooms, :number_of_bathrooms, - :conditioned_floor_area, :conditioned_building_volume, :residential_facility_type, - :building_footprint_area, :number_of_units, :number_of_units_in_building, - :manufactured_home_sections] + ATTRS = [:year_built, # [Integer] YearBuilt + :residential_facility_type, # [String] ResidentialFacilityType (HXPML::ResidentialTypeXXX) + :number_of_units, # [Integer] NumberofUnits + :number_of_units_in_building, # [Integer] NumberofUnitsInBuilding + :number_of_conditioned_floors, # [Double] NumberofConditionedFloors + :number_of_conditioned_floors_above_grade, # [Double] NumberofConditionedFloorsAboveGrade + :average_ceiling_height, # [Double] AverageCeilingHeight (ft) + :number_of_bedrooms, # [Integer] NumberofBedrooms + :number_of_bathrooms, # [Integer] NumberofBathrooms + :building_footprint_area, # [Double] BuildingFootprintArea (ft2) + :conditioned_floor_area, # [Double] ConditionedFloorArea (ft2) + :conditioned_building_volume, # [Double] ConditionedBuildingVolume (ft3) + :manufactured_home_sections] # [String] ManufacturedHomeSections attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? building_construction = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'BuildingSummary', 'BuildingConstruction']) @@ -2133,7 +2486,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(building_construction, 'ManufacturedHomeSections', @manufactured_home_sections, :string) unless @manufactured_home_sections.nil? end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? building_construction = XMLHelper.get_element(building, 'BuildingDetails/BuildingSummary/BuildingConstruction') @@ -2155,24 +2512,45 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for high-level Building-specific information in /HPXML/Building/BuildingDetails/BuildingSummary/extension. class BuildingHeader < BaseElement - ATTRS = [:schedules_filepaths, :extension_properties, :natvent_days_per_week, - :heat_pump_sizing_methodology, :heat_pump_backup_sizing_methodology, :allow_increased_fixed_capacities, - :shading_summer_begin_month, :shading_summer_begin_day, :shading_summer_end_month, - :shading_summer_end_day, :manualj_heating_design_temp, :manualj_cooling_design_temp, - :manualj_heating_setpoint, :manualj_cooling_setpoint, :manualj_humidity_setpoint, - :manualj_internal_loads_sensible, :manualj_internal_loads_latent, :manualj_num_occupants, - :manualj_daily_temp_range, :manualj_humidity_difference, :manualj_infiltration_method] + ATTRS = [:heat_pump_sizing_methodology, # [String] HVACSizingControl/HeatPumpSizingMethodology (HPXML::HeatPumpSizingXXX) + :heat_pump_backup_sizing_methodology, # [String] HVACSizingControl/HeatPumpBackupSizingMethodology (HPXML::HeatPumpBackupSizingXXX) + :allow_increased_fixed_capacities, # [Boolean] HVACSizingControl/AllowIncreasedFixedCapacities + :manualj_heating_design_temp, # [Double] HVACSizingControl/ManualJInputs/HeatingDesignTemperature (F) + :manualj_cooling_design_temp, # [Double] HVACSizingControl/ManualJInputs/CoolingDesignTemperature (F) + :manualj_daily_temp_range, # [String] HVACSizingControl/ManualJInputs/DailyTemperatureRange (HPXML::ManualJDailyTempRangeXXX) + :manualj_heating_setpoint, # [Double] HVACSizingControl/ManualJInputs/HeatingSetpoint (F) + :manualj_cooling_setpoint, # [Double] HVACSizingControl/ManualJInputs/CoolingSetpoint (F) + :manualj_humidity_setpoint, # [Double] HVACSizingControl/ManualJInputs/HumiditySetpoint (frac) + :manualj_humidity_difference, # [Double] HVACSizingControl/ManualJInputs/HumidityDifference (grains) + :manualj_internal_loads_sensible, # [Double] HVACSizingControl/ManualJInputs/InternalLoadsSensible (Btu/hr) + :manualj_internal_loads_latent, # [Double] HVACSizingControl/ManualJInputs/InternalLoadsLatent (Btu/hr) + :manualj_num_occupants, # [Integer] HVACSizingControl/ManualJInputs/NumberofOccupants + :manualj_infiltration_method, # [String] HVACSizingControl/ManualJInputs/InfiltrationMethod (HPXML::ManualJInfiltrationMethodXXX) + :natvent_days_per_week, # [Integer] NaturalVentilationAvailabilityDaysperWeek + :schedules_filepaths, # [Array] SchedulesFilePath + :shading_summer_begin_month, # [Integer] ShadingControl/SummerBeginMonth + :shading_summer_begin_day, # [Integer] ShadingControl/SummerBeginDayOfMonth + :shading_summer_end_month, # [Integer] ShadingControl/SummerEndMonth + :shading_summer_end_day, # [Integer] ShadingControl/SummerEndDayOfMonth + :extension_properties] # [Hash] AdditionalProperties attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] errors += HPXML::check_dates('Shading Summer Season', @shading_summer_begin_month, @shading_summer_begin_day, @shading_summer_end_month, @shading_summer_end_day) return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? building_summary = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'BuildingSummary']) @@ -2217,7 +2595,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? building_summary = XMLHelper.get_element(building, 'BuildingDetails/BuildingSummary') @@ -2255,23 +2637,34 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/ClimateandRiskZones. class ClimateandRiskZones < BaseElement def initialize(hpxml_bldg, *args, **kwargs) @climate_zone_ieccs = ClimateZoneIECCs.new(hpxml_bldg) super(hpxml_bldg, *args, **kwargs) end - ATTRS = [:weather_station_id, :weather_station_name, :weather_station_wmo, :weather_station_epw_filepath] + CLASS_ATTRS = [:climate_zone_ieccs] # [HPXML::ClimateZoneIECCs] + ATTRS = [:weather_station_id, # [String] WeatherStation/SystemIdentifier/@id + :weather_station_name, # [String] WeatherStation/Name + :weather_station_wmo, # [String] WeatherStation/WMO + :weather_station_epw_filepath] # [String] WeatherStation/extension/EPWFilePath + attr_reader(*CLASS_ATTRS) attr_accessor(*ATTRS) - attr_reader(:climate_zone_ieccs) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] errors += @climate_zone_ieccs.check_for_errors return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? climate_and_risk_zones = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'ClimateandRiskZones']) @@ -2288,13 +2681,17 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? climate_and_risk_zones = XMLHelper.get_element(building, 'BuildingDetails/ClimateandRiskZones') return if climate_and_risk_zones.nil? - @climate_zone_ieccs.from_doc(climate_and_risk_zones) + @climate_zone_ieccs.from_doc(building) weather_station = XMLHelper.get_element(climate_and_risk_zones, 'WeatherStation') if not weather_station.nil? @@ -2306,42 +2703,64 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::ClimateZoneIECC objects. class ClimateZoneIECCs < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << ClimateZoneIECC.new(@parent_object, **kwargs) end - def from_doc(climate_and_risk_zones) # rubocop:disable Style/DocumentationMethod - return if climate_and_risk_zones.nil? + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) + return if building.nil? - XMLHelper.get_elements(climate_and_risk_zones, 'ClimateZoneIECC').each do |climate_zone_iecc| + XMLHelper.get_elements(building, 'BuildingDetails/ClimateandRiskZones/ClimateZoneIECC').each do |climate_zone_iecc| self << ClimateZoneIECC.new(@parent_object, climate_zone_iecc) end end end - # TODO + # Object for /HPXML/Building/BuildingDetails/ClimateandRiskZones/ClimateZoneIECC. class ClimateZoneIECC < BaseElement - ATTRS = [:year, :zone] + ATTRS = [:year, # [Integer] Year + :zone] # [String] ClimateZone attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.climate_and_risk_zones.climate_zone_ieccs.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(climate_and_risk_zones) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param climate_and_risk_zones [Oga::XML::Element] Parent XML element + # @return [void] + def to_doc(climate_and_risk_zones) climate_zone_iecc = XMLHelper.add_element(climate_and_risk_zones, 'ClimateZoneIECC') XMLHelper.add_element(climate_zone_iecc, 'Year', @year, :integer, @year_isdefaulted) unless @year.nil? XMLHelper.add_element(climate_zone_iecc, 'ClimateZone', @zone, :string, @zone_isdefaulted) unless @zone.nil? end - def from_doc(climate_zone_iecc) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param climate_and_risk_zones [Oga::XML::Element] The current ClimateZoneIECC XML element + # @return [void] + def from_doc(climate_zone_iecc) return if climate_zone_iecc.nil? @year = XMLHelper.get_value(climate_zone_iecc, 'Year', :integer) @@ -2349,13 +2768,20 @@ def from_doc(climate_zone_iecc) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Zone objects. class Zones < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Zone.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Zones/Zone').each do |zone| @@ -2364,16 +2790,25 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Zones/Zone. class Zone < BaseElement def initialize(hpxml_bldg, *args, **kwargs) @spaces = Spaces.new(hpxml_bldg) super(hpxml_bldg, *args, **kwargs) end - ATTRS = [:id, :zone_type, :spaces] + HDL_ATTRS.keys + CDL_SENS_ATTRS.keys + CDL_LAT_ATTRS.keys + CLASS_ATTRS = [:spaces] # [HPXML::Spaces] + ATTRS = [:id, # [String] SystemIdentifier/@id + :zone_type] + # [String] ZoneType (HPXML::ZoneTypeXXX) + HDL_ATTRS.keys + + CDL_SENS_ATTRS.keys + + CDL_LAT_ATTRS.keys + attr_accessor(*CLASS_ATTRS) attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] if zone_type == ZoneTypeConditioned # Check all surfaces attached to the zone are adjacent to conditioned space @@ -2387,94 +2822,133 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete hvac_systems.reverse_each do |hvac_system| hvac_system.attached_to_zone_idref = nil end @parent_object.zones.delete(self) end - # TODO + # Returns all heating systems for this zone. + # + # @return [Array] List of heating system objects def heating_systems return @parent_object.heating_systems.select { |s| s.attached_to_zone_idref == @id } end - # TODO + # Returns all cooling systems for this zone. + # + # @return [Array] List of cooling system objects def cooling_systems return @parent_object.cooling_systems.select { |s| s.attached_to_zone_idref == @id } end - # TODO + # Returns all heat pumps for this zone. + # + # @return [Array] List of heat pump objects def heat_pumps return @parent_object.heat_pumps.select { |s| s.attached_to_zone_idref == @id } end - # TODO + # Returns all HVAC systems for this zone. + # + # @return [Array] List of HVAC system objects def hvac_systems return @parent_object.hvac_systems.select { |s| s.attached_to_zone_idref == @id } end - # TODO + # Returns all HVAC distributions for this zone. + # + # @return [Array] List of HVAC distribution objects def hvac_distributions return hvac_systems.select { |s| !s.distribution_system.nil? }.map { |s| s.distribution_system }.uniq end - # TODO + # Returns the total floor area for this zone. + # + # @return [Double] Zone floor area (ft2) def floor_area return spaces.map { |space| space.floor_area }.sum end - # TODO + # Returns all roofs for this zone. + # + # @return [Array] List of roof objects def roofs return spaces.map { |space| space.roofs }.flatten end - # TODO + # Returns all rim joists for this zone. + # + # @return [Array] List of rim joist objects def rim_joists return spaces.map { |space| space.rim_joists }.flatten end - # TODO + # Returns all walls for this zone. + # + # @return [Array] List of wall objects def walls return spaces.map { |space| space.walls }.flatten end - # TODO + # Returns all foundation walls for this zone. + # + # @return [Array] List of foundation wall objects def foundation_walls return spaces.map { |space| space.foundation_walls }.flatten end - # TODO + # Returns all floors for this zone. + # + # @return [Array] List of floor objects def floors return spaces.map { |space| space.floors }.flatten end - # TODO + # Returns all slabs for this zone. + # + # @return [Array] List of slab objects def slabs return spaces.map { |space| space.slabs }.flatten end - # TODO + # Returns all windows for this zone. + # + # @return [Array] List of window objects def windows return spaces.map { |space| space.windows }.flatten end - # TODO + # Returns all doors for this zone. + # + # @return [Array] List of door objects def doors return spaces.map { |space| space.doors }.flatten end - # TODO + # Returns all skylights for this zone. + # + # @return [Array] List of skylight objects def skylights return spaces.map { |space| space.skylights }.flatten end - # TODO + # Returns all enclosure surfaces for this zone. + # + # @return [Array] List of surface objects def surfaces return (roofs + rim_joists + walls + foundation_walls + floors + slabs) end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? zones = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Zones']) @@ -2488,7 +2962,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(zone) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param zone [Oga::XML::Element] The current Zone XML element + # @return [void] + def from_doc(zone) return if zone.nil? @id = HPXML::get_id(zone) @@ -2498,13 +2976,20 @@ def from_doc(zone) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Space objects. class Spaces < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Space.new(@parent_object, **kwargs) end - def from_doc(zone) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param zone [Oga::XML::Element] The current Zone XML element + # @return [void] + def from_doc(zone) return if zone.nil? XMLHelper.get_elements(zone, 'Spaces/Space').each do |space| @@ -2513,80 +2998,119 @@ def from_doc(zone) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Zones/Zone/Spaces/Space. class Space < BaseElement - ATTRS = [:id, :floor_area, :manualj_internal_loads_sensible, :manualj_internal_loads_latent, - :manualj_num_occupants, :fenestration_load_procedure] + HDL_ATTRS.keys + CDL_SENS_ATTRS.keys + CDL_LAT_ATTRS.keys + ATTRS = [:id, # [String] SystemIdentifier/@id + :floor_area, # [Double] FloorArea (ft2) + :manualj_internal_loads_sensible, # [Double] extension/ManualJInputs/InternalLoadsSensible (Btu/hr) + :manualj_internal_loads_latent, # [Double] extension/ManualJInputs/InternalLoadsLatent (Btu/hr) + :manualj_num_occupants, # [Double] extension/ManualJInputs/NumberofOccupants + :fenestration_load_procedure] + # [String] extension/ManualJInputs/FenestrationLoadProcedure (HPXML::SpaceFenestrationLoadProcedureXXX) + HDL_ATTRS.keys + + CDL_SENS_ATTRS.keys + + CDL_LAT_ATTRS.keys attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete surfaces.reverse_each do |surface| surface.attached_to_space_idref = nil end zone.spaces.delete(self) end - # TODO + # Returns the parent zone. + # + # @return [HPXML::Zone] Zone object def zone return @parent_object.zones.find { |zone| zone.spaces.include? self } end - # TODO + # Returns all roofs for this space. + # + # @return [Array] List of roof objects def roofs return @parent_object.roofs.select { |s| s.attached_to_space_idref == @id } end - # TODO + # Returns all rim joists for this space. + # + # @return [Array] List of rim joist objects def rim_joists return @parent_object.rim_joists.select { |s| s.attached_to_space_idref == @id } end - # TODO + # Returns all walls for this space. + # + # @return [Array] List of wall objects def walls return @parent_object.walls.select { |s| s.attached_to_space_idref == @id } end - # TODO + # Returns all foundation walls for this space. + # + # @return [Array] List of foundation wall objects def foundation_walls return @parent_object.foundation_walls.select { |s| s.attached_to_space_idref == @id } end - # TODO + # Returns all floors for this space. + # + # @return [Array] List of floor objects def floors return @parent_object.floors.select { |s| s.attached_to_space_idref == @id } end - # TODO + # Returns all slabs for this space. + # + # @return [Array] List of slab objects def slabs return @parent_object.slabs.select { |s| s.attached_to_space_idref == @id } end - # TODO + # Returns all windows for this space. + # + # @return [Array] List of window objects def windows return @parent_object.windows.select { |s| s.wall.attached_to_space_idref == @id } end - # TODO + # Returns all doors for this space. + # + # @return [Array] List of door objects def doors return @parent_object.doors.select { |s| s.wall.attached_to_space_idref == @id } end - # TODO + # Returns all skylights for this space. + # + # @return [Array] List of skylight objects def skylights return @parent_object.skylights.select { |s| s.roof.attached_to_space_idref == @id || ((not s.floor.nil?) && s.floor.attached_to_space_idref == @id) } end - # TODO + # Returns all enclosure surfaces for this space. + # + # @return [Array] List of surface objects def surfaces return (roofs + rim_joists + walls + foundation_walls + floors + slabs) end - def to_doc(zone) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param zone [Oga::XML::Element] Parent XML element + # @return [void] + def to_doc(zone) return if nil? spaces = XMLHelper.create_elements_as_needed(zone, ['Spaces']) @@ -2606,7 +3130,11 @@ def to_doc(zone) # rubocop:disable Style/DocumentationMethod end end - def from_doc(space) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param space [Oga::XML::Element] The current Space XML element + # @return [void] + def from_doc(space) return if space.nil? @id = HPXML::get_id(space) @@ -2619,24 +3147,35 @@ def from_doc(space) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/AirInfiltration. class AirInfiltration < BaseElement - ATTRS = [:has_flue_or_chimney_in_conditioned_space] + ATTRS = [:has_flue_or_chimney_in_conditioned_space] # [Boolean] extension/HasFlueOrChimneyInConditionedSpace attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? air_infiltration = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'AirInfiltration']) XMLHelper.add_extension(air_infiltration, 'HasFlueOrChimneyInConditionedSpace', @has_flue_or_chimney_in_conditioned_space, :boolean, @has_flue_or_chimney_in_conditioned_space_isdefaulted) unless @has_flue_or_chimney_in_conditioned_space.nil? end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? air_infiltration = XMLHelper.get_element(building, 'BuildingDetails/Enclosure/AirInfiltration') @@ -2646,13 +3185,20 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::AirInfiltrationMeasurement objects. class AirInfiltrationMeasurements < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << AirInfiltrationMeasurement.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/AirInfiltration/AirInfiltrationMeasurement').each do |air_infiltration_measurement| @@ -2661,18 +3207,34 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/AirInfiltration/AirInfiltrationMeasurement. class AirInfiltrationMeasurement < BaseElement - ATTRS = [:id, :house_pressure, :unit_of_measure, :air_leakage, :effective_leakage_area, :type_of_measurement, - :infiltration_volume, :leakiness_description, :infiltration_height, :a_ext, :infiltration_type] + ATTRS = [:id, # [String] SystemIdentifier/@id + :type_of_measurement, # [String] TypeOfInfiltrationMeasurement + :infiltration_type, # [String] TypeOfInfiltrationLeakage (HPXML::InfiltrationTypeXXX) + :house_pressure, # [Double] HousePressure (Pa) + :leakiness_description, # [String] LeakinessDescription (HPXML::LeakinessXXX) + :unit_of_measure, # [String] BuildingAirLeakage/UnitofMeasure (HPXML::UnitsXXX) + :air_leakage, # [Double] BuildingAirLeakage/AirLeakage + :effective_leakage_area, # [Double] EffectiveLeakageArea (sq. in.) + :infiltration_volume, # [Double] InfiltrationVolume (ft3) + :infiltration_height, # [Double] InfiltrationHeight (ft) + :a_ext] # [Double] Aext (frac) attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? air_infiltration = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'AirInfiltration']) @@ -2694,7 +3256,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(air_infiltration_measurement, 'Aext', @a_ext, :float, @a_ext_isdefaulted) unless @a_ext.nil? end - def from_doc(air_infiltration_measurement) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param air_infiltration_measurement [Oga::XML::Element] The current AirInfiltrationMeasurement XML element + # @return [void] + def from_doc(air_infiltration_measurement) return if air_infiltration_measurement.nil? @id = HPXML::get_id(air_infiltration_measurement) @@ -2711,13 +3277,20 @@ def from_doc(air_infiltration_measurement) # rubocop:disable Style/Documentation end end - # TODO + # Array of HPXML::Attic objects. class Attics < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Attic.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Attics/Attic').each do |attic| @@ -2726,13 +3299,21 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Attics/Attic. class Attic < BaseElement - ATTRS = [:id, :attic_type, :vented_attic_sla, :vented_attic_ach, :within_infiltration_volume, - :attached_to_roof_idrefs, :attached_to_wall_idrefs, :attached_to_floor_idrefs] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attic_type, # [String] AtticType/* + :vented_attic_sla, # [Double] AtticType/Vented/VentilationRate[UnitofMeasure="SLA"]/Value + :vented_attic_ach, # [Double] AtticType/Vented/VentilationRate[UnitofMeasure="ACHnatural"]/Value + :within_infiltration_volume, # [Boolean] WithinInfiltrationVolume + :attached_to_roof_idrefs, # [Array] AttachedToRoof/@idref + :attached_to_wall_idrefs, # [Array] AttachedToWall/@idref + :attached_to_floor_idrefs] # [Array] AttachedToFloor/@idref attr_accessor(*ATTRS) - # TODO + # Returns all roofs for this attic. + # + # @return [Array] List of roof objects def attached_roofs return [] if @attached_to_roof_idrefs.nil? @@ -2744,7 +3325,9 @@ def attached_roofs return list end - # TODO + # Returns all walls for this attic. + # + # @return [Array] List of wall objects def attached_walls return [] if @attached_to_wall_idrefs.nil? @@ -2756,7 +3339,9 @@ def attached_walls return list end - # TODO + # Returns all floors for this attic. + # + # @return [Array] List of floor objects def attached_floors return [] if @attached_to_floor_idrefs.nil? @@ -2768,7 +3353,9 @@ def attached_floors return list end - # TODO + # Returns the location that corresponds to the attic. + # + # @return [String] Adjacent location (HPXML::LocationXXX) def to_location return if @attic_type.nil? @@ -2783,11 +3370,17 @@ def to_location end end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.attics.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; attached_roofs; rescue StandardError => e; errors << e.message; end begin; attached_walls; rescue StandardError => e; errors << e.message; end @@ -2796,7 +3389,11 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? attics = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Attics']) @@ -2850,7 +3447,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(attic) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param attic [Oga::XML::Element] The current Attic XML element + # @return [void] + def from_doc(attic) return if attic.nil? @id = HPXML::get_id(attic) @@ -2887,13 +3488,20 @@ def from_doc(attic) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Foundation objects. class Foundations < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Foundation.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Foundations/Foundation').each do |foundation| @@ -2902,15 +3510,23 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Foundations/Foundation. class Foundation < BaseElement - ATTRS = [:id, :foundation_type, :vented_crawlspace_sla, :within_infiltration_volume, - :belly_wing_skirt_present, :attached_to_slab_idrefs, :attached_to_floor_idrefs, - :attached_to_foundation_wall_idrefs, :attached_to_wall_idrefs, - :attached_to_rim_joist_idrefs] + ATTRS = [:id, # [String] SystemIdentifier/@id + :foundation_type, # [String] FoundationType/* + :vented_crawlspace_sla, # [Double] FoundationType/Crawlspace[Vented="true"]/VentilationRate[UnitofMeasure="SLA"]/Value + :belly_wing_skirt_present, # [Boolean] FoundationType/BellyAndWing/SkirtPresent + :within_infiltration_volume, # [Boolean] WithinInfiltrationVolume + :attached_to_rim_joist_idrefs, # [Array] AttachedToRimJoist/@idref + :attached_to_wall_idrefs, # [Array] AttachedToWall/@idref + :attached_to_foundation_wall_idrefs, # [Array] AttachedToFoundationWall/@idref + :attached_to_floor_idrefs, # [Array] AttachedToFloor/@idref + :attached_to_slab_idrefs] # [Array] AttachedToSlab/@idref attr_accessor(*ATTRS) - # TODO + # Returns all slabs for this foundation. + # + # @return [Array] List of slab objects def attached_slabs return [] if @attached_to_slab_idrefs.nil? @@ -2922,7 +3538,9 @@ def attached_slabs return list end - # TODO + # Returns all floors for this foundation. + # + # @return [Array] List of floor objects def attached_floors return [] if @attached_to_floor_idrefs.nil? @@ -2934,7 +3552,9 @@ def attached_floors return list end - # TODO + # Returns all foundation walls for this foundation. + # + # @return [Array] List of foundation wall objects def attached_foundation_walls return [] if @attached_to_foundation_wall_idrefs.nil? @@ -2946,7 +3566,9 @@ def attached_foundation_walls return list end - # TODO + # Returns all walls for this foundation. + # + # @return [Array] List of wall objects def attached_walls return [] if @attached_to_wall_idrefs.nil? @@ -2958,7 +3580,9 @@ def attached_walls return list end - # TODO + # Returns all rim joists for this foundation. + # + # @return [Array] List of rim joist objects def attached_rim_joists return [] if @attached_to_rim_joist_idrefs.nil? @@ -2970,7 +3594,9 @@ def attached_rim_joists return list end - # TODO + # Returns the location that corresponds to the foundation. + # + # @return [String] Adjacent location (HPXML::LocationXXX) def to_location return if @foundation_type.nil? @@ -2995,7 +3621,9 @@ def to_location end end - # TODO + # Calculates the foundation footprint area. + # + # @return [Double] Foundation area (ft2) def area sum_area = 0.0 # Check Slabs first @@ -3011,11 +3639,17 @@ def area return sum_area end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.foundations.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; attached_slabs; rescue StandardError => e; errors << e.message; end begin; attached_floors; rescue StandardError => e; errors << e.message; end @@ -3026,7 +3660,11 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? foundations = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Foundations']) @@ -3097,7 +3735,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(foundation) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param foundation [Oga::XML::Element] The current Foundation XML element + # @return [void] + def from_doc(foundation) return if foundation.nil? @id = HPXML::get_id(foundation) @@ -3148,13 +3790,20 @@ def from_doc(foundation) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Roof objects. class Roofs < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Roof.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Roofs/Roof').each do |roof| @@ -3163,23 +3812,45 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Roofs/Roof. class Roof < BaseElement - ATTRS = [:id, :interior_adjacent_to, :area, :azimuth, :orientation, :roof_type, - :roof_color, :solar_absorptance, :emittance, :pitch, :radiant_barrier, - :insulation_id, :insulation_assembly_r_value, :insulation_cavity_r_value, - :insulation_continuous_r_value, :radiant_barrier_grade, :insulation_grade, - :interior_finish_type, :interior_finish_thickness, :framing_factor, - :framing_size, :framing_spacing, :insulation_cavity_material, - :insulation_continuous_material, :attached_to_space_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attached_to_space_idref, # [String] AttachedToSpace/@idref + :interior_adjacent_to, # [String] InteriorAdjacentTo (HPXML::LocationXXX) + :area, # [Double] Area (ft2) + :orientation, # [String] Orientation (HPXML::OrientationXXX) + :azimuth, # [Integer] Azimuth (deg) + :roof_type, # [String] RoofType (HPXML::RoofTypeXXX) + :roof_color, # [String] RoofColor (HPXML::ColorXXX) + :solar_absorptance, # [Double] SolarAbsorptance + :emittance, # [Double] Emittance + :interior_finish_type, # [String] InteriorFinish/Type (HPXML::InteriorFinishXXX) + :interior_finish_thickness, # [Double] InteriorFinish/Thickness (in) + :framing_size, # [String] Rafters/Size + :framing_spacing, # [Double] Rafters/Spacing (in) + :framing_factor, # [Double] Rafters/FramingFactor (frac) + :pitch, # [Double] Pitch (?/12) + :radiant_barrier, # [Boolean] RadiantBarrier + :radiant_barrier_grade, # [Integer] RadiantBarrierGrade + :insulation_id, # [String] Insulation/@id + :insulation_grade, # [Integer] Insulation/InsulationGrade + :insulation_assembly_r_value, # [Double] Insulation/AssemblyEffectiveRValue (F-ft2-hr/Btu) + :insulation_cavity_material, # [String] Insulation/Layer[InstallationType="cavity"]/InsulationMaterial/* + :insulation_cavity_r_value, # [Double] Insulation/Layer[InstallationType="cavity"]/NominalRValue (F-ft2-hr/Btu) + :insulation_continuous_material, # [String] Insulation/Layer[InstallationType="continuous"]/InsulationMaterial/* + :insulation_continuous_r_value] # [Double] Insulation/Layer[InstallationType="continuous"]/NominalRValue (F-ft2-hr/Btu) attr_accessor(*ATTRS) - # TODO + # Returns all skylights for this roof. + # + # @return [Array] List of skylight objects def skylights return @parent_object.skylights.select { |skylight| skylight.attached_to_roof_idref == @id } end - # TODO + # Returns the space that the roof is attached to. + # + # @return [HPXML::Space] Space object def space return if @attached_to_space_idref.nil? @@ -3192,7 +3863,9 @@ def space fail "Attached space '#{@attached_to_space_idref}' not found for roof '#{@id}'." end - # TODO + # Calculates the net area (gross area minus subsurface area). + # + # @return [Double] Net area (ft2) def net_area return if nil? return if @area.nil? @@ -3206,37 +3879,54 @@ def net_area return val end - # TODO + # Returns the assumed exterior adjacent to location. + # + # @return [String] Exterior adjacent to location (HPXML::LocationXXX) def exterior_adjacent_to return LocationOutside end - # TODO + # Returns whether the roof is an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior return true end - # TODO + # Returns whether the roof is an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the roof is between conditioned space and outside. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(self) end - # TODO + # Returns whether the roof is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the roof is adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.roofs.delete(self) skylights.reverse_each do |skylight| skylight.delete @@ -3246,14 +3936,21 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; net_area; rescue StandardError => e; errors << e.message; end begin; space; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? roofs = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Roofs']) @@ -3317,7 +4014,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(roof) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param roof [Oga::XML::Element] The current Roof XML element + # @return [void] + def from_doc(roof) return if roof.nil? @id = HPXML::get_id(roof) @@ -3362,13 +4063,20 @@ def from_doc(roof) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::RimJoist objects. class RimJoists < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << RimJoist.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/RimJoists/RimJoist').each do |rim_joist| @@ -3377,15 +4085,31 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/RimJoists/RimJoist. class RimJoist < BaseElement - ATTRS = [:id, :exterior_adjacent_to, :interior_adjacent_to, :area, :orientation, :azimuth, :siding, - :color, :solar_absorptance, :emittance, :insulation_id, :insulation_assembly_r_value, - :insulation_cavity_r_value, :insulation_continuous_r_value, :framing_size, - :insulation_cavity_material, :insulation_continuous_material, :attached_to_space_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attached_to_space_idref, # [String] AttachedToSpace/@idref + :exterior_adjacent_to, # [String] ExteriorAdjacentTo (HPXML::LocationXXX) + :interior_adjacent_to, # [String] InteriorAdjacentTo (HPXML::LocationXXX) + :area, # [Double] Area (ft2) + :orientation, # [String] Orientation (HPXML::OrientationXXX) + :azimuth, # [Integer] Azimuth (deg) + :siding, # [String] Siding (HPXML::SidingTypeXXX) + :color, # [String] Color (HPXML::ColorXXX) + :solar_absorptance, # [Double] SolarAbsorptance + :emittance, # [Double] Emittance + :insulation_id, # [String] Insulation/SystemIdentifier/@id + :insulation_assembly_r_value, # [Double] Insulation/AssemblyEffectiveRValue (F-ft2-hr/Btu) + :insulation_cavity_r_value, # [Double] Insulation/Layer[InstallationType="cavity"]/NominalRValue (F-ft2-hr/Btu) + :insulation_cavity_material, # [String] Insulation/Layer[InstallationType="cavity"]/InsulationMaterial/* + :insulation_continuous_r_value, # [Double] Insulation/Layer[InstallationType="continuous"]/NominalRValue (F-ft2-hr/Btu) + :insulation_continuous_material, # [String] Insulation/Layer[InstallationType="continuous"]/InsulationMaterial/* + :framing_size] # [String] FloorJoists/Size attr_accessor(*ATTRS) - # TODO + # Returns the space that the rim joist is attached to. + # + # @return [HPXML::Space] Space object def space return if @attached_to_space_idref.nil? @@ -3398,64 +4122,83 @@ def space fail "Attached space '#{@attached_to_space_idref}' not found for rim joist '#{@id}'." end - # TODO + # Returns whether the rim joist is an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior - if @exterior_adjacent_to == LocationOutside - return true - end - - return false + return @exterior_adjacent_to == LocationOutside end - # TODO - def is_exposed - return HPXML::is_exposed(self) - end - - # TODO + # Returns whether the rim joist is an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the rim joist is determined to be adiabatic. + # + # @return [Boolean] True if adiabatic def is_adiabatic return HPXML::is_adiabatic(self) end - # TODO + # Returns whether the rim joist is between conditioned space and outside/ground/unconditioned space. + # Note: The location of insulation is not considered here, so an insulated rim joist of an + # unconditioned basement, for example, returns false. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(self) end - # TODO + # Returns whether the rim joist is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the rim joist is adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - # TODO + # Calculates the net area (gross area minus subsurface area). + # + # @return [Double] Net area (ft2) def net_area return area end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.rim_joists.delete(self) @parent_object.foundations.each do |foundation| foundation.attached_to_rim_joist_idrefs.delete(@id) unless foundation.attached_to_rim_joist_idrefs.nil? end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; space; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? rim_joists = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'RimJoists']) @@ -3509,7 +4252,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(rim_joist) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param rim_joist [Oga::XML::Element] The current RimJoist XML element + # @return [void] + def from_doc(rim_joist) return if rim_joist.nil? @id = HPXML::get_id(rim_joist) @@ -3544,13 +4291,20 @@ def from_doc(rim_joist) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Wall objects. class Walls < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Wall.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Walls/Wall').each do |wall| @@ -3559,27 +4313,55 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Walls/Wall. class Wall < BaseElement - ATTRS = [:id, :exterior_adjacent_to, :interior_adjacent_to, :wall_type, :optimum_value_engineering, - :area, :orientation, :azimuth, :siding, :color, :solar_absorptance, :emittance, :radiant_barrier, - :radiant_barrier_grade, :insulation_id, :insulation_assembly_r_value, :insulation_cavity_r_value, - :insulation_continuous_r_value, :interior_finish_type, :interior_finish_thickness, - :attic_wall_type, :framing_factor, :framing_size, :framing_spacing, :insulation_grade, - :insulation_cavity_material, :insulation_continuous_material, :attached_to_space_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attached_to_space_idref, # [String] AttachedToSpace/@idref + :exterior_adjacent_to, # [String] ExteriorAdjacentTo (HPXML::LocationXXX) + :interior_adjacent_to, # [String] InteriorAdjacentTo (HPXML::LocationXXX) + :attic_wall_type, # [String] AtticWallType (HPXML::AtticWallTypeXXX) + :wall_type, # [String] WallType/* + :optimum_value_engineering, # [Boolean] WallType/WoodStud/OptimumValueEngineering + :area, # [Double] Area (ft2) + :orientation, # [String] Orientation (HPXML::OrientationXXX) + :azimuth, # [Integer] Azimuth (deg) + :framing_size, # [String] Studs/Size + :framing_spacing, # [Double] Studs/Spacing (in) + :framing_factor, # [Double] Studs/FramingFactor (frac) + :siding, # [String] Siding (HPXML::SidingTypeXXX) + :color, # [String] Color (HPXML::ColorXXX) + :solar_absorptance, # [Double] SolarAbsorptance + :emittance, # [Double] Emittance + :interior_finish_type, # [String] InteriorFinish/Type (HPXML::InteriorFinishXXX) + :interior_finish_thickness, # [Double] InteriorFinish/Thickness (in) + :radiant_barrier, # [Boolean] RadiantBarrier + :radiant_barrier_grade, # [Integer] RadiantBarrierGrade + :insulation_id, # [String] Insulation/SystemIdentifier/@id + :insulation_grade, # [Integer] Insulation/InsulationGrade + :insulation_assembly_r_value, # [Double] Insulation/AssemblyEffectiveRValue (F-ft2-hr/Btu) + :insulation_cavity_material, # [String] Insulation/Layer[InstallationType="cavity"]/InsulationMaterial/* + :insulation_cavity_r_value, # [Double] Insulation/Layer[InstallationType="cavity"]/NominalRValue (F-ft2-hr/Btu) + :insulation_continuous_material, # [String] Insulation/Layer[InstallationType="continuous"]/InsulationMaterial/* + :insulation_continuous_r_value] # [Double] Insulation/Layer[InstallationType="continuous"]/NominalRValue (F-ft2-hr/Btu) attr_accessor(*ATTRS) - # TODO + # Returns all windows for this wall. + # + # @return [Array] List of window objects def windows return @parent_object.windows.select { |window| window.attached_to_wall_idref == @id } end - # TODO + # Returns all doors for this wall. + # + # @return [Array] List of door objects def doors return @parent_object.doors.select { |door| door.attached_to_wall_idref == @id } end - # TODO + # Returns the space that the wall is attached to. + # + # @return [HPXML::Space] Space object def space return if @attached_to_space_idref.nil? @@ -3592,7 +4374,9 @@ def space fail "Attached space '#{@attached_to_space_idref}' not found for wall '#{@id}'." end - # TODO + # Calculates the net area (gross area minus subsurface area). + # + # @return [Double] Net area (ft2) def net_area return if nil? return if @area.nil? @@ -3606,51 +4390,56 @@ def net_area return val end - # TODO + # Returns whether the wall is an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior - if @exterior_adjacent_to == LocationOutside - return true - end - - return false + return @exterior_adjacent_to == LocationOutside end - # TODO - def is_exposed - return HPXML::is_exposed(self) - end - - # TODO + # Returns whether the wall is an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the wall is determined to be adiabatic. + # + # @return [Boolean] True if adiabatic def is_adiabatic return HPXML::is_adiabatic(self) end - # TODO + # Returns whether the wall is between conditioned space and outside/ground/unconditioned space. + # Note: The location of insulation is not considered here, so an insulated wall of a garage, + # for example, returns false. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(self) end - # TODO + # Returns whether the wall is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO - def is_conditioned_and_adjacent_to_multifamily_common_space - return (HPXML::is_conditioned(self) && (HPXML::multifamily_common_space_locations.include? @exterior_adjacent_to)) - end - - # TODO + # Returns whether the wall is adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.walls.delete(self) windows.reverse_each do |window| window.delete @@ -3666,14 +4455,21 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; net_area; rescue StandardError => e; errors << e.message; end begin; space; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? walls = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Walls']) @@ -3745,7 +4541,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(wall) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param wall [Oga::XML::Element] The current Wall XML element + # @return [void] + def from_doc(wall) return if wall.nil? @id = HPXML::get_id(wall) @@ -3795,13 +4595,20 @@ def from_doc(wall) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::FoundationWall objects. class FoundationWalls < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << FoundationWall.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/FoundationWalls/FoundationWall').each do |foundation_wall| @@ -3810,23 +4617,51 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/FoundationWalls/FoundationWall. class FoundationWall < BaseElement - ATTRS = [:id, :exterior_adjacent_to, :interior_adjacent_to, :length, :height, :area, :orientation, - :type, :azimuth, :thickness, :depth_below_grade, :insulation_id, :insulation_interior_r_value, - :insulation_interior_distance_to_top, :insulation_interior_distance_to_bottom, - :insulation_exterior_r_value, :insulation_exterior_distance_to_top, - :insulation_exterior_distance_to_bottom, :insulation_assembly_r_value, - :interior_finish_type, :interior_finish_thickness, :insulation_interior_material, - :insulation_exterior_material, :attached_to_space_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attached_to_space_idref, # [String] AttachedToSpace/@idref + :exterior_adjacent_to, # [String] ExteriorAdjacentTo (HPXML::LocationXXX) + :interior_adjacent_to, # [String] InteriorAdjacentTo (HPXML::LocationXXX) + :type, # [String] Type (HPXML::FoundationWallTypeXXX) + :length, # [Double] Length (ft) + :height, # [Double] Height (ft) + :area, # [Double] Area (ft2) + :orientation, # [String] Orientation (HPXML::OrientationXXX) + :azimuth, # [Integer] Azimuth (deg) + :thickness, # [Double] Thickness (in) + :depth_below_grade, # [Double] DepthBelowGrade (ft) + :interior_finish_type, # [String] InteriorFinish/Type (HPXML::InteriorFinishXXX) + :interior_finish_thickness, # [Double] InteriorFinish/Thickness (in) + :insulation_id, # [String] Insulation/SystemIdentifier/@id + :insulation_assembly_r_value, # [Double] Insulation/AssemblyEffectiveRValue (F-ft2-hr/Btu) + :insulation_exterior_material, # [String] Insulation/Layer[InstallationType="continuous - exterior"]/InsulationMaterial/* + :insulation_exterior_r_value, # [Double] Insulation/Layer[InstallationType="continuous - exterior"]/NominalRValue (F-ft2-hr/Btu) + :insulation_exterior_distance_to_top, # [Double] Insulation/Layer[InstallationType="continuous - exterior"]/DistanceToTopOfInsulation (ft) + :insulation_exterior_distance_to_bottom, # [Double] Insulation/Layer[InstallationType="continuous - exterior"]/DistanceToBottomOfInsulation (ft) + :insulation_interior_material, # [String] Insulation/Layer[InstallationType="continuous - interior"]/InsulationMaterial/* + :insulation_interior_r_value, # [Double] Insulation/Layer[InstallationType="continuous - interior"]/NominalRValue (F-ft2-hr/Btu) + :insulation_interior_distance_to_top, # [Double] Insulation/Layer[InstallationType="continuous - interior"]/DistanceToTopOfInsulation (ft) + :insulation_interior_distance_to_bottom] # [Double] Insulation/Layer[InstallationType="continuous - interior"]/DistanceToBottomOfInsulation (ft) attr_accessor(*ATTRS) - # TODO + # Returns all windows for this foundation wall. + # + # @return [Array] List of window objects def windows return @parent_object.windows.select { |window| window.attached_to_wall_idref == @id } end - # TODO + # Returns all doors for this foundation wall. + # + # @return [Array] List of door objects + def doors + return @parent_object.doors.select { |door| door.attached_to_wall_idref == @id } + end + + # Returns the space that the foundation wall is attached to. + # + # @return [HPXML::Space] Space object def space return if @attached_to_space_idref.nil? @@ -3839,12 +4674,9 @@ def space fail "Attached space '#{@attached_to_space_idref}' not found for foundation wall '#{@id}'." end - # TODO - def doors - return @parent_object.doors.select { |door| door.attached_to_wall_idref == @id } - end - - # TODO + # Calculates the net area (gross area minus subsurface area). + # + # @return [Double] Net area (ft2) def net_area return if nil? return if @area.nil? @@ -3860,12 +4692,18 @@ def net_area return val end - # TODO + # Returns all slabs that are adjacent to the same HPXML::LocationXXX as the connected + # foundation walls. + # FUTURE: Is this just returning slabs with the same interior_adjacent_to as this slab? + # + # @return [Array] List of connected slabs def connected_slabs return @parent_object.slabs.select { |s| s.connected_foundation_walls.include? self } end - # TODO + # Estimates the fraction of the foundation wall's length that is along exposed perimeter. + # + # @return [Double] Exposed fraction def exposed_fraction # Calculate total slab exposed perimeter slab_exposed_length = connected_slabs.select { |s| s.interior_adjacent_to == interior_adjacent_to }.map { |s| s.exposed_perimeter }.sum @@ -3882,46 +4720,56 @@ def exposed_fraction return 1.0 end - # TODO + # Returns whether the foundation wall is an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior - if @exterior_adjacent_to == LocationGround - return true - end - - return false - end - - # TODO - def is_exposed - return HPXML::is_exposed(self) + return @exterior_adjacent_to == LocationGround end - # TODO + # Returns whether the foundation wall is an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the foundation wall is determined to be adiabatic. + # + # @return [Boolean] True if adiabatic def is_adiabatic return HPXML::is_adiabatic(self) end - # TODO + # Returns whether the foundation wall is between conditioned space and outside/ground/unconditioned space. + # Note: The location of insulation is not considered here, so an insulated foundation wall of an + # unconditioned basement, for example, returns false. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(self) end - # TODO + # Returns whether the foundation wall is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the foundation wall is adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.foundation_walls.delete(self) windows.reverse_each do |window| window.delete @@ -3934,14 +4782,21 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; net_area; rescue StandardError => e; errors << e.message; end begin; space; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? foundation_walls = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'FoundationWalls']) @@ -4001,7 +4856,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(foundation_wall) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param foundation_wall [Oga::XML::Element] The current FoundationWall XML element + # @return [void] + def from_doc(foundation_wall) return if foundation_wall.nil? @id = HPXML::get_id(foundation_wall) @@ -4045,13 +4904,20 @@ def from_doc(foundation_wall) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Floor objects. class Floors < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Floor.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Floors/Floor').each do |floor| @@ -4060,21 +4926,41 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Floors/Floor. class Floor < BaseElement - ATTRS = [:id, :exterior_adjacent_to, :interior_adjacent_to, :floor_type, :area, :insulation_id, - :insulation_assembly_r_value, :insulation_cavity_r_value, :insulation_continuous_r_value, - :floor_or_ceiling, :interior_finish_type, :interior_finish_thickness, :insulation_grade, - :framing_factor, :framing_size, :framing_spacing, :radiant_barrier, :radiant_barrier_grade, - :insulation_cavity_material, :insulation_continuous_material, :attached_to_space_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attached_to_space_idref, # [String] AttachedToSpace/@idref + :exterior_adjacent_to, # [String] ExteriorAdjacentTo (HPXML::LocationXXX) + :interior_adjacent_to, # [String] InteriorAdjacentTo (HPXML::LocationXXX) + :floor_or_ceiling, # [String] FloorOrCeiling (HPXML::FloorOrCeilingXXX) + :floor_type, # [String] FloorType/* (HPXML::FloorTypeXXX) + :framing_size, # [String] FloorJoists/Size + :framing_spacing, # [Double] FloorJoists/Spacing (in) + :framing_factor, # [Double] FloorJoists/FramingFactor (frac) + :area, # [Double] Area (ft2) + :interior_finish_type, # [String] InteriorFinish/Type (HPXML::InteriorFinishXXX) + :interior_finish_thickness, # [Double] InteriorFinish/Thickness (in) + :radiant_barrier, # [Boolean] RadiantBarrier + :radiant_barrier_grade, # [Integer] RadiantBarrierGrade + :insulation_id, # [String] Insulation/SystemIdentifier/@id + :insulation_grade, # [Integer] Insulation/InsulationGrade + :insulation_assembly_r_value, # [Double] Insulation/AssemblyEffectiveRValue (F-ft2-hr/Btu) + :insulation_cavity_material, # [String] Insulation/Layer[InstallationType="cavity"]/InsulationMaterial/* + :insulation_cavity_r_value, # [Double] Insulation/Layer[InstallationType="cavity"]/NominalRValue (F-ft2-hr/Btu) + :insulation_continuous_material, # [String] Insulation/Layer[InstallationType="continuous"]/InsulationMaterial/* + :insulation_continuous_r_value] # [Double] Insulation/Layer[InstallationType="continuous"]/NominalRValue (F-ft2-hr/Btu) attr_accessor(*ATTRS) - # TODO + # Returns all skylights for this floor. + # + # @return [Array] List of skylight objects def skylights return @parent_object.skylights.select { |skylight| skylight.attached_to_floor_idref == @id } end - # TODO + # Returns the space that the floor is attached to. + # + # @return [HPXML::Space] Space object def space return if @attached_to_space_idref.nil? @@ -4087,17 +4973,9 @@ def space fail "Attached space '#{@attached_to_space_idref}' not found for floor '#{@id}'." end - # TODO - def is_ceiling - # From the perspective of the conditioned space - if @floor_or_ceiling.nil? - return HPXML::is_floor_a_ceiling(self, true) - else - return @floor_or_ceiling == FloorOrCeilingCeiling - end - end - - # TODO + # Calculates the net area (gross area minus subsurface area). + # + # @return [Double] Net area (ft2) def net_area return if nil? return if @area.nil? @@ -4111,42 +4989,82 @@ def net_area return val end - # TODO + # Returns whether the HPXML::Floor object represents a ceiling or floor + # from the perspective of the conditioned space. + # + # For example, the surface above an unconditioned basement is a floor. + # The surface below an attic is a ceiling. + # + # @return [Boolean] True if the surface is a ceiling + def is_ceiling + if @floor_or_ceiling.nil? + return HPXML::is_floor_a_ceiling(self, true) + else + return @floor_or_ceiling == FloorOrCeilingCeiling + end + end + + # Returns whether the HPXML::Floor object represents a ceiling or floor + # from the perspective of the conditioned space. + # + # For example, the surface above an unconditioned basement is a floor. + # The surface below an attic is a ceiling. + # + # @return [Boolean] True if the surface is a floor def is_floor return !is_ceiling end - # TODO + # Returns whether the floor is an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior return [LocationOutside, LocationManufacturedHomeUnderBelly].include?(@exterior_adjacent_to) end - # TODO + # Returns whether the floor is an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the floor is determined to be adiabatic. + # + # @return [Boolean] True if adiabatic def is_adiabatic return HPXML::is_adiabatic(self) end - # TODO + # Returns whether the floor is between conditioned space and outside/unconditioned space. + # Note: The location of insulation is not considered here, so an insulated floor of a + # garage, for example, returns false. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(self) end - # TODO + # Returns whether the floor is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the floor is adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.floors.delete(self) skylights.reverse_each do |skylight| skylight.delete @@ -4162,14 +5080,21 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; net_area; rescue StandardError => e; errors << e.message; end begin; space; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? floors = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Floors']) @@ -4232,7 +5157,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(floor) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param floor [Oga::XML::Element] The current Floor XML element + # @return [void] + def from_doc(floor) return if floor.nil? @id = HPXML::get_id(floor) @@ -4273,13 +5202,20 @@ def from_doc(floor) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Slab objects. class Slabs < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Slab.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Slabs/Slab').each do |slab| @@ -4288,17 +5224,32 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Slabs/Slab. class Slab < BaseElement - ATTRS = [:id, :interior_adjacent_to, :exterior_adjacent_to, :area, :thickness, :exposed_perimeter, - :perimeter_insulation_depth, :under_slab_insulation_width, - :under_slab_insulation_spans_entire_slab, :depth_below_grade, :carpet_fraction, - :carpet_r_value, :perimeter_insulation_id, :perimeter_insulation_r_value, - :under_slab_insulation_id, :under_slab_insulation_r_value, :perimeter_insulation_material, - :under_slab_insulation_material, :gap_insulation_r_value, :attached_to_space_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attached_to_space_idref, # [String] AttachedToSpace/@idref + :interior_adjacent_to, # [String] InteriorAdjacentTo (HPXML::LocationXXX) + :area, # [Double] Area (ft2) + :thickness, # [Double] Thickness (in) + :exposed_perimeter, # [Double] ExposedPerimeter (ft) + :depth_below_grade, # [Double] DepthBelowGrade (ft) + :perimeter_insulation_id, # [String] PerimeterInsulation/SystemIdentifier/@id + :perimeter_insulation_material, # [String] PerimeterInsulation/Layer/InsulationMaterial/* + :perimeter_insulation_r_value, # [Double] PerimeterInsulation/Layer/NominalRValue (F-ft2-hr/Btu) + :perimeter_insulation_depth, # [Double] PerimeterInsulation/Layer/InsulationDepth (ft) + :under_slab_insulation_id, # [String] UnderSlabInsulation/SystemIdentifier/@id + :under_slab_insulation_material, # [String] UnderSlabInsulation/Layer/InsulationMaterial/* + :under_slab_insulation_r_value, # [Double] UnderSlabInsulation/Layer/NominalRValue (F-ft2-hr/Btu) + :under_slab_insulation_width, # [Double] UnderSlabInsulation/Layer/InsulationWidth (ft) + :under_slab_insulation_spans_entire_slab, # [Boolean] UnderSlabInsulation/Layer/InsulationSpansEntireSlab + :gap_insulation_r_value, # [Double] extension/GapInsulationRValue (F-ft2-hr/Btu) + :carpet_fraction, # [Double] extension/CarpetFraction (frac) + :carpet_r_value] # [Double] extension/CarpetRValue (F-ft2-hr/Btu) attr_accessor(*ATTRS) - # TODO + # Returns the space that the slab is attached to. + # + # @return [HPXML::Space] Space object def space return if @attached_to_space_idref.nil? @@ -4311,55 +5262,83 @@ def space fail "Attached space '#{@attached_to_space_idref}' not found for slab '#{@id}'." end - # TODO + # Returns the assumed exterior adjacent to location. + # + # @return [String] Exterior adjacent to location (HPXML::LocationXXX) def exterior_adjacent_to return LocationGround end - # TODO + # Returns whether the slab is an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior return true end - # TODO + # Returns whether the slab is an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the slab is between conditioned space and ground. + # Note: The location of insulation is not considered here, so an insulated slab of a + # garage, for example, returns false. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(self) end - # TODO + # Returns whether the slab is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the slab is adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - # TODO + # Returns all foundation walls that are adjacent to the same HPXML::LocationXXX as the slab. + # + # @return [Array] List of connected foundation walls def connected_foundation_walls - return @parent_object.foundation_walls.select { |fw| interior_adjacent_to == fw.interior_adjacent_to || interior_adjacent_to == fw.exterior_adjacent_to } + return @parent_object.foundation_walls.select { |fw| [fw.interior_adjacent_to, fw.exterior_adjacent_to].include? interior_adjacent_to } end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.slabs.delete(self) @parent_object.foundations.each do |foundation| foundation.attached_to_slab_idrefs.delete(@id) unless foundation.attached_to_slab_idrefs.nil? end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; space; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? slabs = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Slabs']) @@ -4411,7 +5390,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(slab, 'CarpetRValue', @carpet_r_value, :float, @carpet_r_value_isdefaulted) unless @carpet_r_value.nil? end - def from_doc(slab) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param slab [Oga::XML::Element] The current Slab XML element + # @return [void] + def from_doc(slab) return if slab.nil? @id = HPXML::get_id(slab) @@ -4450,13 +5433,20 @@ def from_doc(slab) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Window objects. class Windows < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Window.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Windows/Window').each do |window| @@ -4465,17 +5455,39 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Windows/Window. class Window < BaseElement - ATTRS = [:id, :area, :azimuth, :orientation, :frame_type, :thermal_break, :glass_layers, - :glass_type, :gas_fill, :ufactor, :shgc, :interior_shading_factor_summer, - :interior_shading_id, :interior_shading_factor_winter, :interior_shading_type, :exterior_shading_factor_summer, - :exterior_shading_id, :exterior_shading_factor_winter, :exterior_shading_type, :storm_type, :overhangs_depth, - :overhangs_distance_to_top_of_window, :overhangs_distance_to_bottom_of_window, - :fraction_operable, :performance_class, :attached_to_wall_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :area, # [Double] Area (ft2) + :azimuth, # [Integer] Azimuth (deg) + :orientation, # [String] Orientation (HPXML::OrientationXXX) + :frame_type, # [String] FrameType/* (HPXML::WindowFrameTypeXXX) + :thermal_break, # [Boolean] FrameType/*/ThermalBreak + :glass_layers, # [String] GlassLayers (HPXML::WindowLayersXXX) + :glass_type, # [String] GlassType (HPXML::WindowGlassTypeXXX) + :gas_fill, # [String] GasFill (HPXML::WindowGasXXX) + :ufactor, # [Double] UFactor (Btu/F-ft2-hr) + :shgc, # [Double] SHGC + :exterior_shading_id, # [String] ExteriorShading/SystemIdentifier/@id + :exterior_shading_type, # [String] ExteriorShading/Type + :exterior_shading_factor_summer, # [Double] ExteriorShading/SummerShadingCoefficient (frac) + :exterior_shading_factor_winter, # [Double] ExteriorShading/WinterShadingCoefficient (frac) + :interior_shading_id, # [String] InteriorShading/SystemIdentifier/@id + :interior_shading_type, # [String] InteriorShading/Type + :interior_shading_factor_summer, # [Double] InteriorShading/SummerShadingCoefficient (frac) + :interior_shading_factor_winter, # [Double] InteriorShading/WinterShadingCoefficient (frac) + :storm_type, # [String] StormWindow/GlassType (HPXML::WindowGlassTypeXXX) + :overhangs_depth, # [Double] Overhangs/Depth (ft) + :overhangs_distance_to_top_of_window, # [Double] Overhangs/DistanceToTopOfWindow (ft) + :overhangs_distance_to_bottom_of_window, # [Double] Overhangs/DistanceToBottomOfWindow (ft) + :fraction_operable, # [Double] FractionOperable (frac) + :performance_class, # [String] PerformanceClass (HPXML::WindowClassXXX) + :attached_to_wall_idref] # [String] AttachedToWall/@idref attr_accessor(*ATTRS) - # TODO + # Returns the parent wall that includes this skylight. + # + # @return [HPXML::Wall] Parent wall surface def wall return if @attached_to_wall_idref.nil? @@ -4487,42 +5499,64 @@ def wall fail "Attached wall '#{@attached_to_wall_idref}' not found for window '#{@id}'." end - # TODO + # Returns whether the window is on an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior return wall.is_exterior end - # TODO + # Returns whether the window is on an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the window is on a thermal boundary parent surface. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(wall) end - # TODO + # Returns whether the window's parent surface is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the window is on a surface adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.windows.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; wall; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? windows = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Windows']) @@ -4588,7 +5622,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(window) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param window [Oga::XML::Element] The current Window XML element + # @return [void] + def from_doc(window) return if window.nil? @id = HPXML::get_id(window) @@ -4624,13 +5662,20 @@ def from_doc(window) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Skylight objects. class Skylights < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Skylight.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Skylights/Skylight').each do |skylight| @@ -4639,16 +5684,37 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Skylights/Skylight. class Skylight < BaseElement - ATTRS = [:id, :area, :azimuth, :orientation, :frame_type, :thermal_break, :glass_layers, - :glass_type, :gas_fill, :ufactor, :shgc, :interior_shading_factor_summer, - :interior_shading_factor_winter, :interior_shading_type, :exterior_shading_factor_summer, - :exterior_shading_factor_winter, :exterior_shading_type, :storm_type, :attached_to_roof_idref, - :attached_to_floor_idref, :curb_area, :curb_assembly_r_value, :shaft_area, :shaft_assembly_r_value] + ATTRS = [:id, # [String] SystemIdentifier/@id + :area, # [Double] Area (ft2) + :azimuth, # [Integer] Azimuth (deg) + :orientation, # [String] Orientation (HPXML::OrientationXXX) + :frame_type, # [String] FrameType/* (HPXML::WindowFrameTypeXXX) + :thermal_break, # [Boolean] FrameType/*/ThermalBreak + :glass_layers, # [String] GlassLayers (HPXML::WindowLayersXXX) + :glass_type, # [String] GlassType (HPXML::WindowGlassTypeXXX) + :gas_fill, # [String] GasFill (HPXML::WindowGasXXX) + :ufactor, # [Double] UFactor (Btu/F-ft2-hr) + :shgc, # [Double] SHGC + :exterior_shading_type, # [String] ExteriorShading/Type + :exterior_shading_factor_summer, # [Double] ExteriorShading/SummerShadingCoefficient (frac) + :exterior_shading_factor_winter, # [Double] ExteriorShading/WinterShadingCoefficient (frac) + :interior_shading_type, # [String] InteriorShading/Type + :interior_shading_factor_summer, # [Double] InteriorShading/SummerShadingCoefficient (frac) + :interior_shading_factor_winter, # [Double] InteriorShading/WinterShadingCoefficient (frac) + :storm_type, # [String] StormWindow/GlassType (HPXML::WindowGlassTypeXXX) + :attached_to_roof_idref, # [String] AttachedToRoof/@idref + :attached_to_floor_idref, # [String] AttachedToFloor/@idref + :curb_area, # [Double] extension/Curb/Area (ft2) + :curb_assembly_r_value, # [Double] extension/Curb/AssemblyEffectiveRValue (F-ft2-hr/Btu) + :shaft_area, # [Double] extension/Shaft/Area (ft2) + :shaft_assembly_r_value] # [Double] extension/Shaft/AssemblyEffectiveRValue (F-ft2-hr/Btu) attr_accessor(*ATTRS) - # TODO + # Returns the parent roof that includes this skylight. + # + # @return [HPXML::Roof] Parent roof surface def roof return if @attached_to_roof_idref.nil? @@ -4660,7 +5726,9 @@ def roof fail "Attached roof '#{@attached_to_roof_idref}' not found for skylight '#{@id}'." end - # TODO + # Returns the parent floor that includes this skylight. + # + # @return [HPXML::Floor] Parent floor surface def floor return if @attached_to_floor_idref.nil? @@ -4672,27 +5740,39 @@ def floor fail "Attached floor '#{@attached_to_floor_idref}' not found for skylight '#{@id}'." end - # TODO + # Returns whether the skylight is on an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior return roof.is_exterior end - # TODO + # Returns whether the skylight is on an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the skylight is on a thermal boundary parent surface. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(roof) end - # TODO + # Returns whether the skylight's parent surface is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the skylight is on a surface adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned if not floor.nil? return HPXML::is_conditioned(floor) @@ -4701,18 +5781,28 @@ def is_conditioned end end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.skylights.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; roof; rescue StandardError => e; errors << e.message; end begin; floor; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? skylights = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Skylights']) @@ -4776,7 +5866,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(skylight) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param skylight [Oga::XML::Element] The current Skylight XML element + # @return [void] + def from_doc(skylight) return if skylight.nil? @id = HPXML::get_id(skylight) @@ -4810,13 +5904,20 @@ def from_doc(skylight) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Door objects. class Doors < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Door.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Enclosure/Doors/Door').each do |door| @@ -4825,12 +5926,19 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/Doors/Door. class Door < BaseElement - ATTRS = [:id, :attached_to_wall_idref, :area, :azimuth, :orientation, :r_value] + ATTRS = [:id, # [String] SystemIdentifier/@id + :attached_to_wall_idref, # [String] AttachedToWall/@idref + :area, # [Double] Area (ft2) + :azimuth, # [Integer] Azimuth (deg) + :orientation, # [String] Orientation (HPXML::OrientationXXX) + :r_value] # [Double] RValue (F-ft2-hr/Btu) attr_accessor(*ATTRS) - # TODO + # Returns the parent wall that includes this door. + # + # @return [HPXML::Wall] Parent wall surface def wall return if @attached_to_wall_idref.nil? @@ -4842,42 +5950,64 @@ def wall fail "Attached wall '#{@attached_to_wall_idref}' not found for door '#{@id}'." end - # TODO + # Returns whether the door is on an exterior surface (i.e., adjacent to + # outside or ground). + # + # @return [Boolean] True if an exterior surface def is_exterior return wall.is_exterior end - # TODO + # Returns whether the door is on an interior surface (i.e., NOT adjacent to + # outside or ground). + # + # @return [Boolean] True if an interior surface def is_interior return !is_exterior end - # TODO + # Returns whether the door is on a thermal boundary parent surface. + # + # @return [Boolean] True if a thermal boundary surface def is_thermal_boundary return HPXML::is_thermal_boundary(wall) end - # TODO + # Returns whether the door's parent surface is both an exterior surface and a thermal boundary surface. + # + # @return [Boolean] True if an exterior, thermal boundary surface def is_exterior_thermal_boundary return (is_exterior && is_thermal_boundary) end - # TODO + # Returns whether the door is on a surface adjacent to conditioned space. + # + # @return [Boolean] True if adjacent to conditioned space def is_conditioned return HPXML::is_conditioned(self) end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.doors.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; wall; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? doors = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'Doors']) @@ -4894,7 +6024,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(door, 'RValue', @r_value, :float) unless @r_value.nil? end - def from_doc(door) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param door [Oga::XML::Element] The current Door XML element + # @return [void] + def from_doc(door) return if door.nil? @id = HPXML::get_id(door) @@ -4906,17 +6040,26 @@ def from_doc(door) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/extension/PartitionWallMass. class PartitionWallMass < BaseElement - ATTRS = [:area_fraction, :interior_finish_type, :interior_finish_thickness] + ATTRS = [:area_fraction, # [Double] AreaFraction (frac) + :interior_finish_type, # [String] InteriorFinish/Type (HPXML::InteriorFinishXXX) + :interior_finish_thickness] # [Double] InteriorFinish/Thickness (in) attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? partition_wall_mass = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'extension', 'PartitionWallMass']) @@ -4928,7 +6071,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? partition_wall_mass = XMLHelper.get_element(building, 'BuildingDetails/Enclosure/extension/PartitionWallMass') @@ -4943,17 +6090,25 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Enclosure/extension/FurnitureMass. class FurnitureMass < BaseElement - ATTRS = [:area_fraction, :type] + ATTRS = [:area_fraction, # [Double] AreaFraction (frac) + :type] # [String] Type (HPXML::FurnitureMassTypeXXX) attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? furniture_mass = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Enclosure', 'extension', 'FurnitureMass']) @@ -4961,7 +6116,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(furniture_mass, 'Type', @type, :string, @type_isdefaulted) unless @type.nil? end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? furniture_mass = XMLHelper.get_element(building, 'BuildingDetails/Enclosure/extension/FurnitureMass') @@ -4972,13 +6131,20 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::HeatingSystem objects. class HeatingSystems < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << HeatingSystem.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/HVAC/HVACPlant/HeatingSystem').each do |heating_system| @@ -4986,30 +6152,56 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Returns the total fraction of building's heating load served by all heating systems. + # + # @return [Double] Total fraction of building's heating load served def total_fraction_heat_load_served map { |htg_sys| htg_sys.fraction_heat_load_served.to_f }.sum(0.0) end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACPlant/HeatingSystem. class HeatingSystem < BaseElement - def initialize(hpxml_object, *args, **kwargs) - @heating_detailed_performance_data = HeatingDetailedPerformanceData.new(hpxml_object) - super(hpxml_object, *args, **kwargs) - end - ATTRS = [:id, :attached_to_zone_idref, :distribution_system_idref, :year_installed, - :heating_system_type, :heating_system_fuel, :heating_capacity, :heating_efficiency_afue, - :heating_efficiency_percent, :fraction_heat_load_served, :electric_auxiliary_energy, - :third_party_certification, :htg_seed_id, :is_shared_system, :number_of_units_served, - :shared_loop_watts, :shared_loop_motor_efficiency, :fan_coil_watts, :fan_watts_per_cfm, - :airflow_defect_ratio, :fan_watts, :heating_airflow_cfm, :location, :primary_system, - :pilot_light, :pilot_light_btuh, :electric_resistance_distribution, :heating_autosizing_factor, - :heating_autosizing_limit] + def initialize(hpxml_element, *args, **kwargs) + @heating_detailed_performance_data = HeatingDetailedPerformanceData.new(hpxml_element) + super(hpxml_element, *args, **kwargs) + end + CLASS_ATTRS = [:heating_detailed_performance_data] # [HPXML::HeatingDetailedPerformanceData] + ATTRS = [:primary_system, # [Boolean] ../PrimarySystems/PrimaryHeatingSystem/@id + :id, # [String] SystemIdentifier/@id + :attached_to_zone_idref, # [String] AttachedToZone/@idref + :location, # [String] UnitLocation (HPXML::LocationXXX) + :year_installed, # [Integer] YearInstalled + :third_party_certification, # [String] ThirdPartyCertification + :distribution_system_idref, # [String] DistributionSystem/@idref + :is_shared_system, # [Boolean] IsSharedSystem + :number_of_units_served, # [Integer] NumberofUnitsServed + :heating_system_type, # [String] HeatingSystemType/* (HPXML::HVACTypeXXX) + :pilot_light, # [Boolean] HeatingSystemType/*/PilotLight + :pilot_light_btuh, # [Double] HeatingSystemType/*/extension/PilotLightBtuh (Btu/hr) + :electric_resistance_distribution, # [String] HeatingSystemType/ElectricResistance/ElectricDistribution (HPXML::ElectricResistanceDistributionXXX) + :heating_system_fuel, # [String] HeatingSystemFuel (HPXML::FuelTypeXXX) + :heating_capacity, # [Double] HeatingCapacity (Btu/hr) + :heating_efficiency_afue, # [Double] AnnualHeatingEfficiency[Units="AFUE"]/Value (frac) + :heating_efficiency_percent, # [Double] AnnualHeatingEfficiency[Units="Percent"]/Value (frac) + :fraction_heat_load_served, # [Double] FractionHeatLoadServed (frac) + :electric_auxiliary_energy, # [Double] ElectricAuxiliaryEnergy (kWh/yr) + :shared_loop_watts, # [Double] extension/SharedLoopWatts (W) + :shared_loop_motor_efficiency, # [Double] extension/SharedLoopMotorEfficiency (frac) + :fan_coil_watts, # [Double] extension/FanCoilWatts (W) + :fan_watts_per_cfm, # [Double] extension/FanPowerWattsPerCFM (W/cfm) + :fan_watts, # [Double] extension/FanPowerWatts (W) + :airflow_defect_ratio, # [Double] extension/AirflowDefectRatio (frac) + :heating_airflow_cfm, # [Double] extension/HeatingAirflowCFM (cfm) + :heating_autosizing_factor, # [Double] extension/HeatingAutosizingFactor (frac) + :heating_autosizing_limit, # [Double] extension/HeatingAutosizingLimit (Btu/hr) + :htg_seed_id] # [String] extension/HeatingSeedId + attr_reader(*CLASS_ATTRS) attr_accessor(*ATTRS) - attr_reader(:heating_detailed_performance_data) - # TODO + # Returns the zone that the heating system serves. + # + # @return [HPXML::Zone] Zone served def zone return if @attached_to_zone_idref.nil? @@ -5020,7 +6212,9 @@ def zone fail "Attached zone '#{@attached_to_zone_idref}' not found for heating system '#{@id}'." end - # TODO + # Returns the HVAC distribution system for the heating system. + # + # @return [HPXML::HVACDistribution] The attached HVAC distribution system def distribution_system return if @distribution_system_idref.nil? @@ -5032,7 +6226,9 @@ def distribution_system fail "Attached HVAC distribution system '#{@distribution_system_idref}' not found for HVAC system '#{@id}'." end - # TODO + # Returns the cooling system on the same distribution system as the heating system. + # + # @return [HPXML::XXX] The attached cooling system def attached_cooling_system return if distribution_system.nil? @@ -5046,7 +6242,10 @@ def attached_cooling_system return end - # TODO + # Returns the water heating system related to the heating system (e.g., for + # a combination boiler that provides both water heating and space heating). + # + # @return [HPXML::WaterHeatingSystem] The related water heating system def related_water_heating_system @parent_object.water_heating_systems.each do |water_heating_system| next unless water_heating_system.related_hvac_idref == @id @@ -5056,7 +6255,9 @@ def related_water_heating_system return end - # TODO + # Returns the primary heat pump when the heating system serves as a heat pump backup system. + # + # @return [HPXML::HeatPump] The primary heat pump def primary_heat_pump # Returns the HP for which this heating system is backup @parent_object.heat_pumps.each do |heat_pump| @@ -5068,12 +6269,17 @@ def primary_heat_pump return end - # TODO + # Returns whether the heating system serves as a heat pump backup system. + # + # @return [Boolean] True if a heat pump backup system def is_heat_pump_backup_system return !primary_heat_pump.nil? end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.heating_systems.delete(self) @parent_object.water_heating_systems.each do |water_heating_system| next unless water_heating_system.related_hvac_idref == @id @@ -5082,7 +6288,10 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; distribution_system; rescue StandardError => e; errors << e.message; end begin; zone; rescue StandardError => e; errors << e.message; end @@ -5090,18 +6299,22 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? hvac_plant = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'HVAC', 'HVACPlant']) primary_systems = XMLHelper.create_elements_as_needed(hvac_plant, ['PrimarySystems']) unless @parent_object.primary_hvac_systems.empty? heating_system = XMLHelper.add_element(hvac_plant, 'HeatingSystem') sys_id = XMLHelper.add_element(heating_system, 'SystemIdentifier') + XMLHelper.add_attribute(sys_id, 'id', @id) if not @attached_to_zone_idref.nil? zone_attached = XMLHelper.add_element(heating_system, 'AttachedToZone') XMLHelper.add_attribute(zone_attached, 'idref', @attached_to_zone_idref) end - XMLHelper.add_attribute(sys_id, 'id', @id) XMLHelper.add_element(heating_system, 'UnitLocation', @location, :string, @location_isdefaulted) unless @location.nil? XMLHelper.add_element(heating_system, 'YearInstalled', @year_installed, :integer) unless @year_installed.nil? XMLHelper.add_element(heating_system, 'ThirdPartyCertification', @third_party_certification, :string) unless @third_party_certification.nil? @@ -5160,7 +6373,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(heating_system) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param heating_system [Oga::XML::Element] The current HeatingSystem XML element + # @return [void] + def from_doc(heating_system) return if heating_system.nil? @id = HPXML::get_id(heating_system) @@ -5205,13 +6422,20 @@ def from_doc(heating_system) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::CoolingSystem objects. class CoolingSystems < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << CoolingSystem.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/HVAC/HVACPlant/CoolingSystem').each do |cooling_system| @@ -5219,36 +6443,71 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Returns the total fraction of building's cooling load served by all cooling systems. + # + # @return [Double] Total fraction of building's cooling load served def total_fraction_cool_load_served map { |clg_sys| clg_sys.fraction_cool_load_served.to_f }.sum(0.0) end - # TODO + # Returns the total fraction of building's heating load served by all cooling systems. + # + # @return [Double] Total fraction of building's heating load served def total_fraction_heat_load_served map { |clg_sys| clg_sys.integrated_heating_system_fraction_heat_load_served.to_f }.sum(0.0) end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACPlant/CoolingSystem. class CoolingSystem < BaseElement - def initialize(hpxml_object, *args, **kwargs) - @cooling_detailed_performance_data = CoolingDetailedPerformanceData.new(hpxml_object) - super(hpxml_object, *args, **kwargs) - end - ATTRS = [:id, :attached_to_zone_idref, :distribution_system_idref, :year_installed, :cooling_system_type, :cooling_system_fuel, - :cooling_capacity, :compressor_type, :fraction_cool_load_served, :cooling_efficiency_seer, - :cooling_efficiency_seer2, :cooling_efficiency_eer, :cooling_efficiency_ceer, :cooling_efficiency_kw_per_ton, - :cooling_shr, :third_party_certification, :clg_seed_id, :is_shared_system, :number_of_units_served, - :shared_loop_watts, :shared_loop_motor_efficiency, :fan_coil_watts, :airflow_defect_ratio, - :fan_watts_per_cfm, :charge_defect_ratio, :cooling_airflow_cfm, :location, :primary_system, - :integrated_heating_system_fuel, :integrated_heating_system_capacity, :integrated_heating_system_efficiency_percent, - :integrated_heating_system_fraction_heat_load_served, :integrated_heating_system_airflow_cfm, :htg_seed_id, :crankcase_heater_watts, - :cooling_autosizing_factor, :cooling_autosizing_limit] + def initialize(hpxml_element, *args, **kwargs) + @cooling_detailed_performance_data = CoolingDetailedPerformanceData.new(hpxml_element) + super(hpxml_element, *args, **kwargs) + end + CLASS_ATTRS = [:cooling_detailed_performance_data] # [HPXML::CoolingDetailedPerformanceData] + ATTRS = [:primary_system, # [Boolean] ../PrimarySystems/PrimaryCoolingSystem/@idref + :id, # [String] SystemIdentifier/@id + :attached_to_zone_idref, # [String] AttachedToZone/@idref + :location, # [String] UnitLocation (HPXML::LocationXXX) + :year_installed, # [Integer] YearInstalled + :third_party_certification, # [String] ThirdPartyCertification + :distribution_system_idref, # [String] DistributionSystem/@idref + :is_shared_system, # [Boolean] IsSharedSystem + :number_of_units_served, # [Integer] NumberofUnitsServed + :cooling_system_type, # [String] CoolingSystemType (HPXML::HVACTypeXXX) + :cooling_system_fuel, # [String] CoolingSystemFuel (HPXML::FuelTypeXXX) + :cooling_capacity, # [Double] CoolingCapacity (Btu/hr) + :compressor_type, # [String] CompressorType (HPXML::HVACCompressorTypeXXX) + :fraction_cool_load_served, # [Double] FractionCoolLoadServed (frac) + :cooling_efficiency_seer, # [Double] AnnualCoolingEfficiency[Units="SEER"]/Value (Btu/Wh) + :cooling_efficiency_seer2, # [Double] AnnualCoolingEfficiency[Units="SEER2"]/Value (Btu/Wh) + :cooling_efficiency_eer, # [Double] AnnualCoolingEfficiency[Units="EER"]/Value (Btu/Wh) + :cooling_efficiency_ceer, # [Double] AnnualCoolingEfficiency[Units="CEER"]/Value (Btu/Wh) + :cooling_efficiency_kw_per_ton, # [Double] AnnualCoolingEfficiency[Units="kW/ton"]/Value (kW/ton) + :cooling_shr, # [Double] SensibleHeatFraction (frac) + :integrated_heating_system_fuel, # [String] IntegratedHeatingSystemFuel (HPXML::FuelTypeXXX) + :integrated_heating_system_capacity, # [Double] IntegratedHeatingSystemCapacity (Btu/hr) + :integrated_heating_system_efficiency_percent, # [Double] IntegratedHeatingSystemAnnualEfficiency[Units="Percent"]/Value (frac) + :integrated_heating_system_fraction_heat_load_served, # [Double] IntegratedHeatingSystemFractionHeatLoadServed (frac) + :airflow_defect_ratio, # [Double] extension/AirflowDefectRatio (frac) + :charge_defect_ratio, # [Double] extension/ChargeDefectRatio (frac) + :fan_watts_per_cfm, # [Double] extension/FanPowerWattsPerCFM (W/cfm) + :cooling_airflow_cfm, # [Double] extension/CoolingAirflowCFM (cfm) + :integrated_heating_system_airflow_cfm, # [Double] extension/HeatingAirflowCFM (cfm) + :shared_loop_watts, # [Double] extension/SharedLoopWatts (W) + :shared_loop_motor_efficiency, # [Double] extension/SharedLoopMotorEfficiency (frac) + :fan_coil_watts, # [Double] extension/FanCoilWatts (W) + :crankcase_heater_watts, # [Double] extension/CrankcaseHeaterPowerWatts (W) + :cooling_autosizing_factor, # [Double] extension/CoolingAutosizingFactor (frac) + :cooling_autosizing_limit, # [Double] extension/CoolingAutosizingLimit (Btu/hr) + :clg_seed_id, # [String] extension/CoolingSeedId + :htg_seed_id] # [String] extension/HeatingSeedId + attr_reader(*CLASS_ATTRS) attr_accessor(*ATTRS) - attr_reader(:cooling_detailed_performance_data) - # TODO + # Returns the zone that the cooling system serves. + # + # @return [HPXML::Zone] Zone served def zone return if @attached_to_zone_idref.nil? @@ -5259,7 +6518,9 @@ def zone fail "Attached zone '#{@attached_to_zone_idref}' not found for cooling system '#{@id}'." end - # TODO + # Returns the HVAC distribution system for the cooling system. + # + # @return [HPXML::HVACDistribution] The attached HVAC distribution system def distribution_system return if @distribution_system_idref.nil? @@ -5271,7 +6532,9 @@ def distribution_system fail "Attached HVAC distribution system '#{@distribution_system_idref}' not found for HVAC system '#{@id}'." end - # TODO + # Returns the heating system on the same distribution system as the cooling system. + # + # @return [HPXML::XXX] The attached heating system def attached_heating_system # by distribution system return if distribution_system.nil? @@ -5284,7 +6547,9 @@ def attached_heating_system return end - # TODO + # Returns whether the cooling system has integrated heating. + # + # @return [Boolean] True if it has integrated heating def has_integrated_heating return false unless [HVACTypePTAC, HVACTypeRoomAirConditioner].include? @cooling_system_type return false if @integrated_heating_system_fuel.nil? @@ -5292,7 +6557,10 @@ def has_integrated_heating return true end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.cooling_systems.delete(self) @parent_object.water_heating_systems.each do |water_heating_system| next unless water_heating_system.related_hvac_idref == @id @@ -5301,7 +6569,10 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; distribution_system; rescue StandardError => e; errors << e.message; end begin; zone; rescue StandardError => e; errors << e.message; end @@ -5309,7 +6580,11 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? hvac_plant = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'HVAC', 'HVACPlant']) @@ -5389,7 +6664,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(cooling_system) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param cooling_system [Oga::XML::Element] The current CoolingSystem XML element + # @return [void] + def from_doc(cooling_system) return if cooling_system.nil? @id = HPXML::get_id(cooling_system) @@ -5438,13 +6717,20 @@ def from_doc(cooling_system) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::HeatPump objects. class HeatPumps < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << HeatPump.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/HVAC/HVACPlant/HeatPump').each do |heat_pump| @@ -5452,42 +6738,91 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Returns the total fraction of building's heating load served by all heat pumps. + # + # @return [Double] Total fraction of building's heating load served def total_fraction_heat_load_served map { |hp| hp.fraction_heat_load_served.to_f }.sum(0.0) end - # TODO + # Returns the total fraction of building's cooling load served by all heat pumps. + # + # @return [Double] Total fraction of building's cooling load served def total_fraction_cool_load_served map { |hp| hp.fraction_cool_load_served.to_f }.sum(0.0) end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACPlant/HeatPump. class HeatPump < BaseElement - def initialize(hpxml_object, *args, **kwargs) - @cooling_detailed_performance_data = CoolingDetailedPerformanceData.new(hpxml_object) - @heating_detailed_performance_data = HeatingDetailedPerformanceData.new(hpxml_object) - super(hpxml_object, *args, **kwargs) - end - ATTRS = [:id, :attached_to_zone_idref, :distribution_system_idref, :year_installed, :heat_pump_type, :heat_pump_fuel, - :heating_capacity, :heating_capacity_17F, :cooling_capacity, :compressor_type, :compressor_lockout_temp, - :cooling_shr, :backup_type, :backup_system_idref, :backup_heating_fuel, :backup_heating_capacity, - :backup_heating_efficiency_percent, :backup_heating_efficiency_afue, :backup_heating_lockout_temp, - :backup_heating_switchover_temp, :fraction_heat_load_served, :fraction_cool_load_served, :cooling_efficiency_seer, - :cooling_efficiency_seer2, :cooling_efficiency_eer, :cooling_efficiency_ceer, :heating_efficiency_hspf, - :heating_efficiency_hspf2, :heating_efficiency_cop, :third_party_certification, :htg_seed_id, :clg_seed_id, - :pump_watts_per_ton, :fan_watts_per_cfm, :is_shared_system, :number_of_units_served, :shared_loop_watts, - :shared_loop_motor_efficiency, :airflow_defect_ratio, :charge_defect_ratio, - :heating_airflow_cfm, :cooling_airflow_cfm, :location, :primary_heating_system, :primary_cooling_system, - :heating_capacity_retention_fraction, :heating_capacity_retention_temp, :crankcase_heater_watts, - :geothermal_loop_idref, :cooling_autosizing_factor, :heating_autosizing_factor, :backup_heating_autosizing_factor, - :cooling_autosizing_limit, :heating_autosizing_limit, :backup_heating_autosizing_limit] + def initialize(hpxml_element, *args, **kwargs) + @cooling_detailed_performance_data = CoolingDetailedPerformanceData.new(hpxml_element) + @heating_detailed_performance_data = HeatingDetailedPerformanceData.new(hpxml_element) + super(hpxml_element, *args, **kwargs) + end + CLASS_ATTRS = [:cooling_detailed_performance_data, # [HPXML::CoolingDetailedPerformanceData] + :heating_detailed_performance_data] # [HPXML::HeatingDetailedPerformanceData] + ATTRS = [:primary_heating_system, # [Boolean] ../PrimarySystems/PrimaryHeatingSystem/@idref + :primary_cooling_system, # [Boolean] ../PrimarySystems/PrimaryCoolingSystem/@idref + :id, # [String] SystemIdentifier/@id + :attached_to_zone_idref, # [String] AttachedToZone/@idref + :location, # [String] UnitLocation (HPXML::LocationXXX) + :year_installed, # [Integer] YearInstalled + :third_party_certification, # [String] ThirdPartyCertification + :distribution_system_idref, # [String] DistributionSystem/@idref + :is_shared_system, # [Boolean] IsSharedSystem + :number_of_units_served, # [Integer] NumberofUnitsServed + :heat_pump_type, # [String] HeatPumpType (HPXML::HVACTypeXXX) + :heat_pump_fuel, # [String] HeatPumpFuel (HPXML::FuelTypeXXX) + :heating_capacity, # [Double] HeatingCapacity (Btu/hr) + :heating_capacity_17F, # [Double] HeatingCapacity17F (Btu/hr) + :cooling_capacity, # [Double] CoolingCapacity (Btu/hr) + :compressor_type, # [String] CompressorType (HPXML::HVACCompressorTypeXXX) + :compressor_lockout_temp, # [Double] CompressorLockoutTemperature (F) + :cooling_shr, # [Double] CoolingSensibleHeatFraction (frac) + :backup_type, # [String] BackupType (HPXML::HeatPumpBackupTypeXXX) + :backup_system_idref, # [String] BackupSystem/@idref + :backup_heating_fuel, # [String] BackupSystemFuel (HPXML::FuelTypeXXX) + :backup_heating_efficiency_percent, # [Double] BackupAnnualHeatingEfficiency[Units="Percent"]/Value (frac) + :backup_heating_efficiency_afue, # [Double] BackupAnnualHeatingEfficiency[Units="AFUE"]/Value (frac) + :backup_heating_capacity, # [Double] BackupHeatingCapacity (Btu/hr) + :backup_heating_switchover_temp, # [Double] BackupHeatingSwitchoverTemperature (F) + :backup_heating_lockout_temp, # [Double] BackupHeatingLockoutTemperature (F) + :fraction_heat_load_served, # [Double] FractionHeatLoadServed (frac) + :fraction_cool_load_served, # [Double] FractionCoolLoadServed (frac) + :cooling_efficiency_seer, # [Double] AnnualCoolingEfficiency[Units="SEER"]/Value (Btu/Wh) + :cooling_efficiency_seer2, # [Double] AnnualCoolingEfficiency[Units="SEER2"]/Value (Btu/Wh) + :cooling_efficiency_eer, # [Double] AnnualCoolingEfficiency[Units="EER"]/Value (Btu/Wh) + :cooling_efficiency_ceer, # [Double] AnnualCoolingEfficiency[Units="CEER"]/Value (Btu/Wh) + :heating_efficiency_hspf, # [Double] AnnualHeatingEfficiency[Units="HSPF"]/Value (Btu/Wh) + :heating_efficiency_hspf2, # [Double] AnnualHeatingEfficiency[Units="HSPF2"]/Value (Btu/Wh) + :heating_efficiency_cop, # [Double] AnnualHeatingEfficiency[Units="COP"]/Value (W/W) + :geothermal_loop_idref, # [String] AttachedToGeothermalLoop/@idref + :airflow_defect_ratio, # [Double] extension/AirflowDefectRatio (frac) + :charge_defect_ratio, # [Double] extension/ChargeDefectRatio (frac) + :fan_watts_per_cfm, # [Double] extension/FanPowerWattsPerCFM (W/cfm) + :heating_airflow_cfm, # [Double] extension/HeatingAirflowCFM (cfm) + :cooling_airflow_cfm, # [Double] extension/CoolingAirflowCFM (cfm) + :pump_watts_per_ton, # [Double] extension/PumpPowerWattsPerTon (W/ton) + :shared_loop_watts, # [Double] extension/SharedLoopWatts (W) + :shared_loop_motor_efficiency, # [Double] extension/SharedLoopMotorEfficiency (frac) + :heating_capacity_retention_fraction, # [Double] extension/HeatingCapacityRetention/Fraction (frac) + :heating_capacity_retention_temp, # [Double] extension/HeatingCapacityRetention/Temperature (F) + :crankcase_heater_watts, # [Double] extension/CrankcaseHeaterPowerWatts (W) + :cooling_autosizing_factor, # [Double] extension/CoolingAutosizingFactor (frac) + :heating_autosizing_factor, # [Double] extension/HeatingAutosizingFactor (frac) + :backup_heating_autosizing_factor, # [Double] extension/BackupHeatingAutosizingFactor (frac) + :cooling_autosizing_limit, # [Double] extension/CoolingAutosizingLimit (Btu/hr) + :heating_autosizing_limit, # [Double] extension/HeatingAutosizingLimit (Btu/hr) + :backup_heating_autosizing_limit, # [Double] extension/BackupHeatingAutosizingLimit (Btu/hr) + :htg_seed_id, # [String] extension/HeatingSeedId + :clg_seed_id] # [String] extension/CoolingSeedId + attr_reader(*CLASS_ATTRS) attr_accessor(*ATTRS) - attr_reader(:cooling_detailed_performance_data) - attr_reader(:heating_detailed_performance_data) - # TODO + # Returns the zone that the heat pump serves. + # + # @return [HPXML::Zone] Zone served def zone return if @attached_to_zone_idref.nil? @@ -5498,7 +6833,9 @@ def zone fail "Attached zone '#{@attached_to_zone_idref}' not found for heat pump '#{@id}'." end - # TODO + # Returns the HVAC distribution system for the heat pump. + # + # @return [HPXML::HVACDistribution] The attached HVAC distribution system def distribution_system return if @distribution_system_idref.nil? @@ -5510,7 +6847,9 @@ def distribution_system fail "Attached HVAC distribution system '#{@distribution_system_idref}' not found for HVAC system '#{@id}'." end - # TODO + # Returns the geothermal loop for the (ground source) heat pump. + # + # @return [HPXML::GeothermalLoop] The attached geothermal loop def geothermal_loop return if @geothermal_loop_idref.nil? @@ -5522,7 +6861,10 @@ def geothermal_loop fail "Attached geothermal loop '#{@geothermal_loop_idref}' not found for heat pump '#{@id}'." end - # TODO + # Returns whether the heat pump is a dual-fuel heat pump (i.e., an electric + # heat pump with fossil fuel backup). + # + # @return [Boolean] True if it is dual-fuel def is_dual_fuel if backup_system.nil? if @backup_heating_fuel.nil? @@ -5540,14 +6882,17 @@ def is_dual_fuel return true end - # TODO + # Returns whether the heat pump is the primary heating or cooling system. + # + # @return [Boolean] True if the primary heating and/or cooling system def primary_system - return true if @primary_heating_system || @primary_cooling_system - - return false + return @primary_heating_system || @primary_cooling_system end - # TODO + # Returns the backup heating system for the heat pump, if the heat pump + # has a separate (i.e., not integrated) backup system. + # + # @return [HPXML::HeatingSystem] The backup heating system def backup_system return if @backup_system_idref.nil? @@ -5558,7 +6903,10 @@ def backup_system end end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.heat_pumps.delete(self) @parent_object.water_heating_systems.each do |water_heating_system| next unless water_heating_system.related_hvac_idref == @id @@ -5567,7 +6915,10 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; distribution_system; rescue StandardError => e; errors << e.message; end begin; zone; rescue StandardError => e; errors << e.message; end @@ -5577,7 +6928,11 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? hvac_plant = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'HVAC', 'HVACPlant']) @@ -5700,7 +7055,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(heat_pump) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param heat_pump [Oga::XML::Element] The current HeatPump XML element + # @return [void] + def from_doc(heat_pump) return if heat_pump.nil? @id = HPXML::get_id(heat_pump) @@ -5773,13 +7132,20 @@ def from_doc(heat_pump) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::GeothermalLoop objects. class GeothermalLoops < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << GeothermalLoop.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/HVAC/HVACPlant/GeothermalLoop').each do |geothermal_loop| @@ -5788,14 +7154,27 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACPlant/GeothermalLoop. class GeothermalLoop < BaseElement - ATTRS = [:id, :loop_configuration, :loop_flow, :bore_config, :num_bore_holes, :bore_spacing, - :bore_length, :bore_diameter, :grout_type, :grout_conductivity, :pipe_type, - :pipe_conductivity, :pipe_diameter, :shank_spacing] + ATTRS = [:id, # [String] SystemIdentifier/@id + :loop_configuration, # [String] LoopConfiguration (HPXML::GeothermalLoopLoopConfigurationXXX) + :loop_flow, # [Double] LoopFlow (gal/min) + :num_bore_holes, # [Integer] BoreholesOrTrenches/Count + :bore_length, # [Double] BoreholesOrTrenches/Length (ft) + :bore_spacing, # [Double] BoreholesOrTrenches/Spacing (ft) + :bore_diameter, # [Double] BoreholesOrTrenches/Diameter (in) + :grout_type, # [String] Grout/Type (HPXML::GeothermalLoopGroutOrPipeTypeXXX) + :grout_conductivity, # [Double] Grout/Conductivity (Btu/hr-ft-F) + :pipe_type, # [String] Pipe/Type (HPXML::GeothermalLoopGroutOrPipeTypeXXX) + :pipe_conductivity, # [Double] Pipe/Conductivity (Btu/hr-ft-F) + :pipe_diameter, # [Double] Pipe/Diameter (in) + :shank_spacing, # [Double] Pipe/ShankSpacing (in) + :bore_config] # [String] extension/BorefieldConfiguration (HPXML::GeothermalLoopBorefieldConfigurationXXX) attr_accessor(*ATTRS) - # TODO + # Returns all heat pumps connect to the geothermal loop. + # + # @return [Array] List of heat pump objects def heat_pump list = [] @parent_object.heat_pumps.each do |heat_pump| @@ -5812,7 +7191,10 @@ def heat_pump end end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.geothermal_loops.delete(self) @parent_object.heat_pumps.each do |heat_pump| next unless heat_pump.geothermal_loop_idref == @id @@ -5821,13 +7203,20 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; heat_pump; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? hvac_plant = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'HVAC', 'HVACPlant']) @@ -5861,7 +7250,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(geothermal_loop) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param geothermal_loop [Oga::XML::Element] The current GeothermalLoop XML element + # @return [void] + def from_doc(geothermal_loop) return if geothermal_loop.nil? @id = HPXML::get_id(geothermal_loop) @@ -5881,24 +7274,35 @@ def from_doc(geothermal_loop) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACPlant/extension. class HVACPlant < BaseElement ATTRS = HDL_ATTRS.keys + CDL_SENS_ATTRS.keys + CDL_LAT_ATTRS.keys attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? hvac_plant = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'HVAC', 'HVACPlant']) HPXML.design_loads_to_doc(self, hvac_plant) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? hvac_plant = XMLHelper.get_element(building, 'BuildingDetails/Systems/HVAC/HVACPlant') @@ -5908,13 +7312,20 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::HVACControl objects. class HVACControls < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << HVACControl.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/HVAC/HVACControl').each do |hvac_control| @@ -5923,31 +7334,55 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACControl. class HVACControl < BaseElement - ATTRS = [:id, :control_type, :heating_setpoint_temp, :heating_setback_temp, - :heating_setback_hours_per_week, :heating_setback_start_hour, :cooling_setpoint_temp, - :cooling_setup_temp, :cooling_setup_hours_per_week, :cooling_setup_start_hour, - :ceiling_fan_cooling_setpoint_temp_offset, :weekday_heating_setpoints, :weekend_heating_setpoints, - :weekday_cooling_setpoints, :weekend_cooling_setpoints, - :seasons_heating_begin_month, :seasons_heating_begin_day, :seasons_heating_end_month, :seasons_heating_end_day, - :seasons_cooling_begin_month, :seasons_cooling_begin_day, :seasons_cooling_end_month, :seasons_cooling_end_day] + ATTRS = [:id, # [String] SystemIdentifier/@id + :control_type, # [String] ControlType (HPXML::HVACControlTypeXXX) + :heating_setpoint_temp, # [Double] SetpointTempHeatingSeason (F) + :heating_setback_temp, # [Double] SetbackTempHeatingSeason (F) + :heating_setback_hours_per_week, # [Double] TotalSetbackHoursperWeekHeating (hrs/week) + :cooling_setup_temp, # [Double] SetupTempCoolingSeason (F) + :cooling_setpoint_temp, # [Double] SetpointTempCoolingSeason (F) + :cooling_setup_hours_per_week, # [Double] TotalSetupHoursperWeekCooling (hrs/week) + :seasons_heating_begin_month, # [Integer] HeatingSeason/BeginMonth + :seasons_heating_begin_day, # [Integer] HeatingSeason/BeginDayOfMonth + :seasons_heating_end_month, # [Integer] HeatingSeason/EndMonth + :seasons_heating_end_day, # [Integer] HeatingSeason/EndDayOfMonth + :seasons_cooling_begin_month, # [Integer] CoolingSeason/BeginMonth + :seasons_cooling_begin_day, # [Integer] CoolingSeason/BeginDayOfMonth + :seasons_cooling_end_month, # [Integer] CoolingSeason/EndMonth + :seasons_cooling_end_day, # [Integer] CoolingSeason/EndDayOfMonth + :heating_setback_start_hour, # [Integer] extension/SetbackStartHourHeating + :cooling_setup_start_hour, # [Integer] extension/SetupStartHourCooling + :ceiling_fan_cooling_setpoint_temp_offset, # [Double] extension/CeilingFanSetpointTempCoolingSeasonOffset (F) + :weekday_heating_setpoints, # [String] extension/WeekdaySetpointTempsHeatingSeason + :weekend_heating_setpoints, # [String] extension/WeekendSetpointTempsHeatingSeason + :weekday_cooling_setpoints, # [String] extension/WeekdaySetpointTempsCoolingSeason + :weekend_cooling_setpoints] # [String] extension/WeekendSetpointTempsCoolingSeason attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.hvac_controls.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] - errors += HPXML::check_dates('Heating Season', @seasons_heating_begin_month, @seasons_heating_begin_day, @seasons_heating_end_month, @seasons_heating_end_day) errors += HPXML::check_dates('Cooling Season', @seasons_cooling_begin_month, @seasons_cooling_begin_day, @seasons_cooling_end_month, @seasons_cooling_end_day) - return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? hvac = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'HVAC']) @@ -5984,7 +7419,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(hvac_control, 'WeekendSetpointTempsCoolingSeason', @weekend_cooling_setpoints, :string) unless @weekend_cooling_setpoints.nil? end - def from_doc(hvac_control) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hvac_control [Oga::XML::Element] The current HVACControl XML element + # @return [void] + def from_doc(hvac_control) return if hvac_control.nil? @id = HPXML::get_id(hvac_control) @@ -6013,13 +7452,20 @@ def from_doc(hvac_control) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::HVACDistribution objects. class HVACDistributions < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << HVACDistribution.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/HVAC/HVACDistribution').each do |hvac_distribution| @@ -6028,20 +7474,32 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACDistribution. class HVACDistribution < BaseElement def initialize(hpxml_bldg, *args, **kwargs) @duct_leakage_measurements = DuctLeakageMeasurements.new(hpxml_bldg) @ducts = Ducts.new(hpxml_bldg) super(hpxml_bldg, *args, **kwargs) end - ATTRS = [:id, :distribution_system_type, :annual_heating_dse, :annual_cooling_dse, :duct_system_sealed, - :conditioned_floor_area_served, :number_of_return_registers, :air_type, :hydronic_type, - :manualj_blower_fan_heat_btuh, :manualj_hot_water_piping_btuh] + CLASS_ATTRS = [:duct_leakage_measurements, # [HPXML::DuctLeakageMeasurements] + :ducts] # [HPXML::Ducts] + ATTRS = [:id, # [String] SystemIdentifier/@id + :distribution_system_type, # [String] DistributionSystemType/* (HPXML::HVACDistributionTypeXXX) + :number_of_return_registers, # [Integer] DistributionSystemType/AirDistribution/NumberofReturnRegisters + :air_type, # [String] DistributionSystemType/AirDistribution/AirDistributionType (HPXML::AirTypeXXX) + :manualj_blower_fan_heat_btuh, # [Double] DistributionSystemType/AirDistribution/extension/ManualJInputs/BlowerFanHeatBtuh (Btu/hr) + :hydronic_type, # [String] DistributionSystemType/HydronicDistribution/HydronicDistributionType (HPXML::HydronicTypeXXX) + :manualj_hot_water_piping_btuh, # [Double] DistributionSystemType/HydronicDistribution/extension/ManualJInputs/HotWaterPipingBtuh (Btu/hr) + :annual_heating_dse, # [Double] DistributionSystemType/Other/AnnualHeatingDistributionSystemEfficiency (frac) + :annual_cooling_dse, # [Double] DistributionSystemType/Other/AnnualCoolingDistributionSystemEfficiency (frac) + :conditioned_floor_area_served, # [Double] ConditionedFloorAreaServed (ft2) + :duct_system_sealed] # [Boolean] HVACDistributionImprovement/DuctSystemSealed + attr_reader(*CLASS_ATTRS) attr_accessor(*ATTRS) - attr_reader(:duct_leakage_measurements, :ducts) - # TODO + # Returns all the HVAC systems attached to this HVAC distribution system. + # + # @return [Array] The list of HVAC systems def hvac_systems list = [] @parent_object.hvac_systems.each do |hvac_system| @@ -6076,7 +7534,10 @@ def hvac_systems return list end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.hvac_distributions.delete(self) @parent_object.hvac_systems.each do |hvac_system| next if hvac_system.distribution_system_idref.nil? @@ -6091,7 +7552,10 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; hvac_systems; rescue StandardError => e; errors << e.message; end errors += @duct_leakage_measurements.check_for_errors @@ -6099,7 +7563,11 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? hvac = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'HVAC']) @@ -6144,7 +7612,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(hvac_distribution) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hvac_distribution [Oga::XML::Element] The current HVACDistribution XML element + # @return [void] + def from_doc(hvac_distribution) return if hvac_distribution.nil? @id = HPXML::get_id(hvac_distribution) @@ -6174,13 +7646,20 @@ def from_doc(hvac_distribution) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::DuctLeakageMeasurement objects. class DuctLeakageMeasurements < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << DuctLeakageMeasurement.new(@parent_object, **kwargs) end - def from_doc(hvac_distribution) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hvac_distribution [Oga::XML::Element] The current HVACDistribution XML element + # @return [void] + def from_doc(hvac_distribution) return if hvac_distribution.nil? XMLHelper.get_elements(hvac_distribution, 'DuctLeakageMeasurement').each do |duct_leakage_measurement| @@ -6189,13 +7668,19 @@ def from_doc(hvac_distribution) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACDistribution/DuctLeakageMeasurement. class DuctLeakageMeasurement < BaseElement - ATTRS = [:duct_type, :duct_leakage_test_method, :duct_leakage_units, :duct_leakage_value, - :duct_leakage_total_or_to_outside] + ATTRS = [:duct_type, # [String] DuctType (HPXML::DuctTypeXXX) + :duct_leakage_test_method, # [String] DuctLeakageTestMethod + :duct_leakage_units, # [String] DuctLeakage/Units (HPXML::UnitsXXX) + :duct_leakage_value, # [Double] DuctLeakage/Value + :duct_leakage_total_or_to_outside] # [String] DuctLeakage/TotalOrToOutside (HPXML::DuctLeakageXXX) attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.hvac_distributions.each do |hvac_distribution| next unless hvac_distribution.duct_leakage_measurements.include? self @@ -6203,12 +7688,19 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(air_distribution) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param air_distribution [Oga::XML::Element] Parent XML element + # @return [void] + def to_doc(air_distribution) duct_leakage_measurement_el = XMLHelper.add_element(air_distribution, 'DuctLeakageMeasurement') XMLHelper.add_element(duct_leakage_measurement_el, 'DuctType', @duct_type, :string) unless @duct_type.nil? XMLHelper.add_element(duct_leakage_measurement_el, 'DuctLeakageTestMethod', @duct_leakage_test_method, :string) unless @duct_leakage_test_method.nil? @@ -6220,7 +7712,11 @@ def to_doc(air_distribution) # rubocop:disable Style/DocumentationMethod end end - def from_doc(duct_leakage_measurement) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param duct_leakage_measurement [Oga::XML::Element] The current DuctLeakageMeasurement XML element + # @return [void] + def from_doc(duct_leakage_measurement) return if duct_leakage_measurement.nil? @duct_type = XMLHelper.get_value(duct_leakage_measurement, 'DuctType', :string) @@ -6231,13 +7727,20 @@ def from_doc(duct_leakage_measurement) # rubocop:disable Style/DocumentationMeth end end - # TODO + # Array of HPXML::Duct objects. class Ducts < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Duct.new(@parent_object, **kwargs) end - def from_doc(hvac_distribution) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hvac_distribution [Oga::XML::Element] The current HVACDistribution XML element + # @return [void] + def from_doc(hvac_distribution) return if hvac_distribution.nil? XMLHelper.get_elements(hvac_distribution, 'Ducts').each do |duct| @@ -6246,14 +7749,26 @@ def from_doc(hvac_distribution) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACDistribution/Ducts. class Duct < BaseElement - ATTRS = [:id, :duct_type, :duct_insulation_r_value, :duct_insulation_material, :duct_location, - :duct_fraction_area, :duct_surface_area, :duct_surface_area_multiplier, :duct_shape, - :duct_buried_insulation_level, :duct_effective_r_value, :duct_fraction_rectangular] + ATTRS = [:id, # [String] SystemIdentifier/@id + :duct_type, # [String] DuctType (HPXML::DuctTypeXXX) + :duct_insulation_material, # [String] DuctInsulationMaterial/* + :duct_insulation_r_value, # [Double] DuctInsulationRValue (F-ft2-hr/Btu) + :duct_buried_insulation_level, # [String] DuctBuriedInsulationLevel (HPXML::DuctBuriedInsulationXXX) + :duct_effective_r_value, # [Double] DuctEffectiveRValue (F-ft2-hr/Btu) + :duct_location, # [String] DuctLocation (HPXML::LocationXXX) + :duct_fraction_area, # [Double] FractionDuctArea (frac) + :duct_surface_area, # [Double] DuctSurfaceArea (ft2) + :duct_shape, # [String] DuctShape (HPXML::DuctShapeXXX) + :duct_surface_area_multiplier, # [Double] extension/DuctSurfaceAreaMultiplier + :duct_fraction_rectangular] # [Double] extension/DuctFractionRectangular (frac) attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.hvac_distributions.each do |hvac_distribution| next unless hvac_distribution.ducts.include? self @@ -6261,12 +7776,19 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(air_distribution) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param air_distribution [Oga::XML::Element] Parent XML element + # @return [void] + def to_doc(air_distribution) ducts_el = XMLHelper.add_element(air_distribution, 'Ducts') sys_id = XMLHelper.add_element(ducts_el, 'SystemIdentifier') XMLHelper.add_attribute(sys_id, 'id', @id) @@ -6286,7 +7808,11 @@ def to_doc(air_distribution) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(ducts_el, 'DuctFractionRectangular', @duct_fraction_rectangular, :float, @duct_fraction_rectangular_isdefaulted) unless @duct_fraction_rectangular.nil? end - def from_doc(duct) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param duct [Oga::XML::Element] The current Duct XML element + # @return [void] + def from_doc(duct) return if duct.nil? @id = HPXML::get_id(duct) @@ -6304,13 +7830,20 @@ def from_doc(duct) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::VentilationFan objects. class VentilationFans < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << VentilationFan.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/MechanicalVentilation/VentilationFans/VentilationFan').each do |ventilation_fan| @@ -6319,21 +7852,47 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/MechanicalVentilation/VentilationFans/VentilationFan. class VentilationFan < BaseElement - ATTRS = [:id, :fan_type, :rated_flow_rate, :tested_flow_rate, :hours_in_operation, :flow_rate_not_tested, - :used_for_whole_building_ventilation, :used_for_seasonal_cooling_load_reduction, - :used_for_local_ventilation, :total_recovery_efficiency, :total_recovery_efficiency_adjusted, - :sensible_recovery_efficiency, :sensible_recovery_efficiency_adjusted, - :fan_power, :fan_power_defaulted, :count, :fan_location, :distribution_system_idref, :start_hour, - :is_shared_system, :in_unit_flow_rate, :fraction_recirculation, :used_for_garage_ventilation, - :preheating_fuel, :preheating_efficiency_cop, :preheating_fraction_load_served, :precooling_fuel, - :precooling_efficiency_cop, :precooling_fraction_load_served, :calculated_flow_rate, - :delivered_ventilation, :cfis_vent_mode_airflow_fraction, :cfis_addtl_runtime_operating_mode, - :cfis_supplemental_fan_idref] + ATTRS = [:id, # [String] SystemIdentifier/@id + :count, # [Integer] Count + :fan_type, # [String] FanType (HPXML::MechVentTypeXXX) + :cfis_addtl_runtime_operating_mode, # [String] CFISControls/AdditionalRuntimeOperatingMode (HPXML::CFISModeXXX) + :cfis_supplemental_fan_idref, # [String] CFISControls/SupplementalFan/@idref + :rated_flow_rate, # [Double] RatedFlowRate (cfm) + :calculated_flow_rate, # [Double] CalculatedFlowRate (cfm) + :tested_flow_rate, # [Double] TestedFlowRate (cfm) + :hours_in_operation, # [Double] HoursInOperation (hrs/day) + :delivered_ventilation, # [Double] DeliveredVentilation (cfm) + :fan_location, # [String] FanLocation (HPXML::LocationXXX) + :used_for_local_ventilation, # [Boolean] UsedForLocalVentilation + :used_for_whole_building_ventilation, # [Boolean] UsedForWholeBuildingVentilation + :used_for_seasonal_cooling_load_reduction, # [Boolean] UsedForSeasonalCoolingLoadReduction + :used_for_garage_ventilation, # [Boolean] UsedForGarageVentilation + :is_shared_system, # [Boolean] IsSharedSystem + :fraction_recirculation, # [Double] FractionRecirculation (frac) + :total_recovery_efficiency, # [Double] TotalRecoveryEfficiency (frac) + :sensible_recovery_efficiency, # [Double] SensibleRecoveryEfficiency (frac) + :total_recovery_efficiency_adjusted, # [Double] AdjustedTotalRecoveryEfficiency (frac) + :sensible_recovery_efficiency_adjusted, # [Double] AdjustedSensibleRecoveryEfficiency (frac) + :fan_power, # [Double] FanPower (W) + :distribution_system_idref, # [String] AttachedToHVACDistributionSystem/@idref + :start_hour, # [Integer] extension/StartHour + :in_unit_flow_rate, # [Double] extension/InUnitFlowRate (cfm) + :preheating_fuel, # [String] extension/PreHeating/Fuel (HPXML::FuelTypeXXX) + :preheating_efficiency_cop, # [Double] extension/PreHeating/AnnualHeatingEfficiency[Units="COP"]/Value (W/W) + :preheating_fraction_load_served, # [Double] extension/PreHeating/FractionVentilationHeatLoadServed (frac) + :precooling_fuel, # [String] extension/PreCooling/Fuel (HPXML::FuelTypeXXX) + :precooling_efficiency_cop, # [Double] extension/PreCooling/AnnualCoolingEfficiency[Units="COP"]/Value (W/W) + :precooling_fraction_load_served, # [Double] extension/PreCooling/FractionVentilationCoolLoadServed (frac) + :flow_rate_not_tested, # [Boolean] extension/FlowRateNotTested + :fan_power_defaulted, # [Boolean] extension/FanPowerDefaulted + :cfis_vent_mode_airflow_fraction] # [Double] extension/VentilationOnlyModeAirflowFraction (frac) attr_accessor(*ATTRS) - # TODO + # Returns the HVAC distribution system for the ventilation fan. + # + # @return [HPXML::HVACDistribution] The attached HVAC distribution system def distribution_system return if @distribution_system_idref.nil? return unless @fan_type == MechVentTypeCFIS @@ -6350,7 +7909,10 @@ def distribution_system fail "Attached HVAC distribution system '#{@distribution_system_idref}' not found for ventilation fan '#{@id}'." end - # TODO + # Returns the (instantaneous) flow rate. Used because there are multiple + # HPXML inputs that can describe the flow rate. + # + # @return [Double] Flow rate (cfm) def flow_rate [@tested_flow_rate, @delivered_ventilation, @calculated_flow_rate, @rated_flow_rate].each do |fr| return fr unless fr.nil? @@ -6358,8 +7920,13 @@ def flow_rate return end - # TODO - def total_unit_flow_rate + # Returns the (instantaneous) flow rate for the dwelling unit. Shared + # ventilation systems that serve multiple dwelling units have a separate + # flow rate input that describes how much of the total airflow serves + # the dwelling unit. + # + # @return [Double] Flow rate to the dwelling unit (cfm) + def unit_flow_rate if not @is_shared_system return flow_rate else @@ -6367,55 +7934,37 @@ def total_unit_flow_rate end end - # TODO + # Returns the outdoor air-only flow rate for the dwelling unit. + # Only differs from unit_flow_rate for shared systems with recirculation. + # + # @return [Double] Outdoor air flow rate to the dwelling unit (cfm) def oa_unit_flow_rate - return if total_unit_flow_rate.nil? + return if unit_flow_rate.nil? if not @is_shared_system - return total_unit_flow_rate + return unit_flow_rate else if @fan_type == HPXML::MechVentTypeExhaust && @fraction_recirculation > 0.0 fail "Exhaust fan '#{@id}' must have the fraction recirculation set to zero." else - return total_unit_flow_rate * (1 - @fraction_recirculation) + return unit_flow_rate * (1 - @fraction_recirculation) end end end - # TODO - def average_oa_unit_flow_rate - # Daily-average outdoor air (cfm) associated with the unit - return if oa_unit_flow_rate.nil? - return if @hours_in_operation.nil? - - return oa_unit_flow_rate * (@hours_in_operation / 24.0) - end - - # TODO - def average_total_unit_flow_rate - # Daily-average total air (cfm) associated with the unit - return if total_unit_flow_rate.nil? - return if @hours_in_operation.nil? - - return total_unit_flow_rate * (@hours_in_operation / 24.0) - end - - # TODO - def unit_flow_rate_ratio - return 1.0 unless @is_shared_system - return if @in_unit_flow_rate.nil? - - if not flow_rate.nil? - ratio = @in_unit_flow_rate / flow_rate - end - return ratio - end - - # TODO + # Returns the (instantaneous) fan power associated with the dwelling unit. + # For shared ventilation systems that serve multiple dwelling units, the + # total fan power is apportioned to the dwelling unit using the + # flow rate to the dwelling unit divided by the total flow rate. + # + # @return [Double] Fan power associated with the dwelling unit (W) def unit_fan_power return if @fan_power.nil? if @is_shared_system - return if unit_flow_rate_ratio.nil? + return if @in_unit_flow_rate.nil? + return if flow_rate.nil? + + unit_flow_rate_ratio = @in_unit_flow_rate / flow_rate return @fan_power * unit_flow_rate_ratio else @@ -6423,42 +7972,64 @@ def unit_fan_power end end - # TODO - def average_unit_fan_power - return if unit_fan_power.nil? + # Returns the daily-average flow rate for the dwelling unit. + # Only differs from unit_flow_rate for systems that operate < 24 hrs/day. + # + # @return [Double] Daily-average flow rate to the dwelling unit (cfm) + def average_unit_flow_rate + return if unit_flow_rate.nil? return if @hours_in_operation.nil? - return unit_fan_power * (@hours_in_operation / 24.0) + return unit_flow_rate * (@hours_in_operation / 24.0) end - # TODO - def includes_supply_air? - if [MechVentTypeSupply, MechVentTypeCFIS, MechVentTypeBalanced, MechVentTypeERV, MechVentTypeHRV].include? @fan_type - return true - end + # Returns the daily-average outdoor air flow rate for the dwelling unit. + # Only differs from oa_unit_flow_rate for systems that operate < 24 hrs/day. + # + # @return [Double] Daily-average outdoor air flow rate to the dwelling unit (cfm) + def average_oa_unit_flow_rate + return if oa_unit_flow_rate.nil? + return if @hours_in_operation.nil? - return false + return oa_unit_flow_rate * (@hours_in_operation / 24.0) end - # TODO - def includes_exhaust_air? - if [MechVentTypeExhaust, MechVentTypeBalanced, MechVentTypeERV, MechVentTypeHRV].include? @fan_type - return true - end + # Returns the daily average fan power associated with the dwelling unit. + # Only differs from unit_fan_power for systems that operate < 24 hrs/day. + # + # @return [Double] Daily-average fan power associated with the dwelling unit (W) + def average_unit_fan_power + return if unit_fan_power.nil? + return if @hours_in_operation.nil? - return false + return unit_fan_power * (@hours_in_operation / 24.0) end - # TODO - def is_balanced? - if includes_supply_air? && includes_exhaust_air? - return true - end + # Returns whether the ventilation fan supplies air. + # + # @return [Boolean] True if it supplies air + def includes_supply_air + return [MechVentTypeSupply, MechVentTypeCFIS, MechVentTypeBalanced, MechVentTypeERV, MechVentTypeHRV].include?(@fan_type) + end - return false + # Returns whether the ventilation fan exhausts air. + # + # @return [Boolean] True if it exhausts air + def includes_exhaust_air + return [MechVentTypeExhaust, MechVentTypeBalanced, MechVentTypeERV, MechVentTypeHRV].include?(@fan_type) + end + + # Returns whether the ventilation fan both supplies and exhausts air, which indicates + # it is a balanced system. + # + # @return [Boolean] True if it is a balanced system + def is_balanced + return includes_supply_air && includes_exhaust_air end - # TODO + # Returns the supplemental fan to this ventilation fan if it's a CFIS system. + # + # @return [HPXML::VentilationFan] The supplemental fan def cfis_supplemental_fan return if @cfis_supplemental_fan_idref.nil? return unless @fan_type == MechVentTypeCFIS @@ -6484,8 +8055,10 @@ def cfis_supplemental_fan fail "CFIS Supplemental Fan '#{@cfis_supplemental_fan_idref}' not found for ventilation fan '#{@id}'." end - # TODO - def is_cfis_supplemental_fan? + # Returns whether this ventilation fan serves as a supplemental fan to a CFIS system. + # + # @return [Boolean] True if a CFIS supplemental fan + def is_cfis_supplemental_fan @parent_object.ventilation_fans.each do |ventilation_fan| next unless ventilation_fan.fan_type == MechVentTypeCFIS next unless ventilation_fan.cfis_supplemental_fan_idref == @id @@ -6495,20 +8068,29 @@ def is_cfis_supplemental_fan? return false end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.ventilation_fans.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; distribution_system; rescue StandardError => e; errors << e.message; end begin; oa_unit_flow_rate; rescue StandardError => e; errors << e.message; end - begin; unit_flow_rate_ratio; rescue StandardError => e; errors << e.message; end begin; cfis_supplemental_fan; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? ventilation_fans = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'MechanicalVentilation', 'VentilationFans']) @@ -6569,7 +8151,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(ventilation_fan, 'VentilationOnlyModeAirflowFraction', @cfis_vent_mode_airflow_fraction, :float, @cfis_vent_mode_airflow_fraction_isdefaulted) unless @cfis_vent_mode_airflow_fraction.nil? end - def from_doc(ventilation_fan) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param ventilation_fan [Oga::XML::Element] The current VentilationFan XML element + # @return [void] + def from_doc(ventilation_fan) return if ventilation_fan.nil? @id = HPXML::get_id(ventilation_fan) @@ -6609,13 +8195,20 @@ def from_doc(ventilation_fan) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::WaterHeatingSystem objects. class WaterHeatingSystems < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << WaterHeatingSystem.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/WaterHeating/WaterHeatingSystem').each do |water_heating_system| @@ -6624,16 +8217,39 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/WaterHeating/WaterHeatingSystem. class WaterHeatingSystem < BaseElement - ATTRS = [:id, :year_installed, :fuel_type, :water_heater_type, :location, :performance_adjustment, - :tank_volume, :fraction_dhw_load_served, :heating_capacity, :energy_factor, :usage_bin, - :uniform_energy_factor, :first_hour_rating, :recovery_efficiency, :uses_desuperheater, :jacket_r_value, - :related_hvac_idref, :third_party_certification, :standby_loss_units, :standby_loss_value, - :temperature, :is_shared_system, :number_of_bedrooms_served, :tank_model_type, :operating_mode] + ATTRS = [:id, # [String] SystemIdentifier/@id + :fuel_type, # [String] FuelType (HPXML::FuelTypeXXX) + :water_heater_type, # [String] WaterHeaterType (HPXML::WaterHeaterTypeXXX) + :location, # [String] Location (HPXML::LocationXXX) + :year_installed, # [Integer] YearInstalled + :is_shared_system, # [Boolean] IsSharedSystem + :performance_adjustment, # [Double] PerformanceAdjustment (frac) + :third_party_certification, # [String] ThirdPartyCertification + :tank_volume, # [Double] TankVolume (gal) + :fraction_dhw_load_served, # [Double] FractionDHWLoadServed (frac) + :heating_capacity, # [Double] HeatingCapacity (Btu/hr) + :energy_factor, # [Double] EnergyFactor (frac) + :uniform_energy_factor, # [Double] UniformEnergyFactor (frac) + :operating_mode, # [String] HPWHOperatingMode (HPXML::WaterHeaterOperatingModeXXX) + :first_hour_rating, # [Double] FirstHourRating (gal/hr) + :usage_bin, # [String] UsageBin (HPXML::WaterHeaterUsageBinXXX) + :recovery_efficiency, # [Double] RecoveryEfficiency (frac) + :jacket_r_value, # [Double] WaterHeaterInsulation/Jacket/JacketRValue (F-ft2-hr/Btu) + :standby_loss_units, # [String] StandbyLoss/Units (HPXML::UnitsXXX) + :standby_loss_value, # [Double] StandbyLoss/Value + :temperature, # [Double] HotWaterTemperature (F) + :uses_desuperheater, # [Boolean] UsesDesuperheater + :related_hvac_idref, # [String] RelatedHVACSystem/@idref + :tank_model_type, # [String] extension/TankModelType (HPXML::WaterHeaterTankModelTypeXXX) + :number_of_bedrooms_served] # [Integer] extension/NumberofBedroomsServed attr_accessor(*ATTRS) - # TODO + # Returns the HVAC system related to this water heating system (e.g., for + # a combination boiler that provides both water heating and space heating). + # + # @return [HPXML::XXX] The HVAC system def related_hvac_system return if @related_hvac_idref.nil? @@ -6645,7 +8261,10 @@ def related_hvac_system fail "RelatedHVACSystem '#{@related_hvac_idref}' not found for water heating system '#{@id}'." end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.water_heating_systems.delete(self) @parent_object.solar_thermal_systems.each do |solar_thermal_system| next unless solar_thermal_system.water_heating_system_idref == @id @@ -6664,13 +8283,20 @@ def delete # rubocop:disable Style/DocumentationMethod end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; related_hvac_system; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? water_heating = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'WaterHeating']) @@ -6716,7 +8342,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(water_heating_system) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param water_heating_system [Oga::XML::Element] The current WaterHeatingSystem XML element + # @return [void] + def from_doc(water_heating_system) return if water_heating_system.nil? @id = HPXML::get_id(water_heating_system) @@ -6747,13 +8377,20 @@ def from_doc(water_heating_system) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::HotWaterDistribution objects. class HotWaterDistributions < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << HotWaterDistribution.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/WaterHeating/HotWaterDistribution').each do |hot_water_distribution| @@ -6762,27 +8399,49 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/WaterHeating/HotWaterDistribution. class HotWaterDistribution < BaseElement - ATTRS = [:id, :system_type, :pipe_r_value, :standard_piping_length, :recirculation_control_type, - :recirculation_piping_length, :recirculation_branch_piping_length, - :recirculation_pump_power, :dwhr_facilities_connected, :dwhr_equal_flow, - :dwhr_efficiency, :has_shared_recirculation, :shared_recirculation_number_of_bedrooms_served, - :shared_recirculation_pump_power, :shared_recirculation_control_type, - :shared_recirculation_motor_efficiency, - :recirculation_pump_weekday_fractions, :recirculation_pump_weekend_fractions, :recirculation_pump_monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :system_type, # [String] SystemType/* (HPXML::DHWDistTypeXXX) + :standard_piping_length, # [Double] SystemType/Standard/PipingLength (ft) + :recirculation_control_type, # [String] SystemType/Recirculation/ControlType (HPXML::DHWRecircControlTypeXXX) + :recirculation_piping_loop_length, # [Double] SystemType/Recirculation/RecirculationPipingLoopLength (ft) + :recirculation_branch_piping_length, # [Double] SystemType/Recirculation/BranchPipingLength (ft) + :recirculation_pump_power, # [Double] SystemType/Recirculation/PumpPower (W) + :pipe_r_value, # [Double] PipeInsulation/PipeRValue (F-ft2-hr/Btu) + :dwhr_facilities_connected, # [String] DrainWaterHeatRecovery/FacilitiesConnected (HPXML::DWHRFacilitiesConnectedXXX) + :dwhr_equal_flow, # [Boolean] DrainWaterHeatRecovery/EqualFlow + :dwhr_efficiency, # [Double] DrainWaterHeatRecovery/Efficiency (frac) + :has_shared_recirculation, # [Boolean] extension/SharedRecirculation + :shared_recirculation_number_of_bedrooms_served, # [Integer] extension/SharedRecirculation/NumberofBedroomsServed + :shared_recirculation_pump_power, # [Double] extension/SharedRecirculation/PumpPower (W) + :shared_recirculation_motor_efficiency, # [Double] extension/SharedRecirculation/MotorEfficiency (frac) + :shared_recirculation_control_type, # [String] extension/SharedRecirculation/ControlType (HPXML::DHWRecircControlTypeXXX) + :recirculation_pump_weekday_fractions, # [String] extension/RecirculationPumpWeekdayScheduleFractions + :recirculation_pump_weekend_fractions, # [String] extension/RecirculationPumpWeekendScheduleFractions + :recirculation_pump_monthly_multipliers] # [String] extension/RecirculationPumpMonthlyScheduleMultipliers attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.hot_water_distributions.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? water_heating = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'WaterHeating']) @@ -6797,7 +8456,7 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod elsif system_type == DHWDistTypeRecirc recirculation = XMLHelper.add_element(system_type_el, @system_type) XMLHelper.add_element(recirculation, 'ControlType', @recirculation_control_type, :string) unless @recirculation_control_type.nil? - XMLHelper.add_element(recirculation, 'RecirculationPipingLoopLength', @recirculation_piping_length, :float, @recirculation_piping_length_isdefaulted) unless @recirculation_piping_length.nil? + XMLHelper.add_element(recirculation, 'RecirculationPipingLoopLength', @recirculation_piping_loop_length, :float, @recirculation_piping_loop_length_isdefaulted) unless @recirculation_piping_loop_length.nil? XMLHelper.add_element(recirculation, 'BranchPipingLength', @recirculation_branch_piping_length, :float, @recirculation_branch_piping_length_isdefaulted) unless @recirculation_branch_piping_length.nil? XMLHelper.add_element(recirculation, 'PumpPower', @recirculation_pump_power, :float, @recirculation_pump_power_isdefaulted) unless @recirculation_pump_power.nil? else @@ -6827,7 +8486,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(hot_water_distribution, 'RecirculationPumpMonthlyScheduleMultipliers', @recirculation_pump_monthly_multipliers, :string, @recirculation_pump_monthly_multipliers_isdefaulted) unless @recirculation_pump_monthly_multipliers.nil? end - def from_doc(hot_water_distribution) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hot_water_distribution [Oga::XML::Element] The current HotWaterDistribution XML element + # @return [void] + def from_doc(hot_water_distribution) return if hot_water_distribution.nil? @id = HPXML::get_id(hot_water_distribution) @@ -6836,7 +8499,7 @@ def from_doc(hot_water_distribution) # rubocop:disable Style/DocumentationMethod @standard_piping_length = XMLHelper.get_value(hot_water_distribution, 'SystemType/Standard/PipingLength', :float) elsif @system_type == 'Recirculation' @recirculation_control_type = XMLHelper.get_value(hot_water_distribution, 'SystemType/Recirculation/ControlType', :string) - @recirculation_piping_length = XMLHelper.get_value(hot_water_distribution, 'SystemType/Recirculation/RecirculationPipingLoopLength', :float) + @recirculation_piping_loop_length = XMLHelper.get_value(hot_water_distribution, 'SystemType/Recirculation/RecirculationPipingLoopLength', :float) @recirculation_branch_piping_length = XMLHelper.get_value(hot_water_distribution, 'SystemType/Recirculation/BranchPipingLength', :float) @recirculation_pump_power = XMLHelper.get_value(hot_water_distribution, 'SystemType/Recirculation/PumpPower', :float) end @@ -6857,13 +8520,20 @@ def from_doc(hot_water_distribution) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::WaterFixture objects. class WaterFixtures < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << WaterFixture.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/WaterHeating/WaterFixture').each do |water_fixture| @@ -6872,21 +8542,35 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/WaterHeating/WaterFixture. class WaterFixture < BaseElement - ATTRS = [:id, :water_fixture_type, :low_flow, :flow_rate, :count] + ATTRS = [:id, # [String] SystemIdentifier/@id + :water_fixture_type, # [String] WaterFixtureType (HPXML::WaterFixtureTypeXXX) + :count, # [Integer] Count + :flow_rate, # [Double] FlowRate (gpm) + :low_flow] # [Boolean] LowFlow attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.water_fixtures.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? water_heating = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'WaterHeating']) @@ -6899,7 +8583,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(water_fixture, 'LowFlow', @low_flow, :boolean, @low_flow_isdefaulted) unless @low_flow.nil? end - def from_doc(water_fixture) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param water_fixture [Oga::XML::Element] The current WaterFixture XML element + # @return [void] + def from_doc(water_fixture) return if water_fixture.nil? @id = HPXML::get_id(water_fixture) @@ -6910,18 +8598,27 @@ def from_doc(water_fixture) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/WaterHeating/extension. class WaterHeating < BaseElement - ATTRS = [:water_fixtures_usage_multiplier, :water_fixtures_weekday_fractions, :water_fixtures_weekend_fractions, - :water_fixtures_monthly_multipliers] + ATTRS = [:water_fixtures_usage_multiplier, # [Double] extension/WaterFixturesUsageMultiplier + :water_fixtures_weekday_fractions, # [String] extension/WaterFixturesWeekdayScheduleFractions + :water_fixtures_weekend_fractions, # [String] extension/WaterFixturesWeekendScheduleFractions + :water_fixtures_monthly_multipliers] # [String] extension/WaterFixturesMonthlyScheduleMultipliers attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? water_heating = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'WaterHeating']) @@ -6931,7 +8628,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(water_heating, 'WaterFixturesMonthlyScheduleMultipliers', @water_fixtures_monthly_multipliers, :string, @water_fixtures_monthly_multipliers_isdefaulted) unless @water_fixtures_monthly_multipliers.nil? end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? water_heating = XMLHelper.get_element(building, 'BuildingDetails/Systems/WaterHeating') @@ -6944,13 +8645,20 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::SolarThermalSystem objects. class SolarThermalSystems < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << SolarThermalSystem.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/SolarThermal/SolarThermalSystem').each do |solar_thermal_system| @@ -6959,14 +8667,26 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/SolarThermal/SolarThermalSystem. class SolarThermalSystem < BaseElement - ATTRS = [:id, :system_type, :collector_area, :collector_loop_type, :collector_orientation, :collector_azimuth, - :collector_type, :collector_tilt, :collector_frta, :collector_frul, :storage_volume, - :water_heating_system_idref, :solar_fraction] + ATTRS = [:id, # [String] SystemIdentifier/@id + :system_type, # [String] SystemType (HPXML::SolarThermalSystemTypeXXX) + :collector_area, # [Double] CollectorArea (ft2) + :collector_loop_type, # [String] CollectorLoopType (HPXML::SolarThermalLoopTypeXXX) + :collector_type, # [String] CollectorType (HPXML::SolarThermalCollectorTypeXXX) + :collector_orientation, # [String] CollectorOrientation (HPXML::OrientationXXX) + :collector_azimuth, # [Integer] CollectorAzimuth (deg) + :collector_tilt, # [Double] CollectorTilt (deg) + :collector_rated_optical_efficiency, # [Double] CollectorRatedOpticalEfficiency (frac) + :collector_rated_thermal_losses, # [Double] CollectorRatedThermalLosses (Btu/hr-ft2-R) + :storage_volume, # [Double] StorageVolume (gal) + :water_heating_system_idref, # [String] ConnectedTo/@idref + :solar_fraction] # [Double] SolarFraction (frac) attr_accessor(*ATTRS) - # TODO + # Returns the water heater connected to the solar thermal system. + # + # @return [HPXML::WaterHeatingSystem] The attached water heating system def water_heating_system return if @water_heating_system_idref.nil? @@ -6978,17 +8698,27 @@ def water_heating_system fail "Attached water heating system '#{@water_heating_system_idref}' not found for solar thermal system '#{@id}'." end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.solar_thermal_systems.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; water_heating_system; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? solar_thermal = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'SolarThermal']) @@ -7002,8 +8732,8 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(solar_thermal_system, 'CollectorOrientation', @collector_orientation, :string, @collector_orientation_isdefaulted) unless @collector_orientation.nil? XMLHelper.add_element(solar_thermal_system, 'CollectorAzimuth', @collector_azimuth, :integer, @collector_azimuth_isdefaulted) unless @collector_azimuth.nil? XMLHelper.add_element(solar_thermal_system, 'CollectorTilt', @collector_tilt, :float) unless @collector_tilt.nil? - XMLHelper.add_element(solar_thermal_system, 'CollectorRatedOpticalEfficiency', @collector_frta, :float) unless @collector_frta.nil? - XMLHelper.add_element(solar_thermal_system, 'CollectorRatedThermalLosses', @collector_frul, :float) unless @collector_frul.nil? + XMLHelper.add_element(solar_thermal_system, 'CollectorRatedOpticalEfficiency', @collector_rated_optical_efficiency, :float) unless @collector_rated_optical_efficiency.nil? + XMLHelper.add_element(solar_thermal_system, 'CollectorRatedThermalLosses', @collector_rated_thermal_losses, :float) unless @collector_rated_thermal_losses.nil? XMLHelper.add_element(solar_thermal_system, 'StorageVolume', @storage_volume, :float, @storage_volume_isdefaulted) unless @storage_volume.nil? if not @water_heating_system_idref.nil? connected_to = XMLHelper.add_element(solar_thermal_system, 'ConnectedTo') @@ -7012,7 +8742,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(solar_thermal_system, 'SolarFraction', @solar_fraction, :float) unless @solar_fraction.nil? end - def from_doc(solar_thermal_system) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param solar_thermal_system [Oga::XML::Element] The current SolarThermalSystem XML element + # @return [void] + def from_doc(solar_thermal_system) return if solar_thermal_system.nil? @id = HPXML::get_id(solar_thermal_system) @@ -7023,21 +8757,28 @@ def from_doc(solar_thermal_system) # rubocop:disable Style/DocumentationMethod @collector_orientation = XMLHelper.get_value(solar_thermal_system, 'CollectorOrientation', :string) @collector_azimuth = XMLHelper.get_value(solar_thermal_system, 'CollectorAzimuth', :integer) @collector_tilt = XMLHelper.get_value(solar_thermal_system, 'CollectorTilt', :float) - @collector_frta = XMLHelper.get_value(solar_thermal_system, 'CollectorRatedOpticalEfficiency', :float) - @collector_frul = XMLHelper.get_value(solar_thermal_system, 'CollectorRatedThermalLosses', :float) + @collector_rated_optical_efficiency = XMLHelper.get_value(solar_thermal_system, 'CollectorRatedOpticalEfficiency', :float) + @collector_rated_thermal_losses = XMLHelper.get_value(solar_thermal_system, 'CollectorRatedThermalLosses', :float) @storage_volume = XMLHelper.get_value(solar_thermal_system, 'StorageVolume', :float) @water_heating_system_idref = HPXML::get_idref(XMLHelper.get_element(solar_thermal_system, 'ConnectedTo')) @solar_fraction = XMLHelper.get_value(solar_thermal_system, 'SolarFraction', :float) end end - # TODO + # Array of HPXML::PVSystem objects. class PVSystems < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << PVSystem.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/Photovoltaics/PVSystem').each do |pv_system| @@ -7046,14 +8787,27 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/Photovoltaics/PVSystem. class PVSystem < BaseElement - ATTRS = [:id, :location, :module_type, :tracking, :array_orientation, :array_azimuth, :array_tilt, - :max_power_output, :inverter_idref, :system_losses_fraction, :number_of_panels, - :year_modules_manufactured, :is_shared_system, :number_of_bedrooms_served] + ATTRS = [:id, # [String] SystemIdentifier/@id + :is_shared_system, # [Boolean] IsSharedSystem + :location, # [String] Location (HPXML::LocationXXX) + :module_type, # [String] ModuleType (HPXML::PVModuleTypeXXX) + :tracking, # [String] Tracking (HPXML::PVTrackingTypeXXX) + :array_orientation, # [String] ArrayOrientation (HPXML::OrientationXXX) + :array_azimuth, # [Integer] ArrayAzimuth (deg) + :array_tilt, # [Double] ArrayTilt (deg) + :max_power_output, # [Double] MaxPowerOutput (W) + :number_of_panels, # [Integer] NumberOfPanels + :system_losses_fraction, # [Double] SystemLossesFraction (frac) + :year_modules_manufactured, # [Integer] YearModulesManufactured + :inverter_idref, # [String] AttachedToInverter/@idref + :number_of_bedrooms_served] # [Integer] extension/NumberofBedroomsServed attr_accessor(*ATTRS) - # TODO + # Returns the inverter connected to the PV system. + # + # @return [HPXML::Inverter] The attached inverter object def inverter return if @inverter_idref.nil? @@ -7065,17 +8819,27 @@ def inverter fail "Attached inverter '#{@inverter_idref}' not found for pv system '#{@id}'." end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.pv_systems.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; inverter; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? photovoltaics = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'Photovoltaics']) @@ -7100,7 +8864,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(pv_system, 'NumberofBedroomsServed', @number_of_bedrooms_served, :integer) unless @number_of_bedrooms_served.nil? end - def from_doc(pv_system) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param pv_system [Oga::XML::Element] The current PVSystem XML element + # @return [void] + def from_doc(pv_system) return if pv_system.nil? @id = HPXML::get_id(pv_system) @@ -7120,13 +8888,20 @@ def from_doc(pv_system) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Inverter objects. class Inverters < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Inverter.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/Photovoltaics/Inverter').each do |inverter| @@ -7135,33 +8910,53 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/Photovoltaics/Inverter. class Inverter < BaseElement - ATTRS = [:id, :inverter_efficiency] + ATTRS = [:id, # [String] SystemIdentifier/@id + :inverter_efficiency] # [Double] InverterEfficiency (frac) attr_accessor(*ATTRS) - # TODO - def pv_system + # Returns all PV systems connected to the inverter. + # + # @return [HPXML::PVSystem] The list of PV systems + def pv_systems return if @id.nil? + list = [] @parent_object.pv_systems.each do |pv| next unless @id == pv.inverter_idref - return pv + list << pv + end + + if list.size == 0 + fail "Inverter '#{@id}' found but no PV systems attached to it." end + + return list end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.inverters.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] - begin; pv_system; rescue StandardError => e; errors << e.message; end + begin; pv_systems; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? photovoltaics = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'Photovoltaics']) @@ -7171,7 +8966,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(inverter, 'InverterEfficiency', @inverter_efficiency, :float, @inverter_efficiency_isdefaulted) unless @inverter_efficiency.nil? end - def from_doc(inverter) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param inverter [Oga::XML::Element] The current Inverter XML element + # @return [void] + def from_doc(inverter) return if inverter.nil? @id = HPXML::get_id(inverter) @@ -7179,68 +8978,20 @@ def from_doc(inverter) # rubocop:disable Style/DocumentationMethod end end - # TODO - class Generators < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod - self << Generator.new(@parent_object, **kwargs) - end - - def from_doc(building) # rubocop:disable Style/DocumentationMethod - return if building.nil? - - XMLHelper.get_elements(building, 'BuildingDetails/Systems/extension/Generators/Generator').each do |generator| - self << Generator.new(@parent_object, generator) - end - end - end - - # TODO - class Generator < BaseElement - ATTRS = [:id, :fuel_type, :annual_consumption_kbtu, :annual_output_kwh, :is_shared_system, :number_of_bedrooms_served] - attr_accessor(*ATTRS) - - def delete # rubocop:disable Style/DocumentationMethod - @parent_object.generators.delete(self) - end - - def check_for_errors # rubocop:disable Style/DocumentationMethod - errors = [] - return errors - end - - def to_doc(building) # rubocop:disable Style/DocumentationMethod - return if nil? - - generators = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'extension', 'Generators']) - generator = XMLHelper.add_element(generators, 'Generator') - sys_id = XMLHelper.add_element(generator, 'SystemIdentifier') - XMLHelper.add_attribute(sys_id, 'id', @id) - XMLHelper.add_element(generator, 'IsSharedSystem', @is_shared_system, :boolean, @is_shared_system_isdefaulted) unless @is_shared_system.nil? - XMLHelper.add_element(generator, 'FuelType', @fuel_type, :string) unless @fuel_type.nil? - XMLHelper.add_element(generator, 'AnnualConsumptionkBtu', @annual_consumption_kbtu, :float) unless @annual_consumption_kbtu.nil? - XMLHelper.add_element(generator, 'AnnualOutputkWh', @annual_output_kwh, :float) unless @annual_output_kwh.nil? - XMLHelper.add_element(generator, 'NumberofBedroomsServed', @number_of_bedrooms_served, :integer) unless @number_of_bedrooms_served.nil? - end - - def from_doc(generator) # rubocop:disable Style/DocumentationMethod - return if generator.nil? - - @id = HPXML::get_id(generator) - @is_shared_system = XMLHelper.get_value(generator, 'IsSharedSystem', :boolean) - @fuel_type = XMLHelper.get_value(generator, 'FuelType', :string) - @annual_consumption_kbtu = XMLHelper.get_value(generator, 'AnnualConsumptionkBtu', :float) - @annual_output_kwh = XMLHelper.get_value(generator, 'AnnualOutputkWh', :float) - @number_of_bedrooms_served = XMLHelper.get_value(generator, 'NumberofBedroomsServed', :integer) - end - end - - # TODO + # Array of HPXML::Battery objects. class Batteries < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Battery.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Systems/Batteries/Battery').each do |battery| @@ -7249,23 +9000,43 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/Batteries/Battery. class Battery < BaseElement - ATTRS = [:id, :type, :location, :lifetime_model, :rated_power_output, :nominal_capacity_kwh, :nominal_capacity_ah, - :nominal_voltage, :round_trip_efficiency, :usable_capacity_kwh, :usable_capacity_ah, :is_shared_system, - :number_of_bedrooms_served] + ATTRS = [:id, # [String] SystemIdentifier/@id + :is_shared_system, # [Boolean] IsSharedSystem + :location, # [String] Location (HPXML::LocationXXX) + :type, # [String] BatteryType (HPXML::BatteryTypeXXX) + :nominal_capacity_kwh, # [Double] NominalCapacity[Units="kWh"]/Value (kWh) + :nominal_capacity_ah, # [Double] NominalCapacity[Units="Ah"]/Value (Ah) + :usable_capacity_kwh, # [Double] UsableCapacity[Units="kWh"]/Value (kWh) + :usable_capacity_ah, # [Double] UsableCapacity[Units="Ah"]/Value (Ah) + :rated_power_output, # [Double] RatedPowerOutput (W) + :nominal_voltage, # [Double] NominalVoltage (V) + :round_trip_efficiency, # [Double] RoundTripEfficiency (frac) + :lifetime_model, # [String] extension/LifetimeModel (HPXML::BatteryLifetimeModelXXX) + :number_of_bedrooms_served] # [Integer] extension/NumberofBedroomsServed attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.batteries.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? batteries = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'Batteries']) @@ -7302,7 +9073,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(battery, 'NumberofBedroomsServed', @number_of_bedrooms_served, :integer) unless @number_of_bedrooms_served.nil? end - def from_doc(battery) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param battery [Oga::XML::Element] The current Battery XML element + # @return [void] + def from_doc(battery) return if battery.nil? @id = HPXML::get_id(battery) @@ -7321,13 +9096,101 @@ def from_doc(battery) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Generator objects. + class Generators < BaseArrayElement + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) + self << Generator.new(@parent_object, **kwargs) + end + + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) + return if building.nil? + + XMLHelper.get_elements(building, 'BuildingDetails/Systems/extension/Generators/Generator').each do |generator| + self << Generator.new(@parent_object, generator) + end + end + end + + # Object for /HPXML/Building/BuildingDetails/Systems/extension/Generators/Generator. + class Generator < BaseElement + ATTRS = [:id, # [String] SystemIdentifier/@id + :is_shared_system, # [Boolean] IsSharedSystem + :fuel_type, # [String] FuelType (HPXML::FuelTypeXXX) + :annual_consumption_kbtu, # [Double] AnnualConsumptionkBtu (kBtu/yr) + :annual_output_kwh, # [Double] AnnualOutputkWh (kWh/yr) + :number_of_bedrooms_served] # [Integer] NumberofBedroomsServed + attr_accessor(*ATTRS) + + # Deletes the current object from the array. + # + # @return [void] + def delete + @parent_object.generators.delete(self) + end + + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors + errors = [] + return errors + end + + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) + return if nil? + + generators = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Systems', 'extension', 'Generators']) + generator = XMLHelper.add_element(generators, 'Generator') + sys_id = XMLHelper.add_element(generator, 'SystemIdentifier') + XMLHelper.add_attribute(sys_id, 'id', @id) + XMLHelper.add_element(generator, 'IsSharedSystem', @is_shared_system, :boolean, @is_shared_system_isdefaulted) unless @is_shared_system.nil? + XMLHelper.add_element(generator, 'FuelType', @fuel_type, :string) unless @fuel_type.nil? + XMLHelper.add_element(generator, 'AnnualConsumptionkBtu', @annual_consumption_kbtu, :float) unless @annual_consumption_kbtu.nil? + XMLHelper.add_element(generator, 'AnnualOutputkWh', @annual_output_kwh, :float) unless @annual_output_kwh.nil? + XMLHelper.add_element(generator, 'NumberofBedroomsServed', @number_of_bedrooms_served, :integer) unless @number_of_bedrooms_served.nil? + end + + # Populates the HPXML object(s) from the XML document. + # + # @param generator [Oga::XML::Element] The current Generator XML element + # @return [void] + def from_doc(generator) + return if generator.nil? + + @id = HPXML::get_id(generator) + @is_shared_system = XMLHelper.get_value(generator, 'IsSharedSystem', :boolean) + @fuel_type = XMLHelper.get_value(generator, 'FuelType', :string) + @annual_consumption_kbtu = XMLHelper.get_value(generator, 'AnnualConsumptionkBtu', :float) + @annual_output_kwh = XMLHelper.get_value(generator, 'AnnualOutputkWh', :float) + @number_of_bedrooms_served = XMLHelper.get_value(generator, 'NumberofBedroomsServed', :integer) + end + end + + # Array of HPXML::ClothesWasher. class ClothesWashers < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << ClothesWasher.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/ClothesWasher').each do |clothes_washer| @@ -7336,17 +9199,32 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/ClothesWasher. class ClothesWasher < BaseElement - ATTRS = [:id, :location, :modified_energy_factor, :integrated_modified_energy_factor, - :rated_annual_kwh, :label_electric_rate, :label_gas_rate, :label_annual_gas_cost, - :capacity, :label_usage, :usage_multiplier, :is_shared_appliance, :count, - :number_of_units_served, :water_heating_system_idref, :hot_water_distribution_idref, - :weekday_fractions, :weekend_fractions, :monthly_multipliers] - + ATTRS = [:id, # [String] SystemIdentifier/@id + :count, # [Integer] Count + :is_shared_appliance, # [Boolean] IsSharedAppliance + :number_of_units_served, # [Integer] NumberofUnitsServed + :water_heating_system_idref, # [String] AttachedToWaterHeatingSystem/@idref + :hot_water_distribution_idref, # [String] AttachedToHotWaterDistribution/@idref + :location, # [String] Location (HPXML::LocationXXX) + :modified_energy_factor, # [Double] ModifiedEnergyFactor (ft3/kWh/cyc) + :integrated_modified_energy_factor, # [Double] IntegratedModifiedEnergyFactor (ft3/kWh/cyc) + :rated_annual_kwh, # [Double] RatedAnnualkWh (kWh/yr) + :label_electric_rate, # [Double] LabelElectricRate ($/kWh) + :label_gas_rate, # [Double] LabelGasRate ($/therm) + :label_annual_gas_cost, # [Double] LabelAnnualGasCost ($) + :label_usage, # [Double] LabelUsage (cyc/wk) + :capacity, # [Double] Capacity (ft3) + :usage_multiplier, # [Double] extension/UsageMultiplier + :weekday_fractions, # [String] extension/WeekdayScheduleFractions + :weekend_fractions, # [String] extension/WeekendScheduleFractions + :monthly_multipliers] # [String] extension/MonthlyScheduleMultipliers attr_accessor(*ATTRS) - # TODO + # Returns the water heating system connected to the clothes washer. + # + # @return [HPXML::WaterHeatingSystem] The attached water heating system def water_heating_system return if @water_heating_system_idref.nil? @@ -7358,7 +9236,9 @@ def water_heating_system fail "Attached water heating system '#{@water_heating_system_idref}' not found for clothes washer '#{@id}'." end - # TODO + # Returns the hot water distribution system connected to the clothes washer. + # + # @return [HPXML::HotWaterDistribution] The connected hot water distribution system def hot_water_distribution return if @hot_water_distribution_idref.nil? @@ -7370,18 +9250,28 @@ def hot_water_distribution fail "Attached hot water distribution '#{@hot_water_distribution_idref}' not found for clothes washer '#{@id}'." end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.clothes_washers.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; water_heating_system; rescue StandardError => e; errors << e.message; end begin; hot_water_distribution; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7413,7 +9303,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(clothes_washer, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? end - def from_doc(clothes_washer) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param clothes_washer [Oga::XML::Element] The current ClothesWasher XML element + # @return [void] + def from_doc(clothes_washer) return if clothes_washer.nil? @id = HPXML::get_id(clothes_washer) @@ -7438,13 +9332,20 @@ def from_doc(clothes_washer) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::ClothesDryer objects. class ClothesDryers < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << ClothesDryer.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/ClothesDryer').each do |clothes_dryer| @@ -7453,24 +9354,45 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/ClothesDryer. class ClothesDryer < BaseElement - ATTRS = [:id, :location, :fuel_type, :energy_factor, :combined_energy_factor, :control_type, - :usage_multiplier, :is_shared_appliance, :count, :number_of_units_served, - :is_vented, :vented_flow_rate, :weekday_fractions, :weekend_fractions, - :monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :count, # [Integer] Count + :is_shared_appliance, # [Boolean] IsSharedAppliance + :number_of_units_served, # [Integer] NumberofUnitsServed + :location, # [String] Location (HPXML::LocationXXX) + :fuel_type, # [String] FuelType (HPXML::FuelTypeXXX) + :energy_factor, # [Double] EnergyFactor (lb/kWh) + :combined_energy_factor, # [Double] CombinedEnergyFactor (lb/kWh) + :control_type, # [String] ControlType (HPXML::ClothesDryerControlTypeXXX) + :is_vented, # [Boolean] Vented + :vented_flow_rate, # [Double] VentedFlowRate (cfm) + :usage_multiplier, # [Double] extension/UsageMultiplier + :weekday_fractions, # [String] extension/WeekdayScheduleFractions + :weekend_fractions, # [String] extension/WeekendScheduleFractions + :monthly_multipliers] # [String] extension/MonthlyScheduleMultipliers attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.clothes_dryers.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7493,7 +9415,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(clothes_dryer, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? end - def from_doc(clothes_dryer) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param clothes_dryer [Oga::XML::Element] The current ClothesDryer XML element + # @return [void] + def from_doc(clothes_dryer) return if clothes_dryer.nil? @id = HPXML::get_id(clothes_dryer) @@ -7514,13 +9440,20 @@ def from_doc(clothes_dryer) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Dishwasher objects. class Dishwashers < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Dishwasher.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/Dishwasher').each do |dishwasher| @@ -7529,15 +9462,29 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/Dishwasher. class Dishwasher < BaseElement - ATTRS = [:id, :location, :energy_factor, :rated_annual_kwh, :place_setting_capacity, - :label_electric_rate, :label_gas_rate, :label_annual_gas_cost, :label_usage, - :usage_multiplier, :is_shared_appliance, :water_heating_system_idref, - :hot_water_distribution_idref, :weekday_fractions, :weekend_fractions, :monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :is_shared_appliance, # [Boolean] IsSharedAppliance + :water_heating_system_idref, # [String] AttachedToWaterHeatingSystem/@idref + :hot_water_distribution_idref, # [String] AttachedToHotWaterDistribution/@idref + :location, # [String] Location (HPXML::LocationXXX) + :rated_annual_kwh, # [Double] RatedAnnualkWh (kWh/yr) + :energy_factor, # [Double] EnergyFactor + :place_setting_capacity, # [Integer] PlaceSettingCapacity + :label_electric_rate, # [Double] LabelElectricRate ($/kWh) + :label_gas_rate, # [Double] LabelGasRate ($/therm) + :label_annual_gas_cost, # [Double] LabelAnnualGasCost ($) + :label_usage, # [Double] LabelUsage (cyc/wk) + :usage_multiplier, # [Double] extension/UsageMultiplier + :weekday_fractions, # [String] extension/WeekdayScheduleFractions + :weekend_fractions, # [String] extension/WeekendScheduleFractions + :monthly_multipliers] # [String] extension/MonthlyScheduleMultipliers attr_accessor(*ATTRS) - # TODO + # Returns the water heating system connected to the dishwasher. + # + # @return [HPXML::WaterHeatingSystem] The attached water heating system def water_heating_system return if @water_heating_system_idref.nil? @@ -7549,7 +9496,9 @@ def water_heating_system fail "Attached water heating system '#{@water_heating_system_idref}' not found for dishwasher '#{@id}'." end - # TODO + # Returns the hot water distribution system connected to the dishwasher. + # + # @return [HPXML::HotWaterDistribution] The connected hot water distribution system def hot_water_distribution return if @hot_water_distribution_idref.nil? @@ -7561,18 +9510,28 @@ def hot_water_distribution fail "Attached hot water distribution '#{@hot_water_distribution_idref}' not found for dishwasher '#{@id}'." end - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.dishwashers.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] begin; water_heating_system; rescue StandardError => e; errors << e.message; end begin; hot_water_distribution; rescue StandardError => e; errors << e.message; end return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7601,7 +9560,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(dishwasher, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? end - def from_doc(dishwasher) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param dishwasher [Oga::XML::Element] The current Dishwasher XML element + # @return [void] + def from_doc(dishwasher) return if dishwasher.nil? @id = HPXML::get_id(dishwasher) @@ -7623,13 +9586,20 @@ def from_doc(dishwasher) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Refrigerator objects. class Refrigerators < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Refrigerator.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/Refrigerator').each do |refrigerator| @@ -7638,23 +9608,40 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/Refrigerator. class Refrigerator < BaseElement - ATTRS = [:id, :location, :rated_annual_kwh, :usage_multiplier, :primary_indicator, - :weekday_fractions, :weekend_fractions, :monthly_multipliers, - :constant_coefficients, :temperature_coefficients] + ATTRS = [:id, # [String] SystemIdentifier/@id + :location, # [String] Location (HPXML::LocationXXX) + :rated_annual_kwh, # [Double] RatedAnnualkWh (kWh/yr) + :primary_indicator, # [Boolean] PrimaryIndicator + :usage_multiplier, # [Double] UsageMultiplier + :weekday_fractions, # [String] WeekdayScheduleFractions + :weekend_fractions, # [String] WeekendScheduleFractions + :monthly_multipliers, # [String] MonthlyScheduleMultipliers + :constant_coefficients, # [String] ConstantScheduleCoefficients + :temperature_coefficients] # [String] TemperatureScheduleCoefficients attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.refrigerators.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7672,7 +9659,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(refrigerator, 'TemperatureScheduleCoefficients', @temperature_coefficients, :string, @temperature_coefficients_isdefaulted) unless @temperature_coefficients.nil? end - def from_doc(refrigerator) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param refrigerator [Oga::XML::Element] The current Refrigerator XML element + # @return [void] + def from_doc(refrigerator) return if refrigerator.nil? @id = HPXML::get_id(refrigerator) @@ -7688,13 +9679,20 @@ def from_doc(refrigerator) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Freezer objects. class Freezers < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Freezer.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/Freezer').each do |freezer| @@ -7703,23 +9701,39 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/Freezer. class Freezer < BaseElement - ATTRS = [:id, :location, :rated_annual_kwh, :usage_multiplier, - :weekday_fractions, :weekend_fractions, :monthly_multipliers, - :constant_coefficients, :temperature_coefficients] + ATTRS = [:id, # [String] SystemIdentifier/@id + :location, # [String] Location (HPXML::LocationXXX) + :rated_annual_kwh, # [Double] RatedAnnualkWh (kWh/yr) + :usage_multiplier, # [Double] UsageMultiplier + :weekday_fractions, # [String] WeekdayScheduleFractions + :weekend_fractions, # [String] WeekendScheduleFractions + :monthly_multipliers, # [String] MonthlyScheduleMultipliers + :constant_coefficients, # [String] ConstantScheduleCoefficients + :temperature_coefficients] # [String] TemperatureScheduleCoefficients attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.freezers.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7736,7 +9750,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(freezer, 'TemperatureScheduleCoefficients', @temperature_coefficients, :string, @temperature_coefficients_isdefaulted) unless @temperature_coefficients.nil? end - def from_doc(freezer) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param freezer [Oga::XML::Element] The current Freezer XML element + # @return [void] + def from_doc(freezer) return if freezer.nil? @id = HPXML::get_id(freezer) @@ -7751,13 +9769,20 @@ def from_doc(freezer) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Dehumidifier objects. class Dehumidifiers < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Dehumidifier.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/Dehumidifier').each do |dehumidifier| @@ -7766,22 +9791,38 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/Dehumidifier. class Dehumidifier < BaseElement - ATTRS = [:id, :type, :capacity, :energy_factor, :integrated_energy_factor, :rh_setpoint, :fraction_served, - :location] + ATTRS = [:id, # [String] SystemIdentifier/@id + :type, # [String] Type (HPXML::DehumidifierTypeXXX) + :location, # [String] Location (HPXML::LocationXXX) + :capacity, # [Double] Capacity (pints/day) + :energy_factor, # [Double] EnergyFactor (liters/kWh) + :integrated_energy_factor, # [Double] IntegratedEnergyFactor (liters/kWh) + :rh_setpoint, # [Double] DehumidistatSetpoint (frac) + :fraction_served] # [Double] FractionDehumidificationLoadServed (frac) attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.dehumidifiers.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7797,7 +9838,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(dehumidifier, 'FractionDehumidificationLoadServed', @fraction_served, :float) unless @fraction_served.nil? end - def from_doc(dehumidifier) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param dehumidifier [Oga::XML::Element] The current Dehumidifier XML element + # @return [void] + def from_doc(dehumidifier) return if dehumidifier.nil? @id = HPXML::get_id(dehumidifier) @@ -7811,13 +9856,20 @@ def from_doc(dehumidifier) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::CookingRange objects. class CookingRanges < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << CookingRange.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/CookingRange').each do |cooking_range| @@ -7826,22 +9878,38 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/CookingRange. class CookingRange < BaseElement - ATTRS = [:id, :location, :fuel_type, :is_induction, :usage_multiplier, - :weekday_fractions, :weekend_fractions, :monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :location, # [String] Location (HPXML::LocationXXX) + :fuel_type, # [String] FuelType (HPXML::FuelTypeXXX) + :is_induction, # [Boolean] IsInduction + :usage_multiplier, # [Double] UsageMultiplier + :weekday_fractions, # [String] WeekdayScheduleFractions + :weekend_fractions, # [String] WeekendScheduleFractions + :monthly_multipliers] # [String] MonthlyScheduleMultipliers attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.cooking_ranges.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7857,7 +9925,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(cooking_range, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? end - def from_doc(cooking_range) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param cooking_range [Oga::XML::Element] The current CookingRange XML element + # @return [void] + def from_doc(cooking_range) return if cooking_range.nil? @id = HPXML::get_id(cooking_range) @@ -7871,13 +9943,20 @@ def from_doc(cooking_range) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::Oven objects. class Ovens < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Oven.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Appliances/Oven').each do |oven| @@ -7886,21 +9965,32 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Appliances/Oven. class Oven < BaseElement - ATTRS = [:id, :is_convection] + ATTRS = [:id, # [String] SystemIdentifier/@id + :is_convection] # [Boolean] IsConvection attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.ovens.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? appliances = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Appliances']) @@ -7910,7 +10000,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_element(oven, 'IsConvection', @is_convection, :boolean, @is_convection_isdefaulted) unless @is_convection.nil? end - def from_doc(oven) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param oven [Oga::XML::Element] The current Oven XML element + # @return [void] + def from_doc(oven) return if oven.nil? @id = HPXML::get_id(oven) @@ -7918,13 +10012,20 @@ def from_doc(oven) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::LightingGroup objects. class LightingGroups < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << LightingGroup.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Lighting/LightingGroup').each do |lighting_group| @@ -7933,21 +10034,35 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Lighting/LightingGroup. class LightingGroup < BaseElement - ATTRS = [:id, :location, :fraction_of_units_in_location, :lighting_type, :kwh_per_year] + ATTRS = [:id, # [String] SystemIdentifier/@id + :location, # [String] Location (HPXML::LocationXXX) + :fraction_of_units_in_location, # [Double] FractionofUnitsInLocation (frac) + :lighting_type, # [String] LightingType/* (HPXML::LightingTypeXXX) + :kwh_per_year] # [Double] Load[Units="kWh/year"]/Value (kWh/yr) attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.lighting_groups.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? lighting = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Lighting']) @@ -7967,7 +10082,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(lighting_group) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param lighting_group [Oga::XML::Element] The current LightingGroup XML element + # @return [void] + def from_doc(lighting_group) return if lighting_group.nil? @id = HPXML::get_id(lighting_group) @@ -7978,25 +10097,130 @@ def from_doc(lighting_group) # rubocop:disable Style/DocumentationMethod end end - # TODO - class Lighting < BaseElement - ATTRS = [:interior_usage_multiplier, :garage_usage_multiplier, :exterior_usage_multiplier, - :interior_weekday_fractions, :interior_weekend_fractions, :interior_monthly_multipliers, - :garage_weekday_fractions, :garage_weekend_fractions, :garage_monthly_multipliers, - :exterior_weekday_fractions, :exterior_weekend_fractions, :exterior_monthly_multipliers, - :holiday_exists, :holiday_kwh_per_day, :holiday_period_begin_month, :holiday_period_begin_day, - :holiday_period_end_month, :holiday_period_end_day, :holiday_weekday_fractions, :holiday_weekend_fractions] + # Array of HPXML::CeilingFan objects. + class CeilingFans < BaseArrayElement + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) + self << CeilingFan.new(@parent_object, **kwargs) + end + + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) + return if building.nil? + + XMLHelper.get_elements(building, 'BuildingDetails/Lighting/CeilingFan').each do |ceiling_fan| + self << CeilingFan.new(@parent_object, ceiling_fan) + end + end + end + + # Object for /HPXML/Building/BuildingDetails/Lighting/CeilingFan. + class CeilingFan < BaseElement + ATTRS = [:id, # [String] SystemIdentifier/@id + :efficiency, # [Double] Airflow[FanSpeed="medium"]/Efficiency (cfm/W) + :count, # [Integer] Count + :label_energy_use, # [Double] LabelEnergyUse (W) + :weekday_fractions, # [String] WeekdayScheduleFractions + :weekend_fractions, # [String] WeekendScheduleFractions + :monthly_multipliers] # [String] MonthlyScheduleMultipliers attr_accessor(*ATTRS) - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete + @parent_object.ceiling_fans.delete(self) + end + + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] + return errors + end - errors += HPXML::check_dates('Exterior Holiday Lighting', @holiday_period_begin_month, @holiday_period_begin_day, @holiday_period_end_month, @holiday_period_end_day) + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) + return if nil? + lighting = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Lighting']) + ceiling_fan = XMLHelper.add_element(lighting, 'CeilingFan') + sys_id = XMLHelper.add_element(ceiling_fan, 'SystemIdentifier') + XMLHelper.add_attribute(sys_id, 'id', @id) + if not @efficiency.nil? + airflow = XMLHelper.add_element(ceiling_fan, 'Airflow') + XMLHelper.add_element(airflow, 'FanSpeed', 'medium', :string) + XMLHelper.add_element(airflow, 'Efficiency', @efficiency, :float, @efficiency_isdefaulted) + end + XMLHelper.add_element(ceiling_fan, 'Count', @count, :integer, @count_isdefaulted) unless @count.nil? + XMLHelper.add_element(ceiling_fan, 'LabelEnergyUse', @label_energy_use, :float, @label_energy_use_isdefaulted) unless @label_energy_use.nil? + XMLHelper.add_extension(ceiling_fan, 'WeekdayScheduleFractions', @weekday_fractions, :string, @weekday_fractions_isdefaulted) unless @weekday_fractions.nil? + XMLHelper.add_extension(ceiling_fan, 'WeekendScheduleFractions', @weekend_fractions, :string, @weekend_fractions_isdefaulted) unless @weekend_fractions.nil? + XMLHelper.add_extension(ceiling_fan, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? + end + + # Populates the HPXML object(s) from the XML document. + # + # @param ceiling_fan [Oga::XML::Element] The current CeilingFan XML element + # @return [void] + def from_doc(ceiling_fan) + @id = HPXML::get_id(ceiling_fan) + @efficiency = XMLHelper.get_value(ceiling_fan, "Airflow[FanSpeed='medium']/Efficiency", :float) + @label_energy_use = XMLHelper.get_value(ceiling_fan, 'LabelEnergyUse', :float) + @count = XMLHelper.get_value(ceiling_fan, 'Count', :integer) + @weekday_fractions = XMLHelper.get_value(ceiling_fan, 'extension/WeekdayScheduleFractions', :string) + @weekend_fractions = XMLHelper.get_value(ceiling_fan, 'extension/WeekendScheduleFractions', :string) + @monthly_multipliers = XMLHelper.get_value(ceiling_fan, 'extension/MonthlyScheduleMultipliers', :string) + end + end + + # Object for /HPXML/Building/BuildingDetails/Lighting/extension. + class Lighting < BaseElement + ATTRS = [:interior_usage_multiplier, # [Double] InteriorUsageMultiplier + :garage_usage_multiplier, # [Double] GarageUsageMultiplier + :exterior_usage_multiplier, # [Double] ExteriorUsageMultiplier + :interior_weekday_fractions, # [String] InteriorWeekdayScheduleFractions + :interior_weekend_fractions, # [String] InteriorWeekendScheduleFractions + :interior_monthly_multipliers, # [String] InteriorMonthlyScheduleMultipliers + :garage_weekday_fractions, # [String] GarageWeekdayScheduleFractions + :garage_weekend_fractions, # [String] GarageWeekendScheduleFractions + :garage_monthly_multipliers, # [String] GarageMonthlyScheduleMultipliers + :exterior_weekday_fractions, # [String] ExteriorWeekdayScheduleFractions + :exterior_weekend_fractions, # [String] ExteriorWeekendScheduleFractions + :exterior_monthly_multipliers, # [String] ExteriorMonthlyScheduleMultipliers + :holiday_exists, # [Boolean] ExteriorHolidayLighting + :holiday_kwh_per_day, # [Double] ExteriorHolidayLighting/Load[Units="kWh/day"]/Value (kWh/day) + :holiday_period_begin_month, # [Integer] ExteriorHolidayLighting/PeriodBeginMonth + :holiday_period_begin_day, # [Integer] ExteriorHolidayLighting/PeriodBeginDayOfMonth + :holiday_period_end_month, # [Integer] ExteriorHolidayLighting/PeriodEndMonth + :holiday_period_end_day, # [Integer] ExteriorHolidayLighting/PeriodEndDayOfMonth + :holiday_weekday_fractions, # [String] ExteriorHolidayLighting/WeekdayScheduleFractions + :holiday_weekend_fractions] # [String] ExteriorHolidayLighting/WeekendScheduleFractions + attr_accessor(*ATTRS) + + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors + errors = [] + errors += HPXML::check_dates('Exterior Holiday Lighting', @holiday_period_begin_month, @holiday_period_begin_day, @holiday_period_end_month, @holiday_period_end_day) return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? lighting = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Lighting']) @@ -8028,7 +10252,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? lighting = XMLHelper.get_element(building, 'BuildingDetails/Lighting') @@ -8061,72 +10289,20 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO - class CeilingFans < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod - self << CeilingFan.new(@parent_object, **kwargs) - end - - def from_doc(building) # rubocop:disable Style/DocumentationMethod - return if building.nil? - - XMLHelper.get_elements(building, 'BuildingDetails/Lighting/CeilingFan').each do |ceiling_fan| - self << CeilingFan.new(@parent_object, ceiling_fan) - end - end - end - - # TODO - class CeilingFan < BaseElement - ATTRS = [:id, :efficiency, :label_energy_use, :count, :weekday_fractions, :weekend_fractions, :monthly_multipliers] - attr_accessor(*ATTRS) - - def delete # rubocop:disable Style/DocumentationMethod - @parent_object.ceiling_fans.delete(self) - end - - def check_for_errors # rubocop:disable Style/DocumentationMethod - errors = [] - return errors - end - - def to_doc(building) # rubocop:disable Style/DocumentationMethod - return if nil? - - lighting = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Lighting']) - ceiling_fan = XMLHelper.add_element(lighting, 'CeilingFan') - sys_id = XMLHelper.add_element(ceiling_fan, 'SystemIdentifier') - XMLHelper.add_attribute(sys_id, 'id', @id) - if not @efficiency.nil? - airflow = XMLHelper.add_element(ceiling_fan, 'Airflow') - XMLHelper.add_element(airflow, 'FanSpeed', 'medium', :string) - XMLHelper.add_element(airflow, 'Efficiency', @efficiency, :float, @efficiency_isdefaulted) - end - XMLHelper.add_element(ceiling_fan, 'Count', @count, :integer, @count_isdefaulted) unless @count.nil? - XMLHelper.add_element(ceiling_fan, 'LabelEnergyUse', @label_energy_use, :float, @label_energy_use_isdefaulted) unless @label_energy_use.nil? - XMLHelper.add_extension(ceiling_fan, 'WeekdayScheduleFractions', @weekday_fractions, :string, @weekday_fractions_isdefaulted) unless @weekday_fractions.nil? - XMLHelper.add_extension(ceiling_fan, 'WeekendScheduleFractions', @weekend_fractions, :string, @weekend_fractions_isdefaulted) unless @weekend_fractions.nil? - XMLHelper.add_extension(ceiling_fan, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? - end - - def from_doc(ceiling_fan) # rubocop:disable Style/DocumentationMethod - @id = HPXML::get_id(ceiling_fan) - @efficiency = XMLHelper.get_value(ceiling_fan, "Airflow[FanSpeed='medium']/Efficiency", :float) - @label_energy_use = XMLHelper.get_value(ceiling_fan, 'LabelEnergyUse', :float) - @count = XMLHelper.get_value(ceiling_fan, 'Count', :integer) - @weekday_fractions = XMLHelper.get_value(ceiling_fan, 'extension/WeekdayScheduleFractions', :string) - @weekend_fractions = XMLHelper.get_value(ceiling_fan, 'extension/WeekendScheduleFractions', :string) - @monthly_multipliers = XMLHelper.get_value(ceiling_fan, 'extension/MonthlyScheduleMultipliers', :string) - end - end - - # TODO + # Array of HPXML::Pool objects. class Pools < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << Pool.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Pools/Pool').each do |pool| @@ -8135,24 +10311,47 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Pools/Pool. class Pool < BaseElement - ATTRS = [:id, :type, :heater_id, :heater_type, :heater_load_units, :heater_load_value, :heater_usage_multiplier, - :pump_id, :pump_type, :pump_kwh_per_year, :pump_usage_multiplier, - :heater_weekday_fractions, :heater_weekend_fractions, :heater_monthly_multipliers, - :pump_weekday_fractions, :pump_weekend_fractions, :pump_monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :type, # [String] Type + :pump_id, # [String] Pumps/Pump/SystemIdentifier/@id + :pump_type, # [String] Pumps/Pump/Type + :pump_kwh_per_year, # [Double] Pumps/Pump/Load[Units="kWh/year"]/Value (kWh/yr) + :pump_usage_multiplier, # [Double] Pumps/Pump/UsageMultiplier + :pump_weekday_fractions, # [String] Pumps/Pump/WeekdayScheduleFractions + :pump_weekend_fractions, # [String] Pumps/Pump/WeekendScheduleFractions + :pump_monthly_multipliers, # [String] Pumps/Pump/MonthlyScheduleMultipliers + :heater_id, # [String] Heater/SystemIdentifier/@id + :heater_type, # [String] Heater/Type (HPXML::HeaterTypeXXX) + :heater_load_units, # [String] Heater/Load/Units (HPXML::UnitsXXX) + :heater_load_value, # [Double] Heater/Load/Value + :heater_usage_multiplier, # [Double] Heater/UsageMultiplier + :heater_weekday_fractions, # [String] Heater/WeekdayScheduleFractions + :heater_weekend_fractions, # [String] Heater/WeekendScheduleFractions + :heater_monthly_multipliers] # [String] Heater/MonthlyScheduleMultipliers attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.pools.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? pools = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Pools']) @@ -8203,7 +10402,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(pool) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param pool [Oga::XML::Element] The current Pool XML element + # @return [void] + def from_doc(pool) @id = HPXML::get_id(pool) @type = XMLHelper.get_value(pool, 'Type', :string) pool_pump = XMLHelper.get_element(pool, 'Pumps/Pump') @@ -8230,13 +10433,20 @@ def from_doc(pool) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::PermanentSpa objects. class PermanentSpas < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << PermanentSpa.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Spas/PermanentSpa').each do |spa| @@ -8245,24 +10455,47 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Spas/PermanentSpa. class PermanentSpa < BaseElement - ATTRS = [:id, :type, :heater_id, :heater_type, :heater_load_units, :heater_load_value, :heater_usage_multiplier, - :pump_id, :pump_type, :pump_kwh_per_year, :pump_usage_multiplier, - :heater_weekday_fractions, :heater_weekend_fractions, :heater_monthly_multipliers, - :pump_weekday_fractions, :pump_weekend_fractions, :pump_monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :type, # [String] Type + :pump_id, # [String] Pumps/Pump/SystemIdentifier/@id + :pump_type, # [String] Pumps/Pump/Type + :pump_kwh_per_year, # [Double] Pumps/Pump/Load[Units="kWh/year"]/Value (kWh/yr) + :pump_usage_multiplier, # [Double] Pumps/Pump/UsageMultiplier + :pump_weekday_fractions, # [String] Pumps/Pump/WeekdayScheduleFractions + :pump_weekend_fractions, # [String] Pumps/Pump/WeekendScheduleFractions + :pump_monthly_multipliers, # [String] Pumps/Pump/MonthlyScheduleMultipliers + :heater_id, # [String] Heater/SystemIdentifier/@id + :heater_type, # [String] Heater/Type (HPXML::HeaterTypeXXX) + :heater_load_units, # [String] Heater/Load/Units (HPXML::UnitsXXX) + :heater_load_value, # [Double] Heater/Load/Value + :heater_usage_multiplier, # [Double] Heater/UsageMultiplier + :heater_weekday_fractions, # [String] Heater/WeekdayScheduleFractions + :heater_weekend_fractions, # [String] Heater/WeekendScheduleFractions + :heater_monthly_multipliers] # [String] Heater/MonthlyScheduleMultipliers attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.permanent_spas.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? spas = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Spas']) @@ -8313,7 +10546,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod end end - def from_doc(spa) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param spa [Oga::XML::Element] The current Spa XML element + # @return [void] + def from_doc(spa) @id = HPXML::get_id(spa) @type = XMLHelper.get_value(spa, 'Type', :string) spa_pump = XMLHelper.get_element(spa, 'Pumps/Pump') @@ -8340,13 +10577,20 @@ def from_doc(spa) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::PortableSpa objects. class PortableSpas < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << PortableSpa.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/Spas/PortableSpa').each do |spa| @@ -8355,21 +10599,31 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Spas/PortableSpa. class PortableSpa < BaseElement - ATTRS = [:id] + ATTRS = [:id] # [String] SystemIdentifier/@id attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.portable_spas.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? spas = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'Spas']) @@ -8378,18 +10632,29 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_attribute(sys_id, 'id', @id) end - def from_doc(spa) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param spa [Oga::XML::Element] The current Spa XML element + # @return [void] + def from_doc(spa) @id = HPXML::get_id(spa) end end - # TODO + # Array of HPXML::PlugLoad objects. class PlugLoads < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << PlugLoad.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/MiscLoads/PlugLoad').each do |plug_load| @@ -8398,22 +10663,39 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/MiscLoads/PlugLoad. class PlugLoad < BaseElement - ATTRS = [:id, :plug_load_type, :kwh_per_year, :frac_sensible, :frac_latent, :usage_multiplier, - :weekday_fractions, :weekend_fractions, :monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :plug_load_type, # [String] PlugLoadType (HPXML::PlugLoadTypeXXX) + :kwh_per_year, # [Double] Load[Units="kWh/year"]/Value (kWh/yr) + :frac_sensible, # [Double] FracSensible (frac) + :frac_latent, # [Double] FracLatent (frac) + :usage_multiplier, # [Double] UsageMultiplier + :weekday_fractions, # [String] WeekdayScheduleFractions + :weekend_fractions, # [String] WeekendScheduleFractions + :monthly_multipliers] # [String] MonthlyScheduleMultipliers attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.plug_loads.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? misc_loads = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'MiscLoads']) @@ -8434,7 +10716,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(plug_load, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? end - def from_doc(plug_load) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param plug_load [Oga::XML::Element] The current PlugLoad XML element + # @return [void] + def from_doc(plug_load) @id = HPXML::get_id(plug_load) @plug_load_type = XMLHelper.get_value(plug_load, 'PlugLoadType', :string) @kwh_per_year = XMLHelper.get_value(plug_load, "Load[Units='#{UnitsKwhPerYear}']/Value", :float) @@ -8447,13 +10733,20 @@ def from_doc(plug_load) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::FuelLoad objects. class FuelLoads < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << FuelLoad.new(@parent_object, **kwargs) end - def from_doc(building) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def from_doc(building) return if building.nil? XMLHelper.get_elements(building, 'BuildingDetails/MiscLoads/FuelLoad').each do |fuel_load| @@ -8462,22 +10755,40 @@ def from_doc(building) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/MiscLoads/FuelLoad. class FuelLoad < BaseElement - ATTRS = [:id, :fuel_load_type, :fuel_type, :therm_per_year, :frac_sensible, :frac_latent, :usage_multiplier, - :weekday_fractions, :weekend_fractions, :monthly_multipliers] + ATTRS = [:id, # [String] SystemIdentifier/@id + :fuel_load_type, # [String] FuelLoadType (HPXML::FuelLoadTypeXXX) + :therm_per_year, # [Double] Load[Units="therm/year"]/Value (therm/yr) + :fuel_type, # [String] FuelType (HPXML::FuelTypeXXX) + :frac_sensible, # [Double] FracSensible (frac) + :frac_latent, # [Double] FracLatent (frac) + :usage_multiplier, # [Double] UsageMultiplier + :weekday_fractions, # [String] WeekdayScheduleFractions + :weekend_fractions, # [String] WeekendScheduleFractions + :monthly_multipliers] # [String] MonthlyScheduleMultipliers attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete @parent_object.fuel_loads.delete(self) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(building) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param building [Oga::XML::Element] The current Building XML element + # @return [void] + def to_doc(building) return if nil? misc_loads = XMLHelper.create_elements_as_needed(building, ['BuildingDetails', 'MiscLoads']) @@ -8499,7 +10810,11 @@ def to_doc(building) # rubocop:disable Style/DocumentationMethod XMLHelper.add_extension(fuel_load, 'MonthlyScheduleMultipliers', @monthly_multipliers, :string, @monthly_multipliers_isdefaulted) unless @monthly_multipliers.nil? end - def from_doc(fuel_load) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param fuel_load [Oga::XML::Element] The current FuelLoad XML element + # @return [void] + def from_doc(fuel_load) @id = HPXML::get_id(fuel_load) @fuel_load_type = XMLHelper.get_value(fuel_load, 'FuelLoadType', :string) @therm_per_year = XMLHelper.get_value(fuel_load, "Load[Units='#{UnitsThermPerYear}']/Value", :float) @@ -8513,13 +10828,19 @@ def from_doc(fuel_load) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::CoolingPerformanceDataPoint objects. class CoolingDetailedPerformanceData < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << CoolingPerformanceDataPoint.new(@parent_object, **kwargs) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] # For every unique outdoor temperature, check we have exactly one minimum and one maximum datapoint outdoor_temps = self.select { |dp| [HPXML::CapacityDescriptionMinimum, HPXML::CapacityDescriptionMaximum].include? dp.capacity_description }.map { |dp| dp.outdoor_temperature }.uniq @@ -8533,7 +10854,11 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def from_doc(hvac_system) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hvac_system [Oga::XML::Element] The current HVAC system XML element + # @return [void] + def from_doc(hvac_system) return if hvac_system.nil? XMLHelper.get_elements(hvac_system, 'CoolingDetailedPerformanceData/PerformanceDataPoint').each do |performance_data_point| @@ -8542,24 +10867,42 @@ def from_doc(hvac_system) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACPlant/*/CoolingDetailedPerformanceData/PerformanceDataPoint. class CoolingPerformanceDataPoint < BaseElement - ATTRS = [:outdoor_temperature, :indoor_temperature, :indoor_wetbulb, :capacity, :capacity_fraction_of_nominal, - :capacity_description, :efficiency_cop, :gross_capacity, :gross_efficiency_cop, :isdefaulted] + ATTRS = [:isdefaulted, # [Boolean] @dataSource="software" + :outdoor_temperature, # [Double] OutdoorTemperature (F) + :indoor_temperature, # [Double] IndoorTemperature (F) + :indoor_wetbulb, # [Double] IndoorWetbulbTemperature (F) + :capacity, # [Double] Capacity (Btu/hr) + :capacity_fraction_of_nominal, # [Double] CapacityFractionOfNominal (frac) + :capacity_description, # [String] CapacityDescription (HPXML::CapacityDescriptionXXX) + :efficiency_cop, # [Double] Efficiency[Units="COP"]/Value (W/W) + :gross_capacity, # FUTURE: Not in HPXML schema, should move to additional_properties + :gross_efficiency_cop] # FUTURE: Not in HPXML schema, should move to additional_properties attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete (@parent_object.cooling_systems + @parent_object.heat_pumps).each do |cooling_system| cooling_system.cooling_detailed_performance_data.delete(self) end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(hvac_system) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param hvac_system [Oga::XML::Element] Parent XML element + # @return [void] + def to_doc(hvac_system) detailed_performance_data = XMLHelper.create_elements_as_needed(hvac_system, ['CoolingDetailedPerformanceData']) performance_data_point = XMLHelper.add_element(detailed_performance_data, 'PerformanceDataPoint') XMLHelper.add_attribute(performance_data_point, 'dataSource', 'software') if @isdefaulted @@ -8576,7 +10919,11 @@ def to_doc(hvac_system) # rubocop:disable Style/DocumentationMethod end end - def from_doc(performance_data_point) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param performance_data_point [Oga::XML::Element] The current CoolingPerformanceDataPoint XML element + # @return [void] + def from_doc(performance_data_point) return if performance_data_point.nil? @outdoor_temperature = XMLHelper.get_value(performance_data_point, 'OutdoorTemperature', :float) @@ -8589,13 +10936,19 @@ def from_doc(performance_data_point) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Array of HPXML::HeatingPerformanceDataPoint objects. class HeatingDetailedPerformanceData < BaseArrayElement - def add(**kwargs) # rubocop:disable Style/DocumentationMethod + # Adds a new object, with the specified keyword arguments, to the array. + # + # @return [void] + def add(**kwargs) self << HeatingPerformanceDataPoint.new(@parent_object, **kwargs) end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] # For every unique outdoor temperature, check we have exactly one minimum and one maximum datapoint outdoor_temps = self.select { |dp| [HPXML::CapacityDescriptionMinimum, HPXML::CapacityDescriptionMaximum].include? dp.capacity_description }.map { |dp| dp.outdoor_temperature }.uniq @@ -8609,7 +10962,11 @@ def check_for_errors # rubocop:disable Style/DocumentationMethod return errors end - def from_doc(hvac_system) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param hvac_system [Oga::XML::Element] The current HVAC system XML element + # @return [void] + def from_doc(hvac_system) return if hvac_system.nil? XMLHelper.get_elements(hvac_system, 'HeatingDetailedPerformanceData/PerformanceDataPoint').each do |performance_data_point| @@ -8618,25 +10975,41 @@ def from_doc(hvac_system) # rubocop:disable Style/DocumentationMethod end end - # TODO + # Object for /HPXML/Building/BuildingDetails/Systems/HVAC/HVACPlant/*/HeatingDetailedPerformanceData/PerformanceDataPoint. class HeatingPerformanceDataPoint < BaseElement - ATTRS = [:outdoor_temperature, :indoor_temperature, :capacity, :capacity_fraction_of_nominal, - :capacity_description, :efficiency_cop, :gross_capacity, :gross_efficiency_cop, - :isdefaulted] + ATTRS = [:isdefaulted, # [Boolean] @dataSource="software" + :outdoor_temperature, # [Double] OutdoorTemperature (F) + :indoor_temperature, # [Double] IndoorTemperature (F) + :capacity, # [Double] Capacity (Btu/hr) + :capacity_fraction_of_nominal, # [Double] CapacityFractionOfNominal (frac) + :capacity_description, # [String] CapacityDescription (HPXML::CapacityDescriptionXXX) + :efficiency_cop, # [Double] Efficiency[Units="COP"]/Value (W/W) + :gross_capacity, # FUTURE: Not in HPXML schema, should move to additional_properties + :gross_efficiency_cop] # FUTURE: Not in HPXML schema, should move to additional_properties attr_accessor(*ATTRS) - def delete # rubocop:disable Style/DocumentationMethod + # Deletes the current object from the array. + # + # @return [void] + def delete (@parent_object.heating_systems + @parent_object.heat_pumps).each do |heating_system| heating_system.cooling_detailed_performance_data.delete(self) end end - def check_for_errors # rubocop:disable Style/DocumentationMethod + # Additional error-checking beyond what's checked in Schema/Schematron validators. + # + # @return [Array] List of error messages + def check_for_errors errors = [] return errors end - def to_doc(hvac_system) # rubocop:disable Style/DocumentationMethod + # Adds this object to the provided Oga XML element. + # + # @param hvac_system [Oga::XML::Element] Parent XML element + # @return [void] + def to_doc(hvac_system) detailed_performance_data = XMLHelper.create_elements_as_needed(hvac_system, ['HeatingDetailedPerformanceData']) performance_data_point = XMLHelper.add_element(detailed_performance_data, 'PerformanceDataPoint') XMLHelper.add_attribute(performance_data_point, 'dataSource', 'software') if @isdefaulted @@ -8652,7 +11025,11 @@ def to_doc(hvac_system) # rubocop:disable Style/DocumentationMethod end end - def from_doc(performance_data_point) # rubocop:disable Style/DocumentationMethod + # Populates the HPXML object(s) from the XML document. + # + # @param performance_data_point [Oga::XML::Element] The current HeatingPerformanceDataPoint XML element + # @return [void] + def from_doc(performance_data_point) return if performance_data_point.nil? @outdoor_temperature = XMLHelper.get_value(performance_data_point, 'OutdoorTemperature', :float) @@ -8664,8 +11041,10 @@ def from_doc(performance_data_point) # rubocop:disable Style/DocumentationMethod end end - # TODO - def _create_hpxml_document() + # Returns a new, empty HPXML document + # + # @return [Oga::XML::Document] The HPXML document + def _create_hpxml_document doc = XMLHelper.create_doc('1.0', 'UTF-8') hpxml = XMLHelper.add_element(doc, 'HPXML') XMLHelper.add_attribute(hpxml, 'xmlns', NameSpace) @@ -8673,10 +11052,10 @@ def _create_hpxml_document() return doc end - # The unique set of HPXML fuel types that end up used in the EnergyPlus model. + # The unique set of HPXML fossil fuel types that end up used in the EnergyPlus model. # Some other fuel types (e.g., FuelTypeCoalAnthracite) are collapsed into this list. # - # @return [Array] List of HPXML::FuelTypeXXXs + # @return [Array] List of fuel types (HPXML::FuelTypeXXX) def self.fossil_fuels return [HPXML::FuelTypeNaturalGas, HPXML::FuelTypePropane, @@ -8686,18 +11065,25 @@ def self.fossil_fuels HPXML::FuelTypeWoodPellets] end - # TODO + # The unique set of all HPXML fuel types that end up used in the EnergyPlus model. + # Some other fuel types (e.g., FuelTypeCoalAnthracite) are collapsed into this list. + # + # @return [Array] List of fuel types (HPXML::FuelTypeXXX) def self.all_fuels return [HPXML::FuelTypeElectricity] + fossil_fuels end - # TODO + # Returns the set of all location types that are vented. + # + # @return [Array] List of vented locations (HPXML::LocationXXX) def self.vented_locations return [HPXML::LocationAtticVented, HPXML::LocationCrawlspaceVented] end - # TODO + # Returns the set of all location types that are conditioned. + # + # @return [Array] List of conditioned locations (HPXML::LocationXXX) def self.conditioned_locations return [HPXML::LocationConditionedSpace, HPXML::LocationBasementConditioned, @@ -8705,77 +11091,89 @@ def self.conditioned_locations HPXML::LocationOtherHousingUnit] end - # TODO + # Returns the set of all location types that are multifamily common spaces. + # + # @return [Array] List of multifamily common space locations (HPXML::LocationXXX) def self.multifamily_common_space_locations return [HPXML::LocationOtherHeatedSpace, HPXML::LocationOtherMultifamilyBufferSpace, HPXML::LocationOtherNonFreezingSpace] end - # TODO + # Returns the set of all location types that are conditioned and part of the + # dwelling unit. + # + # @return [Array] List of conditioned locations (HPXML::LocationXXX) def self.conditioned_locations_this_unit return [HPXML::LocationConditionedSpace, HPXML::LocationBasementConditioned, HPXML::LocationCrawlspaceConditioned] end - # TODO + # Returns the set of all location types that are conditioned and assumed to + # be finished (e.g., have interior finishes like drywall). + # + # @return [Array] List of conditioned, finished locations (HPXML::LocationXXX) def self.conditioned_finished_locations return [HPXML::LocationConditionedSpace, HPXML::LocationBasementConditioned] end - # TODO + # Returns the set of all location types that are conditioned and above-grade. + # + # @return [Array] List of conditioned, above-grade locations (HPXML::LocationXXX) def self.conditioned_below_grade_locations return [HPXML::LocationBasementConditioned, HPXML::LocationCrawlspaceConditioned] end - # TODO + # Returns whether the surface is adjacent to conditioned space. + # + # @param surface [HPXML::XXX] HPXML surface of interest + # @return [Boolean] True if adjacent to conditioned space def self.is_conditioned(surface) return conditioned_locations.include?(surface.interior_adjacent_to) end - # TODO - def self.is_exposed(surface) - if HPXML::is_conditioned(surface) && - (surface.exterior_adjacent_to == LocationOutside || - surface.exterior_adjacent_to == LocationOtherNonFreezingSpace) - return true - end - - return false - end - - # TODO + # Returns whether the surface is determined to be adiabatic. + # + # @param surface [HPXML::XXX] HPXML surface of interest + # @return [Boolean] True if adiabatic def self.is_adiabatic(surface) if surface.exterior_adjacent_to == surface.interior_adjacent_to # E.g., wall between unit crawlspace and neighboring unit crawlspace return true elsif conditioned_locations.include?(surface.interior_adjacent_to) && conditioned_locations.include?(surface.exterior_adjacent_to) - # E.g., floor between conditioned space and conditioned basement, or - # wall between conditioned space and "other housing unit" + # E.g., wall with conditioned space on both sides return true end return false end - # Returns true if the surface is between conditioned space and outside/ground/unconditioned space. + # Returns whether the surface is between conditioned space and outside/ground/unconditioned space. # Note: The location of insulation is not considered here, so an insulated foundation wall of an # unconditioned basement, for example, returns false. # # @param surface [OpenStudio::Model::Surface] the surface of interest - # @return [Boolean] true if a thermal boundary surface + # @return [Boolean] True if a thermal boundary surface def self.is_thermal_boundary(surface) interior_conditioned = conditioned_locations.include? surface.interior_adjacent_to exterior_conditioned = conditioned_locations.include? surface.exterior_adjacent_to return (interior_conditioned != exterior_conditioned) end - # TODO - def self.is_floor_a_ceiling(surface, force_decision) + # Returns whether the HPXML::Floor object represents a ceiling or floor + # from the perspective of the conditioned space. + # + # For example, the surface above an unconditioned basement is a floor. + # The surface below an attic is a ceiling. + # + # @param hpxml_floor [HPXML::Floor] HPXML floor surface + # @param force_decision [Boolean] If false, can return nil if not explicitly known + # @return [Boolean or nil] True if the surface is a ceiling + def self.is_floor_a_ceiling(hpxml_floor, force_decision) ceiling_locations = [LocationAtticUnconditioned, LocationAtticVented, LocationAtticUnvented] @@ -8785,9 +11183,9 @@ def self.is_floor_a_ceiling(surface, force_decision) LocationBasementConditioned, LocationBasementUnconditioned, LocationManufacturedHomeUnderBelly] - if (ceiling_locations.include? surface.interior_adjacent_to) || (ceiling_locations.include? surface.exterior_adjacent_to) + if (ceiling_locations.include? hpxml_floor.interior_adjacent_to) || (ceiling_locations.include? hpxml_floor.exterior_adjacent_to) return true - elsif (floor_locations.include? surface.interior_adjacent_to) || (floor_locations.include? surface.exterior_adjacent_to) + elsif (floor_locations.include? hpxml_floor.interior_adjacent_to) || (floor_locations.include? hpxml_floor.exterior_adjacent_to) return false elsif force_decision # If we don't explicitly know, assume a floor @@ -8795,18 +11193,32 @@ def self.is_floor_a_ceiling(surface, force_decision) end end - # TODO + # Gets the ID attribute for the given element. + # + # @param parent [Oga::XML::Element] The parent HPXML element + # @param element_name [String] The name of the child element with the ID attribute + # @return [String] The element ID attribute def self.get_id(parent, element_name = 'SystemIdentifier') return XMLHelper.get_attribute_value(XMLHelper.get_element(parent, element_name), 'id') end - # TODO + # Gets the IDREF attribute for the given element. + # + # @param element [Oga::XML::Element] The HPXML element + # @return [String] The element IDREF attribute def self.get_idref(element) return XMLHelper.get_attribute_value(element, 'idref') end - # TODO - def self.check_dates(str, begin_month, begin_day, end_month, end_day) + # Checks whether a given date is valid (e.g., Sep 31 is invalid). + # + # @param use_case [String] Name of the use case to include in the error message + # @param begin_month [Integer] Date begin month + # @param begin_day [Integer] Date begin day + # @param end_month [Integer] Date end month + # @param end_day [Integer] Date end day + # @return [Array] List of error messages + def self.check_dates(use_case, begin_month, begin_day, end_month, end_day) errors = [] # Check for valid months @@ -8814,13 +11226,13 @@ def self.check_dates(str, begin_month, begin_day, end_month, end_day) if not begin_month.nil? if not valid_months.include? begin_month - errors << "#{str} Begin Month (#{begin_month}) must be one of: #{valid_months.join(', ')}." + errors << "#{use_case} Begin Month (#{begin_month}) must be one of: #{valid_months.join(', ')}." end end if not end_month.nil? if not valid_months.include? end_month - errors << "#{str} End Month (#{end_month}) must be one of: #{valid_months.join(', ')}." + errors << "#{use_case} End Month (#{end_month}) must be one of: #{valid_months.join(', ')}." end end @@ -8829,20 +11241,24 @@ def self.check_dates(str, begin_month, begin_day, end_month, end_day) months_days.each do |months, valid_days| if (not begin_day.nil?) && (months.include? begin_month) if not valid_days.include? begin_day - errors << "#{str} Begin Day of Month (#{begin_day}) must be one of: #{valid_days.join(', ')}." + errors << "#{use_case} Begin Day of Month (#{begin_day}) must be one of: #{valid_days.join(', ')}." end end next unless (not end_day.nil?) && (months.include? end_month) if not valid_days.include? end_day - errors << "#{str} End Day of Month (#{end_day}) must be one of: #{valid_days.join(', ')}." + errors << "#{use_case} End Day of Month (#{end_day}) must be one of: #{valid_days.join(', ')}." end end return errors end - # TODO + # Adds this object's design loads to the provided Oga XML element. + # + # @param hpxml_object [HPXML::XXX] The Zone/Space/HVACPlant object + # @param hpxml_element [Oga::XML::Element] The Zone/Space/HVACPlant XML element + # @return [void] def self.design_loads_to_doc(hpxml_object, hpxml_element) { HDL_ATTRS => 'Heating', CDL_SENS_ATTRS => 'CoolingSensible', @@ -8862,7 +11278,11 @@ def self.design_loads_to_doc(hpxml_object, hpxml_element) end end - # TODO + # Populates the HPXML object's design loads from the XML element. + # + # @param hpxml_object [HPXML::XXX] The Zone/Space/HVACPlant object + # @param hpxml_element [Oga::XML::Element] The Zone/Space/HVACPlant XML element + # @return [void] def self.design_loads_from_doc(hpxml_object, hpxml_element) { HDL_ATTRS => 'Heating', CDL_SENS_ATTRS => 'CoolingSensible', diff --git a/HPXMLtoOpenStudio/resources/hpxml_defaults.rb b/HPXMLtoOpenStudio/resources/hpxml_defaults.rb index d748231411..ce54c4b729 100644 --- a/HPXMLtoOpenStudio/resources/hpxml_defaults.rb +++ b/HPXMLtoOpenStudio/resources/hpxml_defaults.rb @@ -17,7 +17,7 @@ module HPXMLDefaults # attributes for all defaulted values. This allows the user to easily observe which # values were defaulted and what default values were used. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml [HPXML] HPXML object # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions @@ -233,7 +233,7 @@ def self.apply_header(hpxml_header, hpxml_bldg, weather) # Assigns default values for omitted optional inputs in the HPXML::BuildingHeader object # specific to HVAC equipment sizing # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param weather [WeatherFile] Weather object containing EPW information # @param nbeds [Integer] Number of bedrooms in the dwelling unit @@ -480,7 +480,7 @@ def self.apply_emissions_scenarios(hpxml_header, has_fuel) # Assigns default values for omitted optional inputs in the HPXML::UtilityBillScenarios objects # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file) # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param has_fuel [Hash] Map of HPXML fuel type => boolean of whether fuel type is used @@ -1326,7 +1326,7 @@ def self.apply_foundation_walls(hpxml_bldg) # Assigns default values for omitted optional inputs in the HPXML::Floor objects # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @return [void] def self.apply_floors(runner, hpxml_bldg) @@ -1640,7 +1640,7 @@ def self.apply_furniture_mass(hpxml_bldg) # Assigns default values for omitted optional inputs in the HPXML::HeatingSystem, # HPXML::CoolingSystem, and HPXML::HeatPump objects # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml [HPXML] HPXML object # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param weather [WeatherFile] Weather object containing EPW information @@ -2536,13 +2536,13 @@ def self.apply_ventilation_fans(hpxml_bldg, weather, cfa, nbeds, eri_version) vent_fan.is_shared_system_isdefaulted = true end - if vent_fan.hours_in_operation.nil? && !vent_fan.is_cfis_supplemental_fan? + if vent_fan.hours_in_operation.nil? && !vent_fan.is_cfis_supplemental_fan vent_fan.hours_in_operation = (vent_fan.fan_type == HPXML::MechVentTypeCFIS) ? 8.0 : 24.0 vent_fan.hours_in_operation_isdefaulted = true end if vent_fan.flow_rate.nil? - if hpxml_bldg.ventilation_fans.select { |vf| vf.used_for_whole_building_ventilation && !vf.is_cfis_supplemental_fan? }.size > 1 + if hpxml_bldg.ventilation_fans.select { |vf| vf.used_for_whole_building_ventilation && !vf.is_cfis_supplemental_fan }.size > 1 fail 'Defaulting flow rates for multiple mechanical ventilation systems is currently not supported.' end @@ -2745,9 +2745,9 @@ def self.apply_hot_water_distribution(hpxml_bldg, cfa, ncfl, schedules_file) hot_water_distribution.standard_piping_length_isdefaulted = true end elsif hot_water_distribution.system_type == HPXML::DHWDistTypeRecirc - if hot_water_distribution.recirculation_piping_length.nil? - hot_water_distribution.recirculation_piping_length = HotWaterAndAppliances.get_default_recirc_loop_length(HotWaterAndAppliances.get_default_std_pipe_length(has_uncond_bsmnt, has_cond_bsmnt, cfa, ncfl)) - hot_water_distribution.recirculation_piping_length_isdefaulted = true + if hot_water_distribution.recirculation_piping_loop_length.nil? + hot_water_distribution.recirculation_piping_loop_length = HotWaterAndAppliances.get_default_recirc_loop_length(HotWaterAndAppliances.get_default_std_pipe_length(has_uncond_bsmnt, has_cond_bsmnt, cfa, ncfl)) + hot_water_distribution.recirculation_piping_loop_length_isdefaulted = true end if hot_water_distribution.recirculation_branch_piping_length.nil? hot_water_distribution.recirculation_branch_piping_length = HotWaterAndAppliances.get_default_recirc_branch_loop_length() @@ -3765,7 +3765,7 @@ def self.apply_fuel_loads(hpxml_bldg, cfa, schedules_file) # Assigns default capacities/airflows for autosized HPXML HVAC equipment. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param weather [WeatherFile] Weather object containing EPW information # @param output_format [String] Detailed output file format ('csv', 'json', or 'msgpack') diff --git a/HPXMLtoOpenStudio/resources/hvac.rb b/HPXMLtoOpenStudio/resources/hvac.rb index a82fbbdf86..3632cdd66c 100644 --- a/HPXMLtoOpenStudio/resources/hvac.rb +++ b/HPXMLtoOpenStudio/resources/hvac.rb @@ -11,7 +11,7 @@ module HVAC # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param cooling_system [TODO] TODO # @param heating_system [TODO] TODO # @param sequential_cool_load_fracs [TODO] TODO @@ -323,7 +323,7 @@ def self.apply_evaporative_cooler(model, cooling_system, sequential_cool_load_fr # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param weather [WeatherFile] Weather object containing EPW information # @param heat_pump [TODO] TODO # @param sequential_heat_load_fracs [TODO] TODO @@ -588,7 +588,7 @@ def self.apply_water_loop_to_air_heat_pump(model, heat_pump, # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param heating_system [TODO] TODO # @param sequential_heat_load_fracs [TODO] TODO # @param control_zone [OpenStudio::Model::ThermalZone] Conditioned space thermal zone @@ -891,11 +891,11 @@ def self.apply_ideal_air_loads(model, sequential_cool_load_fracs, # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param dehumidifiers [TODO] TODO # @param conditioned_space [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @return [TODO] TODO def self.apply_dehumidifiers(runner, model, dehumidifiers, conditioned_space, unavailable_periods, unit_multiplier) @@ -979,12 +979,12 @@ def self.apply_dehumidifiers(runner, model, dehumidifiers, conditioned_space, un # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param weather [WeatherFile] Weather object containing EPW information # @param ceiling_fan [TODO] TODO # @param conditioned_space [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_ceiling_fans(model, runner, weather, ceiling_fan, conditioned_space, schedules_file, unavailable_periods) @@ -1039,7 +1039,7 @@ def self.apply_ceiling_fans(model, runner, weather, ceiling_fan, conditioned_spa # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param weather [WeatherFile] Weather object containing EPW information # @param hvac_control [TODO] TODO # @param conditioned_zone [TODO] TODO @@ -1100,7 +1100,7 @@ def self.apply_setpoints(model, runner, weather, hvac_control, conditioned_zone, # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param heating_days [TODO] TODO # @param cooling_days [TODO] TODO # @param htg_weekday_setpoints [TODO] TODO @@ -2179,7 +2179,7 @@ def self.adjust_dehumidifier_load_EMS(fraction_served, zone_hvac, model, conditi # @param obj_name [String] Name for the OpenStudio object # @param heat_pump [TODO] TODO # @param hpxml_header [HPXML::Header] HPXML Header object (one per HPXML file) - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @return [TODO] TODO def self.create_supp_heating_coil(model, obj_name, heat_pump, hpxml_header = nil, runner = nil, hpxml_bldg = nil) @@ -3745,7 +3745,7 @@ def self.apply_two_speed_realistic_staging_EMS(model, unitary_system, htg_supp_c # Creates EMS program to determine and control the stage that can reach the maximum power constraint. # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @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 @@ -4316,7 +4316,7 @@ def self.calc_sequential_load_fractions(load_fraction, remaining_fraction, avail # # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param fractions [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.get_sequential_load_schedule(model, fractions, unavailable_periods) if fractions.nil? @@ -4396,7 +4396,7 @@ def self.set_sequential_load_fractions(model, control_zone, hvac_object, sequent # TODO # # @param heat_pump [TODO] TODO - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def self.set_heat_pump_temperatures(heat_pump, runner = nil) hp_ap = heat_pump.additional_properties diff --git a/HPXMLtoOpenStudio/resources/hvac_sizing.rb b/HPXMLtoOpenStudio/resources/hvac_sizing.rb index 1f570fe232..7e8e10962b 100644 --- a/HPXMLtoOpenStudio/resources/hvac_sizing.rb +++ b/HPXMLtoOpenStudio/resources/hvac_sizing.rb @@ -6,7 +6,7 @@ module HVACSizing # values (e.g., capacities, airflows) specific to each HVAC system. # Calculations follow ACCA Manual J (and S). # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param weather [WeatherFile] Weather object containing EPW information # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param hvac_systems [Array] List of HPXML HVAC (heating and/or cooling) systems @@ -335,7 +335,7 @@ def self.determine_daily_temperature_range_class(daily_temperature_range) # # @param mj [MJValues] Object with a collection of misc Manual J values # @param weather [WeatherFile] Weather object containing EPW information - # @param location [String] The HPXML::LocationXXX of interest + # @param location [String] The location of interest (HPXML::LocationXXX) # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @return [Double] Heating design temperature (F) def self.get_design_temp_heating(mj, weather, location, hpxml_bldg) @@ -395,7 +395,7 @@ def self.get_design_temp_heating(mj, weather, location, hpxml_bldg) # # @param mj [MJValues] Object with a collection of misc Manual J values # @param weather [WeatherFile] Weather object containing EPW information - # @param location [String] The HPXML::LocationXXX of interest + # @param location [String] The location of interest (HPXML::LocationXXX) # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @return [Double] Cooling design temperature (F) def self.get_design_temp_cooling(mj, weather, location, hpxml_bldg) @@ -542,7 +542,7 @@ def self.get_design_temp_cooling(mj, weather, location, hpxml_bldg) # Estimates the fraction of garage under conditioned space from adjacent surfaces. # # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit - # @param location [String] The HPXML::LocationXXX of interest + # @param location [String] The location of interest (HPXML::LocationXXX) # @return [Double] Garage fraction under conditioned space def self.get_garage_frac_under_conditioned(hpxml_bldg, location) area_total = 0.0 @@ -580,7 +580,7 @@ def self.init_loads(hpxml_bldg) all_zone_loads[zone] = DesignLoadValues.new zone.spaces.each do |space| all_space_loads[space] = DesignLoadValues.new - space.additional_properties.total_exposed_wall_area = 0.0 + space.additional_properties.total_exposed_wall_area = 0.0 # Wall area in contact with outdoor air # Initialize Hourly Aggregate Fenestration Loads (AFL) space.additional_properties.afl_hr_windows = [0.0] * 12 # Data saved for peak load space.additional_properties.afl_hr_skylights = [0.0] * 12 # Data saved for peak load @@ -1023,57 +1023,45 @@ def self.process_load_walls(mj, hpxml_bldg, all_zone_loads, all_space_loads) ashrae_wall_group = get_ashrae_wall_group(wall) - if wall.azimuth.nil? - azimuths = [0.0, 90.0, 180.0, 270.0] # Assume 4 equal surfaces facing every direction - else - azimuths = [wall.azimuth] - end - - htg_htm = 0.0 - clg_htm = 0.0 - azimuths.each do |_azimuth| - if wall.is_exposed - # Store exposed wall gross area for infiltration calculation - space.additional_properties.total_exposed_wall_area += wall.area / azimuths.size + if wall.is_exterior + # Store exposed wall gross area for infiltration calculation + space.additional_properties.total_exposed_wall_area += wall.area + + # Adjust base Cooling Load Temperature Difference (CLTD) + # Assume absorptivity for light walls < 0.5, medium walls <= 0.75, dark walls > 0.75 (based on MJ8 Table 4B Notes) + if wall.solar_absorptance <= 0.5 + color_multiplier = 0.65 # MJ8 Table 4B Notes, pg 348 + elsif wall.solar_absorptance <= 0.75 + color_multiplier = 0.83 # MJ8 Appendix 12, pg 519 + else + color_multiplier = 1.0 end - if wall.is_exterior - - # Adjust base Cooling Load Temperature Difference (CLTD) - # Assume absorptivity for light walls < 0.5, medium walls <= 0.75, dark walls > 0.75 (based on MJ8 Table 4B Notes) - if wall.solar_absorptance <= 0.5 - color_multiplier = 0.65 # MJ8 Table 4B Notes, pg 348 - elsif wall.solar_absorptance <= 0.75 - color_multiplier = 0.83 # MJ8 Appendix 12, pg 519 - else - color_multiplier = 1.0 - end - - # Base Cooling Load Temperature Differences (CLTD's) for dark colored sunlit and shaded walls - # with 95 degF outside temperature taken from MJ8 Figure A12-8 (intermediate wall groups were - # determined using linear interpolation). Shaded walls apply to partition walls only. - cltd_base_sun = { 'G' => 38.0, 'F-G' => 34.95, 'F' => 31.9, 'E-F' => 29.45, 'E' => 27.0, 'D-E' => 24.5, 'D' => 22.0, 'C-D' => 21.25, 'C' => 20.5, 'B-C' => 19.65, 'B' => 18.8 } - # cltd_base_shade = { 'G' => 25.0, 'F-G' => 22.5, 'F' => 20.0, 'E-F' => 18.45, 'E' => 16.9, 'D-E' => 15.45, 'D' => 14.0, 'C-D' => 13.55, 'C' => 13.1, 'B-C' => 12.85, 'B' => 12.6 } - # Non-directional exterior walls - cltd_base = cltd_base_sun - cltd = cltd_base[ashrae_wall_group] * color_multiplier + # Base Cooling Load Temperature Differences (CLTD's) for dark colored sunlit and shaded walls + # with 95 degF outside temperature taken from MJ8 Figure A12-8 (intermediate wall groups were + # determined using linear interpolation). Shaded walls apply to partition walls only. + cltd_base_sun = { 'G' => 38.0, 'F-G' => 34.95, 'F' => 31.9, 'E-F' => 29.45, 'E' => 27.0, 'D-E' => 24.5, 'D' => 22.0, 'C-D' => 21.25, 'C' => 20.5, 'B-C' => 19.65, 'B' => 18.8 } + # cltd_base_shade = { 'G' => 25.0, 'F-G' => 22.5, 'F' => 20.0, 'E-F' => 18.45, 'E' => 16.9, 'D-E' => 15.45, 'D' => 14.0, 'C-D' => 13.55, 'C' => 13.1, 'B-C' => 12.85, 'B' => 12.6 } - if mj.ctd >= 10.0 - # Adjust base CLTD for different CTD or DR - cltd += (hpxml_bldg.header.manualj_cooling_design_temp - 95.0) + mj.daily_range_temp_adjust[mj.daily_range_num] - else - # Handling cases ctd < 10 is based on A12-18 in MJ8 - cltd_corr = mj.ctd - 20.0 - mj.daily_range_temp_adjust[mj.daily_range_num] - cltd = [cltd + cltd_corr, 0.0].max # NOTE: The CLTD_Alt equation in A12-18 part 5 suggests CLTD - CLTD_corr, but A12-19 suggests it should be CLTD + CLTD_corr (where CLTD_corr is negative) - end + # Non-directional exterior walls + cltd_base = cltd_base_sun + cltd = cltd_base[ashrae_wall_group] * color_multiplier - clg_htm += (1.0 / wall.insulation_assembly_r_value) / azimuths.size * cltd - htg_htm += (1.0 / wall.insulation_assembly_r_value) / azimuths.size * mj.htd - else # Partition wall - adjacent_space = wall.exterior_adjacent_to - clg_htm += (1.0 / wall.insulation_assembly_r_value) / azimuths.size * (mj.cool_design_temps[adjacent_space] - mj.cool_setpoint) - htg_htm += (1.0 / wall.insulation_assembly_r_value) / azimuths.size * (mj.heat_setpoint - mj.heat_design_temps[adjacent_space]) + if mj.ctd >= 10.0 + # Adjust base CLTD for different CTD or DR + cltd += (hpxml_bldg.header.manualj_cooling_design_temp - 95.0) + mj.daily_range_temp_adjust[mj.daily_range_num] + else + # Handling cases ctd < 10 is based on A12-18 in MJ8 + cltd_corr = mj.ctd - 20.0 - mj.daily_range_temp_adjust[mj.daily_range_num] + cltd = [cltd + cltd_corr, 0.0].max # NOTE: The CLTD_Alt equation in A12-18 part 5 suggests CLTD - CLTD_corr, but A12-19 suggests it should be CLTD + CLTD_corr (where CLTD_corr is negative) end + + clg_htm = (1.0 / wall.insulation_assembly_r_value) * cltd + htg_htm = (1.0 / wall.insulation_assembly_r_value) * mj.htd + else # Partition wall + adjacent_space = wall.exterior_adjacent_to + clg_htm = (1.0 / wall.insulation_assembly_r_value) * (mj.cool_design_temps[adjacent_space] - mj.cool_setpoint) + htg_htm = (1.0 / wall.insulation_assembly_r_value) * (mj.heat_setpoint - mj.heat_design_temps[adjacent_space]) end clg_loads = clg_htm * wall.net_area htg_loads = htg_htm * wall.net_area @@ -1096,13 +1084,11 @@ def self.process_load_walls(mj, hpxml_bldg, all_zone_loads, all_space_loads) space = foundation_wall.space zone = space.zone - if foundation_wall.is_exposed + if foundation_wall.is_exterior # Store exposed wall gross area for infiltration calculation ag_frac = (foundation_wall.height - foundation_wall.depth_below_grade) / foundation_wall.height space.additional_properties.total_exposed_wall_area += foundation_wall.area * ag_frac - end - if foundation_wall.is_exterior u_wall_with_soil = get_foundation_wall_ufactor(foundation_wall, true, mj.ground_conductivity) htg_htm = u_wall_with_soil * mj.htd else # Partition wall @@ -1985,7 +1971,7 @@ def self.apply_hvac_cfis_loads(mj, hvac_loads, zone_loads, hvac_heating, hvac_co vent_mech_cfis = hpxml_bldg.ventilation_fans.find { |vent_mech| vent_mech.fan_type == HPXML::MechVentTypeCFIS && vent_mech.distribution_system_idref == hvac_distribution.id } return if vent_mech_cfis.nil? - vent_cfm = vent_mech_cfis.average_total_unit_flow_rate + vent_cfm = vent_mech_cfis.average_unit_flow_rate heat_load = 1.1 * mj.acf * vent_cfm * mj.htd cool_sens_load = 1.1 * mj.acf * vent_cfm * mj.ctd @@ -2060,7 +2046,7 @@ def self.apply_hvac_piping_load(hvac_loads, zone_loads, hvac_heating) # Equipment Adjustments # # @param mj [MJValues] Object with a collection of misc Manual J values - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hvac_sizings [HVACSizingValues] Object with sizing values for a given HVAC system # @param weather [WeatherFile] Weather object containing EPW information # @param hvac_heating [HPXML::HeatingSystem or HPXML::HeatPump] The heating portion of the current HPXML HVAC system @@ -2764,7 +2750,7 @@ def self.apply_hvac_final_capacities(hvac_sizings, hvac_heating, hvac_cooling, h # GSHP Ground Loop Sizing Calculations # # @param mj [MJValues] Object with a collection of misc Manual J values - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hvac_sizings [HVACSizingValues] Object with sizing values for a given HVAC system # @param weather [WeatherFile] Weather object containing EPW information # @param hvac_cooling [HPXML::CoolingSystem or HPXML::HeatPump] The cooling portion of the current HPXML HVAC system @@ -2908,7 +2894,7 @@ def self.get_geothermal_loop_borefield_ft_per_ton(mj, hpxml_bldg, geothermal_loo # Returns the geothermal loop g-function response factors. # - # @param bore_config [String] Borefield configuration of type HPXML::GeothermalLoopBorefieldConfigurationXXX + # @param bore_config [String] Borefield configuration (HPXML::GeothermalLoopBorefieldConfigurationXXX) # @param g_functions_json [JSON] JSON object with g-function data # @param geothermal_loop [HPXML::GeothermalLoop] Geothermal loop of interest # @param num_bore_holes [Integer] Total number of boreholes @@ -2973,7 +2959,7 @@ def self.get_geothermal_g_functions_data(bore_config, g_functions_json, geotherm # Returns the geothermal loop g-function logtimes/values for a specific configuration in the JSON file. # # @param g_functions_json [JSON] JSON object with g-function data - # @param bore_config [String] Borefield configuration of type HPXML::GeothermalLoopBorefieldConfigurationXXX + # @param bore_config [String] Borefield configuration (HPXML::GeothermalLoopBorefieldConfigurationXXX) # @param num_bore_holes [Integer] Total number of boreholes # @param b_h_rb [String] The lookup key (B._H._rb) in the g-function data. # @return [Array, Array>] List of logtimes, list of g-function values @@ -3131,7 +3117,7 @@ def self.calculate_heat_pump_backup_load(mj, hvac_heating, heating_load, hp_nomi # minimum compressor temperature, design loads, heat pump performance curves, etc. # # @param mj [MJValues] Object with a collection of misc Manual J values - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hvac_sizings [HVACSizingValues] Object with sizing values for a given HVAC system # @param weather [WeatherFile] Weather object containing EPW information # @param hvac_heating [HPXML::HeatPump] The HPXML heat pump of interest @@ -3206,7 +3192,7 @@ def self.process_heat_pump_adjustment(mj, runner, hvac_sizings, weather, hvac_he def self.get_ventilation_data(hpxml_bldg) # If CFIS w/ supplemental fan, assume air handler is running the full hour and can provide # all ventilation needs (i.e., supplemental fan does not need to run), so skip supplement fan - vent_fans_mech = hpxml_bldg.ventilation_fans.select { |f| f.used_for_whole_building_ventilation && !f.is_cfis_supplemental_fan? && f.flow_rate > 0 && f.hours_in_operation > 0 } + vent_fans_mech = hpxml_bldg.ventilation_fans.select { |f| f.used_for_whole_building_ventilation && !f.is_cfis_supplemental_fan && f.flow_rate > 0 && f.hours_in_operation > 0 } if vent_fans_mech.empty? return { q_unbal: 0.0, q_bal: 0.0, q_preheat: 0.0, q_precool: 0.0, q_recirc: 0.0, bal_sens_eff: 0.0, bal_lat_eff: 0.0 } @@ -3224,16 +3210,16 @@ def self.get_ventilation_data(hpxml_bldg) vent_mech_erv_hrv_tot = vent_fans_mech.select { |vent_mech| [HPXML::MechVentTypeERV, HPXML::MechVentTypeHRV].include? vent_mech.fan_type } # Average in-unit CFMs (include recirculation from in unit CFMs for shared systems) - q_sup_tot = vent_mech_sup_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) - q_exh_tot = vent_mech_exh_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) - q_bal_tot = vent_mech_bal_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) - q_erv_hrv_tot = vent_mech_erv_hrv_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) - q_cfis_tot = vent_mech_cfis_tot.map { |vent_mech| vent_mech.average_total_unit_flow_rate }.sum(0.0) + q_sup_tot = vent_mech_sup_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) + q_exh_tot = vent_mech_exh_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) + q_bal_tot = vent_mech_bal_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) + q_erv_hrv_tot = vent_mech_erv_hrv_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) + q_cfis_tot = vent_mech_cfis_tot.map { |vent_mech| vent_mech.average_unit_flow_rate }.sum(0.0) # Average preconditioned OA air CFMs (only OA, recirculation will be addressed below for all shared systems) q_preheat = vent_mech_preheat.map { |vent_mech| vent_mech.average_oa_unit_flow_rate * vent_mech.preheating_fraction_load_served }.sum(0.0) q_precool = vent_mech_precool.map { |vent_mech| vent_mech.average_oa_unit_flow_rate * vent_mech.precooling_fraction_load_served }.sum(0.0) - q_recirc = vent_mech_shared.map { |vent_mech| vent_mech.average_total_unit_flow_rate - vent_mech.average_oa_unit_flow_rate }.sum(0.0) + q_recirc = vent_mech_shared.map { |vent_mech| vent_mech.average_unit_flow_rate - vent_mech.average_oa_unit_flow_rate }.sum(0.0) # Total CFMS q_tot_sup = q_sup_tot + q_bal_tot + q_erv_hrv_tot + q_cfis_tot @@ -3680,7 +3666,7 @@ def self.get_mj_azimuth(azimuth) # Calculates UA (U-factor times Area) values for a HPXML location. # # @param mj [MJValues] Object with a collection of misc Manual J values - # @param location [String] The HPXML::LocationXXX of interest + # @param location [String] The location of interest (HPXML::LocationXXX) # @param weather [WeatherFile] Weather object containing EPW information # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @return [Hash] UA values for adjacency to outdoor air, ground, or conditioned space (Btu/hr-F) @@ -3772,7 +3758,7 @@ def self.get_space_ua_values(mj, location, weather, hpxml_bldg) # UA-based heat balance method. (Unvented attics w/ roof insulation are handled as a special case.) # # @param mj [MJValues] Object with a collection of misc Manual J values - # @param location [String] The HPXML::LocationXXX of interest + # @param location [String] The location of interest (HPXML::LocationXXX) # @param weather [WeatherFile] Weather object containing EPW information # @param hpxml_bldg [HPXML::Building] HPXML Building object representing an individual dwelling unit # @param setpoint_temp [Double] The conditioned space heating or cooling setpoint temperature (F) @@ -3843,7 +3829,7 @@ def self.calculate_space_design_temp(mj, location, weather, hpxml_bldg, setpoint # Retrieves the design temperature for a space that uses scheduled temperatures (e.g., multifamily # spaces when modeling an individual dwelling unit). # - # @param location [String] The HPXML::LocationXXX of interest + # @param location [String] The location of interest (HPXML::LocationXXX) # @param setpoint_temp [Double] The conditioned space heating or cooling setpoint temperature (F) # @param outdoor_design_temp [Double] The outdoor heating or cooling design temperature (F) # @param ground_temp [Double] The approximate ground temperature during the heating or cooling season (F) @@ -4887,63 +4873,63 @@ def self.floors(obj) # Object with a collection of misc Manual J values that are calculated up front. class MJValues - attr_accessor(:daily_range_temp_adjust, # CLTD adjustments based on daily temperature range (F) - :daily_range_num, # Daily Temperature Range (DTR) class; 0=low, 1=medium; 2=high - :cool_setpoint, # Conditioned space cooling setpoint (F) - :cool_design_grains, # Difference between absolute humidity of the outdoor and indoor air (grains) - :cool_indoor_wetbulb, # Conditioned space cooling wetbulb temperature (F) - :cool_indoor_enthalpy, # Conditioned space cooling enthalpy (Btu/lb) - :cool_outdoor_wetbulb, # Outdoor cooling wetbulb temperature (F) - :cool_design_temps, # Hash of HPXML location => cooling design temperature (F) - :ctd, # Cooling Temperature Difference, difference between setpoint and outdoor design temperature (F) - :heat_setpoint, # Conditioned space heating setpoint (F) - :heat_design_temps, # Hash of HPXML location => heating design temperature (F) - :htd, # Heating Temperature Difference, difference between setpoint and outdoor design temperature (F) - :acf, # Altitude Correction Factor - :indoor_air_density, # Conditioned space air density (lb/ft3) - :outside_air_density, # Outdoor air density (lb/ft3) - :p_atm, # Pressure of air (atm) - :p_psi, # Pressure of air (psi) - :ground_conductivity) # Ground conductivity (Btu/hr-ft-F) + attr_accessor(:daily_range_temp_adjust, # [Double] CLTD adjustments based on daily temperature range (F) + :daily_range_num, # [Integer] Daily Temperature Range (DTR) class; 0=low, 1=medium; 2=high + :cool_setpoint, # [Double] Conditioned space cooling setpoint (F) + :cool_design_grains, # [Double] Difference between absolute humidity of the outdoor and indoor air (grains) + :cool_indoor_wetbulb, # [Double] Conditioned space cooling wetbulb temperature (F) + :cool_indoor_enthalpy, # [Double] Conditioned space cooling enthalpy (Btu/lb) + :cool_outdoor_wetbulb, # [Double] Outdoor cooling wetbulb temperature (F) + :cool_design_temps, # [Hash] Map of HPXML location => cooling design temperature (F) + :ctd, # [Double] Cooling Temperature Difference, difference between setpoint and outdoor design temperature (F) + :heat_setpoint, # [Double] Conditioned space heating setpoint (F) + :heat_design_temps, # [Hash] Map of HPXML location => heating design temperature (F) + :htd, # [Double] Heating Temperature Difference, difference between setpoint and outdoor design temperature (F) + :acf, # [Double] Altitude Correction Factor + :indoor_air_density, # [Double] Conditioned space air density (lb/ft3) + :outside_air_density, # [Double] Outdoor air density (lb/ft3) + :p_atm, # [Double] Pressure of air (atm) + :p_psi, # [Double] Pressure of air (psi) + :ground_conductivity) # [Double] Ground conductivity (Btu/hr-ft-F) end # Object with design loads (component-level and totals) for the building, zone, or space class DesignLoadValues - attr_accessor(:Cool_Sens, # Total sensible cooling load (Btu/hr) - :Cool_Lat, # Total latent cooling load (Btu/hr) - :Cool_Tot, # Total (sensible + latent) cooling load (Btu/hr) - :Cool_Ducts_Sens, # Ducts sensible cooling load (Btu/hr) - :Cool_Ducts_Lat, # Ducts latent cooling load (Btu/hr) - :Cool_Windows, # Windows sensible cooling load (Btu/hr) - :Cool_Skylights, # Skylights sensible cooling load (Btu/hr) - :Cool_Doors, # Doors sensible cooling load (Btu/hr) - :Cool_Walls, # Walls sensible cooling load (Btu/hr) - :Cool_Roofs, # Roofs sensible cooling load (Btu/hr) - :Cool_Floors, # Floors sensible cooling load (Btu/hr) - :Cool_Slabs, # Slabs sensible cooling load (Btu/hr) - :Cool_Ceilings, # Ceilings sensible cooling load (Btu/hr) - :Cool_Infil_Sens, # Infiltration sensible cooling load (Btu/hr) - :Cool_Infil_Lat, # Infiltration latent cooling load (Btu/hr) - :Cool_Vent_Sens, # Ventilation sensible cooling load (Btu/hr) - :Cool_Vent_Lat, # Ventilation latent cooling load (Btu/hr) - :Cool_IntGains_Sens, # Internal gains sensible cooling load (Btu/hr) - :Cool_IntGains_Lat, # Internal gains latent cooling load (Btu/hr) - :Cool_BlowerHeat, # Central system blower fan heat cooling load (Btu/hr) - :Cool_AEDExcursion, # Adequate Exposure Diversity (AED) excursion cooling load (Btu/hr) - :Heat_Tot, # Total sensible heating load (Btu/hr) - :Heat_Ducts, # Ducts sensible heating load (Btu/hr) - :Heat_Windows, # Windows sensible heating load (Btu/hr) - :Heat_Skylights, # Skylights sensible heating load (Btu/hr) - :Heat_Doors, # Doors sensible heating load (Btu/hr) - :Heat_Walls, # Walls sensible heating load (Btu/hr) - :Heat_Roofs, # Roofs sensible heating load (Btu/hr) - :Heat_Floors, # Floors sensible heating load (Btu/hr) - :Heat_Slabs, # Slabs sensible heating load (Btu/hr) - :Heat_Ceilings, # Ceilings sensible heating load (Btu/hr) - :Heat_Infil, # Infiltration sensible heating load (Btu/hr) - :Heat_Vent, # Ventilation sensible heating load (Btu/hr) - :Heat_Piping, # Hydronic piping sensible heating load (Btu/hr) - :HourlyFenestrationLoads) # Array of hourly fenestration loads for AED curve (Btu/hr) + attr_accessor(:Cool_Sens, # [Double] Total sensible cooling load (Btu/hr) + :Cool_Lat, # [Double] Total latent cooling load (Btu/hr) + :Cool_Tot, # [Double] Total (sensible + latent) cooling load (Btu/hr) + :Cool_Ducts_Sens, # [Double] Ducts sensible cooling load (Btu/hr) + :Cool_Ducts_Lat, # [Double] Ducts latent cooling load (Btu/hr) + :Cool_Windows, # [Double] Windows sensible cooling load (Btu/hr) + :Cool_Skylights, # [Double] Skylights sensible cooling load (Btu/hr) + :Cool_Doors, # [Double] Doors sensible cooling load (Btu/hr) + :Cool_Walls, # [Double] Walls sensible cooling load (Btu/hr) + :Cool_Roofs, # [Double] Roofs sensible cooling load (Btu/hr) + :Cool_Floors, # [Double] Floors sensible cooling load (Btu/hr) + :Cool_Slabs, # [Double] Slabs sensible cooling load (Btu/hr) + :Cool_Ceilings, # [Double] Ceilings sensible cooling load (Btu/hr) + :Cool_Infil_Sens, # [Double] Infiltration sensible cooling load (Btu/hr) + :Cool_Infil_Lat, # [Double] Infiltration latent cooling load (Btu/hr) + :Cool_Vent_Sens, # [Double] Ventilation sensible cooling load (Btu/hr) + :Cool_Vent_Lat, # [Double] Ventilation latent cooling load (Btu/hr) + :Cool_IntGains_Sens, # [Double] Internal gains sensible cooling load (Btu/hr) + :Cool_IntGains_Lat, # [Double] Internal gains latent cooling load (Btu/hr) + :Cool_BlowerHeat, # [Double] Central system blower fan heat cooling load (Btu/hr) + :Cool_AEDExcursion, # [Double] Adequate Exposure Diversity (AED) excursion cooling load (Btu/hr) + :Heat_Tot, # [Double] Total sensible heating load (Btu/hr) + :Heat_Ducts, # [Double] Ducts sensible heating load (Btu/hr) + :Heat_Windows, # [Double] Windows sensible heating load (Btu/hr) + :Heat_Skylights, # [Double] Skylights sensible heating load (Btu/hr) + :Heat_Doors, # [Double] Doors sensible heating load (Btu/hr) + :Heat_Walls, # [Double] Walls sensible heating load (Btu/hr) + :Heat_Roofs, # [Double] Roofs sensible heating load (Btu/hr) + :Heat_Floors, # [Double] Floors sensible heating load (Btu/hr) + :Heat_Slabs, # [Double] Slabs sensible heating load (Btu/hr) + :Heat_Ceilings, # [Double] Ceilings sensible heating load (Btu/hr) + :Heat_Infil, # [Double] Infiltration sensible heating load (Btu/hr) + :Heat_Vent, # [Double] Ventilation sensible heating load (Btu/hr) + :Heat_Piping, # [Double] Hydronic piping sensible heating load (Btu/hr) + :HourlyFenestrationLoads) # [Array] Array of hourly fenestration loads for AED curve (Btu/hr) def initialize @Cool_Sens = 0.0 @@ -4986,33 +4972,33 @@ def initialize # Object with sizing values (loads, capacities, airflows, etc.) for a specific HVAC system class HVACSizingValues - attr_accessor(:Cool_Load_Sens, # Total sensible cooling load (Btu/hr) - :Cool_Load_Lat, # Total latent cooling load (Btu/hr) - :Cool_Load_Tot, # Total (sensible + latent) cooling load (Btu/hr) - :Heat_Load, # Total heating sensible load (Btu/hr) - :Heat_Load_Supp, # Total heating sensible load for the HP backup (Btu/hr) - :Cool_Capacity, # Nominal total cooling capacity (Btu/hr) - :Cool_Capacity_Sens, # Nominal sensible cooling capacity (Btu/hr) - :Heat_Capacity, # Nominal heating capacity (Btu/hr) - :Heat_Capacity_Supp, # Nominal heating capacity for the HP backup (Btu/hr) - :Cool_Airflow, # Cooling airflow rate (cfm) - :Heat_Airflow, # Heating airflow rate (cfm) - :GSHP_Loop_Flow, # Ground-source heat pump water flow rate through the geothermal loop (gal/min) - :GSHP_Bore_Holes, # Ground-source heat pump number of boreholes (#) - :GSHP_Bore_Depth, # Ground-source heat pump depth of each borehole (ft) - :GSHP_G_Functions, # Ground-source heat pump G-functions - :GSHP_Bore_Config) # Ground-source heat pump borefield configuration (e.g., Rectangular) + attr_accessor(:Cool_Load_Sens, # [Double] Total sensible cooling load (Btu/hr) + :Cool_Load_Lat, # [Double] Total latent cooling load (Btu/hr) + :Cool_Load_Tot, # [Double] Total (sensible + latent) cooling load (Btu/hr) + :Heat_Load, # [Double] Total heating sensible load (Btu/hr) + :Heat_Load_Supp, # [Double] Total heating sensible load for the HP backup (Btu/hr) + :Cool_Capacity, # [Double] Nominal total cooling capacity (Btu/hr) + :Cool_Capacity_Sens, # [Double] Nominal sensible cooling capacity (Btu/hr) + :Heat_Capacity, # [Double] Nominal heating capacity (Btu/hr) + :Heat_Capacity_Supp, # [Double] Nominal heating capacity for the HP backup (Btu/hr) + :Cool_Airflow, # [Double] Cooling airflow rate (cfm) + :Heat_Airflow, # [Double] Heating airflow rate (cfm) + :GSHP_Loop_Flow, # [Double] Ground-source heat pump water flow rate through the geothermal loop (gal/min) + :GSHP_Bore_Holes, # [Integer] Ground-source heat pump number of boreholes (#) + :GSHP_Bore_Depth, # [Double] Ground-source heat pump depth of each borehole (ft) + :GSHP_G_Functions, # [Array, Array>] Ground-source heat pump G-functions + :GSHP_Bore_Config) # [String] Ground-source heat pump borefield configuration (HPXML::GeothermalLoopBorefieldConfigurationXXX) end # Object with data needed to write out the detailed output (used for populating an ACCA J1 form). class DetailedOutputValues - attr_accessor(:Area, # Surface area (ft2) - :Length, # Slab length (ft) - :Heat_HTM, # Heating Heat Transfer Multiplier (HTM) (Btu/hr-ft2) - :Cool_HTM, # Cooling Heat Transfer Multiplier (HTM) (Btu/hr-ft2) - :Heat_Load, # Total sensible heating load (Btu/hr) - :Cool_Load_Sens, # Total sensible cooling load (Btu/hr) - :Cool_Load_Lat) # Total latent cooling load (Btu/hr) + attr_accessor(:Area, # [Double] Surface area (ft2) + :Length, # [Double] Slab length (ft) + :Heat_HTM, # [Double] Heating Heat Transfer Multiplier (HTM) (Btu/hr-ft2) + :Cool_HTM, # [Double] Cooling Heat Transfer Multiplier (HTM) (Btu/hr-ft2) + :Heat_Load, # [Double] Total sensible heating load (Btu/hr) + :Cool_Load_Sens, # [Double] Total sensible cooling load (Btu/hr) + :Cool_Load_Lat) # [Double] Total latent cooling load (Btu/hr) def initialize(heat_load:, cool_load_sens:, cool_load_lat:, area: nil, length: nil, heat_htm: nil, cool_htm: nil) @Heat_Load = heat_load.round diff --git a/HPXMLtoOpenStudio/resources/lighting.rb b/HPXMLtoOpenStudio/resources/lighting.rb index 116c9d7a46..7fd7c7d52f 100644 --- a/HPXMLtoOpenStudio/resources/lighting.rb +++ b/HPXMLtoOpenStudio/resources/lighting.rb @@ -4,7 +4,7 @@ module Lighting # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param spaces [Hash] keys are locations and values are OpenStudio::Model::Space objects # @param lighting_groups [TODO] TODO @@ -12,7 +12,7 @@ module Lighting # @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files # @param cfa [Double] Conditioned floor area in the dwelling unit (ft2) - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @return [TODO] TODO def self.apply(runner, model, spaces, lighting_groups, lighting, eri_version, schedules_file, cfa, diff --git a/HPXMLtoOpenStudio/resources/location.rb b/HPXMLtoOpenStudio/resources/location.rb index 49ccd43445..3f31500d60 100644 --- a/HPXMLtoOpenStudio/resources/location.rb +++ b/HPXMLtoOpenStudio/resources/location.rb @@ -155,8 +155,8 @@ def self.get_epw_path(hpxml_bldg, hpxml_path) # @param weather [WeatherFile] Weather object containing EPW information # @return [TODO] TODO def self.get_sim_calendar_year(sim_calendar_year, weather) - if (not weather.nil?) && (not weather.header.ActualYearStartDate.nil?) # AMY - sim_calendar_year = weather.header.ActualYearStartDate + if (not weather.nil?) && (not weather.header.ActualYear.nil?) # AMY + sim_calendar_year = weather.header.ActualYear end if sim_calendar_year.nil? sim_calendar_year = 2007 diff --git a/HPXMLtoOpenStudio/resources/materials.rb b/HPXMLtoOpenStudio/resources/materials.rb index 291d8d7667..e247019333 100644 --- a/HPXMLtoOpenStudio/resources/materials.rb +++ b/HPXMLtoOpenStudio/resources/materials.rb @@ -225,11 +225,6 @@ def self.AirFilmSlopeReducedReflective(roof_pitch) # @param roof_pitch [TODO] TODO # @return [TODO] TODO def self.AirFilmRoof(roof_pitch) - # Use weighted average between enhanced and reduced convection based on degree days. - # hdd_frac = hdd65f / (hdd65f + cdd65f) - # cdd_frac = cdd65f / (hdd65f + cdd65f) - # return self.AirFilmSlopeEnhanced(roof_pitch).rvalue * hdd_frac + self.AirFilmSlopeReduced(roof_pitch).rvalue * cdd_frac # hr-ft-F/Btu - # Simplification to not depend on weather rvalue = (self.AirFilmSlopeEnhanced(roof_pitch).rvalue + self.AirFilmSlopeReduced(roof_pitch).rvalue) / 2.0 # hr-ft-F/Btu return self.AirFilm(rvalue) end @@ -239,11 +234,6 @@ def self.AirFilmRoof(roof_pitch) # @param roof_pitch [TODO] TODO # @return [TODO] TODO def self.AirFilmRoofRadiantBarrier(roof_pitch) - # Use weighted average between enhanced and reduced convection based on degree days. - # hdd_frac = hdd65f / (hdd65f + cdd65f) - # cdd_frac = cdd65f / (hdd65f + cdd65f) - # return self.AirFilmSlopeEnhancedReflective(roof_pitch).rvalue * hdd_frac + self.AirFilmSlopeReducedReflective(roof_pitch).rvalue * cdd_frac # hr-ft-F/Btu - # Simplification to not depend on weather rvalue = (self.AirFilmSlopeEnhancedReflective(roof_pitch).rvalue + self.AirFilmSlopeReducedReflective(roof_pitch).rvalue) / 2.0 # hr-ft-F/Btu return self.AirFilm(rvalue) end diff --git a/HPXMLtoOpenStudio/resources/math.rb b/HPXMLtoOpenStudio/resources/math.rb new file mode 100644 index 0000000000..e7d21c9a0d --- /dev/null +++ b/HPXMLtoOpenStudio/resources/math.rb @@ -0,0 +1,236 @@ +# frozen_string_literal: true + +# Collection of methods related to various math tools. +module MathTools + # Returns the linear interpolation between two results. + # + # @param x [Double] the x-coordinate corresponding to the point to interpolate + # @param x0 [Double] known point 1 x-coordinate + # @param x1 [Double] known point 2 x-coordinate + # @param f0 [Double] known point 1 function value + # @param f1 [Double] known point 2 function value + # @return [Double] the interpolated value for given x-coordinate + def self.interp2(x, x0, x1, f0, f1) + return f0 + ((x - x0) / (x1 - x0)) * (f1 - f0) + end + + # Returns the bilinear interpolation between four results. + # + # @param x [Double] the x-coordinate corresponding to the point to interpolate + # @param y [Double] the y-coordinate corresponding to the point to interpolate + # @param x1 [Double] known points 1 and 2 x-coordinate + # @param x2 [Double] known points 3 and 4 x-coordinate + # @param y1 [Double] known points 1 and 3 y-coordinate + # @param y2 [Double] known points 2 and 4 y-coordinate + # @param fx1y1 [Double] known point 1 function value + # @param fx1y2 [Double] known point 2 function value + # @param fx2y1 [Double] known point 3 function value + # @param fx2y2 [Double] known point 4 function value + # @return [Double] the interpolated value for the given x- and y- coordinates + def self.interp4(x, y, x1, x2, y1, y2, fx1y1, fx1y2, fx2y1, fx2y2) + return (fx1y1 / ((x2 - x1) * (y2 - y1))) * (x2 - x) * (y2 - y) \ + + (fx2y1 / ((x2 - x1) * (y2 - y1))) * (x - x1) * (y2 - y) \ + + (fx1y2 / ((x2 - x1) * (y2 - y1))) * (x2 - x) * (y - y1) \ + + (fx2y2 / ((x2 - x1) * (y2 - y1))) * (x - x1) * (y - y1) + end + + # Calculate the result of a biquadratic polynomial with independent variables. + # x and y, and a list of coefficients, c: + # + # z = c[1] + c[2]*x + c[3]*x**2 + c[4]*y + c[5]*y**2 + c[6]*x*y + # + # @param x [Double] independent variable 1 + # @param y [Double] independent variable 2 + # @param c [Array] list of 6 coefficients + # @return [Double] result of biquadratic polynomial + def self.biquadratic(x, y, c) + if c.length != 6 + fail 'Error: There must be 6 coefficients in a biquadratic polynomial' + end + + z = c[0] + c[1] * x + c[2] * x**2 + c[3] * y + c[4] * y**2 + c[5] * y * x + return z + end + + # Calculate the result of a quadratic polynomial with independent variable. + # x and a list of coefficients, c: + # + # y = c[1] + c[2]*x + c[3]*x**2 + # + # @param x [Double] independent variable + # @param c [Array] list of 3 coefficients + # @return [Double] result of quadratic polynomial + def self.quadratic(x, c) + if c.size != 3 + fail 'Error: There must be 3 coefficients in a quadratic polynomial' + end + + y = c[0] + c[1] * x + c[2] * x**2 + + return y + end + + # Calculate the result of a bicubic polynomial with independent variables. + # x and y, and a list of coefficients, c: + + # z = c[1] + c[2]*x + c[3]*y + c[4]*x**2 + c[5]*x*y + c[6]*y**2 + \ + # c[7]*x**3 + c[8]*y*x**2 + c[9]*x*y**2 + c[10]*y**3 + # + # @param x [Double] independent variable 1 + # @param y [Double] independent variable 2 + # @param c [Array] list of 10 coefficients + # @return [Double] result of bicubic polynomial + def self.bicubic(x, y, c) + if c.size != 10 + fail 'Error: There must be 10 coefficients in a bicubic polynomial' + end + + z = c[0] + c[1] * x + c[2] * x**2 + c[3] * y + c[4] * y**2 + c[5] * x * y + \ + c[6] * x**3 + c[7] * y**3 + c[8] * x**2 * y + c[9] * x * y**2 + + return z + end + + # Determine if a guess is within tolerance for convergence. + # If not, output a new guess using the Newton-Raphson method. + # + # Based on XITERATE f77 code in ResAC (Brandemuehl). + # + # @param x0 [Double] current guess value + # @param f0 [Double] value of function f(x) at current guess value + # @param x1 [Double] previous two guess values, used to create quadratic (or linear fit) + # @param f1 [Double] previous two values of f(x) + # @param x2 [Double] previous two guess values, used to create quadratic (or linear fit) + # @param f2 [Double] previous two values of f(x) + # @param icount [Integer] iteration count + # @param cvg [Boolean] whether the iteration has reached convergence + # @return [Double, Boolean, Double, Double, Double, Double] new guess value, whether the iteration has reached convergence, updated previous two guess values, used to create quadratic (or linear fit), updated previous two values of f(x) + def self.Iterate(x0, f0, x1, f1, x2, f2, icount, cvg) + ''' + Example: + -------- + # Find a value of x that makes f(x) equal to some specific value f: + # initial guess (all values of x) + x = 1.0 + x1 = x + x2 = x + # initial error + error = f - f(x) + error1 = error + error2 = error + itmax = 50 # maximum iterations + cvg = False # initialize convergence to "False" + for i in range(1,itmax+1): + error = f - f(x) + x,cvg,x1,error1,x2,error2 = \ + Iterate(x,error,x1,error1,x2,error2,i,cvg) + if cvg: + break + if cvg: + print "x converged after", i, :iterations" + else: + print "x did NOT converge after", i, "iterations" + print "x, when f(x) is", f,"is", x + ''' + + tolRel = 1e-5 + dx = 0.1 + + # Test for convergence + if (((x0 - x1).abs < tolRel * [x0.abs, Constants.small].max) && (icount != 1)) || (f0 == 0) + x_new = x0 + cvg = true + else + cvg = false + + if icount == 1 # Perturbation + mode = 1 + elsif icount == 2 # Linear fit + mode = 2 + else # Quadratic fit + mode = 3 + end + + if mode == 3 + # Quadratic fit + if x0 == x1 # If two xi are equal, use a linear fit + x1 = x2 + f1 = f2 + mode = 2 + elsif x0 == x2 # If two xi are equal, use a linear fit + mode = 2 + else + # Set up quadratic coefficients + c = ((f2 - f0) / (x2 - x0) - (f1 - f0) / (x1 - x0)) / (x2 - x1) + b = (f1 - f0) / (x1 - x0) - (x1 + x0) * c + a = f0 - (b + c * x0) * x0 + + if c.abs < Constants.small # If points are co-linear, use linear fit + mode = 2 + elsif ((a + (b + c * x1) * x1 - f1) / f1).abs > Constants.small + # If coefficients do not accurately predict data points due to + # round-off, use linear fit + mode = 2 + else + d = b**2 - 4.0 * a * c # calculate discriminant to check for real roots + if d < 0.0 # if no real roots, use linear fit + mode = 2 + else + if d > 0.0 # if real unequal roots, use nearest root to recent guess + x_new = (-b + Math.sqrt(d)) / (2 * c) + x_other = -x_new - b / c + if (x_new - x0).abs > (x_other - x0).abs + x_new = x_other + end + else # If real equal roots, use that root + x_new = -b / (2 * c) + end + + if (f1 * f0 > 0) && (f2 * f0 > 0) # If the previous two f(x) were the same sign as the new + if f2.abs > f1.abs + x2 = x1 + f2 = f1 + end + else + if f2 * f0 > 0 + x2 = x1 + f2 = f1 + end + end + x1 = x0 + f1 = f0 + end + end + end + end + + if mode == 2 + # Linear Fit + m = (f1 - f0) / (x1 - x0) + if m == 0 # If slope is zero, use perturbation + mode = 1 + else + x_new = x0 - f0 / m + x2 = x1 + f2 = f1 + x1 = x0 + f1 = f0 + end + end + + if mode == 1 + # Perturbation + if x0.abs > Constants.small + x_new = x0 * (1 + dx) + else + x_new = dx + end + x2 = x1 + f2 = f1 + x1 = x0 + f1 = f0 + end + end + return x_new, cvg, x1, f1, x2, f2 + end +end diff --git a/HPXMLtoOpenStudio/resources/meta_measure.rb b/HPXMLtoOpenStudio/resources/meta_measure.rb index 86850d1906..98c14fcfca 100644 --- a/HPXMLtoOpenStudio/resources/meta_measure.rb +++ b/HPXMLtoOpenStudio/resources/meta_measure.rb @@ -189,7 +189,7 @@ def run_hpxml_workflow(rundir, measures, measures_dir, debug: false, output_vars # # @param measures_dir [TODO] TODO # @param measures [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param show_measure_calls [TODO] TODO # @param measure_type [TODO] TODO @@ -245,7 +245,7 @@ def apply_measures(measures_dir, measures, runner, model, show_measure_calls = t # # @param measures_dir [TODO] TODO # @param measures [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param workspace [TODO] TODO # @return [TODO] TODO @@ -275,7 +275,7 @@ def apply_energyplus_output_requests(measures_dir, measures, runner, model, work # # @param measure_args [TODO] TODO # @param measure_dir [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def print_measure_call(measure_args, measure_dir, runner) if measure_args.nil? || measure_dir.nil? @@ -316,7 +316,7 @@ def get_measure_instance(measure_rb_path) # @param provided_args [TODO] TODO # @param lookup_file [TODO] TODO # @param measure_name [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def validate_measure_args(measure_args, provided_args, lookup_file, measure_name, runner = nil) measure_arg_names = measure_args.map { |arg| arg.name } @@ -379,7 +379,7 @@ def validate_measure_args(measure_args, provided_args, lookup_file, measure_name # @param provided_args [TODO] TODO # @param lookup_file [TODO] TODO # @param measure_name [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def get_argument_map(model, measure, provided_args, lookup_file, measure_name, runner = nil) measure_args = measure.arguments(model) @@ -419,7 +419,7 @@ def get_value_from_workflow_step_value(step_value) # @param model [OpenStudio::Model::Model] OpenStudio Model object # @param measure [TODO] TODO # @param argument_map [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def run_measure(model, measure, argument_map, runner) begin @@ -496,7 +496,7 @@ def hash_to_string(hash, delim = '=', separator = ',') # TODO # # @param msg [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def register_error(msg, runner = nil) if not runner.nil? @@ -510,7 +510,7 @@ def register_error(msg, runner = nil) # TODO # # @param full_path [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def check_file_exists(full_path, runner = nil) if not File.exist?(full_path) @@ -521,7 +521,7 @@ def check_file_exists(full_path, runner = nil) # TODO # # @param full_path [TODO] TODO -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @return [TODO] TODO def check_dir_exists(full_path, runner = nil) if not Dir.exist?(full_path) @@ -550,7 +550,7 @@ def update_args_hash(hash, key, args, add_new = true) # TODO # -# @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object +# @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param rundir [TODO] TODO # @param debug [TODO] TODO # @return [TODO] TODO diff --git a/HPXMLtoOpenStudio/resources/misc_loads.rb b/HPXMLtoOpenStudio/resources/misc_loads.rb index 0eb3f30abc..d0cbe2a963 100644 --- a/HPXMLtoOpenStudio/resources/misc_loads.rb +++ b/HPXMLtoOpenStudio/resources/misc_loads.rb @@ -5,13 +5,13 @@ module MiscLoads # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param plug_load [TODO] TODO # @param obj_name [String] Name for the OpenStudio object # @param conditioned_space [TODO] TODO # @param apply_ashrae140_assumptions [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_plug(model, runner, plug_load, obj_name, conditioned_space, apply_ashrae140_assumptions, schedules_file, unavailable_periods) kwh = 0 @@ -74,12 +74,12 @@ def self.apply_plug(model, runner, plug_load, obj_name, conditioned_space, apply # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param fuel_load [TODO] TODO # @param obj_name [String] Name for the OpenStudio object # @param conditioned_space [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_fuel(model, runner, fuel_load, obj_name, conditioned_space, schedules_file, unavailable_periods) therm = 0 @@ -133,12 +133,12 @@ def self.apply_fuel(model, runner, fuel_load, obj_name, conditioned_space, sched # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @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 conditioned_space [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_pool_or_permanent_spa_heater(runner, model, pool_or_spa, conditioned_space, schedules_file, unavailable_periods) return if pool_or_spa.heater_type == HPXML::TypeNone @@ -222,12 +222,12 @@ def self.apply_pool_or_permanent_spa_heater(runner, model, pool_or_spa, conditio # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @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 conditioned_space [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.apply_pool_or_permanent_spa_pump(runner, model, pool_or_spa, conditioned_space, schedules_file, unavailable_periods) pump_kwh = 0 diff --git a/HPXMLtoOpenStudio/resources/psychrometrics.rb b/HPXMLtoOpenStudio/resources/psychrometrics.rb index 1db6cd470d..0b99a7d9d3 100644 --- a/HPXMLtoOpenStudio/resources/psychrometrics.rb +++ b/HPXMLtoOpenStudio/resources/psychrometrics.rb @@ -59,7 +59,7 @@ def self.Psat_fT(tdb) # # Source: 2009 ASHRAE Handbook # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param p [Double] pressure (psia) # @return [Double] saturated vapor temperature (F) def self.Tsat_fP(runner, p) @@ -98,7 +98,7 @@ def self.Tsat_fP(runner, p) # # Source: Based on TAIRSAT f77 code in ResAC (Brandemuehl) # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param h [Double] enthalpy (Btu/lbm) # @param p [Double] pressure (psia) # @return [Double] drybulb temperature (F) @@ -201,7 +201,7 @@ def self.Pstd_fZ(z) # # Source: Based on WETBULB f77 code in ResAC (Brandemuehl) # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param tdb [Double] drybulb temperature (F) # @param w [Double] humidity ratio (lbm/lbm) # @param p [Double] pressure (psia) @@ -408,7 +408,7 @@ def self.w_fT_R_P_SI(tdb, r, p) # Calculate the wetbulb temperature at a given drybulb temperature, relative humidity, and pressure. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param tdb [Double] drybulb temperature (F) # @param r [Double] relative humidity (frac) # @param p [Double] pressure (psia) @@ -419,7 +419,8 @@ def self.Twb_fT_R_P(runner, tdb, r, p) return twb end - # Find the coil Ao factor at the given incoming air state (entering drybulb and wetbulb) and CFM, total capacity, and SHR. + # Calculate the coil Ao factor at the given incoming air state (entering drybulb and wetbulb) and CFM, total capacity, and SHR. + # The Ao factor is the effective coil surface area as calculated using the relation BF = exp(-NTU) where NTU = Ao/(m*cp). # # Source: EnergyPlus source code # @@ -434,12 +435,13 @@ def self.CoilAoFactor(dBin, p, qdot, cfm, shr, win) bf = self.CoilBypassFactor(dBin, p, qdot, cfm, shr, win) mfr = UnitConversions.convert(self.CalculateMassflowRate(dBin, p, cfm, win), 'lbm/min', 'kg/s') - ntu = -1.0 * Math.log(bf) + ntu = -1.0 * Math.log(bf) # Number of Transfer Units ao = ntu * mfr return ao end - # Find the coil bypass factor at the given incoming air state (entering drybulb and wetbulb) and CFM, total capacity, and SHR. + # Calculate the coil bypass factor at the given incoming air state (entering drybulb and wetbulb) and CFM, total capacity, and SHR. + # The bypass factor is analogous to the "ineffectiveness" (1-ε) of a heat exchanger. # # Source: EnergyPlus source code # @@ -513,6 +515,8 @@ def self.CoilBypassFactor(dBin, p, qdot, cfm, shr, win) end # Calculate the coil SHR at the given incoming air state, CFM, total capacity, and coil Ao factor. + # Uses the apparatus dewpoint (ADP)/bypass factor (BF) approach described in the EnergyPlus + # Engineering Reference documentation. # # Source: EnergyPlus source code # diff --git a/HPXMLtoOpenStudio/resources/schedules.rb b/HPXMLtoOpenStudio/resources/schedules.rb index 204df02cfa..33ac32fbcb 100644 --- a/HPXMLtoOpenStudio/resources/schedules.rb +++ b/HPXMLtoOpenStudio/resources/schedules.rb @@ -6,7 +6,7 @@ class ScheduleConstant # @param sch_name [String] name that is assigned to the OpenStudio Schedule object # @param val [Double] the constant schedule value # @param schedule_type_limits_name [String] data type for the values contained in the schedule - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies def initialize(model, sch_name, val = 1.0, schedule_type_limits_name = nil, unavailable_periods: []) year = model.getYearDescription.assumedYear @schedule = create_schedule(model, sch_name, val, year, schedule_type_limits_name, unavailable_periods) @@ -23,7 +23,7 @@ def initialize(model, sch_name, val = 1.0, schedule_type_limits_name = nil, unav # @param val [Double] the constant schedule value # @param year [Integer] the calendar year # @param schedule_type_limits_name [String] data type for the values contained in the schedule - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [OpenStudio::Model::ScheduleConstant or OpenStudio::Model::ScheduleRuleset] the OpenStudio Schedule object with constant schedule def create_schedule(model, sch_name, val, year, schedule_type_limits_name, unavailable_periods) if unavailable_periods.empty? @@ -64,7 +64,7 @@ class HourlyByMonthSchedule # @param weekday_month_by_hour_values [Array>] a 12-element array of 24-element arrays of numbers # @param schedule_type_limits_name [String] data type for the values contained in the schedule # @param normalize_values [Boolean] whether to divide schedule values by the max value - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies def initialize(model, sch_name, weekday_month_by_hour_values, weekend_month_by_hour_values, schedule_type_limits_name = nil, normalize_values = true, unavailable_periods: nil) year = model.getYearDescription.assumedYear @@ -130,7 +130,7 @@ def calc_max_val() # @param sch_name [String] name that is assigned to the OpenStudio Schedule object # @param year [Integer] the calendar year # @param schedule_type_limits_name [String] data type for the values contained in the schedule - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [OpenStudio::Model::Ruleset] the OpenStudio Schedule object with rules def create_schedule(model, sch_name, year, schedule_type_limits_name, unavailable_periods) day_startm = Schedule.day_start_months(year) @@ -238,7 +238,7 @@ class HourlyByDaySchedule # @param weekday_day_by_hour_values [Array>] a 365-element array of 24-element arrays of numbers # @param weekend_day_by_hour_values [Array>] a 365-element array of 24-element arrays of numbers # @param normalize_values [Boolean] whether to divide schedule values by the max value - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies def initialize(model, sch_name, weekday_day_by_hour_values, weekend_day_by_hour_values, schedule_type_limits_name = nil, normalize_values = true, unavailable_periods: nil) year = model.getYearDescription.assumedYear @@ -306,7 +306,7 @@ def calc_max_val() # @param year [Integer] the calendar year # @param num_days [Integer] the number of days in the calendar year # @param schedule_type_limits_name [String] data type for the values contained in the schedule - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [OpenStudio::Model::Ruleset] the OpenStudio Schedule object with rules def create_schedule(model, sch_name, year, num_days, schedule_type_limits_name, unavailable_periods) time = [] @@ -417,7 +417,7 @@ class MonthWeekdayWeekendSchedule # @param begin_day [Integer] TODO # @param end_month [Integer] TODO # @param end_day [Integer] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies def initialize(model, sch_name, weekday_hourly_values, weekend_hourly_values, monthly_values, schedule_type_limits_name = nil, normalize_values = true, begin_month = 1, begin_day = 1, end_month = 12, end_day = 31, unavailable_periods: nil) @@ -540,7 +540,7 @@ def calc_sch_adjust() # @param end_month [TODO] TODO # @param end_day [TODO] TODO # @param schedule_type_limits_name [String] data type for the values contained in the schedule - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [OpenStudio::Model::ScheduleRuleset] the OpenStudio Schedule object with rules def create_schedule(model, sch_name, year, begin_month, begin_day, end_month, end_day, schedule_type_limits_name, unavailable_periods) @@ -828,9 +828,9 @@ def self.set_weekend_rule(rule) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param schedule_name [TODO] TODO - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.get_unavailable_periods(runner, schedule_name, unavailable_periods) return unavailable_periods.select { |p| Schedule.unavailable_period_applies(runner, schedule_name, p.column_name) } @@ -840,7 +840,7 @@ def self.get_unavailable_periods(runner, schedule_name, unavailable_periods) # # @param schedule [TODO] TODO # @param sch_name [String] name that is assigned to the OpenStudio Schedule object - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param year [Integer] the calendar year # @return [TODO] TODO def self.set_unavailable_periods(schedule, sch_name, unavailable_periods, year) @@ -1753,7 +1753,7 @@ def self.get_unavailable_periods_csv_data # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param schedule_name [TODO] TODO # @param col_name [TODO] TODO # @return [TODO] TODO @@ -1792,7 +1792,7 @@ def self.unavailable_period_applies(runner, schedule_name, col_name) # Ensure that the defined schedule value array (or string of numbers) is the correct length. # - # @param values [Array or String] a num_values-element array of numbers or a comma-seperated string of numbers + # @param values [Array or Array or String] a num_values-element array of numbers or a comma-separated string of numbers # @param num_values [Integer] expected number of values in the outer array # @param sch_name [String] name that is assigned to the OpenStudio Schedule object # @return [Array] a num_values-element array of numbers @@ -1907,10 +1907,10 @@ def initialize(name, used_by_unavailable_periods, can_be_stochastic, type) WholeHouseFan: Column.new('whole_house_fan', true, false, nil), } - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param schedules_paths [Array] array of file paths pointing to detailed schedule CSVs # @param year [Integer] the calendar year - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param output_path [String] the file path for which to export a single detailed schedule CSV file and also reference from OpenStudio ScheduleFile objects def initialize(runner: nil, schedules_paths:, @@ -2288,8 +2288,8 @@ def expand_schedules # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [void] def set_unavailable_periods(runner, unavailable_periods) if @unavailable_periods_csv_data.nil? diff --git a/HPXMLtoOpenStudio/resources/util.rb b/HPXMLtoOpenStudio/resources/util.rb index 8595cd105f..78583a83e7 100644 --- a/HPXMLtoOpenStudio/resources/util.rb +++ b/HPXMLtoOpenStudio/resources/util.rb @@ -1,327 +1,15 @@ # frozen_string_literal: true -# TODO -module MathTools - # TODO - # - # @param str [TODO] TODO - # @return [TODO] TODO - def self.valid_float?(str) - !!Float(str) rescue false - end - - # TODO - # - # @param x [TODO] TODO - # @param x0 [TODO] TODO - # @param x1 [TODO] TODO - # @param f0 [TODO] TODO - # @param f1 [TODO] TODO - # @return [TODO] TODO - def self.interp2(x, x0, x1, f0, f1) - ''' - Returns the linear interpolation between two results. - ''' - - return f0 + ((x - x0) / (x1 - x0)) * (f1 - f0) - end - - # TODO - # - # @param x [TODO] TODO - # @param y [TODO] TODO - # @param x1 [TODO] TODO - # @param x2 [TODO] TODO - # @param y1 [TODO] TODO - # @param y2 [TODO] TODO - # @param fx1y1 [TODO] TODO - # @param fx1y2 [TODO] TODO - # @param fx2y1 [TODO] TODO - # @param fx2y2 [TODO] TODO - # @return [TODO] TODO - def self.interp4(x, y, x1, x2, y1, y2, fx1y1, fx1y2, fx2y1, fx2y2) - ''' - Returns the bilinear interpolation between four results. - ''' - - return (fx1y1 / ((x2 - x1) * (y2 - y1))) * (x2 - x) * (y2 - y) \ - + (fx2y1 / ((x2 - x1) * (y2 - y1))) * (x - x1) * (y2 - y) \ - + (fx1y2 / ((x2 - x1) * (y2 - y1))) * (x2 - x) * (y - y1) \ - + (fx2y2 / ((x2 - x1) * (y2 - y1))) * (x - x1) * (y - y1) - end - - # TODO - # - # @param x [TODO] TODO - # @param y [TODO] TODO - # @param c [TODO] TODO - # @return [TODO] TODO - def self.biquadratic(x, y, c) - ''' - Description: - ------------ - Calculate the result of a biquadratic polynomial with independent variables - x and y, and a list of coefficients, c: - z = c[1] + c[2]*x + c[3]*x**2 + c[4]*y + c[5]*y**2 + c[6]*x*y - Inputs: - ------- - x float independent variable 1 - y float independent variable 2 - c tuple list of 6 coeffients [floats] - Outputs: - -------- - z float result of biquadratic polynomial - ''' - if c.length != 6 - fail 'Error: There must be 6 coefficients in a biquadratic polynomial' - end - - z = c[0] + c[1] * x + c[2] * x**2 + c[3] * y + c[4] * y**2 + c[5] * y * x - return z - end - - # TODO - # - # @param x [TODO] TODO - # @param c [TODO] TODO - # @return [TODO] TODO - def self.quadratic(x, c) - ''' - Description: - ------------ - Calculate the result of a quadratic polynomial with independent variable - x and a list of coefficients, c: - - y = c[1] + c[2]*x + c[3]*x**2 - - Inputs: - ------- - x float independent variable - c tuple list of 6 coeffients [floats] - - Outputs: - -------- - y float result of biquadratic polynomial - ''' - if c.size != 3 - fail 'Error: There must be 3 coefficients in a quadratic polynomial' - end - - y = c[0] + c[1] * x + c[2] * x**2 - - return y - end - - # TODO - # - # @param x [TODO] TODO - # @param y [TODO] TODO - # @param c [TODO] TODO - # @return [TODO] TODO - def self.bicubic(x, y, c) - ''' - Description: - ------------ - Calculate the result of a bicubic polynomial with independent variables - x and y, and a list of coefficients, c: - - z = c[1] + c[2]*x + c[3]*y + c[4]*x**2 + c[5]*x*y + c[6]*y**2 + \ - c[7]*x**3 + c[8]*y*x**2 + c[9]*x*y**2 + c[10]*y**3 - - Inputs: - ------- - x float independent variable 1 - y float independent variable 2 - c tuple list of 10 coeffients [floats] - - Outputs: - -------- - z float result of bicubic polynomial - ''' - if c.size != 10 - fail 'Error: There must be 10 coefficients in a bicubic polynomial' - end - - z = c[0] + c[1] * x + c[2] * x**2 + c[3] * y + c[4] * y**2 + c[5] * x * y + \ - c[6] * x**3 + c[7] * y**3 + c[8] * x**2 * y + c[9] * x * y**2 - - return z - end - - # TODO - # - # @param x0 [TODO] TODO - # @param f0 [TODO] TODO - # @param x1 [TODO] TODO - # @param f1 [TODO] TODO - # @param x2 [TODO] TODO - # @param f2 [TODO] TODO - # @param icount [TODO] TODO - # @param cvg [TODO] TODO - # @return [TODO] TODO - def self.Iterate(x0, f0, x1, f1, x2, f2, icount, cvg) - ''' - Description: - ------------ - Determine if a guess is within tolerance for convergence - if not, output a new guess using the Newton-Raphson method - Source: - ------- - Based on XITERATE f77 code in ResAC (Brandemuehl) - Inputs: - ------- - x0 float current guess value - f0 float value of function f(x) at current guess value - x1,x2 floats previous two guess values, used to create quadratic - (or linear fit) - f1,f2 floats previous two values of f(x) - icount int iteration count - cvg bool Has the iteration reached convergence? - Outputs: - -------- - x_new float new guess value - cvg bool Has the iteration reached convergence? - x1,x2 floats updated previous two guess values, used to create quadratic - (or linear fit) - f1,f2 floats updated previous two values of f(x) - Example: - -------- - # Find a value of x that makes f(x) equal to some specific value f: - # initial guess (all values of x) - x = 1.0 - x1 = x - x2 = x - # initial error - error = f - f(x) - error1 = error - error2 = error - itmax = 50 # maximum iterations - cvg = False # initialize convergence to "False" - for i in range(1,itmax+1): - error = f - f(x) - x,cvg,x1,error1,x2,error2 = \ - Iterate(x,error,x1,error1,x2,error2,i,cvg) - if cvg: - break - if cvg: - print "x converged after", i, :iterations" - else: - print "x did NOT converge after", i, "iterations" - print "x, when f(x) is", f,"is", x - ''' - - tolRel = 1e-5 - dx = 0.1 - - # Test for convergence - if (((x0 - x1).abs < tolRel * [x0.abs, Constants.small].max) && (icount != 1)) || (f0 == 0) - x_new = x0 - cvg = true - else - cvg = false - - if icount == 1 # Perturbation - mode = 1 - elsif icount == 2 # Linear fit - mode = 2 - else # Quadratic fit - mode = 3 - end - - if mode == 3 - # Quadratic fit - if x0 == x1 # If two xi are equal, use a linear fit - x1 = x2 - f1 = f2 - mode = 2 - elsif x0 == x2 # If two xi are equal, use a linear fit - mode = 2 - else - # Set up quadratic coefficients - c = ((f2 - f0) / (x2 - x0) - (f1 - f0) / (x1 - x0)) / (x2 - x1) - b = (f1 - f0) / (x1 - x0) - (x1 + x0) * c - a = f0 - (b + c * x0) * x0 - - if c.abs < Constants.small # If points are co-linear, use linear fit - mode = 2 - elsif ((a + (b + c * x1) * x1 - f1) / f1).abs > Constants.small - # If coefficients do not accurately predict data points due to - # round-off, use linear fit - mode = 2 - else - d = b**2 - 4.0 * a * c # calculate discriminant to check for real roots - if d < 0.0 # if no real roots, use linear fit - mode = 2 - else - if d > 0.0 # if real unequal roots, use nearest root to recent guess - x_new = (-b + Math.sqrt(d)) / (2 * c) - x_other = -x_new - b / c - if (x_new - x0).abs > (x_other - x0).abs - x_new = x_other - end - else # If real equal roots, use that root - x_new = -b / (2 * c) - end - - if (f1 * f0 > 0) && (f2 * f0 > 0) # If the previous two f(x) were the same sign as the new - if f2.abs > f1.abs - x2 = x1 - f2 = f1 - end - else - if f2 * f0 > 0 - x2 = x1 - f2 = f1 - end - end - x1 = x0 - f1 = f0 - end - end - end - end - - if mode == 2 - # Linear Fit - m = (f1 - f0) / (x1 - x0) - if m == 0 # If slope is zero, use perturbation - mode = 1 - else - x_new = x0 - f0 / m - x2 = x1 - f2 = f1 - x1 = x0 - f1 = f0 - end - end - - if mode == 1 - # Perturbation - if x0.abs > Constants.small - x_new = x0 * (1 + dx) - else - x_new = dx - end - x2 = x1 - f2 = f1 - x1 = x0 - f1 = f0 - end - end - return x_new, cvg, x1, f1, x2, f2 - end -end - -# Adapted from https://stackoverflow.com/questions/6934185/ruby-net-http-following-redirects +# Adapted from https://stackoverflow.com/questions/6934185/ruby-net-http-following-redirects. module UrlResolver - # TODO + # Fetch specified outfile from specified uri_str. # - # @param uri_str [TODO] TODO - # @param outfile [TODO] TODO - # @param agent [TODO] TODO - # @param max_attempts [TODO] TODO - # @param timeout [TODO] TODO - # @return [TODO] TODO + # @param uri_str [String] uniform resource identifier string + # @param outfile [Tempfile] instance of a class for managing temporary files + # @param agent [String] a string of text that a web browser sends to a web server to identify itself and provide information about the browser's capabilities + # @param max_attempts [Integer] the maximum number of attempts + # @param timeout [Integer] both the number of seconds to (1) wait for the connection to open and (2) wait for one block to be read (via one read(2) call) + # @return [void] def self.fetch(uri_str, outfile, agent = 'curl/7.43.0', max_attempts = 10, timeout = 10) attempts = 0 cookie = nil @@ -388,14 +76,14 @@ def self.fetch(uri_str, outfile, agent = 'curl/7.43.0', max_attempts = 10, timeo end end -# TODO +# Collection of methods related to file paths. module FilePath - # TODO + # Check the existence of an absolute file path, or a file path relative a given directory. # - # @param path [TODO] TODO - # @param relative_dir [TODO] TODO - # @param name [TODO] TODO - # @return [TODO] TODO + # @param path [String] the file path to check + # @param relative_dir [String] relative directory for which to check file path against + # @param name [String] the name to report in case file path does not exist + # @return [String] the absolute file path if it exists def self.check_path(path, relative_dir, name) return if path.nil? return File.absolute_path(path) if File.exist? path diff --git a/HPXMLtoOpenStudio/resources/utility_bills.rb b/HPXMLtoOpenStudio/resources/utility_bills.rb index 21d770e42a..544702fd97 100644 --- a/HPXMLtoOpenStudio/resources/utility_bills.rb +++ b/HPXMLtoOpenStudio/resources/utility_bills.rb @@ -1,11 +1,11 @@ # frozen_string_literal: true -# TODO +# Collection of methods related to getting units by fuel type, EIA average and marginal rates by state, and household consumptions by state. class UtilityBills - # TODO + # Get type of unit according to HPXML fuel type. # - # @param fuel_type [TODO] TODO - # @return [TODO] TODO + # @param fuel_type [String] HPXML fuel type + # @return [String] type of unit as stored in unit_conversions.rb def self.get_fuel_units(fuel_type) return { HPXML::FuelTypeElectricity => 'kwh', HPXML::FuelTypeNaturalGas => 'therm', @@ -16,31 +16,39 @@ def self.get_fuel_units(fuel_type) HPXML::FuelTypeWoodPellets => 'kbtu' }[fuel_type] end - # TODO + # For a given state, get either the average rate from EIA data and calculate the marginal rate or calculate the average rate from a given marginal rate. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object - # @param state_code [TODO] TODO - # @param fuel_type [TODO] TODO - # @param fixed_charge [TODO] TODO - # @param marginal_rate [TODO] TODO - # @return [TODO] TODO + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings + # @param state_code [String] State code from the HPXML file + # @param fuel_type [String] HPXML fuel type + # @param fixed_charge [Double] the monthly fixed charge (USD/month) + # @param marginal_rate [Double] the marginal flat rate (USD/kWh or USD/therm, etc.) + # @return [Array] the marginal and average rates (USD/kWh or USD/therm, etc., USD/month) def self.get_rates_from_eia_data(runner, state_code, fuel_type, fixed_charge, marginal_rate = nil) msn_codes = Constants.StateCodesMap.keys msn_codes << 'US' return unless msn_codes.include? state_code # Check if the state_code is valid average_rate = nil + if [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas].include? fuel_type household_consumption = get_household_consumption(state_code, fuel_type) - if not marginal_rate.nil? - # Calculate average rate from user-specified fixed charge, user-specified marginal rate, and EIA data + end + + if not marginal_rate.nil? + if [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas].include? fuel_type + # Calculate average rate from user-specified marginal rate, user-specified fixed charge, and EIA data average_rate = marginal_rate_to_average_rate(marginal_rate, fixed_charge, household_consumption) - else + elsif [HPXML::FuelTypeOil, HPXML::FuelTypePropane, HPXML::FuelTypeCoal, HPXML::FuelTypeWoodCord, HPXML::FuelTypeWoodPellets].include? fuel_type + # Do nothing + end + else + if [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas].include? fuel_type average_rate = get_eia_seds_rate(runner, state_code, fuel_type) marginal_rate = average_rate_to_marginal_rate(average_rate, fixed_charge, household_consumption) + elsif [HPXML::FuelTypeOil, HPXML::FuelTypePropane, HPXML::FuelTypeCoal, HPXML::FuelTypeWoodCord, HPXML::FuelTypeWoodPellets].include? fuel_type + marginal_rate = get_eia_seds_rate(runner, state_code, fuel_type) end - elsif [HPXML::FuelTypeOil, HPXML::FuelTypePropane, HPXML::FuelTypeCoal, HPXML::FuelTypeWoodCord, HPXML::FuelTypeWoodPellets].include? fuel_type - marginal_rate = get_eia_seds_rate(runner, state_code, fuel_type) end marginal_rate = marginal_rate.round(4) unless marginal_rate.nil? @@ -49,11 +57,11 @@ def self.get_rates_from_eia_data(runner, state_code, fuel_type, fixed_charge, ma return marginal_rate, average_rate end - # TODO + # Get the average household consumption (kWh or therm per home per year) by state. # - # @param state_code [TODO] TODO - # @param fuel_type [TODO] TODO - # @return [TODO] TODO + # @param state_code [String] State code from the HPXML file + # @param fuel_type [String] HPXML fuel type + # @return [Double] average household electricity or natural gas consumption (kWh/home/yr or therms/home/yr) def self.get_household_consumption(state_code, fuel_type) rows = CSV.read(File.join(File.dirname(__FILE__), '../../ReportUtilityBills/resources/simple_rates/HouseholdConsumption.csv')) rows.each do |row| @@ -67,32 +75,32 @@ def self.get_household_consumption(state_code, fuel_type) end end - # TODO + # Get the marginal rate given fixed charge and average household consumption. # - # @param average_rate [TODO] TODO - # @param fixed_charge [TODO] TODO - # @param household_consumption [TODO] TODO - # @return [TODO] TODO + # @param average_rate [Double] the fuel rate averaged over both fixed and marginal annual costs (USD/kWh or USD/therm, etc.) + # @param fixed_charge [Double] the monthly fixed charge (USD/month) + # @param household_consumption [Double] average household electricity or natural gas consumption (kWh/home/yr or therms/home/yr) + # @return [Double] the marginal flat rate (USD/kWh or USD/therm, etc.) def self.average_rate_to_marginal_rate(average_rate, fixed_charge, household_consumption) return average_rate - 12.0 * fixed_charge / household_consumption end - # TODO + # Get the average rate given fixed charge and average household consumption. # - # @param marginal_rate [TODO] TODO - # @param fixed_charge [TODO] TODO - # @param household_consumption [TODO] TODO - # @return [TODO] TODO + # @param marginal_rate [Double] the marginal flat rate (USD/kWh or USD/therm, etc.) + # @param fixed_charge [Double] the monthly fixed charge (USD/month) + # @param household_consumption [Double] average household electricity or natural gas consumption (kWh/home/yr or therms/home/yr) + # @return [Double] the fuel rate averaged over both fixed and marginal annual costs (USD/kWh or USD/therm, etc.) def self.marginal_rate_to_average_rate(marginal_rate, fixed_charge, household_consumption) return marginal_rate + 12.0 * fixed_charge / household_consumption end - # TODO + # Get the EIA SEDS prices by state and fuel type. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object - # @param state_code [TODO] TODO - # @param fuel_type [TODO] TODO - # @return [TODO] TODO + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings + # @param state_code [String] State code from the HPXML file + # @param fuel_type [String] HPXML fuel type + # @return [Double] average rate for electricity or natural gas, and marginal rate for all other fuel types (USD/kWh or USD/therm, etc.) def self.get_eia_seds_rate(runner, state_code, fuel_type) msn_code_map = { HPXML::FuelTypeElectricity => 'ESRCD', diff --git a/HPXMLtoOpenStudio/resources/waterheater.rb b/HPXMLtoOpenStudio/resources/waterheater.rb index 4a2483209c..b36cf25a73 100644 --- a/HPXMLtoOpenStudio/resources/waterheater.rb +++ b/HPXMLtoOpenStudio/resources/waterheater.rb @@ -5,7 +5,7 @@ module Waterheater # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param loc_space [TODO] TODO # @param loc_schedule [TODO] TODO # @param water_heating_system [TODO] TODO @@ -13,7 +13,7 @@ module Waterheater # @param solar_thermal_system [TODO] TODO # @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @param nbeds [Integer] Number of bedrooms in the dwelling unit # @return [TODO] TODO @@ -49,7 +49,7 @@ def self.apply_tank(model, runner, loc_space, loc_schedule, water_heating_system # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param loc_space [TODO] TODO # @param loc_schedule [TODO] TODO # @param water_heating_system [TODO] TODO @@ -57,7 +57,7 @@ def self.apply_tank(model, runner, loc_space, loc_schedule, water_heating_system # @param solar_thermal_system [TODO] TODO # @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @param nbeds [Integer] Number of bedrooms in the dwelling unit # @return [TODO] TODO @@ -94,7 +94,7 @@ def self.apply_tankless(model, runner, loc_space, loc_schedule, water_heating_sy # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param loc_space [TODO] TODO # @param loc_schedule [TODO] TODO # @param elevation [Double] Elevation of the building site (ft) @@ -104,7 +104,7 @@ def self.apply_tankless(model, runner, loc_space, loc_schedule, water_heating_sy # @param conditioned_zone [TODO] TODO # @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @param nbeds [Integer] Number of bedrooms in the dwelling unit # @return [TODO] TODO @@ -195,7 +195,7 @@ def self.apply_heatpump(model, runner, loc_space, loc_schedule, elevation, water # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param loc_space [TODO] TODO # @param loc_schedule [TODO] TODO # @param water_heating_system [TODO] TODO @@ -203,7 +203,7 @@ def self.apply_heatpump(model, runner, loc_space, loc_schedule, elevation, water # @param solar_thermal_system [TODO] TODO # @param eri_version [String] Version of the ANSI/RESNET/ICC 301 Standard to use for equations/assumptions # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @param nbeds [Integer] Number of bedrooms in the dwelling unit # @return [TODO] TODO @@ -443,13 +443,13 @@ def self.apply_solar_thermal(model, loc_space, loc_schedule, solar_thermal_syste obj_name = Constants.ObjectNameSolarHotWater - if [HPXML::SolarThermalTypeEvacuatedTube].include? solar_thermal_system.collector_type + if [HPXML::SolarThermalCollectorTypeEvacuatedTube].include? solar_thermal_system.collector_type iam_coeff2 = 0.3023 # IAM coeff1=1 by definition, values based on a system listed by SRCC with values close to the average iam_coeff3 = -0.3057 - elsif [HPXML::SolarThermalTypeSingleGlazing, HPXML::SolarThermalTypeDoubleGlazing].include? solar_thermal_system.collector_type + elsif [HPXML::SolarThermalCollectorTypeSingleGlazing, HPXML::SolarThermalCollectorTypeDoubleGlazing].include? solar_thermal_system.collector_type iam_coeff2 = 0.1 iam_coeff3 = 0 - elsif [HPXML::SolarThermalTypeICS].include? solar_thermal_system.collector_type + elsif [HPXML::SolarThermalCollectorTypeICS].include? solar_thermal_system.collector_type iam_coeff2 = 0.1 iam_coeff3 = 0 end @@ -567,7 +567,7 @@ def self.apply_solar_thermal(model, loc_space, loc_schedule, solar_thermal_syste shading_surface.setName(obj_name + ' shading surface') shading_surface.setShadingSurfaceGroup(shading_surface_group) - if solar_thermal_system.collector_type == HPXML::SolarThermalTypeICS + if solar_thermal_system.collector_type == HPXML::SolarThermalCollectorTypeICS collector_plate = OpenStudio::Model::SolarCollectorIntegralCollectorStorage.new(model) collector_plate.setName(obj_name + ' coll plate') collector_plate.setSurface(shading_surface) @@ -598,8 +598,8 @@ def self.apply_solar_thermal(model, loc_space, loc_schedule, solar_thermal_syste collector_performance.setTestFluid('Water') collector_performance.setTestFlowRate(UnitConversions.convert(coll_flow, 'cfm', 'm^3/s')) collector_performance.setTestCorrelationType('Inlet') - collector_performance.setCoefficient1ofEfficiencyEquation(solar_thermal_system.collector_frta) - collector_performance.setCoefficient2ofEfficiencyEquation(-UnitConversions.convert(solar_thermal_system.collector_frul, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)')) + collector_performance.setCoefficient1ofEfficiencyEquation(solar_thermal_system.collector_rated_optical_efficiency) + collector_performance.setCoefficient2ofEfficiencyEquation(-UnitConversions.convert(solar_thermal_system.collector_rated_thermal_losses, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)')) collector_performance.setCoefficient2ofIncidentAngleModifier(-iam_coeff2) collector_performance.setCoefficient3ofIncidentAngleModifier(iam_coeff3) @@ -625,7 +625,7 @@ def self.apply_solar_thermal(model, loc_space, loc_schedule, solar_thermal_syste storage_tank.setName(obj_name + ' storage tank') storage_tank.setSourceSideEffectiveness(heat_ex_eff) storage_tank.setTankShape('VerticalCylinder') - if (solar_thermal_system.collector_type == HPXML::SolarThermalTypeICS) || (fluid_type == Constants.FluidWater) # Use a 60 gal tank dummy tank for direct systems, storage volume for ICS is assumed to be collector volume + if (solar_thermal_system.collector_type == HPXML::SolarThermalCollectorTypeICS) || (fluid_type == Constants.FluidWater) # Use a 60 gal tank dummy tank for direct systems, storage volume for ICS is assumed to be collector volume tank_volume = UnitConversions.convert(60 * unit_multiplier, 'gal', 'm^3') else tank_volume = UnitConversions.convert(storage_volume, 'gal', 'm^3') @@ -757,7 +757,7 @@ def self.setup_hpwh_wrapped_condenser(model, obj_name_hpwh, coil, tank, fan, h_t # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param water_heating_system [TODO] TODO # @param elevation [Double] Elevation of the building site (ft) # @param obj_name_hpwh [TODO] TODO @@ -1095,7 +1095,7 @@ def self.add_hpwh_inlet_air_and_zone_heat_gain_program(model, obj_name_hpwh, loc # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param obj_name_hpwh [TODO] TODO # @param amb_temp_sensor [TODO] TODO # @param hpwh_top_element_sp [TODO] TODO @@ -1280,7 +1280,7 @@ def self.get_desuperheatercoil(water_heating_system, model) # TODO # # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param water_heating_system [TODO] TODO # @param tank [TODO] TODO # @param loc_space [TODO] TODO @@ -1931,7 +1931,7 @@ def self.create_new_schedule_manager(model, t_set_c) # @param act_vol [TODO] TODO # @param loc_space [TODO] TODO # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param ua [TODO] TODO # @param water_heating_system [TODO] TODO # @param t_set_c [TODO] TODO @@ -1941,7 +1941,7 @@ def self.create_new_schedule_manager(model, t_set_c) # @param is_dsh_storage [TODO] TODO # @param is_combi [TODO] TODO # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @param unit_multiplier [Integer] Number of similar dwelling units # @return [TODO] TODO def self.create_new_heater(name:, water_heating_system: nil, act_vol:, t_set_c: nil, loc_space:, loc_schedule: nil, model:, runner:, u: nil, ua:, eta_c: nil, is_dsh_storage: false, is_combi: false, schedules_file: nil, unavailable_periods: [], unit_multiplier: 1.0) @@ -2085,8 +2085,8 @@ def self.set_wh_ambient(loc_space, loc_schedule, wh_obj) # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files # @param t_set_c [TODO] TODO # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.configure_mixed_tank_setpoint_schedule(new_heater, schedules_file, t_set_c, model, runner, unavailable_periods) new_schedule = nil @@ -2111,8 +2111,8 @@ def self.configure_mixed_tank_setpoint_schedule(new_heater, schedules_file, t_se # @param schedules_file [SchedulesFile] SchedulesFile wrapper class instance of detailed schedule files # @param t_set_c [TODO] TODO # @param model [OpenStudio::Model::Model] OpenStudio Model object - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object - # @param unavailable_periods [HPXML::UnavailablePeriods] HPXML UnavailablePeriods object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings + # @param unavailable_periods [HPXML::UnavailablePeriods] Object that defines periods for, e.g., power outages or vacancies # @return [TODO] TODO def self.configure_stratified_tank_setpoint_schedules(new_heater, schedules_file, t_set_c, model, runner, unavailable_periods) new_schedule = nil diff --git a/HPXMLtoOpenStudio/resources/weather.rb b/HPXMLtoOpenStudio/resources/weather.rb index 440106bb74..f8e90481c6 100644 --- a/HPXMLtoOpenStudio/resources/weather.rb +++ b/HPXMLtoOpenStudio/resources/weather.rb @@ -1,29 +1,10 @@ # frozen_string_literal: true -# TODO -class WeatherHeader - ATTRS ||= [:City, :StateProvinceRegion, :Latitude, :Longitude, :Elevation, :TimeZone, :WMONumber, :DSTStartDate, :DSTEndDate, :ActualYearStartDate, :RecordsPerHour, :NumRecords] - attr_accessor(*ATTRS) -end - -# TODO -class WeatherData - ATTRS ||= [:AnnualAvgDrybulb, :AnnualMinDrybulb, :AnnualMaxDrybulb, :CDD50F, :CDD65F, :HDD50F, :HDD65F, :MonthlyAvgDrybulbs, :ShallowGroundAnnualTemp, :ShallowGroundMonthlyTemps, - :DeepGroundAnnualTemp, :DeepGroundSurfTempAmp1, :DeepGroundSurfTempAmp2, :DeepGroundPhaseShiftTempAmp1, :DeepGroundPhaseShiftTempAmp2, - :WSF, :MonthlyAvgDailyHighDrybulbs, :MonthlyAvgDailyLowDrybulbs, :MainsAnnualTemp, :MainsDailyTemps, :MainsMonthlyTemps] - attr_accessor(*ATTRS) -end - -# TODO -class WeatherDesign - ATTRS ||= [:HeatingDrybulb, :CoolingDrybulb, :CoolingHumidityRatio, :DailyTemperatureRange] - attr_accessor(*ATTRS) -end - -# TODO +# Object that stores EnergyPlus weather information (either directly sourced from the EPW or +# calculated based on the EPW data). class WeatherFile # @param epw_path [String] Path to the EPW weather file - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param hpxml [HPXML] HPXML object def initialize(epw_path:, runner:, hpxml: nil) @header = WeatherHeader.new @@ -41,12 +22,12 @@ def initialize(epw_path:, runner:, hpxml: nil) private - # TODO + # Main method that processes the EPW file to extract any information we need. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param epw_path [String] Path to the EPW weather file # @param hpxml [HPXML] HPXML object - # @return [TODO] TODO + # @return [void] def process_epw(runner, epw_path, hpxml) epw_file = OpenStudio::EpwFile.new(epw_path, true) @@ -120,30 +101,28 @@ def process_epw(runner, epw_path, hpxml) data.WSF = calc_ashrae_622_wsf(rowdata) if not epw_has_design_data - calc_design_info(runner, rowdata, data) + calc_design_info(runner, rowdata) end end - # TODO + # Calculates and stores heating/cooling degree days for different base temperatures. # - # @param dailydbs [TODO] TODO - # @return [TODO] TODO + # @param dailydbs [Array] Daily average drybulb temperatures (C) + # @return [void] def calc_heat_cool_degree_days(dailydbs) - # Calculates and stores heating/cooling degree days data.HDD65F = calc_degree_days(dailydbs, 65, true) data.HDD50F = calc_degree_days(dailydbs, 50, true) data.CDD65F = calc_degree_days(dailydbs, 65, false) data.CDD50F = calc_degree_days(dailydbs, 50, false) end - # TODO + # Calculates and returns degree days from a base temperature for either heating or cooling. # - # @param dailydbs [TODO] TODO - # @param base_temp_f [TODO] TODO - # @param is_heating [TODO] TODO - # @return [TODO] TODO + # @param dailydbs [Array] Daily average drybulb temperatures (C) + # @param base_temp_f [Double] Base drybulb temperature for the calculation (F) + # @param is_heating [Boolean] True if heating, false if cooling + # @return [Double] Degree days (deltaF) def calc_degree_days(daily_dbs, base_temp_f, is_heating) - # Calculates and returns degree days from a base temperature for either heating or cooling base_temp_c = UnitConversions.convert(base_temp_f, 'F', 'C') deg_days = [] @@ -165,16 +144,15 @@ def calc_degree_days(daily_dbs, base_temp_f, is_heating) end deg_days = deg_days.sum(0.0) - return 1.8 * deg_days + return UnitConversions.convert(deg_days, 'deltac', 'deltaf') end - # TODO + # Calculates and stores avg daily highs and lows for each month. # - # @param daily_high_dbs [TODO] TODO - # @param daily_low_dbs [TODO] TODO - # @return [TODO] TODO + # @param daily_high_dbs [Array] Daily maximum drybulb temperatures (C) + # @param daily_low_dbs [Array] Daily minimum drybulb temperatures (C) + # @return [void] def calc_avg_monthly_highs_lows(daily_high_dbs, daily_low_dbs) - # Calculates and stores avg daily highs and lows for each month data.MonthlyAvgDailyHighDrybulbs = [] data.MonthlyAvgDailyLowDrybulbs = [] @@ -199,10 +177,12 @@ def calc_avg_monthly_highs_lows(daily_high_dbs, daily_low_dbs) end end - # TODO + # Calculates the ASHRAE 62.2 Weather and Shielding Factor (WSF) value per report + # LBNL-5795E "Infiltration as Ventilation: Weather-Induced Dilution" if the value is + # not available in the ashrae_622_wsf.csv resource file. # - # @param rowdata [TODO] TODO - # @return [TODO] TODO + # @param rowdata [Array] Weather data for each EPW record + # @return [Double] WSF value def calc_ashrae_622_wsf(rowdata) require 'csv' ashrae_csv = File.join(File.dirname(__FILE__), 'data', 'ashrae_622_wsf.csv') @@ -215,23 +195,20 @@ def calc_ashrae_622_wsf(rowdata) end return wsf unless wsf.nil? - # If not available in ashrae_622_wsf.csv... - # Calculates the wSF value per report LBNL-5795E "Infiltration as Ventilation: Weather-Induced Dilution" - # Constants - c_d = 1.0 # unitless, discharge coefficient for ELA (at 4 Pa) - t_indoor = 22.0 # C, indoor setpoint year-round - n = 0.67 # unitless, pressure exponent - s = 0.7 # unitless, shelter class 4 for 1-story with flue, enhanced model - delta_p = 4.0 # Pa, pressure difference indoor-outdoor - u_min = 1.0 # m/s, minimum windspeed per hour - ela = 0.074 # m^2, effective leakage area (assumed) - cfa = 185.0 # m^2, conditioned floor area - h = 2.5 # m, single story height - g = 0.48 # unitless, wind speed multiplier for 1-story, enhanced model - c_s = 0.069 # (Pa/K)^n, stack coefficient, 1-story with flue, enhanced model - c_w = 0.142 # (Pa*s^2/m^2)^n, wind coefficient, bsmt slab 1-story with flue, enhanced model - roe = 1.2 # kg/m^3, air density (assumed at sea level) + c_d = 1.0 # discharge coefficient for ELA (at 4 Pa) (unitless) + t_indoor = 22.0 # indoor setpoint year-round (C) + n = 0.67 # pressure exponent (unitless) + s = 0.7 # shelter class 4 for 1-story with flue, enhanced model (unitless) + delta_p = 4.0 # pressure difference indoor-outdoor (Pa) + u_min = 1.0 # minimum windspeed per hour (m/s) + ela = 0.074 # effective leakage area (assumed) (m2) + cfa = 185.0 # conditioned floor area (m2) + h = 2.5 # single story height (m) + g = 0.48 # wind speed multiplier for 1-story, enhanced model (unitless) + c_s = 0.069 # stack coefficient, 1-story with flue, enhanced model ((Pa/K)^n) + c_w = 0.142 # wind coefficient, bsmt slab 1-story with flue, enhanced model ((Pa*s^2/m^2)^n) + roe = 1.2 # air density (assumed at sea level) (kg/m^3) c = c_d * ela * (2 / roe)**0.5 * delta_p**(0.5 - n) # m^3/(s*Pa^n), flow coefficient @@ -252,10 +229,10 @@ def calc_ashrae_622_wsf(rowdata) return wsf.round(2) end - # TODO + # Gets and stores various EPW header data. # # @param epw_file [OpenStudio::EpwFile] OpenStudio EpwFile object - # @return [TODO] TODO + # @return [void] def get_header_info_from_epw(epw_file) header.City = epw_file.city header.StateProvinceRegion = epw_file.stateProvinceRegion @@ -271,7 +248,7 @@ def get_header_info_from_epw(epw_file) header.DSTEndDate = epw_file.daylightSavingEndDate.get end if epw_file.startDateActualYear.is_initialized - header.ActualYearStartDate = epw_file.startDateActualYear.get + header.ActualYear = epw_file.startDateActualYear.get end header.RecordsPerHour = epw_file.recordsPerHour header.NumRecords = epw_file.data.size @@ -281,17 +258,15 @@ def get_header_info_from_epw(epw_file) end end - # TODO + # Stores design conditions from the EPW header if available. If there are multiple + # design conditions, retrieves the first one and issues a warning. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param epw_file [OpenStudio::EpwFile] OpenStudio EpwFile object - # @return [TODO] TODO + # @return [Boolean] True if the EPW file has design conditions in the header def get_design_info_from_epw(runner, epw_file) - # Retrieve design conditions from weather header epw_design_conditions = epw_file.designConditions - epw_has_design_data = false if epw_design_conditions.length > 0 - epw_has_design_data = true epw_design_condition = epw_design_conditions[0] if epw_design_conditions.length > 1 runner.registerWarning("Multiple EPW design conditions found; the first one (#{epw_design_condition.titleOfDesignCondition}) will be used.") @@ -301,18 +276,18 @@ def get_design_info_from_epw(runner, epw_file) design.DailyTemperatureRange = UnitConversions.convert(epw_design_condition.coolingDryBulbRange, 'deltaC', 'deltaF') press_psi = Psychrometrics.Pstd_fZ(header.Elevation) design.CoolingHumidityRatio = Psychrometrics.w_fT_Twb_P(design.CoolingDrybulb, UnitConversions.convert(epw_design_condition.coolingMeanCoincidentWetBulb1, 'C', 'F'), press_psi) + return true end - return epw_has_design_data + return false end - # TODO + # Calculates and stores design conditions from the EPW data. This is a fallback for + # when the EPW header does not have design conditions. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object - # @param rowdata [TODO] TODO - # @param data [TODO] TODO - # @return [TODO] TODO - def calc_design_info(runner, rowdata, data) - # Calculate design conditions from weather data + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings + # @param rowdata [Array] Weather data for each EPW record + # @return [void] + def calc_design_info(runner, rowdata) if not runner.nil? runner.registerWarning('No design condition info found; calculating design conditions from EPW weather data.') end @@ -343,13 +318,11 @@ def calc_design_info(runner, rowdata, data) design.HeatingDrybulb = UnitConversions.convert(heat99per_db, 'C', 'F') end - # TODO + # Calculates and stores shallow monthly/annual ground temperatures. + # This correlation is the same that is used in DOE-2's src\WTH.f file, subroutine GTEMP. # - # @return [TODO] TODO + # @return [void] def calc_shallow_ground_temperatures() - # Return shallow monthly/annual ground temperatures. - # This correlation is the same that is used in DOE-2's src\WTH.f file, subroutine GTEMP - amon = [15.0, 46.0, 74.0, 95.0, 135.0, 166.0, 196.0, 227.0, 258.0, 288.0, 319.0, 349.0] po = 0.6 dif = 0.025 @@ -378,14 +351,12 @@ def calc_shallow_ground_temperatures() end end - # TODO + # Stores deep ground temperature data for Xing's model if there is a ground + # source heat pump in the building. # # @param hpxml [HPXML] HPXML object - # @return [TODO] TODO + # @return [void] def calc_deep_ground_temperatures(hpxml) - # Return deep annual ground temperature. - # Annual average ground temperature using Xing's model. - # Avoid this lookup/calculation if there's no GSHP since there is a (small) runtime penalty. if !hpxml.nil? has_gshp = false @@ -423,12 +394,12 @@ def calc_deep_ground_temperatures(hpxml) data.DeepGroundPhaseShiftTempAmp2 = temperatures_amplitudes[4] # days end - # TODO + # Calculates and stores the mains water temperature using Burch & Christensen algorithm from + # "Towards Development of an Algorithm for Mains Water Temperature". # - # @param n_days [TODO] TODO - # @return [TODO] TODO + # @param n_days [Integer] Number of days (typically 365 or 366 if a leap year) in the EPW file + # @return [void] def calc_mains_temperatures(n_days) - # Algorithm based on Burch & Christensen "Towards Development of an Algorithm for Mains Water Temperature" deg_rad = Math::PI / 180 tmains_ratio = 0.4 + 0.01 * (data.AnnualAvgDrybulb - 44) @@ -457,3 +428,53 @@ def calc_mains_temperatures(n_days) data.MainsMonthlyTemps.map! { |temp| [32.0, temp].max } # ensure mains never gets below freezing. Algorithm will never provide water over boiling without a check end end + +# WeatherFile child object with EPW header data +class WeatherHeader + attr_accessor(:City, # [String] Weather station name of city + :StateProvinceRegion, # [String] Weather station state or province + :Latitude, # [Double] Weather station latitude (+/- degrees.minutes) + :Longitude, # [Double] Weather station longitude (+/- degrees.minutes) + :Elevation, # [Double] Weather station elevation (ft) + :TimeZone, # [Double] Weather station time zone (GTM +/-) + :WMONumber, # [String] Weather station World Meteorological Organization (WMO) number + :DSTStartDate, # [OpenStudio::Date] Daylight Saving start date + :DSTEndDate, # [OpenStudio::Date] Daylight Saving end date + :ActualYear, # [Integer] Calendar year if an AMY (Actual Meteorological Year) weather file + :RecordsPerHour, # [Integer] Number of EPW datapoints per hour (typically 1) + :NumRecords) # [Integer] Number of EPW datapoints (typically 8760 or 8784 if a leap year) +end + +# WeatherFile child object with data calculated based on 8760 hourly EPW data or other sources +class WeatherData + attr_accessor(:AnnualAvgDrybulb, # [Double] Annual average drybulb temperature (F) + :AnnualMinDrybulb, # [Double] Annual minimum drybulb temperature (F) + :AnnualMaxDrybulb, # [Double] Annual maximum drybulb temperature (F) + :CDD50F, # [Double] Cooling degree days using 50 F base temperature (F-days) + :CDD65F, # [Double] Cooling degree days using 65 F base temperature (F-days) + :HDD50F, # [Double] Heating degree days using 50 F base temperature (F-days) + :HDD65F, # [Double] Heating degree days using 65 F base temperature (F-days) + :MonthlyAvgDrybulbs, # [Array] Monthly average drybulb temperatures (F) + :ShallowGroundAnnualTemp, # [Double] Shallow ground annual average drybulb temperature (F) + :ShallowGroundMonthlyTemps, # [Array] Shallow ground monthly average drybulb temperatures (F) + :DeepGroundAnnualTemp, # [Double] Deep ground annual average drybulb temperature (F) + :DeepGroundSurfTempAmp1, # [Double] First ground temperature amplitude parameter for Xing model (deltaF) + :DeepGroundSurfTempAmp2, # [Double] Second ground temperature amplitude parameter for Xing model (deltaF) + :DeepGroundPhaseShiftTempAmp1, # [Double] First phase shift of surface temperature amplitude for Xing model (days) + :DeepGroundPhaseShiftTempAmp2, # [Double] Second phase shift of surface temperature amplitude for Xing model (days) + :WSF, # [Double] Weather and Shielding Factor (WSF) from ASHRAE 62.2 + :MonthlyAvgDailyHighDrybulbs, # [Array] Average daily high drybulb temperatures for each month (F) + :MonthlyAvgDailyLowDrybulbs, # [Array] Average daily low drybulb temperatures for each month (F) + :MainsAnnualTemp, # [Double] Annual average mains water temperature (F) + :MainsDailyTemps, # [Array] Daily average mains water temperatures (F) + :MainsMonthlyTemps) # [Array] Monthly average mains water temperatures (F) +end + +# WeatherFile child object with EPW data related to design load calculations +# Either taken directly directly from the EPW header or calculated based on the 8760 hourly data +class WeatherDesign + attr_accessor(:HeatingDrybulb, # [Double] 99% heating design drybulb temperature (F) + :CoolingDrybulb, # [Double] 1% cooling design drybulb temperature (F) + :CoolingHumidityRatio, # [Double] Humidity ratio corresponding to cooling mean coincident wetbulb temperature (lbm/lbm) + :DailyTemperatureRange) # [Double] Difference between daily high/low outdoor drybulb temperatures during the hottest month (deltaF) +end diff --git a/HPXMLtoOpenStudio/resources/xmlvalidator.rb b/HPXMLtoOpenStudio/resources/xmlvalidator.rb index 4eecb132f2..ac9777db6a 100644 --- a/HPXMLtoOpenStudio/resources/xmlvalidator.rb +++ b/HPXMLtoOpenStudio/resources/xmlvalidator.rb @@ -34,9 +34,9 @@ def self.validate_against_schema(hpxml_path, validator) # # @param hpxml_path [String] Path to the HPXML file # @param validator [OpenStudio::XMLValidator] OpenStudio XMLValidator object - # @param hpxml_doc [Oga::XML::Element] Root XML element of the HPXML document + # @param hpxml_element [Oga::XML::Element] Root XML element of the HPXML document # @return [Array, Array>] list of error messages, list of warning messages - def self.validate_against_schematron(hpxml_path, validator, hpxml_doc) + def self.validate_against_schematron(hpxml_path, validator, hpxml_element) errors, warnings = [], [] validator.validate(hpxml_path) if validator.fullValidationReport.is_initialized @@ -60,7 +60,7 @@ def self.validate_against_schematron(hpxml_path, validator, hpxml_doc) msg_txt = XMLHelper.get_value(n, 'svrl:text', :string) # Try to retrieve SystemIdentifier - context_element = hpxml_doc.xpath(current_context.gsub('h:', ''))[current_context_idx] + context_element = hpxml_element.xpath(current_context.gsub('h:', ''))[current_context_idx] if context_element.nil? fail "Could not find element at xpath '#{current_context}' with index #{current_context_idx}." end diff --git a/HPXMLtoOpenStudio/tests/test_airflow.rb b/HPXMLtoOpenStudio/tests/test_airflow.rb index f62e537a0e..675e6c5841 100644 --- a/HPXMLtoOpenStudio/tests/test_airflow.rb +++ b/HPXMLtoOpenStudio/tests/test_airflow.rb @@ -243,7 +243,7 @@ def test_mechanical_ventilation_supply # Get HPXML values vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation } - vent_fan_cfm = vent_fan.average_total_unit_flow_rate + vent_fan_cfm = vent_fan.average_unit_flow_rate vent_fan_power = vent_fan.fan_power # Check infiltration/ventilation program @@ -267,7 +267,7 @@ def test_mechanical_ventilation_exhaust # Get HPXML values vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation } - vent_fan_cfm = vent_fan.average_total_unit_flow_rate + vent_fan_cfm = vent_fan.average_unit_flow_rate vent_fan_power = vent_fan.fan_power # Check infiltration/ventilation program @@ -291,7 +291,7 @@ def test_mechanical_ventilation_balanced # Get HPXML values vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation } - vent_fan_cfm = vent_fan.average_total_unit_flow_rate + vent_fan_cfm = vent_fan.average_unit_flow_rate vent_fan_power = vent_fan.fan_power # Check infiltration/ventilation program @@ -315,7 +315,7 @@ def test_mechanical_ventilation_erv # Get HPXML values vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation } - vent_fan_cfm = vent_fan.average_total_unit_flow_rate + vent_fan_cfm = vent_fan.average_unit_flow_rate vent_fan_power = vent_fan.fan_power # Check infiltration/ventilation program @@ -339,7 +339,7 @@ def test_mechanical_ventilation_hrv # Get HPXML values vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation } - vent_fan_cfm = vent_fan.average_total_unit_flow_rate + vent_fan_cfm = vent_fan.average_unit_flow_rate vent_fan_power = vent_fan.fan_power # Check infiltration/ventilation program @@ -458,7 +458,7 @@ def test_multiple_mechvent model, _hpxml, hpxml_bldg = _test_measure(args_hash) # Get HPXML values - vent_fans = hpxml_bldg.ventilation_fans.select { |f| !f.is_cfis_supplemental_fan? } + vent_fans = hpxml_bldg.ventilation_fans.select { |f| !f.is_cfis_supplemental_fan } vent_fans.each do |vent_fan| vent_fan.hours_in_operation = 24.0 if vent_fan.hours_in_operation.nil? end @@ -473,16 +473,16 @@ def test_multiple_mechvent whole_fans = vent_fans.select { |f| f.used_for_whole_building_ventilation } vent_fan_sup = whole_fans.select { |f| f.fan_type == HPXML::MechVentTypeSupply } - vent_fan_cfm_sup = vent_fan_sup.map { |f| f.average_total_unit_flow_rate }.sum(0.0) + vent_fan_cfm_sup = vent_fan_sup.map { |f| f.average_unit_flow_rate }.sum(0.0) vent_fan_power_sup = vent_fan_sup.map { |f| f.average_unit_fan_power }.sum(0.0) vent_fan_exh = whole_fans.select { |f| f.fan_type == HPXML::MechVentTypeExhaust } - vent_fan_cfm_exh = vent_fan_exh.map { |f| f.average_total_unit_flow_rate }.sum(0.0) + vent_fan_cfm_exh = vent_fan_exh.map { |f| f.average_unit_flow_rate }.sum(0.0) vent_fan_power_exh = vent_fan_exh.map { |f| f.average_unit_fan_power }.sum(0.0) vent_fan_bal = whole_fans.select { |f| f.fan_type == HPXML::MechVentTypeBalanced } - vent_fan_cfm_bal = vent_fan_bal.map { |f| f.average_total_unit_flow_rate }.sum(0.0) + vent_fan_cfm_bal = vent_fan_bal.map { |f| f.average_unit_flow_rate }.sum(0.0) vent_fan_power_bal = vent_fan_bal.map { |f| f.average_unit_fan_power }.sum(0.0) vent_fan_ervhrv = whole_fans.select { |f| [HPXML::MechVentTypeERV, HPXML::MechVentTypeHRV].include?(f.fan_type) } - vent_fan_cfm_ervhrv = vent_fan_ervhrv.map { |f| f.average_total_unit_flow_rate }.sum(0.0) + vent_fan_cfm_ervhrv = vent_fan_ervhrv.map { |f| f.average_unit_flow_rate }.sum(0.0) vent_fan_power_ervhrv = vent_fan_ervhrv.map { |f| f.average_unit_fan_power }.sum(0.0) vent_fan_cfis = whole_fans.select { |f| f.fan_type == HPXML::MechVentTypeCFIS } vent_fan_cfm_cfis = vent_fan_cfis.map { |f| f.oa_unit_flow_rate }.sum(0.0) @@ -534,9 +534,9 @@ def test_shared_mechvent_multiple vent_fans_precool = hpxml_bldg.ventilation_fans.select { |f| (not f.precooling_fuel.nil?) } vent_fans_tot_pow_noncfis = hpxml_bldg.ventilation_fans.select { |f| f.fan_type != HPXML::MechVentTypeCFIS }.map { |f| f.average_unit_fan_power }.sum(0.0) # total cfms - vent_fans_cfm_tot_sup = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeSupply }.map { |f| f.average_total_unit_flow_rate }.sum(0.0) - vent_fans_cfm_tot_exh = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeExhaust }.map { |f| f.average_total_unit_flow_rate }.sum(0.0) - vent_fans_cfm_tot_ervhrvbal = hpxml_bldg.ventilation_fans.select { |f| [HPXML::MechVentTypeERV, HPXML::MechVentTypeHRV, HPXML::MechVentTypeBalanced].include? f.fan_type }.map { |f| f.average_total_unit_flow_rate }.sum(0.0) + vent_fans_cfm_tot_sup = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeSupply }.map { |f| f.average_unit_flow_rate }.sum(0.0) + vent_fans_cfm_tot_exh = hpxml_bldg.ventilation_fans.select { |f| f.fan_type == HPXML::MechVentTypeExhaust }.map { |f| f.average_unit_flow_rate }.sum(0.0) + vent_fans_cfm_tot_ervhrvbal = hpxml_bldg.ventilation_fans.select { |f| [HPXML::MechVentTypeERV, HPXML::MechVentTypeHRV, HPXML::MechVentTypeBalanced].include? f.fan_type }.map { |f| f.average_unit_flow_rate }.sum(0.0) # preconditioned mech vent oa cfms vent_fans_cfm_oa_preheat_sup = vent_fans_preheat.select { |f| f.fan_type == HPXML::MechVentTypeSupply }.map { |f| f.average_oa_unit_flow_rate }.sum(0.0) vent_fans_cfm_oa_precool_sup = vent_fans_precool.select { |f| f.fan_type == HPXML::MechVentTypeSupply }.map { |f| f.average_oa_unit_flow_rate }.sum(0.0) diff --git a/HPXMLtoOpenStudio/tests/test_defaults.rb b/HPXMLtoOpenStudio/tests/test_defaults.rb index 7b86e425af..de47cee932 100644 --- a/HPXMLtoOpenStudio/tests/test_defaults.rb +++ b/HPXMLtoOpenStudio/tests/test_defaults.rb @@ -3134,7 +3134,7 @@ def test_hot_water_distribution # Test defaults w/ recirculation & conditioned basement hpxml, hpxml_bldg = _create_hpxml('base-dhw-recirc-demand.xml') - hpxml_bldg.hot_water_distributions[0].recirculation_piping_length = nil + hpxml_bldg.hot_water_distributions[0].recirculation_piping_loop_length = nil hpxml_bldg.hot_water_distributions[0].recirculation_branch_piping_length = nil hpxml_bldg.hot_water_distributions[0].recirculation_pump_power = nil hpxml_bldg.hot_water_distributions[0].pipe_r_value = nil @@ -5210,7 +5210,7 @@ def _test_default_hydronic_distribution_values(hpxml_bldg, manualj_hot_water_pip def _test_default_mech_vent_values(hpxml_bldg, is_shared_system, hours_in_operation, fan_power, flow_rate, cfis_vent_mode_airflow_fraction = nil, cfis_addtl_runtime_operating_mode = nil) - vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation && !f.is_cfis_supplemental_fan? } + vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation && !f.is_cfis_supplemental_fan } assert_equal(is_shared_system, vent_fan.is_shared_system) assert_equal(hours_in_operation, vent_fan.hours_in_operation) @@ -5229,7 +5229,7 @@ def _test_default_mech_vent_values(hpxml_bldg, is_shared_system, hours_in_operat end def _test_default_mech_vent_suppl_values(hpxml_bldg, is_shared_system, hours_in_operation, fan_power, flow_rate) - vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation && f.is_cfis_supplemental_fan? } + vent_fan = hpxml_bldg.ventilation_fans.find { |f| f.used_for_whole_building_ventilation && f.is_cfis_supplemental_fan } assert_equal(is_shared_system, vent_fan.is_shared_system) if hours_in_operation.nil? @@ -5326,7 +5326,7 @@ def _test_default_standard_distribution_values(hot_water_distribution, piping_le end def _test_default_recirc_distribution_values(hot_water_distribution, piping_length, branch_piping_length, pump_power, pipe_r_value, weekday_sch, weekend_sch, monthly_mults) - assert_in_epsilon(piping_length, hot_water_distribution.recirculation_piping_length, 0.01) + assert_in_epsilon(piping_length, hot_water_distribution.recirculation_piping_loop_length, 0.01) assert_in_epsilon(branch_piping_length, hot_water_distribution.recirculation_branch_piping_length, 0.01) assert_in_epsilon(pump_power, hot_water_distribution.recirculation_pump_power, 0.01) assert_equal(pipe_r_value, hot_water_distribution.pipe_r_value) diff --git a/HPXMLtoOpenStudio/tests/test_validation.rb b/HPXMLtoOpenStudio/tests/test_validation.rb index 1baf5c3c78..796d94b118 100644 --- a/HPXMLtoOpenStudio/tests/test_validation.rb +++ b/HPXMLtoOpenStudio/tests/test_validation.rb @@ -1169,22 +1169,22 @@ def test_ruby_error_messages distribution_system_idref: hpxml_bldg.hvac_distributions[0].id) elsif ['cfis-invalid-supplemental-fan'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-mechvent-cfis-supplemental-fan-exhaust.xml') - suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan? } + suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan } suppl_fan.fan_type = HPXML::MechVentTypeBalanced elsif ['cfis-invalid-supplemental-fan2'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-mechvent-cfis-supplemental-fan-exhaust.xml') - suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan? } + suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan } suppl_fan.used_for_whole_building_ventilation = false suppl_fan.used_for_garage_ventilation = true elsif ['cfis-invalid-supplemental-fan3'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-mechvent-cfis-supplemental-fan-exhaust.xml') - suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan? } + suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan } suppl_fan.is_shared_system = true suppl_fan.fraction_recirculation = 0.0 suppl_fan.in_unit_flow_rate = suppl_fan.tested_flow_rate / 2.0 elsif ['cfis-invalid-supplemental-fan4'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-mechvent-cfis-supplemental-fan-exhaust.xml') - suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan? } + suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan } suppl_fan.hours_in_operation = 12.0 elsif ['dehumidifier-setpoints'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-appliances-dehumidifier-multiple.xml') @@ -1538,38 +1538,38 @@ def test_ruby_error_messages elsif ['solar-thermal-system-with-combi-tankless'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-dhw-combi-tankless.xml') hpxml_bldg.solar_thermal_systems.add(id: "SolarThermalSystem#{hpxml_bldg.solar_thermal_systems.size + 1}", - system_type: HPXML::SolarThermalSystemType, + system_type: HPXML::SolarThermalSystemTypeHotWater, collector_area: 40, - collector_type: HPXML::SolarThermalTypeSingleGlazing, + collector_type: HPXML::SolarThermalCollectorTypeSingleGlazing, collector_loop_type: HPXML::SolarThermalLoopTypeIndirect, collector_azimuth: 180, collector_tilt: 20, - collector_frta: 0.77, - collector_frul: 0.793, + collector_rated_optical_efficiency: 0.77, + collector_rated_thermal_losses: 0.793, water_heating_system_idref: 'WaterHeatingSystem1') elsif ['solar-thermal-system-with-desuperheater'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-dhw-desuperheater.xml') hpxml_bldg.solar_thermal_systems.add(id: "SolarThermalSystem#{hpxml_bldg.solar_thermal_systems.size + 1}", - system_type: HPXML::SolarThermalSystemType, + system_type: HPXML::SolarThermalSystemTypeHotWater, collector_area: 40, - collector_type: HPXML::SolarThermalTypeSingleGlazing, + collector_type: HPXML::SolarThermalCollectorTypeSingleGlazing, collector_loop_type: HPXML::SolarThermalLoopTypeIndirect, collector_azimuth: 180, collector_tilt: 20, - collector_frta: 0.77, - collector_frul: 0.793, + collector_rated_optical_efficiency: 0.77, + collector_rated_thermal_losses: 0.793, water_heating_system_idref: 'WaterHeatingSystem1') elsif ['solar-thermal-system-with-dhw-indirect'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base-dhw-combi-tankless.xml') hpxml_bldg.solar_thermal_systems.add(id: "SolarThermalSystem#{hpxml_bldg.solar_thermal_systems.size + 1}", - system_type: HPXML::SolarThermalSystemType, + system_type: HPXML::SolarThermalSystemTypeHotWater, collector_area: 40, - collector_type: HPXML::SolarThermalTypeSingleGlazing, + collector_type: HPXML::SolarThermalCollectorTypeSingleGlazing, collector_loop_type: HPXML::SolarThermalLoopTypeIndirect, collector_azimuth: 180, collector_tilt: 20, - collector_frta: 0.77, - collector_frul: 0.793, + collector_rated_optical_efficiency: 0.77, + collector_rated_thermal_losses: 0.793, water_heating_system_idref: 'WaterHeatingSystem1') elsif ['storm-windows-unexpected-window-ufactor'].include? error_case hpxml, hpxml_bldg = _create_hpxml('base.xml') @@ -1791,7 +1791,7 @@ def test_ruby_warning_messages # Create HPXML object if ['cfis-undersized-supplemental-fan'].include? warning_case hpxml, hpxml_bldg = _create_hpxml('base-mechvent-cfis-supplemental-fan-exhaust.xml') - suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan? } + suppl_fan = hpxml_bldg.ventilation_fans.find { |f| f.is_cfis_supplemental_fan } suppl_fan.tested_flow_rate = 90.0 elsif ['duct-lto-cfm25'].include? warning_case hpxml, hpxml_bldg = _create_hpxml('base-atticroof-conditioned.xml') diff --git a/HPXMLtoOpenStudio/tests/test_water_heater.rb b/HPXMLtoOpenStudio/tests/test_water_heater.rb index 9c4a800e81..3fd2b0a55c 100644 --- a/HPXMLtoOpenStudio/tests/test_water_heater.rb +++ b/HPXMLtoOpenStudio/tests/test_water_heater.rb @@ -488,7 +488,7 @@ def test_solar_direct_evacuated_tube ther_eff = 1.0 iam_coeff2 = 0.3023 iam_coeff3 = -0.3057 - collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_frul, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') + collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_rated_thermal_losses, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') storage_tank_volume = 0.2271 storage_tank_height = UnitConversions.convert(4.5, 'ft', 'm') storage_tank_u = 0.0 @@ -519,7 +519,7 @@ def test_solar_direct_evacuated_tube collector = model.getSolarCollectorFlatPlateWaters[0] collector_performance = collector.solarCollectorPerformance assert_in_epsilon(collector_area, collector_performance.grossArea, 0.001) - assert_in_epsilon(solar_thermal_system.collector_frta, collector_performance.coefficient1ofEfficiencyEquation, 0.001) + assert_in_epsilon(solar_thermal_system.collector_rated_optical_efficiency, collector_performance.coefficient1ofEfficiencyEquation, 0.001) assert_in_epsilon(collector_coeff_2, collector_performance.coefficient2ofEfficiencyEquation, 0.001) assert_in_epsilon(-iam_coeff2, collector_performance.coefficient2ofIncidentAngleModifier.get, 0.001) assert_in_epsilon(iam_coeff3, collector_performance.coefficient3ofIncidentAngleModifier.get, 0.001) @@ -561,7 +561,7 @@ def test_solar_direct_flat_plate ther_eff = 1.0 iam_coeff2 = 0.1 iam_coeff3 = 0 - collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_frul, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') + collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_rated_thermal_losses, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') storage_tank_volume = 0.2271 storage_tank_height = UnitConversions.convert(4.5, 'ft', 'm') storage_tank_u = 0.0 @@ -592,7 +592,7 @@ def test_solar_direct_flat_plate collector = model.getSolarCollectorFlatPlateWaters[0] collector_performance = collector.solarCollectorPerformance assert_in_epsilon(collector_area, collector_performance.grossArea, 0.001) - assert_in_epsilon(solar_thermal_system.collector_frta, collector_performance.coefficient1ofEfficiencyEquation, 0.001) + assert_in_epsilon(solar_thermal_system.collector_rated_optical_efficiency, collector_performance.coefficient1ofEfficiencyEquation, 0.001) assert_in_epsilon(collector_coeff_2, collector_performance.coefficient2ofEfficiencyEquation, 0.001) assert_in_epsilon(-iam_coeff2, collector_performance.coefficient2ofIncidentAngleModifier.get, 0.001) assert_in_epsilon(iam_coeff3, collector_performance.coefficient3ofIncidentAngleModifier.get, 0.001) @@ -634,7 +634,7 @@ def test_solar_indirect_flat_plate ther_eff = 1.0 iam_coeff2 = 0.1 iam_coeff3 = 0 - collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_frul, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') + collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_rated_thermal_losses, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') storage_tank_volume = UnitConversions.convert(solar_thermal_system.storage_volume, 'gal', 'm^3') storage_tank_height = UnitConversions.convert(4.5, 'ft', 'm') storage_tank_u = UnitConversions.convert(0.1, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') @@ -665,7 +665,7 @@ def test_solar_indirect_flat_plate collector = model.getSolarCollectorFlatPlateWaters[0] collector_performance = collector.solarCollectorPerformance assert_in_epsilon(collector_area, collector_performance.grossArea, 0.001) - assert_in_epsilon(solar_thermal_system.collector_frta, collector_performance.coefficient1ofEfficiencyEquation, 0.001) + assert_in_epsilon(solar_thermal_system.collector_rated_optical_efficiency, collector_performance.coefficient1ofEfficiencyEquation, 0.001) assert_in_epsilon(collector_coeff_2, collector_performance.coefficient2ofEfficiencyEquation, 0.001) assert_in_epsilon(-iam_coeff2, collector_performance.coefficient2ofIncidentAngleModifier.get, 0.001) assert_in_epsilon(iam_coeff3, collector_performance.coefficient3ofIncidentAngleModifier.get, 0.001) @@ -707,7 +707,7 @@ def test_solar_thermosyphon_flat_plate ther_eff = 1.0 iam_coeff2 = 0.1 iam_coeff3 = 0 - collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_frul, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') + collector_coeff_2 = -UnitConversions.convert(solar_thermal_system.collector_rated_thermal_losses, 'Btu/(hr*ft^2*F)', 'W/(m^2*K)') storage_tank_volume = 0.2271 storage_tank_height = UnitConversions.convert(4.5, 'ft', 'm') storage_tank_u = 0.0 @@ -738,7 +738,7 @@ def test_solar_thermosyphon_flat_plate collector = model.getSolarCollectorFlatPlateWaters[0] collector_performance = collector.solarCollectorPerformance assert_in_epsilon(collector_area, collector_performance.grossArea, 0.001) - assert_in_epsilon(solar_thermal_system.collector_frta, collector_performance.coefficient1ofEfficiencyEquation, 0.001) + assert_in_epsilon(solar_thermal_system.collector_rated_optical_efficiency, collector_performance.coefficient1ofEfficiencyEquation, 0.001) assert_in_epsilon(collector_coeff_2, collector_performance.coefficient2ofEfficiencyEquation, 0.001) assert_in_epsilon(-iam_coeff2, collector_performance.coefficient2ofIncidentAngleModifier.get, 0.001) assert_in_epsilon(iam_coeff3, collector_performance.coefficient3ofIncidentAngleModifier.get, 0.001) diff --git a/ReportSimulationOutput/measure.rb b/ReportSimulationOutput/measure.rb index cf97400cdc..6d9bfd2061 100644 --- a/ReportSimulationOutput/measure.rb +++ b/ReportSimulationOutput/measure.rb @@ -312,7 +312,7 @@ def outputs # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param arguments [TODO] TODO # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [TODO] TODO @@ -331,7 +331,7 @@ def get_arguments(runner, arguments, user_arguments) # Return a vector of IdfObject's to request EnergyPlus objects needed by the run method. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [Array] array of OpenStudio IdfObject objects def energyPlusOutputRequests(runner, user_arguments) @@ -543,7 +543,7 @@ def energyPlusOutputRequests(runner, user_arguments) # Define what happens when the measure is run. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [Boolean] true if successful def run(runner, user_arguments) @@ -740,7 +740,7 @@ def rollup_timeseries_output_to_daily_or_monthly(timeseries_output, timeseries_f # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param args [Hash] Map of :argument_name => value # @return [TODO] TODO def get_outputs(runner, args) @@ -1480,7 +1480,7 @@ def check_for_errors(runner, outputs) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param outputs [TODO] TODO # @param args [Hash] Map of :argument_name => value # @param annual_output_path [TODO] TODO @@ -1660,7 +1660,7 @@ def report_runperiod_output_results(runner, outputs, args, annual_output_path) # TODO # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param outputs [TODO] TODO # @param args [Hash] Map of :argument_name => value # @param timestamps_dst [TODO] TODO diff --git a/ReportSimulationOutput/measure.xml b/ReportSimulationOutput/measure.xml index d93ad02d41..c159f345de 100644 --- a/ReportSimulationOutput/measure.xml +++ b/ReportSimulationOutput/measure.xml @@ -3,8 +3,8 @@ 3.1 report_simulation_output df9d170c-c21a-4130-866d-0d46b06073fd - 21d8c18f-64f5-4b1d-b7ac-8d8caea4d92c - 2024-07-08T15:46:17Z + cad8b6ff-ed40-494a-8c8e-948499029726 + 2024-07-12T14:33:32Z 9BF1E6AC ReportSimulationOutput HPXML Simulation Output Report @@ -1929,7 +1929,7 @@ measure.rb rb script - F59BC96C + 9728288E test_report_sim_output.rb diff --git a/ReportUtilityBills/measure.rb b/ReportUtilityBills/measure.rb index 9f667bfaf3..aefdda9489 100644 --- a/ReportUtilityBills/measure.rb +++ b/ReportUtilityBills/measure.rb @@ -151,7 +151,7 @@ def check_for_next_type_warnings(utility_bill_scenario) # Return a vector of IdfObject's to request EnergyPlus objects needed by the run method. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [Array] array of OpenStudio IdfObject objects def energyPlusOutputRequests(runner, user_arguments) @@ -227,7 +227,7 @@ def energyPlusOutputRequests(runner, user_arguments) # Register to the runner each warning. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param warnings [Array] array of warnings # @return [Boolean] true if any warnings were registered def register_warnings(runner, warnings) @@ -241,7 +241,7 @@ def register_warnings(runner, warnings) # Define what happens when the measure is run. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param user_arguments [OpenStudio::Measure::OSArgumentMap] OpenStudio measure arguments # @return [Boolean] true if successful def run(runner, user_arguments) @@ -404,7 +404,7 @@ def get_timestamps(args) # Write and/or register to the runner the calculated runperiod utility bills. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param args [Hash] Map of :argument_name => value # @param utility_bills [Hash] Fuel type => UtilityRate object # @param annual_output_path [String] the file path containing annual utility bills @@ -467,7 +467,7 @@ def get_monthly_output_results(args, utility_bills, bill_scenario_name, monthly_ # Write and/or register to the runner the calculated monthly utility bills. # - # @param runner [OpenStudio::Measure::OSRunner] OpenStudio Runner object + # @param runner [OpenStudio::Measure::OSRunner] Object typically used to display warnings # @param args [Hash] Map of :argument_name => value # @param timestamps [Array] array of monthly timestamps (e.g., 2007-01-01T00:00:00) # @param monthly_data [Array] lines of monthly utility bill data diff --git a/ReportUtilityBills/measure.xml b/ReportUtilityBills/measure.xml index 1b8f623a48..a067601655 100644 --- a/ReportUtilityBills/measure.xml +++ b/ReportUtilityBills/measure.xml @@ -3,8 +3,8 @@ 3.1 report_utility_bills ca88a425-e59a-4bc4-af51-c7e7d1e960fe - b155cc01-3ea6-4b3e-a133-a1b508261be5 - 2024-07-02T19:47:36Z + e7a1eb0f-f485-45ad-9448-2e5f6c145c5f + 2024-07-17T17:05:04Z 15BF4E57 ReportUtilityBills Utility Bills Report @@ -180,7 +180,7 @@ measure.rb rb script - 5ECE5EAB + DE8B3221 detailed_rates/Sample Flat Rate Min Annual Charge.json @@ -306,7 +306,7 @@ util.rb rb resource - 6990D619 + 0B994914 Contains Demand Charges.json @@ -348,7 +348,7 @@ test_report_utility_bills.rb rb test - 99536BCB + B05DF20C diff --git a/ReportUtilityBills/resources/util.rb b/ReportUtilityBills/resources/util.rb index ba7df45990..5323295194 100644 --- a/ReportUtilityBills/resources/util.rb +++ b/ReportUtilityBills/resources/util.rb @@ -3,7 +3,7 @@ # Object that stores collections of EnergyPlus meter names, units, and timeseries data. class Fuel # @param meters [Array] array of EnergyPlus meter names - # @param units [String] fuel units of type HPXML::FuelTypeXXX + # @param units [String] fuel units (HPXML::FuelTypeXXX) def initialize(meters: [], units:) @meters = meters @timeseries = [] diff --git a/ReportUtilityBills/tests/test_report_utility_bills.rb b/ReportUtilityBills/tests/test_report_utility_bills.rb index 5b8e57d354..76033b4cd6 100644 --- a/ReportUtilityBills/tests/test_report_utility_bills.rb +++ b/ReportUtilityBills/tests/test_report_utility_bills.rb @@ -1,7 +1,6 @@ # frozen_string_literal: true require 'oga' -require_relative '../../HPXMLtoOpenStudio/resources/utility_bills' require_relative '../../HPXMLtoOpenStudio/resources/constants' require_relative '../../HPXMLtoOpenStudio/resources/energyplus' require_relative '../../HPXMLtoOpenStudio/resources/hpxml' @@ -9,6 +8,7 @@ require_relative '../../HPXMLtoOpenStudio/resources/minitest_helper' require_relative '../../HPXMLtoOpenStudio/resources/schedules' require_relative '../../HPXMLtoOpenStudio/resources/unit_conversions' +require_relative '../../HPXMLtoOpenStudio/resources/utility_bills' require_relative '../../HPXMLtoOpenStudio/resources/xmlhelper' require_relative '../../HPXMLtoOpenStudio/resources/version' require_relative '../resources/util.rb' @@ -284,19 +284,28 @@ def test_workflow_detailed_calculations_all_electric def test_auto_marginal_rate fuel_types = [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas, HPXML::FuelTypeOil, HPXML::FuelTypeCoal, HPXML::FuelTypePropane, HPXML::FuelTypeWoodCord, HPXML::FuelTypeWoodPellets] - # Check that we can successfully look up "auto" rates for every state - # and every fuel type. + # Check that we can successfully look up "auto" rates for every state and every fuel type. Constants.StateCodesMap.keys.each do |state_code| fuel_types.each do |fuel_type| - flatratebuy, _ = UtilityBills.get_rates_from_eia_data(nil, state_code, fuel_type, 0) + flatratebuy, average_rate = UtilityBills.get_rates_from_eia_data(nil, state_code, fuel_type, 1) # fixed_charge > 0 ensures marginal_rate != average_rate refute_nil(flatratebuy) + if [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas].include? fuel_type + assert_operator(flatratebuy, :<, average_rate) + else + assert_nil(average_rate) + end end end # Check that we can successfully look up "auto" rates for the US too. fuel_types.each do |fuel_type| - flatratebuy, _ = UtilityBills.get_rates_from_eia_data(nil, 'US', fuel_type, 0) + flatratebuy, average_rate = UtilityBills.get_rates_from_eia_data(nil, 'US', fuel_type, 1) # fixed_charge > 0 ensures marginal_rate != average_rate refute_nil(flatratebuy) + if [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas].include? fuel_type + assert_operator(flatratebuy, :<, average_rate) + else + assert_nil(average_rate) + end end # Check that any other state code is gracefully handled (no error) @@ -305,6 +314,35 @@ def test_auto_marginal_rate end end + def test_specified_marginal_rate + fuel_types = [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas, HPXML::FuelTypeOil, HPXML::FuelTypeCoal, HPXML::FuelTypePropane, HPXML::FuelTypeWoodCord, HPXML::FuelTypeWoodPellets] + marginal_rate = 0.1 + + # Check that we can successfully provide rates for every state and every fuel type. + Constants.StateCodesMap.keys.each do |state_code| + fuel_types.each do |fuel_type| + flatratebuy, average_rate = UtilityBills.get_rates_from_eia_data(nil, state_code, fuel_type, 1, marginal_rate) # fixed_charge > 0 ensures marginal_rate != average_rate + assert_equal(flatratebuy, marginal_rate) + if [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas].include? fuel_type + assert_operator(flatratebuy, :<, average_rate) + else + assert_nil(average_rate) + end + end + end + + # Check that we can successfully provide rates for the US too. + fuel_types.each do |fuel_type| + flatratebuy, average_rate = UtilityBills.get_rates_from_eia_data(nil, 'US', fuel_type, 1, marginal_rate) # fixed_charge > 0 ensures marginal_rate != average_rate + assert_equal(flatratebuy, marginal_rate) + if [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas].include? fuel_type + assert_operator(flatratebuy, :<, average_rate) + else + assert_nil(average_rate) + end + end + end + def test_warning_dse @args_hash['hpxml_path'] = File.absolute_path(@tmp_hpxml_path) hpxml = HPXML.new(hpxml_path: File.join(@sample_files_path, 'base-hvac-dse.xml')) diff --git a/docs/source/workflow_inputs.rst b/docs/source/workflow_inputs.rst index 625ee174df..ae7448f4fb 100644 --- a/docs/source/workflow_inputs.rst +++ b/docs/source/workflow_inputs.rst @@ -1707,7 +1707,7 @@ If the skylight has a curb, additional information is entered in ``Skylight``. =========================================== ======== ============ =========== ======== ======== ======================================================== Element Type Units Constraints Required Default Notes =========================================== ======== ============ =========== ======== ======== ======================================================== - ``extension/Curb/Area`` double ft^2 > 0 Yes Total area including all sides + ``extension/Curb/Area`` double ft2 > 0 Yes Total area including all sides ``extension/Curb/AssemblyEffectiveRValue`` double F-ft2-hr/Btu > 0 Yes Assembly R-value [#]_ =========================================== ======== ============ =========== ======== ======== ======================================================== @@ -1723,7 +1723,7 @@ If the skylight has a shaft, additional information is entered in ``Skylight``. =========================================== ======== ============ =========== ======== ======== ======================================================== Element Type Units Constraints Required Default Notes =========================================== ======== ============ =========== ======== ======== ======================================================== - ``extension/Shaft/Area`` double ft^2 > 0 Yes Total area including all sides + ``extension/Shaft/Area`` double ft2 > 0 Yes Total area including all sides ``extension/Shaft/AssemblyEffectiveRValue`` double F-ft2-hr/Btu > 0 Yes Assembly R-value [#]_ =========================================== ======== ============ =========== ======== ======== ======================================================== @@ -2169,7 +2169,7 @@ Each central air conditioner is entered as a ``/HPXML/Building/BuildingDetails/S ``CoolingSystemFuel`` string electricity Yes Fuel type ``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 + ``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 [#]_ ``SensibleHeatFraction`` double frac > 0.5, <= 1 No See [#]_ Sensible heat fraction ``CoolingDetailedPerformanceData`` element No Cooling detailed performance data [#]_ @@ -3506,7 +3506,7 @@ Each central fan integrated supply (CFIS) system is entered as a ``/HPXML/Buildi ``HoursInOperation`` double hrs/day >= 0, <= 24 false 8 Hours per day of operation [#]_ ``FanPower`` double W >= 0 No See [#]_ Fan power ``AttachedToHVACDistributionSystem`` idref See [#]_ Yes ID of attached distribution system - ``extension/VentilationOnlyModeAirflowFraction`` double >= 0, <= 1 No 1.0 Blower airflow rate fraction during ventilation only mode [#]_ + ``extension/VentilationOnlyModeAirflowFraction`` double frac >= 0, <= 1 No 1.0 Blower airflow rate fraction during ventilation only mode [#]_ ============================================================================================= ======== ======= ============================= ======== =============== ========================================= .. [#] All other UsedFor... elements (i.e., ``UsedForLocalVentilation``, ``UsedForSeasonalCoolingLoadReduction``, ``UsedForGarageVentilation``) must be omitted or false. @@ -4483,11 +4483,11 @@ If the RatedAnnualkWh or EnergyFactor is provided, a complete set of EnergyGuide ======================== ======= ======= =========== ======== ======= ================================== Element Type Units Constraints Required Default Notes ======================== ======= ======= =========== ======== ======= ================================== + ``PlaceSettingCapacity`` integer # > 0 Yes Number of place settings ``LabelElectricRate`` double $/kWh > 0 Yes EnergyGuide label electricity rate ``LabelGasRate`` double $/therm > 0 Yes EnergyGuide label natural gas rate ``LabelAnnualGasCost`` double $ > 0 Yes EnergyGuide label annual gas cost ``LabelUsage`` double cyc/wk > 0 Yes EnergyGuide label number of cycles - ``PlaceSettingCapacity`` integer # > 0 Yes Number of place settings ======================== ======= ======= =========== ======== ======= ================================== Dishwasher energy use and hot water use is calculated per the Energy Rating Rated Home in `ANSI/RESNET/ICC 301-2019 Addendum A `_. diff --git a/tasks.rb b/tasks.rb index f9fa1868bc..0d13832022 100644 --- a/tasks.rb +++ b/tasks.rb @@ -331,7 +331,7 @@ def apply_hpxml_modification_sample_files(hpxml_path, hpxml) # --------------------- # # General logic for all files - hpxml_bldg.site.fuels = [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas] + hpxml_bldg.site.available_fuels = [HPXML::FuelTypeElectricity, HPXML::FuelTypeNaturalGas] # Logic that can only be applied based on the file name if ['base-schedules-simple.xml', @@ -2036,7 +2036,7 @@ def apply_hpxml_modification_sample_files(hpxml_path, hpxml) related_hvac_idref: 'HeatingSystem1', temperature: 125.0) hpxml_bldg.solar_thermal_systems.add(id: "SolarThermalSystem#{hpxml_bldg.solar_thermal_systems.size + 1}", - system_type: HPXML::SolarThermalSystemType, + system_type: HPXML::SolarThermalSystemTypeHotWater, water_heating_system_idref: nil, # Apply to all water heaters solar_fraction: 0.65) end diff --git a/workflow/tests/base_results/results_simulations_hvac.csv b/workflow/tests/base_results/results_simulations_hvac.csv index acc0309e7c..127f97f2d5 100644 --- a/workflow/tests/base_results/results_simulations_hvac.csv +++ b/workflow/tests/base_results/results_simulations_hvac.csv @@ -421,7 +421,7 @@ base-simcontrol-timestep-10-mins-occupancy-stochastic-10-mins.xml,6.8,91.76,3600 base-simcontrol-timestep-10-mins-occupancy-stochastic-60-mins.xml,6.8,91.76,36000.0,24000.0,0.0,31783.0,8654.0,7508.0,0.0,575.0,6571.0,0.0,0.0,1738.0,2171.0,4566.0,0.0,0.0,19895.0,6102.0,7037.0,0.0,207.0,321.0,0.0,0.0,0.0,2293.0,615.0,0.0,3320.0,0.0,0.0,147.0,0.0,-653.0,0.0,800.0 base-simcontrol-timestep-10-mins.xml,6.8,91.76,36000.0,24000.0,0.0,31783.0,8654.0,7508.0,0.0,575.0,6571.0,0.0,0.0,1738.0,2171.0,4566.0,0.0,0.0,19895.0,6102.0,7037.0,0.0,207.0,321.0,0.0,0.0,0.0,2293.0,615.0,0.0,3320.0,0.0,0.0,147.0,0.0,-653.0,0.0,800.0 base-simcontrol-timestep-30-mins.xml,6.8,91.76,36000.0,24000.0,0.0,31783.0,8654.0,7508.0,0.0,575.0,6571.0,0.0,0.0,1738.0,2171.0,4566.0,0.0,0.0,19895.0,6102.0,7037.0,0.0,207.0,321.0,0.0,0.0,0.0,2293.0,615.0,0.0,3320.0,0.0,0.0,147.0,0.0,-653.0,0.0,800.0 -base-zones-spaces-multiple.xml,6.8,91.76,36000.0,24000.0,0.0,30312.0,8922.0,5506.0,0.0,575.0,6835.0,0.0,0.0,1738.0,2171.0,4566.0,0.0,0.0,16662.0,3478.0,5579.0,0.0,207.0,571.0,0.0,0.0,0.0,2293.0,615.0,0.0,3920.0,0.0,0.0,447.0,0.0,-653.0,0.0,1100.0 +base-zones-spaces-multiple.xml,6.8,91.76,36000.0,24000.0,0.0,30328.0,8938.0,5506.0,0.0,575.0,6835.0,0.0,0.0,1738.0,2171.0,4566.0,0.0,0.0,16594.0,3409.0,5579.0,0.0,207.0,571.0,0.0,0.0,0.0,2293.0,615.0,0.0,3920.0,0.0,0.0,447.0,0.0,-653.0,0.0,1100.0 base-zones-spaces.xml,6.8,91.76,36000.0,24000.0,0.0,30396.0,9005.0,5506.0,0.0,575.0,6835.0,0.0,0.0,1738.0,2171.0,4566.0,0.0,0.0,16611.0,3426.0,5579.0,0.0,207.0,571.0,0.0,0.0,0.0,2293.0,615.0,0.0,3920.0,0.0,0.0,447.0,0.0,-653.0,0.0,1100.0 base.xml,6.8,91.76,36000.0,24000.0,0.0,31783.0,8654.0,7508.0,0.0,575.0,6571.0,0.0,0.0,1738.0,2171.0,4566.0,0.0,0.0,19895.0,6102.0,7037.0,0.0,207.0,321.0,0.0,0.0,0.0,2293.0,615.0,0.0,3320.0,0.0,0.0,147.0,0.0,-653.0,0.0,800.0 house001.xml,25.88,98.42,90000.0,60000.0,0.0,62814.0,24252.0,7740.0,0.0,1014.0,7822.0,453.0,766.0,9187.0,2236.0,9343.0,0.0,0.0,58147.0,28634.0,10583.0,0.0,781.0,5966.0,299.0,576.0,0.0,3975.0,3541.0,0.0,3780.0,0.0,12.0,7152.0,3503.0,2449.0,0.0,1200.0 diff --git a/workflow/tests/util.rb b/workflow/tests/util.rb index fc5a034a82..b59887f11b 100644 --- a/workflow/tests/util.rb +++ b/workflow/tests/util.rb @@ -891,7 +891,7 @@ def _verify_outputs(rundir, hpxml_path, results, hpxml, unit_multiplier) assert_equal(hpxml_bldg.total_fraction_cool_load_served > 0, clg_energy > 0) # Mechanical Ventilation - whole_vent_fans = hpxml_bldg.ventilation_fans.select { |vent_mech| vent_mech.used_for_whole_building_ventilation && !vent_mech.is_cfis_supplemental_fan? } + whole_vent_fans = hpxml_bldg.ventilation_fans.select { |vent_mech| vent_mech.used_for_whole_building_ventilation && !vent_mech.is_cfis_supplemental_fan } local_vent_fans = hpxml_bldg.ventilation_fans.select { |vent_mech| vent_mech.used_for_local_ventilation } fan_cfis_with_addl_runtime = whole_vent_fans.select { |vent_mech| vent_mech.fan_type == HPXML::MechVentTypeCFIS && vent_mech.cfis_addtl_runtime_operating_mode != HPXML::CFISModeNone } fan_sup = whole_vent_fans.select { |vent_mech| vent_mech.fan_type == HPXML::MechVentTypeSupply }