Class: ASHRAE901PRM Abstract
- Includes:
- ASHRAE901PRMFan, ASHRAEPRMCoilDX
- Defined in:
- lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Space.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Surface.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanOnOff.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ThermalZone.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlanarSurface.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.BoilerHotWater.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingGas.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanZoneExhaust.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanConstantVolume.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanVariableVolume.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ZoneHVACComponent.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ChillerElectricEIR.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.HeatExchangerSensLat.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXTwoSpeed.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXSingleSpeed.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingDXSingleSpeed.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctVAVReheat.rb,
lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctParallelPIUReheat.rb
Overview
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.
Direct Known Subclasses
Constant Summary
Constants inherited from Standard
Instance Attribute Summary
Attributes inherited from Standard
#space_multiplier_map, #standards_data, #template
Model collapse
-
#find_prm_heat_type(hvac_building_type, climate_zone) ⇒ String
Determine whether heating type is fuel or electric.
-
#generate_baseline_log(file_directory) ⇒ Object
Generate baseline log to a specific file directory.
-
#get_baseline_system_groups_for_one_building_type(model, hvac_building_type, zones_in_building_type) ⇒ Array<Hash>
Assign spaces to system groups for one hvac building type One group contains all zones associated with one HVAC type Separate groups are made for laboratories, computer rooms, district cooled zones, heated-only zones, or hybrids of these Groups may include zones from multiple floors; separating by floor is handled later For stable baseline, heating type is based on climate, not proposed heating type Isolate zones that have heating-only or district (purchased) heat or chilled water.
-
#get_model_fenestration_area_by_orientation(user_model) ⇒ Hash
Function that extract the total fenestration area from a model by orientations.
-
#handle_airloop_doas_user_input_data(model) ⇒ Object
A function to load airloop DOAS data from userdata csv files.
-
#handle_airloop_user_input_data(model) ⇒ Object
A function to load airloop data from userdata csv files The function works with validated user data only.
-
#handle_electric_equipment_user_input_data(model) ⇒ Object
A function to load electric equipment csv files The file name is userdata_electric_equipment.csv.
-
#handle_exterior_lighting_user_input_data(model) ⇒ Object
A function to load exterior lighting data from user data csv files The file name is userdata_exterior_lighting.csv.
-
#handle_gas_equipment_user_input_data(model) ⇒ Object
A function to load gas equipment csv files The file name is userdata_gas_equipment.csv.
-
#handle_lights_user_input_data(model) ⇒ Object
A function to load lights from user data csv files The file name is userdata_lights.csv.
-
#handle_multi_building_area_types(model, climate_zone, default_hvac_building_type, default_wwr_building_type, default_swh_building_type, bldg_type_hvac_zone_hash) ⇒ Boolean
Analyze HVAC, window-to-wall ratio and SWH building (area) types from user data inputs in the @standard_data library This function returns True, but the values are stored in the multi-building_data argument.
-
#handle_outdoor_air_user_input_data(model) ⇒ Object
A function to load outdoor air data from user data csv files The file name is userdata_design_specification_outdoor_air.csv.
-
#handle_thermal_zone_user_input_data(model) ⇒ Object
A function to load thermal zone data from userdata csv files.
-
#handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_building_type, default_wwr_building_type, default_swh_building_type, bldg_type_hvac_zone_hash) ⇒ Boolean
A template method that handles the loading of user input data from multiple sources include data source from: 1.
-
#handle_wateruse_connections_user_input_data(model) ⇒ Object
A function to load water use connections schedules from user data csv files The file name is userdata_wateruse_connections.csv.
-
#handle_wateruse_equipment_definition_user_input_data(model) ⇒ Object
A function to load water use equipment definition from user data csv files The file name is userdata_wateruse_equipment_definition.csv.
-
#handle_wateruse_equipment_user_input_data(model, default_swh_building_type) ⇒ Object
A function to load water use equipment from user data csv files The file name is userdata_wateruse_equipment.csv.
-
#handle_zone_hvac_user_input_data(model) ⇒ Object
Retrieve zone HVAC user specified compliance inputs from CSV file.
-
#model_add_apxg_dcv_properties(model) ⇒ Object
Check if zones in the baseline model (to be created) should have DCV based on 90.1 2019 G3.1.2.5.
-
#model_add_dcv_requirement_properties(model) ⇒ Object
add zone additional property “airloop dcv required by 901” - “true” if the airloop supporting this zone is required by 90.1 (non-exception requirement + user provided exception flag) to have DCV regarding user model - “false” otherwise add zone additional property “zone dcv required by 901” - “true” if the zone is required by 90.1(non-exception requirement + user provided exception flag) to have DCV regarding user model - ‘flase’ otherwise.
-
#model_add_dcv_user_exception_properties(model) ⇒ Object
read user data and add to zone additional properties “airloop user specified DCV exception” “one user specified DCV exception”.
-
#model_add_prm_elevators(model) ⇒ Object
Function to add baseline elevators based on user data.
-
#model_adjusted_building_envelope_infiltration(building_envelope_area_m2, specific_space_infiltration_rate_75_pa = nil) ⇒ Double
This method calculates the building envelope infiltration, this approach uses the 90.1 PRM rules.
-
#model_apply_baseline_exterior_lighting(model) ⇒ Object
Apply baseline values to exterior lights objects Characterization of objects must be done via user data.
-
#model_apply_baseline_swh_loops(model, building_type) ⇒ Boolean
Modify the existing service water heating loops to match the baseline required heating type.
-
#model_apply_constructions(model, climate_zone, wwr_building_type, wwr_info) ⇒ Boolean
Apply the standard construction to each surface in the model, based on the construction type currently assigned.
-
#model_apply_hvac_efficiency_standard(model, climate_zone, apply_controls: true, sql_db_vars_map: nil) ⇒ Boolean
Applies the HVAC parts of the template to all objects in the model using the the template specified in the model.
-
#model_apply_multizone_vav_outdoor_air_sizing(model) ⇒ Boolean
Applies the multi-zone VAV outdoor air sizing requirements to all applicable air loops in the model.
-
#model_apply_prm_baseline_sizing_schedule(model) ⇒ Object
Add design day schedule objects for space loads, for PRM 2019 baseline models.
-
#model_apply_prm_baseline_skylight_to_roof_ratio(model) ⇒ Boolean
Reduces the SRR to the values specified by the PRM.
-
#model_apply_prm_construction_types(model) ⇒ Boolean
Go through the default construction sets and hard-assigned constructions.
-
#model_apply_standard_constructions(model, climate_zone, wwr_building_type: nil, wwr_info: {}) ⇒ Boolean
Apply the standard construction to each surface in the model, based on the construction type currently assigned.
-
#model_apply_standard_infiltration(model, specific_space_infiltration_rate_75_pa = nil) ⇒ Boolean
This method creates customized infiltration objects for each space and removes the SpaceType-level infiltration objects.
-
#model_baseline_system_vav_fan_type(model) ⇒ String
Determines the fan type used by VAV_Reheat and VAV_PFP_Boxes systems.
-
#model_building_envelope_area(model) ⇒ Double
Calculate the building envelope area according to the 90.1 definition.
-
#model_create_multizone_fan_schedule(model, zone_op_hrs, pri_zones, system_name) ⇒ Object
For a multizone system, create the fan schedule based on zone occupancy/fan schedules.
-
#model_current_building_envelope_infiltration_at_75pa(model, building_envelope_area_m2) ⇒ Double
This methods calculate the current model air leakage rate @ 75 Pa.
-
#model_differentiate_primary_secondary_thermal_zones(model, zones, zone_fan_scheds) ⇒ Hash
For a multizone system, identify any zones to isolate to separate PSZ systems isolated zones are on the ‘secondary’ list This version of the method applies to standard years 2016 and later (stable baseline).
-
#model_does_require_wwr_adjustment?(wwr_limit, wwr_list) ⇒ Boolean
This function checks whether it is required to adjust the window to wall ratio based on the model WWR and wwr limit.
-
#model_evaluate_dcv_requirements(model) ⇒ Boolean
Template method for evaluate DCV requirements in the user model.
-
#model_get_bat_wwr_target(bat, wwr_list) ⇒ Double
For 2019, it is required to adjusted wwr based on building categories for all other types.
-
#model_get_fan_power_breakdown ⇒ Boolean
Indicate if fan power breakdown (supply, return, and relief) are needed.
-
#model_get_infiltration_coefficients(model) ⇒ String
This method retrieves the infiltration coefficients used in the model.
-
#model_get_infiltration_method(model) ⇒ String
This method retrieves the type of infiltration input used in the model.
-
#model_get_space_air_leakage(space) ⇒ Double
This methods calculate the air leakage rate of a space.
-
#model_identify_non_mechanically_cooled_systems(model) ⇒ Hash
Identifies non mechanically cooled (“nmc”) systems, if applicable and add a flag to the zone’s and air loop’s additional properties.
-
#model_mark_zone_dcv_existence(model) ⇒ Boolean
Add zone additional property “zone DCV implemented in user model”: - ‘true’ if zone OA flow requirement is specified as per person & airloop supporting this zone has DCV enabled - ‘false’ otherwise.
-
#model_prm_baseline_system_change_fuel_type(model, fuel_type, climate_zone) ⇒ String
Change the fuel type based on climate zone, depending on the standard.
-
#model_prm_baseline_system_groups(model, custom, bldg_type_hvac_zone_hash) ⇒ Array<Hash>
Assign spaces to system groups based on building area type Get zone groups separately for each hvac building type.
-
#model_prm_baseline_system_number(model, climate_zone, area_type, fuel_type, area_ft2, num_stories, custom) ⇒ String
Determines which system number is used for the baseline system.
-
#model_prm_baseline_system_type(model, climate_zone, sys_group, custom, hvac_building_type, district_heat_zones) ⇒ String
Alternate method for 2016 and later stable baseline Limits for each building area type are taken from data table Heating fuel is based on climate zone, unless district heat is in proposed.
-
#model_raise_user_model_dcv_errors(model) ⇒ Object
based on previously added flag, raise error if DCV is required but not implemented in zones, in which case baseline generation will be terminated; raise warning if DCV is not required but implemented, and continue baseline generation.
-
#model_readjust_surface_wwr(residual_ratio, space, model) ⇒ Boolean
Readjusted the WWR for surfaces previously has no windows to meet the overall WWR requirement.
-
#model_refine_size_dependent_values(model, sizing_run_dir) ⇒ Boolean
This method is a catch-all run at the end of create-baseline to make final adjustements to HVAC capacities to account for recent model changes.
-
#model_set_baseline_demand_control_ventilation(model, climate_zone) ⇒ Object
Set DCV in baseline HVAC system if required.
-
#model_set_central_preheat_coil_spm(model, thermal_zones, coil) ⇒ Boolean
Template method for adding a setpoint manager for a coil control logic to a heating coil.
-
#model_update_ground_temperature_profile(model, climate_zone) ⇒ Boolean
Update ground temperature profile based on the weather file specified in the model.
-
#run_all_orientations(run_all_orients, user_model) ⇒ Boolean
Check whether the baseline model generation needs to run all four orientations The default shall be true The orientation takes priority of: 1.
-
#set_coil_cooling_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) ⇒ Hash
This function returns the cooling dx coil efficiency and curve coefficient in a Hashmap.
-
#set_coil_heating_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) ⇒ Hash
This function returns the heating dx coil efficiency and curve coefficient in a Hashmap.
-
#surface_get_wwr_reduction_ratio(multiplier, surface, wwr_building_type: 'All others', wwr_target: nil, total_wall_m2: 0.0, total_wall_with_fene_m2: 0.0, total_fene_m2: 0.0, total_plenum_wall_m2: 0.0) ⇒ Double
Calculate the window to wall ratio reduction factor.
-
#thermal_zone_prm_lab_delta_t(thermal_zone) ⇒ Double
Specify supply to room delta for laboratory spaces based on 90.1 Appendix G Exception to G3.1.2.8.1.
-
#thermal_zone_prm_unitheater_design_supply_temperature(thermal_zone) ⇒ Double
Specify supply air temperature setpoint for unit heaters based on 90.1 Appendix G G3.1.2.8.2.
Space collapse
-
#space_add_prm_computer_room_equipment_schedule(space) ⇒ Boolean
Create and assign PRM computer room electric equipment schedule.
-
#space_apply_infiltration_rate(space, tot_infil_m3_per_s, infil_method, infil_coefficients) ⇒ Boolean
Set the infiltration rate for this space to include the impact of air leakage requirements in the standard.
-
#space_set_baseline_daylighting_controls(space, remove_existing = false, draw_areas_for_debug = false) ⇒ Boolean
For stable baseline, remove all daylighting controls (sidelighting and toplighting).
SpaceType collapse
-
#calculate_electric_value_by_userdata(user_equip_data, power_equipment, power_schedule_hash, space_type, user_space_data = nil) ⇒ Boolean
A function to calculate electric value for an electric equipment.
-
#calculate_lpd_by_space(space_type, space) ⇒ Double
calculate the lighting power density per area based on space type The function will calculate the LPD based on the space type (STRING) It considers lighting per area, lighting per length as well as occupancy factors in the database.
-
#calculate_lpd_from_userdata(user_data, space) ⇒ Double
Calculate the lighting power density per area based on user data (space_based) The function will calculate the LPD based on the space type (STRING) It considers lighting per area, lighting per length as well as occupancy factors in the database.
- #deep_copy_schedule(new_schedule_name, schedule, adjustment_factor, model) ⇒ Object
-
#has_multi_lpd_values_space_type(space_type) ⇒ Boolean
Function checks whether there are multi lpd values in the space type multi-lpd value means there are multiple spaces and the lighting_per_length > 0.
-
#has_multi_lpd_values_user_data(user_data, space_type) ⇒ Boolean
Function checks whether there are multi lpd values in the space type from user’s data The sum of each space fraction in the user_data is assumed to be 1.0 multi-lpd value means lighting per area > 0 and lighting_per_length > 0.
-
#has_user_lpd_values(user_space_data) ⇒ Boolean
Function checks whether the user data contains lighting data.
-
#set_lpd_on_space_type(space_type, user_spaces, user_spacetypes) ⇒ Boolean
Function to test LPD on default space type.
-
#space_to_space_type_apply_lighting(user_spaces, user_spacetypes, space_type) ⇒ ArrayOpenStudio::Model::Space
Function that applies user LPD to each space by duplicating space types This function is used when there are user space data available or the spaces under space type has lighting per length value which may cause multiple lighting power densities under one space_type.
-
#space_to_space_type_apply_power_equipment(user_spacetypes, user_spaces, space_array) ⇒ Boolean
Apply space to space type power equipment adjustment.
-
#space_type_apply_internal_loads(space_type, set_people, set_lights, set_electric_equipment, set_gas_equipment, set_ventilation, set_infiltration) ⇒ Boolean
Sets the selected internal loads to standards-based or typical values.
-
#space_type_apply_power_equipment(space_type) ⇒ Boolean
Apply power equipment to space type This is utility function for applying user data to space type.
-
#space_type_light_sch_change(model) ⇒ Object
Modify the lighting schedules for Appendix G PRM for 2016 and later.
-
#update_power_equipment_credits(power_equipment, user_power_equipment, schedule_hash, space_type, user_data = nil) ⇒ Boolean
Function update a power equipment schedule based on user data.
AirLoopHVAC collapse
-
#air_loop_hvac_allowable_system_brake_horsepower(air_loop_hvac) ⇒ Double
Determine the allowable fan system brake horsepower Per Section G3.1.2.9.
-
#air_loop_hvac_apply_energy_recovery_ventilator_efficiency(erv, erv_type: 'ERV', heat_exchanger_type: 'Rotary') ⇒ OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent
Set effectiveness value of an ERV’s heat exchanger.
-
#air_loop_hvac_apply_minimum_vav_damper_positions(air_loop_hvac, has_ddc = true) ⇒ Boolean
Set the minimum VAV damper positions.
-
#air_loop_hvac_apply_prm_baseline_fan_power(air_loop_hvac) ⇒ Object
Calculate and apply the performance rating method baseline fan power to this air loop based on the system type that it represents.
-
#air_loop_hvac_economizer_limits(air_loop_hvac, climate_zone) ⇒ Array<Double>
Determine the limits for the type of economizer present on the AirLoopHVAC, if any.
-
#air_loop_hvac_enable_unoccupied_fan_shutoff(air_loop_hvac, min_occ_pct = 0.05) ⇒ Boolean
Shut off the system during unoccupied periods.
-
#air_loop_hvac_energy_recovery_ventilator_flow_limit(air_loop_hvac, climate_zone, pct_oa) ⇒ Double
Determine the airflow limits that govern whether or not an ERV is required.
-
#air_loop_hvac_fan_power_limitation_pressure_drop_adjustment_brake_horsepower(air_loop_hvac) ⇒ Double
Determine the fan power limitation pressure drop adjustment Per Table 6.5.3.1-2 (90.1-2019).
-
#air_loop_hvac_integrated_economizer_required?(air_loop_hvac, climate_zone) ⇒ Boolean
Determine if the system economizer must be integrated or not.
-
#air_loop_hvac_multizone_vav_system?(air_loop_hvac) ⇒ Boolean
Determine if the system is a multizone VAV system.
-
#air_loop_hvac_optimum_start_required?(air_loop_hvac) ⇒ Boolean
Determines if optimum start control is required.
-
#air_loop_hvac_prm_baseline_economizer_required?(air_loop_hvac, climate_zone) ⇒ Boolean
Determine if an economizer is required per the PRM.
-
#air_loop_hvac_prm_economizer_type_and_limits(air_loop_hvac, climate_zone) ⇒ Array<Double>
Determine the economizer type and limits for the the PRM Defaults to 90.1-2007 logic.
-
#air_loop_hvac_set_vsd_curve_type ⇒ String name of appropriate curve for this code version
Set fan curve for stable baseline to be VSD with fixed static pressure setpoint.
-
#air_loop_hvac_unoccupied_threshold ⇒ Object
Default occupancy fraction threshold for determining if the spaces on the air loop are occupied.
-
#air_loop_hvac_vav_damper_action(air_loop_hvac) ⇒ String
Determine whether the VAV damper control is single maximum or dual maximum control.
-
#baseline_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) ⇒ Boolean
Check if the air loop in baseline model needs to have DCV.
-
#baseline_thermal_zone_demand_control_ventilation_required?(thermal_zone) ⇒ Boolean
Check if the thermal zone in baseline model needs to have DCV.
-
#get_airloop_hvac_design_oa_from_sql(air_loop_hvac) ⇒ Double
Get the air loop HVAC design outdoor air flow rate by reading Standard 62.1 Summary from the sizing sql.
-
#user_model_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) ⇒ Boolean
Check if an air loop in user model needs to have DCV per air loop related requiremends in ASHRAE 90.1-2019 6.4.3.8.
-
#user_model_zone_demand_control_ventilation_required?(thermal_zone) ⇒ Boolean
Check if a zone in user model needs to have DCV per zone related requiremends in ASHRAE 90.1-2019 6.4.3.8.
ThermalZone collapse
-
#thermal_zone_get_fan_power_limitations(thermal_zone, is_energy_recovery_required) ⇒ Object
Determine the fan power limitation pressure drop adjustment Per Table 6.5.3.1-2 (90.1-2019).
-
#thermal_zone_get_zone_fuels_for_occ_and_fuel_type(thermal_zone) ⇒ String with applicable DistrictHeating and/or DistrictCooling
Identify if zone has district energy for occ_and_fuel_type method.
PlanarSurface collapse
-
#planar_surface_apply_standard_construction(planar_surface, climate_zone, previous_construction_map = {}, wwr_building_type = nil, wwr_info = {}, surface_category) ⇒ Hash
If construction properties can be found based on the template, the standards intended surface type, the standards construction type, the climate zone, and the occupancy type, create a construction that meets those properties and assign it to this surface.
BoilerHotWater collapse
-
#boiler_get_eff_fplr(boiler_hot_water) ⇒ String
Determine what part load efficiency degredation curve should be used for a boiler.
-
#boiler_hot_water_apply_efficiency_and_curves(boiler_hot_water) ⇒ Boolean
Applies the standard efficiency ratings to this object.
-
#coil_heating_gas_apply_efficiency_and_curves(coil_heating_gas, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings and typical performance curves to this object.
-
#coil_heating_gas_find_search_criteria(coil_heating_gas, sys_type) ⇒ Hash
find search criteria.
-
#coil_heating_gas_standard_minimum_thermal_efficiency(coil_heating_gas, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return minimum thermal efficiency.
ZoneHVACComponent collapse
-
#zone_hvac_component_apply_prm_baseline_fan_power(zone_hvac_component) ⇒ Boolean
Sets the fan power of zone level HVAC equipment (Fan coils, Unit Heaters, PTACs, PTHPs, VRF Terminals, WSHPs, ERVs) based on the W/cfm specified in the standard.
-
#zone_hvac_unoccupied_threshold ⇒ Double
Default occupancy fraction threshold for determining if the spaces served by the zone hvac are occupied.
ChillerElectricEIR collapse
-
#chiller_electric_eir_apply_efficiency_and_curves(chiller_electric_eir) ⇒ Boolean
Applies the standard efficiency ratings to this object.
HeatExchangerSensLat collapse
-
#heat_exchanger_air_to_air_sensible_and_latent_design_conditions(heat_exchanger_air_to_air_sensible_and_latent, climate_zone) ⇒ String
Determine the heat exchanger design conditions for a specific climate zones.
-
#heat_exchanger_air_to_air_sensible_and_latent_enthalpy_recovery_ratio(heat_exchanger_air_to_air_sensible_and_latent) ⇒ Double
Determine the required enthalpy recovery ratio (ERR).
-
#heat_exchanger_air_to_air_sensible_and_latent_minimum_effectiveness(heat_exchanger_air_to_air_sensible_and_latent) ⇒ Array
Defines the minimum sensible and latent effectiveness of the heat exchanger.
AirTerminalSingleDuctVAVReheat collapse
-
#air_terminal_single_duct_vav_reheat_apply_minimum_damper_position(air_terminal_single_duct_vav_reheat, zone_min_oa = nil, has_ddc = true) ⇒ Boolean
Set the minimum damper position based on OA rate of the space and the template.
AirTerminalSingleDuctParallelPIUReheat collapse
-
#air_terminal_single_duct_parallel_piu_reheat_fan_on_flow_fraction ⇒ Double
Return the fan on flow fraction for a parallel PIU terminal.
Instance Method Summary collapse
-
#add_ems_for_multiple_chiller_pumps_w_secondary_plant(model, primary_plant) ⇒ Object
Adds EMS program for pumps serving 3 chillers on primary + secondary loop.
-
#add_ems_program_for_2_pump_chiller_plant(model, sorted_chiller_list, primary_plant) ⇒ Object
Adds EMS program for pumps serving 2 chillers on primary + secondary loop.
-
#add_ems_program_for_3_pump_chiller_plant(model, sorted_chiller_list, primary_plant) ⇒ Object
Adds EMS program for pumps serving 3 chillers on primary + secondary loop.
-
#check_userdata_airloop_hvac(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::AIRLOOP_HVAC].
-
#check_userdata_airloop_hvac_doas(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::AIRLOOP_HVAC_DOAS].
-
#check_userdata_building(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::BUILDING].
-
#check_userdata_electric_equipment(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
-
#check_userdata_exterior_lighting(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
-
#check_userdata_gas_equipment(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
-
#check_userdata_lights(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::LIGHTS].
-
#check_userdata_outdoor_air(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::DESIGN_SPECIFICATION_OUTDOOR_AIR].
-
#check_userdata_space_and_spacetype(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
-
#check_userdata_thermal_zone(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::THERMAL_ZONE].
-
#check_userdata_wateruse_connections(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
-
#check_userdata_wateruse_equipment(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
-
#check_userdata_wateruse_equipment_definition(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
-
#check_userdata_zone_hvac(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::ZONE_HVAC].
-
#chw_sizing_control(model, chilled_water_loop, dsgn_sup_wtr_temp, dsgn_sup_wtr_temp_delt) ⇒ Boolean
Apply sizing and controls to chilled water loop.
-
#coil_cooling_dx_single_speed_apply_efficiency_and_curves(coil_cooling_dx_single_speed, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings to this object.
-
#coil_cooling_dx_single_speed_find_capacity(coil_cooling_dx_single_speed, sys_type) ⇒ Double
Finds capacity in W.
-
#coil_cooling_dx_single_speed_standard_minimum_cop(coil_cooling_dx_single_speed, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return efficiency.
-
#coil_cooling_dx_two_speed_apply_efficiency_and_curves(coil_cooling_dx_two_speed, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings to this object.
-
#coil_cooling_dx_two_speed_find_capacity(coil_cooling_dx_two_speed, sys_type) ⇒ Double
Finds capacity in W.
-
#coil_cooling_dx_two_speed_standard_minimum_cop(coil_cooling_dx_two_speed, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return efficiency.
-
#coil_heating_dx_single_speed_apply_efficiency_and_curves(coil_heating_dx_single_speed, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings and typical performance curves to this object.
-
#coil_heating_dx_single_speed_find_capacity(coil_heating_dx_single_speed, sys_type) ⇒ Double
Finds capacity in W.
-
#coil_heating_dx_single_speed_standard_minimum_cop(coil_heating_dx_single_speed, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return efficiency.
-
#convert_userdata_csv_to_json(user_data_path, project_path) ⇒ String
Convert user data csv files to json format and save to project folder Method will create the json_folder in the project_path.
-
#fan_variable_volume_part_load_fan_power_limitation?(fan_variable_volume) ⇒ Boolean
Determines whether there is a requirement to have a VSD or some other method to reduce fan power at low part load ratios.
-
#fan_variable_volume_part_load_fan_power_limitation_hp_limit(fan_variable_volume) ⇒ Double
The threhold horsepower below which part load control is not required.
-
#generate_userdata_to_csv(user_model, user_data_path, user_data_file = nil) ⇒ Object
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.
-
#initialize ⇒ ASHRAE901PRM
constructor
A new instance of ASHRAE901PRM.
- #load_standards_database(data_directories = []) ⇒ Object
-
#load_userdata_to_standards_database(json_path) ⇒ Object
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.
-
#plant_loop_apply_prm_baseline_pump_power(plant_loop) ⇒ Boolean
Apply prm baseline pump power.
-
#plant_loop_apply_prm_number_of_chillers(plant_loop) ⇒ Boolean
Splits the single chiller used for the initial sizing run into multiple separate chillers based on Appendix G.
-
#plant_loop_apply_prm_number_of_cooling_towers(plant_loop) ⇒ Boolean
Returns true if successful, false if not.
-
#plant_loop_set_chw_pri_sec_configuration(model) ⇒ String
Set configuration in model for chilled water primary/secondary loop interface Use heat_exchanger for stable baseline.
-
#stage_chilled_water_loop_operation_schemes(model, chilled_water_loop) ⇒ Object
Updates a chilled water plant’s operation scheme to match the EMS written by either add_ems_program_for_3_pump_chiller_plant or add_ems_program_for_2_pump_chiller_plant.
-
#surface_adjust_fenestration_in_a_surface(surface, reduction, model) ⇒ Boolean
Adjust the fenestration area to the values specified by the reduction value in a surface.
-
#user_data_preprocessor(row) ⇒ Object
Perform user data preprocessing.
-
#user_data_validation(object_name, user_data) ⇒ Boolean
True if data is valid, false if error found.
Methods included from ASHRAEPRMCoilDX
#coil_dx_find_search_criteria, #coil_dx_subcategory
Methods included from ASHRAE901PRMFan
#fan_standard_minimum_motor_efficiency_and_size
Methods inherited from Standard
#adjust_sizing_system, #afue_to_thermal_eff, #air_loop_hvac_add_motorized_oa_damper, #air_loop_hvac_adjust_minimum_vav_damper_positions, #air_loop_hvac_adjust_minimum_vav_damper_positions_outpatient, #air_loop_hvac_apply_baseline_fan_pressure_rise, #air_loop_hvac_apply_economizer_integration, #air_loop_hvac_apply_economizer_limits, #air_loop_hvac_apply_energy_recovery_ventilator, #air_loop_hvac_apply_maximum_reheat_temperature, #air_loop_hvac_apply_multizone_vav_outdoor_air_sizing, #air_loop_hvac_apply_prm_baseline_controls, #air_loop_hvac_apply_prm_baseline_economizer, #air_loop_hvac_apply_prm_sizing_temperatures, #air_loop_hvac_apply_single_zone_controls, #air_loop_hvac_apply_standard_controls, #air_loop_hvac_apply_vav_damper_action, #air_loop_hvac_data_center_area_served, #air_loop_hvac_dcv_required_when_erv, #air_loop_hvac_demand_control_ventilation_limits, #air_loop_hvac_demand_control_ventilation_required?, #air_loop_hvac_disable_multizone_vav_optimization, #air_loop_hvac_dx_cooling?, #air_loop_hvac_economizer?, #air_loop_hvac_economizer_required?, #air_loop_hvac_economizer_type_allowable?, #air_loop_hvac_enable_demand_control_ventilation, #air_loop_hvac_enable_multizone_vav_optimization, #air_loop_hvac_enable_optimum_start, #air_loop_hvac_enable_supply_air_temperature_reset_delta, #air_loop_hvac_enable_supply_air_temperature_reset_outdoor_temperature, #air_loop_hvac_enable_supply_air_temperature_reset_warmest_zone, #air_loop_hvac_energy_recovery?, #air_loop_hvac_energy_recovery_ventilator_heat_exchanger_type, #air_loop_hvac_energy_recovery_ventilator_required?, #air_loop_hvac_energy_recovery_ventilator_type, #air_loop_hvac_find_design_supply_air_flow_rate, #air_loop_hvac_floor_area_served, #air_loop_hvac_floor_area_served_exterior_zones, #air_loop_hvac_floor_area_served_interior_zones, #air_loop_hvac_get_occupancy_schedule, #air_loop_hvac_get_relief_fan_power, #air_loop_hvac_get_return_fan_power, #air_loop_hvac_get_supply_fan, #air_loop_hvac_get_supply_fan_power, #air_loop_hvac_has_parallel_piu_air_terminals?, #air_loop_hvac_has_simple_transfer_air?, #air_loop_hvac_humidifier_count, #air_loop_hvac_include_cooling_coil?, #air_loop_hvac_include_economizer?, #air_loop_hvac_include_evaporative_cooler?, #air_loop_hvac_include_hydronic_cooling_coil?, #air_loop_hvac_include_unitary_system?, #air_loop_hvac_include_wshp?, #air_loop_hvac_minimum_zone_ventilation_efficiency, #air_loop_hvac_motorized_oa_damper_limits, #air_loop_hvac_motorized_oa_damper_required?, #air_loop_hvac_multi_stage_dx_cooling?, #air_loop_hvac_multizone_vav_optimization_required?, #air_loop_hvac_remove_erv, #air_loop_hvac_remove_motorized_oa_damper, #air_loop_hvac_residential_area_served, #air_loop_hvac_return_air_plenum, #air_loop_hvac_set_minimum_damper_position, #air_loop_hvac_single_zone_controls_num_stages, #air_loop_hvac_standby_mode_occupancy_control, #air_loop_hvac_static_pressure_reset_required?, #air_loop_hvac_supply_air_temperature_reset_required?, #air_loop_hvac_supply_return_exhaust_relief_fans, #air_loop_hvac_system_fan_brake_horsepower, #air_loop_hvac_system_multiplier, #air_loop_hvac_terminal_reheat?, #air_loop_hvac_total_cooling_capacity, #air_loop_hvac_unitary_system?, #air_loop_hvac_unoccupied_fan_shutoff_required?, #air_loop_hvac_vav_system?, #air_terminal_single_duct_parallel_piu_reheat_apply_minimum_primary_airflow_fraction, #air_terminal_single_duct_parallel_piu_reheat_apply_prm_baseline_fan_power, #air_terminal_single_duct_parallel_reheat_piu_minimum_primary_airflow_fraction, #air_terminal_single_duct_vav_reheat_apply_initial_prototype_damper_position, #air_terminal_single_duct_vav_reheat_minimum_damper_position, #air_terminal_single_duct_vav_reheat_reheat_type, #air_terminal_single_duct_vav_reheat_set_heating_cap, #apply_lighting_schedule, #apply_limit_to_subsurface_ratio, #boiler_hot_water_find_capacity, #boiler_hot_water_find_design_water_flow_rate, #boiler_hot_water_find_search_criteria, #boiler_hot_water_standard_minimum_thermal_efficiency, build, #chiller_electric_eir_find_capacity, #chiller_electric_eir_find_search_criteria, #chiller_electric_eir_get_cap_f_t_curve_name, #chiller_electric_eir_get_eir_f_plr_curve_name, #chiller_electric_eir_get_eir_f_t_curve_name, #chiller_electric_eir_standard_minimum_full_load_efficiency, #coil_cooling_dx_multi_speed_apply_efficiency_and_curves, #coil_cooling_dx_multi_speed_find_capacity, #coil_cooling_dx_multi_speed_standard_minimum_cop, #coil_cooling_water_to_air_heat_pump_apply_efficiency_and_curves, #coil_cooling_water_to_air_heat_pump_find_capacity, #coil_cooling_water_to_air_heat_pump_standard_minimum_cop, #coil_heating_dx_multi_speed_apply_efficiency_and_curves, #coil_heating_dx_single_speed_apply_defrost_eir_curve_limits, #coil_heating_gas_additional_search_criteria, #coil_heating_gas_apply_prototype_efficiency, #coil_heating_gas_find_capacity, #coil_heating_gas_multi_stage_apply_efficiency_and_curves, #coil_heating_gas_multi_stage_find_capacity, #coil_heating_gas_multi_stage_find_search_criteria, #coil_heating_water_to_air_heat_pump_apply_efficiency_and_curves, #coil_heating_water_to_air_heat_pump_find_capacity, #coil_heating_water_to_air_heat_pump_standard_minimum_cop, #combustion_eff_to_thermal_eff, #controller_water_coil_set_convergence_limits, #convert_curve_biquadratic, #cooling_tower_single_speed_apply_efficiency_and_curves, #cooling_tower_two_speed_apply_efficiency_and_curves, #cooling_tower_variable_speed_apply_efficiency_and_curves, #cop_heating_to_cop_heating_no_fan, #cop_no_fan_to_eer, #cop_no_fan_to_seer, #cop_to_eer, #cop_to_kw_per_ton, #cop_to_seer, #create_air_conditioner_variable_refrigerant_flow, #create_boiler_hot_water, #create_central_air_source_heat_pump, #create_coil_cooling_dx_single_speed, #create_coil_cooling_dx_two_speed, #create_coil_cooling_water, #create_coil_cooling_water_to_air_heat_pump_equation_fit, #create_coil_heating_dx_single_speed, #create_coil_heating_electric, #create_coil_heating_gas, #create_coil_heating_water, #create_coil_heating_water_to_air_heat_pump_equation_fit, #create_curve_bicubic, #create_curve_biquadratic, #create_curve_cubic, #create_curve_exponent, #create_curve_quadratic, #create_fan_constant_volume, #create_fan_constant_volume_from_json, #create_fan_on_off, #create_fan_on_off_from_json, #create_fan_variable_volume, #create_fan_variable_volume_from_json, #create_fan_zone_exhaust, #create_fan_zone_exhaust_from_json, #define_space_multiplier, #eer_to_cop, #eer_to_cop_no_fan, #ems_friendly_name, #enthalpy_recovery_ratio_design_to_typical_adjustment, #fan_constant_volume_airloop_fan_pressure_rise, #fan_constant_volume_apply_prototype_fan_pressure_rise, #fan_on_off_airloop_or_unitary_fan_pressure_rise, #fan_on_off_apply_prototype_fan_pressure_rise, #fan_variable_volume_airloop_fan_pressure_rise, #fan_variable_volume_apply_prototype_fan_pressure_rise, #fan_variable_volume_cooling_system_type, #fan_variable_volume_part_load_fan_power_limitation_capacity_limit, #fan_variable_volume_set_control_type, #fan_zone_exhaust_apply_prototype_fan_pressure_rise, #find_exposed_conditioned_roof_surfaces, #find_exposed_conditioned_vertical_surfaces, #find_highest_roof_centre, #fluid_cooler_apply_minimum_power_per_flow, #get_avg_of_other_zones, #get_default_surface_cons_from_surface_type, #get_fan_object_for_airloop, #get_fan_schedule_for_each_zone, #get_group_heat_types, #get_outdoor_subsurface_ratio, #get_weekday_values_from_8760, #get_wtd_avg_of_other_zones, #headered_pumps_variable_speed_set_control_type, #heat_exchanger_air_to_air_sensible_and_latent_apply_effectiveness, #heat_exchanger_air_to_air_sensible_and_latent_apply_prototype_efficiency, #heat_exchanger_air_to_air_sensible_and_latent_apply_prototype_efficiency_enthalpy_recovery_ratio, #heat_exchanger_air_to_air_sensible_and_latent_apply_prototype_nominal_electric_power, #heat_exchanger_air_to_air_sensible_and_latent_enthalpy_recovery_ratio_to_effectiveness, #heat_exchanger_air_to_air_sensible_and_latent_prototype_default_fan_efficiency, #hspf_to_cop, #hspf_to_cop_no_fan, #interior_lighting_get_prm_data, #kw_per_ton_to_cop, #load_hvac_map, #load_initial_osm, #make_ruleset_sched_from_8760, #make_week_ruleset_sched_from_168, #model_add_baseboard, #model_add_cav, #model_add_central_air_source_heat_pump, #model_add_chw_loop, #model_add_construction, #model_add_construction_set, #model_add_crac, #model_add_crah, #model_add_curve, #model_add_cw_loop, #model_add_data_center_hvac, #model_add_data_center_load, #model_add_daylighting_controls, #model_add_district_ambient_loop, #model_add_doas, #model_add_doas_cold_supply, #model_add_elevator, #model_add_elevators, #model_add_evap_cooler, #model_add_exhaust_fan, #model_add_four_pipe_fan_coil, #model_add_furnace_central_ac, #model_add_ground_hx_loop, #model_add_high_temp_radiant, #model_add_hp_loop, #model_add_hvac, #model_add_hvac_system, #model_add_hw_loop, #model_add_ideal_air_loads, #model_add_low_temp_radiant, #model_add_material, #model_add_minisplit_hp, #model_add_plant_supply_water_temperature_control, #model_add_prm_baseline_system, #model_add_psz_ac, #model_add_psz_vav, #model_add_ptac, #model_add_pthp, #model_add_pvav, #model_add_pvav_pfp_boxes, #model_add_radiant_basic_controls, #model_add_radiant_proportional_controls, #model_add_refrigeration_case, #model_add_refrigeration_compressor, #model_add_refrigeration_system, #model_add_refrigeration_walkin, #model_add_residential_erv, #model_add_residential_ventilator, #model_add_schedule, #model_add_split_ac, #model_add_swh, #model_add_swh_end_uses_by_space, #model_add_transformer, #model_add_typical_exterior_lights, #model_add_typical_refrigeration, #model_add_typical_swh, #model_add_unitheater, #model_add_vav_pfp_boxes, #model_add_vav_reheat, #model_add_vrf, #model_add_water_source_hp, #model_add_waterside_economizer, #model_add_window_ac, #model_add_zone_erv, #model_add_zone_heat_cool_request_count_program, #model_add_zone_ventilation, #model_apply_infiltration_standard, #model_apply_prm_baseline_window_to_wall_ratio, #model_apply_prm_sizing_parameters, #model_create_exterior_lighting_area_length_count_hash, #model_create_prm_any_baseline_building, #model_create_prm_baseline_building, #model_create_prm_baseline_building_requires_proposed_model_sizing_run, #model_create_prm_baseline_building_requires_vlt_sizing_run, #model_create_prm_proposed_building, #model_create_prm_stable_baseline_building, #model_create_space_type_hash, #model_create_story_hash, #model_cw_loop_cooling_tower_fan_type, #model_effective_num_stories, #model_elevator_fan_pwr, #model_elevator_lift_power, #model_elevator_lighting_pct_incandescent, #model_eliminate_outlier_zones, #model_find_and_add_construction, #model_find_ashrae_hot_water_demand, #model_find_climate_zone_set, #model_find_icc_iecc_2015_hot_water_demand, #model_find_icc_iecc_2015_internal_loads, #model_find_object, #model_find_objects, #model_find_prototype_floor_area, #model_find_target_eui, #model_find_target_eui_by_end_use, #model_find_water_heater_capacity_volume_and_parasitic, #model_get_baseline_system_type_by_zone, #model_get_building_properties, #model_get_climate_zone_set_from_list, #model_get_construction_properties, #model_get_construction_set, #model_get_district_heating_zones, #model_get_lookup_name, #model_get_or_add_ambient_water_loop, #model_get_or_add_chilled_water_loop, #model_get_or_add_ground_hx_loop, #model_get_or_add_heat_pump_loop, #model_get_or_add_hot_water_loop, #model_is_hvac_autosized, #model_legacy_results_by_end_use_and_fuel_type, #model_make_name, #model_prm_skylight_to_roof_ratio_limit, #model_process_results_for_datapoint, #model_remap_office, #model_remove_external_shading_devices, #model_remove_prm_ems_objects, #model_remove_prm_hvac, #model_remove_unused_resource_objects, #model_set_vav_terminals_to_control_for_outdoor_air, #model_system_outdoor_air_sizing_vrp_method, #model_two_pipe_loop, #model_typical_display_case_zone, #model_typical_hvac_system_type, #model_typical_walkin_zone, #model_validate_standards_spacetypes_in_model, #model_ventilation_method, #model_walkin_freezer_latent_case_credit_curve, #model_zones_with_occ_and_fuel_type, #plant_loop_adiabatic_pipes_only, #plant_loop_apply_prm_baseline_chilled_water_pumping_type, #plant_loop_apply_prm_baseline_chilled_water_temperatures, #plant_loop_apply_prm_baseline_condenser_water_pumping_type, #plant_loop_apply_prm_baseline_condenser_water_temperatures, #plant_loop_apply_prm_baseline_hot_water_pumping_type, #plant_loop_apply_prm_baseline_hot_water_temperatures, #plant_loop_apply_prm_baseline_pumping_type, #plant_loop_apply_prm_baseline_temperatures, #plant_loop_apply_prm_number_of_boilers, #plant_loop_apply_standard_controls, #plant_loop_capacity_w_by_maxflow_and_delta_t_forwater, #plant_loop_enable_supply_water_temperature_reset, #plant_loop_find_maximum_loop_flow_rate, #plant_loop_prm_baseline_condenser_water_temperatures, #plant_loop_supply_water_temperature_reset_required?, #plant_loop_swh_loop?, #plant_loop_swh_system_type, #plant_loop_total_cooling_capacity, #plant_loop_total_floor_area_served, #plant_loop_total_heating_capacity, #plant_loop_total_rated_w_per_gpm, #plant_loop_variable_flow_system?, #prototype_apply_condenser_water_temperatures, #prototype_condenser_water_temperatures, #pump_variable_speed_control_type, #pump_variable_speed_get_control_type, #pump_variable_speed_set_control_type, register_standard, #remove_air_loops, #remove_all_hvac, #remove_all_plant_loops, #remove_all_zone_equipment, #remove_hvac, #remove_plant_loops, #remove_unused_curves, #remove_vrf, #remove_zone_equipment, #rename_air_loop_nodes, #rename_plant_loop_nodes, #safe_load_model, #seer_to_cop, #seer_to_cop_no_fan, #set_maximum_fraction_outdoor_air_schedule, #space_add_daylighting_controls, #space_conditioning_category, #space_daylighted_area_window_width, #space_daylighted_areas, #space_daylighting_control_required?, #space_daylighting_fractions_and_windows, #space_get_equip_annual_array, #space_get_loads_for_all_equips, #space_infiltration_rate_75_pa, #space_internal_load_annual_array, #space_occupancy_annual_array, #space_remove_daylighting_controls, #space_sidelighting_effective_aperture, #space_skylight_effective_aperture, #space_type_apply_int_loads_prm, #space_type_apply_internal_load_schedules, #space_type_apply_rendering_color, #space_type_get_construction_properties, #space_type_get_standards_data, #standard_design_sizing_temperatures, #standards_lookup_table_first, #standards_lookup_table_many, #strip_model, #sub_surface_create_centered_subsurface_from_scaled_surface, #sub_surface_create_scaled_subsurfaces_from_surface, #surface_subsurface_ua, #thermal_eff_to_afue, #thermal_eff_to_comb_eff, #thermal_zone_add_exhaust, #thermal_zone_add_exhaust_fan_dcv, #thermal_zone_apply_prm_baseline_supply_temperatures, #thermal_zone_conditioning_category, #thermal_zone_demand_control_ventilation_limits, #thermal_zone_demand_control_ventilation_required?, #thermal_zone_exhaust_fan_dcv_required?, #thermal_zone_fossil_or_electric_type, #thermal_zone_get_annual_operating_hours, #thermal_zone_infer_system_type, #thermal_zone_occupancy_eflh, #thermal_zone_occupancy_type, #thermal_zone_peak_internal_load, #thermal_zone_prm_baseline_cooling_design_supply_temperature, #thermal_zone_prm_baseline_heating_design_supply_temperature, #true?, #validate_initial_model, #water_heater_convert_energy_factor_to_thermal_efficiency_and_ua, #water_heater_convert_uniform_energy_factor_to_energy_factor, #water_heater_determine_sub_type, #water_heater_mixed_additional_search_criteria, #water_heater_mixed_apply_efficiency, #water_heater_mixed_apply_prm_baseline_fuel_type, #water_heater_mixed_find_capacity, #water_heater_mixed_get_efficiency_requirement, #zone_hvac_component_apply_standard_controls, #zone_hvac_component_apply_vestibule_heating_control, #zone_hvac_component_occupancy_ventilation_control, #zone_hvac_component_prm_baseline_fan_efficacy, #zone_hvac_component_vestibule_heating_control_required?, #zone_hvac_get_fan_object, #zone_hvac_model_standby_mode_occupancy_control
Methods included from PrototypeFan
apply_base_fan_variables, #create_fan_by_name, #get_fan_from_standards, #lookup_fan_curve_coefficients_from_json, #prototype_fan_apply_prototype_fan_efficiency
Methods included from CoilDX
#coil_dx_find_search_criteria, #coil_dx_heat_pump?, #coil_dx_heating_type, #coil_dx_subcategory
Methods included from CoolingTower
#cooling_tower_apply_minimum_power_per_flow, #cooling_tower_apply_minimum_power_per_flow_gpm_limit
Methods included from Pump
#pump_apply_prm_pressure_rise_and_motor_efficiency, #pump_apply_standard_minimum_motor_efficiency, #pump_brake_horsepower, #pump_motor_horsepower, #pump_pumppower, #pump_rated_w_per_gpm, #pump_standard_minimum_motor_efficiency_and_size
Methods included from Fan
#fan_adjust_pressure_rise_to_meet_fan_power, #fan_apply_standard_minimum_motor_efficiency, #fan_baseline_impeller_efficiency, #fan_brake_horsepower, #fan_change_impeller_efficiency, #fan_change_motor_efficiency, #fan_design_air_flow, #fan_fanpower, #fan_motor_horsepower, #fan_rated_w_per_cfm, #fan_small_fan?, #fan_standard_minimum_motor_efficiency_and_size
Constructor Details
#initialize ⇒ ASHRAE901PRM
Returns a new instance of ASHRAE901PRM.
8 9 10 11 12 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 8 def initialize super() load_standards_database @sizing_run_dir = Dir.pwd end |
Instance Method Details
#add_ems_for_multiple_chiller_pumps_w_secondary_plant(model, primary_plant) ⇒ Object
Adds EMS program for pumps serving 3 chillers on primary + secondary loop. This was due to an issue when modeling two dedicated loops. The headered pumps or dedicated constant speed pumps operate at full flow as long as there’s a load on the loop unless this EMS is in place.
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 252 def add_ems_for_multiple_chiller_pumps_w_secondary_plant(model, primary_plant) # Aggregate array of chillers on primary plant supply side chiller_list = [] primary_plant.supplyComponents.each do |sc| if sc.to_ChillerElectricEIR.is_initialized chiller_list << sc.to_ChillerElectricEIR.get end end num_of_chillers = chiller_list.length # Either 2 or 3 return if num_of_chillers <= 1 plant_name = primary_plant.name.to_s # Make a variable to track the chilled water demand chw_sensor = OpenStudio::Model::EnergyManagementSystemSensor.new(model, 'Plant Supply Side Cooling Demand Rate') chw_sensor.setKeyName(plant_name) chw_sensor.setName("#{plant_name.gsub(/[-\s]+/, '_')}_CHW_DEMAND") # Sort chillers by their reference capacity sorted_chiller_list = chiller_list.sort_by { |chiller| chiller.referenceCapacity.get.to_f} # Make pump specific parameters for EMS. Use counter sorted_chiller_list.each_with_index do |chiller, i| # Get chiller pump pump_name = "#{chiller.name} Inlet Pump" pump = model.getPumpVariableSpeedByName(pump_name).get # Set EMS names ems_pump_flow_name = "CHILLER_PUMP_#{i + 1}_FLOW" ems_pump_status_name = "CHILLER_PUMP_#{i + 1}_STATUS" ems_pump_design_flow_name = "CHILLER_PUMP_#{i + 1}_DES_FLOW" # ---- Actuators ---- # Pump Flow Actuator actuator_pump_flow = OpenStudio::Model::EnergyManagementSystemActuator.new(pump, 'Pump', 'Pump Mass Flow Rate') actuator_pump_flow.setName(ems_pump_flow_name) # Pump Status Actuator actuator_pump_status = OpenStudio::Model::EnergyManagementSystemActuator.new(pump, 'Plant Component Pump:VariableSpeed', 'On/Off Supervisory') actuator_pump_status.setName(ems_pump_status_name) # ---- Internal Variable ---- internal_variable = OpenStudio::Model::EnergyManagementSystemInternalVariable.new(model, 'Pump Maximum Mass Flow Rate') internal_variable.setInternalDataIndexKeyName(pump_name) internal_variable.setName(ems_pump_design_flow_name) end # Write EMS program if num_of_chillers > 3 OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.PlantLoop', "EMS Code for multiple chiller pump has not been written for greater than 2 chillers. This has #{num_of_chillers} chillers") elsif num_of_chillers == 3 add_ems_program_for_3_pump_chiller_plant(model, sorted_chiller_list, primary_plant) elsif num_of_chillers == 2 add_ems_program_for_2_pump_chiller_plant(model, sorted_chiller_list, primary_plant) end # Update chilled water loop operation scheme to work with updated EMS ranges stage_chilled_water_loop_operation_schemes(model, primary_plant) end |
#add_ems_program_for_2_pump_chiller_plant(model, sorted_chiller_list, primary_plant) ⇒ Object
Adds EMS program for pumps serving 2 chillers on primary + secondary loop. This was due to an issue when modeling two dedicated loops. The headered pumps or dedicated constant speed pumps operate at full flow as long as there’s a load on the loop unless this EMS is in place.
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 416 def add_ems_program_for_2_pump_chiller_plant(model, sorted_chiller_list, primary_plant) plant_name = primary_plant.name.to_s # Break out sorted chillers and get their respective capacities small_chiller = sorted_chiller_list[0] large_chiller = sorted_chiller_list[1] capacity_small_chiller = small_chiller.referenceCapacity.get capacity_large_chiller = large_chiller.referenceCapacity.get chw_demand = "#{primary_plant.name.to_s.gsub(/[-\s]+/, '_')}_CHW_DEMAND" ems_pump_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model) ems_pump_program.setName("#{plant_name.gsub(/[-\s]+/, '_')}_Pump_EMS") ems_pump_program.addLine('SET CHILLER_PUMP_1_STATUS = NULL, !- Program Line 1') ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = NULL, !- Program Line 2') ems_pump_program.addLine('SET CHILLER_PUMP_1_FLOW = NULL, !- A3') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = NULL, !- A4') ems_pump_program.addLine("IF #{chw_demand} <= #{0.8 * capacity_small_chiller}, !- A5") ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = 0, !- A6') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = 0, !- A7') ems_pump_program.addLine("ELSEIF #{chw_demand} <= #{capacity_large_chiller}, !- A8") ems_pump_program.addLine('SET CHILLER_PUMP_1_STATUS = 0, !- A9') ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = 1, !- A10') ems_pump_program.addLine('SET CHILLER_PUMP_1_FLOW = 0, !- A11') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = CHILLER_PUMP_2_DES_FLOW, !- A12') ems_pump_program.addLine("ELSEIF #{chw_demand} > #{capacity_large_chiller}, !- A13") ems_pump_program.addLine('SET CHILLER_PUMP_1_STATUS = 1, !- A14') ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = 1, !- A15') ems_pump_program.addLine('SET CHILLER_PUMP_1_FLOW = CHILLER_PUMP_1_DES_FLOW, !- A16') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = CHILLER_PUMP_2_DES_FLOW, !- A17') ems_pump_program.addLine('ENDIF !- A18') ems_pump_program_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model) ems_pump_program_manager.setName("#{plant_name.gsub(/[-\s]+/, '_')}_Pump_Program_Manager") ems_pump_program_manager.setCallingPoint('InsideHVACSystemIterationLoop') ems_pump_program_manager.addProgram(ems_pump_program) end |
#add_ems_program_for_3_pump_chiller_plant(model, sorted_chiller_list, primary_plant) ⇒ Object
Adds EMS program for pumps serving 3 chillers on primary + secondary loop. This was due to an issue when modeling two dedicated loops. The headered pumps or dedicated constant speed pumps operate at full flow as long as there’s a load on the loop unless this EMS is in place.
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 461 def add_ems_program_for_3_pump_chiller_plant(model, sorted_chiller_list, primary_plant) plant_name = primary_plant.name.to_s # Break out sorted chillers and get their respective capacities primary_chiller = sorted_chiller_list[0] medium_chiller = sorted_chiller_list[1] large_chiller = sorted_chiller_list[2] capacity_80_pct_small = 0.8 * primary_chiller.referenceCapacity.get capacity_medium_chiller = medium_chiller.referenceCapacity.get capacity_large_chiller = large_chiller.referenceCapacity.get if capacity_80_pct_small >= capacity_medium_chiller first_stage_capacity = capacity_medium_chiller else first_stage_capacity = capacity_80_pct_small end chw_demand = "#{primary_plant.name.to_s.gsub(/[-\s]+/, '_')}_CHW_DEMAND" ems_pump_program = OpenStudio::Model::EnergyManagementSystemProgram.new(model) ems_pump_program.setName("#{plant_name.gsub(/[-\s]+/, '_')}_Pump_EMS") ems_pump_program.addLine('SET CHILLER_PUMP_1_STATUS = NULL, !- Program Line 1') ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = NULL, !- Program Line 2') ems_pump_program.addLine('SET CHILLER_PUMP_3_STATUS = NULL, !- A4') ems_pump_program.addLine('SET CHILLER_PUMP_1_FLOW = NULL, !- A5') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = NULL, !- A6') ems_pump_program.addLine('SET CHILLER_PUMP_3_FLOW = NULL, !- A7') ems_pump_program.addLine("IF #{chw_demand} <= #{first_stage_capacity}, !- A8") ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = 0, !- A9') ems_pump_program.addLine('SET CHILLER_PUMP_3_STATUS = 0, !- A10') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = 0, !- A11') ems_pump_program.addLine('SET CHILLER_PUMP_3_FLOW = 0, !- A12') if capacity_80_pct_small < capacity_medium_chiller ems_pump_program.addLine("ELSEIF #{chw_demand} <= #{capacity_medium_chiller}, !- A13") ems_pump_program.addLine('SET CHILLER_PUMP_1_STATUS = 0, !- A14') ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = 1, !- A15') ems_pump_program.addLine('SET CHILLER_PUMP_3_STATUS = 0, !- A16') ems_pump_program.addLine('SET CHILLER_PUMP_1_FLOW = 0, !- A17') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = CHILLER_PUMP_2_DES_FLOW, !- A18') ems_pump_program.addLine('SET CHILLER_PUMP_3_FLOW = 0, !- A19') end ems_pump_program.addLine("ELSEIF #{chw_demand} <= #{capacity_medium_chiller + capacity_large_chiller}, !- A20") ems_pump_program.addLine('SET CHILLER_PUMP_1_STATUS = 0, !- A21') ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = 1, !- A22') ems_pump_program.addLine('SET CHILLER_PUMP_3_STATUS = 1, !- A23') ems_pump_program.addLine('SET CHILLER_PUMP_1_FLOW = 0, !- A24') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = CHILLER_PUMP_2_DES_FLOW, !- A25') ems_pump_program.addLine('SET CHILLER_PUMP_3_FLOW = CHILLER_PUMP_3_DES_FLOW, !- A26') ems_pump_program.addLine("ELSEIF #{chw_demand} > #{capacity_medium_chiller + capacity_large_chiller}, !- A27") ems_pump_program.addLine('SET CHILLER_PUMP_1_STATUS = 1, !- A28') ems_pump_program.addLine('SET CHILLER_PUMP_2_STATUS = 1, !- A29') ems_pump_program.addLine('SET CHILLER_PUMP_3_STATUS = 1, !- A30') ems_pump_program.addLine('SET CHILLER_PUMP_1_FLOW = CHILLER_PUMP_1_DES_FLOW, !- A31') ems_pump_program.addLine('SET CHILLER_PUMP_2_FLOW = CHILLER_PUMP_2_DES_FLOW, !- A32') ems_pump_program.addLine('SET CHILLER_PUMP_3_FLOW = CHILLER_PUMP_3_DES_FLOW, !- A33') ems_pump_program.addLine('ENDIF !- A34') ems_pump_program_manager = OpenStudio::Model::EnergyManagementSystemProgramCallingManager.new(model) ems_pump_program_manager.setName("#{plant_name.gsub(/[-\s]+/, '_')}_Pump_Program_Manager") ems_pump_program_manager.setCallingPoint('InsideHVACSystemIterationLoop') ems_pump_program_manager.addProgram(ems_pump_program) end |
#air_loop_hvac_allowable_system_brake_horsepower(air_loop_hvac) ⇒ Double
Determine the allowable fan system brake horsepower Per Section G3.1.2.9
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 407 def air_loop_hvac_allowable_system_brake_horsepower(air_loop_hvac) # Get design supply air flow rate (whether autosized or hard-sized) dsn_air_flow_m3_per_s = 0 dsn_air_flow_cfm = 0 if air_loop_hvac.autosizedDesignSupplyAirFlowRate.is_initialized dsn_air_flow_m3_per_s = air_loop_hvac.autosizedDesignSupplyAirFlowRate.get dsn_air_flow_cfm = OpenStudio.convert(dsn_air_flow_m3_per_s, 'm^3/s', 'cfm').get OpenStudio.logFree(OpenStudio::Debug, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "* #{dsn_air_flow_cfm.round} cfm = Autosized Design Supply Air Flow Rate.") else dsn_air_flow_m3_per_s = air_loop_hvac.designSupplyAirFlowRate.get dsn_air_flow_cfm = OpenStudio.convert(dsn_air_flow_m3_per_s, 'm^3/s', 'cfm').get OpenStudio.logFree(OpenStudio::Debug, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "* #{dsn_air_flow_cfm.round} cfm = Hard sized Design Supply Air Flow Rate.") end # Get the fan limitation pressure drop adjustment bhp fan_pwr_adjustment_bhp = air_loop_hvac_fan_power_limitation_pressure_drop_adjustment_brake_horsepower(air_loop_hvac) # Get system type associated with air loop system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get # Calculate the Allowable Fan System brake horsepower per Table G3.1.2.9 allowable_fan_bhp = 0.0 case system_type when 'PSZ_HP', 'PSZ_AC', 'SZ_CV' # 3, 4, 12, 13 allowable_fan_bhp = (dsn_air_flow_cfm * 0.00094) + fan_pwr_adjustment_bhp when 'PVAV_Reheat', 'PVAV_PFP_Boxes', 'VAV_Reheat', 'VAV_PFP_Boxes', 'SZ_VAV' # 5, 6, 7, 8, 11 allowable_fan_bhp = (dsn_air_flow_cfm * 0.0013) + fan_pwr_adjustment_bhp else OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "Air loop #{air_loop_hvac.name} is not associated with a baseline system.") end return allowable_fan_bhp end |
#air_loop_hvac_apply_energy_recovery_ventilator_efficiency(erv, erv_type: 'ERV', heat_exchanger_type: 'Rotary') ⇒ OpenStudio::Model::HeatExchangerAirToAirSensibleAndLatent
Set effectiveness value of an ERV’s heat exchanger
666 667 668 669 670 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 666 def air_loop_hvac_apply_energy_recovery_ventilator_efficiency(erv, erv_type: 'ERV', heat_exchanger_type: 'Rotary') heat_exchanger_air_to_air_sensible_and_latent_apply_effectiveness(erv) return erv end |
#air_loop_hvac_apply_minimum_vav_damper_positions(air_loop_hvac, has_ddc = true) ⇒ Boolean
Set the minimum VAV damper positions.
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 557 def air_loop_hvac_apply_minimum_vav_damper_positions(air_loop_hvac, has_ddc = true) air_loop_hvac.thermalZones.each do |zone| zone.equipment.each do |equip| if equip.to_AirTerminalSingleDuctVAVReheat.is_initialized zone_oa = OpenstudioStandards::ThermalZone.thermal_zone_get_outdoor_airflow_rate(zone) vav_terminal = equip.to_AirTerminalSingleDuctVAVReheat.get air_terminal_single_duct_vav_reheat_apply_minimum_damper_position(vav_terminal, zone_oa, has_ddc) elsif equip.to_AirTerminalSingleDuctParallelPIUReheat.is_initialized zone_oa = OpenstudioStandards::ThermalZone.thermal_zone_get_outdoor_airflow_rate(zone) fp_vav_terminal = equip.to_AirTerminalSingleDuctParallelPIUReheat.get air_terminal_single_duct_parallel_piu_reheat_apply_minimum_primary_airflow_fraction(fp_vav_terminal, zone_oa) end end end return true end |
#air_loop_hvac_apply_prm_baseline_fan_power(air_loop_hvac) ⇒ Object
Calculate and apply the performance rating method baseline fan power to this air loop based on the system type that it represents.
Fan motor efficiency will be set, and then fan pressure rise adjusted so that the fan power is the maximum allowable.
Also adjusts the fan power and flow rates of any parallel PIU terminals on the system.
return [Boolean] true if successful, false if not.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 218 def air_loop_hvac_apply_prm_baseline_fan_power(air_loop_hvac) # Get system type associated with air loop system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get # Find out if air loop represents a non mechanically cooled system is_nmc = false is_nmc = true if air_loop_hvac.additionalProperties.hasFeature('non_mechanically_cooled') # Get all air loop fans all_fans = air_loop_hvac_supply_return_exhaust_relief_fans(air_loop_hvac) allowable_fan_bhp = 0.0 allowable_power_w = 0.0 fan_efficacy_w_per_cfm = 0.0 supply_fan_power_fraction = 0.0 return_fan_power_fraction = 0.0 relief_fan_power_fraction = 0.0 if system_type == 'PSZ_AC' || system_type == 'PSZ_HP' || system_type == 'PVAV_Reheat' || system_type == 'PVAV_PFP_Boxes' || system_type == 'VAV_Reheat' || system_type == 'VAV_PFP_Boxes' || system_type == 'SZ_VAV' || system_type == 'SZ_CV' # Calculate the allowable fan motor bhp for the air loop allowable_fan_bhp = air_loop_hvac_allowable_system_brake_horsepower(air_loop_hvac) # Divide the allowable power based # individual zone air flow air_loop_total_zone_design_airflow = 0 air_loop_hvac.thermalZones.sort.each do |zone| # error if zone design air flow rate is not available if zone.model.version < OpenStudio::VersionString.new('3.6.0') OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', 'Required ThermalZone method .autosizedDesignAirFlowRate is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.') end zone_air_flow = zone.autosizedDesignAirFlowRate.to_f air_loop_total_zone_design_airflow += zone_air_flow # Fractions variables are actually power at that point supply_fan_power_fraction += zone_air_flow * zone.additionalProperties.getFeatureAsDouble('supply_fan_w').get return_fan_power_fraction += zone_air_flow * zone.additionalProperties.getFeatureAsDouble('return_fan_w').get relief_fan_power_fraction += zone_air_flow * zone.additionalProperties.getFeatureAsDouble('relief_fan_w').get end if air_loop_total_zone_design_airflow > 0 # Get average power for each category of fan supply_fan_power_fraction /= air_loop_total_zone_design_airflow return_fan_power_fraction /= air_loop_total_zone_design_airflow relief_fan_power_fraction /= air_loop_total_zone_design_airflow # Convert to power fraction total_fan_avg_fan_w = (supply_fan_power_fraction + return_fan_power_fraction + relief_fan_power_fraction) supply_fan_power_fraction /= total_fan_avg_fan_w return_fan_power_fraction /= total_fan_avg_fan_w relief_fan_power_fraction /= total_fan_avg_fan_w else OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "Total zone design airflow for #{air_loop_hvac.name} is 0.") end elsif system_type == 'PTAC' || system_type == 'PTHP' || system_type == 'Gas_Furnace' || system_type == 'Electric_Furnace' # Determine allowable fan power if is_nmc fan_efficacy_w_per_cfm = 0.054 else fan_efficacy_w_per_cfm = 0.3 end # Configuration is supply fan only supply_fan_power_fraction = 1.0 end supply_fan = air_loop_hvac_get_supply_fan(air_loop_hvac) if supply_fan.nil? OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.AirLoopHVAC', "Supply not found on #{airloop.name}.") end supply_fan_max_flow = if supply_fan.maximumFlowRate.is_initialized supply_fan.maximumFlowRate.get elsif supply_fan.autosizedMaximumFlowRate.is_initialized supply_fan.autosizedMaximumFlowRate.get end # Check that baseline system has the same # types of fans as the proposed model, if # not, create them. We assume that the # system has at least a supply fan. if return_fan_power_fraction > 0.0 && !air_loop_hvac.returnFan.is_initialized # Create return fan return_fan = supply_fan.clone(air_loop_hvac.model) if return_fan.to_FanConstantVolume.is_initialized return_fan = return_fan.to_FanConstantVolume.get elsif return_fan.to_FanVariableVolume.is_initialized return_fan = return_fan.to_FanVariableVolume.get elsif return_fan.to_FanOnOff.is_initialized return_fan = return_fan.to_FanOnOff.get elsif return_fan.to_FanSystemModel.is_initialized return_fan = return_fan.to_FanSystemModel.get end return_fan.setName("#{air_loop_hvac.name} Return Fan") return_fan.addToNode(air_loop_hvac.returnAirNode.get) return_fan.setMaximumFlowRate(supply_fan_max_flow) end if relief_fan_power_fraction > 0.0 && !air_loop_hvac.reliefFan.is_initialized # Create return fan relief_fan = supply_fan.clone(air_loop_hvac.model) if relief_fan.to_FanConstantVolume.is_initialized relief_fan = relief_fan.to_FanConstantVolume.get elsif relief_fan.to_FanVariableVolume.is_initialized relief_fan = relief_fan.to_FanVariableVolume.get elsif relief_fan.to_FanOnOff.is_initialized relief_fan = relief_fan.to_FanOnOff.get elsif relief_fan.to_FanSystemModel.is_initialized relief_fan = relief_fan.to_FanSystemModel.get end relief_fan.setName("#{air_loop_hvac.name} Relief Fan") relief_fan.addToNode(air_loop_hvac.reliefAirNode.get) relief_fan.setMaximumFlowRate(supply_fan_max_flow) end # Get all air loop fans all_fans = air_loop_hvac_supply_return_exhaust_relief_fans(air_loop_hvac) # Set the motor efficiencies # for all fans based on the calculated # allowed brake hp. Then calculate the allowable # fan power for each fan and adjust # the fan pressure rise accordingly all_fans.each do |fan| # Efficacy requirement if fan_efficacy_w_per_cfm > 0 # Convert efficacy to metric fan_efficacy_w_per_m3_per_s = OpenStudio.convert(fan_efficacy_w_per_cfm, 'm^3/s', 'cfm').get fan_change_impeller_efficiency(fan, fan_baseline_impeller_efficiency(fan)) # Get fan BHP fan_bhp = fan_brake_horsepower(fan) # Set the motor efficiency, preserving the impeller efficiency. # For zone HVAC fans, a bhp lookup of 0.5bhp is always used because # they are assumed to represent a series of small fans in reality. fan_apply_standard_minimum_motor_efficiency(fan, fan_bhp) # Calculate a new pressure rise to hit the target W/cfm fan_tot_eff = fan.fanEfficiency fan_rise_new_pa = fan_efficacy_w_per_m3_per_s * fan_tot_eff fan.setPressureRise(fan_rise_new_pa) end # BHP requirements if allowable_fan_bhp > 0 fan_apply_standard_minimum_motor_efficiency(fan, allowable_fan_bhp) allowable_power_w = allowable_fan_bhp * 746 / fan.motorEfficiency # Breakdown fan power based on fan type if supply_fan.name.to_s == fan.name.to_s allowable_power_w *= supply_fan_power_fraction elsif fan.airLoopHVAC.is_initialized if fan.airLoopHVAC.get.returnFan.is_initialized && fan.airLoopHVAC.get.returnFan.get.name.to_s == fan.name.to_s allowable_power_w *= return_fan_power_fraction end if fan.airLoopHVAC.get.reliefFan.is_initialized && fan.airLoopHVAC.get.reliefFan.get.name.to_s == fan.name.to_s allowable_power_w *= relief_fan_power_fraction end end fan_adjust_pressure_rise_to_meet_fan_power(fan, allowable_power_w) end end return true unless system_type == 'PVAV_PFP_Boxes' || system_type == 'VAV_PFP_Boxes' # Adjust fan powered terminal fans power air_loop_hvac.demandComponents.each do |dc| next if dc.to_AirTerminalSingleDuctParallelPIUReheat.empty? pfp_term = dc.to_AirTerminalSingleDuctParallelPIUReheat.get air_terminal_single_duct_parallel_piu_reheat_apply_prm_baseline_fan_power(pfp_term) end return true end |
#air_loop_hvac_economizer_limits(air_loop_hvac, climate_zone) ⇒ Array<Double>
Determine the limits for the type of economizer present on the AirLoopHVAC, if any.
580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 580 def air_loop_hvac_economizer_limits(air_loop_hvac, climate_zone) drybulb_limit_f = nil enthalpy_limit_btu_per_lb = nil dewpoint_limit_f = nil # Get the OA system and OA controller oa_sys = air_loop_hvac.airLoopHVACOutdoorAirSystem return [nil, nil, nil] unless oa_sys.is_initialized oa_sys = oa_sys.get oa_control = oa_sys.getControllerOutdoorAir economizer_type = oa_control.getEconomizerControlType case economizer_type when 'NoEconomizer' return [nil, nil, nil] when 'FixedDryBulb' climate_zone_code = climate_zone.split('-')[-1] climate_zone_code = 7 if ['7A', '7B'].include? climate_zone_code climate_zone_code = 8 if ['8A', '8B'].include? climate_zone_code search_criteria = { 'template' => template, 'climate_id' => climate_zone_code } econ_limits = model_find_object(standards_data['prm_economizers'], search_criteria) drybulb_limit_f = econ_limits['high_limit_shutoff'] when 'FixedEnthalpy' enthalpy_limit_btu_per_lb = 28 when 'FixedDewPointAndDryBulb' drybulb_limit_f = 75 dewpoint_limit_f = 55 end return [drybulb_limit_f, enthalpy_limit_btu_per_lb, dewpoint_limit_f] end |
#air_loop_hvac_enable_unoccupied_fan_shutoff(air_loop_hvac, min_occ_pct = 0.05) ⇒ Boolean
Shut off the system during unoccupied periods. During these times, systems will cycle on briefly if temperature drifts below setpoint. If the system already has a schedule other than Always-On, no change will be made. If the system has an Always-On schedule assigned, a new schedule will be created. In this case, occupied is defined as the total percent occupancy for the loop for all zones served. For stable baseline, schedule is Always-On for computer rooms and when health and safety exception is used
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 14 def air_loop_hvac_enable_unoccupied_fan_shutoff(air_loop_hvac, min_occ_pct = 0.05) if air_loop_hvac.additionalProperties.hasFeature('zone_group_type') zone_group_type = air_loop_hvac.additionalProperties.getFeatureAsString('zone_group_type').get else zone_group_type = 'None' end if zone_group_type == 'computer_zones' # Computer rooms are exempt from night cycle control return false end # Check for user data exceptions for night cycling # If any zone has the exception, then system will not cycle health_safety_exception = false air_loop_hvac.thermalZones.each do |thermal_zone| if thermal_zone.additionalProperties.hasFeature('has_health_safety_night_cycle_exception') exception = thermal_zone.additionalProperties.getFeatureAsBoolean('has_health_safety_night_cycle_exception').get return false if exception == true end end # Set the system to night cycle # The fan of a parallel PIU terminal are set to only cycle during heating operation # This is achieved using the CycleOnAnyCoolingOrHeatingZone; During cooling operation # the load is met by running the central system which stays off during heating # operation air_loop_hvac.setNightCycleControlType('CycleOnAny') if air_loop_hvac_has_parallel_piu_air_terminals?(air_loop_hvac) avail_mgrs = air_loop_hvac.availabilityManagers if !avail_mgrs.nil? avail_mgrs.each do |avail_mgr| if avail_mgr.to_AvailabilityManagerNightCycle.is_initialized avail_mgr_nc = avail_mgr.to_AvailabilityManagerNightCycle.get avail_mgr_nc.setControlType('CycleOnAnyCoolingOrHeatingZone') zones = air_loop_hvac.thermalZones avail_mgr_nc.setCoolingControlThermalZones(zones) avail_mgr_nc.setHeatingZoneFansOnlyThermalZones(zones) end end end end model = air_loop_hvac.model # Check if schedule was stored in an additionalProperties field of the air loop air_loop_name = air_loop_hvac.name if air_loop_hvac.hasAdditionalProperties && air_loop_hvac.additionalProperties.hasFeature('fan_sched_name') fan_sched_name = air_loop_hvac.additionalProperties.getFeatureAsString('fan_sched_name').get fan_sched = model.getScheduleRulesetByName(fan_sched_name).get air_loop_hvac.setAvailabilitySchedule(fan_sched) return true end # Check if already using a schedule other than always on avail_sch = air_loop_hvac.availabilitySchedule unless avail_sch == air_loop_hvac.model.alwaysOnDiscreteSchedule OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: Availability schedule is already set to #{avail_sch.name}. Will assume this includes unoccupied shut down; no changes will be made.") return true end # Get the airloop occupancy schedule loop_occ_sch = air_loop_hvac_get_occupancy_schedule(air_loop_hvac, occupied_percentage_threshold: min_occ_pct) flh = OpenstudioStandards::Schedules.schedule_get_equivalent_full_load_hours(loop_occ_sch) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}: Annual occupied hours = #{flh.round} hr/yr, assuming a #{min_occ_pct} occupancy threshold. This schedule will be used as the HVAC operation schedule.") # Set HVAC availability schedule to follow occupancy air_loop_hvac.setAvailabilitySchedule(loop_occ_sch) air_loop_hvac.supplyComponents.each do |comp| if comp.to_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.is_initialized comp.to_AirLoopHVACUnitaryHeatPumpAirToAirMultiSpeed.get.(loop_occ_sch) elsif comp.to_AirLoopHVACUnitarySystem.is_initialized comp.to_AirLoopHVACUnitarySystem.get.(loop_occ_sch) end end return true end |
#air_loop_hvac_energy_recovery_ventilator_flow_limit(air_loop_hvac, climate_zone, pct_oa) ⇒ Double
Determine the airflow limits that govern whether or not an ERV is required. Based on climate zone and % OA.
679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 679 def air_loop_hvac_energy_recovery_ventilator_flow_limit(air_loop_hvac, climate_zone, pct_oa) if pct_oa < 0.7 erv_cfm = nil else # Heating thermostat setpoint threshold temp_c = OpenStudio.convert(60, 'F', 'C').get # Check for exceptions for each zone air_loop_hvac.thermalZones.each do |thermal_zone| # Get heating thermosat setpoint and comparing to heating thermostat setpoint threshold tstat = thermal_zone.thermostat.get if tstat.to_ThermostatSetpointDualSetpoint tstat = tstat.to_ThermostatSetpointDualSetpoint.get htg_sch = tstat.getHeatingSchedule if htg_sch.is_initialized htg_sch = htg_sch.get if htg_sch.to_ScheduleRuleset.is_initialized htg_sch = htg_sch.to_ScheduleRuleset.get max_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end elsif htg_sch.to_ScheduleConstant.is_initialized htg_sch = htg_sch.to_ScheduleConstant.get max_c = OpenstudioStandards::Schedules.schedule_constant_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end elsif htg_sch.to_ScheduleCompact.is_initialized htg_sch = htg_sch.to_ScheduleCompact.get max_c = OpenstudioStandards::Schedules.schedule_compact_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end else OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Zone #{thermal_zone.name} used an unknown schedule type for the heating setpoint; assuming heated.") htd = true end end elsif tstat.to_ZoneControlThermostatStagedDualSetpoint tstat = tstat.to_ZoneControlThermostatStagedDualSetpoint.get htg_sch = tstat.heatingTemperatureSetpointSchedule if htg_sch.is_initialized htg_sch = htg_sch.get if htg_sch.to_ScheduleRuleset.is_initialized htg_sch = htg_sch.to_ScheduleRuleset.get max_c = OpenstudioStandards::Schedules.schedule_ruleset_get_min_max(htg_sch)['max'] if max_c > temp_c htd = true end end end end # Exception 1 - Systems heated to less than 60F since all baseline system provide cooling if !htd return nil end # Exception 2 - System exhausting toxic fumes if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_toxic_fumes_etc') && thermal_zone.additionalProperties.getFeatureAsBoolean('exhaust_energy_recovery_exception_for_toxic_fumes_etc') return nil end # Exception 3 - Commercial kitchen hoods if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_type1_kitchen_hoods') && thermal_zone.additionalProperties.getFeatureAsBoolean('exhaust_energy_recovery_exception_for_type1_kitchen_hoods') return nil end # Exception 6 - Distributed exhaust if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_type_distributed_exhaust') && thermal_zone.additionalProperties.getFeatureAsBoolean('exhaust_energy_recovery_exception_for_type_distributed_exhaust') return nil end # Exception 7 - Dehumidification if thermal_zone.additionalProperties.hasFeature('exhaust_energy_recovery_exception_for_dehumidifcation_with_series_cooling_recovery') && thermal_zone.additionalProperties.getFeatureAsBoolean('exhaust_energy_recovery_exception_for_dehumidifcation_with_series_cooling_recovery') return nil end end # Exception 4 - Heating systems in certain climate zones if ['ASHRAE 169-2006-0A', 'ASHRAE 169-2006-0B', 'ASHRAE 169-2006-1A', 'ASHRAE 169-2006-1B', 'ASHRAE 169-2006-2A', 'ASHRAE 169-2006-2B', 'ASHRAE 169-2006-3A', 'ASHRAE 169-2006-3B', 'ASHRAE 169-2006-3C', 'ASHRAE 169-2013-0A', 'ASHRAE 169-2013-0B', 'ASHRAE 169-2013-1A', 'ASHRAE 169-2013-1B', 'ASHRAE 169-2013-2A', 'ASHRAE 169-2013-2B', 'ASHRAE 169-2013-3A', 'ASHRAE 169-2013-3B', 'ASHRAE 169-2013-3C'].include?(climate_zone) && air_loop_hvac.additionalProperties.hasFeature('baseline_system_type') system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get if system_type == 'Gas_Furnace' || system_type == 'Electric_Furnace' return nil end end erv_cfm = 5000 end return erv_cfm end |
#air_loop_hvac_fan_power_limitation_pressure_drop_adjustment_brake_horsepower(air_loop_hvac) ⇒ Double
Determine the fan power limitation pressure drop adjustment Per Table 6.5.3.1-2 (90.1-2019)
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 621 def air_loop_hvac_fan_power_limitation_pressure_drop_adjustment_brake_horsepower(air_loop_hvac) # Calculate Fan Power Limitation Pressure Drop Adjustment fan_pwr_adjustment_bhp = 0 # Retrieve climate zone climate_zone = air_loop_hvac.model.getClimateZones.getClimateZone(0) # Check if energy recovery is required is_energy_recovery_required = air_loop_hvac_energy_recovery_ventilator_required?(air_loop_hvac, climate_zone) system_type = '' # Get baseline system type if applicable if air_loop_hvac.additionalProperties.hasFeature('baseline_system_type') system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').to_s end air_loop_hvac.thermalZones.each do |zone| # Take fan power deductions into account; # Deductions are calculated based on the # baseline model design. # The only deduction that's applicable # is the "System with central electric # resistance heat" for system 6 and 8 if system_type == 'PVAV_PFP_Boxes' || system_type == 'VAV_PFP_Boxes' if zone.additionalProperties.hasFeature('has_fan_power_deduction_system_with_central_electric_resistance_heat') current_value = zone.additionalProperties.getFeatureAsDouble('has_fan_power_deduction_system_with_central_electric_resistance_heat') zone.additionalProperties.setFeature('has_fan_power_deduction_system_with_central_electric_resistance_heat', current_value + 1.0) else zone.additionalProperties.setFeature('has_fan_power_deduction_system_with_central_electric_resistance_heat', 1.0) end end # Determine fan power adjustment fan_pwr_adjustment_bhp += thermal_zone_get_fan_power_limitations(zone, is_energy_recovery_required) end return fan_pwr_adjustment_bhp end |
#air_loop_hvac_integrated_economizer_required?(air_loop_hvac, climate_zone) ⇒ Boolean
Determine if the system economizer must be integrated or not. Always required for stable baseline if there is an economizer
123 124 125 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 123 def air_loop_hvac_integrated_economizer_required?(air_loop_hvac, climate_zone) return true end |
#air_loop_hvac_multizone_vav_system?(air_loop_hvac) ⇒ Boolean
Determine if the system is a multizone VAV system
95 96 97 98 99 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 95 def air_loop_hvac_multizone_vav_system?(air_loop_hvac) return true if air_loop_hvac.name.to_s.include?('Sys5') || air_loop_hvac.name.to_s.include?('Sys6') || air_loop_hvac.name.to_s.include?('Sys7') || air_loop_hvac.name.to_s.include?('Sys8') return false end |
#air_loop_hvac_optimum_start_required?(air_loop_hvac) ⇒ Boolean
Determines if optimum start control is required. PRM does not require optimum start - override it to false.
202 203 204 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 202 def air_loop_hvac_optimum_start_required?(air_loop_hvac) return false end |
#air_loop_hvac_prm_baseline_economizer_required?(air_loop_hvac, climate_zone) ⇒ Boolean
Determine if an economizer is required per the PRM.
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 156 def air_loop_hvac_prm_baseline_economizer_required?(air_loop_hvac, climate_zone) economizer_required = false baseline_system_type = air_loop_hvac.additionalProperties.getFeatureAsString('baseline_system_type').get climate_zone_code = climate_zone.split('-')[-1] # System type 3 through 8 and 11, 12 and 13 if ['SZ_AC', 'PSZ_AC', 'PVAV_Reheat', 'VAV_Reheat', 'SZ_VAV', 'PSZ_HP', 'SZ_CV', 'PSZ_HP', 'PVAV_PFP_Boxes', 'VAV_PFP_Boxes'].include? baseline_system_type unless ['0A', '0B', '1A', '1B', '2A', '3A', '4A'].include? climate_zone_code economizer_required = true end end # System type 3 and 4 in computer rooms are subject to exceptions if baseline_system_type == 'PSZ_AC' || baseline_system_type == 'PSZ_HP' if air_loop_hvac.additionalProperties.hasFeature('zone_group_type') && air_loop_hvac.additionalProperties.getFeatureAsString('zone_group_type').get == 'computer_zones' economizer_required = false end end # Check user_data in the zones gas_phase_exception = false open_refrigeration_exception = false air_loop_hvac.thermalZones.each do |thermal_zone| if thermal_zone.additionalProperties.hasFeature('economizer_exception_for_gas_phase_air_cleaning') gas_phase_exception = true end if thermal_zone.additionalProperties.hasFeature('economizer_exception_for_open_refrigerated_cases') open_refrigeration_exception = true end end if gas_phase_exception || open_refrigeration_exception economizer_required = false end return economizer_required end |
#air_loop_hvac_prm_economizer_type_and_limits(air_loop_hvac, climate_zone) ⇒ Array<Double>
Determine the economizer type and limits for the the PRM Defaults to 90.1-2007 logic.
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 133 def air_loop_hvac_prm_economizer_type_and_limits(air_loop_hvac, climate_zone) economizer_type = 'NoEconomizer' drybulb_limit_f = nil enthalpy_limit_btu_per_lb = nil dewpoint_limit_f = nil climate_zone_code = climate_zone.split('-')[-1] if ['0B', '1B', '2B', '3B', '3C', '4B', '4C', '5B', '5C', '6B', '7A', '7B', '8A', '8B'].include? climate_zone_code economizer_type = 'FixedDryBulb' drybulb_limit_f = 75 elsif ['5A', '6A'].include? climate_zone_code economizer_type = 'FixedDryBulb' drybulb_limit_f = 70 end return [economizer_type, drybulb_limit_f, enthalpy_limit_btu_per_lb, dewpoint_limit_f] end |
#air_loop_hvac_set_vsd_curve_type ⇒ String name of appropriate curve for this code version
Set fan curve for stable baseline to be VSD with fixed static pressure setpoint
193 194 195 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 193 def air_loop_hvac_set_vsd_curve_type return 'Multi Zone VAV with VSD and Fixed SP Setpoint' end |
#air_loop_hvac_unoccupied_threshold ⇒ Object
Default occupancy fraction threshold for determining if the spaces on the air loop are occupied
112 113 114 115 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 112 def air_loop_hvac_unoccupied_threshold # Use 10% based on PRM-RM return 0.10 end |
#air_loop_hvac_vav_damper_action(air_loop_hvac) ⇒ String
Determine whether the VAV damper control is single maximum or dual maximum control. Defaults to Single Maximum for stable baseline.
106 107 108 109 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 106 def air_loop_hvac_vav_damper_action(air_loop_hvac) damper_action = 'Single Maximum' return damper_action end |
#air_terminal_single_duct_parallel_piu_reheat_fan_on_flow_fraction ⇒ Double
Return the fan on flow fraction for a parallel PIU terminal
7 8 9 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctParallelPIUReheat.rb', line 7 def air_terminal_single_duct_parallel_piu_reheat_fan_on_flow_fraction return 0.0 # will make the secondary fans run for heating loads end |
#air_terminal_single_duct_vav_reheat_apply_minimum_damper_position(air_terminal_single_duct_vav_reheat, zone_min_oa = nil, has_ddc = true) ⇒ Boolean
remove exception where older vintages don’t have minimum positions adjusted.
Set the minimum damper position based on OA rate of the space and the template. Zones with low OA per area get lower initial guesses. Final position will be adjusted upward as necessary by Standards.AirLoopHVAC.adjust_minimum_vav_damper_positions
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirTerminalSingleDuctVAVReheat.rb', line 16 def air_terminal_single_duct_vav_reheat_apply_minimum_damper_position(air_terminal_single_duct_vav_reheat, zone_min_oa = nil, has_ddc = true) # Minimum damper position min_damper_position = air_terminal_single_duct_vav_reheat_minimum_damper_position(air_terminal_single_duct_vav_reheat, has_ddc) air_terminal_single_duct_vav_reheat.setConstantMinimumAirFlowFraction(min_damper_position) OpenStudio.logFree(OpenStudio::Debug, 'openstudio.standards.AirTerminalSingleDuctVAVReheat', "For #{air_terminal_single_duct_vav_reheat.name}: set minimum damper position to #{min_damper_position}.") # Minimum OA flow rate # If specified, set the MDP as the larger of the two unless zone_min_oa.nil? min_oa_damp_position = [zone_min_oa / air_terminal_single_duct_vav_reheat.autosizedMaximumAirFlowRate.get, min_damper_position].max air_terminal_single_duct_vav_reheat.setConstantMinimumAirFlowFraction(min_oa_damp_position) end return true end |
#baseline_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) ⇒ Boolean
Check if the air loop in baseline model needs to have DCV
507 508 509 510 511 512 513 514 515 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 507 def baseline_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) any_zone_req_dcv = false air_loop_hvac.thermalZones.each do |zone| if baseline_thermal_zone_demand_control_ventilation_required?(zone) any_zone_req_dcv = true end end return any_zone_req_dcv # baseline airloop needs dcv if any zone it serves needs dcv end |
#baseline_thermal_zone_demand_control_ventilation_required?(thermal_zone) ⇒ Boolean
Check if the thermal zone in baseline model needs to have DCV
522 523 524 525 526 527 528 529 530 531 532 533 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 522 def baseline_thermal_zone_demand_control_ventilation_required?(thermal_zone) # zone needs dcv if user model has dcv and baseline does not meet apxg exception if thermal_zone.additionalProperties.hasFeature('apxg no need to have DCV') # meaning it was served by an airloop in the user model, does not mean much here, conditional as a safeguard # in case it was not served by an airloop in the user model if !thermal_zone.additionalProperties.getFeatureAsBoolean('apxg no need to have DCV').get && # does not meet apxg exception (need to have dcv if user model has it thermal_zone.additionalProperties.getFeatureAsBoolean('zone DCV implemented in user model').get return true end end return false end |
#boiler_get_eff_fplr(boiler_hot_water) ⇒ String
Determine what part load efficiency degredation curve should be used for a boiler
23 24 25 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.BoilerHotWater.rb', line 23 def boiler_get_eff_fplr(boiler_hot_water) return 'Boiler with Minimum Turndown' end |
#boiler_hot_water_apply_efficiency_and_curves(boiler_hot_water) ⇒ Boolean
Applies the standard efficiency ratings to this object.
8 9 10 11 12 13 14 15 16 17 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.BoilerHotWater.rb', line 8 def boiler_hot_water_apply_efficiency_and_curves(boiler_hot_water) # Get the minimum efficiency standards thermal_eff = boiler_hot_water_standard_minimum_thermal_efficiency(boiler_hot_water) # Set the efficiency values unless thermal_eff.nil? boiler_hot_water.setNominalThermalEfficiency(thermal_eff) end return true end |
#calculate_electric_value_by_userdata(user_equip_data, power_equipment, power_schedule_hash, space_type, user_space_data = nil) ⇒ Boolean
A function to calculate electric value for an electric equipment. The function will check whether this electric equipment is motor, refrigeration, elevator or generic electric equipment and decide actions based on the equipment types
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 156 def calculate_electric_value_by_userdata(user_equip_data, power_equipment, power_schedule_hash, space_type, user_space_data = nil) # Check if the plug load represents a motor (check if motorhorsepower exist), if so, record the motor HP and efficiency. if !user_equip_data['motor_horsepower'].nil? # Pre-processing will ensure these three user data are added correctly (float, float, boolean) # @todo move this part to user data processing. power_equipment.additionalProperties.setFeature('motor_horsepower', user_equip_data['motor_horsepower'].to_f) power_equipment.additionalProperties.setFeature('motor_efficiency', user_equip_data['motor_efficiency'].to_f) power_equipment.additionalProperties.setFeature('motor_is_exempt', user_equip_data['motor_is_exempt']) elsif !(user_equip_data['fraction_of_controlled_receptacles'].nil? && user_equip_data['receptacle_power_savings'].nil?) # If not a motor - update. # Update the electric equipment occupancy credit (if it has) update_power_equipment_credits(power_equipment, user_equip_data, power_schedule_hash, space_type, user_space_data) else # The electric equipment is either an elevator or refrigeration OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ElectricEquipment', "#{power_equipment.name} is an elevator or refrigeration according to the user data provided. Skip receptacle power credit.") return false end return true end |
#calculate_lpd_by_space(space_type, space) ⇒ Double
calculate the lighting power density per area based on space type The function will calculate the LPD based on the space type (STRING) It considers lighting per area, lighting per length as well as occupancy factors in the database.
536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 536 def calculate_lpd_by_space(space_type, space) # get interior lighting data space_type_properties = interior_lighting_get_prm_data(space_type) OpenStudio.logFree(OpenStudio::Info, 'prm.log', "The lighting properties for space: #{space.name.get} is based on lighting_space_type: #{space_type_properties['lpd_space_type']}, primary_space_type: #{space_type_properties['primary_space_type']}, secondary_space_type: #{space_type_properties['secondary_space_type']}.") space_lighting_per_area = 0.0 # Assign data lights_have_info = false lighting_per_area = space_type_properties['w/ft^2'].to_f lighting_per_length = space_type_properties['w/ft'].to_f manon_or_partauto = space_type_properties['manon_or_partauto'].to_i lights_have_info = true unless lighting_per_area.zero? && lighting_per_length.zero? occ_control_reduction_factor = 0.0 if lights_have_info # Space height space_volume = space.volume space_area = space.floorArea space_height = OpenStudio.convert(space_volume / space_area, 'm', 'ft').get # calculate the new lpd values space_lighting_per_area = ((lighting_per_length * space_height) / space_area) + lighting_per_area # Adjust the occupancy control sensor reduction factor from dataset if manon_or_partauto == 1 occ_control_reduction_factor = space_type_properties['occup_sensor_savings'].to_f else occ_control_reduction_factor = space_type_properties['occup_sensor_auto_on_svgs'].to_f end end # add calculated occupancy control credit for later ltg schedule adjustment space.additionalProperties.setFeature('occ_control_credit', occ_control_reduction_factor) return space_lighting_per_area end |
#calculate_lpd_from_userdata(user_data, space) ⇒ Double
Calculate the lighting power density per area based on user data (space_based) The function will calculate the LPD based on the space type (STRING) It considers lighting per area, lighting per length as well as occupancy factors in the database. The sum of each space fraction in the user_data is assumed to be 1.0
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 626 def calculate_lpd_from_userdata(user_data, space) num_std_ltg_types = user_data['num_std_ltg_types'].to_i space_lighting_per_area = 0.0 occupancy_control_credit_sum = 0.0 std_ltg_index = 0 # loop index # Loop through standard lighting type in a space while std_ltg_index < num_std_ltg_types # Retrieve data from user_data type_key = format('std_ltg_type%02d', (std_ltg_index + 1)) frac_key = format('std_ltg_type_frac%02d', (std_ltg_index + 1)) sub_space_type = user_data[type_key] sub_space_type_frac = user_data[frac_key].to_f # Adjust while loop condition factors std_ltg_index += 1 # get interior lighting data sub_space_type_properties = interior_lighting_get_prm_data(sub_space_type) # Assign data lights_have_info = false lighting_per_area = sub_space_type_properties['w/ft^2'].to_f lighting_per_length = sub_space_type_properties['w/ft'].to_f lights_have_info = true unless lighting_per_area.zero? && lighting_per_length.zero? manon_or_partauto = sub_space_type_properties['manon_or_partauto'].to_i if lights_have_info # Space height space_volume = space.volume space_area = space.floorArea space_height = OpenStudio.convert(space_volume / space_area, 'm', 'ft').get # calculate and add new lpd values user_space_type_lighting_per_area = (((lighting_per_length * space_height) / space_area) + lighting_per_area) * sub_space_type_frac space_lighting_per_area += user_space_type_lighting_per_area # Adjust the occupancy control sensor reduction factor from dataset occ_control_reduction_factor = 0.0 if manon_or_partauto == 1 occ_control_reduction_factor = sub_space_type_properties['occup_sensor_savings'].to_f else occ_control_reduction_factor = sub_space_type_properties['occup_sensor_auto_on_svgs'].to_f end # Now calculate the occupancy control credit factor (weighted by frac_lpd) occupancy_control_credit_sum += occ_control_reduction_factor * user_space_type_lighting_per_area end end # add calculated occupancy control credit for later ltg schedule adjustment # If space_lighting_per_area = 0, it means there is no lights_have_info, and subsequently, the occupancy_control_credit_sum should be 0 space.additionalProperties.setFeature('occ_control_credit', space_lighting_per_area > 0 ? occupancy_control_credit_sum / space_lighting_per_area : occupancy_control_credit_sum) return space_lighting_per_area end |
#check_userdata_airloop_hvac(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::AIRLOOP_HVAC]
407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 407 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.each_key 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_userdata_airloop_hvac_doas(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::AIRLOOP_HVAC_DOAS]
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 326 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.each_key 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_userdata_building(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::BUILDING]
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 224 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_userdata_electric_equipment(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 520 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_userdata_exterior_lighting(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 463 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_userdata_gas_equipment(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 491 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_userdata_lights(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::LIGHTS]
195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 195 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_userdata_outdoor_air(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::DESIGN_SPECIFICATION_OUTDOOR_AIR]
367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 367 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_userdata_space_and_spacetype(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 606 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_userdata_thermal_zone(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::THERMAL_ZONE]
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 264 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_userdata_wateruse_connections(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
638 639 640 641 642 643 644 645 646 647 648 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 638 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_userdata_wateruse_equipment(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 656 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_userdata_wateruse_equipment_definition(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 681 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 |
#check_userdata_zone_hvac(object_name, user_data) ⇒ Boolean
Check for incorrect data in [UserDataFiles::ZONE_HVAC]
285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 285 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.each_key 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 |
#chiller_electric_eir_apply_efficiency_and_curves(chiller_electric_eir) ⇒ Boolean
Applies the standard efficiency ratings to this object.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ChillerElectricEIR.rb', line 8 def chiller_electric_eir_apply_efficiency_and_curves(chiller_electric_eir) # Get the chiller capacity capacity_w = chiller_electric_eir_find_capacity(chiller_electric_eir) # Convert capacity to tons capacity_tons = OpenStudio.convert(capacity_w, 'W', 'ton').get # Set the efficiency value cop = chiller_electric_eir_standard_minimum_full_load_efficiency(chiller_electric_eir) unless cop OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.ChillerElectricEIR', "For #{chiller_electric_eir.name}, cannot find minimum full load efficiency, will not be set.") return false end chiller_electric_eir.setReferenceCOP(cop) # Append the name with size and kw/ton kw_per_ton = cop_to_kw_per_ton(cop) chiller_electric_eir.setName("#{chiller_electric_eir.name} #{capacity_tons.round}tons #{kw_per_ton.round(1)}kW/ton") OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ChillerElectricEIR', "For #{template}: #{chiller_electric_eir.name}: Capacity = #{capacity_tons.round}tons; COP = #{cop.round(1)} (#{kw_per_ton.round(1)}kW/ton)") return true end |
#chw_sizing_control(model, chilled_water_loop, dsgn_sup_wtr_temp, dsgn_sup_wtr_temp_delt) ⇒ Boolean
Apply sizing and controls to chilled water loop
619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 619 def chw_sizing_control(model, chilled_water_loop, dsgn_sup_wtr_temp, dsgn_sup_wtr_temp_delt) design_chilled_water_temperature = 44 # Loop design chilled water temperature (F) design_chilled_water_temperature_delta = 10.1 # Loop design chilled water temperature (deltaF) chw_outdoor_temperature_high = 80 # Chilled water temperature reset at high outdoor air temperature (F) chw_outdoor_temperature_low = 60 # Chilled water temperature reset at low outdoor air temperature (F) chw_outdoor_high_setpoint = 44 # Chilled water setpoint temperature at high outdoor air temperature (F) chw_outdoor_low_setpoint = 54 # Chilled water setpoint temperature at low outdoor air temperature (F) chiller_chw_low_temp_limit = 36 # Chiller leaving chilled water lower temperature limit (F) chiller_chw_cond_temp = 95 # Chiller entering condenser fluid temperature (F) primary_pump_power = 9 # primary pump power (W/gpm) if dsgn_sup_wtr_temp.nil? dsgn_sup_wtr_temp_c = OpenStudio.convert(design_chilled_water_temperature, 'F', 'C').get else dsgn_sup_wtr_temp_c = OpenStudio.convert(dsgn_sup_wtr_temp, 'F', 'C').get end if dsgn_sup_wtr_temp_delt.nil? dsgn_sup_wtr_temp_delt_k = OpenStudio.convert(design_chilled_water_temperature_delta, 'R', 'K').get else dsgn_sup_wtr_temp_delt_k = OpenStudio.convert(dsgn_sup_wtr_temp_delt, 'R', 'K').get end chilled_water_loop.setMinimumLoopTemperature(1.0) chilled_water_loop.setMaximumLoopTemperature(40.0) sizing_plant = chilled_water_loop.sizingPlant sizing_plant.setLoopType('Cooling') sizing_plant.setDesignLoopExitTemperature(dsgn_sup_wtr_temp_c) sizing_plant.setLoopDesignTemperatureDifference(dsgn_sup_wtr_temp_delt_k) # Use OA reset setpoint manager outdoor_low_temperature_c = OpenStudio.convert(chw_outdoor_temperature_low, 'F', 'C').get.round(1) outdoor_high_temperature_c = OpenStudio.convert(chw_outdoor_temperature_high, 'F', 'C').get.round(1) setpoint_temperature_outdoor_high_c = OpenStudio.convert(chw_outdoor_high_setpoint, 'F', 'C').get.round(1) setpoint_temperature_outdoor_low_c = OpenStudio.convert(chw_outdoor_low_setpoint, 'F', 'C').get.round(1) chw_stpt_manager = OpenStudio::Model::SetpointManagerOutdoorAirReset.new(model) chw_stpt_manager.setName("#{chilled_water_loop.name} Setpoint Manager") chw_stpt_manager.setOutdoorHighTemperature(outdoor_high_temperature_c) # Degrees Celsius chw_stpt_manager.setSetpointatOutdoorHighTemperature(setpoint_temperature_outdoor_high_c) # Degrees Celsius chw_stpt_manager.setOutdoorLowTemperature(outdoor_low_temperature_c) # Degrees Celsius chw_stpt_manager.setSetpointatOutdoorLowTemperature(setpoint_temperature_outdoor_low_c) # Degrees Celsius chw_stpt_manager.addToNode(chilled_water_loop.supplyOutletNode) return true end |
#coil_cooling_dx_single_speed_apply_efficiency_and_curves(coil_cooling_dx_single_speed, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings to this object.
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXSingleSpeed.rb', line 119 def coil_cooling_dx_single_speed_apply_efficiency_and_curves(coil_cooling_dx_single_speed, sql_db_vars_map, sys_type) # Preserve the original name orig_name = coil_cooling_dx_single_speed.name.to_s # Find the minimum COP and rename with efficiency rating # Set last argument to false to avoid renaming coil, since that complicates lookup of HP heating coil efficiency later cop = coil_cooling_dx_single_speed_standard_minimum_cop(coil_cooling_dx_single_speed, sys_type, false) # Map the original name to the new name sql_db_vars_map[coil_cooling_dx_single_speed.name.to_s] = orig_name # Set the efficiency values unless cop.nil? coil_cooling_dx_single_speed.setRatedCOP(OpenStudio::OptionalDouble.new(cop)) end return sql_db_vars_map end |
#coil_cooling_dx_single_speed_find_capacity(coil_cooling_dx_single_speed, sys_type) ⇒ Double
Finds capacity in W
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXSingleSpeed.rb', line 11 def coil_cooling_dx_single_speed_find_capacity(coil_cooling_dx_single_speed, sys_type) capacity_w = nil if coil_cooling_dx_single_speed.ratedTotalCoolingCapacity.is_initialized capacity_w = coil_cooling_dx_single_speed.ratedTotalCoolingCapacity.get elsif coil_cooling_dx_single_speed.autosizedRatedTotalCoolingCapacity.is_initialized capacity_w = coil_cooling_dx_single_speed.autosizedRatedTotalCoolingCapacity.get else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXSingleSpeed', "For #{coil_cooling_dx_single_speed.name} capacity is not available, cannot apply efficiency standard.") return 0.0 end # Check for user data that indicates multiple systems per thermal zone # This could be true for a data center where this is common practice # Or it could be for a thermal zone that represents multiple real building zones mult = 1 thermal_zone = nil comp = coil_cooling_dx_single_speed.containingHVACComponent if comp.is_initialized && comp.get.to_AirLoopHVACUnitarySystem.is_initialized unitary = comp.get.to_AirLoopHVACUnitarySystem.get thermal_zone = unitary.controllingZoneorThermostatLocation.get end # meth = comp.methods comp = coil_cooling_dx_single_speed.containingZoneHVACComponent if comp.is_initialized && comp.get.thermalZone.is_initialized thermal_zone = comp.get.thermalZone.get end if !thermal_zone.nil? && standards_data.key?('userdata_thermal_zone') standards_data['userdata_thermal_zone'].each do |row| next unless row['name'].to_s.downcase.strip == thermal_zone.name.to_s.downcase.strip if row['number_of_systems'].to_s.upcase.strip != '' mult = row['number_of_systems'].to_s if mult.to_i.to_s == mult mult = mult.to_i capacity_w /= mult else OpenStudio.logFree(OpenStudio::Error, 'prm.log', 'In userdata_thermalzone, number_of_systems requires integer input.') end break end end end # If it's a PTAC or PTHP System, we need to divide the capacity by the potential zone multiplier # because the COP is dependent on capacity, and the capacity should be the capacity of a single zone, not all the zones if sys_type == 'PTAC' || sys_type == 'PTHP' mult = 1 comp = coil_cooling_dx_single_speed.containingZoneHVACComponent if comp.is_initialized && comp.get.thermalZone.is_initialized mult = comp.get.thermalZone.get.multiplier if mult > 1 total_cap = capacity_w capacity_w /= mult OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXSingleSpeed', "For #{coil_cooling_dx_single_speed.name}, total capacity of #{OpenStudio.convert(total_cap, 'W', 'kBtu/hr').get.round(2)}kBTU/hr was divided by the zone multiplier of #{mult} to give #{capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get.round(2)}kBTU/hr.") end end end return capacity_w end |
#coil_cooling_dx_single_speed_standard_minimum_cop(coil_cooling_dx_single_speed, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return efficiency
79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXSingleSpeed.rb', line 79 def coil_cooling_dx_single_speed_standard_minimum_cop(coil_cooling_dx_single_speed, sys_type, rename = false) # find properties capacity_w = coil_cooling_dx_single_speed_find_capacity(coil_cooling_dx_single_speed, sys_type) capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get search_criteria = coil_dx_find_search_criteria(coil_cooling_dx_single_speed, capacity_btu_per_hr, sys_type) # Lookup efficiencies depending on whether it is a unitary AC or a heat pump ac_props = nil ac_props = if sys_type == 'PSZ_HP' || sys_type == 'PTHP' model_find_object(standards_data['heat_pumps'], search_criteria, capacity_btu_per_hr, Date.today) else model_find_object(standards_data['unitary_acs'], search_criteria, capacity_btu_per_hr, Date.today) end # Get the minimum efficiency standards cop = nil # Check to make sure properties were found if ac_props.nil? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXSingleSpeed', "For #{coil_cooling_dx_single_speed.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.") return cop # value of nil end cop = ac_props['copnfcooling'] new_comp_name = "#{coil_cooling_dx_single_speed.name} #{capacity_btu_per_hr.round}Btu/hr #{cop}COP" # Rename if rename coil_cooling_dx_single_speed.setName(new_comp_name) end return cop end |
#coil_cooling_dx_two_speed_apply_efficiency_and_curves(coil_cooling_dx_two_speed, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings to this object.
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXTwoSpeed.rb', line 86 def coil_cooling_dx_two_speed_apply_efficiency_and_curves(coil_cooling_dx_two_speed, sql_db_vars_map, sys_type) # Preserve the original name orig_name = coil_cooling_dx_two_speed.name.to_s # Find the minimum COP and rename with efficiency rating cop = coil_cooling_dx_two_speed_standard_minimum_cop(coil_cooling_dx_two_speed, sys_type, true) # Map the original name to the new name sql_db_vars_map[coil_cooling_dx_two_speed.name.to_s] = orig_name # Set the efficiency values unless cop.nil? coil_cooling_dx_two_speed.setRatedHighSpeedCOP(cop) coil_cooling_dx_two_speed.setRatedLowSpeedCOP(cop) end return sql_db_vars_map end |
#coil_cooling_dx_two_speed_find_capacity(coil_cooling_dx_two_speed, sys_type) ⇒ Double
Finds capacity in W
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXTwoSpeed.rb', line 11 def coil_cooling_dx_two_speed_find_capacity(coil_cooling_dx_two_speed, sys_type) capacity_w = nil if coil_cooling_dx_two_speed.ratedHighSpeedTotalCoolingCapacity.is_initialized capacity_w = coil_cooling_dx_two_speed.ratedHighSpeedTotalCoolingCapacity.get elsif coil_cooling_dx_two_speed.autosizedRatedHighSpeedTotalCoolingCapacity.is_initialized capacity_w = coil_cooling_dx_two_speed.autosizedRatedHighSpeedTotalCoolingCapacity.get else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXTwoSpeed', "For #{coil_cooling_dx_two_speed.name} capacity is not available, cannot apply efficiency standard.") return 0.0 end # If it's a PTAC or PTHP System, we need to divide the capacity by the potential zone multiplier # because the COP is dependent on capacity, and the capacity should be the capacity of a single zone, not all the zones if sys_type == 'PTAC' || sys_type == 'PTHP' mult = 1 comp = coil_cooling_dx_two_speed.containingZoneHVACComponent if comp.is_initialized && comp.get.thermalZone.is_initialized mult = comp.get.thermalZone.get.multiplier if mult > 1 total_cap = capacity_w capacity_w /= mult OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilCoolingDXTwoSpeed', "For #{coil_cooling_dx_single_speed.name}, total capacity of #{OpenStudio.convert(total_cap, 'W', 'kBtu/hr').get.round(2)}kBTU/hr was divided by the zone multiplier of #{mult} to give #{capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get.round(2)}kBTU/hr.") end end end return capacity_w end |
#coil_cooling_dx_two_speed_standard_minimum_cop(coil_cooling_dx_two_speed, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return efficiency
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilCoolingDXTwoSpeed.rb', line 46 def coil_cooling_dx_two_speed_standard_minimum_cop(coil_cooling_dx_two_speed, sys_type, rename = false) # find properties capacity_w = coil_cooling_dx_two_speed_find_capacity(coil_cooling_dx_two_speed, sys_type) capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get search_criteria = coil_dx_find_search_criteria(coil_cooling_dx_two_speed, capacity_btu_per_hr, sys_type) # Lookup efficiencies depending on whether it is a unitary AC or a heat pump ac_props = nil ac_props = if sys_type == 'PSZ_HP' || sys_type == 'PTHP' model_find_object(standards_data['heat_pumps'], search_criteria, capacity_btu_per_hr, Date.today) else model_find_object(standards_data['unitary_acs'], search_criteria, capacity_btu_per_hr, Date.today) end # Get the minimum efficiency standards cop = nil # Check to make sure properties were found if ac_props.nil? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilCoolingDXTwoSpeed', "For #{coil_cooling_dx_two_speed.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.") return cop # value of nil end cop = ac_props['copnfcooling'] new_comp_name = "#{coil_cooling_dx_two_speed.name} #{capacity_btu_per_hr.round}Btu/hr #{cop}COP" # Rename if rename coil_cooling_dx_two_speed.setName(new_comp_name) end return cop end |
#coil_heating_dx_single_speed_apply_efficiency_and_curves(coil_heating_dx_single_speed, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings and typical performance curves to this object.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingDXSingleSpeed.rb', line 169 def coil_heating_dx_single_speed_apply_efficiency_and_curves(coil_heating_dx_single_speed, sql_db_vars_map, sys_type) # Preserve the original name orig_name = coil_heating_dx_single_speed.name.to_s # Find the minimum COP and rename with efficiency rating cop = coil_heating_dx_single_speed_standard_minimum_cop(coil_heating_dx_single_speed, sys_type, false) # Map the original name to the new name sql_db_vars_map[coil_heating_dx_single_speed.name.to_s] = orig_name # Set the efficiency values unless cop.nil? coil_heating_dx_single_speed.setRatedCOP(cop) end return sql_db_vars_map end |
#coil_heating_dx_single_speed_find_capacity(coil_heating_dx_single_speed, sys_type) ⇒ Double
Finds capacity in W. This is the cooling capacity of the paired DX cooling coil.
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingDXSingleSpeed.rb', line 11 def coil_heating_dx_single_speed_find_capacity(coil_heating_dx_single_speed, sys_type) capacity_w = nil # Get the paired cooling coil clg_coil = nil # Unitary and zone equipment if coil_heating_dx_single_speed.airLoopHVAC.empty? if coil_heating_dx_single_speed.containingHVACComponent.is_initialized containing_comp = coil_heating_dx_single_speed.containingHVACComponent.get if containing_comp.to_AirLoopHVACUnitaryHeatPumpAirToAir.is_initialized clg_coil = containing_comp.to_AirLoopHVACUnitaryHeatPumpAirToAir.get.coolingCoil elsif containing_comp.to_AirLoopHVACUnitarySystem.is_initialized unitary = containing_comp.to_AirLoopHVACUnitarySystem.get if unitary.coolingCoil.is_initialized clg_coil = unitary.coolingCoil.get end end elsif coil_heating_dx_single_speed.containingZoneHVACComponent.is_initialized containing_comp = coil_heating_dx_single_speed.containingZoneHVACComponent.get # PTHP if containing_comp.to_ZoneHVACPackagedTerminalHeatPump.is_initialized pthp = containing_comp.to_ZoneHVACPackagedTerminalHeatPump.get clg_coil = containing_comp.to_ZoneHVACPackagedTerminalHeatPump.get.coolingCoil end end end # On AirLoop directly if coil_heating_dx_single_speed.airLoopHVAC.is_initialized air_loop = coil_heating_dx_single_speed.airLoopHVAC.get # Check for the presence of any other type of cooling coil clg_types = ['OS:Coil:Cooling:DX:SingleSpeed', 'OS:Coil:Cooling:DX:TwoSpeed'] clg_types.each do |ct| coils = air_loop.supplyComponents(ct.to_IddObjectType) next if coils.empty? clg_coil = coils[0] break # Stop on first DX cooling coil found end end # If no paired cooling coil was found, throw an error and fall back to the heating capacity of the DX heating coil if clg_coil.nil? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXSingleSpeed', "For #{coil_heating_dx_single_speed.name}, the paired DX cooling coil could not be found to determine capacity. Efficiency will incorrectly be based on DX coil's heating capacity.") if coil_heating_dx_single_speed.ratedTotalHeatingCapacity.is_initialized capacity_w = coil_heating_dx_single_speed.ratedTotalHeatingCapacity.get elsif coil_heating_dx_single_speed.autosizedRatedTotalHeatingCapacity.is_initialized capacity_w = coil_heating_dx_single_speed.autosizedRatedTotalHeatingCapacity.get else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXSingleSpeed', "For #{coil_heating_dx_single_speed.name} capacity is not available, cannot apply efficiency standard to paired DX heating coil.") return 0.0 end return capacity_w end # If a coil was found, cast to the correct type if clg_coil.to_CoilCoolingDXSingleSpeed.is_initialized clg_coil = clg_coil.to_CoilCoolingDXSingleSpeed.get capacity_w = coil_cooling_dx_single_speed_find_capacity(clg_coil, sys_type) elsif clg_coil.to_CoilCoolingDXTwoSpeed.is_initialized clg_coil = clg_coil.to_CoilCoolingDXTwoSpeed.get capacity_w = coil_cooling_dx_two_speed_find_capacity(clg_coil, sys_type) end # Check for user data that indicates multiple systems per thermal zone # This could be true for a data center where this is common practice # Or it could be for a thermal zone that represents multiple real building zones mult = 1 thermal_zone = nil comp = coil_heating_dx_single_speed.containingHVACComponent if comp.is_initialized && comp.get.to_AirLoopHVACUnitarySystem.is_initialized unitary = comp.get.to_AirLoopHVACUnitarySystem.get thermal_zone = unitary.controllingZoneorThermostatLocation.get end # meth = comp.methods comp = coil_heating_dx_single_speed.containingZoneHVACComponent if comp.is_initialized && comp.get.thermalZone.is_initialized thermal_zone = comp.get.thermalZone.get end if !thermal_zone.nil? && standards_data.key?('userdata_thermal_zone') standards_data['userdata_thermal_zone'].each do |row| next unless row['name'].to_s.downcase.strip == thermal_zone.name.to_s.downcase.strip if row['number_of_systems'].to_s.upcase.strip != '' mult = row['number_of_systems'].to_s if mult.to_i.to_s == mult mult = mult.to_i capacity_w /= mult else OpenStudio.logFree(OpenStudio::Error, 'prm.log', 'In userdata_thermalzone, number_of_systems requires integer input.') end break end end end # If it's a PTAC or PTHP System, we need to divide the capacity by the potential zone multiplier # because the COP is dependent on capacity, and the capacity should be the capacity of a single zone, not all the zones if sys_type == 'PTHP' mult = 1 comp = coil_heating_dx_single_speed.containingZoneHVACComponent if comp.is_initialized && comp.get.thermalZone.is_initialized mult = comp.get.thermalZone.get.multiplier if mult > 1 total_cap = capacity_w capacity_w /= mult OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingDXSingleSpeed', "For #{coil_heating_dx_single_speed.name}, total capacity of #{OpenStudio.convert(total_cap, 'W', 'kBtu/hr').get.round(2)}kBTU/hr was divided by the zone multiplier of #{mult} to give #{capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get.round(2)}kBTU/hr.") end end end return capacity_w end |
#coil_heating_dx_single_speed_standard_minimum_cop(coil_heating_dx_single_speed, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return efficiency
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingDXSingleSpeed.rb', line 134 def coil_heating_dx_single_speed_standard_minimum_cop(coil_heating_dx_single_speed, sys_type, rename = false) # find ac properties capacity_w = coil_heating_dx_single_speed_find_capacity(coil_heating_dx_single_speed, sys_type) capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get search_criteria = coil_dx_find_search_criteria(coil_heating_dx_single_speed, capacity_btu_per_hr, sys_type) # find object ac_props = nil ac_props = model_find_object(standards_data['heat_pumps_heating'], search_criteria, capacity_btu_per_hr, Date.today) # Get the minimum efficiency standards cop = nil # Check to make sure properties were found if ac_props.nil? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingDXSingleSpeed', "For #{coil_heating_dx_single_speed.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.") return cop # value of nil end cop = ac_props['copnfcooling'] new_comp_name = "#{coil_heating_dx_single_speed.name} #{capacity_btu_per_hr.round}Btu/hr #{cop}COP" # Rename if rename coil_heating_dx_single_speed.setName(new_comp_name) end return cop end |
#coil_heating_gas_apply_efficiency_and_curves(coil_heating_gas, sql_db_vars_map, sys_type) ⇒ Hash
Applies the standard efficiency ratings and typical performance curves to this object.
87 88 89 90 91 92 93 94 95 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingGas.rb', line 87 def coil_heating_gas_apply_efficiency_and_curves(coil_heating_gas, sql_db_vars_map, sys_type) # Thermal efficiency thermal_eff = coil_heating_gas_standard_minimum_thermal_efficiency(coil_heating_gas, sys_type) # Set the efficiency values coil_heating_gas.setGasBurnerEfficiency(thermal_eff.to_f) return sql_db_vars_map end |
#coil_heating_gas_find_search_criteria(coil_heating_gas, sys_type) ⇒ Hash
find search criteria
9 10 11 12 13 14 15 16 17 18 19 20 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingGas.rb', line 9 def coil_heating_gas_find_search_criteria(coil_heating_gas, sys_type) # Define the criteria to find the furnace properties # in the hvac standards data set. search_criteria = {} search_criteria['fuel_type'] = 'NaturalGas' if sys_type == 'Gas_Furnace' search_criteria['equipment_type'] = 'Warm Air Unit Heaters' else search_criteria['equipment_type'] = 'Warm Air Furnace' end return search_criteria end |
#coil_heating_gas_standard_minimum_thermal_efficiency(coil_heating_gas, sys_type, rename = false) ⇒ Double
Finds lookup object in standards and return minimum thermal efficiency
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.CoilHeatingGas.rb', line 28 def coil_heating_gas_standard_minimum_thermal_efficiency(coil_heating_gas, sys_type, rename = false) # Get the coil properties search_criteria = coil_heating_gas_find_search_criteria(coil_heating_gas, sys_type) capacity_w = coil_heating_gas_find_capacity(coil_heating_gas) capacity_btu_per_hr = OpenStudio.convert(capacity_w, 'W', 'Btu/hr').get capacity_kbtu_per_hr = OpenStudio.convert(capacity_w, 'W', 'kBtu/hr').get # Get the minimum efficiency standards thermal_eff = nil # Get the coil properties coil_table = @standards_data['furnaces'] coil_props = model_find_object(coil_table, search_criteria, [capacity_btu_per_hr, 0.001].max) # Check to make sure properties were found if coil_props.nil? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingGas', "For #{coil_heating_gas.name}, cannot find efficiency info using #{search_criteria}, cannot apply efficiency standard.") successfully_set_all_properties = false return successfully_set_all_properties end # New name initial value new_comp_name = coil_heating_gas.name # If specified as thermal efficiency unless coil_props['minimum_thermal_efficiency'].nil? thermal_eff = coil_props['minimum_thermal_efficiency'] new_comp_name = "#{coil_heating_gas.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{thermal_eff} Thermal Eff" OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingGas', "For #{template}: #{coil_heating_gas.name}: Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; Thermal Efficiency = #{thermal_eff}") end # If specified as combustion efficiency unless coil_props['minimum_combustion_efficiency'].nil? min_comb_eff = coil_props['minimum_combustion_efficiency'] thermal_eff = combustion_eff_to_thermal_eff(min_comb_eff) new_comp_name = "#{coil_heating_gas.name} #{capacity_kbtu_per_hr.round}kBtu/hr #{min_comb_eff} Combustion Eff" OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.CoilHeatingGas', "For #{template}: #{coil_heating_gas.name}: Capacity = #{capacity_kbtu_per_hr.round}kBtu/hr; Combustion Efficiency = #{min_comb_eff}") end unless thermal_eff OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.CoilHeatingGas', "For #{CoilHeatingGas.name}, cannot find coil efficiency, cannot apply efficiency standard.") successfully_set_all_properties = false return successfully_set_all_properties end # Rename if rename coil_heating_gas.setName(new_comp_name) end return thermal_eff end |
#convert_userdata_csv_to_json(user_data_path, project_path) ⇒ String
Convert user data csv files to json format and save to project folder Method will create the json_folder in the project_path
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 57 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" FileUtils.rm_rf(json_path) FileUtils.mkdir_p(json_path) # 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 |
#deep_copy_schedule(new_schedule_name, schedule, adjustment_factor, model) ⇒ Object
509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 509 def deep_copy_schedule(new_schedule_name, schedule, adjustment_factor, model) OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Creating a new lighting schedule that applies occupancy sensor adjustment factor: #{adjustment_factor} based on #{schedule.name.get} schedule") sch = OpenstudioStandards::Schedules multiplier = 1.0 / (1.0 - adjustment_factor.to_f) case schedule.iddObjectType.valueName.to_s when 'OS_Schedule_Constant' schedule_constant = schedule.to_ScheduleConstant.get schedule_value = schedule_constant.value return sch.create_constant_schedule_ruleset(model, schedule_value * multiplier, name: new_schedule_name) when 'OS_Schedule_Ruleset' new_schedule = schedule.clone(model) new_schedule.setName(new_schedule_name) schedule_ruleset = new_schedule.to_ScheduleRuleset.get return sch.schedule_ruleset_simple_value_adjust(schedule_ruleset, multiplier, modification_type = 'Multiplier') when 'OS_Schedule_Compact' prm_raise(false, @sizing_run_dir, 'PRM does not support using Compact schedule for lighting schedules. Please update it to ruleset based or constant schedules.') else prm_raise(false, @sizing_run_dir, 'PRM only supports ruleset based or constant schedules for lighting schedules') end end |
#fan_variable_volume_part_load_fan_power_limitation?(fan_variable_volume) ⇒ Boolean
Determines whether there is a requirement to have a VSD or some other method to reduce fan power at low part load ratios. Required for all VAV fans for stable baseline
10 11 12 13 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanVariableVolume.rb', line 10 def fan_variable_volume_part_load_fan_power_limitation?(fan_variable_volume) part_load_control_required = true return part_load_control_required end |
#fan_variable_volume_part_load_fan_power_limitation_hp_limit(fan_variable_volume) ⇒ Double
The threhold horsepower below which part load control is not required. always required for stable baseline, so threshold is zero
20 21 22 23 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.FanVariableVolume.rb', line 20 def fan_variable_volume_part_load_fan_power_limitation_hp_limit(fan_variable_volume) hp_limit = 0 return hp_limit end |
#find_prm_heat_type(hvac_building_type, climate_zone) ⇒ String
Determine whether heating type is fuel or electric
3320 3321 3322 3323 3324 3325 3326 3327 3328 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 3320 def find_prm_heat_type(hvac_building_type, climate_zone) climate_code = climate_zone.split('-')[-1] heat_type_props = model_find_object(standards_data['prm_heat_type'], 'template' => template, 'hvac_building_type' => hvac_building_type, 'climate_zone' => climate_code) if !heat_type_props # try again with wild card for climate heat_type_props = model_find_object(standards_data['prm_heat_type'], 'template' => template, 'hvac_building_type' => hvac_building_type, 'climate_zone' => 'any') end if !heat_type_props # try again with wild card for building type heat_type_props = model_find_object(standards_data['prm_heat_type'], 'template' => template, 'hvac_building_type' => 'all others', 'climate_zone' => climate_code) end prm_raise(heat_type_props, @sizing_run_dir, "Could not find baseline heat type for: #{template}-#{hvac_building_type}-#{climate_zone}.") return heat_type_props['heat_type'] end |
#generate_baseline_log(file_directory) ⇒ Object
Generate baseline log to a specific file directory
2417 2418 2419 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2417 def generate_baseline_log(file_directory) ("#{file_directory}/prm.log", false) end |
#generate_userdata_to_csv(user_model, user_data_path, user_data_file = nil) ⇒ Object
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
24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 24 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 |
#get_airloop_hvac_design_oa_from_sql(air_loop_hvac) ⇒ Double
Get the air loop HVAC design outdoor air flow rate by reading Standard 62.1 Summary from the sizing sql
539 540 541 542 543 544 545 546 547 548 549 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 539 def get_airloop_hvac_design_oa_from_sql(air_loop_hvac) return false unless air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized cooling_oa = air_loop_hvac.model.sqlFile.get.execAndReturnFirstDouble( "SELECT Value FROM TabularDataWithStrings WHERE ReportName='Standard62.1Summary' AND ReportForString='Entire Facility' AND TableName = 'System Ventilation Requirements for Cooling' AND ColumnName LIKE 'Outdoor Air Intake Flow%Vot' AND RowName='#{air_loop_hvac.name.to_s.upcase}'" ) heating_oa = air_loop_hvac.model.sqlFile.get.execAndReturnFirstDouble( "SELECT Value FROM TabularDataWithStrings WHERE ReportName='Standard62.1Summary' AND ReportForString='Entire Facility' AND TableName = 'System Ventilation Requirements for Heating' AND ColumnName LIKE 'Outdoor Air Intake Flow%Vot' AND RowName='#{air_loop_hvac.name.to_s.upcase}'" ) return [cooling_oa.to_f, heating_oa.to_f].max end |
#get_baseline_system_groups_for_one_building_type(model, hvac_building_type, zones_in_building_type) ⇒ Array<Hash>
Assign spaces to system groups for one hvac building type One group contains all zones associated with one HVAC type Separate groups are made for laboratories, computer rooms, district cooled zones, heated-only zones, or hybrids of these Groups may include zones from multiple floors; separating by floor is handled later For stable baseline, heating type is based on climate, not proposed heating type Isolate zones that have heating-only or district (purchased) heat or chilled water
2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 2836 2837 2838 2839 2840 2841 2842 2843 2844 2845 2846 2847 2848 2849 2850 2851 2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862 2863 2864 2865 2866 2867 2868 2869 2870 2871 2872 2873 2874 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 2891 2892 2893 2894 2895 2896 2897 2898 2899 2900 2901 2902 2903 2904 2905 2906 2907 2908 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 2921 2922 2923 2924 2925 2926 2927 2928 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2582 def get_baseline_system_groups_for_one_building_type(model, hvac_building_type, zones_in_building_type) # Build zones hash of [zone, zone area, occupancy type, building type, fuel] zones = model_zones_with_occ_and_fuel_type(model, 'custom') # Ensure that there is at least one conditioned zone prm_raise(!zones.empty?, @sizing_run_dir, 'The building does not appear to have any conditioned zones. Make sure zones have thermostat with appropriate heating and cooling setpoint schedules.') # Consider special rules for computer rooms # need load of all # Get cooling load of all computer rooms to establish system types comp_room_loads = {} bldg_comp_room_load = 0 zones.each do |zn| zone_load = 0.0 has_computer_room = false # First check if any space in zone has a computer room zn['zone'].spaces.each do |space| if prm_get_optional_handler(space, @sizing_run_dir, 'spaceType', 'standardsSpaceType') == 'computer room' has_computer_room = true break end end if has_computer_room # Collect load for entire zone if zn['zone'].model.version < OpenStudio::VersionString.new('3.6.0') OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.Model', 'Required ThermalZone method .autosizedCoolingDesignLoad is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.') end zone_load_w = zn['zone'].autosizedCoolingDesignLoad.get zone_load_w *= zn['zone'].multiplier zone_load = OpenStudio.convert(zone_load_w, 'W', 'Btu/hr').get end comp_room_loads[zn['zone'].name.get] = zone_load bldg_comp_room_load += zone_load end # Lab zones are grouped separately if total lab exhaust in building > 15000 cfm # Make list of zone objects that contain laboratory spaces lab_zones = [] has_lab_spaces = {} model.getThermalZones.each do |zone| # Check if this zone includes laboratory space zone.spaces.each do |space| space_type = prm_get_optional_handler(space, @sizing_run_dir, 'spaceType', 'standardsSpaceType') zone_name = zone.name.get has_lab_spaces[zone_name] = false if space_type == 'laboratory' lab_zones << zone has_lab_spaces[zone_name] = true break end end end lab_exhaust_si = 0 lab_relief_si = 0 if !lab_zones.empty? # Build a hash of return_node:zone_name node_list = {} zone_return_flow_si = Hash.new(0) var_name = 'System Node Standard Density Volume Flow Rate' frequency = 'hourly' model.getThermalZones.each do |zone| port_list = zone.returnPortList port_list_objects = port_list.modelObjects port_list_objects.each do |node| node_name = node.nameString node_list[node_name] = zone.name.get end zone_return_flow_si[zone.name.get] = 0 end # Get return air flow for each zone (even non-lab zones are needed) # Take from hourly reports created during sizing run node_list.each do |node_name, zone_name| sql = model.sqlFile prm_raise(sql.is_initialized, @sizing_run_dir, 'Model is missing SQL file. It is likely caused by: 1. unsuccessful simulation, 2. SQL is not set as one of the output file.') sql = sql.get query = "SELECT ReportDataDictionaryIndex FROM ReportDataDictionary WHERE KeyValue = '#{node_name}' COLLATE NOCASE" val = sql.execAndReturnFirstDouble(query) prm_raise(val.is_initialized, @sizing_run_dir, "No hourly return air flow data reported for node #{node_name}") report_data_dict_index = val.get query = "SELECT MAX(Value) FROM ReportData WHERE ReportDataDictionaryIndex = '#{report_data_dict_index}'" val = sql.execAndReturnFirstDouble(query) prm_raise(val.is_initialized, @sizing_run_dir, "No hourly return air flow data reported at report index #{report_data_dict_index}") zone_return_flow_si[zone_name] += OpenStudio::OptionalDouble.new(val.get).to_f end # Calc ratio of Air Loop relief to sum of zone return for each air loop # and store in zone hash # For each air loop, get relief air flow and calculate lab exhaust from the central air handler # Take from hourly reports created during sizing run zone_relief_flow_si = {} model.getAirLoopHVACs.each do |air_loop_hvac| # First get relief air flow from sizing run sql file relief_node = prm_get_optional_handler(air_loop_hvac, @sizing_run_dir, 'reliefAirNode') node_name = relief_node.nameString relief_flow_si = 0 relief_fraction = 0 sql = model.sqlFile prm_raise(sql.is_initialized, @sizing_run_dir, 'Model is missing SQL file. It is likely caused by: 1. unsuccessful simulation, 2. SQL is not set as one of the output file.') sql = sql.get query = "SELECT ReportDataDictionaryIndex FROM ReportDataDictionary WHERE KeyValue = '#{node_name}' COLLATE NOCASE" val = sql.execAndReturnFirstDouble(query) query = "SELECT MAX(Value) FROM ReportData WHERE ReportDataDictionaryIndex = '#{val.get}'" val = sql.execAndReturnFirstDouble(query) if val.is_initialized result = OpenStudio::OptionalDouble.new(val.get) end relief_flow_si = result.to_f # Get total flow of zones on this air loop total_zone_return_si = 0 air_loop_hvac.thermalZones.each do |zone| total_zone_return_si += zone_return_flow_si[zone.name.get] end relief_fraction = relief_flow_si / total_zone_return_si unless total_zone_return_si == 0 # For each zone calc total effective exhaust air_loop_hvac.thermalZones.each do |zone| zone_relief_flow_si[zone.name.get] = relief_fraction * zone_return_flow_si[zone.name.get] end end # Now check for exhaust driven by zone exhaust fans lab_zones.each do |zone| zone.equipment.each do |zone_equipment| # Get tally of exhaust fan flow if zone_equipment.to_FanZoneExhaust.is_initialized zone_exh_fan = zone_equipment.to_FanZoneExhaust.get # Check if any spaces in this zone are laboratory lab_exhaust_si += zone_exh_fan.maximumFlowRate.get end end # Also account for outdoor air exhausted from this zone via return/relief lab_relief_si += zone_relief_flow_si[zone.name.get] end end lab_exhaust_si += lab_relief_si lab_exhaust_cfm = OpenStudio.convert(lab_exhaust_si, 'm^3/s', 'cfm').get # Isolate computer rooms onto separate groups # Computer rooms may need to be split to two groups, depending on load # Isolate heated-only and destrict cooling zones onto separate groups # District heating does not require separate group final_groups = [] # Initialize arrays of zone objects by category heated_only_zones = [] heated_cooled_zones = [] district_cooled_zones = [] comp_room_svav_zones = [] comp_room_psz_zones = [] dist_comp_room_svav_zones = [] dist_comp_room_psz_zones = [] lab_zones = [] total_area_ft2 = 0 zones.each do |zn| if OpenstudioStandards::ThermalZone.thermal_zone_heated?(zn['zone']) && !OpenstudioStandards::ThermalZone.thermal_zone_cooled?(zn['zone']) # this will occur when there is no cooling tstat, or when min cooling setpoint is above 91 F heated_only_zones << zn['zone'] elsif comp_room_loads[zn['zone'].name.get] > 0 # This is a computer room zone if bldg_comp_room_load > 3_000_000 || comp_room_loads[zn['zone'].name.get] > 600_000 # System 11 if zn['fuel'].include?('DistrictCooling') dist_comp_room_svav_zones << zn['zone'] else comp_room_svav_zones << zn['zone'] end else # PSZ if zn['fuel'].include?('DistrictCooling') dist_comp_room_psz_zones << zn['zone'] else comp_room_psz_zones << zn['zone'] end end elsif has_lab_spaces[zn['zone'].name.get] && lab_exhaust_cfm > 15_000 lab_zones << zn['zone'] elsif zn['fuel'].include?('DistrictCooling') district_cooled_zones << zn['zone'] else heated_cooled_zones << zn['zone'] end # Collect total floor area of all zones for this building area type area_m2 = zn['zone'].floorArea * zn['zone'].multiplier total_area_ft2 += OpenStudio.convert(area_m2, 'm^2', 'ft^2').get end # Build final_groups array unless heated_only_zones.empty? htd_only_group = {} htd_only_group['occ'] = 'heated-only storage' htd_only_group['fuel'] = 'any' htd_only_group['zone_group_type'] = 'heated_only_zones' area_m2 = 0 heated_only_zones.each do |zone| area_m2 += zone.floorArea * zone.multiplier end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get htd_only_group['group_area_ft2'] = area_ft2 htd_only_group['building_area_type_ft2'] = total_area_ft2 htd_only_group['zones'] = heated_only_zones final_groups << htd_only_group end unless district_cooled_zones.empty? district_cooled_group = {} district_cooled_group['occ'] = hvac_building_type district_cooled_group['fuel'] = 'districtcooling' district_cooled_group['zone_group_type'] = 'district_cooled_zones' area_m2 = 0 district_cooled_zones.each do |zone| area_m2 += zone.floorArea * zone.multiplier end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get district_cooled_group['group_area_ft2'] = area_ft2 district_cooled_group['building_area_type_ft2'] = total_area_ft2 district_cooled_group['zones'] = district_cooled_zones # store info if any zone has district, fuel, or electric heating district_cooled_group['fuel'] = get_group_heat_types(model, district_cooled_zones) final_groups << district_cooled_group end unless heated_cooled_zones.empty? heated_cooled_group = {} heated_cooled_group['occ'] = hvac_building_type heated_cooled_group['fuel'] = 'any' heated_cooled_group['zone_group_type'] = 'heated_cooled_zones' area_m2 = 0 heated_cooled_zones.each do |zone| area_m2 += zone.floorArea * zone.multiplier end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get heated_cooled_group['group_area_ft2'] = area_ft2 heated_cooled_group['building_area_type_ft2'] = total_area_ft2 heated_cooled_group['zones'] = heated_cooled_zones # store info if any zone has district, fuel, or electric heating heated_cooled_group['fuel'] = get_group_heat_types(model, heated_cooled_zones) final_groups << heated_cooled_group end unless lab_zones.empty? lab_group = {} lab_group['occ'] = hvac_building_type lab_group['fuel'] = 'any' lab_group['zone_group_type'] = 'lab_zones' area_m2 = 0 lab_zones.each do |zone| area_m2 += zone.floorArea * zone.multiplier end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get lab_group['group_area_ft2'] = area_ft2 lab_group['building_area_type_ft2'] = total_area_ft2 lab_group['zones'] = lab_zones # store info if any zone has district, fuel, or electric heating lab_group['fuel'] = get_group_heat_types(model, lab_zones) final_groups << lab_group end unless comp_room_svav_zones.empty? comp_room_svav_group = {} comp_room_svav_group['occ'] = 'computer room szvav' comp_room_svav_group['fuel'] = 'any' comp_room_svav_group['zone_group_type'] = 'computer_zones' area_m2 = 0 comp_room_svav_zones.each do |zone| area_m2 += zone.floorArea * zone.multiplier end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get comp_room_svav_group['group_area_ft2'] = area_ft2 comp_room_svav_group['building_area_type_ft2'] = total_area_ft2 comp_room_svav_group['zones'] = comp_room_svav_zones # store info if any zone has district, fuel, or electric heating comp_room_svav_group['fuel'] = get_group_heat_types(model, comp_room_svav_zones) final_groups << comp_room_svav_group end unless comp_room_psz_zones.empty? comp_room_psz_group = {} comp_room_psz_group['occ'] = 'computer room psz' comp_room_psz_group['fuel'] = 'any' comp_room_psz_group['zone_group_type'] = 'computer_zones' area_m2 = 0 comp_room_psz_zones.each do |zone| area_m2 += zone.floorArea * zone.multiplier end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get comp_room_psz_group['group_area_ft2'] = area_ft2 comp_room_psz_group['building_area_type_ft2'] = total_area_ft2 comp_room_psz_group['zones'] = comp_room_psz_zones # store info if any zone has district, fuel, or electric heating comp_room_psz_group['fuel'] = get_group_heat_types(model, comp_room_psz_zones) final_groups << comp_room_psz_group end unless dist_comp_room_svav_zones.empty? dist_comp_room_svav_group = {} dist_comp_room_svav_group['occ'] = hvac_building_type dist_comp_room_svav_group['fuel'] = 'districtcooling' dist_comp_room_svav_group['zone_group_type'] = 'computer_zones' area_m2 = 0 dist_comp_room_svav_zones.each do |zone| area_m2 += zone.floorArea * zone.multiplier end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get dist_comp_room_svav_group['group_area_ft2'] = area_ft2 dist_comp_room_svav_group['building_area_type_ft2'] = total_area_ft2 dist_comp_room_svav_group['zones'] = dist_comp_room_svav_zones # store info if any zone has district, fuel, or electric heating dist_comp_room_svav_group['fuel'] = get_group_heat_types(model, dist_comp_room_svav_zones) final_groups << dist_comp_room_svav_group end unless dist_comp_room_psz_zones.empty? dist_comp_room_psz_group = {} dist_comp_room_psz_group['occ'] = hvac_building_type dist_comp_room_psz_group['fuel'] = 'districtcooling' dist_comp_room_psz_group['zone_group_type'] = 'computer_zones' area_m2 = 0 dist_comp_room_psz_zones.each do |zone| end area_ft2 = OpenStudio.convert(area_m2, 'm^2', 'ft^2').get dist_comp_room_psz_group['group_area_ft2'] = area_ft2 dist_comp_room_psz_group['building_area_type_ft2'] = total_area_ft2 dist_comp_room_psz_group['zones'] = dist_comp_room_psz_zones # store info if any zone has district, fuel, or electric heating dist_comp_room_psz_group['fuel'] = get_group_heat_types(model, dist_comp_room_psz_zones) final_groups << dist_comp_room_psz_group end ngrps = final_groups.count # Determine the number of stories spanned by each group and report out info. final_groups.each do |group| # Determine the number of stories this group spans group['stories'] = OpenstudioStandards::Geometry.thermal_zones_get_number_of_stories_spanned(group['zones']) # Report out the final grouping OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Final system type group: occ = #{group['occ']}, fuel = #{group['fuel']}, area = #{group['group_area_ft2'].round} ft2, num stories = #{group['stories']}, zones:") group['zones'].sort.each_slice(5) do |zone_list| zone_names = [] zone_list.each do |zone| zone_names << zone.name.get.to_s end OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "--- #{zone_names.join(', ')}") end end return final_groups end |
#get_model_fenestration_area_by_orientation(user_model) ⇒ Hash
Function that extract the total fenestration area from a model by orientations. Orientation is identified as N (North), S (South), E (East), W (West)
2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2326 def get_model_fenestration_area_by_orientation(user_model) # First index is wall, second index is window fenestration_area_hash = { 'N' => 0.0, 'S' => 0.0, 'E' => 0.0, 'W' => 0.0 } user_model.getSpaces.each do |space| space_cond_type = space_conditioning_category(space) next if space_cond_type == 'Unconditioned' # Get zone multiplier multiplier = prm_get_optional_handler(space, @sizing_run_dir, 'thermalZone').multiplier space.surfaces.each do |surface| next if surface.surfaceType != 'Wall' next if surface.outsideBoundaryCondition != 'Outdoors' orientation = OpenstudioStandards::Geometry.surface_get_cardinal_direction(surface) surface.subSurfaces.each do |subsurface| subsurface_type = subsurface.subSurfaceType.to_s.downcase # Do not count doors next unless (subsurface_type.include? 'window') || (subsurface_type.include? 'glass') fenestration_area_hash[orientation] += subsurface.grossArea * subsurface.multiplier * multiplier end end end return fenestration_area_hash end |
#handle_airloop_doas_user_input_data(model) ⇒ Object
A function to load airloop DOAS data from userdata csv files
1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1903 def handle_airloop_doas_user_input_data(model) # Get user data user_airloop_doass = get_userdata(UserDataFiles::AIRLOOP_HVAC_DOAS) model.getAirLoopHVACDedicatedOutdoorAirSystems.each do |air_loop_doas| if user_airloop_doass user_data_updated = false user_airloop_doass.each do |user_airloop_doas| next unless UserData.compare(user_airloop_doas['name'], air_loop_doas.name.get) # Parse fan power credits data user_airloop_doas.each_key do |info_key| if info_key.include?('has_fan_power_credit') && UserDataBoolean.compare(user_airloop_doas[info_key], UserDataBoolean::TRUE) air_loop_doas.airLoops.each do |air_loop| air_loop.thermalZones.each do |thermal_zone| current_value = get_additional_property_as_double(thermal_zone, info_key, 0.0) thermal_zone.additionalProperties.setFeature(info_key, current_value + 1.0) end end elsif info_key.include?('fan_power_credit') # Case 2: user provided value air_loop_doas.airLoops.each do |air_loop| air_loop.thermalZones.each do |thermal_zone| current_value = get_additional_property_as_double(thermal_zone, info_key, 0.0) thermal_zone.additionalProperties.setFeature(info_key, current_value + prm_read_user_data(user_airloop_doas, info_key, '0.0').to_f) end end end end user_data_updated = true end unless user_data_updated OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Air Loop DOAS name #{air_loop_doas.name.get} was not found in user data file: #{UserDataFiles::AIRLOOP_HVAC_DOAS}; No user data applied.") end end end end |
#handle_airloop_user_input_data(model) ⇒ Object
A function to load airloop data from userdata csv files The function works with validated user data only.
1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1772 def handle_airloop_user_input_data(model) # ============================Process airloop info ============================================ user_airloops = get_userdata(UserDataFiles::AIRLOOP_HVAC) model.getAirLoopHVACs.each do |air_loop| if user_airloops user_data_updated = false user_airloops.each do |user_airloop| next unless UserData.compare(air_loop.name.get, user_airloop['name']) air_loop.thermalZones.each do |thermal_zone| # gas phase air cleaning is system base - add proposed hvac system name to zones economizer_exception_for_gas_phase_air_cleaning = user_airloop['economizer_exception_for_gas_phase_air_cleaning'] economizer_exception_for_open_refrigerated_cases = user_airloop['economizer_exception_for_open_refrigerated_cases'] user_airloop.each_key do |info_key| if info_key.include?('has_fan_power_credit') && UserData.compare(user_airloop[info_key], UserDataBoolean::TRUE) current_value = get_additional_property_as_double(thermal_zone, info_key, 0.0) thermal_zone.additionalProperties.setFeature(info_key, current_value + 1.0) elsif info_key.include?('fan_power_credit') # Case 2: user provided value fan_power_credit = prm_read_user_data(user_airloop, info_key, '0.0').to_f current_value = get_additional_property_as_double(thermal_zone, info_key, 0.0) thermal_zone.additionalProperties.setFeature(info_key, current_value + fan_power_credit) end # Exhaust air energy recovery if info_key.include?('exhaust_energy_recovery_exception') if UserData.compare(user_airloop[info_key], UserDataBoolean::TRUE) thermal_zone.additionalProperties.setFeature(info_key, true) else thermal_zone.additionalProperties.setFeature(info_key, false) end end end if UserData.compare(economizer_exception_for_gas_phase_air_cleaning, UserDataBoolean::TRUE) thermal_zone.additionalProperties.setFeature('economizer_exception_for_gas_phase_air_cleaning', true) else thermal_zone.additionalProperties.setFeature('economizer_exception_for_gas_phase_air_cleaning', false) end if UserData.compare(economizer_exception_for_open_refrigerated_cases, UserDataBoolean::TRUE) thermal_zone.additionalProperties.setFeature('economizer_exception_for_open_refrigerated_cases', true) else thermal_zone.additionalProperties.setFeature('economizer_exception_for_open_refrigerated_cases', false) end end user_data_updated = true end unless user_data_updated OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Air loop name #{air_loop.name.get} was not found in user data file: #{UserDataFiles::AIRLOOP_HVAC}; No user data applied.") end end end end |
#handle_electric_equipment_user_input_data(model) ⇒ Object
A function to load electric equipment csv files The file name is userdata_electric_equipment.csv
1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1669 def handle_electric_equipment_user_input_data(model) user_data_plug_load = get_userdata(UserDataFiles::ELECTRIC_EQUIPMENT) model.getElectricEquipments.each do |elevator_equipment| if user_data_plug_load user_data_updated = false 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) number_of_levels = prm_read_user_data(user_plug_load, 'elevator_number_of_stories', '0').to_i elevator_equipment.additionalProperties.setFeature('elevator_number_of_stories', number_of_levels) elevator_weight_of_car = prm_read_user_data(user_plug_load, 'elevator_weight_of_car', '0.0').to_f elevator_equipment.additionalProperties.setFeature('elevator_weight_of_car', elevator_weight_of_car) elevator_weight_of_car = prm_read_user_data(user_plug_load, 'elevator_counter_weight_of_car', '0.0').to_f elevator_equipment.additionalProperties.setFeature('elevator_counter_weight_of_car', elevator_weight_of_car) elevator_rated_load = prm_read_user_data(user_plug_load, 'elevator_rated_load', '0.0').to_f elevator_equipment.additionalProperties.setFeature('elevator_rated_load', elevator_rated_load) elevator_speed_of_car = prm_read_user_data(user_plug_load, 'elevator_speed_of_car', '0.0').to_f elevator_equipment.additionalProperties.setFeature('elevator_speed_of_car', elevator_speed_of_car) elevator_ventilation_cfm = prm_read_user_data(user_plug_load, 'elevator_ventilation_cfm', '0.0').to_f elevator_equipment.additionalProperties.setFeature('elevator_ventilation_cfm', elevator_ventilation_cfm) elevator_area_ft2 = prm_read_user_data(user_plug_load, 'elevator_area_ft2', '0.0').to_f elevator_equipment.additionalProperties.setFeature('elevator_area_ft2', elevator_area_ft2) end user_data_updated = true end unless user_data_updated OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Electric equipment name #{elevator_equipment.name.get} was not found in user data file: #{UserDataFiles::ELECTRIC_EQUIPMENT}; No user data applied.") end end end end |
#handle_exterior_lighting_user_input_data(model) ⇒ Object
A function to load exterior lighting data from user data csv files The file name is userdata_exterior_lighting.csv
1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 1661 1662 1663 1664 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1600 def handle_exterior_lighting_user_input_data(model) user_data_exterior_lighting_objects = get_userdata(UserDataFiles::EXTERIOR_LIGHTS) search_criteria = { 'template' => template } ext_ltg_baseline_values = standards_lookup_table_first(table_name: 'prm_exterior_lighting', search_criteria: search_criteria) model.getExteriorLightss.each do |exterior_light| if user_data_exterior_lighting_objects user_data_updated = false # get exterior lighting object. user_data_exterior_lighting_objects.each do |user_exterior_lighting| next unless UserData.compare(exterior_light.name.get, user_exterior_lighting['name']) num_cats = prm_read_user_data(user_exterior_lighting, 'num_ext_lights_subcats', '0').to_i # Make sure none of the categories are nontradeable and not a mix of tradeable and nontradeable num_trade = 0 num_notrade = 0 ext_ltg_cats = {} (1..num_cats).each do |icat| cat_key = format('end_use_subcategory_%02d', icat) # validated subcat = user_exterior_lighting[cat_key] # handle the userdata missing value issue. if UserDataNonTradableLightsCategory.matched_any?(subcat) num_notrade += 1 else num_trade += 1 meas_val_key = format('end_use_measurement_value_%02d', icat) meas_val = prm_read_user_data(user_exterior_lighting, meas_val_key, '0.0').to_f unless meas_val == 0 OpenStudio.logFree(OpenStudio::Info, 'prm.log', "End use subcategory #{subcat} has either missing measurement value or invalid measurement value, set to 0.0") end ext_ltg_cats[subcat] = meas_val end end # skip this if all lights are non-tradeable if num_trade == 0 exterior_light.additionalProperties.setFeature('design_level', 0.0) next end if (num_trade > 0) && (num_notrade > 0) OpenStudio.logFree(OpenStudio::Warn, 'prm.log', "ExteriorLights object named #{user_exterior_lighting['name']} from user data file has a mix of tradeable and non-tradeable lighting types. All will be treated as non-tradeable.") next end ext_ltg_pwr = 0 ext_ltg_cats.each do |subcat, meas_val| # Get baseline power for this type of exterior lighting baseline_value = ext_ltg_baseline_values[subcat].to_f ext_ltg_pwr += baseline_value * meas_val end exterior_light.additionalProperties.setFeature('design_level', ext_ltg_pwr) user_data_updated = true end unless user_data_updated OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Exterior Lights name #{exterior_light.name.get} was not found in user data file: #{UserDataFiles::EXTERIOR_LIGHTS}; No user data applied.") end end end end |
#handle_gas_equipment_user_input_data(model) ⇒ Object
A function to load gas equipment csv files The file name is userdata_gas_equipment.csv
1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1714 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 |
#handle_lights_user_input_data(model) ⇒ Object
A function to load lights from user data csv files The file name is userdata_lights.csv
1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1441 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', 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', false) 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 |
#handle_multi_building_area_types(model, climate_zone, default_hvac_building_type, default_wwr_building_type, default_swh_building_type, bldg_type_hvac_zone_hash) ⇒ Boolean
Analyze HVAC, window-to-wall ratio and SWH building (area) types from user data inputs in the @standard_data library This function returns True, but the values are stored in the multi-building_data argument. The hierarchy for process the building types
-
Highest: PRM rules - if rules applied against user inputs, the function will use the calculated value to reset the building type
-
Second: User defined building type in the csv file.
-
Third: User defined userdata_building.csv file. If an object (e.g. space, thermalzone) are not defined in their correspondent userdata csv file, use the building csv file
-
Fourth: Dropdown list in the measure GUI. If none presented, use the data from the dropdown list.
NOTE! This function will add building types to OpenStudio objects as an additional features for hierarchy 1-3 The object additional feature is empty when the function determined it uses fourth hierarchy.
1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1989 def handle_multi_building_area_types(model, climate_zone, default_hvac_building_type, default_wwr_building_type, default_swh_building_type, bldg_type_hvac_zone_hash) # Construct the user_building hashmap user_buildings = get_userdata(UserDataFiles::BUILDING) # Build up a hvac_building_type : thermal zone hash map # =============================HVAC user data process=========================================== user_thermal_zones = get_userdata(UserDataFiles::THERMAL_ZONE) # First construct hvac building type -> thermal Zone hash and hvac building type -> floor area bldg_type_zone_hash = {} bldg_type_zone_area_hash = {} model.getThermalZones.each do |thermal_zone| # get climate zone to check the conditioning category thermal_zone_condition_category = thermal_zone_conditioning_category(thermal_zone, climate_zone) if thermal_zone_condition_category == 'Semiheated' || thermal_zone_condition_category == 'Unconditioned' next end # Check for Second hierarchy hvac_building_type = nil if user_thermal_zones user_thermal_zone_index = user_thermal_zones.index { |user_thermal_zone| UserData.compare(user_thermal_zone['name'], thermal_zone.name.get) } # make sure the thermal zone has assigned a building_type_for_hvac unless user_thermal_zone_index.nil? || user_thermal_zones[user_thermal_zone_index]['building_type_for_hvac'].nil? # Only thermal zone in the user data and have building_type_for_hvac data will be assigned. hvac_building_type = user_thermal_zones[user_thermal_zone_index]['building_type_for_hvac'] end end # Second hierarchy does not apply, check Third hierarchy if hvac_building_type.nil? && user_buildings building_name = prm_get_optional_handler(thermal_zone.model, @sizing_run_dir, 'building', 'name') user_building_index = user_buildings.index { |user_building| UserData.compare(user_building['name'], building_name) } unless user_building_index.nil? || user_buildings[user_building_index]['building_type_for_hvac'].nil? # Only thermal zone in the buildings user data and have building_type_for_hvac data will be assigned. hvac_building_type = user_buildings[user_building_index]['building_type_for_hvac'] end end # Third hierarchy does not apply, apply Fourth hierarchy if hvac_building_type.nil? hvac_building_type = default_hvac_building_type end # Add data to the hash map unless bldg_type_zone_hash.key?(hvac_building_type) bldg_type_zone_hash[hvac_building_type] = [] end unless bldg_type_zone_area_hash.key?(hvac_building_type) bldg_type_zone_area_hash[hvac_building_type] = 0.0 end # calculate floor area for the thermal zone part_of_floor_area = false thermal_zone.spaces.sort.each do |space| next unless space.partofTotalFloorArea # a space in thermal zone is part of floor area. part_of_floor_area = true bldg_type_zone_area_hash[hvac_building_type] += space.floorArea * space.multiplier end if part_of_floor_area # Only add the thermal_zone if it is part of the floor area bldg_type_zone_hash[hvac_building_type].append(thermal_zone) end end if bldg_type_zone_hash.empty? # Build hash with all zones assigned to default hvac building type zone_array = [] model.getThermalZones.each do |thermal_zone| zone_array.append(thermal_zone) thermal_zone.additionalProperties.setFeature('building_type_for_hvac', default_hvac_building_type) end bldg_type_hvac_zone_hash[default_hvac_building_type] = zone_array else # Calculate the total floor area. # If the max tie, this algorithm will pick the first encountered hvac building type as the maximum. total_floor_area = 0.0 hvac_bldg_type_with_max_floor = nil hvac_bldg_type_max_floor_area = 0.0 bldg_type_zone_area_hash.each do |key, value| if value > hvac_bldg_type_max_floor_area hvac_bldg_type_with_max_floor = key hvac_bldg_type_max_floor_area = value end total_floor_area += value end # Reset the thermal zones by going through the hierarchy 1 logics bldg_type_hvac_zone_hash.clear # Add the thermal zones for the maximum floor (primary system) bldg_type_hvac_zone_hash[hvac_bldg_type_with_max_floor] = bldg_type_zone_hash[hvac_bldg_type_with_max_floor] bldg_type_zone_hash.each do |bldg_type, bldg_type_zone| # loop the rest bldg_types unless bldg_type.eql? hvac_bldg_type_with_max_floor if OpenStudio.convert(total_floor_area, 'm^2', 'ft^2').get <= 40000 # Building is smaller than 40k sqft, it could only have one hvac_building_type, reset all the thermal zones. bldg_type_hvac_zone_hash[hvac_bldg_type_with_max_floor].push(*bldg_type_zone) OpenStudio.logFree(OpenStudio::Info, 'prm.log', "The building floor area is less than 40,000 square foot. Thermal zones under hvac building type #{bldg_type} is reset to #{hvac_bldg_type_with_max_floor}") else if OpenStudio.convert(bldg_type_zone_area_hash[bldg_type], 'm^2', 'ft^2').get < 20000 # in this case, all thermal zones shall be categorized as the primary hvac_building_type bldg_type_hvac_zone_hash[hvac_bldg_type_with_max_floor].push(*bldg_type_zone) OpenStudio.logFree(OpenStudio::Info, 'prm.log', "The floor area in hvac building type #{bldg_type} is less than 20,000 square foot. Thermal zones under this hvac building type is reset to #{hvac_bldg_type_with_max_floor}") else bldg_type_hvac_zone_hash[bldg_type] = bldg_type_zone end end end end # Write in hvac building type thermal zones by thermal zone bldg_type_hvac_zone_hash.each do |h1_bldg_type, bldg_type_zone_array| bldg_type_zone_array.each do |thermal_zone| thermal_zone.additionalProperties.setFeature('building_type_for_hvac', h1_bldg_type) end end end # =============================SPACE user data process=========================================== user_spaces = get_userdata(UserDataFiles::SPACE) model.getSpaces.each do |space| type_for_wwr = nil # Check for 2nd level hierarchy if user_spaces user_spaces.each do |user_space| unless user_space['building_type_for_wwr'].nil? if UserData.compare(space.name.get, user_space['name']) type_for_wwr = user_space['building_type_for_wwr'] end end end end if type_for_wwr.nil? # 2nd Hierarchy does not apply, check for 3rd level hierarchy building_name = prm_get_optional_handler(space.model, @sizing_run_dir, 'building', 'name') if user_buildings user_buildings.each do |user_building| unless user_building['building_type_for_wwr'].nil? if UserData.compare(user_building['name'], building_name) type_for_wwr = user_building['building_type_for_wwr'] end end end end end if type_for_wwr.nil? # 3rd level hierarchy does not apply, Apply 4th level hierarchy type_for_wwr = default_wwr_building_type end # add wwr type to space: space.additionalProperties.setFeature('building_type_for_wwr', type_for_wwr) end # =============================SWH user data process=========================================== user_wateruse_equipments = get_userdata(UserDataFiles::WATERUSE_EQUIPMENT) model.getWaterUseEquipments.each do |wateruse_equipment| type_for_swh = nil # Check for 2nd hierarchy if user_wateruse_equipments user_wateruse_equipments.each do |user_wateruse_equipment| unless user_wateruse_equipment['building_type_for_swh'].nil? if UserData.compare(wateruse_equipment.name.get, user_wateruse_equipment['name']) type_for_swh = user_wateruse_equipment['building_type_for_swh'] end end end end if type_for_swh.nil? # 2nd hierarchy does not apply, check for 3rd hierarchy # get space building type building_name = prm_get_optional_handler(wateruse_equipment.model, @sizing_run_dir, 'building', 'name') if user_buildings user_buildings.each do |user_building| unless user_building['building_type_for_swh'].nil? if UserData.compare(user_building['name'], building_name) type_for_swh = user_building['building_type_for_swh'] end end end end end if type_for_swh.nil? # 3rd hierarchy does not apply, apply 4th hierarchy type_for_swh = default_swh_building_type end # add swh type to wateruse equipment: wateruse_equipment.additionalProperties.setFeature('building_type_for_swh', type_for_swh) end return true end |
#handle_outdoor_air_user_input_data(model) ⇒ Object
A function to load outdoor air data from user data csv files The file name is userdata_design_specification_outdoor_air.csv
1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1741 def handle_outdoor_air_user_input_data(model) user_data_oas = get_userdata(UserDataFiles::DESIGN_SPECIFICATION_OUTDOOR_AIR) model.getDesignSpecificationOutdoorAirs.each do |zone_oa| if user_data_oas user_data_updated = false user_data_oas.each do |user_oa| next unless UserData.compare(zone_oa.name.get, user_oa['name']) user_oa.each_key do |info_key| if info_key == 'name' zone_oa.additionalProperties.setFeature('has_user_data', true) else # this will capture the invalid string to 0.0, need to add note OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Add user provided outdoor air field: #{info_key}, value: #{user_oa[info_key].to_f} to DesignSpecification:OutdoorAir #{zone_oa.name.get} ") zone_oa.additionalProperties.setFeature(info_key, user_oa[info_key].to_f) end end user_data_updated = true end unless user_data_updated OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Zone outdoor air name #{zone_oa.name.get} was not found in user data file: #{UserDataFiles::DESIGN_SPECIFICATION_OUTDOOR_AIR}; No user data applied.") end end end end |
#handle_thermal_zone_user_input_data(model) ⇒ Object
A function to load thermal zone data from userdata csv files
1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1942 def handle_thermal_zone_user_input_data(model) userdata_thermal_zones = get_userdata(UserDataFiles::THERMAL_ZONE) model.getThermalZones.each do |thermal_zone| nightcycle_exception = false if userdata_thermal_zones user_data_updated = false userdata_thermal_zones.each do |row| next unless UserData.compare(row['name'], thermal_zone.name.get) if UserData.compare(row['has_health_safety_night_cycle_exception'], UserDataBoolean::TRUE) nightcycle_exception = true break end user_data_updated = true end unless user_data_updated OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Thermal Zone name #{thermal_zone.name.get} was not found in user data file: #{UserDataFiles::THERMAL_ZONE}.") end end if nightcycle_exception thermal_zone.additionalProperties.setFeature('has_health_safety_night_cycle_exception', true) end # mark unmarked zones unless thermal_zone.additionalProperties.hasFeature('has_health_safety_night_cycle_exception') thermal_zone.additionalProperties.setFeature('has_health_safety_night_cycle_exception', false) end end end |
#handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_building_type, default_wwr_building_type, default_swh_building_type, bldg_type_hvac_zone_hash) ⇒ Boolean
A template method that handles the loading of user input data from multiple sources include data source from:
-
user data csv files
-
data from measure and OpenStudio interface
1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1406 def handle_user_input_data(model, climate_zone, sizing_run_dir, default_hvac_building_type, default_wwr_building_type, default_swh_building_type, bldg_type_hvac_zone_hash) # Set sizing run directory @sizing_run_dir = sizing_run_dir # load the multiple building area types from user data handle_multi_building_area_types(model, climate_zone, default_hvac_building_type, default_wwr_building_type, default_swh_building_type, bldg_type_hvac_zone_hash) # load user data from proposed model 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 handle_airloop_doas_user_input_data(model) # load zone HVAC user data from proposed model handle_zone_hvac_user_input_data(model) # load thermal zone user data from proposed model 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 handle_wateruse_equipment_user_input_data(model, default_swh_building_type) # load water use equipment definition user data handle_wateruse_equipment_definition_user_input_data(model) return true end |
#handle_wateruse_connections_user_input_data(model) ⇒ Object
A function to load water use connections schedules from user data csv files The file name is userdata_wateruse_connections.csv
1563 1564 1565 1566 1567 1568 1569 1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1563 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 |
#handle_wateruse_equipment_definition_user_input_data(model) ⇒ Object
A function to load water use equipment definition from user data csv files The file name is userdata_wateruse_equipment_definition.csv
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1480 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 |
#handle_wateruse_equipment_user_input_data(model, default_swh_building_type) ⇒ Object
A function to load water use equipment from user data csv files The file name is userdata_wateruse_equipment.csv
1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 1545 1546 1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1523 def handle_wateruse_equipment_user_input_data(model, default_swh_building_type) user_data_wateruse_equipment = get_userdata(UserDataFiles::WATERUSE_EQUIPMENT) user_data_building = get_userdata(UserDataFiles::BUILDING) # get swh building type from user data building default_type = default_swh_building_type if user_data_building building_name = prm_get_optional_handler(model, @sizing_run_dir, 'building', 'name') user_building_index = user_data_building.index { |user_building| UserData.compare(user_building['name'], building_name) } unless user_building_index.nil? || prm_read_user_data(user_data_building[user_building_index], 'building_type_swh', nil) # Only thermal zone in the buildings user data and have building_type_for_hvac data will be assigned. default_type = prm_read_user_data(user_data_building[user_building_index], 'building_type_swh', default_type) OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Building type swh found in #{UserDataFiles::WATERUSE_EQUIPMENT} for building #{building_name}, set default building type swh to #{default_type}") end end model.getWaterUseEquipments.each do |wateruse_equipment| user_data_updated = false if user_data_wateruse_equipment user_data_wateruse_equipment.each do |user_wateruse| if 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 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}; default building swh type #{default_type} applied.") end end # No user data updated, use default type unless user_data_updated wateruse_equipment.additionalProperties.setFeature('building_type_swh', default_type) end end end |
#handle_zone_hvac_user_input_data(model) ⇒ Object
Retrieve zone HVAC user specified compliance inputs from CSV file
1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1829 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, '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 thermal_zone = zone_hvac_eqp.thermalZone.get zone_hvac_eqp_info.each_key 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 |
#has_multi_lpd_values_space_type(space_type) ⇒ Boolean
Function checks whether there are multi lpd values in the space type multi-lpd value means there are multiple spaces and the lighting_per_length > 0
585 586 587 588 589 590 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 585 def has_multi_lpd_values_space_type(space_type) space_type_properties = interior_lighting_get_prm_data(space_type) lighting_per_length = space_type_properties['w/ft'].to_f return space_type.spaces.size > 1 && lighting_per_length > 0 end |
#has_multi_lpd_values_user_data(user_data, space_type) ⇒ Boolean
Function checks whether there are multi lpd values in the space type from user’s data The sum of each space fraction in the user_data is assumed to be 1.0 multi-lpd value means lighting per area > 0 and lighting_per_length > 0
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 598 def has_multi_lpd_values_user_data(user_data, space_type) num_std_ltg_types = user_data['num_std_ltg_types'].to_i std_ltg_index = 0 # loop index # Loop through standard lighting type in a space sum_lighting_per_area = 0 sum_lighting_per_length = 0 while std_ltg_index < num_std_ltg_types # Retrieve data from user_data type_key = format('std_ltg_type%02d', (std_ltg_index + 1)) sub_space_type = user_data[type_key] # Adjust while loop condition factors std_ltg_index += 1 # get interior lighting data sub_space_type_properties = interior_lighting_get_prm_data(sub_space_type) # Assign data lighting_per_length = sub_space_type_properties['w/ft'].to_f sum_lighting_per_length += lighting_per_length end return space_type.spaces.size > 1 && sum_lighting_per_length > 0 end |
#has_user_lpd_values(user_space_data) ⇒ Boolean
Function checks whether the user data contains lighting data
572 573 574 575 576 577 578 579 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 572 def has_user_lpd_values(user_space_data) user_space_data.each do |user_data| if user_data.key?('num_std_ltg_types') && user_data['num_std_ltg_types'].to_f > 0 return true end end return false end |
#heat_exchanger_air_to_air_sensible_and_latent_design_conditions(heat_exchanger_air_to_air_sensible_and_latent, climate_zone) ⇒ String
Determine the heat exchanger design conditions for a specific climate zones
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.HeatExchangerSensLat.rb', line 29 def heat_exchanger_air_to_air_sensible_and_latent_design_conditions(heat_exchanger_air_to_air_sensible_and_latent, climate_zone) case climate_zone when 'ASHRAE 169-2006-6B', 'ASHRAE 169-2013-6B', 'ASHRAE 169-2006-7A', 'ASHRAE 169-2013-7A', 'ASHRAE 169-2006-7B', 'ASHRAE 169-2013-7B', 'ASHRAE 169-2006-8A', 'ASHRAE 169-2013-8A', 'ASHRAE 169-2006-8B', 'ASHRAE 169-2013-8B' design_conditions = 'heating' else design_conditions = 'cooling' end return design_conditions end |
#heat_exchanger_air_to_air_sensible_and_latent_enthalpy_recovery_ratio(heat_exchanger_air_to_air_sensible_and_latent) ⇒ Double
Determine the required enthalpy recovery ratio (ERR)
52 53 54 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.HeatExchangerSensLat.rb', line 52 def heat_exchanger_air_to_air_sensible_and_latent_enthalpy_recovery_ratio(heat_exchanger_air_to_air_sensible_and_latent) return 0.5 end |
#heat_exchanger_air_to_air_sensible_and_latent_minimum_effectiveness(heat_exchanger_air_to_air_sensible_and_latent) ⇒ Array
Defines the minimum sensible and latent effectiveness of the heat exchanger. Assumed to apply to sensible and latent effectiveness at all flow rates.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.HeatExchangerSensLat.rb', line 9 def heat_exchanger_air_to_air_sensible_and_latent_minimum_effectiveness(heat_exchanger_air_to_air_sensible_and_latent) # Get required ERR enthalpy_recovery_ratio = heat_exchanger_air_to_air_sensible_and_latent_enthalpy_recovery_ratio(heat_exchanger_air_to_air_sensible_and_latent) # Get design condition for climate zones climate_zone = OpenstudioStandards::Weather.model_get_climate_zone(heat_exchanger_air_to_air_sensible_and_latent.model) design_conditions = heat_exchanger_air_to_air_sensible_and_latent_design_conditions(heat_exchanger_air_to_air_sensible_and_latent, climate_zone) # Adjust, and convert ERR to Effectiveness for input to the model enthalpy_recovery_ratio = enthalpy_recovery_ratio_design_to_typical_adjustment(enthalpy_recovery_ratio, climate_zone) full_htg_sens_eff, full_htg_lat_eff, part_htg_sens_eff, part_htg_lat_eff, full_cool_sens_eff, full_cool_lat_eff, part_cool_sens_eff, part_cool_lat_eff = heat_exchanger_air_to_air_sensible_and_latent_enthalpy_recovery_ratio_to_effectiveness(enthalpy_recovery_ratio, design_conditions) return full_htg_sens_eff, full_htg_lat_eff, part_htg_sens_eff, part_htg_lat_eff, full_cool_sens_eff, full_cool_lat_eff, part_cool_sens_eff, part_cool_lat_eff end |
#load_standards_database(data_directories = []) ⇒ Object
14 15 16 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 14 def load_standards_database(data_directories = []) super([__dir__] + data_directories) end |
#load_userdata_to_standards_database(json_path) ⇒ Object
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
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 119 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 |
#model_add_apxg_dcv_properties(model) ⇒ Object
Check if zones in the baseline model (to be created) should have DCV based on 90.1 2019 G3.1.2.5. Zone additional property ‘apxg no need to have DCV’ added
1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1344 def model_add_apxg_dcv_properties(model) model.getAirLoopHVACs.each do |air_loop_hvac| if air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized oa_flow_m3_per_s = get_airloop_hvac_design_oa_from_sql(air_loop_hvac) else OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}, DCV not applicable because it has no OA intake.") return false end oa_flow_cfm = OpenStudio.convert(oa_flow_m3_per_s, 'm^3/s', 'cfm').get if oa_flow_cfm <= 3000 air_loop_hvac.thermalZones.each do |thermal_zone| thermal_zone.additionalProperties.setFeature('apxg no need to have DCV', true) end else # oa_flow_cfg > 3000, check zone people density air_loop_hvac.thermalZones.each do |thermal_zone| area_served_m2 = 0 num_people = 0 thermal_zone.spaces.each do |space| area_served_m2 += space.floorArea num_people += space.numberOfPeople end area_served_ft2 = OpenStudio.convert(area_served_m2, 'm^2', 'ft^2').get occ_per_1000_ft2 = num_people / area_served_ft2 * 1000 if occ_per_1000_ft2 <= 100 thermal_zone.additionalProperties.setFeature('apxg no need to have DCV', true) else thermal_zone.additionalProperties.setFeature('apxg no need to have DCV', false) end end end end # if a zone does not have this additional property, it means it was not served by airloop. end |
#model_add_dcv_requirement_properties(model) ⇒ Object
add zone additional property “airloop dcv required by 901”
-
“true” if the airloop supporting this zone is required by 90.1 (non-exception requirement + user provided exception flag) to have DCV regarding user model
-
“false” otherwise
add zone additional property “zone dcv required by 901”
-
“true” if the zone is required by 90.1(non-exception requirement + user provided exception flag) to have DCV regarding user model
-
‘flase’ otherwise
1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1286 def model_add_dcv_requirement_properties(model) model.getAirLoopHVACs.each do |air_loop_hvac| if user_model_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) air_loop_hvac.thermalZones.each do |thermal_zone| thermal_zone.additionalProperties.setFeature('airloop dcv required by 901', true) # the zone level dcv requirement can only be true if it is in an airloop that is required to have DCV if user_model_zone_demand_control_ventilation_required?(thermal_zone) thermal_zone.additionalProperties.setFeature('zone dcv required by 901', true) end end end end # mark unmarked zones model.getThermalZones.each do |zone| unless zone.additionalProperties.hasFeature('airloop dcv required by 901') zone.additionalProperties.setFeature('airloop dcv required by 901', false) end unless zone.additionalProperties.hasFeature('zone dcv required by 901') zone.additionalProperties.setFeature('zone dcv required by 901', false) end end end |
#model_add_dcv_user_exception_properties(model) ⇒ Object
read user data and add to zone additional properties “airloop user specified DCV exception” “one user specified DCV exception”
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1226 def model_add_dcv_user_exception_properties(model) model.getAirLoopHVACs.each do |air_loop_hvac| dcv_airloop_user_exception = false if standards_data.key?('userdata_airloop_hvac') standards_data['userdata_airloop_hvac'].each do |row| next unless row['name'].to_s.downcase.strip == air_loop_hvac.name.to_s.downcase.strip if row['dcv_exception_airloop'].to_s.upcase.strip == 'TRUE' dcv_airloop_user_exception = true break end end end air_loop_hvac.thermalZones.each do |thermal_zone| if dcv_airloop_user_exception thermal_zone.additionalProperties.setFeature('airloop user specified DCV exception', true) end end end # zone level exception tagging is put outside of airloop because it directly reads from user data and # a zone not under an airloop in user model may be in an airloop in baseline model.getThermalZones.each do |thermal_zone| dcv_zone_user_exception = false if standards_data.key?('userdata_thermal_zone') standards_data['userdata_thermal_zone'].each do |row| next unless row['name'].to_s.downcase.strip == thermal_zone.name.to_s.downcase.strip if row['dcv_exception_thermal_zone'].to_s.upcase.strip == 'TRUE' dcv_zone_user_exception = true break end end end if dcv_zone_user_exception thermal_zone.additionalProperties.setFeature('zone user specified DCV exception', true) end end # mark unmarked zones model.getThermalZones.each do |zone| unless zone.additionalProperties.hasFeature('airloop user specified DCV exception') zone.additionalProperties.setFeature('airloop user specified DCV exception', false) end unless zone.additionalProperties.hasFeature('zone user specified DCV exception') zone.additionalProperties.setFeature('zone user specified DCV exception', false) end end end |
#model_add_prm_elevators(model) ⇒ Object
Function to add baseline elevators based on user data
727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 727 def model_add_prm_elevators(model) # Load elevator data from userdata csv files equipment_array = model.getElectricEquipments + model.getExteriorFuelEquipments equipment_array.each do |equipment| elevator_number_of_lifts = get_additional_property_as_integer(equipment, 'elevator_number_of_lifts', 0) next unless elevator_number_of_lifts > 0.0 elevator_name = equipment.name.get elevator_number_of_stories = get_additional_property_as_integer(equipment, 'elevator_number_of_stories', 0) elevator_weight_of_car = get_additional_property_as_double(equipment, 'elevator_weight_of_car', 0.0) elevator_rated_load = get_additional_property_as_double(equipment, 'elevator_rated_load', 0.0) elevator_speed_of_car = get_additional_property_as_double(equipment, 'elevator_speed_of_car', 0.0) elevator_counter_weight_of_car = get_additional_property_as_double(equipment, 'elevator_counter_weight_of_car', 0.0) if elevator_number_of_stories < 5 # From Table G3.9.2 performance rating method baseline elevator motor elevator_mech_eff = 0.58 elevator_counter_weight_of_car = 0.0 search_criteria = { 'template' => template, 'type' => 'Hydraulic' } else # From Table G3.9.2 performance rating method baseline elevator motor elevator_mech_eff = 0.64 # Determine the elevator counterweight if elevator_counter_weight_of_car < 0.001 # When the proposed design counterweight is not specified # it is determined as per Table G3.9.2 elevator_counter_weight_of_car = elevator_weight_of_car + (0.4 * elevator_rated_load) end search_criteria = { 'template' => template, 'type' => 'Any' } end elevator_motor_bhp = (elevator_weight_of_car + elevator_rated_load - elevator_counter_weight_of_car) * elevator_speed_of_car / (33000 * elevator_mech_eff) # Lookup the minimum motor efficiency elevator_motor_eff = standards_data['motors'] motor_properties = model_find_object(elevator_motor_eff, search_criteria, nil, nil, nil, nil, elevator_motor_bhp) if motor_properties.nil? OpenStudio.logFree(OpenStudio::Error, 'prm.log', "For #{elevator_name}, could not find motor properties using search criteria: #{search_criteria}, motor_bhp = #{elevator_motor_bhp} hp.") return false end nominal_hp = motor_properties['maximum_capacity'].to_f.round(1) # Round to nearest whole HP for niceness if nominal_hp >= 2 nominal_hp = nominal_hp.round end # Get the efficiency based on the nominal horsepower # Add 0.01 hp to avoid search errors. motor_properties = model_find_object(elevator_motor_eff, search_criteria, nil, nil, nil, nil, nominal_hp + 0.01) if motor_properties.nil? OpenStudio.logFree(OpenStudio::Error, 'prm.log', "For #{elevator_name}, could not find nominal motor properties using search criteria: #{search_criteria}, motor_hp = #{nominal_hp} hp.") return false end motor_eff = motor_properties['nominal_full_load_efficiency'].to_f elevator_power = elevator_number_of_lifts * elevator_motor_bhp * 746 / motor_eff if equipment.is_a?(OpenStudio::Model::ElectricEquipment) equipment.electricEquipmentDefinition.setDesignLevel(elevator_power) else equipment.exteriorFuelEquipmentDefinition.setDesignLevel(elevator_power) end elevator_space = prm_get_optional_handler(equipment, @sizing_run_dir, 'space') # Add ventilation and lighting process loads if modeled in the proposed model misc_elevator_process_loads = 0.0 misc_elevator_process_loads += get_additional_property_as_double(equipment, 'elevator_ventilation_cfm', 0.0) * 0.33 misc_elevator_process_loads += get_additional_property_as_double(equipment, 'elevator_area_ft2', 0.0) * 3.14 if misc_elevator_process_loads > 0 misc_elevator_process_loads_def = OpenStudio::Model::ElectricEquipmentDefinition.new(model) misc_elevator_process_loads_def.setName("#{elevator_name} - Misc Process Loads - Def") misc_elevator_process_loads_def.setDesignLevel(misc_elevator_process_loads) misc_elevator_process_loads = OpenStudio::Model::ElectricEquipment.new(misc_elevator_process_loads_def) misc_elevator_process_loads.setName("#{elevator_name} - Misc Process Loads") misc_elevator_process_loads.setEndUseSubcategory('Elevators') misc_elevator_process_loads.setSchedule(model.alwaysOnDiscreteSchedule) misc_elevator_process_loads.setSpace(elevator_space) end end end |
#model_adjusted_building_envelope_infiltration(building_envelope_area_m2, specific_space_infiltration_rate_75_pa = nil) ⇒ Double
This method calculates the building envelope infiltration, this approach uses the 90.1 PRM rules
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 323 def model_adjusted_building_envelope_infiltration(building_envelope_area_m2, specific_space_infiltration_rate_75_pa = nil) # Determine the total building baseline infiltration rate in cfm per ft2 of the building envelope at 75 Pa if specific_space_infiltration_rate_75_pa.nil? basic_infil_rate_cfm_per_ft2 = space_infiltration_rate_75_pa else basic_infil_rate_cfm_per_ft2 = specific_space_infiltration_rate_75_pa end # Conversion factor conv_fact = OpenStudio.convert(1.0, 'm^3/s', 'ft^3/min').get / OpenStudio.convert(1.0, 'm^2', 'ft^2').get # Adjust the infiltration rate to the average pressure for the prototype buildings. # adj_infil_rate_cfm_per_ft2 = 0.112 * basic_infil_rate_cfm_per_ft2 adj_infil_rate_cfm_per_ft2 = OpenstudioStandards::Infiltration.adjust_infiltration_to_prototype_building_conditions(basic_infil_rate_cfm_per_ft2) adj_infil_rate_m3_per_s_per_m2 = adj_infil_rate_cfm_per_ft2 / conv_fact # Calculate the total infiltration tot_infil_m3_per_s = adj_infil_rate_m3_per_s_per_m2 * building_envelope_area_m2 return tot_infil_m3_per_s end |
#model_apply_baseline_exterior_lighting(model) ⇒ Object
Apply baseline values to exterior lights objects Characterization of objects must be done via user data
711 712 713 714 715 716 717 718 719 720 721 722 723 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 711 def model_apply_baseline_exterior_lighting(model) model.getExteriorLightss.each do |ext_lights_obj| # Update existing exterior lights object: control, schedule, power ext_lights_obj.setControlOption('AstronomicalClock') ext_lights_obj.setSchedule(model.alwaysOnDiscreteSchedule) ext_lights_obj.setMultiplier(1) ext_lights_def = ext_lights_obj.exteriorLightsDefinition ext_ltg_pwr = get_additional_property_as_double(ext_lights_obj, 'design_level', 0.0) if ext_ltg_pwr > 0.0 ext_lights_def.setDesignLevel(ext_ltg_pwr) end end end |
#model_apply_baseline_swh_loops(model, building_type) ⇒ Boolean
Modify the existing service water heating loops to match the baseline required heating type.
2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2185 def model_apply_baseline_swh_loops(model, building_type) model.getPlantLoops.each do |plant_loop| # Skip non service water heating loops next unless plant_loop_swh_loop?(plant_loop) # Rename the loop to avoid accidentally hooking up the HVAC systems to this loop later. plant_loop.setName('Service Water Heating Loop') htg_fuels, combination_system, storage_capacity, total_heating_capacity = plant_loop_swh_system_type(plant_loop) electric = true if htg_fuels.include?('NaturalGas') || htg_fuels.include?('PropaneGas') || htg_fuels.include?('FuelOilNo1') || htg_fuels.include?('FuelOilNo2') || htg_fuels.include?('Coal') || htg_fuels.include?('Diesel') || htg_fuels.include?('Gasoline') electric = false end # Per Table G3.1 11.e, if the baseline system was a combination of heating and service water heating, # delete all heating equipment and recreate a WaterHeater:Mixed. if combination_system a = plant_loop.supplyComponents b = plant_loop.demandComponents plantloop_components = a += b plantloop_components.each do |component| # Get the object type obj_type = component.iddObjectType.valueName.to_s next if ['OS_Node', 'OS_Pump_ConstantSpeed', 'OS_Pump_VariableSpeed', 'OS_Connector_Splitter', 'OS_Connector_Mixer', 'OS_Pipe_Adiabatic'].include?(obj_type) component.remove end water_heater = OpenStudio::Model::WaterHeaterMixed.new(model) water_heater.setName('Baseline Water Heater') water_heater.setHeaterMaximumCapacity(total_heating_capacity) water_heater.setTankVolume(storage_capacity) plant_loop.addSupplyBranchForComponent(water_heater) if electric # G3.1.11.b: If electric, WaterHeater:Mixed with electric resistance water_heater.setHeaterFuelType('Electricity') water_heater.setHeaterThermalEfficiency(1.0) else # @todo for now, just get the first fuel that isn't Electricity # A better way would be to count the capacities associated # with each fuel type and use the preponderant one fuels = htg_fuels - ['Electricity'] fossil_fuel_type = fuels[0] water_heater.setHeaterFuelType(fossil_fuel_type) water_heater.setHeaterThermalEfficiency(0.8) end # If it's not a combination heating and service water heating system # just change the fuel type of all water heaters on the system # to electric resistance if it's electric else # Per Table G3.1 11.i, piping losses was deleted plant_loop_adiabatic_pipes_only(plant_loop) if electric plant_loop.supplyComponents.each do |component| next unless component.to_WaterHeaterMixed.is_initialized water_heater = component.to_WaterHeaterMixed.get # G3.1.11.b: If electric, WaterHeater:Mixed with electric resistance water_heater.setHeaterFuelType('Electricity') water_heater.setHeaterThermalEfficiency(1.0) end end end end # Set the water heater fuel types if it's 90.1-2013 model.getWaterHeaterMixeds.sort.each do |water_heater| water_heater_mixed_apply_prm_baseline_fuel_type(water_heater, building_type) end return true end |
#model_apply_constructions(model, climate_zone, wwr_building_type, wwr_info) ⇒ Boolean
Apply the standard construction to each surface in the model, based on the construction type currently assigned.
2362 2363 2364 2365 2366 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2362 def model_apply_constructions(model, climate_zone, wwr_building_type, wwr_info) model_apply_standard_constructions(model, climate_zone, wwr_building_type: wwr_building_type, wwr_info: wwr_info) return true end |
#model_apply_hvac_efficiency_standard(model, climate_zone, apply_controls: true, sql_db_vars_map: nil) ⇒ Boolean
Applies the HVAC parts of the template to all objects in the model using the the template specified in the model.
970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 970 def model_apply_hvac_efficiency_standard(model, climate_zone, apply_controls: true, sql_db_vars_map: nil) sql_db_vars_map = {} if sql_db_vars_map.nil? OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Started applying HVAC efficiency standards for #{template} template.") # Air Loop Controls if apply_controls.nil? || apply_controls == true model.getAirLoopHVACs.sort.each { |obj| air_loop_hvac_apply_standard_controls(obj, climate_zone) } end # Plant Loop Controls if apply_controls.nil? || apply_controls == true model.getPlantLoops.sort.each { |obj| plant_loop_apply_standard_controls(obj, climate_zone) } end # Zone HVAC Controls model.getZoneHVACComponents.sort.each { |obj| zone_hvac_component_apply_standard_controls(obj) } # @todo The fan and pump efficiency will be done by another task. # Fans # model.getFanVariableVolumes.sort.each { |obj| fan_apply_standard_minimum_motor_efficiency(obj, fan_brake_horsepower(obj)) } # model.getFanConstantVolumes.sort.each { |obj| fan_apply_standard_minimum_motor_efficiency(obj, fan_brake_horsepower(obj)) } # model.getFanOnOffs.sort.each { |obj| fan_apply_standard_minimum_motor_efficiency(obj, fan_brake_horsepower(obj)) } # model.getFanZoneExhausts.sort.each { |obj| fan_apply_standard_minimum_motor_efficiency(obj, fan_brake_horsepower(obj)) } # Pumps # model.getPumpConstantSpeeds.sort.each { |obj| pump_apply_standard_minimum_motor_efficiency(obj) } # model.getPumpVariableSpeeds.sort.each { |obj| pump_apply_standard_minimum_motor_efficiency(obj) } # model.getHeaderedPumpsConstantSpeeds.sort.each { |obj| pump_apply_standard_minimum_motor_efficiency(obj) } # model.getHeaderedPumpsVariableSpeeds.sort.each { |obj| pump_apply_standard_minimum_motor_efficiency(obj) } # Zone level systems/components model.getThermalZones.each do |zone| if zone.additionalProperties.getFeatureAsString('baseline_system_type').is_initialized sys_type = zone.additionalProperties.getFeatureAsString('baseline_system_type').get end zone.equipment.each do |zone_equipment| if zone_equipment.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized ptac = zone_equipment.to_ZoneHVACPackagedTerminalAirConditioner.get cooling_coil = ptac.coolingCoil sql_db_vars_map = set_coil_cooling_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) elsif zone_equipment.to_ZoneHVACPackagedTerminalHeatPump.is_initialized pthp = zone_equipment.to_ZoneHVACPackagedTerminalHeatPump.get cooling_coil = pthp.coolingCoil heating_coil = pthp.heatingCoil sql_db_vars_map = set_coil_cooling_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) sql_db_vars_map = set_coil_heating_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) elsif zone_equipment.to_ZoneHVACUnitHeater.is_initialized unit_heater = zone_equipment.to_ZoneHVACUnitHeater.get heating_coil = unit_heater.heatingCoil sql_db_vars_map = set_coil_heating_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) end end end # Airloop HVAC level components model.getAirLoopHVACs.sort.each do |air_loop| sys_type = air_loop.additionalProperties.getFeatureAsString('baseline_system_type').get air_loop.components.each do |icomponent| if icomponent.to_AirLoopHVACUnitarySystem.is_initialized unitary_system = icomponent.to_AirLoopHVACUnitarySystem.get if unitary_system.coolingCoil.is_initialized cooling_coil = unitary_system.coolingCoil.get sql_db_vars_map = set_coil_cooling_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) end if unitary_system.heatingCoil.is_initialized heating_coil = unitary_system.heatingCoil.get sql_db_vars_map = set_coil_heating_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) end elsif icomponent.to_CoilCoolingDXSingleSpeed.is_initialized cooling_coil = icomponent.to_CoilCoolingDXSingleSpeed.get sql_db_vars_map = coil_cooling_dx_single_speed_apply_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) elsif icomponent.to_CoilCoolingDXTwoSpeed.is_initialized cooling_coil = icomponent.to_CoilCoolingDXTwoSpeed.get sql_db_vars_map = coil_cooling_dx_two_speed_apply_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) elsif icomponent.to_CoilHeatingDXSingleSpeed.is_initialized heating_coil = icomponent.to_CoilHeatingDXSingleSpeed.get sql_db_vars_map = coil_heating_dx_single_speed_apply_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) elsif icomponent.to_CoilHeatingGas.is_initialized heating_coil = icomponent.to_CoilHeatingGas.get sql_db_vars_map = coil_heating_gas_apply_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) end end end # Chillers model.getChillerElectricEIRs.sort.each { |obj| chiller_electric_eir_apply_efficiency_and_curves(obj) } # Boilers model.getBoilerHotWaters.sort.each { |obj| boiler_hot_water_apply_efficiency_and_curves(obj) } # Cooling Towers model.getCoolingTowerVariableSpeeds.sort.each { |obj| cooling_tower_variable_speed_apply_efficiency_and_curves(obj) } OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Finished applying HVAC efficiency standards for #{template} template.") return true end |
#model_apply_multizone_vav_outdoor_air_sizing(model) ⇒ Boolean
This is not applicable to the stable baseline; hence no action in this method
Applies the multi-zone VAV outdoor air sizing requirements to all applicable air loops in the model.
898 899 900 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 898 def model_apply_multizone_vav_outdoor_air_sizing(model) return true end |
#model_apply_prm_baseline_sizing_schedule(model) ⇒ Object
Add design day schedule objects for space loads, for PRM 2019 baseline models
812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 812 def model_apply_prm_baseline_sizing_schedule(model) space_loads = model.getSpaceLoads loads = [] space_loads.sort.each do |space_load| casted_load = model_cast_model_object(space_load) loads << casted_load unless casted_load.nil? end load_schedule_name_hash = { 'People' => 'numberofPeopleSchedule', 'Lights' => 'schedule', 'ElectricEquipment' => 'schedule', 'GasEquipment' => 'schedule', 'SpaceInfiltration_DesignFlowRate' => 'schedule' } loads.each do |load| load_type = load.iddObjectType.valueName.sub('OS_', '').strip load_schedule_name = load_schedule_name_hash[load_type] next if load_schedule_name.nil? # check if the load is in a dwelling space if load.spaceType.is_initialized space_type = load.spaceType.get elsif load.space.is_initialized && load.space.get.spaceType.is_initialized space_type = load.space.get.spaceType.get else space_type = nil puts "No hosting space/spacetype found for load: #{load.name}" end if !space_type.nil? && /apartment/i =~ space_type.standardsSpaceType.to_s load_in_dwelling = true else load_in_dwelling = false end load_schedule = load.public_send(load_schedule_name).get schedule_type = load_schedule.iddObjectType.valueName.sub('OS_', '').strip.sub('_', '') load_schedule = load_schedule.public_send("to_#{schedule_type}").get case schedule_type when 'ScheduleRuleset' load_schmax = OpenstudioStandards::Schedules.schedule_get_min_max(load_schedule)['max'] load_schmin = OpenstudioStandards::Schedules.schedule_get_min_max(load_schedule)['min'] load_schmode = get_weekday_values_from_8760(model, Array(OpenstudioStandards::Schedules.schedule_get_hourly_values(load_schedule)), value_includes_holiday = true).mode[0] # AppendixG-2019 G3.1.2.2.1 if load_type == 'SpaceInfiltration_DesignFlowRate' summer_value = load_schmax winter_value = load_schmax else summer_value = load_schmax winter_value = load_schmin end # AppendixG-2019 Exception to G3.1.2.2.1 if load_in_dwelling summer_value = load_schmode end # set cooling design day schedule summer_dd_schedule = OpenStudio::Model::ScheduleDay.new(model) summer_dd_schedule.setName("#{load.name} Summer Design Day") summer_dd_schedule.addValue(OpenStudio::Time.new(1.0), summer_value) load_schedule.setSummerDesignDaySchedule(summer_dd_schedule) # set heating design day schedule winter_dd_schedule = OpenStudio::Model::ScheduleDay.new(model) winter_dd_schedule.setName("#{load.name} Winter Design Day") winter_dd_schedule.addValue(OpenStudio::Time.new(1.0), winter_value) load_schedule.setWinterDesignDaySchedule(winter_dd_schedule) when 'ScheduleConstant' OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "Space load #{load.name} has schedule type of ScheduleConstant. Nothing to be done for ScheduleConstant") next end end end |
#model_apply_prm_baseline_skylight_to_roof_ratio(model) ⇒ Boolean
Reduces the SRR to the values specified by the PRM. SRR reduction will be done by shrinking vertices toward the centroid.
629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 629 def model_apply_prm_baseline_skylight_to_roof_ratio(model) # Loop through all spaces in the model, and # per the 90.1-2019 PRM User Manual, only # account for exterior roofs for enclosed # spaces. Include space multipliers. roof_m2 = 0.001 # Avoids divide by zero errors later sky_m2 = 0 total_roof_m2 = 0.001 total_subsurface_m2 = 0 model.getSpaces.sort.each do |space| next if space_conditioning_category(space) == 'Unconditioned' # Loop through all surfaces in this space roof_area_m2 = 0 sky_area_m2 = 0 space.surfaces.sort.each do |surface| # Skip non-outdoor surfaces next unless surface.outsideBoundaryCondition == 'Outdoors' # Skip non-walls next unless surface.surfaceType == 'RoofCeiling' # This roof's gross area (including skylight area) roof_area_m2 += surface.grossArea * space.multiplier # Subsurfaces in this surface surface.subSurfaces.sort.each do |ss| next unless ss.subSurfaceType == 'Skylight' sky_area_m2 += ss.netArea * space.multiplier end end total_roof_m2 += roof_area_m2 total_subsurface_m2 += sky_area_m2 end # Calculate the SRR of each category srr = ((total_subsurface_m2 / total_roof_m2) * 100.0).round(1) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "The skylight to roof ratios (SRRs) is: : #{srr.round}%.") # SRR limit srr_lim = model_prm_skylight_to_roof_ratio_limit(model) # Check against SRR limit red = srr > srr_lim # Stop here unless skylights need reducing return true unless red OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Reducing the size of all skylights equally down to the limit of #{srr_lim.round}%.") # Determine the factors by which to reduce the skylight area mult = srr_lim / srr # Reduce the skylight area if any of the categories necessary model.getSpaces.sort.each do |space| next if space_conditioning_category(space) == 'Unconditioned' # Loop through all surfaces in this space space.surfaces.sort.each do |surface| # Skip non-outdoor surfaces next unless surface.outsideBoundaryCondition == 'Outdoors' # Skip non-walls next unless surface.surfaceType == 'RoofCeiling' # Subsurfaces in this surface surface.subSurfaces.sort.each do |ss| next unless ss.subSurfaceType == 'Skylight' # Reduce the size of the skylight red = 1.0 - mult OpenstudioStandards::Geometry.sub_surface_reduce_area_by_percent_by_shrinking_toward_centroid(ss, red) end end end return true end |
#model_apply_prm_construction_types(model) ⇒ Boolean
Go through the default construction sets and hard-assigned constructions. Clone the existing constructions and set their intended surface type and standards construction type per the PRM. For some standards, this will involve making modifications. For others, it will not. 90.1-2019
504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 504 def model_apply_prm_construction_types(model) types_to_modify = [] # Possible boundary conditions are # Adiabatic # Surface # Outdoors # Ground # Foundation # GroundFCfactorMethod # OtherSideCoefficients # OtherSideConditionsModel # GroundSlabPreprocessorAverage # GroundSlabPreprocessorCore # GroundSlabPreprocessorPerimeter # GroundBasementPreprocessorAverageWall # GroundBasementPreprocessorAverageFloor # GroundBasementPreprocessorUpperWall # GroundBasementPreprocessorLowerWall # Possible surface types are # AtticFloor # AtticWall # AtticRoof # DemisingFloor # DemisingWall # DemisingRoof # ExteriorFloor # ExteriorWall # ExteriorRoof # ExteriorWindow # ExteriorDoor # GlassDoor # GroundContactFloor # GroundContactWall # GroundContactRoof # InteriorFloor # InteriorWall # InteriorCeiling # InteriorPartition # InteriorWindow # InteriorDoor # OverheadDoor # Skylight # TubularDaylightDome # TubularDaylightDiffuser # Possible standards construction types # Mass # SteelFramed # WoodFramed # IEAD # View # Daylight # Swinging # NonSwinging # Heated # Unheated # RollUp # Sliding # Metal # Nonmetal framing (all) # Metal framing (curtainwall/storefront) # Metal framing (entrance door) # Metal framing (all other) # Metal Building # Attic and Other # Glass with Curb # Plastic with Curb # Without Curb # Create an array of types types_to_modify << ['Outdoors', 'ExteriorWall', 'SteelFramed'] types_to_modify << ['Outdoors', 'ExteriorRoof', 'IEAD'] types_to_modify << ['Outdoors', 'ExteriorFloor', 'SteelFramed'] types_to_modify << ['Outdoors', 'ExteriorWindow', 'Any Vertical Glazing'] types_to_modify << ['Outdoors', 'GlassDoor', 'Any Vertical Glazing'] types_to_modify << ['Outdoors', 'ExteriorDoor', 'NonSwinging'] types_to_modify << ['Outdoors', 'ExteriorDoor', 'Swinging'] types_to_modify << ['Ground', 'GroundContactFloor', 'Unheated'] types_to_modify << ['Ground', 'GroundContactWall', 'Mass'] # Foundation types_to_modify << ['Foundation', 'GroundContactFloor', 'Unheated'] types_to_modify << ['Foundation', 'GroundContactWall', 'Mass'] # F/C-Factor methods types_to_modify << ['GroundFCfactorMethod', 'GroundContactFloor', 'Unheated'] types_to_modify << ['GroundFCfactorMethod', 'GroundContactWall', 'Mass'] # Other side coefficients types_to_modify << ['OtherSideCoefficients', 'GroundContactFloor', 'Unheated'] types_to_modify << ['OtherSideConditionsModel', 'GroundContactFloor', 'Unheated'] types_to_modify << ['OtherSideCoefficients', 'GroundContactWall', 'Mass'] types_to_modify << ['OtherSideConditionsModel', 'GroundContactWall', 'Mass'] # Slab preprocessor types_to_modify << ['GroundSlabPreprocessorAverage', 'GroundContactFloor', 'Unheated'] types_to_modify << ['GroundSlabPreprocessorCore', 'GroundContactFloor', 'Unheated'] types_to_modify << ['GroundSlabPreprocessorPerimeter', 'GroundContactFloor', 'Unheated'] # Basement preprocessor types_to_modify << ['GroundBasementPreprocessorAverageWall', 'GroundContactWall', 'Mass'] types_to_modify << ['GroundBasementPreprocessorAverageFloor', 'GroundContactFloor', 'Unheated'] types_to_modify << ['GroundBasementPreprocessorUpperWall', 'GroundContactWall', 'Mass'] types_to_modify << ['GroundBasementPreprocessorLowerWall', 'GroundContactWall', 'Mass'] # Modify all constructions of each type types_to_modify.each do |boundary_cond, surf_type, const_type| constructions = OpenstudioStandards::Constructions.model_get_constructions(model, boundary_cond, surf_type) constructions.sort.each do |const| standards_info = const.standardsInformation standards_info.setIntendedSurfaceType(surf_type) standards_info.setStandardsConstructionType(const_type) end end return true end |
#model_apply_standard_constructions(model, climate_zone, wwr_building_type: nil, wwr_info: {}) ⇒ Boolean
Apply the standard construction to each surface in the model, based on the construction type currently assigned.
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 352 def model_apply_standard_constructions(model, climate_zone, wwr_building_type: nil, wwr_info: {}) types_to_modify = [] # Possible boundary conditions are # Adiabatic # Surface # Outdoors # Ground # Foundation # GroundFCfactorMethod # OtherSideCoefficients # OtherSideConditionsModel # GroundSlabPreprocessorAverage # GroundSlabPreprocessorCore # GroundSlabPreprocessorPerimeter # GroundBasementPreprocessorAverageWall # GroundBasementPreprocessorAverageFloor # GroundBasementPreprocessorUpperWall # GroundBasementPreprocessorLowerWall # Possible surface types are # Floor # Wall # RoofCeiling # FixedWindow # OperableWindow # Door # GlassDoor # OverheadDoor # Skylight # TubularDaylightDome # TubularDaylightDiffuser # Create an array of surface types types_to_modify << ['Outdoors', 'Floor'] types_to_modify << ['Outdoors', 'Wall'] types_to_modify << ['Outdoors', 'RoofCeiling'] types_to_modify << ['Outdoors', 'FixedWindow'] types_to_modify << ['Outdoors', 'OperableWindow'] types_to_modify << ['Outdoors', 'Door'] types_to_modify << ['Outdoors', 'GlassDoor'] types_to_modify << ['Outdoors', 'OverheadDoor'] types_to_modify << ['Outdoors', 'Skylight'] types_to_modify << ['Surface', 'Floor'] types_to_modify << ['Surface', 'Wall'] types_to_modify << ['Surface', 'RoofCeiling'] types_to_modify << ['Surface', 'FixedWindow'] types_to_modify << ['Surface', 'OperableWindow'] types_to_modify << ['Surface', 'Door'] types_to_modify << ['Surface', 'GlassDoor'] types_to_modify << ['Surface', 'OverheadDoor'] types_to_modify << ['Ground', 'Floor'] types_to_modify << ['Ground', 'Wall'] types_to_modify << ['Foundation', 'Wall'] types_to_modify << ['GroundFCfactorMethod', 'Wall'] types_to_modify << ['OtherSideCoefficients', 'Wall'] types_to_modify << ['OtherSideConditionsModel', 'Wall'] types_to_modify << ['GroundBasementPreprocessorAverageWall', 'Wall'] types_to_modify << ['GroundBasementPreprocessorUpperWall', 'Wall'] types_to_modify << ['GroundBasementPreprocessorLowerWall', 'Wall'] types_to_modify << ['Foundation', 'Floor'] types_to_modify << ['GroundFCfactorMethod', 'Floor'] types_to_modify << ['OtherSideCoefficients', 'Floor'] types_to_modify << ['OtherSideConditionsModel', 'Floor'] types_to_modify << ['GroundSlabPreprocessorAverage', 'Floor'] types_to_modify << ['GroundSlabPreprocessorCore', 'Floor'] types_to_modify << ['GroundSlabPreprocessorPerimeter', 'Floor'] # Find just those surfaces surfaces_to_modify = [] surface_category = {} org_surface_boundary_conditions = {} types_to_modify.each do |boundary_condition, surface_type| # Surfaces model.getSurfaces.sort.each do |surf| next unless surf.outsideBoundaryCondition == boundary_condition next unless surf.surfaceType == surface_type # Check if surface is adjacent to an unenclosed or unconditioned space (e.g. attic or parking garage) if surf.outsideBoundaryCondition == 'Surface' adj_space = surf.adjacentSurface.get.space.get adj_space_cond_type = space_conditioning_category(adj_space) if adj_space_cond_type == 'Unconditioned' # Get adjacent surface adjacent_surf = surf.adjacentSurface.get # Store original boundary condition type org_surface_boundary_conditions[surf.name.to_s] = adjacent_surf # Identify this surface as exterior surface_category[surf] = 'ExteriorSurface' # Temporary change the surface's boundary condition to 'Outdoors' so it can be assigned a baseline construction surf.setOutsideBoundaryCondition('Outdoors') adjacent_surf.setOutsideBoundaryCondition('Outdoors') end end if boundary_condition == 'Outdoors' surface_category[surf] = 'ExteriorSurface' elsif ['Ground', 'Foundation', 'GroundFCfactorMethod', 'OtherSideCoefficients', 'OtherSideConditionsModel', 'GroundSlabPreprocessorAverage', 'GroundSlabPreprocessorCore', 'GroundSlabPreprocessorPerimeter', 'GroundBasementPreprocessorAverageWall', 'GroundBasementPreprocessorAverageFloor', 'GroundBasementPreprocessorUpperWall', 'GroundBasementPreprocessorLowerWall'].include?(boundary_condition) surface_category[surf] = 'GroundSurface' else surface_category[surf] = 'NA' end surfaces_to_modify << surf end # SubSurfaces model.getSubSurfaces.sort.each do |surf| next unless surf.outsideBoundaryCondition == boundary_condition next unless surf.subSurfaceType == surface_type surface_category[surf] = 'ExteriorSubSurface' surfaces_to_modify << surf end end # Modify these surfaces prev_created_consts = {} surfaces_to_modify.sort.each do |surf| # Get space conditioning space = surf.space.get space_cond_type = space_conditioning_category(space) # Do not modify constructions for unconditioned spaces prev_created_consts = planar_surface_apply_standard_construction(surf, climate_zone, prev_created_consts, wwr_building_type, wwr_info, surface_category[surf]) unless space_cond_type == 'Unconditioned' # Reset boundary conditions to original if they were temporary modified if org_surface_boundary_conditions.include?(surf.name.to_s) surf.setAdjacentSurface(org_surface_boundary_conditions[surf.name.to_s]) end end # List the unique array of constructions if prev_created_consts.empty? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', 'None of the constructions in your proposed model have both Intended Surface Type and Standards Construction Type') else prev_created_consts.each do |surf_type, construction| OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "For #{surf_type.join(' ')}, applied #{construction.name}.") end end return true end |
#model_apply_standard_infiltration(model, specific_space_infiltration_rate_75_pa = nil) ⇒ Boolean
This method creates customized infiltration objects for each space and removes the SpaceType-level infiltration objects.
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 136 def model_apply_standard_infiltration(model, specific_space_infiltration_rate_75_pa = nil) # Model shouldn't use SpaceInfiltrationEffectiveLeakageArea # Excerpt from the EnergyPlus Input/Output reference manual: # "This model is based on work by Sherman and Grimsrud (1980) # and is appropriate for smaller, residential-type buildings." # Raise exception if the model does use this object ela = 0 model.getSpaceInfiltrationEffectiveLeakageAreas.sort.each do |eff_la| ela += 1 end if ela > 0 OpenStudio.logFree(OpenStudio::Warn, 'prm.log', 'The current model cannot include SpaceInfiltrationEffectiveLeakageArea. These objects will be skipped in modeling infiltration according to the 90.1-PRM rules.') end # Get the space building envelope area building_envelope_area_m2 = model_building_envelope_area(model) prm_raise(building_envelope_area_m2 > 0.0, @sizing_run_dir, 'Calculated building envelope area is 0 m2, Please check model inputs.') # Calculate current model air leakage rate @ 75 Pa and report it curr_tot_infil_m3_per_s_per_envelope_area = model_current_building_envelope_infiltration_at_75pa(model, building_envelope_area_m2) OpenStudio.logFree(OpenStudio::Info, 'prm.log', "The model's I_75Pa is estimated to be #{curr_tot_infil_m3_per_s_per_envelope_area} m3/s per m2 of total building envelope.") # Calculate building adjusted building envelope # air infiltration following the 90.1 PRM rules tot_infil_m3_per_s = model_adjusted_building_envelope_infiltration(building_envelope_area_m2, specific_space_infiltration_rate_75_pa) # Find infiltration method used in the model, if any. # # If multiple methods are used, use per above grade wall # area (i.e. exterior wall area), if air/changes per hour # or exterior surface area is used, use Flow/ExteriorWallArea infil_method = model_get_infiltration_method(model) infil_method = 'Flow/ExteriorWallArea' if infil_method != 'Flow/Area' || infil_method != 'Flow/ExteriorWallArea' infil_coefficients = model_get_infiltration_coefficients(model) # Set the infiltration rate at each space model.getSpaces.each do |space| space_apply_infiltration_rate(space, tot_infil_m3_per_s, infil_method, infil_coefficients) end # Remove infiltration rates set at the space type model.getSpaceTypes.each do |space_type| space_type.spaceInfiltrationDesignFlowRates.each(&:remove) end return true end |
#model_baseline_system_vav_fan_type(model) ⇒ String
Determines the fan type used by VAV_Reheat and VAV_PFP_Boxes systems. Variable speed fan for 90.1-2019
102 103 104 105 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 102 def model_baseline_system_vav_fan_type(model) fan_type = 'Variable Speed Fan' return fan_type end |
#model_building_envelope_area(model) ⇒ Double
Calculate the building envelope area according to the 90.1 definition
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 111 def model_building_envelope_area(model) # Get the space building envelope area # According to the 90.1 definition, building envelope include: # - "the elements of a building that separate conditioned spaces from the exterior" # - "the elements of a building that separate conditioned space from unconditioned # space or that enclose semiheated spaces through which thermal energy may be # transferred to or from the exterior, to or from unconditioned spaces or to or # from conditioned spaces." building_envelope_area_m2 = 0 model.getSpaces.each do |space| building_envelope_area_m2 += OpenstudioStandards::Geometry.space_get_envelope_area(space) end if building_envelope_area_m2 < 0.01 OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', 'Calculated building envelope area is 0 m2, no infiltration will be added.') return 0.0 end return building_envelope_area_m2 end |
#model_create_multizone_fan_schedule(model, zone_op_hrs, pri_zones, system_name) ⇒ Object
For a multizone system, create the fan schedule based on zone occupancy/fan schedules
3067 3068 3069 3070 3071 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 3067 def model_create_multizone_fan_schedule(model, zone_op_hrs, pri_zones, system_name) # Create fan schedule for multizone system fan_8760 = [] # If any zone is on for an hour, then the system fan must be on for that hour pri_zones.each do |zone| zone_name = zone.name.get.to_s if fan_8760.empty? fan_8760 = zone_op_hrs[zone_name] else (0..fan_8760.size - 1).each do |ihr| if zone_op_hrs[zone_name][ihr] > 0 fan_8760[ihr] = 1 end end end end # Convert 8760 array to schedule ruleset fan_sch_limits = model.getScheduleTypeLimitsByName('fan schedule limits for prm') if fan_sch_limits.empty? fan_sch_limits = OpenStudio::Model::ScheduleTypeLimits.new(model) fan_sch_limits.setName('fan schedule limits for prm') fan_sch_limits.setNumericType('DISCRETE') fan_sch_limits.setUnitType('Dimensionless') fan_sch_limits.setLowerLimitValue(0) fan_sch_limits.setUpperLimitValue(1) else fan_sch_limits = fan_sch_limits.get end sch_name = "#{system_name} fan schedule" make_ruleset_sched_from_8760(model, fan_8760, sch_name, fan_sch_limits) air_loop = model.getAirLoopHVACByName(system_name).get air_loop.additionalProperties.setFeature('fan_sched_name', sch_name) end |
#model_current_building_envelope_infiltration_at_75pa(model, building_envelope_area_m2) ⇒ Double
This methods calculate the current model air leakage rate @ 75 Pa. It assumes that the model follows the PRM methods, see G3.1.1.4 in 90.1-2019 for reference.
305 306 307 308 309 310 311 312 313 314 315 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 305 def model_current_building_envelope_infiltration_at_75pa(model, building_envelope_area_m2) bldg_air_leakage_rate = 0 model.getSpaces.each do |space| bldg_air_leakage_rate += model_get_space_air_leakage(space) end # adjust_infiltration_to_prototype_building_conditions(1) corresponds # to the 0.112 shown in G3.1.1.4 curr_tot_infil_m3_per_s_per_envelope_area = bldg_air_leakage_rate / OpenstudioStandards::Infiltration.adjust_infiltration_to_prototype_building_conditions(1) / building_envelope_area_m2 return curr_tot_infil_m3_per_s_per_envelope_area end |
#model_differentiate_primary_secondary_thermal_zones(model, zones, zone_fan_scheds) ⇒ Hash
For a multizone system, identify any zones to isolate to separate PSZ systems isolated zones are on the ‘secondary’ list This version of the method applies to standard years 2016 and later (stable baseline)
3112 3113 3114 3115 3116 3117 3118 3119 3120 3121 3122 3123 3124 3125 3126 3127 3128 3129 3130 3131 3132 3133 3134 3135 3136 3137 3138 3139 3140 3141 3142 3143 3144 3145 3146 3147 3148 3149 3150 3151 3152 3153 3154 3155 3156 3157 3158 3159 3160 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 3232 3233 3234 3235 3236 3237 3238 3239 3240 3241 3242 3243 3244 3245 3246 3247 3248 3249 3250 3251 3252 3253 3254 3255 3256 3257 3258 3259 3260 3261 3262 3263 3264 3265 3266 3267 3268 3269 3270 3271 3272 3273 3274 3275 3276 3277 3278 3279 3280 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 3112 def model_differentiate_primary_secondary_thermal_zones(model, zones, zone_fan_scheds) pri_zones = [] sec_zones = [] pri_zone_names = [] sec_zone_names = [] zone_op_hrs = {} # hash of zoneName: 8760 array of operating hours # If there is only one zone, then set that as primary if zones.size == 1 zones.each do |zone| pri_zones << zone pri_zone_names << zone.name.get.to_s zone_name = zone.name.get.to_s if zone_fan_scheds.key?(zone_name) zone_fan_sched = zone_fan_scheds[zone_name] else zone_fan_sched = nil end zone_op_hrs[zone.name.get.to_s] = (model, zone, zone_fan_sched) end # Report out the primary vs. secondary zones unless sec_zone_names.empty? OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Secondary system zones = #{sec_zone_names.join(', ')}.") end return { 'primary' => pri_zones, 'secondary' => sec_zones, 'zone_op_hrs' => zone_op_hrs } end zone_eflh = {} # hash of zoneName: eflh for zone zone_max_load = {} # hash of zoneName: coincident max internal load load_limit = 10 # differ by 10 Btu/hr-sf or more eflh_limit = 40 # differ by more than 40 EFLH/week from average of other zones zone_area = {} # hash of zoneName:area # Get coincident peak internal load for each zone zones.each do |zone| zone_name = zone.name.get.to_s if zone_fan_scheds.key?(zone_name) zone_fan_sched = zone_fan_scheds[zone_name] else zone_fan_sched = nil end zone_op_hrs[zone_name] = (model, zone, zone_fan_sched) zone_eflh[zone_name] = thermal_zone_occupancy_eflh(zone, zone_op_hrs[zone_name]) zone_max_load_w = thermal_zone_peak_internal_load(model, zone) zone_max_load_w_m2 = zone_max_load_w / zone.floorArea zone_max_load[zone_name] = OpenStudio.convert(zone_max_load_w_m2, 'W/m^2', 'Btu/hr*ft^2').get zone_area[zone_name] = zone.floorArea end # Eliminate all zones for which both max load and EFLH exceed limits zones.each do |zone| zone_name = zone.name.get.to_s max_load = zone_max_load[zone_name] avg_max_load = get_wtd_avg_of_other_zones(zone_max_load, zone_area, zone_name) max_load_diff = (max_load - avg_max_load).abs avg_eflh = get_avg_of_other_zones(zone_eflh, zone_name) eflh_diff = (avg_eflh - zone_eflh[zone_name]).abs if max_load_diff >= load_limit && eflh_diff > eflh_limit # Add zone to secondary list, and remove from hashes OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "Zone moved to PSZ due to load AND eflh: #{zone_name}; load limit = #{load_limit}, eflh_limit = #{eflh_limit}") OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "load diff = #{max_load_diff}, this zone load = #{max_load}, avg zone load = #{avg_max_load}") OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "eflh diff = #{eflh_diff}, this zone load = #{zone_eflh[zone_name]}, avg zone eflh = #{avg_eflh}") sec_zones << zone sec_zone_names << zone_name zone_eflh.delete(zone_name) zone_max_load.delete(zone_name) end end # Eliminate worst zone where EFLH exceeds limit # Repeat until all zones are within limit num_zones = zone_eflh.size avg_eflh_save = 0 max_zone_name = '' max_eflh_diff = 0 max_zone = nil (1..num_zones).each do |izone| # This loop is to iterate to eliminate one zone at a time max_eflh_diff = 0 zones.each do |zone| # This loop finds the worst remaining zone to eliminate if above threshold zone_name = zone.name.get.to_s next if !zone_eflh.key?(zone_name) avg_eflh = get_avg_of_other_zones(zone_eflh, zone_name) eflh_diff = (avg_eflh - zone_eflh[zone_name]).abs if eflh_diff > max_eflh_diff max_eflh_diff = eflh_diff max_zone_name = zone_name max_zone = zone avg_eflh_save = avg_eflh end end # All zones are now within the limit, exit the iteration break unless max_eflh_diff > eflh_limit # Move the max Zone to the secondary list OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "Zone moved to PSZ due to eflh: #{max_zone_name}; limit = #{eflh_limit}") OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "eflh diff = #{max_eflh_diff}, this zone load = #{zone_eflh[max_zone_name]}, avg zone eflh = #{avg_eflh_save}") sec_zones << max_zone sec_zone_names << max_zone_name zone_eflh.delete(max_zone_name) zone_max_load.delete(max_zone_name) end # Eliminate worst zone where max load exceeds limit and repeat until all pass num_zones = zone_eflh.size highest_max_load_diff = -1 highest_zone = nil highest_zone_name = '' highest_max_load = 0 avg_max_load_save = 0 (1..num_zones).each do |izone| # This loop is to iterate to eliminate one zone at a time highest_max_load_diff = 0 zones.each do |zone| # This loop finds the worst remaining zone to eliminate if above threshold zone_name = zone.name.get.to_s next if !zone_max_load.key?(zone_name) max_load = zone_max_load[zone_name] avg_max_load = get_wtd_avg_of_other_zones(zone_max_load, zone_area, zone_name) max_load_diff = (max_load - avg_max_load).abs if max_load_diff >= highest_max_load_diff highest_max_load_diff = max_load_diff highest_zone_name = zone_name highest_zone = zone highest_max_load = max_load avg_max_load_save = avg_max_load end end # All zones are now within the limit, exit the iteration break unless highest_max_load_diff > load_limit # Move the max Zone to the secondary list OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "Zone moved to PSZ due to load: #{highest_zone_name}; load limit = #{load_limit}") OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "load diff = #{highest_max_load_diff}, this zone load = #{highest_max_load}, avg zone load = #{avg_max_load_save}") sec_zones << highest_zone sec_zone_names << highest_zone_name zone_eflh.delete(highest_zone_name) zone_max_load.delete(highest_zone_name) end # Place remaining zones in multizone system list zone_eflh.each_key do |key| zones.each do |zone| if key == zone.name.get.to_s pri_zones << zone pri_zone_names << key end end end # Report out the primary vs. secondary zones unless pri_zone_names.empty? OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Primary system zones = #{pri_zone_names.join(', ')}.") end unless sec_zone_names.empty? OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Secondary system zones = #{sec_zone_names.join(', ')}.") end return { 'primary' => pri_zones, 'secondary' => sec_zones, 'zone_op_hrs' => zone_op_hrs } end |
#model_does_require_wwr_adjustment?(wwr_limit, wwr_list) ⇒ Boolean
This function checks whether it is required to adjust the window to wall ratio based on the model WWR and wwr limit.
2425 2426 2427 2428 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2425 def model_does_require_wwr_adjustment?(wwr_limit, wwr_list) # 90.1 PRM routine requires return true end |
#model_evaluate_dcv_requirements(model) ⇒ Boolean
Template method for evaluate DCV requirements in the user model
1112 1113 1114 1115 1116 1117 1118 1119 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1112 def model_evaluate_dcv_requirements(model) model_mark_zone_dcv_existence(model) model_add_dcv_user_exception_properties(model) model_add_dcv_requirement_properties(model) model_add_apxg_dcv_properties(model) model_raise_user_model_dcv_errors(model) return true end |
#model_get_bat_wwr_target(bat, wwr_list) ⇒ Double
For 2019, it is required to adjusted wwr based on building categories for all other types
2435 2436 2437 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2435 def model_get_bat_wwr_target(bat, wwr_list) wwr_limit = 40.0 # Lookup WWR target from stable baseline table wwr_lib = standards_data['prm_wwr_bldg_type'] search_criteria = { 'template' => template, 'wwr_building_type' => bat } wwr_limit_bat = model_find_object(wwr_lib, search_criteria) # If building type isn't found, assume that it's # the same as 'All Others' if wwr_limit_bat.nil? || bat.casecmp?('all others') wwr = wwr_list.max # All others type # use the min of 40% and the max wwr in the ZCC-wwr list. wwr_limit = [wwr_limit, wwr].min else # Matched type: use WWR from database. wwr_limit = wwr_limit_bat['wwr'] * 100.0 end return wwr_limit end |
#model_get_fan_power_breakdown ⇒ Boolean
Indicate if fan power breakdown (supply, return, and relief) are needed
959 960 961 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 959 def model_get_fan_power_breakdown return true end |
#model_get_infiltration_coefficients(model) ⇒ String
This method retrieves the infiltration coefficients used in the model. If input is inconsitent, returns
- 0, 0, 0.224, 0
-
as per PRM user manual
224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 224 def model_get_infiltration_coefficients(model) cst = nil temp = nil vel = nil vel_2 = nil infil_coeffs = [cst, temp, vel, vel_2] model.getSpaces.each do |space| # Infiltration at the space level unless space.spaceInfiltrationDesignFlowRates.empty? old_infil = space.spaceInfiltrationDesignFlowRates[0] cst = old_infil.constantTermCoefficient temp = old_infil.temperatureTermCoefficient vel = old_infil.velocityTermCoefficient vel_2 = old_infil.velocitySquaredTermCoefficient old_infil_coeffs = [cst, temp, vel, vel_2] if !(cst.nil? && temp.nil? && vel.nil? && vel_2.nil?) # Return flow per space floor area if method is inconsisten in proposed model return [0.0, 0.0, 0.224, 0.0] if infil_coeffs != old_infil_coeffs && !(infil_coeffs[0].nil? && infil_coeffs[1].nil? && infil_coeffs[2].nil? && infil_coeffs[3].nil?) infil_coeffs = old_infil_coeffs end # Infiltration at the space type level if infil_coeffs == [nil, nil, nil, nil] && space.spaceType.is_initialized space_type = space.spaceType.get unless space_type.spaceInfiltrationDesignFlowRates.empty? old_infil = space_type.spaceInfiltrationDesignFlowRates[0] cst = old_infil.constantTermCoefficient temp = old_infil.temperatureTermCoefficient vel = old_infil.velocityTermCoefficient vel_2 = old_infil.velocitySquaredTermCoefficient old_infil_coeffs = [cst, temp, vel, vel_2] if !(cst.nil? && temp.nil? && vel.nil? && vel_2.nil?) # Return flow per space floor area if method is inconsisten in proposed model return [0.0, 0.0, 0.224, 0.0] unless infil_coeffs != old_infil_coeffs && !(infil_coeffs[0].nil? && infil_coeffs[1].nil? && infil_coeffs[2].nil? && infil_coeffs[3].nil?) infil_coeffs = old_infil_coeffs end end end return infil_coeffs end |
#model_get_infiltration_method(model) ⇒ String
This method retrieves the type of infiltration input used in the model. If input is inconsistent, returns Flow/Area
189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 189 def model_get_infiltration_method(model) infil_method = nil model.getSpaces.each do |space| # Infiltration at the space level unless space.spaceInfiltrationDesignFlowRates.empty? old_infil = space.spaceInfiltrationDesignFlowRates[0] old_infil_method = old_infil.designFlowRateCalculationMethod.to_s # Return flow per space floor area if method is inconsisten in proposed model return 'Flow/Area' if infil_method != old_infil_method && !infil_method.nil? infil_method = old_infil_method end # Infiltration at the space type level if infil_method.nil? && space.spaceType.is_initialized space_type = space.spaceType.get unless space_type.spaceInfiltrationDesignFlowRates.empty? old_infil = space_type.spaceInfiltrationDesignFlowRates[0] old_infil_method = old_infil.designFlowRateCalculationMethod.to_s # Return flow per space floor area if method is inconsisten in proposed model return 'Flow/Area' if infil_method != old_infil_method && !infil_method.nil? infil_method = old_infil_method end end end return infil_method end |
#model_get_space_air_leakage(space) ⇒ Double
This methods calculate the air leakage rate of a space
275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 275 def model_get_space_air_leakage(space) space_air_leakage = 0 space_multipler = space.multiplier # Infiltration at the space level unless space.spaceInfiltrationDesignFlowRates.empty? space.spaceInfiltrationDesignFlowRates.each do |infil_obj| unless infil_obj.designFlowRate.is_initialized if infil_obj.flowperSpaceFloorArea.is_initialized space_air_leakage += infil_obj.flowperSpaceFloorArea.get * space.floorArea * space_multipler elsif infil_obj.flowperExteriorSurfaceArea.is_initialized space_air_leakage += infil_obj.flowperExteriorSurfaceArea.get * space.exteriorArea * space_multipler elsif infil_obj.flowperExteriorWallArea.is_initialized space_air_leakage += infil_obj.flowperExteriorWallArea.get * space.exteriorWallArea * space_multipler elsif infil_obj.airChangesperHour.is_initialized space_air_leakage += infil_obj.airChangesperHour.get * space.volume * space_multipler / 3600 end end end end return space_air_leakage end |
#model_identify_non_mechanically_cooled_systems(model) ⇒ Hash
Zone-level evaporative cooler is not currently supported
Identifies non mechanically cooled (“nmc”) systems, if applicable and add a flag to the zone’s and air loop’s additional properties. by OpenStudio, will need to be added to the method when supported.
909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 909 def model_identify_non_mechanically_cooled_systems(model) # Iterate through zones to find out if they are served by nmc systems model.getThermalZones.each do |zone| # Check if airloop has economizer and either: # - No cooling coil and/or, # - An evaporative cooling coil zone.airLoopHVACs.each do |air_loop| if (!air_loop_hvac_include_cooling_coil?(air_loop) && air_loop_hvac_include_evaporative_cooler?(air_loop)) || (!air_loop_hvac_include_cooling_coil?(air_loop) && air_loop_hvac_include_economizer?(air_loop)) air_loop.additionalProperties.setFeature('non_mechanically_cooled', true) zone.additionalProperties.setFeature('non_mechanically_cooled', true) end end end end |
#model_mark_zone_dcv_existence(model) ⇒ Boolean
Add zone additional property “zone DCV implemented in user model”:
- 'true' if zone OA flow requirement is specified as per person & airloop supporting this zone has DCV enabled
- 'false' otherwise
1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1180 def model_mark_zone_dcv_existence(model) model.getAirLoopHVACs.each do |air_loop_hvac| next unless air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized oa_system = air_loop_hvac.airLoopHVACOutdoorAirSystem.get controller_oa = oa_system.getControllerOutdoorAir controller_mv = controller_oa.controllerMechanicalVentilation next unless controller_mv.demandControlledVentilation == true air_loop_hvac.thermalZones.each do |thermal_zone| zone_dcv = false thermal_zone.spaces.each do |space| dsn_oa = space.designSpecificationOutdoorAir next if dsn_oa.empty? dsn_oa = dsn_oa.get next if dsn_oa.outdoorAirMethod == 'Maximum' if dsn_oa.outdoorAirFlowperPerson > 0 # only in this case the thermal zone is considered to be implemented with DCV zone_dcv = true end end if zone_dcv thermal_zone.additionalProperties.setFeature('zone DCV implemented in user model', true) end end end # mark unmarked zones model.getThermalZones.each do |zone| next if zone.additionalProperties.hasFeature('zone DCV implemented in user model') zone.additionalProperties.setFeature('zone DCV implemented in user model', false) end return true end |
#model_prm_baseline_system_change_fuel_type(model, fuel_type, climate_zone) ⇒ String
Change the fuel type based on climate zone, depending on the standard. For 90.1-2013, fuel type is based on climate zone, not the proposed model.
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 77 def model_prm_baseline_system_change_fuel_type(model, fuel_type, climate_zone) # For 90.1-2013 the fuel type is determined based on climate zone. # Don't change the fuel if it purchased heating or cooling. if fuel_type == 'electric' || fuel_type == 'fossil' case climate_zone when 'ASHRAE 169-2006-1A', 'ASHRAE 169-2006-2A', 'ASHRAE 169-2006-3A', 'ASHRAE 169-2013-1A', 'ASHRAE 169-2013-2A', 'ASHRAE 169-2013-3A' fuel_type = 'electric' else fuel_type = 'fossil' end OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', "Heating fuel is #{fuel_type} for 90.1-2013, climate zone #{climate_zone}. This is independent of the heating fuel type in the proposed building, per G3.1.1-3. This is different than previous versions of 90.1.") end return fuel_type end |
#model_prm_baseline_system_groups(model, custom, bldg_type_hvac_zone_hash) ⇒ Array<Hash>
Assign spaces to system groups based on building area type Get zone groups separately for each hvac building type
2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2556 def model_prm_baseline_system_groups(model, custom, bldg_type_hvac_zone_hash) bldg_groups = [] bldg_type_hvac_zone_hash.each_key do |hvac_building_type, zones_in_building_type| # Get all groups for this hvac building type new_groups = get_baseline_system_groups_for_one_building_type(model, hvac_building_type, zones_in_building_type) # Add the groups for this hvac building type to the full list new_groups.each do |group| bldg_groups << group end end return bldg_groups end |
#model_prm_baseline_system_number(model, climate_zone, area_type, fuel_type, area_ft2, num_stories, custom) ⇒ String
Determines which system number is used for the baseline system.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 8 def model_prm_baseline_system_number(model, climate_zone, area_type, fuel_type, area_ft2, num_stories, custom) sys_num = nil # Customization - Xcel EDA Program Manual 2014 # Table 3.2.2 Baseline HVAC System Types if custom == 'Xcel Energy CO EDA' OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.Model', 'Custom; per Xcel EDA Program Manual 2014 Table 3.2.2 Baseline HVAC System Types, the 90.1-2010 lookup for HVAC system types shall be used.') # Set the area limit limit_ft2 = 25_000 case area_type when 'residential' sys_num = '1_or_2' when 'nonresidential' # nonresidential and 3 floors or less and <25,000 ft2 if num_stories <= 3 && area_ft2 < limit_ft2 sys_num = '3_or_4' # nonresidential and 4 or 5 floors or 5 floors or less and 25,000 ft2 to 150,000 ft2 elsif ((num_stories == 4 || num_stories == 5) && area_ft2 < limit_ft2) || (num_stories <= 5 && (area_ft2 >= limit_ft2 && area_ft2 <= 150_000)) sys_num = '5_or_6' # nonresidential and more than 5 floors or >150,000 ft2 elsif num_stories >= 5 || area_ft2 > 150_000 sys_num = '7_or_8' end when 'heatedonly' sys_num = '9_or_10' when 'retail' # Should only be hit by Xcel EDA sys_num = '3_or_4' end else # Set the area limit limit_ft2 = 25_000 case area_type when 'residential' sys_num = '1_or_2' when 'nonresidential' # nonresidential and 3 floors or less and <25,000 ft2 if num_stories <= 3 && area_ft2 < limit_ft2 sys_num = '3_or_4' # nonresidential and 4 or 5 floors or 5 floors or less and 25,000 ft2 to 150,000 ft2 elsif ((num_stories == 4 || num_stories == 5) && area_ft2 < limit_ft2) || (num_stories <= 5 && (area_ft2 >= limit_ft2 && area_ft2 <= 150_000)) sys_num = '5_or_6' # nonresidential and more than 5 floors or >150,000 ft2 elsif num_stories >= 5 || area_ft2 > 150_000 sys_num = '7_or_8' end when 'heatedonly' sys_num = '9_or_10' when 'retail' sys_num = '3_or_4' end end return sys_num end |
#model_prm_baseline_system_type(model, climate_zone, sys_group, custom, hvac_building_type, district_heat_zones) ⇒ String
Select system type from data table base on key parameters
Alternate method for 2016 and later stable baseline Limits for each building area type are taken from data table Heating fuel is based on climate zone, unless district heat is in proposed
2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 2973 2974 2975 2976 2977 2978 2979 2980 2981 2982 2983 2984 2985 2986 2987 2988 2989 2990 2991 2992 2993 2994 2995 2996 2997 2998 2999 3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011 3012 3013 3014 3015 3016 3017 3018 3019 3020 3021 3022 3023 3024 3025 3026 3027 3028 3029 3030 3031 3032 3033 3034 3035 3036 3037 3038 3039 3040 3041 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 3056 3057 3058 3059 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2942 def model_prm_baseline_system_type(model, climate_zone, sys_group, custom, hvac_building_type, district_heat_zones) area_type = sys_group['occ'] fuel_type = sys_group['fuel'] area_ft2 = sys_group['building_area_type_ft2'] num_stories = sys_group['stories'] # [type, central_heating_fuel, zone_heating_fuel, cooling_fuel] system_type = [nil, nil, nil, nil] # Find matching record from prm baseline hvac table # First filter by number of stories i_story_group = 0 props = {} 0.upto(9) do |i| i_story_group += 1 props = model_find_object(standards_data['prm_baseline_hvac'], 'template' => template, 'hvac_building_type' => area_type, 'flrs_range_group' => i_story_group, 'area_range_group' => 1) prm_raise(props, @sizing_run_dir, "Could not find baseline HVAC type for: #{template}-#{area_type}.") if num_stories <= props['bldg_flrs_max'] # Story Group Is found break end end # Next filter by floor area i_area_group = 0 loop do i_area_group += 1 props = model_find_object(standards_data['prm_baseline_hvac'], 'template' => template, 'hvac_building_type' => area_type, 'flrs_range_group' => i_story_group, 'area_range_group' => i_area_group) prm_raise(props && i_area_group <= 9, @sizing_run_dir, "Could not find baseline HVAC type for: #{template}-#{area_type}.") below_max = false above_min = false # check if actual building floor area is within range for this area group if props['max_area_qual'] == 'LT' if area_ft2 < props['bldg_area_max'] below_max = true end elsif props['max_area_qual'] == 'LE' if area_ft2 <= props['bldg_area_max'] below_max = true end end if props['min_area_qual'] == 'GT' if area_ft2 > props['bldg_area_min'] above_min = true end elsif props['min_area_qual'] == 'GE' if area_ft2 >= props['bldg_area_min'] above_min = true end end if above_min && below_max # break condition. break end end heat_type = find_prm_heat_type(hvac_building_type, climate_zone) # hash to relate apx G systype categories to sys types for model sys_hash = {} if heat_type == 'fuel' sys_hash['PTAC'] = 'PTAC' sys_hash['PSZ'] = 'PSZ_AC' sys_hash['SZ-CV'] = 'SZ_CV' sys_hash['Heating and ventilation'] = 'Gas_Furnace' sys_hash['PSZ-AC'] = 'PSZ_AC' sys_hash['Packaged VAV'] = 'PVAV_Reheat' sys_hash['VAV'] = 'VAV_Reheat' sys_hash['Unconditioned'] = 'None' sys_hash['SZ-VAV'] = 'SZ_VAV' else sys_hash['PTAC'] = 'PTHP' sys_hash['PSZ'] = 'PSZ_HP' sys_hash['SZ-CV'] = 'SZ_CV' sys_hash['Heating and ventilation'] = 'Electric_Furnace' sys_hash['PSZ-AC'] = 'PSZ_HP' sys_hash['Packaged VAV'] = 'PVAV_PFP_Boxes' sys_hash['VAV'] = 'VAV_PFP_Boxes' sys_hash['Unconditioned'] = 'None' sys_hash['SZ-VAV'] = 'SZ_VAV' end model_sys_type = sys_hash[props['system_type']] if /districtheating/i =~ fuel_type central_heat = 'DistrictHeating' elsif heat_type =~ /fuel/i central_heat = 'NaturalGas' else central_heat = 'Electricity' end if /districtheating/i =~ fuel_type && /elec/i !~ fuel_type && /fuel/i !~ fuel_type # if no zone has fuel or elect, set default to district for zones zone_heat = 'DistrictHeating' elsif heat_type =~ /fuel/i zone_heat = 'NaturalGas' else zone_heat = 'Electricity' end if /districtcooling/i =~ fuel_type cool_type = 'DistrictCooling' elsif props['system_type'] =~ /Heating and ventilation/i || props['system_type'] =~ /unconditioned/i cool_type = nil end system_type = [model_sys_type, central_heat, zone_heat, cool_type] return system_type end |
#model_raise_user_model_dcv_errors(model) ⇒ Object
JXL add log msgs to PRM logger
based on previously added flag, raise error if DCV is required but not implemented in zones, in which case baseline generation will be terminated; raise warning if DCV is not required but implemented, and continue baseline generation
1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1319 def model_raise_user_model_dcv_errors(model) model.getThermalZones.each do |thermal_zone| if thermal_zone.additionalProperties.getFeatureAsBoolean('zone DCV implemented in user model').get && (!thermal_zone.additionalProperties.getFeatureAsBoolean('zone dcv required by 901').get || !thermal_zone.additionalProperties.getFeatureAsBoolean('airloop dcv required by 901').get) OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "For thermal zone #{thermal_zone.name}, ASHRAE 90.1 2019 6.4.3.8 does NOT require this zone to have demand control ventilation, but it was implemented in the user model, Appendix G baseline generation will continue!") if thermal_zone.additionalProperties.hasFeature('apxg no need to have DCV') if !thermal_zone.additionalProperties.getFeatureAsBoolean('apxg no need to have DCV').get OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "Moreover, for thermal zone #{thermal_zone.name}, Appendix G baseline model will have DCV based on ASHRAE 90.1 2019 G3.1.2.5") end end end if thermal_zone.additionalProperties.getFeatureAsBoolean('zone dcv required by 901').get && thermal_zone.additionalProperties.getFeatureAsBoolean('airloop dcv required by 901').get && !thermal_zone.additionalProperties.getFeatureAsBoolean('zone DCV implemented in user model').get OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.Model', "For thermal zone #{thermal_zone.name}, ASHRAE 90.1 2019 6.4.3.8 requires this zone to have demand control ventilation, but it was not implemented in the user model, Appendix G baseline generation should be terminated!") end end end |
#model_readjust_surface_wwr(residual_ratio, space, model) ⇒ Boolean
Readjusted the WWR for surfaces previously has no windows to meet the overall WWR requirement. This function shall only be called if the maximum WWR value for surfaces with fenestration is lower than 90% due to accommodating the total door surface areas
2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2535 def model_readjust_surface_wwr(residual_ratio, space, model) # In this loop, we will focus on the surfaces with newly added a fenestration. space.surfaces.sort.each do |surface| next unless surface.additionalProperties.hasFeature('added_wwr') added_wwr = surface.additionalProperties.getFeatureAsDouble('added_wwr').to_f # The full calculation of adjustment is: # ((residual_ratio * surface_area + added_wwr * surface_area) / surface_area ) / added_wwr adjustment_ratio = (residual_ratio / added_wwr) + 1.0 surface_adjust_fenestration_in_a_surface(surface, adjustment_ratio, model) end end |
#model_refine_size_dependent_values(model, sizing_run_dir) ⇒ Boolean
This method is a catch-all run at the end of create-baseline to make final adjustements to HVAC capacities to account for recent model changes
3287 3288 3289 3290 3291 3292 3293 3294 3295 3296 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 3312 3313 3314 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 3287 def model_refine_size_dependent_values(model, sizing_run_dir) # Final sizing run before refining size-dependent values if model_run_sizing_run(model, "#{sizing_run_dir}/SR3") == false return false end model.getAirLoopHVACs.sort.each do |air_loop_hvac| # Reset secondary design secondary flow rate based on updated primary flow air_loop_hvac.demandComponents.each do |dc| next if dc.to_AirTerminalSingleDuctParallelPIUReheat.empty? pfp_term = dc.to_AirTerminalSingleDuctParallelPIUReheat.get sec_flow_frac = 0.5 # Get the maximum flow rate through the terminal max_primary_air_flow_rate = nil if pfp_term.maximumPrimaryAirFlowRate.is_initialized max_primary_air_flow_rate = pfp_term.maximumPrimaryAirFlowRate.get elsif pfp_term.autosizedMaximumPrimaryAirFlowRate.is_initialized max_primary_air_flow_rate = pfp_term.autosizedMaximumPrimaryAirFlowRate.get end max_sec_flow_rate_m3_per_s = max_primary_air_flow_rate * sec_flow_frac pfp_term.setMaximumSecondaryAirFlowRate(max_sec_flow_rate_m3_per_s) end end return true end |
#model_set_baseline_demand_control_ventilation(model, climate_zone) ⇒ Object
Set DCV in baseline HVAC system if required
1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1382 def model_set_baseline_demand_control_ventilation(model, climate_zone) model.getAirLoopHVACs.each do |air_loop_hvac| if baseline_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) air_loop_hvac_enable_demand_control_ventilation(air_loop_hvac, climate_zone) air_loop_hvac.thermalZones.sort.each do |zone| unless baseline_thermal_zone_demand_control_ventilation_required?(zone) OpenstudioStandards::ThermalZone.thermal_zone_convert_outdoor_air_to_per_area(zone) end end end end end |
#model_set_central_preheat_coil_spm(model, thermal_zones, coil) ⇒ Boolean
Template method for adding a setpoint manager for a coil control logic to a heating coil. ASHRAE 90.1-2019 Appendix G.
1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1128 def model_set_central_preheat_coil_spm(model, thermal_zones, coil) # search for the highest zone setpoint temperature max_heat_setpoint = 0.0 coil_name = coil.name.get.to_s thermal_zones.each do |zone| tstat = zone.thermostatSetpointDualSetpoint if tstat.is_initialized tstat = tstat.get setpoint_sch = tstat.heatingSetpointTemperatureSchedule setpoint_c = OpenstudioStandards::Schedules.schedule_get_design_day_min_max(setpoint_sch.get, 'winter')['max'] next if setpoint_c.nil? if setpoint_c > max_heat_setpoint max_heat_setpoint = setpoint_c end end end # in this situation, we hard set the temperature to be 22 F # (ASHRAE 90.1 Room heating stepoint temperature is 72 F) max_heat_setpoint = 22.2 if max_heat_setpoint.zero? max_heat_setpoint_f = OpenStudio.convert(max_heat_setpoint, 'C', 'F').get preheat_setpoint_f = max_heat_setpoint_f - 20 preheat_setpoint_c = OpenStudio.convert(preheat_setpoint_f, 'F', 'C').get # create a new constant schedule and this method will add schedule limit type preheat_coil_sch = OpenstudioStandards::Schedules.create_constant_schedule_ruleset(model, preheat_setpoint_c, name: "#{coil_name} Setpoint Temp - #{preheat_setpoint_f.round}F", schedule_type_limit: 'Temperature') preheat_coil_manager = OpenStudio::Model::SetpointManagerScheduled.new(model, preheat_coil_sch) preheat_coil_manager.setName("#{coil_name} Preheat Coil Setpoint Manager") if coil.to_CoilHeatingWater.is_initialized preheat_coil_manager.addToNode(coil.airOutletModelObject.get.to_Node.get) elsif coil.to_CoilHeatingElectric.is_initialized preheat_coil_manager.addToNode(coil.outletModelObject.get.to_Node.get) elsif coil.to_CoilHeatingGas.is_initialized OpenStudio.logFree(OpenStudio::Warn, 'openstudio.models.CoilHeatingGas', 'Preheat coils in baseline system shall only be electric or hydronic. Current coil type: Natural Gas') preheat_coil_manager.addToNode(coil.airOutletModelObject.get.to_Node.get) end return true end |
#model_update_ground_temperature_profile(model, climate_zone) ⇒ Boolean
Update ground temperature profile based on the weather file specified in the model
2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2373 def model_update_ground_temperature_profile(model, climate_zone) # Check if the ground temperature profile is needed surfaces_with_fc_factor_boundary = false model.getSurfaces.each do |surface| if surface.outsideBoundaryCondition.to_s == 'GroundFCfactorMethod' surfaces_with_fc_factor_boundary = true break end end if surfaces_with_fc_factor_boundary # Remove existing FCFactor temperature profile model.getSiteGroundTemperatureFCfactorMethod.remove # Get path to weather file specified in the model weather_file_path = prm_get_optional_handler(model.getWeatherFile, @sizing_run_dir, 'path').to_s # Look for stat file corresponding to the weather file stat_file_path = weather_file_path.sub('.epw', '.stat').to_s if !File.exist? stat_file_path # When the stat file corresponding with the weather file in the model is missing, # use the weather file that represent the climate zone climate_zone_weather_file_map = OpenstudioStandards::Weather.climate_zone_weather_file_map prm_raise(climate_zone_weather_file_map.key?(climate_zone), @sizing_run_dir, "Failed to find a matching climate zone #{climate_zone} from the climate zone weather files.") weather_file = climate_zone_weather_file_map[climate_zone] stat_file_path = OpenstudioStandards::Weather.get_standards_weather_file_path(weather_file).sub('.epw', '.stat').to_s end ground_temp = OpenStudio::Model::SiteGroundTemperatureFCfactorMethod.new(model) stat_file = OpenstudioStandards::Weather::StatFile.load(stat_file_path) ground_temperatures = stat_file.monthly_lagged_dry_bulb unless ground_temperatures.empty? # set the site ground temperature building surface ground_temp.setAllMonthlyTemperatures(ground_temperatures) end end return surfaces_with_fc_factor_boundary end |
#planar_surface_apply_standard_construction(planar_surface, climate_zone, previous_construction_map = {}, wwr_building_type = nil, wwr_info = {}, surface_category) ⇒ Hash
Align the standard construction enumerations in the
If construction properties can be found based on the template, the standards intended surface type, the standards construction type, the climate zone, and the occupancy type, create a construction that meets those properties and assign it to this surface. 90.1-PRM-2019
spreadsheet with the enumerations in OpenStudio (follow CBECC-Com).
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlanarSurface.rb', line 25 def planar_surface_apply_standard_construction(planar_surface, climate_zone, previous_construction_map = {}, wwr_building_type = nil, wwr_info = {}, surface_category) # Skip surfaces not in a space return previous_construction_map if planar_surface.space.empty? space = planar_surface.space.get if surface_category == 'ExteriorSubSurface' surface_type = planar_surface.subSurfaceType else surface_type = planar_surface.surfaceType end # Skip surfaces that don't have a construction # return previous_construction_map if planar_surface.construction.empty? if planar_surface.construction.empty? # Get appropriate default construction if not defined inside surface object construction = nil space_type = space.spaceType.get if space.defaultConstructionSet.is_initialized cons_set = space.defaultConstructionSet.get construction = get_default_surface_cons_from_surface_type(surface_category, surface_type, cons_set) end if construction.nil? && space_type.defaultConstructionSet.is_initialized cons_set = space_type.defaultConstructionSet.get construction = get_default_surface_cons_from_surface_type(surface_category, surface_type, cons_set) end if construction.nil? && space.buildingStory.get.defaultConstructionSet.is_initialized cons_set = space.buildingStory.get.defaultConstructionSet.get construction = get_default_surface_cons_from_surface_type(surface_category, surface_type, cons_set) end if construction.nil? && space.model.building.get.defaultConstructionSet.is_initialized cons_set = space.model.building.get.defaultConstructionSet.get construction = get_default_surface_cons_from_surface_type(surface_category, surface_type, cons_set) end OpenStudio.logFree(OpenStudio::Error, 'prm.log', "Surface #{planar_surface.name.get} does not have a construction. Failed to find defaultConstructionSet for #{planar_surface.name.get}. Add a construction for the surface or add a defaultConstructionSet to Space #{space.name.get} or SpaceType #{space_type.name.get}.") prm_raise(construction, @sizing_run_dir, "Failed to find defaultConstructionSet for #{planar_surface.name.get}. Check inputs.") else construction = planar_surface.construction.get end # Determine if residential or nonresidential # based on the space type. occ_type = 'Nonresidential' if OpenstudioStandards::Space.space_residential?(space) occ_type = 'Residential' end # Get the climate zone set climate_zone_set = model_find_climate_zone_set(planar_surface.model, climate_zone) # Get the intended surface type standards_info = construction.standardsInformation surf_type = standards_info.intendedSurfaceType if surf_type.empty? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.PlanarSurface', "Could not determine the intended surface type for #{planar_surface.name} from #{construction.name}. This surface will not have the standard applied.") return previous_construction_map end surf_type = surf_type.get # Get the standards type, which is based on different fields # if is intended for a window, a skylight, or something else. # Mapping is between standards-defined enumerations and the # enumerations available in OpenStudio. stds_type = nil case surf_type when 'ExteriorWindow', 'GlassDoor' # Windows and Glass Doors stds_type = standards_info.fenestrationFrameType if stds_type.is_initialized stds_type = stds_type.get if !wwr_building_type.nil? stds_type = 'Any Vertical Glazing' end case stds_type when 'Metal Framing', 'Metal Framing with Thermal Break' stds_type = 'Metal framing (all other)' when 'Non-Metal Framing' stds_type = 'Nonmetal framing (all)' when 'Any Vertical Glazing' stds_type = 'Any Vertical Glazing' else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.PlanarSurface', "The standards fenestration frame type #{stds_type} cannot be used on #{surf_type} in #{planar_surface.name}. This surface will not have the standard applied.") return previous_construction_map end else if wwr_building_type.nil? OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.PlanarSurface', "Could not determine the standards fenestration frame type for #{planar_surface.name} from #{construction.name}. This surface will not have the standard applied.") return previous_construction_map else stds_type = 'Any Vertical Glazing' end end when 'ExteriorDoor' # Exterior Doors stds_type = standards_info.standardsConstructionType if stds_type.is_initialized stds_type = stds_type.get case stds_type when 'RollUp' stds_type = 'NonSwinging' end else stds_type = 'Swinging' end when 'Skylight' # Skylights # There is only one type for AppendixG stable baseline stds_type = 'Any Skylight' else # All other surface types stds_type = standards_info.standardsConstructionType if stds_type.is_initialized stds_type = stds_type.get else if planar_surface.outsideBoundaryCondition == 'Surface' && surface_category == 'NA' OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.PlanarSurface', "Standards construction is not needed and not applied for interior wall: #{planar_surface.name}.") else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.PlanarSurface', "Could not determine the standards construction type for #{planar_surface.name}. This surface will not have the standard applied.") end return previous_construction_map end end # Check if the construction type was already created. # If yes, use that construction. If no, make a new one. # for multi-building type - search for the surface wwr type surface_std_wwr_type = wwr_building_type new_construction = nil type = [template, climate_zone, surf_type, stds_type, occ_type] # Only apply the surface_std_wwr_type update when wwr_building_type has Truthy values if !wwr_building_type.nil? && (surf_type == 'ExteriorWindow' || surf_type == 'GlassDoor') space = planar_surface.space.get if space.hasAdditionalProperties && space.additionalProperties.hasFeature('building_type_for_wwr') surface_std_wwr_type = space.additionalProperties.getFeatureAsString('building_type_for_wwr').get end type.push(surface_std_wwr_type) end if previous_construction_map[type] && !previous_construction_map[type].iddObjectType.valueName.to_s.include?('factorGround') new_construction = previous_construction_map[type] else new_construction = model_find_and_add_construction(planar_surface.model, climate_zone_set, surf_type, stds_type, occ_type, wwr_building_type: surface_std_wwr_type, wwr_info: wwr_info, surface: planar_surface) if !new_construction == false previous_construction_map[type] = new_construction end end # Assign the new construction to the surface if new_construction planar_surface.setConstruction(new_construction) OpenStudio.logFree(OpenStudio::Debug, 'openstudio.standards.PlanarSurface', "Set the construction for #{planar_surface.name} to #{new_construction.name}.") else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.PlanarSurface', "Could not generate a standard construction for #{planar_surface.name}.") return previous_construction_map end return previous_construction_map end |
#plant_loop_apply_prm_baseline_pump_power(plant_loop) ⇒ Boolean
I think it makes more sense to sense the motor efficiency right there… But actually it’s completely irrelevant… you could set at 0.9 and just calculate the pressure rise to have your 19 W/GPM or whatever
Apply prm baseline pump power
534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 534 def plant_loop_apply_prm_baseline_pump_power(plant_loop) hot_water_pump_power = 19 # W/gpm hot_water_district_pump_power = 14 # W/gpm chilled_water_primary_pump_power = 9 # W/gpm chilled_water_secondary_pump_power = 13 # W/gpm chilled_water_district_pump_power = 16 # W/gpm condenser_water_pump_power = 19 # W/gpm # Determine the pumping power per # flow based on loop type. w_per_gpm = nil chiller_counter = 0 sizing_plant = plant_loop.sizingPlant loop_type = sizing_plant.loopType case loop_type when 'Heating' has_district_heating = false plant_loop.supplyComponents.each do |sc| if sc.iddObjectType.valueName.to_s.include?('DistrictHeating') has_district_heating = true end end w_per_gpm = if has_district_heating # District HW hot_water_district_pump_power else # HW hot_water_pump_power end when 'Cooling' has_district_cooling = false plant_loop.supplyComponents.each do |sc| if sc.to_DistrictCooling.is_initialized has_district_cooling = true elsif sc.to_ChillerElectricEIR.is_initialized chiller_counter += 1 end end if has_district_cooling # District CHW w_per_gpm = chilled_water_district_pump_power elsif plant_loop.additionalProperties.hasFeature('is_primary_loop') # The primary loop of the primary/secondary CHW w_per_gpm = chilled_water_primary_pump_power elsif plant_loop.additionalProperties.hasFeature('is_secondary_loop') # The secondary loop of the primary/secondary CHW w_per_gpm = chilled_water_secondary_pump_power else # Primary only CHW combine 9W/gpm + 13W/gpm w_per_gpm = chilled_water_primary_pump_power + chilled_water_secondary_pump_power end when 'Condenser' # @todo prm condenser loop pump power w_per_gpm = condenser_water_pump_power end # Modify all the primary pumps plant_loop.supplyComponents.each do |sc| if sc.to_PumpConstantSpeed.is_initialized pump = sc.to_PumpConstantSpeed.get if chiller_counter > 0 w_per_gpm /= chiller_counter end pump_apply_prm_pressure_rise_and_motor_efficiency(pump, w_per_gpm) elsif sc.to_PumpVariableSpeed.is_initialized pump = sc.to_PumpVariableSpeed.get pump_apply_prm_pressure_rise_and_motor_efficiency(pump, w_per_gpm) elsif sc.to_HeaderedPumpsConstantSpeed.is_initialized pump = sc.to_HeaderedPumpsConstantSpeed.get pump_apply_prm_pressure_rise_and_motor_efficiency(pump, w_per_gpm) elsif sc.to_HeaderedPumpsVariableSpeed.is_initialized pump = sc.to_HeaderedPumpsVariableSpeed.get pump_apply_prm_pressure_rise_and_motor_efficiency(pump, w_per_gpm) end end return true end |
#plant_loop_apply_prm_number_of_chillers(plant_loop) ⇒ Boolean
Splits the single chiller used for the initial sizing run into multiple separate chillers based on Appendix G. Also applies EMS to stage chillers properly
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 99 def plant_loop_apply_prm_number_of_chillers(plant_loop) # Skip non-cooling plants & secondary cooling loop return true unless plant_loop.sizingPlant.loopType == 'Cooling' # If the loop is cooling but it is a secondary loop, then skip. return true if plant_loop.additionalProperties.hasFeature('is_secondary_loop') # Set the equipment to stage sequentially or uniformload if there is secondary loop if plant_loop.additionalProperties.hasFeature('is_primary_loop') plant_loop.setLoadDistributionScheme('UniformLoad') else plant_loop.setLoadDistributionScheme('SequentialLoad') end model = plant_loop.model # Get all existing chillers and pumps. Copy chiller properties needed when duplicating existing settings chillers = [] pumps = [] default_cop = nil condenser_water_loop = nil dsgn_sup_wtr_temp_c = nil plant_loop.supplyComponents.each do |sc| if sc.to_ChillerElectricEIR.is_initialized chiller = sc.to_ChillerElectricEIR.get # Copy the last chillers COP, leaving chilled water temperature, and reference cooling tower. These will be the # default for any extra chillers. default_cop = chiller.referenceCOP dsgn_sup_wtr_temp_c = chiller.referenceLeavingChilledWaterTemperature condenser_water_loop = chiller.condenserWaterLoop chillers << chiller elsif sc.to_PumpConstantSpeed.is_initialized pumps << sc.to_PumpConstantSpeed.get elsif sc.to_PumpVariableSpeed.is_initialized pumps << sc.to_PumpVariableSpeed.get end end # Get existing plant loop pump. We'll copy this pumps parameters before removing it. Throw exception for multiple pumps on supply side if pumps.size.zero? OpenStudio.logFree(OpenStudio::Error, 'prm.log', "For #{plant_loop.name}, found #{pumps.size} pumps. A loop must have at least one pump.") return false elsif pumps.size > 1 OpenStudio.logFree(OpenStudio::Error, 'prm.log', "For #{plant_loop.name}, found #{pumps.size} pumps, cannot split up per performance rating method baseline requirements.") return false else original_pump = pumps[0] end return true if chillers.empty? # Determine the capacity of the loop cap_w = plant_loop_total_cooling_capacity(plant_loop) cap_tons = OpenStudio.convert(cap_w, 'W', 'ton').get # Throw exception for > 2,400 tons as this breaks our staging strategy cap of 3 chillers if cap_tons > 2400 OpenStudio.logFree(OpenStudio::Error, 'prm.log', "For #{plant_loop.name}, the total capacity (#{cap_w}) exceeded 2400 tons and would require more than 3 chillers. The existing code base cannot accommodate the staging required for this") end if cap_tons <= 300 num_chillers = 1 chiller_cooling_type = 'WaterCooled' chiller_compressor_type = 'Rotary Screw' elsif cap_tons > 300 && cap_tons < 600 num_chillers = 2 chiller_cooling_type = 'WaterCooled' chiller_compressor_type = 'Rotary Screw' else # Max capacity of a single chiller max_cap_ton = 800.0 num_chillers = (cap_tons / max_cap_ton).floor + 1 # Must be at least 2 chillers num_chillers += 1 if num_chillers == 1 chiller_cooling_type = 'WaterCooled' chiller_compressor_type = 'Centrifugal' end if chillers.length > num_chillers OpenStudio.logFree(OpenStudio::Error, 'prm.log', "For #{plant_loop.name}, the existing number of chillers exceeds the recommended amount. We have not accounted for this in the codebase yet.") end # Determine the per-chiller capacity and sizing factor per_chiller_sizing_factor = (1.0 / num_chillers).round(2) per_chiller_cap_w = cap_w / num_chillers # Set the sizing factor and the chiller types # chillers.each_with_index do |chiller, i| for i in 0..num_chillers - 1 # if not enough chillers exist, create a new one. Else reference the i'th chiller if i <= chillers.length - 1 chiller = chillers[i] else chiller = OpenStudio::Model::ChillerElectricEIR.new(model) plant_loop.addSupplyBranchForComponent(chiller) chiller.setReferenceLeavingChilledWaterTemperature(dsgn_sup_wtr_temp_c) chiller.setLeavingChilledWaterLowerTemperatureLimit(OpenStudio.convert(36.0, 'F', 'C').get) chiller.setReferenceEnteringCondenserFluidTemperature(OpenStudio.convert(95.0, 'F', 'C').get) chiller.setMinimumPartLoadRatio(0.15) chiller.setMaximumPartLoadRatio(1.0) chiller.setOptimumPartLoadRatio(1.0) chiller.setMinimumUnloadingRatio(0.25) chiller.setChillerFlowMode('ConstantFlow') chiller.setReferenceCOP(default_cop) condenser_water_loop.get.addDemandBranchForComponent(chiller) if condenser_water_loop.is_initialized end chiller.setName("#{template} #{chiller_cooling_type} #{chiller_compressor_type} Chiller #{i + 1} of #{num_chillers}") chiller.setSizingFactor(per_chiller_sizing_factor) chiller.setReferenceCapacity(per_chiller_cap_w) chiller.setCondenserType(chiller_cooling_type) chiller.additionalProperties.setFeature('compressor_type', chiller_compressor_type) # Add inlet pump new_pump = OpenStudio::Model::PumpVariableSpeed.new(plant_loop.model) new_pump.setName("#{chiller.name} Inlet Pump") new_pump.setRatedPumpHead(original_pump.ratedPumpHead / num_chillers) pump_variable_speed_set_control_type(new_pump, control_type = 'Riding Curve') chiller_inlet_node = chiller.connectedObject(chiller.supplyInletPort).get.to_Node.get new_pump.addToNode(chiller_inlet_node) end # Remove original pump, dedicated chiller pumps have all been added original_pump.remove OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.PlantLoop', "For #{plant_loop.name}, there are #{chillers.size} #{chiller_cooling_type} #{chiller_compressor_type} chillers.") # Check for a heat exchanger fluid to fluid-- that lets you know if this is a primary loop has_secondary_plant_loop = !plant_loop.demandComponents(OpenStudio::Model::HeatExchangerFluidToFluid.iddObjectType).empty? if has_secondary_plant_loop # Add EMS to stage chillers if there's a primary/secondary configuration if num_chillers > 3 OpenStudio.logFree(OpenStudio::Error, 'prm.log', "For #{plant_loop.name} has more than 3 chillers. We do not have an EMS strategy for that yet.") elsif num_chillers > 1 add_ems_for_multiple_chiller_pumps_w_secondary_plant(model, plant_loop) end end return true end |
#plant_loop_apply_prm_number_of_cooling_towers(plant_loop) ⇒ Boolean
Returns true if successful, false if not
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 6 def plant_loop_apply_prm_number_of_cooling_towers(plant_loop) # Skip non-cooling plants return true unless plant_loop.sizingPlant.loopType == 'Condenser' # Determine the number of chillers # already in the model num_chillers = plant_loop.model.getChillerElectricEIRs.size # Get all existing cooling towers and pumps clg_twrs = [] pumps = [] plant_loop.supplyComponents.each do |sc| if sc.to_CoolingTowerSingleSpeed.is_initialized clg_twrs << sc.to_CoolingTowerSingleSpeed.get elsif sc.to_CoolingTowerTwoSpeed.is_initialized clg_twrs << sc.to_CoolingTowerTwoSpeed.get elsif sc.to_CoolingTowerVariableSpeed.is_initialized clg_twrs << sc.to_CoolingTowerVariableSpeed.get elsif sc.to_PumpConstantSpeed.is_initialized pumps << sc.to_PumpConstantSpeed.get elsif sc.to_PumpVariableSpeed.is_initialized pumps << sc.to_PumpVariableSpeed.get end end # Ensure there is only 1 cooling tower to start orig_twr = nil if clg_twrs.empty? return true elsif clg_twrs.size > 1 OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.PlantLoop', "For #{plant_loop.name}, found #{clg_twrs.size} cooling towers, cannot split up per performance rating method baseline requirements.") return false else orig_twr = clg_twrs[0] end # Ensure there is only 1 pump to start orig_pump = nil if pumps.empty? OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.PlantLoop', "For #{plant_loop.name}, found #{pumps.size} pumps. A loop must have at least one pump.") return false elsif pumps.size > 1 OpenStudio.logFree(OpenStudio::Error, 'openstudio.standards.PlantLoop', "For #{plant_loop.name}, found #{pumps.size} pumps, cannot split up per performance rating method baseline requirements.") return false else orig_pump = pumps[0] end # Determine the per-cooling_tower sizing factor clg_twr_sizing_factor = (1.0 / num_chillers).round(2) final_twrs = [orig_twr] # return unless there is more than one chiller return true unless num_chillers > 1 # If there is more than one chiller, replace the original pump with a headered pump of the same type and properties. num_pumps = num_chillers new_pump = nil if orig_pump.to_PumpConstantSpeed.is_initialized new_pump = OpenStudio::Model::HeaderedPumpsConstantSpeed.new(plant_loop.model) new_pump.setNumberofPumpsinBank(num_pumps) new_pump.setName("#{orig_pump.name} Bank of #{num_pumps}") new_pump.setRatedPumpHead(orig_pump.ratedPumpHead) new_pump.setMotorEfficiency(orig_pump.motorEfficiency) new_pump.setFractionofMotorInefficienciestoFluidStream(orig_pump.fractionofMotorInefficienciestoFluidStream) new_pump.setPumpControlType(orig_pump.pumpControlType) elsif orig_pump.to_PumpVariableSpeed.is_initialized new_pump = OpenStudio::Model::HeaderedPumpsVariableSpeed.new(plant_loop.model) new_pump.setNumberofPumpsinBank(num_pumps) new_pump.setName("#{orig_pump.name} Bank of #{num_pumps}") new_pump.setRatedPumpHead(orig_pump.ratedPumpHead) new_pump.setMotorEfficiency(orig_pump.motorEfficiency) new_pump.setFractionofMotorInefficienciestoFluidStream(orig_pump.fractionofMotorInefficienciestoFluidStream) new_pump.setPumpControlType(orig_pump.pumpControlType) new_pump.setCoefficient1ofthePartLoadPerformanceCurve(orig_pump.coefficient1ofthePartLoadPerformanceCurve) new_pump.setCoefficient2ofthePartLoadPerformanceCurve(orig_pump.coefficient2ofthePartLoadPerformanceCurve) new_pump.setCoefficient3ofthePartLoadPerformanceCurve(orig_pump.coefficient3ofthePartLoadPerformanceCurve) new_pump.setCoefficient4ofthePartLoadPerformanceCurve(orig_pump.coefficient4ofthePartLoadPerformanceCurve) end # Remove the old pump orig_pump.remove # Attach the new headered pumps new_pump.addToNode(plant_loop.supplyInletNode) return true end |
#plant_loop_set_chw_pri_sec_configuration(model) ⇒ String
Set configuration in model for chilled water primary/secondary loop interface Use heat_exchanger for stable baseline
669 670 671 672 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 669 def plant_loop_set_chw_pri_sec_configuration(model) pri_sec_config = 'heat_exchanger' return pri_sec_config end |
#run_all_orientations(run_all_orients, user_model) ⇒ Boolean
Check whether the baseline model generation needs to run all four orientations The default shall be true The orientation takes priority of:
-
Appx G
-
Method user input.
-
User data override.
2277 2278 2279 2280 2281 2282 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2277 def run_all_orientations(run_all_orients, user_model) run_orients_flag = false # Step 1 check orientation variations - priority 3 fenestration_area_hash = get_model_fenestration_area_by_orientation(user_model) fenestration_area_hash.each do |orientation, fenestration_area| OpenStudio.logFree(OpenStudio::Info, 'prm.log', "#{orientation} orientation has total fenestration area of #{fenestration_area} m2") fenestration_area_hash.each do |other_orientation, other_fenestration_area| next unless orientation != other_orientation variance = (other_fenestration_area - fenestration_area) / fenestration_area if variance.abs > 0.05 # if greater then 0.05 OpenStudio.logFree(OpenStudio::Info, 'prm.log', "#{orientation} has total fenestration area of #{fenestration_area} m2, which is higher than 5% variance compare to #{other_fenestration_area} at #{other_orientation}") run_orients_flag = true end end end # Step 2, assign method user input if it is provided as false. unless run_all_orients OpenStudio.logFree(OpenStudio::Error, 'prm.log', 'The run_all_orientation flag is set to False, update the run to a single orientation PRM generation.') run_orients_flag = run_all_orients end # Step 3 read user data - priority 1 - user data will override the priority 2 user_buildings = @standards_data.key?('userdata_building') ? @standards_data['userdata_building'] : nil if user_buildings building_name = user_model.building.get.name.get user_building_index = user_buildings.index { |user_building| building_name.include? user_building['name'] } unless user_building_index.nil? || user_buildings[user_building_index]['is_exempt_from_rotations'].nil? # user data exempt the rotation, No indicates true for running orients. OpenStudio.logFree(OpenStudio::Error, 'prm.log', "User data in the userdata_building.csv indicate building #{building_name} is exempted from rotation. Update the run to a single orientation PRM generation.") # @todo need to use user data enums later. run_orients_flag = user_buildings[user_building_index]['is_exempt_from_rotations'].casecmp('False') == 0 end end return run_orients_flag end |
#set_coil_cooling_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) ⇒ Hash
This function returns the cooling dx coil efficiency and curve coefficient in a Hashmap.
1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1074 def set_coil_cooling_efficiency_and_curves(cooling_coil, sql_db_vars_map, sys_type) if cooling_coil.to_CoilCoolingDXSingleSpeed.is_initialized # single speed coil sql_db_vars_map = coil_cooling_dx_single_speed_apply_efficiency_and_curves(cooling_coil.to_CoilCoolingDXSingleSpeed.get, sql_db_vars_map, sys_type) elsif cooling_coil.to_CoilCoolingDXTwoSpeed.is_initialized # two speed coil sql_db_vars_map = coil_cooling_dx_two_speed_apply_efficiency_and_curves(cooling_coil.to_CoilCoolingDXTwoSpeed.get, sql_db_vars_map, sys_type) else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "#{cooling_coil.name} is not single speed or two speed DX cooling coil. Nothing to be done for efficiency") end return sql_db_vars_map end |
#set_coil_heating_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) ⇒ Hash
This function returns the heating dx coil efficiency and curve coefficient in a Hashmap.
1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 1094 def set_coil_heating_efficiency_and_curves(heating_coil, sql_db_vars_map, sys_type) if heating_coil.to_CoilHeatingDXSingleSpeed.is_initialized # single speed coil sql_db_vars_map = coil_heating_dx_single_speed_apply_efficiency_and_curves(heating_coil.to_CoilHeatingDXSingleSpeed.get, sql_db_vars_map, sys_type) elsif heating_coil.to_CoilHeatingGas.is_initialized # single speed coil sql_db_vars_map = coil_heating_gas_apply_efficiency_and_curves(heating_coil.to_CoilHeatingGas.get, sql_db_vars_map, sys_type) else OpenStudio.logFree(OpenStudio::Warn, 'openstudio.standards.Model', "#{heating_coil.name} is not single speed DX heating coil. Nothing to be done for efficiency") end return sql_db_vars_map end |
#set_lpd_on_space_type(space_type, user_spaces, user_spacetypes) ⇒ Boolean
Function to test LPD on default space type. The function assigns lighting power density to an light object.
364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 364 def set_lpd_on_space_type(space_type, user_spaces, user_spacetypes) if has_multi_lpd_values_space_type(space_type) # If multiple LPD value exist - then enforce space-space_type one on one relationship space_to_space_type_apply_lighting(user_spaces, user_spacetypes, space_type) else # use default - loop through space to assign occupancy credit to each space. space_type_lighting_per_area = 0.0 space_type.spaces.each do |space| space_lighting_per_area = calculate_lpd_by_space(space_type, space) space_type_lighting_per_area = space_lighting_per_area end if space_type.hasAdditionalProperties && space_type.additionalProperties.hasFeature('regulated_lights_name') lights_name = space_type.additionalProperties.getFeatureAsString('regulated_lights_name').to_s lights_obj = space_type.model.getLightsByName(lights_name).get OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Setting lighting object #{lights_obj.name.get} lighting per area to #{space_type_lighting_per_area} W/ft^2") lights_obj.lightsDefinition.setWattsperSpaceFloorArea(OpenStudio.convert(space_type_lighting_per_area.to_f, 'W/ft^2', 'W/m^2').get) end end return true end |
#space_add_prm_computer_room_equipment_schedule(space) ⇒ Boolean
Create and assign PRM computer room electric equipment schedule
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Space.rb', line 115 def space_add_prm_computer_room_equipment_schedule(space) # Get proposed or baseline model model = space.model # Get space type associated with the space standard_space_type = prm_get_optional_handler(space, @sizing_run_dir, 'spaceType', 'standardsSpaceType').delete(' ').downcase # Check if the PRM computer room schedule is already in the model schedule_name = 'ASHRAE 90.1 Appendix G - Computer Room Equipment Schedule' schedule_found = model.getScheduleRulesetByName(schedule_name) # Create and assign the the electric equipment schedule if standard_space_type == 'computerroom' space.spaceType.get.electricEquipment.each do |elec_equipment| # Only create the schedule if it could not be found if schedule_found.is_initialized computer_room_equipment_schedule_ruleset = model.getScheduleRulesetByName(schedule_name).get else computer_room_equipment_schedule_ruleset = OpenStudio::Model::ScheduleRuleset.new(model) computer_room_equipment_schedule_ruleset.setName(schedule_name) schedule_fractions = [0.25, 0.5, 0.75, 1.0, 0.25, 0.5, 0.75, 1.0, 0.25, 0.5, 0.75, 1.0] # Weekdays and weekends schedules schedule_fractions.each_with_index do |frac, i| sch_rule = OpenStudio::Model::ScheduleRule.new(computer_room_equipment_schedule_ruleset) sch_rule.setStartDate(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(i.to_i + 1), 1)) # No leap year according to PRM-RM sch_rule.setEndDate(OpenStudio::Date.new(OpenStudio::MonthOfYear.new(i.to_i + 1), Date.new(2006, i.to_i + 1, -1).day)) day_sch = sch_rule.daySchedule day_sch.setName("#{schedule_name} - Month #{i + 1} - Fraction #{frac}") model_add_vals_to_sch(model, day_sch, 'Constant', [frac]) sch_rule.setApplyAllDays(true) end # Special days schedules equipment_on = OpenStudio::Model::ScheduleDay.new(model) model_add_vals_to_sch(model, equipment_on, 'Constant', [1]) equipment_off = OpenStudio::Model::ScheduleDay.new(model) model_add_vals_to_sch(model, equipment_off, 'Constant', [0]) computer_room_equipment_schedule_ruleset.setHolidaySchedule(equipment_on) computer_room_equipment_schedule_ruleset.setCustomDay1Schedule(equipment_on) computer_room_equipment_schedule_ruleset.setCustomDay2Schedule(equipment_on) computer_room_equipment_schedule_ruleset.setSummerDesignDaySchedule(equipment_on) computer_room_equipment_schedule_ruleset.setWinterDesignDaySchedule(equipment_off) end elec_equipment.setSchedule(computer_room_equipment_schedule_ruleset) end end return true end |
#space_apply_infiltration_rate(space, tot_infil_m3_per_s, infil_method, infil_coefficients) ⇒ Boolean
Set the infiltration rate for this space to include the impact of air leakage requirements in the standard.
13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Space.rb', line 13 def space_apply_infiltration_rate(space, tot_infil_m3_per_s, infil_method, infil_coefficients) # Calculate infiltration rate case infil_method.to_s when 'Flow/ExteriorWallArea' # Spread the total infiltration rate total_exterior_wall_area = 0 space.model.getSpaces.each do |spc| # Get the space conditioning type space_cond_type = space_conditioning_category(spc) total_exterior_wall_area += spc.exteriorWallArea * spc.multiplier unless space_cond_type == 'Unconditioned' end prm_raise(total_exterior_wall_area > 0, @sizing_run_dir, 'Total exterior wall area in the model is 0. Check your model inputs') adj_infil_flow_ext_wall_area = tot_infil_m3_per_s / total_exterior_wall_area OpenStudio.logFree(OpenStudio::Debug, 'prm.log', "For #{space.name}, adj infil = #{adj_infil_flow_ext_wall_area.round(8)} m^3/s*m^2 of above grade wall area.") when 'Flow/Area' # Spread the total infiltration rate total_floor_area = 0 space.model.getSpaces.each do |spc| # Get the space conditioning type space_cond_type = space_conditioning_category(spc) total_floor_area += spc.floorArea * spc.multipler unless space_cond_type == 'Unconditioned' || space.exteriorArea == 0 end prm_raise(total_floor_area > 0, @sizing_run_dir, 'Sum of the floor area in exterior spaces in the model is 0. Check your model inputs') adj_infil_flow_area = tot_infil_m3_per_s / total_floor_area OpenStudio.logFree(OpenStudio::Debug, 'prm.log', "For #{space.name}, adj infil = #{adj_infil_flow_area.round(8)} m^3/s*m^2 of space floor area.") end # Get any infiltration schedule already assigned to this space or its space type # If not, the always on schedule will be applied. # @todo Infiltration schedules should be based on HVAC operation infil_sch = nil unless space.spaceInfiltrationDesignFlowRates.empty? old_infil = space.spaceInfiltrationDesignFlowRates[0] if old_infil.schedule.is_initialized infil_sch = old_infil.schedule.get end end if infil_sch.nil? && space.spaceType.is_initialized space_type = space.spaceType.get unless space_type.spaceInfiltrationDesignFlowRates.empty? old_infil = space_type.spaceInfiltrationDesignFlowRates[0] if old_infil.schedule.is_initialized infil_sch = old_infil.schedule.get end end end if infil_sch.nil? infil_sch = space.model.alwaysOnDiscreteSchedule else # Add specific schedule type object to insure compatibility with the OpenStudio infiltration object infil_sch_limit_type = OpenstudioStandards::Schedules.create_schedule_type_limits(space.model, name: 'Infiltration Schedule Type Limits', lower_limit_value: 0.0, upper_limit_value: 1.0, numeric_type: 'Continuous', unit_type: 'Dimensionless') infil_sch.setScheduleTypeLimits(infil_sch_limit_type) end # Remove all pre-existing space infiltration objects space.spaceInfiltrationDesignFlowRates.each(&:remove) # Get the space conditioning type space_cond_type = space_conditioning_category(space) if space_cond_type != 'Unconditioned' # Create an infiltration rate object for this space infiltration = OpenStudio::Model::SpaceInfiltrationDesignFlowRate.new(space.model) infiltration.setName("#{space.name} Infiltration") case infil_method.to_s when 'Flow/ExteriorWallArea' infiltration.setFlowperExteriorWallArea(adj_infil_flow_ext_wall_area.round(13)) if space.exteriorWallArea > 0 when 'Flow/Area' infiltration.setFlowperSpaceFloorArea(adj_infil_flow_area.round(13)) if space.exteriorArea > 0 end infiltration.setSchedule(infil_sch) infiltration.setConstantTermCoefficient(infil_coefficients[0]) infiltration.setTemperatureTermCoefficient(infil_coefficients[1]) infiltration.setVelocityTermCoefficient(infil_coefficients[2]) infiltration.setVelocitySquaredTermCoefficient(infil_coefficients[3]) infiltration.setSpace(space) end return true end |
#space_set_baseline_daylighting_controls(space, remove_existing = false, draw_areas_for_debug = false) ⇒ Boolean
For stable baseline, remove all daylighting controls (sidelighting and toplighting)
106 107 108 109 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Space.rb', line 106 def space_set_baseline_daylighting_controls(space, remove_existing = false, draw_areas_for_debug = false) removed = space_remove_daylighting_controls(space) return removed end |
#space_to_space_type_apply_lighting(user_spaces, user_spacetypes, space_type) ⇒ ArrayOpenStudio::Model::Space
Function that applies user LPD to each space by duplicating space types This function is used when there are user space data available or the spaces under space type has lighting per length value which may cause multiple lighting power densities under one space_type.
393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 393 def space_to_space_type_apply_lighting(user_spaces, user_spacetypes, space_type) space_lighting_per_area_hash = {} # first priority - user_space data if user_spaces && user_spaces.length >= 1 space_type.spaces.each do |space| user_space_index = user_spaces.index { |user_space| user_space['name'] == space.name.get } unless user_space_index.nil? user_space_data = user_spaces[user_space_index] if user_space_data.key?('num_std_ltg_types') && user_space_data['num_std_ltg_types'].to_f > 0 space_lighting_per_area = calculate_lpd_from_userdata(user_space_data, space) space_lighting_per_area_hash[space.name.get] = space_lighting_per_area end end end end # second priority - user_spacetype if user_spacetypes && user_spacetypes.length >= 1 # if space type has user data user_space_type_index = user_spacetypes.index { |user_spacetype| user_spacetype['name'] == space_type.name.get } unless user_space_type_index.nil? user_space_type_data = user_spacetypes[user_space_type_index] if user_space_type_data.key?('num_std_ltg_types') && user_space_type_data['num_std_ltg_types'].to_f > 0 space_type.spaces.each do |space| # unless the space is in the hash, we will add lighting per area to the space space_name = space.name.get unless space_lighting_per_area_hash.key?(space_name) space_lighting_per_area = calculate_lpd_from_userdata(user_space_type_data, space) space_lighting_per_area_hash[space_name] = space_lighting_per_area end end end end end # Third priority # set space type to every space in the space_type, third priority # will also be assigned from the default space type space_type.spaces.each do |space| space_name = space.name.get unless space_lighting_per_area_hash.key?(space_name) space_lighting_per_area = calculate_lpd_by_space(space_type, space) space_lighting_per_area_hash[space_name] = space_lighting_per_area end end # All space is explored. # Now rewrite the space type in each space - might need to change the logic space_array = [] space_type.spaces.each do |space| space_name = space.name.get new_space_type = space_type.clone.to_SpaceType.get space.setSpaceType(new_space_type) lighting_per_area = space_lighting_per_area_hash[space_name] new_space_type.lights.each do |inst| lights_name = inst.name.get new_space_type.additionalProperties.setFeature('regulated_lights_name', lights_name) definition = inst.lightsDefinition unless lighting_per_area.zero? new_definition = definition.clone.to_LightsDefinition.get new_definition.setWattsperSpaceFloorArea(OpenStudio.convert(lighting_per_area.to_f, 'W/ft^2', 'W/m^2').get) inst.setLightsDefinition(new_definition) OpenStudio.logFree(OpenStudio::Info, 'log.prm', "#{space_type.name} set LPD to #{lighting_per_area} W/ft^2.") end end space_array.push(space) end return space_array end |
#space_to_space_type_apply_power_equipment(user_spacetypes, user_spaces, space_array) ⇒ Boolean
Apply space to space type power equipment adjustment. NOTE! this function shall only be used if the space to space type is one to one relationship. This function can process both electric equipment and gas equipment and this function will process user data from electric equipment and gas equipment user data
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 221 def space_to_space_type_apply_power_equipment(user_spacetypes, user_spaces, space_array) # Step 1: Set electric / gas equipment # save schedules in a hash in case it is needed for new electric equipment power_schedule_hash = {} # check if electric equipment data is available. user_electric_equipment_data = @standards_data.key?('userdata_electric_equipment') ? @standards_data['userdata_electric_equipment'] : nil user_gas_equipment_data = @standards_data.key?('userdata_gas_equipment') ? @standards_data['userdata_gas_equipment'] : nil if user_electric_equipment_data && user_electric_equipment_data.length >= 1 space_array.each do |space| # Each space has a unique space type space_type = space.spaceType.get user_spacestypes_index = user_spacetypes.index { |user_spacetype| /#{user_spacetype['name']}/i =~ space_type.name.get } user_space_index = user_spaces.index { |user_space| user_space['name'] == space.name.get } # Initialize with standard space_type user_space_data = space_type.name.get unless user_spacestypes_index.nil? # override with user space type if specified user_space_data = user_spacetypes[user_spacestypes_index] end unless user_space_index.nil? # override with user space if specified user_space_data = user_spaces[user_space_index] end space_type_electric_equipments = space_type.electricEquipment space_type_electric_equipments.each do |sp_electric_equipment| electric_equipment_name = sp_electric_equipment.name.get select_user_electric_equipment_array = user_electric_equipment_data.select { |elec| /#{elec['name']}/i =~ electric_equipment_name } unless select_user_electric_equipment_array.empty? select_user_electric_equipment = select_user_electric_equipment_array[0] calculate_electric_value_by_userdata(select_user_electric_equipment, sp_electric_equipment, power_schedule_hash, space_type, user_space_data) end end end elsif user_gas_equipment_data && user_gas_equipment_data.length >= 1 space_array.each do |space| space_type = space.spaceType.get user_spacestypes_index = user_spacetypes.index { |user_spacetype| user_spacetype['name'] == space_type.name.get } user_space_index = user_spaces.index { |user_space| user_space['name'] == space.name.get } user_space_data = space_type.name.get unless user_spacestypes_index.nil? user_space_data = user_spacetypes[user_spacestypes_index] end unless user_space_index.nil? user_space_data = user_spaces[user_space_index] end space_type_gas_equipments = space_type.gasEquipment space_type_gas_equipments.each do |sp_gas_equipment| gas_equipment_name = sp_gas_equipment.name.get select_user_gas_equipment_array = user_gas_equipment_data.select { |gas| gas['name'].casecmp(gas_equipment_name) == 0 } unless select_user_gas_equipment_array.empty? select_user_gas_equipment = select_user_gas_equipment_array[0] # Update the gas equipment occupancy credit (if it has) update_power_equipment_credits(sp_gas_equipment, select_user_gas_equipment, power_schedule_hash, space_type.model, user_space_data) end end end end return true end |
#space_type_apply_internal_loads(space_type, set_people, set_lights, set_electric_equipment, set_gas_equipment, set_ventilation, set_infiltration) ⇒ Boolean
Sets the selected internal loads to standards-based or typical values. For each category that is selected get all load instances. Remove all but the first instance if multiple instances. Add a new instance/definition if no instance exists. Modify the definition for the remaining instance to have the specified values. This method does not alter any loads directly assigned to spaces. This method skips plenums.
22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 22 def space_type_apply_internal_loads(space_type, set_people, set_lights, set_electric_equipment, set_gas_equipment, set_ventilation, set_infiltration) # Skip plenums # Check if the space type name # contains the word plenum. if space_type.name.get.to_s.downcase.include?('plenum') return false end if space_type.standardsSpaceType.is_initialized && space_type.standardsSpaceType.get.downcase.include?('plenum') return false end # Save information about lighting exceptions before removing extra lights objects # First get list of all lights objects that are exempt regulated_lights = [] unregulated_lights = [] user_lights = @standards_data.key?('userdata_lights') ? @standards_data['userdata_lights'] : nil if user_lights && user_lights.length >= 1 user_lights.each do |user_data| lights_name = user_data['name'] lights_obj = space_type.model.getLightsByName(lights_name).get if user_data['has_retail_display_exception'].to_s.downcase == 'yes' || user_data['has_unregulated_exception'].to_s.downcase == 'yes' # If either exception is applicable # Put this one on the unregulated list unregulated_lights.push(lights_name) end end end # Get all lights objects that are not exempt space_type.lights.sort.each do |lights_obj| lights_name = lights_obj.name.get if !unregulated_lights.include? lights_name regulated_lights << lights_obj end end # Pre-process the light instances in the space type # Remove all regulated instances but leave one in the space type if regulated_lights.empty? definition = OpenStudio::Model::LightsDefinition.new(space_type.model) definition.setName("#{space_type.name} Lights Definition") instance = OpenStudio::Model::Lights.new(definition) lights_name = "#{space_type.name} Lights" instance.setName(lights_name) instance.setSpaceType(space_type) OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.SpaceType', "#{space_type.name} had no lights, one has been created.") space_type.additionalProperties.setFeature('regulated_lights_name', lights_name) regulated_lights << instance else regulated_lights.each_with_index do |inst, i| if i.zero? # Save the name of the first instance to use as the baseline lights object lights_name = inst.name.get space_type.additionalProperties.setFeature('regulated_lights_name', lights_name) next end # Remove all other lights objects that have not been identified as unregulated if i == 1 ref_name = space_type.additionalProperties.getFeatureAsString('regulated_lights_name').to_s OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Multiple lights objects found in user model for #{space_type.name}. Baseline schedule will be determined from #{ref_name}") end OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Removed lighting object #{inst.name} from #{space_type.name}. ") inst.remove end end # Get userdata from userdata_space and userdata_spacetype user_spaces = @standards_data.key?('userdata_space') ? @standards_data['userdata_space'] : nil user_spacetypes = @standards_data.key?('userdata_spacetype') ? @standards_data['userdata_spacetype'] : nil if user_spaces && user_spaces.length >= 1 && has_user_lpd_values(user_spaces) # if space type has user data & data has lighting data for user space # call this function to enforce space-space_type one on one relationship new_space_array = space_to_space_type_apply_lighting(user_spaces, user_spacetypes, space_type) # process power equipment with new spaces. space_to_space_type_apply_power_equipment(user_spacetypes, user_spaces, new_space_array) # remove the old space space_type.remove else if user_spacetypes && user_spacetypes.length >= 1 && has_user_lpd_values(user_spacetypes) # if space type has user data & data has lighting data for user space type user_space_type_index = user_spacetypes.index { |user_spacetype| user_spacetype['name'] == space_type.name.get } if user_space_type_index.nil? # cannot find a matched user_spacetype to space_type, use space_type to set LPD set_lpd_on_space_type(space_type, user_spaces, user_spacetypes) space_type_apply_power_equipment(space_type) else user_space_type = user_spacetypes[user_space_type_index] # If multiple LPD value exist - then enforce space-space_type one on one relationship if has_multi_lpd_values_user_data(user_space_type, space_type) new_space_array = space_to_space_type_apply_lighting(user_spaces, user_spacetypes, space_type) space_to_space_type_apply_power_equipment(user_spacetypes, user_spaces, new_space_array) space_type.remove else # Process the user_space type data - at this point, we are sure there is no lighting per length # So all the LPD should be identical by space # Loop because we need to assign the occupancy control credit to each space for # Schedule processing. space_type_lighting_per_area = 0.0 space_type.spaces.each do |space| space_lighting_per_area = calculate_lpd_from_userdata(user_space_type, space) space_type_lighting_per_area = space_lighting_per_area end if space_type.hasAdditionalProperties && space_type.additionalProperties.hasFeature('regulated_lights_name') lights_name = space_type.additionalProperties.getFeatureAsString('regulated_lights_name').to_s lights_obj = space_type.model.getLightsByName(lights_name).get lights_obj.lightsDefinition.setWattsperSpaceFloorArea(OpenStudio.convert(space_type_lighting_per_area.to_f, 'W/ft^2', 'W/m^2').get) end end # process power equipment space_type_apply_power_equipment(space_type) end else # no user data, set space_type LPD set_lpd_on_space_type(space_type, user_spaces, user_spacetypes) # process power equipment space_type_apply_power_equipment(space_type) end end end |
#space_type_apply_power_equipment(space_type) ⇒ Boolean
Apply power equipment to space type This is utility function for applying user data to space type
181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 181 def space_type_apply_power_equipment(space_type) # save schedules in a hash in case it is needed for new electric equipment power_schedule_hash = {} # @todo move this part to user data processing user_electric_equipment_data = @standards_data.key?('userdata_electric_equipment') ? @standards_data['userdata_electric_equipment'] : nil user_gas_equipment_data = @standards_data.key?('userdata_gas_equipment') ? @standards_data['userdata_gas_equipment'] : nil if user_electric_equipment_data && user_electric_equipment_data.length >= 1 space_type_electric_equipments = space_type.electricEquipment space_type_electric_equipments.each do |sp_electric_equipment| electric_equipment_name = sp_electric_equipment.name.get select_user_electric_equipment_array = user_electric_equipment_data.select { |elec| elec['name'].casecmp(electric_equipment_name) == 0 } unless select_user_electric_equipment_array.empty? select_user_electric_equipment = select_user_electric_equipment_array[0] calculate_electric_value_by_userdata(select_user_electric_equipment, sp_electric_equipment, power_schedule_hash, space_type, nil) end end elsif user_gas_equipment_data && user_gas_equipment_data.length >= 1 space_type_gas_equipments = space_type.gasEquipment space_type_gas_equipments.each do |sp_gas_equipment| gas_equipment_name = sp_gas_equipment.name.get select_user_gas_equipment_array = user_gas_equipment_data.select { |gas| gas['name'].casecmp(gas_equipment_name) == 0 } unless select_user_gas_equipment_array.empty? select_user_gas_equipment = select_user_gas_equipment_array[0] # Update the gas equipment occupancy credit (if it has) update_power_equipment_credits(sp_gas_equipment, select_user_gas_equipment, power_schedule_hash, space_type.model, nil) end end end return true end |
#space_type_light_sch_change(model) ⇒ Object
Modify the lighting schedules for Appendix G PRM for 2016 and later
463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 463 def space_type_light_sch_change(model) # set schedule for lighting schedule_hash = {} model.getSpaces.each do |space| space_type = prm_get_optional_handler(space, @sizing_run_dir, 'spaceType') if space_type.hasAdditionalProperties && space_type.additionalProperties.hasFeature('regulated_lights_name') lights_name = space_type.additionalProperties.getFeatureAsString('regulated_lights_name').to_s ltg_option = space_type.model.getLightsByName(lights_name) if ltg_option.is_initialized ltg = ltg_option.get else # raise exception if we cannot find the lights in the model prm_raise(false, @sizing_run_dir, "Cannot find the lights #{lights_name} in the model") end # this will raise exception if the ltg has no schedule assigned. if ltg.schedule.is_initialized ltg_schedule = ltg.schedule.get else # case such as Attic may have light object but no light schedule assigned # Eplus use default 0 so in here we raise Error but continue processing. ltg_schedule = nil OpenStudio.logFree(OpenStudio::Warn, 'prm.log', "schedule is not available in component #{ltg.name.get}. Skip processing") end if ltg_schedule ltg_schedule_name = ltg_schedule.name.get occupancy_sensor_credit = get_additional_property_as_double(space, 'occ_control_credit', 0.0) if schedule_hash.key?(ltg_schedule_name) # In this case, there is a schedule created, can retrieve the schedule object and reset in this space type schedule_rule = schedule_hash[ltg_schedule_name] ltg.setSchedule(schedule_rule) else # In this case, create a new schedule # 1. Clone the existing schedule new_ltg_schedule_name = format("#{ltg_schedule_name}_%.4f", occupancy_sensor_credit) new_rule_set_schedule = deep_copy_schedule(new_ltg_schedule_name, ltg_schedule, occupancy_sensor_credit, model) if ltg.setSchedule(new_rule_set_schedule) schedule_hash[new_ltg_schedule_name] = new_rule_set_schedule end end end end end end |
#stage_chilled_water_loop_operation_schemes(model, chilled_water_loop) ⇒ Object
Updates a chilled water plant’s operation scheme to match the EMS written by either add_ems_program_for_3_pump_chiller_plant or add_ems_program_for_2_pump_chiller_plant
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.PlantLoop.rb', line 323 def stage_chilled_water_loop_operation_schemes(model, chilled_water_loop) # Initialize array of cooling plant systems chillers = [] # Gets all associated chillers from the supply side and adds them to the chillers list chilled_water_loop.supplyComponents(OpenStudio::Model::ChillerElectricEIR.iddObjectType).each do |chiller| chillers << chiller.to_ChillerElectricEIR.get end # Skip those without chillers or only 1 (i.e., nothing to stage) return if chillers.empty? return if chillers.length == 1 # Sort chillers by capacity sorted_chillers = chillers.sort_by { |chiller| chiller.referenceCapacity.get } primary_chiller = sorted_chillers[0] secondary_1_chiller = sorted_chillers[1] secondary_2_chiller = sorted_chillers[2] if chillers.length == 3 equip_operation_cool_load = OpenStudio::Model::PlantEquipmentOperationCoolingLoad.new(model) # Calculate load ranges into the PlantEquipmentOperation:CoolingLoad loading_factor = 0.8 # # when the capacity of primary chiller is larger than the capacity of secondary chiller - the loading factor # # will need to be adjusted to avoid load range intersect. # if secondary_1_chiller.referenceCapacity.get <= primary_chiller.referenceCapacity.get * loading_factor # # Adjustment_factor can creates a bandwidth for step 2 staging strategy. # # set adjustment_factor = 1.0 means the step 2 staging strategy is skipped # adjustment_factor = 1.0 # loading_factor = secondary_1_chiller.referenceCapacity.get / primary_chiller.referenceCapacity.get * adjustment_factor # end if chillers.length == 3 # Add four ranges for small, medium, and large chiller capacities # 1: 0 W -> 80% of smallest chiller capacity # 2: 80% of primary chiller -> medium size chiller capacity # 3: medium chiller capacity -> medium + large chiller capacity # 4: medium + large chiller capacity -> infinity # Control strategy first stage equipment_list = [primary_chiller] range = primary_chiller.referenceCapacity.get * loading_factor equip_operation_cool_load.addLoadRange(range, equipment_list) # Control strategy second stage equipment_list = [secondary_1_chiller] range = secondary_1_chiller.referenceCapacity.get equip_operation_cool_load.addLoadRange(range, equipment_list) # Control strategy third stage equipment_list = [secondary_1_chiller, secondary_2_chiller] range = secondary_1_chiller.referenceCapacity.get + secondary_2_chiller.referenceCapacity.get equip_operation_cool_load.addLoadRange(range, equipment_list) equipment_list = [primary_chiller, secondary_1_chiller, secondary_2_chiller] range = 999999999 equip_operation_cool_load.addLoadRange(range, equipment_list) elsif chillers.length == 2 # Add three ranges for primary and secondary chiller capacities # 1: 0 W -> 80% of smallest chiller capacity # 2: 80% of primary chiller -> secondary chiller capacity # 3: secondary chiller capacity -> infinity # Control strategy first stage equipment_list = [primary_chiller] range = primary_chiller.referenceCapacity.get * loading_factor equip_operation_cool_load.addLoadRange(range, equipment_list) # Control strategy second stage equipment_list = [secondary_1_chiller] range = secondary_1_chiller.referenceCapacity.get equip_operation_cool_load.addLoadRange(range, equipment_list) # Control strategy third stage equipment_list = [primary_chiller, secondary_1_chiller] range = 999999999 equip_operation_cool_load.addLoadRange(range, equipment_list) else raise "Failed to stage chillers, #{chillers.length} chillers found in the loop.Logic for staging chillers has only been done for either 2 or 3 chillers" end chilled_water_loop.setPlantEquipmentOperationCoolingLoad(equip_operation_cool_load) end |
#surface_adjust_fenestration_in_a_surface(surface, reduction, model) ⇒ Boolean
Adjust the fenestration area to the values specified by the reduction value in a surface
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Surface.rb', line 8 def surface_adjust_fenestration_in_a_surface(surface, reduction, model) # do nothing for cases when reduction == 1.0 if reduction < 1.0 surface.subSurfaces.each do |ss| next unless ss.subSurfaceType == 'FixedWindow' || ss.subSurfaceType == 'OperableWindow' || ss.subSurfaceType == 'GlassDoor' OpenstudioStandards::Geometry.sub_surface_reduce_area_by_percent_by_shrinking_toward_centroid(ss, reduction) end elsif reduction > 1.0 # case increase the window surface_wwr = OpenstudioStandards::Geometry.surface_get_window_to_wall_ratio(surface) if surface_wwr < 0.0001 # In this case, we are adding fenestration wwr_adjusted = reduction - 1.0 # add the value to additional properties in case of readjusting WWR for doors surface.additionalProperties.setFeature('added_wwr', wwr_adjusted) else wwr_adjusted = surface_wwr * reduction end # Save doors to a temp list door_list = [] surface.subSurfaces.each do |sub| if sub.subSurfaceType == 'Door' door = {} door['name'] = sub.name.get door['vertices'] = sub.vertices door['construction'] = sub.construction.get door_list << door end end # remove all existing windows and set the window to wall ratio to the calculated new WWR # Remove all sub-surfaces including doors surface.subSurfaces.each(&:remove) # Apply default construction to the subsurface - the standard construction will be applied later. surface.setWindowToWallRatio(wwr_adjusted, 0.6, true) # add door back. unless door_list.empty? door_list.each do |door| os_door = OpenStudio::Model::SubSurface.new(door['vertices'], model) os_door.setName(door['name']) os_door.setConstruction(door['construction']) os_door.setSurface(surface) end end end end |
#surface_get_wwr_reduction_ratio(multiplier, surface, wwr_building_type: 'All others', wwr_target: nil, total_wall_m2: 0.0, total_wall_with_fene_m2: 0.0, total_fene_m2: 0.0, total_plenum_wall_m2: 0.0) ⇒ Double
Calculate the window to wall ratio reduction factor
2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 2468 def surface_get_wwr_reduction_ratio(multiplier, surface, wwr_building_type: 'All others', wwr_target: nil, total_wall_m2: 0.0, # prevent 0.0 division total_wall_with_fene_m2: 0.0, total_fene_m2: 0.0, total_plenum_wall_m2: 0.0) surface_name = surface.name.get surface_wwr = OpenstudioStandards::Geometry.surface_get_window_to_wall_ratio(surface) surface_dr = OpenstudioStandards::Geometry.surface_get_door_to_wall_ratio(surface) if multiplier < 1.0 # Case when reduction is required reduction_ratio = 1.0 - multiplier OpenStudio.logFree(OpenStudio::Info, 'prm.log', "Surface #{surface_name} WWR is #{surface_wwr}. Reduce its WWR to #{surface_wwr * reduction_ratio}%") else # Case when increase is required - takes the door area into consideration. # The target is to increase each surface to maximum 90% WWR deduct the total door area. exist_max_wwr = 0.0 if total_wall_m2 > 0 then exist_max_wwr = total_wall_with_fene_m2 * 0.9 / total_wall_m2 end if exist_max_wwr < wwr_target # In this case, it is required to add vertical fenestration to other surfaces if surface_wwr < 0.001 # delta_fenestration_surface_area / delta_wall_surface_area + 1.0 = increase_ratio for a surface with no windows. # ASSUMPTION!! assume adding windows to surface with no windows will never be window_m2 + door_m2 > surface_m2. reduction_ratio = ((wwr_target - exist_max_wwr) * total_wall_m2 / (total_wall_m2 - total_wall_with_fene_m2 - total_plenum_wall_m2)) + 1.0 OpenStudio.logFree(OpenStudio::Info, 'prm.log', "The max window to wall ratio is #{exist_max_wwr}, smaller than the target window to wall ratio #{wwr_target}. Surface #{surface_name} has no fenestration subsurfaces. Adding new fenestration band with WWR of #{(reduction_ratio - 1) * 100}%") else # surface has fenestration - expand it to 90% WWR or surface area minus door area, whichever is smaller. if (1.0 - surface_dr) < 0.9 # A negative reduction ratio as a flat to main function that this reduction ratio is adjusted by doors # and it is needed to adjust the WWR of the no fenestration surfaces to meet the lost reduction_ratio = (surface_dr - 1.0) / surface_wwr else reduction_ratio = 0.9 / surface_wwr end OpenStudio.logFree(OpenStudio::Info, 'prm.log', "The max window to wall ratio is #{exist_max_wwr}, smaller than the target window to wall ratio #{wwr_target}. Surface #{surface_name} will expand its WWR to 90%") end else # multiplier will be negative number thus resulting in > 1 reduction_ratio if surface_wwr < 0.001 # 1.0 means remain the original form reduction_ratio = 1.0 else reduction_ratio = multiplier end end end return reduction_ratio end |
#thermal_zone_get_fan_power_limitations(thermal_zone, is_energy_recovery_required) ⇒ Object
Determine the fan power limitation pressure drop adjustment Per Table 6.5.3.1-2 (90.1-2019)
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ThermalZone.rb', line 8 def thermal_zone_get_fan_power_limitations(thermal_zone, is_energy_recovery_required) fan_pwr_adjustment_in_wc = 0 # error if zone design air flow rate is not available if thermal_zone.model.version < OpenStudio::VersionString.new('3.6.0') OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.ThermalZone', 'Required ThermalZone method .autosizedDesignAirFlowRate is not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.') end # Get autosized zone design supply air flow rate dsn_zone_air_flow_m3_per_s = thermal_zone.autosizedDesignAirFlowRate.to_f dsn_zone_air_flow_cfm = OpenStudio.convert(dsn_zone_air_flow_m3_per_s, 'm^3/s', 'cfm').get # Retrieve credits from zone additional features # Fully ducted return and/or exhaust air systems if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_fully_ducted') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_fully_ducted').to_f adj_in_wc = 0.5 * mult fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for fully ducted return and/or exhaust air systems") end # Return and/or exhaust airflow control devices if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_return_or_exhaust_flow_control') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_return_or_exhaust_flow_control').to_f adj_in_wc = 0.5 * mult fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for return and/or exhaust airflow control devices") end # Exhaust filters, scrubbers, or other exhaust treatment if thermal_zone.additionalProperties.hasFeature('fan_power_credit_exhaust_treatment') adj_in_wc = thermal_zone.additionalProperties.getFeatureAsDouble('fan_power_credit_exhaust_treatment').to_f fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for exhaust filters, scrubbers, or other exhaust treatment") end # MERV 9 through 12 if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_filtration_m9to12') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_filtration_m9to12').to_f adj_in_wc = 0.5 * mult fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for particulate Filtration Credit: MERV 9 through 12") end # MERV 13 through 15 if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_filtration_m13to15') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_filtration_m13to15').to_f adj_in_wc = 0.9 * mult fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for particulate Filtration Credit: MERV 13 through 15") end # MERV 16 and greater and electronically enhanced filters if thermal_zone.additionalProperties.hasFeature('clean_filter_pressure_drop_for_fan_power_credit_filtration_m16plus') adj_in_wc = thermal_zone.additionalProperties.getFeatureAsDouble('clean_filter_pressure_drop_for_fan_power_credit_filtration_m16plus').to_f fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for particulate Filtration Credit: MERV 16 and greater and electronically enhanced filters") end # Carbon and other gas-phase air cleaners if thermal_zone.additionalProperties.hasFeature('fan_power_credit_gas_phase_cleaners') adj_in_wc = thermal_zone.additionalProperties.getFeatureAsDouble('fan_power_credit_gas_phase_cleaners').to_f fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for carbon and other gas-phase air cleaners") end # Biosafety cabinet if thermal_zone.additionalProperties.hasFeature('fan_power_credit_biosafety') adj_in_wc = thermal_zone.additionalProperties.getFeatureAsDouble('fan_power_credit_biosafety').to_f fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for biosafety cabinet") end # Energy recovery device, other than coil runaround loop if thermal_zone.additionalProperties.hasFeature('fan_power_credit_other_than_coil_runaround') && is_energy_recovery_required adj_in_wc = thermal_zone.additionalProperties.getFeatureAsDouble('fan_power_credit_other_than_coil_runaround').to_f fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for energy recovery device other than coil runaround loop") end # Coil runaround loop if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_coil_runaround') && is_energy_recovery_required mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_coil_runaround').to_f adj_in_wc = 0.6 * 2 * mult # for each stream fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for coil runaround loop") end # Evaporative humidifier/cooler in series with another cooling coil if thermal_zone.additionalProperties.hasFeature('fan_power_credit_evaporative_humidifier_or_cooler') OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', '--Added 0 in wc for evaporative humidifier/cooler in series with another coil as per Table G3.1.2.9 Note 2') end # Sound attenuation section (fans serving spoaces with design background noise goals below NC35) if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_sound_attenuation') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_sound_attenuation').to_f adj_in_wc = 0.15 * mult fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for sound attenuation section") end # Exhaust system serving fume hoods if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_exhaust_serving_fume_hoods') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_exhaust_serving_fume_hoods').to_f adj_in_wc = 0.35 * mult fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for exhaust system serving fume hoods") end # Laboratory and vivarium exhaust systems in high-rise buildings if thermal_zone.additionalProperties.hasFeature('has_fan_power_credit_lab_or_vivarium_highrise_vertical_duct') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_credit_lab_or_vivarium_highrise_vertical_duct').to_f adj_in_wc = 0.35 * mult fan_pwr_adjustment_in_wc += adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Added #{adj_in_wc} in wc for laboratory and vivarium exhaust systems in high-rise buildings") end # Deductions # Systems without central cooling device if thermal_zone.additionalProperties.hasFeature('has_fan_power_deduction_system_without_central_cooling_device') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_deduction_system_without_central_cooling_device').to_f adj_in_wc = 0.60 * mult fan_pwr_adjustment_in_wc -= adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Removed #{adj_in_wc} in wc for system without central cooling device") end # Systems without central heating device if thermal_zone.additionalProperties.hasFeature('has_fan_power_deduction_system_without_central_heating_device') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_deduction_system_without_central_heating_device').to_f adj_in_wc = 0.30 * mult fan_pwr_adjustment_in_wc -= adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Removed #{adj_in_wc} in wc for system without central heating device") end # Systems with central electric resistance heat if thermal_zone.additionalProperties.hasFeature('has_fan_power_deduction_system_with_central_electric_resistance_heat') mult = thermal_zone.additionalProperties.getFeatureAsDouble('has_fan_power_deduction_system_with_central_electric_resistance_heat').to_f adj_in_wc = 0.20 * mult fan_pwr_adjustment_in_wc -= adj_in_wc OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "--Removed #{adj_in_wc} in wc for system with central electric resistance heat") end # Convert the pressure drop adjustment to brake horsepower (bhp) # assuming that all supply air passes through all devices return fan_pwr_adjustment_in_wc * dsn_zone_air_flow_cfm / 4131 end |
#thermal_zone_get_zone_fuels_for_occ_and_fuel_type(thermal_zone) ⇒ String with applicable DistrictHeating and/or DistrictCooling
Identify if zone has district energy for occ_and_fuel_type method
158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ThermalZone.rb', line 158 def thermal_zone_get_zone_fuels_for_occ_and_fuel_type(thermal_zone) zone_fuels = '' # error if HVACComponent heating fuels method is not available if thermal_zone.model.version < OpenStudio::VersionString.new('3.6.0') OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.ThermalZone', 'Required HVACComponent methods .heatingFuelTypes and .coolingFuelTypes are not available in pre-OpenStudio 3.6.0 versions. Use a more recent version of OpenStudio.') end htg_fuels = thermal_zone.heatingFuelTypes.map(&:valueName) if htg_fuels.include?('DistrictHeating') zone_fuels = 'DistrictHeating' end clg_fuels = thermal_zone.coolingFuelTypes.map(&:valueName) if clg_fuels.include?('DistrictCooling') zone_fuels += 'DistrictCooling' end return zone_fuels end |
#thermal_zone_prm_lab_delta_t(thermal_zone) ⇒ Double
Specify supply to room delta for laboratory spaces based on 90.1 Appendix G Exception to G3.1.2.8.1
944 945 946 947 948 949 950 951 952 953 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 944 def thermal_zone_prm_lab_delta_t(thermal_zone) # For labs, add 17 delta-T; otherwise, add 20 delta-T thermal_zone.spaces.each do |space| space_std_type = space.spaceType.get.standardsSpaceType.get if space_std_type == 'laboratory' return 17 end end return nil end |
#thermal_zone_prm_unitheater_design_supply_temperature(thermal_zone) ⇒ Double
Specify supply air temperature setpoint for unit heaters based on 90.1 Appendix G G3.1.2.8.2
931 932 933 934 935 936 937 938 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.Model.rb', line 931 def thermal_zone_prm_unitheater_design_supply_temperature(thermal_zone) thermal_zone.equipment.each do |eqt| if eqt.to_ZoneHVACUnitHeater.is_initialized return OpenStudio.convert(105, 'F', 'C').get end end return nil end |
#update_power_equipment_credits(power_equipment, user_power_equipment, schedule_hash, space_type, user_data = nil) ⇒ Boolean
Function update a power equipment schedule based on user data. This function works with both electric equipment and gas equipment and applies the ruleset on power equipment The function process user data including the fraction of controlled receptacles and receptacle power savings.
291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.SpaceType.rb', line 291 def update_power_equipment_credits(power_equipment, user_power_equipment, schedule_hash, space_type, user_data = nil) exception_list = ['office - enclosed <= 250 sf', 'conference/meeting/multipurpose', 'copy/print', 'lounge/breakroom - all other', 'lounge/breakroom - healthcare facility', 'classroom/lecture/training - all other', 'classroom/lecture/training - preschool to 12th', 'office - open'] receptacle_power_credits = 0.0 # Check fraction_of_controlled_receptacles or receptacle_power_savings exist if user_power_equipment.key?('fraction_of_controlled_receptacles') && !user_power_equipment['fraction_of_controlled_receptacles'].nil? rc = user_power_equipment['fraction_of_controlled_receptacles'].to_f # receptacle power credits = percent of all controlled receptacles * 10% receptacle_power_credits = rc * 0.1 elsif user_power_equipment.key?('receptacle_power_savings') && !user_power_equipment['receptacle_power_savings'].nil? receptacle_power_credits = user_power_equipment['receptacle_power_savings'].to_f OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.ElectricEquipment', "#{power_equipment.name.get} has a user specified receptacle power saving credit #{receptacle_power_credits}. The modeler needs to make sure the credit is approved by a rating authority per Table G3.1 section 12.") end # process user space data if user_data.is_a?(Hash) if user_data.key?('num_std_ltg_types') && user_data['num_std_ltg_types'].to_f > 0 adjusted_receptacle_power_credits = 0.0 num_std_space_types = user_data['num_std_ltg_types'].to_i std_space_index = 0 # loop index # Loop through standard lighting type in a space while std_space_index < num_std_space_types std_space_index += 1 # Retrieve data from user_data type_key = format('std_ltg_type%02d', std_space_index) frac_key = format('std_ltg_type_frac%02d', std_space_index) sub_space_type = user_data[type_key] next if exception_list.include?(sub_space_type) adjusted_receptacle_power_credits += user_data[frac_key].to_f * receptacle_power_credits # Adjust while loop condition factors end receptacle_power_credits = adjusted_receptacle_power_credits end elsif user_data.is_a?(String) if exception_list.include?(space_type.standardsSpaceType.get) # the space type is in the exception list, no credit to the space type receptacle_power_credits = 0.0 end end # return false if no receptacle power credits unless receptacle_power_credits > 0.0 return false end # Step 2: check if need to adjust the electric equipment schedule. - apply credit if needed. # get current schedule power_schedule = power_equipment.schedule.get power_schedule_name = power_schedule.name.get new_power_schedule_name = format("#{power_schedule_name}_%.4f", receptacle_power_credits) if schedule_hash.key?(new_power_schedule_name) # In this case, there is a schedule created, can retrieve the schedule object and reset in this space type. schedule_rule = schedule_hash[new_power_schedule_name] power_equipment.setSchedule(schedule_rule) else # In this case, create a new schedule # 1. Clone the existing schedule new_rule_set_schedule = deep_copy_schedule(new_power_schedule_name, power_schedule, receptacle_power_credits, space_type.model) if power_equipment.setSchedule(new_rule_set_schedule) schedule_hash[new_power_schedule_name] = new_rule_set_schedule end end return true end |
#user_data_preprocessor(row) ⇒ Object
Perform user data preprocessing
137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 137 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 |
#user_data_validation(object_name, user_data) ⇒ Boolean
Returns true if data is valid, false if error found.
155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.rb', line 155 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 |
#user_model_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) ⇒ Boolean
Check if an air loop in user model needs to have DCV per air loop related requiremends in ASHRAE 90.1-2019 6.4.3.8
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 446 def user_model_air_loop_hvac_demand_control_ventilation_required?(air_loop_hvac) # all zones in the same airloop in user model are set with the same value, so use the first zone under the loop dcv_airloop_user_exception = air_loop_hvac.thermalZones[0].additionalProperties.getFeatureAsBoolean('airloop user specified DCV exception').get return false if dcv_airloop_user_exception # check the following conditions at airloop level # has air economizer OR design outdoor airflow > 3000 cfm has_economizer = air_loop_hvac_economizer?(air_loop_hvac) if air_loop_hvac.airLoopHVACOutdoorAirSystem.is_initialized oa_flow_m3_per_s = get_airloop_hvac_design_oa_from_sql(air_loop_hvac) else OpenStudio.logFree(OpenStudio::Info, 'openstudio.standards.AirLoopHVAC', "For #{air_loop_hvac.name}, DCV not applicable because it has no OA intake.") return false end oa_flow_cfm = OpenStudio.convert(oa_flow_m3_per_s, 'm^3/s', 'cfm').get any_zones_req_dcv = false air_loop_hvac.thermalZones.sort.each do |zone| if user_model_zone_demand_control_ventilation_required?(zone) any_zones_req_dcv = true break end end return true if any_zones_req_dcv && (has_economizer || (oa_flow_cfm > 3000)) return false end |
#user_model_zone_demand_control_ventilation_required?(thermal_zone) ⇒ Boolean
Check if a zone in user model needs to have DCV per zone related requiremends in ASHRAE 90.1-2019 6.4.3.8
481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.AirLoopHVAC.rb', line 481 def user_model_zone_demand_control_ventilation_required?(thermal_zone) dcv_zone_user_exception = thermal_zone.additionalProperties.getFeatureAsBoolean('zone user specified DCV exception').get return false if dcv_zone_user_exception # check the following conditions at zone level # zone > 500 sqft AND design occ > 25 ppl/ksqft area_served_m2 = 0 num_people = 0 thermal_zone.spaces.each do |space| area_served_m2 += space.floorArea num_people += space.numberOfPeople end area_served_ft2 = OpenStudio.convert(area_served_m2, 'm^2', 'ft^2').get occ_per_1000_ft2 = num_people / area_served_ft2 * 1000 return true if (area_served_ft2 > 500) && (occ_per_1000_ft2 > 25) return false end |
#zone_hvac_component_apply_prm_baseline_fan_power(zone_hvac_component) ⇒ Boolean
Sets the fan power of zone level HVAC equipment (Fan coils, Unit Heaters, PTACs, PTHPs, VRF Terminals, WSHPs, ERVs) based on the W/cfm specified in the standard.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ZoneHVACComponent.rb', line 9 def zone_hvac_component_apply_prm_baseline_fan_power(zone_hvac_component) OpenStudio.logFree(OpenStudio::Debug, 'openstudio.ashrae_90_1_prm.ZoneHVACComponent', "Setting fan power for #{zone_hvac_component.name}.") # Convert this to the actual class type zone_hvac = if zone_hvac_component.to_ZoneHVACFourPipeFanCoil.is_initialized zone_hvac_component.to_ZoneHVACFourPipeFanCoil.get elsif zone_hvac_component.to_ZoneHVACUnitHeater.is_initialized zone_hvac_component.to_ZoneHVACUnitHeater.get elsif zone_hvac_component.to_ZoneHVACPackagedTerminalAirConditioner.is_initialized zone_hvac_component.to_ZoneHVACPackagedTerminalAirConditioner.get elsif zone_hvac_component.to_ZoneHVACPackagedTerminalHeatPump.is_initialized zone_hvac_component.to_ZoneHVACPackagedTerminalHeatPump.get elsif zone_hvac_component.to_ZoneHVACTerminalUnitVariableRefrigerantFlow.is_initialized zone_hvac_component.to_ZoneHVACTerminalUnitVariableRefrigerantFlow.get elsif zone_hvac_component.to_ZoneHVACWaterToAirHeatPump.is_initialized zone_hvac_component.to_ZoneHVACWaterToAirHeatPump.get elsif zone_hvac_component.to_ZoneHVACEnergyRecoveryVentilator.is_initialized zone_hvac_component.to_ZoneHVACEnergyRecoveryVentilator.get end # Do nothing for other types of zone HVAC equipment return false if zone_hvac.nil? # Do nothing if zone hav component isn't assigned to thermal zone return false unless zone_hvac.thermalZone.is_initialized # Get baseline system type system_type = zone_hvac.thermalZone.get.additionalProperties.getFeatureAsString('baseline_system_type').get # Get non-mechanically cooled flag if zone_hvac.thermalZone.get.additionalProperties.hasFeature('non_mechanically_cooled') nmc_flag = zone_hvac.thermalZone.get.additionalProperties.getFeatureAsString('non_mechanically_cooled') else nmc_flag = false end # Get the fan fan = if zone_hvac.supplyAirFan.to_FanConstantVolume.is_initialized zone_hvac.supplyAirFan.to_FanConstantVolume.get elsif zone_hvac.supplyAirFan.to_FanVariableVolume.is_initialized zone_hvac.supplyAirFan.to_FanVariableVolume.get elsif zone_hvac.supplyAirFan.to_FanOnOff.is_initialized zone_hvac.supplyAirFan.to_FanOnOff.get elsif zone_hvac.supplyAirFan.to_FanSystemModel.is_initialized zone_hvac.supplyAirFan.to_FanSystemModel.get end if system_type == 'SZ_CV' # System 12, 13 # Get design supply air flow rate (whether autosized or hard-sized) dsn_air_flow_m3_per_s = 0 dsn_air_flow_cfm = 0 if fan.maximumFlowRate.is_initialized dsn_air_flow_m3_per_s = fan.maximumFlowRate.get elsif fan.isMaximumFlowRateAutosized dsn_air_flow_m3_per_s = fan.autosizedMaximumFlowRate.get end dsn_air_flow_cfm = OpenStudio.convert(dsn_air_flow_m3_per_s, 'm^3/s', 'cfm').get # Determine allowable fan BHP and power allowable_fan_bhp = (0.00094 * dsn_air_flow_cfm) + thermal_zone_get_fan_power_limitations(zone_hvac.thermalZone.get, false) fan_apply_standard_minimum_motor_efficiency(fan, allowable_fan_bhp) allowable_power_w = (allowable_fan_bhp * 746) / fan.motorEfficiency # Modify fan pressure rise to match target fan power fan_adjust_pressure_rise_to_meet_fan_power(fan, allowable_power_w) else # System 1, 2 # Determine the W/cfm fan_efficacy_w_per_cfm = 0.0 case system_type when 'PTAC', 'PTHP' fan_efficacy_w_per_cfm = 0.3 # System 9, 10 when 'Gas_Furnace', 'Electric_Furnace' # Zone heater cannot provide cooling if nmc_flag && !zone_hvac_component.to_ZoneHVACUnitHeater.is_initialized fan_efficacy_w_per_cfm = 0.054 else fan_efficacy_w_per_cfm = 0.3 end else OpenStudio.logFree(OpenStudio::Error, 'openstudio.ashrae_90_1_prm.ZoneHVACComponent', 'Zone HVAC system fan power lookup missing.') end # Convert efficacy to metric fan_efficacy_w_per_m3_per_s = OpenStudio.convert(fan_efficacy_w_per_cfm, 'm^3/s', 'cfm').get # Get the maximum flow rate through the fan max_air_flow_rate = nil if fan.maximumFlowRate.is_initialized max_air_flow_rate = fan.maximumFlowRate.get elsif fan.autosizedMaximumFlowRate.is_initialized max_air_flow_rate = fan.autosizedMaximumFlowRate.get end max_air_flow_rate_cfm = OpenStudio.convert(max_air_flow_rate, 'm^3/s', 'ft^3/min').get # Set the impeller efficiency fan_change_impeller_efficiency(fan, fan_baseline_impeller_efficiency(fan)) # Get fan BHP fan_bhp = fan_brake_horsepower(fan) # Set the motor efficiency, preserving the impeller efficiency. # For zone HVAC fans, a bhp lookup of 0.5bhp is always used because # they are assumed to represent a series of small fans in reality. fan_apply_standard_minimum_motor_efficiency(fan, fan_bhp) # Calculate a new pressure rise to hit the target W/cfm fan_tot_eff = fan.fanEfficiency fan_rise_new_pa = fan_efficacy_w_per_m3_per_s * fan_tot_eff fan.setPressureRise(fan_rise_new_pa) # Calculate the newly set efficacy fan_power_new_w = fan_rise_new_pa * max_air_flow_rate / fan_tot_eff fan_efficacy_new_w_per_cfm = fan_power_new_w / max_air_flow_rate_cfm OpenStudio.logFree(OpenStudio::Info, 'openstudio.ashrae_90_1_prm.ZoneHVACComponent', "For #{zone_hvac_component.name}: fan efficacy set to #{fan_efficacy_new_w_per_cfm.round(2)} W/cfm.") end return true end |
#zone_hvac_unoccupied_threshold ⇒ Double
Default occupancy fraction threshold for determining if the spaces served by the zone hvac are occupied
129 130 131 132 |
# File 'lib/openstudio-standards/standards/ashrae_90_1_prm/ashrae_90_1_prm.ZoneHVACComponent.rb', line 129 def zone_hvac_unoccupied_threshold # Use 10% based on PRM-RM return 0.10 end |