From f080db8b146844dcf641200c03cb7a8b723364f9 Mon Sep 17 00:00:00 2001 From: kevin-moos Date: Mon, 23 Feb 2026 20:45:42 -0600 Subject: [PATCH 1/6] HybridUnitaryHVAC - hook up Objective Function to Minimize field --- src/EnergyPlus/HybridEvapCoolingModel.cc | 11 +++++++---- src/EnergyPlus/HybridEvapCoolingModel.hh | 15 +++++++++++++++ src/EnergyPlus/HybridUnitaryAirConditioners.cc | 6 ++++++ 3 files changed, 28 insertions(+), 4 deletions(-) diff --git a/src/EnergyPlus/HybridEvapCoolingModel.cc b/src/EnergyPlus/HybridEvapCoolingModel.cc index bd46a6c0760..6ffbf1ff8d3 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.cc +++ b/src/EnergyPlus/HybridEvapCoolingModel.cc @@ -1527,7 +1527,7 @@ namespace HybridEvapCoolingModel { if (Conditioning_load_met && Humidification_load_met) { // store best performing mode - if (RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) { + if (ObjectiveFunction == ObjectiveFunctionType::ElectricityUse && RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) { OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; OptimalSetting = thisSetting; DidWeMeetLoad = true; @@ -1562,9 +1562,12 @@ namespace HybridEvapCoolingModel { } } if (store_best_attempt) { - OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; - OptimalSetting = thisSetting; - DidWePartlyMeetLoad = true; + if (ObjectiveFunction == ObjectiveFunctionType::ElectricityUse && + RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) { + OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; + OptimalSetting = thisSetting; + DidWePartlyMeetLoad = true; + } } } } diff --git a/src/EnergyPlus/HybridEvapCoolingModel.hh b/src/EnergyPlus/HybridEvapCoolingModel.hh index 56e1f8ba9c1..6c9c682e3f9 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.hh +++ b/src/EnergyPlus/HybridEvapCoolingModel.hh @@ -91,6 +91,19 @@ namespace HybridEvapCoolingModel { Num }; + enum class ObjectiveFunctionType + { + Invalid = -1, + ElectricityUse, + SecondFuelUse, + ThirdFuelUse, + WaterUse, + Num + }; + + constexpr std::array objectiveFunctionNamesUC = { + "ELECTRICITY USE", "SECOND FUEL USE", "THIRD FUEL USE", "WATER USE"}; + class CModeSolutionSpace { public: @@ -248,6 +261,8 @@ namespace HybridEvapCoolingModel { Constant::eFuel firstFuel = Constant::eFuel::Invalid; // First fuel type, currently electricity is only option Constant::eFuel secondFuel = Constant::eFuel::Invalid; // Second fuel type Constant::eFuel thirdFuel = Constant::eFuel::Invalid; // Third fuel type + ObjectiveFunctionType ObjectiveFunction = + ObjectiveFunctionType::ElectricityUse; // Objective function to minimize, currently only Electricity Use works int UnitOn; // feels like it should be a bool but its an output and I couldn't get it to work as a bool Real64 UnitTotalCoolingRate; // unit output to zone, total cooling rate [W] diff --git a/src/EnergyPlus/HybridUnitaryAirConditioners.cc b/src/EnergyPlus/HybridUnitaryAirConditioners.cc index 92f475cf833..610869178e7 100644 --- a/src/EnergyPlus/HybridUnitaryAirConditioners.cc +++ b/src/EnergyPlus/HybridUnitaryAirConditioners.cc @@ -660,6 +660,12 @@ void GetInputZoneHybridUnitaryAirConditioners(EnergyPlusData &state, bool &Error } // A18, \field Objective Function Minimizes + if (!lAlphaBlanks(18) && (hybridUnitaryAC.ObjectiveFunction = static_cast( + getEnumValue(HybridEvapCoolingModel::objectiveFunctionNamesUC, Util::makeUPPER(Alphas(18))))) == + HybridEvapCoolingModel::ObjectiveFunctionType::Invalid) { + ShowSevereInvalidKey(state, eoh, cAlphaFields(18), Alphas(18)); + ErrorsFound = true; + } // A19, \ OA requirement pointer if (!lAlphaBlanks(19)) { From b5accc23bc5a5ed85b063fa1ae02f83d38136851 Mon Sep 17 00:00:00 2001 From: kevin-moos Date: Wed, 29 Apr 2026 18:53:35 -0500 Subject: [PATCH 2/6] Update unit test to check that objective function was set or defaulted correctly --- .../unit/UnitaryHybridAirConditioner.unit.cc | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc b/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc index d46389c9a6c..cde006c529f 100644 --- a/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc +++ b/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc @@ -546,7 +546,7 @@ TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_ValidateFieldsParsing "Electricity, !- First fuel type", "NaturalGas, !- Second fuel type", "DistrictCooling, !- Third fuel type", - ", !- Objective Function Minimizes", + "Electricity Use, !- Objective Function Minimizes", "SZ DSOA SPACE 2, !- Design Specification Outdoor Air Object Name", "Mode0 Standby, !- Mode0 Name", ", !- Mode0 Supply Air Temperature Lookup Table Name", @@ -591,12 +591,18 @@ TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_ValidateFieldsParsing bool ErrorsFound = false; GetInputZoneHybridUnitaryAirConditioners(*state, ErrorsFound); unsigned long expectedOperatingModesSize = 2; + auto &hybridUnit1 = state->dataHybridUnitaryAC->ZoneHybridUnitaryAirConditioner(1); + auto &hybridUnit2 = state->dataHybridUnitaryAC->ZoneHybridUnitaryAirConditioner(2); + // check the number of operating modes - EXPECT_EQ(state->dataHybridUnitaryAC->ZoneHybridUnitaryAirConditioner(1).OperatingModes.size(), expectedOperatingModesSize); - EXPECT_EQ(state->dataHybridUnitaryAC->ZoneHybridUnitaryAirConditioner(2).OperatingModes.size(), expectedOperatingModesSize); + EXPECT_EQ(hybridUnit1.OperatingModes.size(), expectedOperatingModesSize); + EXPECT_EQ(hybridUnit2.OperatingModes.size(), expectedOperatingModesSize); // check if names for HybridUnitaryAC are converted to upper case - EXPECT_EQ("HYBRID UNIT 1", state->dataHybridUnitaryAC->ZoneHybridUnitaryAirConditioner(1).Name); - EXPECT_EQ("HYBRID UNIT 2", state->dataHybridUnitaryAC->ZoneHybridUnitaryAirConditioner(2).Name); + EXPECT_EQ(hybridUnit1.Name, "HYBRID UNIT 1"); + EXPECT_EQ(hybridUnit2.Name, "HYBRID UNIT 2"); + // check that objective function was set or defaulted correctly + EXPECT_EQ(hybridUnit1.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::ElectricityUse); + EXPECT_EQ(hybridUnit2.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::ElectricityUse); } TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_ValidateMinimumIdfInput) From f21c836cf33ee8366a22303887aa044c3666f3ec Mon Sep 17 00:00:00 2001 From: kevin-moos Date: Sun, 3 May 2026 10:22:09 -0500 Subject: [PATCH 3/6] Fix unit test error --- src/EnergyPlus/HybridEvapCoolingModel.cc | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/EnergyPlus/HybridEvapCoolingModel.cc b/src/EnergyPlus/HybridEvapCoolingModel.cc index d8e729dec20..ad71094c359 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.cc +++ b/src/EnergyPlus/HybridEvapCoolingModel.cc @@ -1567,8 +1567,7 @@ namespace HybridEvapCoolingModel { } } if (store_best_attempt) { - if (ObjectiveFunction == ObjectiveFunctionType::ElectricityUse && - RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) { + if (ObjectiveFunction == ObjectiveFunctionType::ElectricityUse) { OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; OptimalSetting = thisSetting; DidWePartlyMeetLoad = true; From 0e09ebb114a2c829f0368a420fea33366ee70d26 Mon Sep 17 00:00:00 2001 From: kevin-moos Date: Sun, 3 May 2026 10:40:59 -0500 Subject: [PATCH 4/6] Hook up remaining objective function types --- src/EnergyPlus/HybridEvapCoolingModel.cc | 50 ++++++++++++------- .../unit/UnitaryHybridAirConditioner.unit.cc | 10 ++-- 2 files changed, 36 insertions(+), 24 deletions(-) diff --git a/src/EnergyPlus/HybridEvapCoolingModel.cc b/src/EnergyPlus/HybridEvapCoolingModel.cc index ad71094c359..4d43fb09a72 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.cc +++ b/src/EnergyPlus/HybridEvapCoolingModel.cc @@ -1518,23 +1518,37 @@ namespace HybridEvapCoolingModel { thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, WATER_USE); // Calculate partload fraction required to meet all requirements - Real64 PartRuntimeFraction = 0; - PartRuntimeFraction = CalculatePartRuntimeFraction(MinOA_Msa, - thisSetting.Supply_Air_Ventilation_Volume * state.dataEnvrn->StdRhoAir, - StepIns.RequestedCoolingLoad, - StepIns.RequestedHeatingLoad, - SensibleRoomORZone, - StepIns.ZoneDehumidificationLoad, - StepIns.ZoneMoistureLoad, - latentRoomORZone); // - - Real64 RunFractionTotalFuel = - thisSetting.ElectricalPower * PartRuntimeFraction; // fraction can be above 1 meaning its not able to do it completely in a time step. - thisSetting.Runtime_Fraction = PartRuntimeFraction; + // Fraction can be above 1 meaning its not able to do it completely in a time step + Real64 PartRuntimeFraction = CalculatePartRuntimeFraction(MinOA_Msa, + thisSetting.Supply_Air_Ventilation_Volume * state.dataEnvrn->StdRhoAir, + StepIns.RequestedCoolingLoad, + StepIns.RequestedHeatingLoad, + SensibleRoomORZone, + StepIns.ZoneDehumidificationLoad, + StepIns.ZoneMoistureLoad, + latentRoomORZone); + + Real64 RunFractionTotalFuel; + switch (ObjectiveFunction) { + default: + case ObjectiveFunctionType::ElectricityUse: + RunFractionTotalFuel = thisSetting.ElectricalPower * PartRuntimeFraction; + break; + case ObjectiveFunctionType::SecondFuelUse: + RunFractionTotalFuel = thisSetting.SecondaryFuelConsumptionRate * PartRuntimeFraction; + break; + case ObjectiveFunctionType::ThirdFuelUse: + RunFractionTotalFuel = thisSetting.ThirdFuelConsumptionRate * PartRuntimeFraction; + break; + case ObjectiveFunctionType::WaterUse: + RunFractionTotalFuel = thisSetting.WaterConsumptionRate * PartRuntimeFraction; + break; + } + thisSetting.Runtime_Fraction = PartRuntimeFraction; // if (Conditioning_load_met && Humidification_load_met) { // store best performing mode - if (ObjectiveFunction == ObjectiveFunctionType::ElectricityUse && RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) { + if (RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) { OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; OptimalSetting = thisSetting; DidWeMeetLoad = true; @@ -1567,11 +1581,9 @@ namespace HybridEvapCoolingModel { } } if (store_best_attempt) { - if (ObjectiveFunction == ObjectiveFunctionType::ElectricityUse) { - OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; - OptimalSetting = thisSetting; - DidWePartlyMeetLoad = true; - } + OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; + OptimalSetting = thisSetting; + DidWePartlyMeetLoad = true; } } } diff --git a/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc b/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc index cde006c529f..8d681213263 100644 --- a/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc +++ b/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc @@ -484,8 +484,8 @@ TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_ValidateFieldsParsing "Electricity, !- First fuel type", "NaturalGas, !- Second fuel type", "DistrictCooling, !- Third fuel type", - ", !- Objective Function Minimizes", - "SZ DSOA SPACE 1, !- Design Specification Outdoor Air Object Name", + "Electricity Use, !- Objective Function Minimizes", + "SZ DSOA SPACE 1, !- Design Specification Outdoor Air Object Name", "Mode0 Standby, !- Mode0 Name", ", !- Mode0 Supply Air Temperature Lookup Table Name", ", !- Mode0 Supply Air Humidity Ratio Lookup Table Name", @@ -546,8 +546,8 @@ TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_ValidateFieldsParsing "Electricity, !- First fuel type", "NaturalGas, !- Second fuel type", "DistrictCooling, !- Third fuel type", - "Electricity Use, !- Objective Function Minimizes", - "SZ DSOA SPACE 2, !- Design Specification Outdoor Air Object Name", + "Water Use, !- Objective Function Minimizes", + "SZ DSOA SPACE 2, !- Design Specification Outdoor Air Object Name", "Mode0 Standby, !- Mode0 Name", ", !- Mode0 Supply Air Temperature Lookup Table Name", ", !- Mode0 Supply Air Humidity Ratio Lookup Table Name", @@ -602,7 +602,7 @@ TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_ValidateFieldsParsing EXPECT_EQ(hybridUnit2.Name, "HYBRID UNIT 2"); // check that objective function was set or defaulted correctly EXPECT_EQ(hybridUnit1.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::ElectricityUse); - EXPECT_EQ(hybridUnit2.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::ElectricityUse); + EXPECT_EQ(hybridUnit2.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::WaterUse); } TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_ValidateMinimumIdfInput) From 6fd0f41c07073b3b10e602f047ad841e86b84de1 Mon Sep 17 00:00:00 2001 From: kevin-moos Date: Sun, 3 May 2026 10:42:43 -0500 Subject: [PATCH 5/6] Update comments --- src/EnergyPlus/HybridEvapCoolingModel.hh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/EnergyPlus/HybridEvapCoolingModel.hh b/src/EnergyPlus/HybridEvapCoolingModel.hh index 2a4da7f3ab7..0007a6fceeb 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.hh +++ b/src/EnergyPlus/HybridEvapCoolingModel.hh @@ -262,7 +262,7 @@ namespace HybridEvapCoolingModel { Constant::eFuel secondFuel = Constant::eFuel::Invalid; // Second fuel type Constant::eFuel thirdFuel = Constant::eFuel::Invalid; // Third fuel type ObjectiveFunctionType ObjectiveFunction = - ObjectiveFunctionType::ElectricityUse; // Objective function to minimize, currently only Electricity Use works + ObjectiveFunctionType::ElectricityUse; // Objective function to minimize int UnitOn; // feels like it should be a bool but its an output and I couldn't get it to work as a bool Real64 UnitTotalCoolingRate; // unit output to zone, total cooling rate [W] From 8466ca1bc7efbbd1500c2b6609d8410af46bf555 Mon Sep 17 00:00:00 2001 From: kevin-moos Date: Sun, 3 May 2026 11:18:49 -0500 Subject: [PATCH 6/6] Clang format --- src/EnergyPlus/HybridEvapCoolingModel.hh | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/EnergyPlus/HybridEvapCoolingModel.hh b/src/EnergyPlus/HybridEvapCoolingModel.hh index 0007a6fceeb..177473c4788 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.hh +++ b/src/EnergyPlus/HybridEvapCoolingModel.hh @@ -257,12 +257,11 @@ namespace HybridEvapCoolingModel { Real64 FanHeatInAirFrac; // the fraction of fan heat in air stream to calculate fan heat gain if not in lookup tables Real64 ScalingFactor; // taken from IDF N3, linear scaling factor. Real64 ScaledSystemMaximumSupplyAirMassFlowRate; // the scaled system max supply mass flow rate in m3/s. - Real64 ScaledSystemMaximumSupplyAirVolumeFlowRate; // the scaled system max supply volume flow rate in m3/s. - Constant::eFuel firstFuel = Constant::eFuel::Invalid; // First fuel type, currently electricity is only option - Constant::eFuel secondFuel = Constant::eFuel::Invalid; // Second fuel type - Constant::eFuel thirdFuel = Constant::eFuel::Invalid; // Third fuel type - ObjectiveFunctionType ObjectiveFunction = - ObjectiveFunctionType::ElectricityUse; // Objective function to minimize + Real64 ScaledSystemMaximumSupplyAirVolumeFlowRate; // the scaled system max supply volume flow rate in m3/s. + Constant::eFuel firstFuel = Constant::eFuel::Invalid; // First fuel type, currently electricity is only option + Constant::eFuel secondFuel = Constant::eFuel::Invalid; // Second fuel type + Constant::eFuel thirdFuel = Constant::eFuel::Invalid; // Third fuel type + ObjectiveFunctionType ObjectiveFunction = ObjectiveFunctionType::ElectricityUse; // Objective function to minimize int UnitOn; // feels like it should be a bool but its an output and I couldn't get it to work as a bool Real64 UnitTotalCoolingRate; // unit output to zone, total cooling rate [W]