From 04ec7c9fc9d70bb94f20514f6800c1fac3ce1b96 Mon Sep 17 00:00:00 2001 From: Weili Xu Date: Mon, 23 Oct 2023 12:50:07 -0700 Subject: [PATCH 1/5] update water use equipment for user data --- .../ashrae_90_1_prm/ashrae_90_1_prm.Model.rb | 110 ++++++++++++++++++ .../ashrae_90_1_prm/ashrae_90_1_prm.rb | 78 ++++++++++++- .../userdata_csv/ashrae_90_1_prm.UserData.rb | 48 ++++++++ .../userdata_wateruse_equipment.csv | 2 +- 4 files changed, 236 insertions(+), 2 deletions(-) diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb index 1ed65ed05c..c0bbcaa57b 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb @@ -1426,9 +1426,119 @@ def handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_bui handle_thermal_zone_user_input_data(model) # load electric equipment user data handle_electric_equipment_user_input_data(model) + # load water use connection user data + handle_wateruse_connections_user_input_data(model) + # load water use equipment user data + handle_wateruse_equipment_user_input_data(model) + # load water use equipment definition user data + handle_wateruse_equipment_definition_user_input_data(model) return true end + # A function to load water use equipment definition from user data csv files + # The file name is userdata_wateruse_equipment_definition.csv + # @param [OpenStudio::Model::Model] model + def handle_wateruse_equipment_definition_user_input_data(model) + user_data_wateruse_equipment_definition = get_userdata(UserDataFiles::WATERUSE_EQUIPMENT_DEFINITION) + model.getWaterUseEquipmentDefinitions.each do |wateruse_equipment| + if user_data_wateruse_equipment_definition + user_data_updated = false + user_data_wateruse_equipment_definition.each do |user_wateruse| + next unless UserData.compare(wateruse_equipment.name.get, user_wateruse['name']) + + peak_flow_rate = prm_read_user_data(user_wateruse, 'peak_flow_rate', nil) + if peak_flow_rate + wateruse_equipment.additionalProperties.setFeature('peak_flow_rate', peak_flow_rate) + end + + flow_rate_fraction_schedule_name = prm_read_user_data(user_wateruse, 'flow_rate_fraction_schedule', '') + # verify the schedule exist in the model + prm_raise(model.getScheduleRulesetByName(flow_rate_fraction_schedule_name) || + model.getScheduleCompactByName(flow_rate_fraction_schedule_name) || + model.getScheduleConstantByName(flow_rate_fraction_schedule_name), + @sizing_run_dir, + "Cannot find #{flow_rate_fraction_schedule_name} in the model. Note, such schedule shall be one of the following type: RuleSet, Compact and Constant") + wateruse_equipment.additionalProperties.setFeature('flow_rate_fraction_schedule', flow_rate_fraction_schedule_name) + + target_temperature_schedule_name = prm_read_user_data(user_wateruse, 'target_temperature_schedule', '') + # verify the schedule exist in the model + prm_raise(model.getScheduleRulesetByName(target_temperature_schedule_name) || + model.getScheduleCompactByName(target_temperature_schedule_name) || + model.getScheduleConstantByName(target_temperature_schedule_name), + @sizing_run_dir, + "Cannot find #{target_temperature_schedule_name} in the model. Note, such schedule shall be one of the following type: RuleSet, Compact and Constant") + wateruse_equipment.additionalProperties.setFeature('target_temperature_schedule', target_temperature_schedule_name) + user_data_updated = true + end + unless user_data_updated + OpenStudio.logFree(OpenStudio::Info, 'prm.log', "WaterUseConnections name #{wateruse_equipment.name.get} was not found in user data file: #{UserDataFiles::WATERUSE_EQUIPMENT_DEFINITION}; No user data applied.") + end + end + end + end + + # A function to load water use equipment from user data csv files + # The file name is userdata_wateruse_equipment.csv + # @param [OpenStudio::Model::Model] model + def handle_wateruse_equipment_user_input_data(model) + user_data_wateruse_equipment = get_userdata(UserDataFiles::WATERUSE_EQUIPMENT) + model.getWaterUseEquipments.each do |wateruse_equipment| + if user_data_wateruse_equipment + user_data_updated = false + user_data_wateruse_equipment.each do |user_wateruse| + next unless UserData.compare(wateruse_equipment.name.get, user_wateruse['name']) + + building_type_swh = prm_read_user_data(user_wateruse, 'building_type_swh', nil) + if building_type_swh + wateruse_equipment.additionalProperties.setFeature('building_type_swh', building_type_swh) + end + user_data_updated = true + end + + unless user_data_updated + OpenStudio.logFree(OpenStudio::Info, 'prm.log', "WaterUseEquipment name #{wateruse_equipment.name.get} was not found in user data file: #{UserDataFiles::WATERUSE_EQUIPMENT}; No user data applied.") + end + end + end + end + + # A function to load water use connections schedules from user data csv files + # The file name is userdata_wateruse_connections.csv + # @param [OpenStudio::Model::Model] model + def handle_wateruse_connections_user_input_data(model) + user_data_wateruse_connections = get_userdata(UserDataFiles::WATERUSE_CONNECTIONS) + model.getWaterUseConnectionss.each do |wateruse_connections| + if user_data_wateruse_connections + user_data_updated = false + user_data_wateruse_connections.each do |user_wateruse| + next unless UserData.compare(wateruse_connections.name.get, user_wateruse['name']) + + hot_water_supply_temperature_schedule_name = prm_read_user_data(user_wateruse, 'hot_water_supply_temperature_schedule', '') + # verify the schedule exist in the model + prm_raise(model.getScheduleRulesetByName(hot_water_supply_temperature_schedule_name) || + model.getScheduleCompactByName(hot_water_supply_temperature_schedule_name) || + model.getScheduleConstantByName(hot_water_supply_temperature_schedule_name), + @sizing_run_dir, + "Cannot find #{hot_water_supply_temperature_schedule_name} in the model. Note, such schedule shall be one of the following type: RuleSet, Compact and Constant") + wateruse_connections.additionalProperties.setFeature('hot_water_supply_temperature_schedule', hot_water_supply_temperature_schedule_name) + + cold_water_supply_temperature_schedule_name = prm_read_user_data(user_wateruse, 'cold_water_supply_temperature_schedule', '') + # verify the schedule exist in the model + prm_raise(model.getScheduleRulesetByName(cold_water_supply_temperature_schedule_name) || + model.getScheduleCompactByName(cold_water_supply_temperature_schedule_name) || + model.getScheduleConstantByName(cold_water_supply_temperature_schedule_name), + @sizing_run_dir, + "Cannot find #{cold_water_supply_temperature_schedule_name} in the model. Note, such schedule shall be one of the following type: RuleSet, Compact and Constant") + wateruse_connections.additionalProperties.setFeature('cold_water_supply_temperature_schedule', cold_water_supply_temperature_schedule_name) + user_data_updated = true + end + unless user_data_updated + OpenStudio.logFree(OpenStudio::Info, 'prm.log', "WaterUseConnections name #{wateruse_connections.name.get} was not found in user data file: #{UserDataFiles::WATERUSE_CONNECTIONS}; No user data applied.") + end + end + end + end + # A function to load exterior lighting data from user data csv files # The file name is userdata_exterior_lighting.csv # @param [OpenStudio::Model::Model] model diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb index fbdf56035b..3e8705ebf1 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb @@ -29,7 +29,10 @@ def generate_userdata_to_csv(user_model, user_data_path, user_data_file = nil) UserDataCSVExteriorLights.new(user_model, user_data_path), UserDataCSVThermalZone.new(user_model, user_data_path), UserDataCSVElectricEquipment.new(user_model, user_data_path), - UserDataCSVOutdoorAir.new(user_model, user_data_path)] + UserDataCSVOutdoorAir.new(user_model, user_data_path), + UserDataWaterUseConnection.new(user_model, user_data_path), + UserDataWaterUseEquipment.new(user_model, user_data_path), + UserDataWaterUseEquipmentDefinition.new(user_model, user_data_path)] if user_data_file.nil? user_data_list.each(&:write_csv) @@ -169,6 +172,12 @@ def user_data_validation(object_name, user_data) return check_userdata_airloop_hvac_doas(object_name, user_data) when UserDataFiles::THERMAL_ZONE return check_userdata_thermal_zone(object_name, user_data) + when UserDataFiles::WATERUSE_CONNECTIONS + return check_userdata_wateruse_connections(object_name, user_data) + when UserDataFiles::WATERUSE_EQUIPMENT + return check_userdata_wateruse_equipment(object_name, user_data) + when UserDataFiles::WATERUSE_EQUIPMENT_DEFINITION + return check_userdata_wateruse_equipment_definition(object_name, user_data) else return true end @@ -491,4 +500,71 @@ def check_userdata_space_and_spacetype(object_name, user_data) end return userdata_valid end + + # Check for incorrect data in water use connections + + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + + # @return [Boolean] true if data is valid, false if error found + def check_userdata_wateruse_connections(object_name, user_data) + userdata_valid = true + user_data.each do |row| + name = prm_read_user_data(row, 'name') + unless name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: water use connection name is missing or empty. user data is not validated.") + return false + end + end + return userdata_valid + end + + # Check for incorrect data in water use equipment + + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + + # @return [Boolean] true if data is valid, false if error found + def check_userdata_wateruse_equipment(object_name, user_data) + userdata_valid = true + user_data.each do |row| + name = prm_read_user_data(row, 'name') + unless name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: water use equipment name is missing or empty. user data is not validated.") + return false + end + + building_swh_type = prm_read_user_data(row, 'building_type_swh', nil) + # gas phase air cleaning is system base - add proposed hvac system name to zones + unless building_swh_type.nil? || UserDataSHWBldgType.matched_any?(building_swh_type) + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, water equipment name #{name}, building_type_swh shall be one of the string listed in https://pnnl.github.io/BEM-for-PRM/user_guide/prm_api_ref/baseline_generation_api/#--default_swh_bldg_type. Got #{building_swh_type}") + userdata_valid = false + end + end + return userdata_valid + end + + # Check for incorrect data in water use equipment definition + + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + + # @return [Boolean] true if data is valid, false if error found + def check_userdata_wateruse_equipment_definition(object_name, user_data) + userdata_valid = true + user_data.each do |row| + name = prm_read_user_data(row, 'name') + unless name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: water use equipment name is missing or empty. user data is not validated.") + return false + end + # check for data type + peak_flow_rate = prm_read_user_data(row, 'peak_flow_rate', nil) + unless peak_flow_rate.nil? || Float(peak_flow_rate, exception: false) + userdata_valid = false + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: water use equipment definition #{name}'s peak flow rate shall be a float, Got #{peak_flow_rate}.") + end + end + return userdata_valid + end end diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb index 1431d0e232..eb935fd2c3 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb @@ -226,3 +226,51 @@ def write_default_rows return Array.new(@headers.length - 1, '') end end + +class UserDataWaterUseConnection < UserDataCSV + # user data userdata_wateruse_connections + # @param model [OpenStudio::Model::Model] + # @param save_dir [String] directory to save user data files + def initialize(model, save_dir) + super + @component_name = 'WaterUseConnections' + @file_name = UserDataFiles::WATERUSE_CONNECTIONS + end + + def write_default_rows + # @todo we can do more here but right now, keep everything unchecked. + return Array.new(@headers.length - 1, '') + end +end + +class UserDataWaterUseEquipment < UserDataCSV + # user data userdata_wateruse_equipment + # @param model [OpenStudio::Model::Model] + # @param save_dir [String] directory to save user data files + def initialize(model, save_dir) + super + @component_name = 'WaterUseEquipment' + @file_name = UserDataFiles::WATERUSE_EQUIPMENT + end + + def write_default_rows + # @todo we can do more here but right now, keep everything unchecked. + return Array.new(@headers.length - 1, '') + end +end + +class UserDataWaterUseEquipmentDefinition < UserDataCSV + # user data userdata_wateruse_equipment + # @param model [OpenStudio::Model::Model] + # @param save_dir [String] directory to save user data files + def initialize(model, save_dir) + super + @component_name = 'WaterUseEquipmentDefinition' + @file_name = UserDataFiles::WATERUSE_EQUIPMENT_DEFINITION + end + + def write_default_rows + # @todo we can do more here but right now, keep everything unchecked. + return Array.new(@headers.length - 1, '') + end +end diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_wateruse_equipment.csv b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_wateruse_equipment.csv index bd03239213..92c847fda9 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_wateruse_equipment.csv +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/userdata_wateruse_equipment.csv @@ -1 +1 @@ -name,bulding_type_swh +name,building_type_swh From 8c55e4203b2dc56a5392b6d09c9fc472212991ae Mon Sep 17 00:00:00 2001 From: Weili Xu Date: Tue, 31 Oct 2023 11:51:18 -0700 Subject: [PATCH 2/5] add lights --- .../ashrae_90_1_prm/ashrae_90_1_prm.Model.rb | 41 +++++++++++++++++++ .../ashrae_90_1_prm/ashrae_90_1_prm.rb | 29 ++++++++++++- .../userdata_csv/ashrae_90_1_prm.UserData.rb | 16 ++++++++ 3 files changed, 85 insertions(+), 1 deletion(-) diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb index c0bbcaa57b..0c2f579c05 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb @@ -1416,6 +1416,8 @@ def handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_bui handle_airloop_user_input_data(model) # exterior lighting handler handle_exterior_lighting_user_input_data(model) + # load lights data from user data + handle_lights_user_input_data(model) # load OA data from user data handle_outdoor_air_user_input_data(model) # load air loop DOAS user data from the proposed model @@ -1435,6 +1437,45 @@ def handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_bui return true end + # A function to load lights from user data csv files + # The file name is userdata_lights.csv + # @param [OpenStudio::Model::Model] model + def handle_lights_user_input_data(model) + user_lights = get_userdata(UserDataFiles::LIGHTS) + model.getLightss.each do |light| + if user_lights + user_data_updated = false + user_lights.each do |user_light| + next unless UserData.compare(light.name.get, user_light['name']) + + has_retail_display_exception = prm_read_user_data(user_light, 'has_retail_display_exception') + if has_retail_display_exception + light.additionalProperties.setFeature('has_retail_display_exception', true) + else + light.additionalProperties.setFeature('has_retail_display_exception', false) + end + + has_unregulated_exception = prm_read_user_data(user_light, 'has_unregulated_exception') + if has_unregulated_exception + light.additionalProperties.setFeature('has_unregulated_exception', true) + else + light.additionalProperties.setFeature('has_unregulated_exception', false) + end + + unregulated_category = prm_read_user_data(user_light, 'unregulated_category') + if unregulated_category + light.additionalProperties.setFeature('unregulated_category', unregulated_category) + end + + user_data_updated = true + end + unless user_data_updated + OpenStudio.logFree(OpenStudio::Info, 'prm.log', "WaterUseConnections name #{light.name.get} was not found in user data file: #{UserDataFiles::LIGHTS}; No user data applied.") + end + end + end + end + # A function to load water use equipment definition from user data csv files # The file name is userdata_wateruse_equipment_definition.csv # @param [OpenStudio::Model::Model] model diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb index 3e8705ebf1..007c02de6d 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb @@ -162,6 +162,8 @@ def user_data_validation(object_name, user_data) return check_userdata_space_and_spacetype(object_name, user_data) when UserDataFiles::ELECTRIC_EQUIPMENT return check_userdata_electric_equipment(object_name, user_data) + when UserDataFiles::LIGHTS + return check_userdata_lights(object_name, user_data) when UserDataFiles::EXTERIOR_LIGHTS return check_userdata_exterior_lighting(object_name, user_data) when UserDataFiles::AIRLOOP_HVAC @@ -183,6 +185,31 @@ def user_data_validation(object_name, user_data) end end + def check_userdata_lights(object_name, user_data) + userdata_valid = true + user_data.each do |user_light| + name = prm_read_user_data(user_light, 'name') + unless name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: lights name is missing or empty. Lights user data has not validated.") + return false + end + + has_retail_display_exception = prm_read_user_data(user_light, 'has_retail_display_exception') + unless has_retail_display_exception.nil? || UserDataBoolean.matched_any?(has_retail_display_exception) + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Lights name #{name}, has_retail_display_exception shall be either True or False. Got #{has_retail_display_exception}") + userdata_valid = false + end + + has_unregulated_exception = prm_read_user_data(user_light, 'has_unregulated_exception') + unless has_unregulated_exception.nil? || UserDataBoolean.matched_any?(has_unregulated_exception) + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Lights name #{name}, has_unregulated_exception shall be either True or False. Got #{has_unregulated_exception}") + userdata_valid = false + end + end + # do we need to regulate the unregulated_category? + return userdata_valid + end + def check_userdata_building(object_name, user_data) userdata_valid = true user_data.each do |user_building| @@ -227,7 +254,7 @@ def check_userdata_thermal_zone(object_name, user_data) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: thermal zone name is missing or empty. Thermal zone user data has not validated.") return false end - has_health_safety_night_cycle_exception = prm_read_user_data(user_thermal_zone, 'has_health_safety_night_cycle_exception', UserDataBoolean::FALSE) + has_health_safety_night_cycle_exception = prm_read_user_data(user_thermal_zone, 'has_health_safety_night_cycle_exception') unless has_health_safety_night_cycle_exception.nil? || UserDataBoolean.matched_any?(has_health_safety_night_cycle_exception) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Thermal zone name #{name}, has_health_safety_night_cycle_exception shall be either True or False. Got #{has_health_safety_night_cycle_exception}") userdata_valid = false diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb index eb935fd2c3..ab2061d7e3 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb @@ -89,6 +89,22 @@ def write_default_rows end end +class UserDataLights < UserDataCSV + # user data userdata_lights + # @param model [OpenStudio::Model::Model] + # @param save_dir [String] directory to save user data files + def initialize(model, save_dir) + super + @component_name = 'Lights' + @file_name = UserDataFiles::LIGHTS + end + + def write_default_rows + # @todo we can do more here but right now, keep everything unchecked. + return Array.new(@headers.length - 1, '') + end +end + class UserDataCSVBuilding < UserDataCSV # user data userdata_building # @param model [OpenStudio::Model::Model] From a1f0874d47133b3d1ff78ec3995b70370fe2a674 Mon Sep 17 00:00:00 2001 From: Weili Xu Date: Tue, 31 Oct 2023 12:55:41 -0700 Subject: [PATCH 3/5] Add gas equipment --- .../ashrae_90_1_prm/ashrae_90_1_prm.Model.rb | 39 +++++++++++- .../ashrae_90_1_prm/ashrae_90_1_prm.rb | 61 +++++++++++++++++++ .../userdata_csv/ashrae_90_1_prm.UserData.rb | 40 ++++++++++-- 3 files changed, 134 insertions(+), 6 deletions(-) diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb index 0c2f579c05..1f58864b8a 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb @@ -1428,6 +1428,8 @@ def handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_bui handle_thermal_zone_user_input_data(model) # load electric equipment user data handle_electric_equipment_user_input_data(model) + # load gas equipment user data + handle_gas_equipment_user_input_data(model) # load water use connection user data handle_wateruse_connections_user_input_data(model) # load water use equipment user data @@ -1448,14 +1450,14 @@ def handle_lights_user_input_data(model) user_lights.each do |user_light| next unless UserData.compare(light.name.get, user_light['name']) - has_retail_display_exception = prm_read_user_data(user_light, 'has_retail_display_exception') + has_retail_display_exception = prm_read_user_data(user_light, 'has_retail_display_exception', false) if has_retail_display_exception light.additionalProperties.setFeature('has_retail_display_exception', true) else light.additionalProperties.setFeature('has_retail_display_exception', false) end - has_unregulated_exception = prm_read_user_data(user_light, 'has_unregulated_exception') + has_unregulated_exception = prm_read_user_data(user_light, 'has_unregulated_exception', false) if has_unregulated_exception light.additionalProperties.setFeature('has_unregulated_exception', true) else @@ -1660,6 +1662,12 @@ def handle_electric_equipment_user_input_data(model) user_data_plug_load.each do |user_plug_load| next unless UserData.compare(elevator_equipment.name.get, user_plug_load['name']) + fraction_of_controlled_receptacles = prm_read_user_data(user_plug_load, 'fraction_of_controlled_receptacles', '0.0').to_f + elevator_equipment.additionalProperties.setFeature('fraction_of_controlled_receptacles', fraction_of_controlled_receptacles) + + receptacle_power_savings = prm_read_user_data(user_plug_load, 'receptacle_power_savings', '0.0').to_f + elevator_equipment.additionalProperties.setFeature('receptacle_power_savings', receptacle_power_savings) + num_lifts = prm_read_user_data(user_plug_load, 'elevator_number_of_lifts', '0').to_i if num_lifts > 0 elevator_equipment.additionalProperties.setFeature('elevator_number_of_lifts', num_lifts) @@ -1688,6 +1696,33 @@ def handle_electric_equipment_user_input_data(model) end end + # A function to load gas equipment csv files + # The file name is userdata_gas_equipment.csv + # @param [OpenStudio::Model::Model] model + def handle_gas_equipment_user_input_data(model) + user_data_gas_equipment = get_userdata(UserDataFiles::GAS_EQUIPMENT) + model.getGasEquipments.each do |gas_equipment| + if user_data_gas_equipment + user_data_updated = false + user_data_gas_equipment.each do |user_gas_equipment| + next unless UserData.compare(gas_equipment.name.get, user_gas_equipment['name']) + + fraction_of_controlled_receptacles = prm_read_user_data(user_gas_equipment, 'fraction_of_controlled_receptacles', '0.0').to_f + prm_raise(fraction_of_controlled_receptacles > 1.0, 'The fraction of all controlled receptacles cannot be higher than 1.0') + gas_equipment.additionalProperties.setFeature('fraction_of_controlled_receptacles', fraction_of_controlled_receptacles) + + receptacle_power_savings = prm_read_user_data(user_gas_equipment, 'receptacle_power_savings', '0.0').to_f + gas_equipment.additionalProperties.setFeature('receptacle_power_savings', receptacle_power_savings) + user_data_updated = true + end + + unless user_data_updated + OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Gas equipment name #{gas_equipment.name.get} was not found in user data file: #{UserDataFiles::GAS_EQUIPMENT}; No user data applied.") + end + end + end + end + # A function to load outdoor air data from user data csv files # The file name is userdata_design_specification_outdoor_air.csv # @param [OpenStudio::Model::Model] model diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb index 007c02de6d..102fb9a827 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb @@ -27,8 +27,10 @@ def generate_userdata_to_csv(user_model, user_data_path, user_data_file = nil) UserDataCSVSpaceTypes.new(user_model, user_data_path), UserDataCSVAirLoopHVACDOAS.new(user_model, user_data_path), UserDataCSVExteriorLights.new(user_model, user_data_path), + UserDataCSVLights.new(user_model, user_data_path), UserDataCSVThermalZone.new(user_model, user_data_path), UserDataCSVElectricEquipment.new(user_model, user_data_path), + UserDataCSVGasEquipment.new(user_model, user_data_path), UserDataCSVOutdoorAir.new(user_model, user_data_path), UserDataWaterUseConnection.new(user_model, user_data_path), UserDataWaterUseEquipment.new(user_model, user_data_path), @@ -162,6 +164,8 @@ def user_data_validation(object_name, user_data) return check_userdata_space_and_spacetype(object_name, user_data) when UserDataFiles::ELECTRIC_EQUIPMENT return check_userdata_electric_equipment(object_name, user_data) + when UserDataFiles::GAS_EQUIPMENT + return check_userdata_gas_equipment(object_name, user_data) when UserDataFiles::LIGHTS return check_userdata_lights(object_name, user_data) when UserDataFiles::EXTERIOR_LIGHTS @@ -185,6 +189,10 @@ def user_data_validation(object_name, user_data) end end + # Check for incorrect data in [UserDataFiles::LIGHTS] + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + # @return [Boolean] true if data is valid, false if error found def check_userdata_lights(object_name, user_data) userdata_valid = true user_data.each do |user_light| @@ -210,6 +218,10 @@ def check_userdata_lights(object_name, user_data) return userdata_valid end + # Check for incorrect data in [UserDataFiles::BUILDING] + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + # @return [Boolean] true if data is valid, false if error found def check_userdata_building(object_name, user_data) userdata_valid = true user_data.each do |user_building| @@ -246,6 +258,10 @@ def check_userdata_building(object_name, user_data) return userdata_valid end + # Check for incorrect data in [UserDataFiles::THERMAL_ZONE] + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + # @return [Boolean] true if data is valid, false if error found def check_userdata_thermal_zone(object_name, user_data) userdata_valid = true user_data.each do |user_thermal_zone| @@ -426,6 +442,35 @@ def check_userdata_exterior_lighting(object_name, user_data) return userdata_valid end + # Check for incorrect data in gas equipment user data + + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + + # @return [Boolean] true if data is valid, false if error found + def check_userdata_gas_equipment(object_name, user_data) + userdata_valid = true + user_data.each do |gas_row| + name = prm_read_user_data(gas_row, 'name') + unless name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: gas equipoment name is missing or empty. Gas equipment user data has not validated.") + return false + end + # check for fractions + fraction_of_controlled_receptacles = prm_read_user_data(gas_row, 'fraction_of_controlled_receptacles') + unless fraction_of_controlled_receptacles.nil? || Float(fraction_of_controlled_receptacles, exception: false) + userdata_valid = false + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: gas equipment definition #{name}'s fraction of controlled receptacles shall be a float, Got #{fraction_of_controlled_receptacles}.") + end + receptacle_power_savings = prm_read_user_data(gas_row, 'receptacle_power_savings') + unless receptacle_power_savings.nil? || Float(receptacle_power_savings, exception: false) + userdata_valid = false + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: gas equipment definition #{name}'s receptacle power savings shall be a float, Got #{receptacle_power_savings}.") + end + end + return userdata_valid + end + # Check for incorrect data in electric equipment user data # @param object_name [String] name of user data csv file to check @@ -435,6 +480,22 @@ def check_userdata_exterior_lighting(object_name, user_data) def check_userdata_electric_equipment(object_name, user_data) userdata_valid = true user_data.each do |electric_row| + name = prm_read_user_data(electric_row, 'name') + unless name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: electric equipoment name is missing or empty. Electric equipment user data has not validated.") + return false + end + # check for fractions + fraction_of_controlled_receptacles = prm_read_user_data(electric_row, 'fraction_of_controlled_receptacles') + unless fraction_of_controlled_receptacles.nil? || Float(fraction_of_controlled_receptacles, exception: false) + userdata_valid = false + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: electric equipment definition #{name}'s fraction of controlled receptacles shall be a float, Got #{fraction_of_controlled_receptacles}.") + end + receptacle_power_savings = prm_read_user_data(electric_row, 'receptacle_power_savings') + unless receptacle_power_savings.nil? || Float(receptacle_power_savings, exception: false) + userdata_valid = false + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: electric equipment definition #{name}'s receptacle power savings shall be a float, Got #{receptacle_power_savings}.") + end # check for data type # unless fan_power_credit.nil? || Float(fan_power_credit, exception: false) motor_horsepower = prm_read_user_data(electric_row, 'motor_horsepower') diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb index ab2061d7e3..61c54b1d13 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb @@ -89,13 +89,45 @@ def write_default_rows end end -class UserDataLights < UserDataCSV +class UserDataCSVGasEquipment < UserDataCSV + # user data userdata_gas_equipment + # @param model [OpenStudio::Model::Model] + # @param save_dir [String] directory to save user data files + def initialize(model, save_dir) + super + @component_name = 'GasEquipments' + @file_name = UserDataFiles::GAS_EQUIPMENT + end + + def write_default_rows + # @todo we can do more here but right now, keep everything unchecked. + return Array.new(@headers.length - 1, '') + end +end + +class UserDataCSVZoneHvac < UserDataCSV + # user data userdata_zone_hvac + # @param model [OpenStudio::Model::Model] + # @param save_dir [String] directory to save user data files + def initialize(model, save_dir) + super + @component_name = 'ZoneHVAC' + @file_name = UserDataFiles::ZONE_HVAC + end + + def write_default_rows + # @todo we can do more here but right now, keep everything unchecked. + return Array.new(@headers.length - 1, '') + end +end + +class UserDataCSVLights < UserDataCSV # user data userdata_lights # @param model [OpenStudio::Model::Model] # @param save_dir [String] directory to save user data files def initialize(model, save_dir) super - @component_name = 'Lights' + @component_name = 'Lightss' @file_name = UserDataFiles::LIGHTS end @@ -265,7 +297,7 @@ class UserDataWaterUseEquipment < UserDataCSV # @param save_dir [String] directory to save user data files def initialize(model, save_dir) super - @component_name = 'WaterUseEquipment' + @component_name = 'WaterUseEquipments' @file_name = UserDataFiles::WATERUSE_EQUIPMENT end @@ -281,7 +313,7 @@ class UserDataWaterUseEquipmentDefinition < UserDataCSV # @param save_dir [String] directory to save user data files def initialize(model, save_dir) super - @component_name = 'WaterUseEquipmentDefinition' + @component_name = 'WaterUseEquipmentDefinitions' @file_name = UserDataFiles::WATERUSE_EQUIPMENT_DEFINITION end From aba47de189b9b40ffa099a1ab97a59322128d81c Mon Sep 17 00:00:00 2001 From: Weili Xu Date: Tue, 31 Oct 2023 15:49:57 -0700 Subject: [PATCH 4/5] add zone hvac data --- .../ashrae_90_1_prm/ashrae_90_1_prm.Model.rb | 225 ++++++++++++------ .../ashrae_90_1_prm/ashrae_90_1_prm.rb | 45 +++- .../userdata_csv/ashrae_90_1_prm.UserData.rb | 45 ++-- 3 files changed, 213 insertions(+), 102 deletions(-) diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb index 1f58864b8a..3f0f95c04d 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb @@ -1439,6 +1439,81 @@ def handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_bui return true end + # Retrieve zone HVAC user specified compliance inputs from CSV file + # + # @param model [OpenStudio::Model::Model] OpenStudio model object + def handle_zone_hvac_user_input_data(model) + user_zone_hvac = @standards_data.key?('userdata_zone_hvac') ? @standards_data['userdata_zone_hvac'] : nil + return unless user_zone_hvac && !user_zone_hvac.empty? + + zone_hvac_equipment = model.getZoneHVACComponents + if zone_hvac_equipment.empty? + OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', 'No zone HVAC equipment is present in the proposed model, user provided information cannot be used to generate the baseline building model.') + return + end + + user_zone_hvac.each do |zone_hvac_eqp_info| + user_defined_zone_hvac_obj_name = zone_hvac_eqp_info['name'] + user_defined_zone_hvac_obj_type_name = zone_hvac_eqp_info['zone_hvac_object_type_name'] + + # Check that the object type name do exist + begin + user_defined_zone_hvac_obj_type_name_idd = user_defined_zone_hvac_obj_type_name.to_IddObjectType + rescue StandardError => e + OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "#{user_defined_zone_hvac_obj_type_name}, provided in the user zone HVAC user data, is not a valid OpenStudio model object.") + end + + # Retrieve zone HVAC object(s) by name + zone_hvac_eqp = model.getZoneHVACComponentsByName(user_defined_zone_hvac_obj_name, false) + + # If multiple object have the same name + if zone_hvac_eqp.empty? + OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "The #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} provided in the user zone HVAC user data could not be found in the model.") + elsif zone_hvac_eqp.length == 1 + zone_hvac_eqp = zone_hvac_eqp[0] + zone_hvac_eqp_idd = zone_hvac_eqp.iddObjectType.to_s + if zone_hvac_eqp_idd != user_defined_zone_hvac_obj_type_name + OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "The object type name provided in the zone HVAC user data (#{user_defined_zone_hvac_obj_type_name}) does not match with the one in the model: #{zone_hvac_eqp_idd}.") + end + else + zone_hvac_eqp.each do |eqp| + zone_hvac_eqp_idd = eqp.iddObjectType + if zone_hvac_eqp_idd == user_defined_zone_hvac_obj_type_name + zone_hvac_eqp = eqp + break + end + end + OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "A #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} (as specified in the user zone HVAC data) could not be found in the model.") + end + + if zone_hvac_eqp.thermalZone.is_initialized + thermal_zone = zone_hvac_eqp.thermalZone.get + + zone_hvac_eqp_info.keys.each do |info_key| + if info_key.include?('fan_power_credit') + if !zone_hvac_eqp_info[info_key].to_s.empty? + if info_key.include?('has_') + if thermal_zone.additionalProperties.hasFeature(info_key) + current_value = thermal_zone.additionalProperties.getFeatureAsDouble(info_key).to_f + thermal_zone.additionalProperties.setFeature(info_key, current_value + 1.0) + else + thermal_zone.additionalProperties.setFeature(info_key, 1.0) + end + else + if thermal_zone.additionalProperties.hasFeature(info_key) + current_value = thermal_zone.additionalProperties.getFeatureAsDouble(info_key).to_f + thermal_zone.additionalProperties.setFeature(info_key, current_value + zone_hvac_eqp_info[info_key]) + else + thermal_zone.additionalProperties.setFeature(info_key, zone_hvac_eqp_info[info_key]) + end + end + end + end + end + end + end + end + # A function to load lights from user data csv files # The file name is userdata_lights.csv # @param [OpenStudio::Model::Model] model @@ -1811,6 +1886,81 @@ def handle_airloop_user_input_data(model) end end + # Retrieve zone HVAC user specified compliance inputs from CSV file + # + # @param model [OpenStudio::Model::Model] OpenStudio model object + def handle_zone_hvac_user_input_data(model) + user_zone_hvac = get_userdata(UserDataFiles::ZONE_HVAC) + return unless user_zone_hvac && !user_zone_hvac.empty? + + zone_hvac_equipment = model.getZoneHVACComponents + if zone_hvac_equipment.empty? + OpenStudio.logFree(OpenStudio::Error, 'prm.log', 'No zone HVAC equipment is present in the proposed model, user provided information cannot be used to generate the baseline building model.') + return + end + + user_zone_hvac.each do |zone_hvac_eqp_info| + user_defined_zone_hvac_obj_name = zone_hvac_eqp_info['name'] + user_defined_zone_hvac_obj_type_name = zone_hvac_eqp_info['zone_hvac_object_type_name'] + + # Check that the object type name do exist + begin + user_defined_zone_hvac_obj_type_name_idd = user_defined_zone_hvac_obj_type_name.to_IddObjectType + rescue StandardError => e + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "#{user_defined_zone_hvac_obj_type_name}, provided in the user zone HVAC user data, is not a valid OpenStudio model object.") + end + + # Retrieve zone HVAC object(s) by name + zone_hvac_eqp = model.getZoneHVACComponentsByName(user_defined_zone_hvac_obj_name, false) + + # If multiple object have the same name + if zone_hvac_eqp.empty? + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "The #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} provided in the user zone HVAC user data could not be found in the model.") + elsif zone_hvac_eqp.length == 1 + zone_hvac_eqp = zone_hvac_eqp[0] + zone_hvac_eqp_idd = zone_hvac_eqp.iddObjectType.to_s + if zone_hvac_eqp_idd != user_defined_zone_hvac_obj_type_name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "The object type name provided in the zone HVAC user data (#{user_defined_zone_hvac_obj_type_name}) does not match with the one in the model: #{zone_hvac_eqp_idd}.") + end + else + zone_hvac_eqp.each do |eqp| + zone_hvac_eqp_idd = eqp.iddObjectType + if zone_hvac_eqp_idd == user_defined_zone_hvac_obj_type_name + zone_hvac_eqp = eqp + break + end + end + OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "A #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} (as specified in the user zone HVAC data) could not be found in the model.") + end + + if zone_hvac_eqp.thermalZone.is_initialized + thermal_zone = zone_hvac_eqp.thermalZone.get + + zone_hvac_eqp_info.keys.each do |info_key| + if info_key.include?('fan_power_credit') + if !zone_hvac_eqp_info[info_key].to_s.empty? + if info_key.include?('has_') + if thermal_zone.additionalProperties.hasFeature(info_key) + current_value = thermal_zone.additionalProperties.getFeatureAsDouble(info_key).to_f + thermal_zone.additionalProperties.setFeature(info_key, current_value + 1.0) + else + thermal_zone.additionalProperties.setFeature(info_key, 1.0) + end + else + if thermal_zone.additionalProperties.hasFeature(info_key) + current_value = thermal_zone.additionalProperties.getFeatureAsDouble(info_key).to_f + thermal_zone.additionalProperties.setFeature(info_key, current_value + zone_hvac_eqp_info[info_key]) + else + thermal_zone.additionalProperties.setFeature(info_key, zone_hvac_eqp_info[info_key]) + end + end + end + end + end + end + end + end + # A function to load airloop DOAS data from userdata csv files # @param model [OpenStudio::Model::Model] OpenStudio model object def handle_airloop_doas_user_input_data(model) @@ -2332,81 +2482,6 @@ def generate_baseline_log(file_directory) log_messages_to_file_prm("#{file_directory}/prm.log", false) end - # Retrieve zone HVAC user specified compliance inputs from CSV file - # - # @param model [OpenStudio::Model::Model] OpenStudio model object - def handle_zone_hvac_user_input_data(model) - user_zone_hvac = @standards_data.key?('userdata_zone_hvac') ? @standards_data['userdata_zone_hvac'] : nil - return unless user_zone_hvac && !user_zone_hvac.empty? - - zone_hvac_equipment = model.getZoneHVACComponents - if zone_hvac_equipment.empty? - OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', 'No zone HVAC equipment is present in the proposed model, user provided information cannot be used to generate the baseline building model.') - return - end - - user_zone_hvac.each do |zone_hvac_eqp_info| - user_defined_zone_hvac_obj_name = zone_hvac_eqp_info['name'] - user_defined_zone_hvac_obj_type_name = zone_hvac_eqp_info['zone_hvac_object_type_name'] - - # Check that the object type name do exist - begin - user_defined_zone_hvac_obj_type_name_idd = user_defined_zone_hvac_obj_type_name.to_IddObjectType - rescue StandardError => e - OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "#{user_defined_zone_hvac_obj_type_name}, provided in the user zone HVAC user data, is not a valid OpenStudio model object.") - end - - # Retrieve zone HVAC object(s) by name - zone_hvac_eqp = model.getZoneHVACComponentsByName(user_defined_zone_hvac_obj_name, false) - - # If multiple object have the same name - if zone_hvac_eqp.empty? - OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "The #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} provided in the user zone HVAC user data could not be found in the model.") - elsif zone_hvac_eqp.length == 1 - zone_hvac_eqp = zone_hvac_eqp[0] - zone_hvac_eqp_idd = zone_hvac_eqp.iddObjectType.to_s - if zone_hvac_eqp_idd != user_defined_zone_hvac_obj_type_name - OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "The object type name provided in the zone HVAC user data (#{user_defined_zone_hvac_obj_type_name}) does not match with the one in the model: #{zone_hvac_eqp_idd}.") - end - else - zone_hvac_eqp.each do |eqp| - zone_hvac_eqp_idd = eqp.iddObjectType - if zone_hvac_eqp_idd == user_defined_zone_hvac_obj_type_name - zone_hvac_eqp = eqp - break - end - end - OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "A #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} (as specified in the user zone HVAC data) could not be found in the model.") - end - - if zone_hvac_eqp.thermalZone.is_initialized - thermal_zone = zone_hvac_eqp.thermalZone.get - - zone_hvac_eqp_info.keys.each do |info_key| - if info_key.include?('fan_power_credit') - if !zone_hvac_eqp_info[info_key].to_s.empty? - if info_key.include?('has_') - if thermal_zone.additionalProperties.hasFeature(info_key) - current_value = thermal_zone.additionalProperties.getFeatureAsDouble(info_key).to_f - thermal_zone.additionalProperties.setFeature(info_key, current_value + 1.0) - else - thermal_zone.additionalProperties.setFeature(info_key, 1.0) - end - else - if thermal_zone.additionalProperties.hasFeature(info_key) - current_value = thermal_zone.additionalProperties.getFeatureAsDouble(info_key).to_f - thermal_zone.additionalProperties.setFeature(info_key, current_value + zone_hvac_eqp_info[info_key]) - else - thermal_zone.additionalProperties.setFeature(info_key, zone_hvac_eqp_info[info_key]) - end - end - end - end - end - end - end - end - # This function checks whether it is required to adjust the window to wall ratio based on the model WWR and wwr limit. # @param wwr_limit [Double] window to wall ratio limit # @param wwr_list [Array] list of wwr of zone conditioning category in a building area type category - residential, nonresidential and semiheated diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb index 102fb9a827..dc479642b5 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb @@ -176,6 +176,8 @@ def user_data_validation(object_name, user_data) return check_userdata_outdoor_air(object_name, user_data) when UserDataFiles::AIRLOOP_HVAC_DOAS return check_userdata_airloop_hvac_doas(object_name, user_data) + when UserDataFiles::ZONE_HVAC + return check_userdata_zone_hvac(object_name, user_data) when UserDataFiles::THERMAL_ZONE return check_userdata_thermal_zone(object_name, user_data) when UserDataFiles::WATERUSE_CONNECTIONS @@ -279,6 +281,47 @@ def check_userdata_thermal_zone(object_name, user_data) return userdata_valid end + # Check for incorrect data in [UserDataFiles::ZONE_HVAC] + # @param object_name [String] name of user data csv file to check + # @param user_data [Hash] hash of data from user data csv file + # @return [Boolean] true if data is valid, false if error found + def check_userdata_zone_hvac(object_name, user_data) + userdata_valid = true + user_data.each do |user_zone_hvac| + name = prm_read_user_data(user_zone_hvac, 'name') + unless name + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: zone HVAC name is missing or empty. Zone HVAC user data has not validated.") + return false + end + # Fan power credits, exhaust air energy recovery + user_zone_hvac.keys.each do |info_key| + # Fan power credits + if info_key.include?('has_fan_power_credit') + has_fan_power_credit = prm_read_user_data(user_zone_hvac, info_key) + unless has_fan_power_credit.nil? || UserDataBoolean.matched_any?(has_fan_power_credit) + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, zone HVAC name #{name}, #{info_key} shall be either True or False. Got #{has_fan_power_credit}.") + userdata_valid = false + end + elsif info_key.include?('fan_power_credit') + fan_power_credit = prm_read_user_data(user_zone_hvac, info_key) + unless fan_power_credit.nil? || Float(fan_power_credit, exception: false) + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, zone HVAC name #{name}, #{info_key} shall be a numeric value. Got #{fan_power_credit}.") + userdata_valid = false + end + end + # Exhaust air energy recovery + if info_key.include?('exhaust_energy_recovery_exception') + exhaust_energy_recovery_exception = prm_read_user_data(user_zone_hvac, info_key) + unless exhaust_energy_recovery_exception.nil? || UserDataBoolean.matched_any?(exhaust_energy_recovery_exception) + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, zone HVAC name #{name}, #{info_key} shall be either True or False. Got #{exhaust_energy_recovery_exception}.") + userdata_valid = false + end + end + end + end + return userdata_valid + end + # Check for incorrect data in [UserDataFiles::AIRLOOP_HVAC_DOAS] # @param object_name [String] name of user data csv file to check # @param user_data [Hash] hash of data from user data csv file @@ -311,7 +354,7 @@ def check_userdata_airloop_hvac_doas(object_name, user_data) if info_key.include?('exhaust_energy_recovery_exception') exhaust_energy_recovery_exception = prm_read_user_data(user_airloop, info_key) unless exhaust_energy_recovery_exception.nil? || UserDataBoolean.matched_any?(exhaust_energy_recovery_exception) - OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Air Loop name #{name}, #{info_key} shall be either True or False. Got #{has_fan_power_credit}.") + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Air Loop name #{name}, #{info_key} shall be either True or False. Got #{exhaust_energy_recovery_exception}.") userdata_valid = false end end diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb index 61c54b1d13..8963b2059c 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/userdata_csv/ashrae_90_1_prm.UserData.rb @@ -33,7 +33,7 @@ def write_csv CSV.open("#{@save_dir}/#{@file_name}.csv", 'w') do |csv| csv << @headers @components.each do |component| - csv << [prm_get_component_name(component)] + write_default_rows + csv << [prm_get_component_name(component)] + write_default_rows(component) end end return true @@ -43,8 +43,9 @@ def write_csv # method to write the parameters in the csv file. # This method provides a template to write in default values to the user data file + # @param component [OpenStudio::Model::Component] Openstudio component # return [Array] array of strings that contains the data in the userdata file - def write_default_rows + def write_default_rows(component) raise NotImplementedError, 'Method write rows should be implemented in class' end @@ -83,7 +84,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::AIRLOOP_HVAC end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -99,7 +100,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::GAS_EQUIPMENT end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -111,11 +112,11 @@ class UserDataCSVZoneHvac < UserDataCSV # @param save_dir [String] directory to save user data files def initialize(model, save_dir) super - @component_name = 'ZoneHVAC' + @component_name = 'ZoneHVACComponents' @file_name = UserDataFiles::ZONE_HVAC end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -131,7 +132,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::LIGHTS end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -147,13 +148,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::BUILDING end - private - - def load_component - return [@model.public_send("get#{@component_name}")] - end - - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -169,9 +164,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::SPACE end - private - - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -189,7 +182,7 @@ def initialize(model, save_dir) private - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -205,7 +198,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::AIRLOOP_HVAC_DOAS end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -221,7 +214,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::EXTERIOR_LIGHTS end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -237,7 +230,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::THERMAL_ZONE end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -253,7 +246,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::ELECTRIC_EQUIPMENT end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -269,7 +262,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::DESIGN_SPECIFICATION_OUTDOOR_AIR end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -285,7 +278,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::WATERUSE_CONNECTIONS end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -301,7 +294,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::WATERUSE_EQUIPMENT end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end @@ -317,7 +310,7 @@ def initialize(model, save_dir) @file_name = UserDataFiles::WATERUSE_EQUIPMENT_DEFINITION end - def write_default_rows + def write_default_rows(component) # @todo we can do more here but right now, keep everything unchecked. return Array.new(@headers.length - 1, '') end From e0d650c7df29cce112ce2a5662aeb832c9ebe8a4 Mon Sep 17 00:00:00 2001 From: Weili Xu Date: Wed, 1 Nov 2023 08:56:37 -0700 Subject: [PATCH 5/5] update user data from yes to true. --- .../standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb | 2 +- .../90_1_prm/data/userdata_ltg_exceptions/userdata_lights.csv | 4 ++-- .../data/userdata_merv13to15_zonehvac/userdata_zone_hvac.csv | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb index 3f0f95c04d..16fa7a97c1 100644 --- a/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb +++ b/lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb @@ -1930,7 +1930,7 @@ def handle_zone_hvac_user_input_data(model) break end end - OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.model', "A #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} (as specified in the user zone HVAC data) could not be found in the model.") + OpenStudio.logFree(OpenStudio::Error, 'prm.log', "A #{user_defined_zone_hvac_obj_type_name} object named #{user_defined_zone_hvac_obj_name} (as specified in the user zone HVAC data) could not be found in the model.") end if zone_hvac_eqp.thermalZone.is_initialized diff --git a/test/90_1_prm/data/userdata_ltg_exceptions/userdata_lights.csv b/test/90_1_prm/data/userdata_ltg_exceptions/userdata_lights.csv index 515ce6485f..88e62b274d 100644 --- a/test/90_1_prm/data/userdata_ltg_exceptions/userdata_lights.csv +++ b/test/90_1_prm/data/userdata_ltg_exceptions/userdata_lights.csv @@ -1,3 +1,3 @@ name,has_retail_display_exception,has_unregulated_exception,unregulated_category -StripMall Strip mall - type 1 Additional Lights,yes,, -StripMall Strip mall - type 2 Additional Lights,,yes,Mirror lighting in dressing rooms +StripMall Strip mall - type 1 Additional Lights,true,, +StripMall Strip mall - type 2 Additional Lights,,true,Mirror lighting in dressing rooms diff --git a/test/90_1_prm/data/userdata_merv13to15_zonehvac/userdata_zone_hvac.csv b/test/90_1_prm/data/userdata_merv13to15_zonehvac/userdata_zone_hvac.csv index aa78354f2e..3629607657 100644 --- a/test/90_1_prm/data/userdata_merv13to15_zonehvac/userdata_zone_hvac.csv +++ b/test/90_1_prm/data/userdata_merv13to15_zonehvac/userdata_zone_hvac.csv @@ -1,2 +1,2 @@ name,zone_hvac_object_type_name,has_fan_power_credit_fully_ducted,has_fan_power_credit_return_or_exhaust_flow_control,fan_power_credit_exhaust_treatment,has_fan_power_credit_filtration_m9to12,has_fan_power_credit_filtration_m13to15,clean_filter_pressure_drop_for_fan_power_credit_filtration_m16plus,fan_power_credit_gas_phase_cleaners,fan_power_credit_biosafety,fan_power_credit_other_than_coil_runaround,has_fan_power_credit_coil_runaround,fan_power_credit_evaporative_humidifier_or_cooler,has_fan_power_credit_sound_attenuation,has_fan_power_credit_exhaust_serving_fume_hoods,has_fan_power_credit_lab_or_vivarium_highrise_vertical_duct -Front_Entry ZN Unit Heater,OS:ZoneHVAC:UnitHeater,,,,,yes,,,,,,,,, \ No newline at end of file +Front_Entry ZN Unit Heater,OS:ZoneHVAC:UnitHeater,,,,,true,,,,,,,,, \ No newline at end of file