-
Notifications
You must be signed in to change notification settings - Fork 26
Address energy outside of an HVAC season or during unavailable period #2151
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8758181
aae60b1
e1c4950
0ff6650
1a40627
554afd1
2873982
e526e25
6eeaa29
3316eab
51bb6a7
897e276
a215af2
8ba115f
3a05c70
8c263cb
61a3792
c1c8046
9345759
2abcd8e
cd0d7ab
641094c
5e0541d
ecdc565
c8dd252
f1da956
b85e3c4
5147828
ba58f27
a4f9f01
13fab78
fd4513d
63dd002
439a213
76cddff
5c2f362
54238a3
2afbc95
44ea2e1
5e820e6
c585f32
5e8f794
69e7703
a6d7be1
546ddbb
9c4b80b
6434c0e
cbc3a2d
8eefb0d
747e359
031529b
56b8ab9
4259784
a94605b
e254a2b
af6e7cf
60e8f0c
1f5d5b2
2b44b26
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -76,7 +76,9 @@ module Constants | |
| ObjectTypeMiscWellPump = 'misc well pump' | ||
| ObjectTypeNaturalVentilation = 'natural vent' | ||
| ObjectTypeNeighbors = 'neighbors' | ||
| ObjectTypeOATDrybulbSensor = 'outdoor air drybulb temperature sensor' | ||
| ObjectTypeOccupants = 'occupants' | ||
| ObjectTypeCrankcaseHeater = 'crankcase heater' | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the new "end use" for actuated other equipment objects. |
||
| ObjectTypePanHeater = 'pan heater' | ||
| ObjectTypePhotovoltaics = 'photovoltaics' | ||
| ObjectTypePTAC = 'packaged terminal air conditioner' | ||
|
|
||
Large diffs are not rendered by default.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1589,7 +1589,7 @@ def self.create_custom_unit_meters(model, hpxml) | |
| model.getModelObjects.sort.each do |object| | ||
| next if object.to_AdditionalProperties.is_initialized | ||
|
|
||
| vars_by_key = get_object_outputs_by_key(model, object, EUT) | ||
| vars_by_key = get_object_outputs_by_key(object, EUT) | ||
| vars_by_key.each do |key, output_vars| | ||
| ft, eut = key | ||
|
|
||
|
|
@@ -1648,7 +1648,7 @@ def self.get_object_outputs_for_hpxml_system(model, sys_id, eut_filter = nil) | |
| next unless obj_id.is_initialized | ||
| next if sys_id != obj_id.get | ||
|
|
||
| vars_by_key = get_object_outputs_by_key(model, object, EUT) | ||
| vars_by_key = get_object_outputs_by_key(object, EUT) | ||
| vars_by_key.each do |key, object_vars| | ||
| if eut_filter.nil? || eut_filter.include?(key[1]) | ||
| vars[key] = {} if vars[key].nil? | ||
|
|
@@ -1663,11 +1663,10 @@ def self.get_object_outputs_for_hpxml_system(model, sys_id, eut_filter = nil) | |
| # For a given object, returns the Output:Variables or Output:Meters to be requested, | ||
| # and associates them with the appropriate keys (e.g., [FT::Elec, EUT::Heating]). | ||
| # | ||
| # @param model [OpenStudio::Model::Model] OpenStudio Model object | ||
| # @param object [OpenStudio::Model::Foo] A given object in the OpenStudio Model | ||
| # @param class_type [Module] The output class type | ||
| # @return [Hash] Map of output key => array of EnergyPlus output variable/meter names | ||
| def self.get_object_outputs_by_key(model, object, class_type) | ||
| def self.get_object_outputs_by_key(object, class_type) | ||
| object_type = object.additionalProperties.getFeatureAsString('ObjectType') | ||
| object_type = object_type.get if object_type.is_initialized | ||
|
|
||
|
|
@@ -1680,13 +1679,6 @@ def self.get_object_outputs_by_key(model, object, class_type) | |
|
|
||
| if object.to_CoilHeatingDXSingleSpeed.is_initialized || object.to_CoilHeatingDXMultiSpeed.is_initialized | ||
| vars = { [FT::Elec, EUT::Heating] => ['Heating Coil Electricity Energy', 'Heating Coil Defrost Electricity Energy'] } | ||
| if object.additionalProperties.getFeatureAsDouble('FractionHeatLoadServed').is_initialized && object.additionalProperties.getFeatureAsDouble('FractionHeatLoadServed').get <= 0 | ||
| # HP only provides cooling, allocate crankcase to cooling end use | ||
| vars[[FT::Elec, EUT::Cooling]] = ['Heating Coil Crankcase Heater Electricity Energy'] | ||
| else | ||
| # Allocate crankcase to heating end use | ||
| vars[[FT::Elec, EUT::Heating]] << 'Heating Coil Crankcase Heater Electricity Energy' | ||
| end | ||
|
Comment on lines
-1683
to
-1689
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This allocation logic (and some below) is moved to the OtherEquipment block. |
||
| return vars | ||
|
|
||
| elsif object.to_CoilHeatingElectric.is_initialized || object.to_CoilHeatingElectricMultiStage.is_initialized | ||
|
|
@@ -1733,26 +1725,7 @@ def self.get_object_outputs_by_key(model, object, class_type) | |
| end | ||
|
|
||
| elsif object.to_CoilCoolingDXSingleSpeed.is_initialized || object.to_CoilCoolingDXMultiSpeed.is_initialized | ||
| vars = { [FT::Elec, EUT::Cooling] => ['Cooling Coil Electricity Energy'] } | ||
| parent = model.getAirLoopHVACUnitarySystems.select { |u| u.coolingCoil.is_initialized && u.coolingCoil.get.handle.to_s == object.handle.to_s } | ||
|
joseph-robertson marked this conversation as resolved.
|
||
| if (not parent.empty?) && parent[0].heatingCoil.is_initialized | ||
| htg_coil = parent[0].heatingCoil.get | ||
| end | ||
| if parent.empty? | ||
| parent = model.getZoneHVACPackagedTerminalAirConditioners.select { |u| u.coolingCoil.handle.to_s == object.handle.to_s } | ||
| if not parent.empty? | ||
| htg_coil = parent[0].heatingCoil | ||
| end | ||
| end | ||
| if parent.empty? | ||
| fail 'Could not find parent object.' | ||
| end | ||
|
|
||
| if htg_coil.nil? || (not (htg_coil.to_CoilHeatingDXSingleSpeed.is_initialized || htg_coil.to_CoilHeatingDXMultiSpeed.is_initialized)) | ||
| # Crankcase variable only available if no DX heating coil on parent | ||
| vars[[FT::Elec, EUT::Cooling]] << 'Cooling Coil Crankcase Heater Electricity Energy' | ||
| end | ||
| return vars | ||
| return { [FT::Elec, EUT::Cooling] => ['Cooling Coil Electricity Energy'] } | ||
|
|
||
| elsif object.to_CoilCoolingWaterToAirHeatPumpEquationFit.is_initialized || object.to_CoilCoolingWaterToAirHeatPumpVariableSpeedEquationFit.is_initialized | ||
| return { [FT::Elec, EUT::Cooling] => ['Cooling Coil Electricity Energy'] } | ||
|
|
@@ -1864,6 +1837,7 @@ def self.get_object_outputs_by_key(model, object, class_type) | |
| Constants::ObjectTypeMechanicalVentilationPreheating => EUT::MechVentPreheat, | ||
| Constants::ObjectTypeMechanicalVentilationPrecooling => EUT::MechVentPrecool, | ||
| Constants::ObjectTypeHPDefrostSupplHeat => EUT::HeatingHeatPumpBackup, | ||
| Constants::ObjectTypeCrankcaseHeater => [EUT::Heating, EUT::Cooling], | ||
| Constants::ObjectTypePanHeater => EUT::Heating, | ||
| Constants::ObjectTypeWaterHeaterAdjustment => EUT::HotWater, | ||
| Constants::ObjectTypeDSEHeating => EUT::Heating, | ||
|
|
@@ -1876,6 +1850,15 @@ def self.get_object_outputs_by_key(model, object, class_type) | |
| next unless subcategory.start_with? obj_name | ||
| fail "Unexpected error: multiple matches for #{eut}." unless end_use.nil? | ||
|
|
||
| if obj_name == Constants::ObjectTypeCrankcaseHeater | ||
| if object.additionalProperties.getFeatureAsDouble('FractionHeatLoadServed').get <= 0 | ||
| # Allocate crankcase to cooling end use (cooling system or HP only provides cooling) | ||
| eut = eut[1] | ||
| else | ||
| eut = eut[0] | ||
| end | ||
| end | ||
|
|
||
| end_use = eut | ||
| end | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1287,22 +1287,24 @@ def test_air_to_air_heat_pump_1_speed_onoff_thermostat | |
| _check_onoff_thermostat_EMS(model, clg_coil, 1.0, 0.0, 0.0, 1.0, 0.0, 0.0) | ||
| end | ||
|
|
||
| def test_heat_pump_defrost_and_pan_heater | ||
| def test_heat_pump_defrost_and_pan_heater_and_crankcase_heater | ||
|
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move the existing crankcase test into here since we're now, like defrost and pan heater, using EMS programs. |
||
| # Single Speed heat pump test | ||
| args_hash = {} | ||
| args_hash['hpxml_path'] = @tmp_hpxml_path | ||
| hpxml, hpxml_bldg = _create_hpxml('base-hvac-air-to-air-heat-pump-1-speed.xml') | ||
| hpxml_bldg.heat_pumps[0].pan_heater_watts = 60.0 | ||
| hpxml_bldg.heat_pumps[0].crankcase_heater_watts = 20.0 | ||
| XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path) | ||
| model, _hpxml, hpxml_bldg = _test_measure(args_hash) | ||
|
|
||
| # Get HPXML values | ||
| backup_fuel = EPlus.fuel_type(hpxml_bldg.heat_pumps[0].backup_heating_fuel) | ||
| pan_heater_watts = hpxml_bldg.heat_pumps[0].pan_heater_watts | ||
| crankcase_heater_watts = hpxml_bldg.heat_pumps[0].crankcase_heater_watts | ||
|
|
||
| assert_equal(1, model.getCoilHeatingDXSingleSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXSingleSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.1, 0.0, pan_heater_watts) | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.1, 0.0, pan_heater_watts, crankcase_heater_watts) | ||
|
|
||
| # Ductless heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1314,7 +1316,7 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0) | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0) | ||
|
|
||
| # Ductless heat pump w/ backup heat during defrost test | ||
| args_hash = {} | ||
|
|
@@ -1326,7 +1328,7 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0) | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0) | ||
|
|
||
| # Dual fuel heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1338,7 +1340,7 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 17584, 0.95, backup_fuel, 0.06667, 0.0) | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, 17584, 0.95, backup_fuel, 0.06667, 0.0) | ||
|
|
||
| # Two heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1351,10 +1353,10 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(2, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 2) | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 30.0, 2) | ||
|
|
||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[1] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 2) | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, 10000, 1.0, backup_fuel, 0.06667, 0.0, 150.0, 30.0, 2) | ||
|
|
||
| # Separate backup heat pump test | ||
| args_hash = {} | ||
|
|
@@ -1366,7 +1368,7 @@ def test_heat_pump_defrost_and_pan_heater | |
|
|
||
| assert_equal(1, model.getCoilHeatingDXMultiSpeeds.size) | ||
| htg_coil = model.getCoilHeatingDXMultiSpeeds[0] | ||
| _check_defrost_and_pan_heater(model, htg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0) | ||
| _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, 0.0, 0.0, backup_fuel, 0.06667, 0.0, 150.0, 15.0) | ||
| end | ||
|
|
||
| def test_mini_split_heat_pump_ductless | ||
|
|
@@ -2204,23 +2206,6 @@ def test_custom_seasons | |
| assert_includes(end_dates, end_date) | ||
| end | ||
|
|
||
| def test_crankcase_heater_watts | ||
| args_hash = {} | ||
| args_hash['hpxml_path'] = @tmp_hpxml_path | ||
| hpxml, hpxml_bldg = _create_hpxml('base.xml') | ||
| hpxml_bldg.cooling_systems[0].crankcase_heater_watts = 40.0 | ||
| XMLHelper.write_file(hpxml.to_doc, @tmp_hpxml_path) | ||
| model, _hpxml, hpxml_bldg = _test_measure(args_hash) | ||
|
|
||
| # Get HPXML values | ||
| cooling_system = hpxml_bldg.cooling_systems[0] | ||
| crankcase_heater_watts = cooling_system.crankcase_heater_watts | ||
|
|
||
| # Check cooling coil | ||
| clg_coil = model.getCoilCoolingDXSingleSpeeds[0] | ||
| assert_in_epsilon(crankcase_heater_watts, clg_coil.crankcaseHeaterCapacity, 0.01) | ||
| end | ||
|
|
||
| def test_ceiling_fan | ||
| args_hash = {} | ||
| args_hash['hpxml_path'] = File.absolute_path(File.join(@sample_files_path, 'base-lighting-ceiling-fans.xml')) | ||
|
|
@@ -2435,7 +2420,7 @@ def _check_onoff_thermostat_EMS(model, clg_or_htg_coil, c1_cap, c2_cap, c3_cap, | |
| return program_values | ||
| end | ||
|
|
||
| def _check_defrost_and_pan_heater(model, htg_coil, supp_capacity, supp_efficiency, backup_fuel, defrost_time_fraction, defrost_power, pan_heater_watts = 150.0, num_of_ems = 1) | ||
| def _check_defrost_and_pan_heater_and_crankcase_heater(model, htg_coil, supp_capacity, supp_efficiency, backup_fuel, defrost_time_fraction, defrost_power, pan_heater_watts = 150.0, crankcase_heater_watts = 30.0, num_of_ems = 1) | ||
| # Check Other equipment inputs | ||
| defrost_heat_load_oe = model.getOtherEquipments.select { |oe| oe.additionalProperties.getFeatureAsString('ObjectType').to_s == Constants::ObjectTypeHPDefrostHeatLoad } | ||
| assert_equal(num_of_ems, defrost_heat_load_oe.size) | ||
|
|
@@ -2454,13 +2439,19 @@ def _check_defrost_and_pan_heater(model, htg_coil, supp_capacity, supp_efficienc | |
| assert_in_epsilon(htg_coil.defrostTimePeriodFraction, defrost_time_fraction, 0.01) | ||
| assert_in_delta(htg_coil.resistiveDefrostHeaterCapacity.get, defrost_power, 1.0) | ||
|
|
||
| # Check EMS | ||
| # Check EMS defrost/pan heater | ||
| program_values = get_ems_values(model.getEnergyManagementSystemPrograms, "#{htg_coil.name} defrost program") | ||
| assert_in_epsilon(program_values['supp_capacity'].sum, supp_capacity, 0.01) | ||
| assert_in_epsilon(program_values['supp_efficiency'].sum, supp_efficiency, 0.01) | ||
| pan_heater_act_name = program_values.keys.find { |k| k.include? 'pan_heater_energy_act' } | ||
| assert_equal(pan_heater_watts, program_values[pan_heater_act_name][0]) | ||
| assert(!program_values.empty?) | ||
|
|
||
| # Check EMS crankcase heater | ||
| program_values = get_ems_values(model.getEnergyManagementSystemPrograms, "#{htg_coil.name} crankcase program") | ||
| crankcase_heater_act_name = program_values.keys.find { |k| k.include? 'crankcase_heater_energy_act' } | ||
| assert_equal(crankcase_heater_watts, program_values[crankcase_heater_act_name][0]) | ||
| assert(!program_values.empty?) | ||
| end | ||
|
|
||
| def _check_ghp_standard(model, heat_pump, clg_cop, htg_cop, soil_density, soil_surface_temp_amps, phase_shift_temp_amps) | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is used for both defrost and crankcase.