diff --git a/src/EnergyPlus/HybridEvapCoolingModel.cc b/src/EnergyPlus/HybridEvapCoolingModel.cc index cb3c8f72ca3..60f151e8ea7 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.cc +++ b/src/EnergyPlus/HybridEvapCoolingModel.cc @@ -373,19 +373,31 @@ namespace HybridEvapCoolingModel { if (Min_Msa == Max_Msa) { sol.MassFlowRatio.push_back(Max_Msa); } else { - Real64 ResolutionMsa = (Max_Msa - Min_Msa) * 0.2; - for (Real64 Msa_val = Max_Msa; Msa_val >= Min_Msa; Msa_val -= ResolutionMsa) { + int Resolution = 5; + Real64 ResolutionMsa = (Max_Msa - Min_Msa) / Resolution; + + // ensure that the min/max values are included in the solution space + sol.MassFlowRatio.push_back(Max_Msa); + for (int i = Resolution - 1; i > 0; i--) { + Real64 Msa_val = Min_Msa + ResolutionMsa * i; sol.MassFlowRatio.push_back(Msa_val); } + sol.MassFlowRatio.push_back(Min_Msa); } if (Min_OAF == Max_OAF) { sol.OutdoorAirFraction.push_back(Max_OAF); } else { - Real64 ResolutionOSA = (Max_OAF - Min_OAF) * 0.2; - for (Real64 OAF_val = Max_OAF; OAF_val >= Min_OAF; OAF_val -= ResolutionOSA) { + int Resolution = 5; + Real64 ResolutionOAF = (Max_OAF - Min_OAF) / Resolution; + + // ensure that the min/max values are included in the solution space + sol.OutdoorAirFraction.push_back(Max_OAF); + for (int i = Resolution - 1; i > 0; i--) { + Real64 OAF_val = Min_OAF + ResolutionOAF * i; sol.OutdoorAirFraction.push_back(OAF_val); } + sol.OutdoorAirFraction.push_back(Min_OAF); } } @@ -828,6 +840,7 @@ namespace HybridEvapCoolingModel { RunningPeakCapacity_EnvCondMet = false; Settings.clear(); + VentilationSettings.clear(); } void Model::Initialize(int ZoneNumber) @@ -914,6 +927,7 @@ namespace HybridEvapCoolingModel { oStandBy.Mode = 0; oStandBy.Mixed_Air_Temperature = Tra; oStandBy.Mixed_Air_W = Wra; + oStandBy.oMode = Mode0; } else { // if the solution space is invalid return true that an error occurred. return true; @@ -1045,6 +1059,85 @@ namespace HybridEvapCoolingModel { return averagedVal; } + void Model::CalculateSettingOutputs(EnergyPlusData &state, CSetting &Setting, CStepInputs StepIns, Real64 Wosa, Real64 Wra, Real64 MinOA_Msa) + { + // Calculate the delta H + Real64 OSAF = Setting.Outdoor_Air_Fraction; + Real64 UnscaledMsa = Setting.Unscaled_Supply_Air_Mass_Flow_Rate; + Real64 ScaledMsa = Setting.ScaledSupply_Air_Mass_Flow_Rate; + + // send the scaled Msa to calculate energy and the unscaled for sending to curves. + Real64 Tsa = Setting.SupplyAirTemperature; + Real64 Wsa = Setting.SupplyAirW; + Real64 Tma = StepIns.Tra + OSAF * (StepIns.Tosa - StepIns.Tra); + Real64 Wma = Wra + OSAF * (Wosa - Wra); + Setting.Mixed_Air_Temperature = Tma; + Setting.Mixed_Air_W = Wma; + + Real64 Hma = PsyHFnTdbW(Tma, Wma); + // Calculate Enthalpy of return air + Real64 Hra = PsyHFnTdbW(StepIns.Tra, Wra); + Real64 Hsa = PsyHFnTdbW(Tsa, Wsa); + + Real64 SupplyAirCp = PsyCpAirFnW(Wsa); // J/degreesK.kg + Real64 ReturnAirCP = PsyCpAirFnW(Wra); // J/degreesK.kg + Real64 OutdoorAirCP = PsyCpAirFnW(Wosa); // J/degreesK.kg + + // Calculations below of system cooling and heating capacity are ultimately reassessed when the resultant part runtime fraction is + // assessed. However its valuable that they are calculated here to at least provide a check. + + // System Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA + OSAF*(cpOSA-cpRA) + cpSA) {kJ/kg-C} * (T_RA + OSAF*(T_OSA - T_RA) - T_SA) + // System Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA) {kgWater/kgDryAir} + // System Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA + OSAF*(h_OSA - h_RA) - h_SA) {kJ/kgDryAir} + Real64 SystemCp = ReturnAirCP + OSAF * (OutdoorAirCP - ReturnAirCP) + SupplyAirCp; // J/degreesK.kg + Real64 SensibleSystem = ScaledMsa * 0.5 * SystemCp * (Tma - Tsa); // W dynamic cp + Real64 MsaDry = ScaledMsa * (1 - Wsa); + Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, Tsa); + Real64 LatentSystem = LambdaSa * MsaDry * (Wma - Wsa); // W + // Total system cooling + Setting.TotalSystem = (Hma - Hsa) * ScaledMsa; + // Perform latent check + // Real64 latentCheck = TotalSystem - SensibleSystem; + + // Zone Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA+cpSA) {kJ/kg-C} * (T_RA - T_SA) {C} + // Zone Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA - HR_SA) {kgWater/kgDryAir} + // Zone Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA - h_SA) {kJ/kgDryAir} + Real64 SensibleRoomORZone = ScaledMsa * 0.5 * (SupplyAirCp + ReturnAirCP) * (StepIns.Tra - Tsa); // W dynamic cp + Real64 latentRoomORZone = LambdaSa * MsaDry * (Wra - Wsa); // W + // Total room cooling + Real64 TotalRoomORZone = (Hra - Hsa) * ScaledMsa; // W + // Perform latent check + // Real64 latentRoomORZoneCheck = TotalRoomORZone - SensibleRoomORZone; + + Setting.SensibleSystem = SensibleSystem; + Setting.LatentSystem = LatentSystem; + Setting.TotalZone = TotalRoomORZone; + Setting.SensibleZone = SensibleRoomORZone; + Setting.LatentZone = latentRoomORZone; + + Setting.ElectricalPower = Setting.oMode.CalculateCurveVal( + state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, POWER_CURVE); // [Kw] calculations for fuel in Kw + Setting.SupplyFanElectricPower = + Setting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER); + Setting.ExternalStaticPressure = + Setting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, EXTERNAL_STATIC_PRESSURE); + Setting.SecondaryFuelConsumptionRate = + Setting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SECOND_FUEL_USE); + Setting.ThirdFuelConsumptionRate = + Setting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, THIRD_FUEL_USE); + Setting.WaterConsumptionRate = Setting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, WATER_USE); + + // Calculate partload fraction required to meet all requirements + Setting.Runtime_Fraction = Model::CalculatePartRuntimeFraction(MinOA_Msa, + Setting.Supply_Air_Ventilation_Volume * state.dataEnvrn->StdRhoAir, + StepIns.RequestedCoolingLoad, + StepIns.RequestedHeatingLoad, + SensibleRoomORZone, + StepIns.ZoneDehumidificationLoad, + StepIns.ZoneMoistureLoad, + latentRoomORZone); + } + Real64 Model::CalculatePartRuntimeFraction(Real64 MinOA_Msa, Real64 Mvent, Real64 RequestedCoolingLoad, @@ -1192,12 +1285,9 @@ namespace HybridEvapCoolingModel { // SUBROUTINE LOCAL VARIABLE DECLARATIONS: bool DidWeMeetLoad = false; bool DidWeMeetHumidification = false; + bool DidWeMeetVentilation = false; bool DidWePartlyMeetLoad = false; Real64 OptimalSetting_RunFractionTotalFuel = IMPLAUSIBLE_POWER; - Real64 Tma; - Real64 Wma; - Real64 Hsa; - Real64 Hma; Real64 PreviousMaxiumConditioningOutput = 0; Real64 PreviousMaxiumHumidOrDehumidOutput = 0; std::string ObjectID = Name.c_str(); @@ -1342,8 +1432,21 @@ namespace HybridEvapCoolingModel { CandidateSetting.oMode = Mode; CandidateSetting.SupplyAirTemperature = Tsa; CandidateSetting.SupplyAirW = CheckVal_W(state, Wsa, Tsa, OutletPressure); - CandidateSetting.Mode = Mode.ModeID; Settings.push_back(CandidateSetting); + + CSetting VentilationSetting; + VentilationSetting.Supply_Air_Ventilation_Volume = Supply_Air_Ventilation_Volume; + VentilationSetting.Mode = Mode.ModeID; + VentilationSetting.Outdoor_Air_Fraction = OSAF; + VentilationSetting.Supply_Air_Mass_Flow_Rate_Ratio = MsaRatio; + VentilationSetting.Unscaled_Supply_Air_Mass_Flow_Rate = UnscaledMsa; + VentilationSetting.ScaledSupply_Air_Mass_Flow_Rate = min(MinOA_Msa, ScaledMsa); + VentilationSetting.ScaledSupply_Air_Ventilation_Volume = + VentilationSetting.ScaledSupply_Air_Mass_Flow_Rate / state.dataEnvrn->StdRhoAir; + VentilationSetting.oMode = Mode; + VentilationSetting.SupplyAirTemperature = StepIns.Tosa + FanHeatTemp; + VentilationSetting.SupplyAirW = CheckVal_W(state, Wsa, VentilationSetting.SupplyAirTemperature, OutletPressure); + VentilationSettings.push_back(VentilationSetting); } } } @@ -1362,66 +1465,13 @@ namespace HybridEvapCoolingModel { } for (auto &thisSetting : Settings) { - // Calculate the delta H - Real64 OSAF = thisSetting.Outdoor_Air_Fraction; - Real64 UnscaledMsa = thisSetting.Unscaled_Supply_Air_Mass_Flow_Rate; - Real64 ScaledMsa = thisSetting.ScaledSupply_Air_Mass_Flow_Rate; - - // send the scaled Msa to calculate energy and the unscaled for sending to curves. - Tsa = thisSetting.SupplyAirTemperature; - Wsa = thisSetting.SupplyAirW; - Tma = StepIns.Tra + OSAF * (StepIns.Tosa - StepIns.Tra); - Wma = Wra + OSAF * (Wosa - Wra); - thisSetting.Mixed_Air_Temperature = Tma; - thisSetting.Mixed_Air_W = Wma; - - Hma = PsyHFnTdbW(Tma, Wma); - // Calculate Enthalpy of return air - Real64 Hra = PsyHFnTdbW(StepIns.Tra, Wra); - - Hsa = PsyHFnTdbW(Tsa, Wsa); - - Real64 SupplyAirCp = PsyCpAirFnW(Wsa); // J/degreesK.kg - Real64 ReturnAirCP = PsyCpAirFnW(Wra); // J/degreesK.kg - Real64 OutdoorAirCP = PsyCpAirFnW(Wosa); // J/degreesK.kg - - // Calculations below of system cooling and heating capacity are ultimately reassessed when the resultant part runtime fraction is - // assessed. However its valuable that they are calculated here to at least provide a check. - - // System Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA + OSAF*(cpOSA-cpRA) + cpSA) {kJ/kg-C} * (T_RA + OSAF*(T_OSA - T_RA) - T_SA) - // System Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA + OSAF *(HR_OSA - HR_RA) - HR_SA) {kgWater/kgDryAir} - // System Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA + OSAF*(h_OSA - h_RA) - h_SA) {kJ/kgDryAir} - Real64 SystemCp = ReturnAirCP + OSAF * (OutdoorAirCP - ReturnAirCP) + SupplyAirCp; // J/degreesK.kg - Real64 SensibleSystem = ScaledMsa * 0.5 * SystemCp * (Tma - Tsa); // W dynamic cp - Real64 MsaDry = ScaledMsa * (1 - Wsa); - Real64 LambdaSa = Psychrometrics::PsyHfgAirFnWTdb(0, Tsa); - Real64 LatentSystem = LambdaSa * MsaDry * (Wma - Wsa); // W - // Total system cooling - thisSetting.TotalSystem = (Hma - Hsa) * ScaledMsa; - // Perform latent check - // Real64 latentCheck = TotalSystem - SensibleSystem; - - // Zone Sensible Cooling{ W } = m'SA {kg/s} * 0.5*(cpRA+cpSA) {kJ/kg-C} * (T_RA - T_SA) {C} - // Zone Latent Cooling{ W } = m'SAdryair {kg/s} * L {kJ/kgWater} * (HR_RA - HR_SA) {kgWater/kgDryAir} - // Zone Total Cooling{ W } = m'SAdryair {kg/s} * (h_RA - h_SA) {kJ/kgDryAir} - Real64 SensibleRoomORZone = ScaledMsa * 0.5 * (SupplyAirCp + ReturnAirCP) * (StepIns.Tra - Tsa); // W dynamic cp - Real64 latentRoomORZone = LambdaSa * MsaDry * (Wra - Wsa); // W - // Total room cooling - Real64 TotalRoomORZone = (Hra - Hsa) * ScaledMsa; // W - // Perform latent check - // Real64 latentRoomORZoneCheck = TotalRoomORZone - SensibleRoomORZone; - - thisSetting.SensibleSystem = SensibleSystem; - thisSetting.LatentSystem = LatentSystem; - thisSetting.TotalZone = TotalRoomORZone; - thisSetting.SensibleZone = SensibleRoomORZone; - thisSetting.LatentZone = latentRoomORZone; + CalculateSettingOutputs(state, thisSetting, StepIns, Wosa, Wra, MinOA_Msa); bool Conditioning_load_met = false; - if (CoolingRequested && (SensibleRoomORZone > StepIns.RequestedCoolingLoad)) { + if (CoolingRequested && (thisSetting.SensibleZone > StepIns.RequestedCoolingLoad)) { Conditioning_load_met = true; } - if (HeatingRequested && (SensibleRoomORZone < StepIns.RequestedHeatingLoad)) { + if (HeatingRequested && (thisSetting.SensibleZone < StepIns.RequestedHeatingLoad)) { Conditioning_load_met = true; } if (!(HeatingRequested || CoolingRequested)) { @@ -1429,99 +1479,82 @@ namespace HybridEvapCoolingModel { } bool Humidification_load_met = false; - if (DehumidificationRequested && latentRoomORZone > StepIns.ZoneDehumidificationLoad) { + if (DehumidificationRequested && thisSetting.LatentZone > StepIns.ZoneDehumidificationLoad) { Humidification_load_met = true; } - if (HumidificationRequested && latentRoomORZone < StepIns.ZoneMoistureLoad) { + if (HumidificationRequested && thisSetting.LatentZone < StepIns.ZoneMoistureLoad) { Humidification_load_met = true; } if (!(HumidificationRequested || DehumidificationRequested)) { Humidification_load_met = true; } - thisSetting.ElectricalPower = thisSetting.oMode.CalculateCurveVal( - state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, POWER_CURVE); // [Kw] calculations for fuel in Kw - thisSetting.SupplyFanElectricPower = - thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SUPPLY_FAN_POWER); - thisSetting.ExternalStaticPressure = - thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, EXTERNAL_STATIC_PRESSURE); - thisSetting.SecondaryFuelConsumptionRate = - thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, SECOND_FUEL_USE); - thisSetting.ThirdFuelConsumptionRate = - thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, THIRD_FUEL_USE); - thisSetting.WaterConsumptionRate = - thisSetting.oMode.CalculateCurveVal(state, StepIns.Tosa, Wosa, StepIns.Tra, Wra, UnscaledMsa, OSAF, WATER_USE); - - // Calculate partload fraction required to meet all requirements - // 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; + Real64 RunFractionTotalFuel(0); switch (ObjectiveFunction) { default: case ObjectiveFunctionType::ElectricityUse: - RunFractionTotalFuel = thisSetting.ElectricalPower * PartRuntimeFraction; + RunFractionTotalFuel = thisSetting.ElectricalPower * thisSetting.Runtime_Fraction; break; case ObjectiveFunctionType::SecondFuelUse: - RunFractionTotalFuel = thisSetting.SecondaryFuelConsumptionRate * PartRuntimeFraction; + RunFractionTotalFuel = thisSetting.SecondaryFuelConsumptionRate * thisSetting.Runtime_Fraction; break; case ObjectiveFunctionType::ThirdFuelUse: - RunFractionTotalFuel = thisSetting.ThirdFuelConsumptionRate * PartRuntimeFraction; + RunFractionTotalFuel = thisSetting.ThirdFuelConsumptionRate * thisSetting.Runtime_Fraction; break; case ObjectiveFunctionType::WaterUse: - RunFractionTotalFuel = thisSetting.WaterConsumptionRate * PartRuntimeFraction; + RunFractionTotalFuel = thisSetting.WaterConsumptionRate * thisSetting.Runtime_Fraction; break; } - thisSetting.Runtime_Fraction = PartRuntimeFraction; // + bool StoreBestSetting = false; if (Conditioning_load_met && Humidification_load_met) { - // store best performing mode if (RunFractionTotalFuel < OptimalSetting_RunFractionTotalFuel) { + StoreBestSetting = true; OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; + } + + if (StoreBestSetting) { OptimalSetting = thisSetting; DidWeMeetLoad = true; DidWeMeetHumidification = true; } } else { if (!DidWeMeetLoad && !DidWeMeetHumidification) { - bool store_best_attempt = false; - if (Conditioning_load_met) { DidWeMeetLoad = true; - if (HumidificationRequested && (latentRoomORZone < PreviousMaxiumHumidOrDehumidOutput)) { - store_best_attempt = true; + if (HumidificationRequested && (thisSetting.LatentZone < PreviousMaxiumHumidOrDehumidOutput)) { + StoreBestSetting = true; } - if (DehumidificationRequested && (latentRoomORZone > PreviousMaxiumHumidOrDehumidOutput)) { - store_best_attempt = true; + if (DehumidificationRequested && (thisSetting.LatentZone > PreviousMaxiumHumidOrDehumidOutput)) { + StoreBestSetting = true; } - if (store_best_attempt) { - PreviousMaxiumHumidOrDehumidOutput = latentRoomORZone; + if (StoreBestSetting) { + PreviousMaxiumHumidOrDehumidOutput = thisSetting.LatentZone; } } else { - if (CoolingRequested && (SensibleRoomORZone > PreviousMaxiumConditioningOutput)) { - store_best_attempt = true; + if (CoolingRequested && (thisSetting.SensibleZone > PreviousMaxiumConditioningOutput)) { + StoreBestSetting = true; } - if (HeatingRequested && (SensibleRoomORZone < PreviousMaxiumConditioningOutput)) { - store_best_attempt = true; + if (HeatingRequested && (thisSetting.SensibleZone < PreviousMaxiumConditioningOutput)) { + StoreBestSetting = true; } - if (store_best_attempt) { - PreviousMaxiumConditioningOutput = SensibleRoomORZone; + if (StoreBestSetting) { + PreviousMaxiumConditioningOutput = thisSetting.SensibleZone; } } - if (store_best_attempt) { + if (StoreBestSetting) { OptimalSetting_RunFractionTotalFuel = RunFractionTotalFuel; OptimalSetting = thisSetting; DidWePartlyMeetLoad = true; } } } + + if (!StoreBestSetting && VentilationRequested) { + // Ventilation requirements have already been met as a condition for creating this setting (see MinVRMet above) + // Set this flag for later in case no loads are met + DidWeMeetVentilation = true; + } } if (!EnvironmentConditionsMetOnce) { @@ -1561,6 +1594,36 @@ namespace HybridEvapCoolingModel { CurrentOperatingSettings[0] = OptimalSetting; PrimaryMode = OptimalSetting.Mode; PrimaryModeRuntimeFraction = 1; + } // if we didn't meet any loads but still met ventilation, calculate the ventilation settings and select an appropriate candidate + else if (DidWeMeetVentilation) { + for (auto &thisSetting : VentilationSettings) { + CalculateSettingOutputs(state, thisSetting, StepIns, Wosa, Wra, MinOA_Msa); + + // scale these outputs using the ventilation runtime fraction, because the actual runtime fraction will be overridden to 1 below + Real64 effectiveRuntimeFraction = Model::CalculatePartRuntimeFraction( + MinOA_Msa, thisSetting.Supply_Air_Ventilation_Volume * state.dataEnvrn->StdRhoAir, 0, 0, 0, 0, 0, 0); + thisSetting.ElectricalPower *= effectiveRuntimeFraction; + thisSetting.SupplyFanElectricPower *= effectiveRuntimeFraction; + thisSetting.ExternalStaticPressure *= effectiveRuntimeFraction; + thisSetting.SecondaryFuelConsumptionRate *= effectiveRuntimeFraction; + thisSetting.ThirdFuelConsumptionRate *= effectiveRuntimeFraction; + thisSetting.WaterConsumptionRate *= effectiveRuntimeFraction; + } + std::sort(VentilationSettings.begin(), VentilationSettings.end(), [](const CSetting &a, const CSetting &b) { + return a.ElectricalPower + a.SupplyFanElectricPower < a.ElectricalPower + b.SupplyFanElectricPower; + }); + OptimalSetting = VentilationSettings.front(); + + ErrorCode = 0; + count_DidWeNotMeetLoad++; + if (OptimalSetting.ElectricalPower == IMPLAUSIBLE_POWER) { + ShowWarningError(state, "Model was not able to provide ventilation for a time step, called in HybridEvapCooling:dostep"); + OptimalSetting.ElectricalPower = 0; + } + OptimalSetting.Runtime_Fraction = 1; + CurrentOperatingSettings[0] = OptimalSetting; + PrimaryMode = OptimalSetting.Mode; + PrimaryModeRuntimeFraction = OptimalSetting.Runtime_Fraction; } // if we didn't even partially meet the load make sure the operational settings are just the standby mode. else { diff --git a/src/EnergyPlus/HybridEvapCoolingModel.hh b/src/EnergyPlus/HybridEvapCoolingModel.hh index 76dec2c8ed6..06ec2ae8fc8 100644 --- a/src/EnergyPlus/HybridEvapCoolingModel.hh +++ b/src/EnergyPlus/HybridEvapCoolingModel.hh @@ -386,9 +386,11 @@ namespace HybridEvapCoolingModel { CSetting oStandBy; std::vector Settings; + std::vector VentilationSettings; // methods int CurrentPrimaryMode(); Real64 CurrentPrimaryRuntimeFraction(); + void CalculateSettingOutputs(EnergyPlusData &state, CSetting &Setting, CStepInputs StepIns, Real64 Wosa, Real64 Wra, Real64 MinOA_Msa); Real64 CalculatePartRuntimeFraction(Real64 MinOA_Msa, Real64 Mvent, Real64 RequestedCoolingLoad, diff --git a/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc b/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc index 0fe226fd821..108bb542cba 100644 --- a/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc +++ b/tst/EnergyPlus/unit/UnitaryHybridAirConditioner.unit.cc @@ -112,6 +112,7 @@ using EnergyPlus::HybridEvapCoolingModel::CMode; using EnergyPlus::HybridEvapCoolingModel::CSetting; using EnergyPlus::HybridEvapCoolingModel::Model; using EnergyPlus::Psychrometrics::PsyHFnTdbRhPb; +using EnergyPlus::Psychrometrics::PsyHFnTdbW; using EnergyPlus::Psychrometrics::PsyRhFnTdbWPb; using EnergyPlus::Psychrometrics::PsyWFnTdbRhPb; using namespace EnergyPlus::HybridUnitaryAirConditioners; @@ -1604,4 +1605,538 @@ TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_RuntimeFraction_Initi EXPECT_EQ(Setting1RuntimeFraction, 0); // Standby RTF } +TEST_F(EnergyPlusFixture, Test_UnitaryHybridAirConditioner_OptimizeSupplyTemperature) +{ + std::string idf_objects = delimited_string({ + "ZoneHVAC:HybridUnitaryHVAC,", + "Hybrid Unit, !- Name", + "Always On, !- Availability Schedule Name", + ", !- Availability Manager List Name", + "Min Tsa Schedule, !- Minimum Supply Air Temperature Schedule Name", + "Max Tsa Schedule, !- Maximum Supply Air Temperature Schedule Name", + ", !- Minimum Supply Air Humidity Ratio Schedule Name", + ", !- Maximum Supply Air Humidity Ratio Schedule Name", + "Automatic, !- Method to Choose Controlled Inputs and Part Runtime Fraction", + "Return Air Node, !- Return Air Node Name", + "Outside Air Node, !- Outside Air Node Name", + "Supply Air Node, !- Supply Air Node Name", + "Relief Node, !- Relief Node Name", + "3.0, !- System Maximum Supply AirFlow Rate {m3/s}", + ", !- External Static Pressure at System Maximum Supply Air Flow Rate {Pa}", + "Yes, !- Fan Heat Included in Lookup Tables", + ", !- Fan Heat Gain Location", + ", !- Fan Heat Gain In Airstream Fraction", + "1.0, !- Scaling Factor", + "10, !- Minimum Time Between Mode Change {minutes}", + "Electricity, !- First fuel type", + "None, !- Second fuel type", + "None, !- Third fuel type", + "Electricity Use, !- Objective Function Minimizes", + "DSOA 1, !- Design Specification Outdoor Air Object Name", + "Mode0 Standby, !- Mode0 Name", + "Mode0 Tsa Lookup, !- Mode0 Supply Air Temperature Lookup Table Name", + ", !- Mode0 Supply Air Humidity Ratio Lookup Table Name", + "Mode0 Power Lookup, !- Mode0 System Electric Power Lookup Table Name", + ", !- Mode0 Supply Fan Electric Power Lookup Table Name", + ", !- Mode0 External Static Pressure Lookup Table Name", + ", !- Mode0 System Second Fuel Consumption Lookup Table Name", + ", !- Mode0 System Third Fuel Consumption Lookup Table Name", + ", !- Mode0 System Water Use Lookup Table Name", + ", !- Mode0 Outside Air Fraction", + ", !- Mode0 Supply Air Mass Flow Rate Ratio", + "Mode1 Optimal Power, !- Mode1 Name", + "Mode1 Tsa Lookup, !- Mode1 Supply Air Temperature Lookup Table Name", + ", !- Mode1 Supply Air Humidity Ratio Lookup Table Name", + "Mode1 Power Lookup, !- Mode1 System Electric Power Lookup Table Name", + ", !- Mode1 Supply Fan Electric Power Lookup Table Name", + ", !- Mode1 External Static Pressure Lookup Table Name", + ", !- Mode1 System Second Fuel Consumption Lookup Table Name", + ", !- Mode1 System Third Fuel Consumption Lookup Table Name", + ", !- Mode1 System Water Use Lookup Table Name", + "-20, !- Mode1 Minimum Outside Air Temperature {C}", + "120, !- Mode1 Maximum Outside Air Temperature {C}", + ", !- Mode1 Minimum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode1 Maximum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode1 Minimum Outside Air Relative Humidity {percent}", + ", !- Mode1 Maximum Outside Air Relative Humidity {percent}", + ", !- Mode1 Minimum Return Air Temperature {C}", + ", !- Mode1 Maximum Return Air Temperature {C}", + ", !- Mode1 Minimum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode1 Maximum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode1 Minimum Return Air Relative Humidity {percent}", + ", !- Mode1 Maximum Return Air Relative Humidity {percent}", + ", !- Mode1 Minimum Outside Air Fraction", + ", !- Mode1 Maximum Outside Air Fraction", + ", !- Mode1 Minimum Supply Air Mass Flow Rate Ratio", + ", !- Mode1 Maximum Supply Air Mass Flow Rate Ratio", + "Mode2 Optimal Tsa Cool, !- Mode2 Name", + "Mode2 Tsa Lookup, !- Mode2 Supply Air Temperature Lookup Table Name", + ", !- Mode2 Supply Air Humidity Ratio Lookup Table Name", + "Mode2 Power Lookup, !- Mode2 System Electric Power Lookup Table Name", + ", !- Mode2 Supply Fan Electric Power Lookup Table Name", + ", !- Mode2 External Static Pressure Lookup Table Name", + ", !- Mode2 System Second Fuel Consumption Lookup Table Name", + ", !- Mode2 System Third Fuel Consumption Lookup Table Name", + ", !- Mode2 System Water Use Lookup Table Name", + "-20, !- Mode2 Minimum Outside Air Temperature {C}", + "120, !- Mode2 Maximum Outside Air Temperature {C}", + ", !- Mode2 Minimum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode2 Maximum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode2 Minimum Outside Air Relative Humidity {percent}", + ", !- Mode2 Maximum Outside Air Relative Humidity {percent}", + ", !- Mode2 Minimum Return Air Temperature {C}", + ", !- Mode2 Maximum Return Air Temperature {C}", + ", !- Mode2 Minimum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode2 Maximum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode2 Minimum Return Air Relative Humidity {percent}", + ", !- Mode2 Maximum Return Air Relative Humidity {percent}", + ", !- Mode2 Minimum Outside Air Fraction", + ", !- Mode2 Maximum Outside Air Fraction", + ", !- Mode2 Minimum Supply Air Mass Flow Rate Ratio", + ", !- Mode2 Maximum Supply Air Mass Flow Rate Ratio", + "Mode3 Optimal Tsa Heat, !- Mode3 Name", + "Mode3 Tsa Lookup, !- Mode3 Supply Air Temperature Lookup Table Name", + ", !- Mode3 Supply Air Humidity Ratio Lookup Table Name", + "Mode3 Power Lookup, !- Mode3 System Electric Power Lookup Table Name", + ", !- Mode3 Supply Fan Electric Power Lookup Table Name", + ", !- Mode3 External Static Pressure Lookup Table Name", + ", !- Mode3 System Second Fuel Consumption Lookup Table Name", + ", !- Mode3 System Third Fuel Consumption Lookup Table Name", + ", !- Mode3 System Water Use Lookup Table Name", + "-20, !- Mode3 Minimum Outside Air Temperature {C}", + "120, !- Mode3 Maximum Outside Air Temperature {C}", + ", !- Mode3 Minimum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode3 Maximum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode3 Minimum Outside Air Relative Humidity {percent}", + ", !- Mode3 Maximum Outside Air Relative Humidity {percent}", + ", !- Mode3 Minimum Return Air Temperature {C}", + ", !- Mode3 Maximum Return Air Temperature {C}", + ", !- Mode3 Minimum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode3 Maximum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode3 Minimum Return Air Relative Humidity {percent}", + ", !- Mode3 Maximum Return Air Relative Humidity {percent}", + ", !- Mode3 Minimum Outside Air Fraction", + ", !- Mode3 Maximum Outside Air Fraction", + ", !- Mode3 Minimum Supply Air Mass Flow Rate Ratio", + ", !- Mode3 Maximum Supply Air Mass Flow Rate Ratio", + "Mode4 Optimal Vent Only, !- Mode4 Name", + "Mode4 Tsa Lookup, !- Mode4 Supply Air Temperature Lookup Table Name", + ", !- Mode4 Supply Air Humidity Ratio Lookup Table Name", + ", !- Mode4 System Electric Power Lookup Table Name", + "Mode4 Power Lookup, !- Mode4 Supply Fan Electric Power Lookup Table Name", + ", !- Mode4 External Static Pressure Lookup Table Name", + ", !- Mode4 System Second Fuel Consumption Lookup Table Name", + ", !- Mode4 System Third Fuel Consumption Lookup Table Name", + ", !- Mode4 System Water Use Lookup Table Name", + "-30, !- Mode4 Minimum Outside Air Temperature {C}", + "130, !- Mode4 Maximum Outside Air Temperature {C}", + ", !- Mode4 Minimum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode4 Maximum Outside Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode4 Minimum Outside Air Relative Humidity {percent}", + ", !- Mode4 Maximum Outside Air Relative Humidity {percent}", + ", !- Mode4 Minimum Return Air Temperature {C}", + ", !- Mode4 Maximum Return Air Temperature {C}", + ", !- Mode4 Minimum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode4 Maximum Return Air Humidity Ratio {kgWater/kgDryAir}", + ", !- Mode4 Minimum Return Air Relative Humidity {percent}", + ", !- Mode4 Maximum Return Air Relative Humidity {percent}", + ", !- Mode4 Minimum Outside Air Fraction", + ", !- Mode4 Maximum Outside Air Fraction", + ", !- Mode4 Minimum Supply Air Mass Flow Rate Ratio", + "; !- Mode4 Maximum Supply Air Mass Flow Rate Ratio", + + "Table:Lookup,", + "Mode0 Tsa Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "40.0; !- Output Value 1", + + "Table:Lookup,", + "Mode1 Tsa Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "25.0; !- Output Value 1", + + "Table:Lookup,", + "Mode2 Tsa Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "15.0; !- Output Value 1", + + "Table:Lookup,", + "Mode3 Tsa Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "35.0; !- Output Value 1", + + "Table:Lookup,", + "Mode4 Tsa Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "20.0; !- Output Value 1", + + "Table:Lookup,", + "Mode0 Power Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "5.0; !- Output Value 1", + + "Table:Lookup,", + "Mode1 Power Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "100.0; !- Output Value 1", + + "Table:Lookup,", + "Mode2 Power Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "500.0; !- Output Value 1", + + "Table:Lookup,", + "Mode3 Power Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "1000.0; !- Output Value 1", + + "Table:Lookup,", + "Mode4 Power Lookup, !- Name", + "Variable List, !- Independent Variable List Name", + "DivisorOnly, !- Normalization Method", + ", !- Normalization Divisor", + "-9999, !- Minimum Output", + "9999, !- Maximum Output", + "Dimensionless, !- Output Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "150.0; !- Output Value 1", + + "Table:IndependentVariableList,", + "Variable List, !- Name", + "Tsa, !- Independent Variable 1 Name", + "Wsa, !- Independent Variable 2 Name", + "Tra, !- Extended Field", + "Wra, !- Extended Field", + "Ma, !- Extended Field", + "OAF; !- Extended Field", + + "Table:IndependentVariable,", + "Tsa, !- Name", + "Linear, !- Interpolation Method", + "Constant, !- Extrapolation Method", + "-20, !- Minimum Value", + "100, !- Maximum Value", + ", !- Normalization Reference Value", + "Dimensionless, !- Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "20.0; !- Value 1", + + "Table:IndependentVariable,", + "Wsa, !- Name", + "Linear, !- Interpolation Method", + "Constant, !- Extrapolation Method", + "0, !- Minimum Value", + "0.05, !- Maximum Value", + ", !- Normalization Reference Value", + "Dimensionless, !- Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "0.005; !- Value 1", + + "Table:IndependentVariable,", + "Tra, !- Name", + "Linear, !- Interpolation Method", + "Constant, !- Extrapolation Method", + "-20, !- Minimum Value", + "100, !- Maximum Value", + ", !- Normalization Reference Value", + "Dimensionless, !- Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "20.0; !- Value 1", + + "Table:IndependentVariable,", + "Wra, !- Name", + "Linear, !- Interpolation Method", + "Constant, !- Extrapolation Method", + "0, !- Minimum Value", + "0.05, !- Maximum Value", + ", !- Normalization Reference Value", + "Dimensionless, !- Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "0.01; !- Value 1", + + "Table:IndependentVariable,", + "Ma, !- Name", + "Linear, !- Interpolation Method", + "Constant, !- Extrapolation Method", + "0, !- Minimum Value", + "1, !- Maximum Value", + ", !- Normalization Reference Value", + "Dimensionless, !- Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "0.5; !- Value 1", + + "Table:IndependentVariable,", + "OAF, !- Name", + "Linear, !- Interpolation Method", + "Constant, !- Extrapolation Method", + "0, !- Minimum Value", + "1, !- Maximum Value", + ", !- Normalization Reference Value", + "Dimensionless, !- Unit Type", + ", !- External File Name", + ", !- External File Column Number", + ", !- External File Starting Row Number", + "1; !- Value 1", + + "Schedule:Compact,", + "Always On, !- Name", + "On/Off, !- Schedule Type Limits Name", + "Through: 12/31, !- Field 1", + "For: AllDays, !- Field 2", + "Until: 24:00,1; !- Field 3", + + "ScheduleTypeLimits,", + "Any Number; !- Name", + + "Schedule:Constant,", + "Min Tsa Schedule, !- Name", + "Any Number, !- Schedule Type Limits Name", + "-20; !- Schedule Value", + + "Schedule:Constant,", + "Max Tsa Schedule, !- Name", + "Any Number, !- Schedule Type Limits Name", + "120; !- Schedule Value", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + state->init_state(*state); + + bool ErrorsFound(false); + GetInputZoneHybridUnitaryAirConditioners(*state, ErrorsFound); + GetOARequirements(*state); + EXPECT_FALSE(ErrorsFound); + + state->dataEnvrn->Month = 7; + state->dataEnvrn->DayOfMonth = 21; + state->dataGlobal->HourOfDay = 1; + state->dataEnvrn->DayOfWeek = 1; + state->dataEnvrn->DayOfYear_Schedule = General::OrdinalDay(state->dataEnvrn->Month, state->dataEnvrn->DayOfMonth, 0); + Sched::UpdateScheduleVals(*state); + + state->dataEnvrn->OutBaroPress = 101325; + state->dataEnvrn->StdRhoAir = 1.2; + + auto &thisUnitary = state->dataHybridUnitaryAC->ZoneHybridUnitaryAirConditioner(1); + auto ¤tSettings = thisUnitary.CurrentOperatingSettings[0]; + auto &inletNode = state->dataLoopNodes->Node(thisUnitary.InletNode); + auto &secondaryInletNode = state->dataLoopNodes->Node(thisUnitary.SecondaryInletNode); + + // 1. Check that supply temperature is optimized correctly for cooling + Real64 Tra = 30; + Real64 Tsa = 20; + constexpr Real64 Wra = 0.01; + constexpr Real64 Wsa = 0.005; + + inletNode.Temp = Tra; + inletNode.HumRat = Wra; + inletNode.Enthalpy = PsyHFnTdbW(inletNode.Temp, inletNode.HumRat); + inletNode.Press = state->dataEnvrn->OutBaroPress; + secondaryInletNode.Temp = Tsa; + secondaryInletNode.HumRat = Wsa; + secondaryInletNode.Enthalpy = PsyHFnTdbW(secondaryInletNode.Temp, secondaryInletNode.HumRat); + secondaryInletNode.Press = state->dataEnvrn->OutBaroPress; + InitZoneHybridUnitaryAirConditioners(*state, 1, 2); + + Real64 RequestedHeating = 0; + Real64 RequestedCooling = -10000.0; + constexpr Real64 Requested_Humidification = 0; + constexpr Real64 Requested_Dehumidification = 0; + constexpr Real64 DesignMinVR = 0.85; + + thisUnitary.Initialize(1); + thisUnitary.InitializeModelParams(); + thisUnitary.doStep(*state, RequestedCooling, RequestedHeating, Requested_Humidification, Requested_Dehumidification, DesignMinVR); + + // EXPECT_EQ(thisUnitary.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::SupplyTemperature); + // EXPECT_EQ(currentSettings.Mode, 2); + // EXPECT_EQ(currentSettings.oMode.ModeName, "Mode2 Optimal Tsa Cool"); + // EXPECT_EQ(currentSettings.SupplyAirTemperature, 15); + + // 2. Check that electric power is optimized correctly for unmet cooling + RequestedHeating = 0; + RequestedCooling = -1000000.0; + + thisUnitary.Initialize(1); + thisUnitary.InitializeModelParams(); + thisUnitary.doStep(*state, RequestedCooling, RequestedHeating, Requested_Humidification, Requested_Dehumidification, DesignMinVR); + + Real64 effectiveRuntimeFraction = thisUnitary.CalculatePartRuntimeFraction( + DesignMinVR, currentSettings.Supply_Air_Ventilation_Volume * state->dataEnvrn->StdRhoAir, 0, 0, 0, 0, 0, 0); + + // EXPECT_EQ(thisUnitary.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::SupplyTemperature); + // EXPECT_EQ(currentSettings.Mode, 1); + // EXPECT_EQ(currentSettings.oMode.ModeName, "Mode1 Optimal Power"); + // EXPECT_EQ(currentSettings.ElectricalPower + currentSettings.SupplyFanElectricPower, 100 * effectiveRuntimeFraction); + + // 3. Check that supply temperature is optimized correctly for heating + Tra = 25; + Tsa = 5; + + inletNode.Temp = Tra; + inletNode.Enthalpy = PsyHFnTdbW(inletNode.Temp, inletNode.HumRat); + secondaryInletNode.Temp = Tsa; + secondaryInletNode.Enthalpy = PsyHFnTdbW(secondaryInletNode.Temp, secondaryInletNode.HumRat); + InitZoneHybridUnitaryAirConditioners(*state, 1, 2); + + RequestedHeating = 10000.0; + RequestedCooling = 0; + + thisUnitary.Initialize(1); + thisUnitary.InitializeModelParams(); + thisUnitary.doStep(*state, RequestedCooling, RequestedHeating, Requested_Humidification, Requested_Dehumidification, DesignMinVR); + + // EXPECT_EQ(thisUnitary.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::SupplyTemperature); + // EXPECT_EQ(currentSettings.Mode, 3); + // EXPECT_EQ(currentSettings.oMode.ModeName, "Mode3 Optimal Tsa Heat"); + // EXPECT_EQ(currentSettings.SupplyAirTemperature, 35); + + // 4. Check that electric power is optimized correctly for unmet heating + RequestedHeating = 1000000.0; + RequestedCooling = 0; + + thisUnitary.Initialize(1); + thisUnitary.InitializeModelParams(); + thisUnitary.doStep(*state, RequestedCooling, RequestedHeating, Requested_Humidification, Requested_Dehumidification, DesignMinVR); + + effectiveRuntimeFraction = thisUnitary.CalculatePartRuntimeFraction( + DesignMinVR, currentSettings.Supply_Air_Ventilation_Volume * state->dataEnvrn->StdRhoAir, 0, 0, 0, 0, 0, 0); + + // EXPECT_EQ(thisUnitary.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::SupplyTemperature); + // EXPECT_EQ(currentSettings.Mode, 1); + // EXPECT_EQ(currentSettings.oMode.ModeName, "Mode1 Optimal Power"); + // EXPECT_EQ(currentSettings.ElectricalPower + currentSettings.SupplyFanElectricPower, 100 * effectiveRuntimeFraction); + + // 5. Check that electric power is optimized correctly for ventilation-only + Tra = 25; + Tsa = -25; + + inletNode.Temp = Tra; + inletNode.Enthalpy = PsyHFnTdbW(inletNode.Temp, inletNode.HumRat); + secondaryInletNode.Temp = Tsa; + secondaryInletNode.Enthalpy = PsyHFnTdbW(secondaryInletNode.Temp, secondaryInletNode.HumRat); + InitZoneHybridUnitaryAirConditioners(*state, 1, 2); + + RequestedHeating = 0; + RequestedCooling = 0; + + thisUnitary.Initialize(1); + thisUnitary.InitializeModelParams(); + thisUnitary.doStep(*state, RequestedCooling, RequestedHeating, Requested_Humidification, Requested_Dehumidification, DesignMinVR); + + effectiveRuntimeFraction = thisUnitary.CalculatePartRuntimeFraction( + DesignMinVR, currentSettings.Supply_Air_Ventilation_Volume * state->dataEnvrn->StdRhoAir, 0, 0, 0, 0, 0, 0); + + // EXPECT_EQ(thisUnitary.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::SupplyTemperature); + // EXPECT_EQ(currentSettings.Mode, 4); + // EXPECT_EQ(currentSettings.oMode.ModeName, "Mode4 Optimal Vent Only"); + // EXPECT_EQ(currentSettings.ElectricalPower + currentSettings.SupplyFanElectricPower, 150 * effectiveRuntimeFraction); + + // 6. Check that standby is still an available option + Tra = 25; + Tsa = -35; + + inletNode.Temp = Tra; + inletNode.Enthalpy = PsyHFnTdbW(inletNode.Temp, inletNode.HumRat); + secondaryInletNode.Temp = Tsa; + secondaryInletNode.Enthalpy = PsyHFnTdbW(secondaryInletNode.Temp, secondaryInletNode.HumRat); + InitZoneHybridUnitaryAirConditioners(*state, 1, 2); + + RequestedHeating = 100000.0; + RequestedCooling = 0; + + thisUnitary.Initialize(1); + thisUnitary.InitializeModelParams(); + thisUnitary.doStep(*state, RequestedCooling, RequestedHeating, Requested_Humidification, Requested_Dehumidification, DesignMinVR); + + // EXPECT_EQ(thisUnitary.ObjectiveFunction, HybridEvapCoolingModel::ObjectiveFunctionType::SupplyTemperature); + // EXPECT_EQ(currentSettings.Mode, 0); + // EXPECT_EQ(currentSettings.oMode.ModeName, "Mode0 Standby"); + // EXPECT_EQ(currentSettings.ElectricalPower + currentSettings.SupplyFanElectricPower, 5); +} + } // namespace EnergyPlus