require 'csv' # This abstract class holds methods that many versions of ASHRAE 90.1 share. # If a method in this class is redefined by a subclass, # the implementation in the subclass is used. # @abstract class ASHRAE901PRM < Standard def initialize load_standards_database @sizing_run_dir = Dir.pwd end def load_standards_database(data_directories = []) super([__dir__] + data_directories) end # Method to generate user data from a user model and save the csvs to the user_data_path # This method can generate one user data csv based on the matching name or a full set of user data if # leave it as nil # @param user_model [OpenStudio::Model::Model] OpenStudio model object # @param user_data_path [String] data path # @param user_data_file [String] the name of the user data file. def generate_userdata_to_csv(user_model, user_data_path, user_data_file = nil) user_data_list = [UserDataCSVAirLoopHVAC.new(user_model, user_data_path), UserDataCSVBuilding.new(user_model, user_data_path), UserDataCSVSpace.new(user_model, user_data_path), 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), UserDataWaterUseEquipmentDefinition.new(user_model, user_data_path)] if user_data_file.nil? user_data_list.each(&:write_csv) else user_data_list.each do |user_data| if user_data.file_name == user_data_file user_data.write_csv end end end end # Convert user data csv files to json format and save to project folder # Method will create the json_folder in the project_path # @author Doug Maddox, PNNL # @param user_data_path [String path to folder containing csv files # @param project_path [String path to project folder # @return [String] path to json files def convert_userdata_csv_to_json(user_data_path, project_path) # Get list of possible files from lib\openstudio-standards\standards\ashrae_90_1_prm\userdata_csv stds_dir = __dir__ src_csv_dir = "#{stds_dir}/userdata_csv/*.csv" json_objs = {} Dir.glob(src_csv_dir).each do |csv_full_name| json_rows = [] csv_file_name = File.basename(csv_full_name, File.extname(csv_full_name)) unless UserDataFiles.matched_any?(csv_file_name) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "user data file: #{csv_file_name} is not a valid file name. See the full list of acceptable file names in https://pnnl.github.io/BEM-for-PRM/user_guide/add_compliance_data/") end json_objs[csv_file_name] = json_rows end # Read all valid files in user_data_folder and load into json array unless user_data_path == '' user_data_validation_outcome = true Dir.glob("#{user_data_path.gsub('\\', '/')}/*.csv").each do |csv_full_name| csv_file_name = File.basename(csv_full_name, File.extname(csv_full_name)) if json_objs.key?(csv_file_name) # Load csv file into array of hashes json_rows = CSV.foreach(csv_full_name, headers: true).map { |row| user_data_preprocessor(row) } next if json_rows.empty? # validate the user_data in json_rows unless user_data_validation(csv_file_name, json_rows) user_data_validation_outcome = false end # remove file extension file_name = File.basename(csv_full_name, File.extname(csv_full_name)) json_objs[file_name] = json_rows end end unless user_data_validation_outcome terminate_prm_write_log('Error found in the user data. Check output log to see detail error messages', project_path, false) end end # Make folder for json files; remove pre-existing first, if needed json_path = "#{project_path}/user_data_json" if !Dir.exist?(json_path) Dir.mkdir(json_path) else FileUtils.rm_rf(json_path) Dir.mkdir(json_path) end # Write all json files json_objs.each do |file_name, json_rows| json_obj = {} json_obj[file_name] = json_rows json_path_file = "#{json_path}/#{file_name}.json" File.open(json_path_file, 'w:UTF-8') do |file| file << JSON.pretty_generate(json_obj) end end return json_path end # Load user data from project folder into standards database data structure # Each user data object type is a new item in the @standards_data hash # @author Doug Maddox, PNNL # @param json_path [String path to folder containing json files def load_userdata_to_standards_database(json_path) files = Dir.glob("#{json_path}/*.json").select { |e| File.file? e } files.each do |file| data = JSON.parse(File.read(file)) data.each_pair do |key, objs| # Override the template in inherited files to match the instantiated template if @standards_data[key].nil? OpenStudio.logFree(OpenStudio::Debug, 'openstudio.standards.standard', "Adding #{key} from #{File.basename(file)}") else OpenStudio.logFree(OpenStudio::Debug, 'openstudio.standards.standard', "Overriding #{key} with #{File.basename(file)}") end @standards_data[key] = objs end end end # Perform user data preprocessing # @param [CSV::ROW] row 2D array for each row. def user_data_preprocessor(row) new_array = [] # Strip the strings in the value row.each do |sub_array| new_array << sub_array.collect { |e| e ? e.strip : e } end # @todo Future expansion can added to here. # Convert the 2d array to hash return new_array.to_h end # Perform user data validation # @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 user_data_validation(object_name, user_data) # 1. Check user_spacetype and user_space LPD total % = 1.0 case object_name when UserDataFiles::BUILDING return check_userdata_building(object_name, user_data) when UserDataFiles::SPACE, UserDataFiles::SPACETYPE 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 return check_userdata_exterior_lighting(object_name, user_data) when UserDataFiles::AIRLOOP_HVAC return check_userdata_airloop_hvac(object_name, user_data) when UserDataFiles::DESIGN_SPECIFICATION_OUTDOOR_AIR 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 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 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| 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 # 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| name = prm_read_user_data(user_building, 'name') unless name OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: building name is missing or empty. Building user data has not validated.") return false end building_type_for_hvac = prm_read_user_data(user_building, 'building_type_for_hvac') unless building_type_for_hvac.nil? || UserDataHVACBldgType.matched_any?(building_type_for_hvac) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Unknown building type #{building_type_for_hvac} for prescribed HVAC system type. For full list of the building type, see: https://pnnl.github.io/BEM-for-PRM/user_guide/prm_api_ref/baseline_generation_api/#--default_hvac_bldg_type") userdata_valid = false end building_type_for_wwr = prm_read_user_data(user_building, 'building_type_for_wwr') unless building_type_for_wwr.nil? || UserDataWWRBldgType.matched_any?(building_type_for_wwr) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Unknown building type #{building_type_for_hvac} for prescribed window-to-wall ratio. For full list of the building type, see: https://pnnl.github.io/BEM-for-PRM/user_guide/prm_api_ref/baseline_generation_api/#--default_wwr_bldg_type") userdata_valid = false end building_type_for_swh = prm_read_user_data(user_building, 'building_type_for_swh') unless building_type_for_swh.nil? || UserDataSHWBldgType.matched_any?(building_type_for_swh) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Unknown building type #{building_type_for_hvac} for prescribed service hot water system. For full list of the building type, see: https://pnnl.github.io/BEM-for-PRM/user_guide/prm_api_ref/baseline_generation_api/#--default_swh_bldg_type") userdata_valid = false end is_exempt_from_rotations = prm_read_user_data(user_building, 'is_exempt_from_rotations') unless is_exempt_from_rotations.nil? || UserDataBoolean.matched_any?(is_exempt_from_rotations) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Building name #{name}, is_exempt_from_rotations shall be either True or False. Got #{is_exempt_from_rotations}.") userdata_valid = false end end 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| name = prm_read_user_data(user_thermal_zone, 'name') unless name 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') 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 end end 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 # @return [Boolean] true if data is valid, false if error found def check_userdata_airloop_hvac_doas(object_name, user_data) userdata_valid = true user_data.each do |user_airloop| name = prm_read_user_data(user_airloop, 'name') unless name OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: air loop name is missing or empty. Air loop user data has not validated.") return false end # Fan power credits, exhaust air energy recovery user_airloop.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_airloop, 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}, Air Loop 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_airloop, info_key) unless fan_power_credit.nil? || Float(fan_power_credit, exception: false) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Air Loop 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_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 #{exhaust_energy_recovery_exception}.") userdata_valid = false end end end end return userdata_valid end # Check for incorrect data in [UserDataFiles::DESIGN_SPECIFICATION_OUTDOOR_AIR] # @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_outdoor_air(object_name, user_data) userdata_valid = true user_data.each do |user_oa| name = prm_read_user_data(user_oa, 'name') unless name OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: air loop name is missing or empty. Air loop user data has not validated.") return false end outdoor_airflow_per_person = prm_read_user_data(user_oa, 'outdoor_airflow_per_person') unless outdoor_airflow_per_person.nil? || Float(outdoor_airflow_per_person, exception: false) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Design outdoor air name #{name}, outdoor_airflow_per_person shall be a numeric value. Got #{outdoor_airflow_per_person}.") userdata_valid = false end outdoor_airflow_per_floor_area = prm_read_user_data(user_oa, 'outdoor_airflow_per_floor_area') unless outdoor_airflow_per_floor_area.nil? || Float(outdoor_airflow_per_floor_area, exception: false) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Design outdoor air name #{name}, outdoor_airflow_per_floor_area shall be a numeric value. Got #{outdoor_airflow_per_floor_area}.") userdata_valid = false end outdoor_air_flowrate = prm_read_user_data(user_oa, 'outdoor_air_flowrate') unless outdoor_air_flowrate.nil? || Float(outdoor_air_flowrate, exception: false) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Design outdoor air name #{name}, outdoor_air_flowrate shall be a numeric value. Got #{outdoor_air_flowrate}.") userdata_valid = false end outdoor_air_flow_air_changes_per_hour = prm_read_user_data(user_oa, 'outdoor_air_flow_air_changes_per_hour') unless outdoor_air_flow_air_changes_per_hour.nil? || Float(outdoor_air_flow_air_changes_per_hour, exception: false) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Design outdoor air name #{name}, outdoor_air_flow_air_changes_per_hour shall be a numeric value. Got #{outdoor_air_flow_air_changes_per_hour}.") userdata_valid = false end end return userdata_valid end # Check for incorrect data in [UserDataFiles::AIRLOOP_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_airloop_hvac(object_name, user_data) userdata_valid = true user_data.each do |user_airloop| name = prm_read_user_data(user_airloop, 'name') unless name OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: air loop name is missing or empty. Air loop user data has not validated.") return false end # gas phase air cleaning is system base - add proposed hvac system name to zones economizer_exception_for_gas_phase_air_cleaning = prm_read_user_data(user_airloop, 'economizer_exception_for_gas_phase_air_cleaning', UserDataBoolean::FALSE) unless economizer_exception_for_gas_phase_air_cleaning.nil? || UserDataBoolean.matched_any?(economizer_exception_for_gas_phase_air_cleaning) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Air Loop name #{name}, economizer_exception_for_gas_phase_air_cleaning shall be either True or False. Got #{economizer_exception_for_gas_phase_air_cleaning}") userdata_valid = false end economizer_exception_for_open_refrigerated_cases = prm_read_user_data(user_airloop, 'economizer_exception_for_open_refrigerated_cases', UserDataBoolean::FALSE) unless economizer_exception_for_open_refrigerated_cases.nil? || UserDataBoolean.matched_any?(economizer_exception_for_open_refrigerated_cases) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Air Loop name #{name}, economizer_exception_for_open_refrigerated_cases shall be either True or False. Got #{economizer_exception_for_open_refrigerated_cases}") userdata_valid = false end # Fan power credits, exhaust air energy recovery user_airloop.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_airloop, 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}, Air Loop 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_airloop, info_key) unless fan_power_credit.nil? || Float(fan_power_credit, exception: false) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Air Loop 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_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}.") userdata_valid = false end end end end return userdata_valid end # Check for incorrect data in exterior lights 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_exterior_lighting(object_name, user_data) userdata_valid = true user_data.each do |exterior_light| name = prm_read_user_data(exterior_light, 'name') unless name OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: exterior light name is missing or empty. Exterior light user data has not validated.") return false end num_cats = prm_read_user_data(exterior_light, 'num_ext_lights_subcats', '0').to_i (1..num_cats).each do |icat| cat_key = format('end_use_subcategory_%02d', icat) subcat = prm_read_user_data(exterior_light, cat_key, nil) unless subcat OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}, Exterior light: #{name}, #{cat_key} is either missing or empty.") userdata_valid = false end end end 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 # @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_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') unless motor_horsepower.nil? || Float(motor_horsepower, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Motor #{electric_row['name']}'s horsepower data is either 0.0 or unavailable. Check the inputs.") end motor_efficiency = prm_read_user_data(electric_row, 'motor_efficiency') unless motor_efficiency.nil? || Float(motor_efficiency, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Motor #{electric_row['name']}'s efficiency data is either 0.0 or unavailable. Check the inputs.") end motor_is_exempt = prm_read_user_data(electric_row, 'motor_is_exempt') unless motor_is_exempt.nil? || UserDataBoolean.matched_any?(motor_is_exempt) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Motor #{electric_row['name']} is exempt data should be either True or False. But get data #{electric_row['motor_is_exempt']}") end # We may need to do the same for refrigeration and elevator? # Check elevator elevator_weight_of_car = prm_read_user_data(electric_row, 'elevator_weight_of_car') unless elevator_weight_of_car.nil? || Float(elevator_weight_of_car, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Elevator #{electric_row['name']}'s weight of car data is either 0.0 or unavailable. Check the inputs.") end elevator_rated_load = prm_read_user_data(electric_row, 'elevator_rated_load') unless elevator_rated_load.nil? || Float(elevator_rated_load, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Elevator #{electric_row['name']}'s rated load data is either 0.0 or unavailable. Check the inputs.") end elevator_counter_weight_of_car = prm_read_user_data(electric_row, 'elevator_counter_weight_of_car') unless elevator_counter_weight_of_car.nil? || Float(elevator_counter_weight_of_car, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Elevator #{electric_row['name']}'s counter weight of car data is either 0.0 or unavailable. Check the inputs.") end elevator_speed_of_car = prm_read_user_data(electric_row, 'elevator_speed_of_car') unless elevator_speed_of_car.nil? || Float(elevator_speed_of_car, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Elevator #{electric_row['name']}'s speed of car data is either 0.0 or unavailable. Check the inputs.") end elevator_number_of_stories = prm_read_user_data(electric_row, 'elevator_number_of_stories') unless elevator_number_of_stories.nil? || Integer(elevator_number_of_stories, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Elevator #{electric_row['name']}'s serves number of stories data is either smaller or equal to 1 or unavailable. Check the inputs.") end # Check refrigeration # Check data type # The equipment class shall be verified at the implementation level refrigeration_equipment_volume = prm_read_user_data(electric_row, 'refrigeration_equipment_volume') unless refrigeration_equipment_volume.nil? || Float(refrigeration_equipment_volume, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Refrigeration #{electric_row['name']}'s equipment volume data is either 0.0 or unavailable. Check the inputs.") end refrigeration_equipment_total_display_area = prm_read_user_data(electric_row, 'refrigeration_equipment_total_display_area') unless refrigeration_equipment_total_display_area.nil? || Float(refrigeration_equipment_total_display_area, exception: false) userdata_valid = false OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data: #{object_name}: Refrigeration #{electric_row['name']}'s total display area data is either 0.0 or unavailable. Check the inputs.") end end return userdata_valid end # Check for incorrect data in space and spacetype 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_space_and_spacetype(object_name, user_data) userdata_valid = true user_data.each do |row| building_type_for_wwr = prm_read_user_data(row, 'building_type_for_wwr') unless building_type_for_wwr.nil? || UserDataWWRBldgType.matched_any?(building_type_for_wwr) OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Unknown building type #{building_type_for_wwr} for prescribed window to wall ratio. For full list of the building type, see: https://pnnl.github.io/BEM-for-PRM/user_guide/prm_api_ref/baseline_generation_api/#--default_wwr_bldg_type") userdata_valid = false end unless prm_read_user_data(row, 'num_std_ltg_types', '0').to_i == 0 num_ltg_type = row['num_std_ltg_types'].to_i total_ltg_percent = 0.0 std_ltg_index = 0 while std_ltg_index < num_ltg_type frac_key = format('std_ltg_type_frac%02d', (std_ltg_index + 1)) total_ltg_percent += prm_read_user_data(row, frac_key, '0.0').to_f std_ltg_index += 1 end if (total_ltg_percent - 1.0).abs > 0.01 OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data #{object_name}: The fraction of user defined lighting types in Space/SpaceType: #{row['name']} does not add up to 1.0. The calculated fraction is #{total_ltg_percent}.") userdata_valid = false end end 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