Skip to content

Commit

Permalink
Merge pull request #8519 from jcyuan2020/IdealLoadsAirSystem_EMS
Browse files Browse the repository at this point in the history
Ideal loads air system ems override enthalpy update correction
  • Loading branch information
Myoldmopar committed Mar 5, 2021
2 parents 964ef1d + dbc3faf commit 5f676db
Show file tree
Hide file tree
Showing 2 changed files with 360 additions and 8 deletions.
19 changes: 11 additions & 8 deletions src/EnergyPlus/PurchasedAirManager.cc
Original file line number Diff line number Diff line change
Expand Up @@ -2698,15 +2698,16 @@ void CalcPurchAirLoads(EnergyPlusData &state,

} // Cooling or heating required

// EMS override point Purch air supply temp and humidty ratio ..... but only if unit is on, SupplyMassFlowRate>0.0
if (PurchAir(PurchAirNum).EMSOverrideSupplyTempOn) {
PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).EMSValueSupplyTemp;
}
if (PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn) {
PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).EMSValueSupplyHumRat;
}

if (SupplyMassFlowRate > 0.0) {
// EMS override point Purch air supply temp and humidty ratio ..... but only if unit is on, SupplyMassFlowRate>0.0
if (PurchAir(PurchAirNum).EMSOverrideSupplyTempOn) {
PurchAir(PurchAirNum).SupplyTemp = PurchAir(PurchAirNum).EMSValueSupplyTemp;
}
if (PurchAir(PurchAirNum).EMSOverrideSupplyHumRatOn) {
PurchAir(PurchAirNum).SupplyHumRat = PurchAir(PurchAirNum).EMSValueSupplyHumRat;
}
SupplyEnthalpy = PsyHFnTdbW(PurchAir(PurchAirNum).SupplyTemp, PurchAir(PurchAirNum).SupplyHumRat);

// compute coil loads
if ((PurchAir(PurchAirNum).SupplyHumRat == PurchAir(PurchAirNum).MixedAirHumRat) &&
(PurchAir(PurchAirNum).SupplyTemp == PurchAir(PurchAirNum).MixedAirTemp)) {
Expand Down Expand Up @@ -2861,6 +2862,8 @@ void CalcPurchAirLoads(EnergyPlusData &state,
PurchAir(PurchAirNum).OALatOutput = 0.0;
PurchAir(PurchAirNum).MixedAirTemp = Node(RecircNodeNum).Temp;
PurchAir(PurchAirNum).MixedAirHumRat = Node(RecircNodeNum).HumRat;
PurchAir(PurchAirNum).SupplyTemp = Node(InNodeNum).Temp;
PurchAir(PurchAirNum).SupplyHumRat = Node(InNodeNum).HumRat;
}

PurchAir(PurchAirNum).OutdoorAirMassFlowRate = OAMassFlowRate;
Expand Down
349 changes: 349 additions & 0 deletions tst/EnergyPlus/unit/PurchasedAirManager.unit.cc
Original file line number Diff line number Diff line change
Expand Up @@ -943,3 +943,352 @@ TEST_F(ZoneIdealLoadsTest, IdealLoads_NoCapacityTest)
// #8365 Supply air mass flow rate should be zero during heating mode when capacity is limited to zero
EXPECT_EQ(state->dataPurchasedAirMgr->PurchAir(1).SupplyAirMassFlowRate, 0.0);
}

TEST_F(ZoneIdealLoadsTest, IdealLoads_EMSOverrideTest_Revised)
{
std::string const idf_objects = delimited_string({
"Zone,",
" EAST ZONE, !- Name",
" 0, !- Direction of Relative North{ deg }",
" 0, !- X Origin{ m }",
" 0, !- Y Origin{ m }",
" 0, !- Z Origin{ m }",
" 1, !- Type",
" 1, !- Multiplier",
" autocalculate, !- Ceiling Height{ m }",
" autocalculate; !- Volume{ m3 }",

"ZoneHVAC:IdealLoadsAirSystem,",
" ZONE 1 IDEAL LOADS, !- Name",
" , !- Availability Schedule Name",
" Zone Inlet Node, !- Zone Supply Air Node Name",
" Zone Exhaust Node, !- Zone Exhaust Air Node Name",
" , !- System Inlet Air Node Name",
" 50, !- Maximum Heating Supply Air Temperature{ C }",
" 13, !- Minimum Cooling Supply Air Temperature{ C }",
" 0.015, !- Maximum Heating Supply Air Humidity Ratio{ kgWater / kgDryAir }",
" 0.009, !- Minimum Cooling Supply Air Humidity Ratio{ kgWater / kgDryAir }",
" NoLimit, !- Heating Limit",
" autosize, !- Maximum Heating Air Flow Rate{ m3 / s }",
" , !- Maximum Sensible Heating Capacity{ W }",
" NoLimit, !- Cooling Limit",
" autosize, !- Maximum Cooling Air Flow Rate{ m3 / s }",
" , !- Maximum Total Cooling Capacity{ W }",
" , !- Heating Availability Schedule Name",
" , !- Cooling Availability Schedule Name",
" ConstantSupplyHumidityRatio, !- Dehumidification Control Type",
" , !- Cooling Sensible Heat Ratio{ dimensionless }",
" ConstantSupplyHumidityRatio, !- Humidification Control Type",
" , !- Design Specification Outdoor Air Object Name",
" , !- Outdoor Air Inlet Node Name",
" , !- Demand Controlled Ventilation Type",
" , !- Outdoor Air Economizer Type",
" , !- Heat Recovery Type",
" , !- Sensible Heat Recovery Effectiveness{ dimensionless }",
" ; !- Latent Heat Recovery Effectiveness{ dimensionless }",

"ZoneHVAC:EquipmentConnections,",
" EAST ZONE, !- Zone Name",
" ZoneEquipment, !- Zone Conditioning Equipment List Name",
" Zone Inlet Node, !- Zone Air Inlet Node or NodeList Name",
" Zone Exhaust Node, !- Zone Air Exhaust Node or NodeList Name",
" Zone Node, !- Zone Air Node Name",
" Zone Outlet Node; !- Zone Return Air Node Name",

"ZoneHVAC:EquipmentList,",
" ZoneEquipment, !- Name",
" SequentialLoad, !- Load Distribution Scheme",
" ZoneHVAC:IdealLoadsAirSystem, !- Zone Equipment 1 Object Type",
" ZONE 1 IDEAL LOADS, !- Zone Equipment 1 Name",
" 1, !- Zone Equipment 1 Cooling Sequence",
" 1; !- Zone Equipment 1 Heating or No - Load Sequence",

" Output:EnergyManagementSystem, ",
" Verbose, !- Actuator Availability Dictionary Reporting ",
" Verbose, !- Internal Variable Availability Dictionary Reporting ",
" Verbose; !- EMS Runtime Language Debug Output Level ",

"EnergyManagementSystem:Actuator,",
"Mdot,",
"ZONE 1 IDEAL LOADS,",
"Ideal Loads Air System,",
"Air Mass Flow Rate;",

"EnergyManagementSystem:Actuator,",
"Tsupply,",
"ZONE 1 IDEAL LOADS,",
"Ideal Loads Air System,",
"Air TEMPERATURE;",

"EnergyManagementSystem:Actuator,",
"HRsupply,",
"ZONE 1 IDEAL LOADS,",
"Ideal Loads Air System,",
"Air Humidity Ratio;",

"EnergyManagementSystem:Sensor,",
"ZoneAirTemp,",
"EAST ZONE,",
"Zone Mean Air Temperature;",

"EnergyManagementSystem:OutputVariable,",
"MassstromIdealLoad_EMS, ! - Name",
"Mdot, ! - EMS Variable Name",
"Averaged, ! - Type of Data in Variable",
"SystemTimeStep; ! - Update Frequency",

"EnergyManagementSystem:OutputVariable,",
"SupplyTempIdealLoad_EMS, ! - Name",
"Tsupply, ! - EMS Variable Name",
"Averaged, ! - Type of Data in Variable",
"SystemTimeStep; ! - Update Frequency",

"EnergyManagementSystem:ProgramCallingManager,",
"Test inside HVAC system iteration Loop,",
"InsideHVACSystemIterationLoop,",
"Test_InsideHVACSystemIterationLoop;",

"EnergyManagementSystem:Program,",
"Test_InsideHVACSystemIterationLoop,",
"set Mdot = 0.1,",
"set Tsupply = 18,",
"set HRsupply = 0.010;",
});

ASSERT_TRUE(process_idf(idf_objects)); // read idf objects

state->dataGlobal->DoWeathSim = true;

bool ErrorsFound = false;
GetZoneData(*state, ErrorsFound);
state->dataHeatBal->Zone(1).HTSurfaceFirst = 1;
state->dataHeatBal->Zone(1).HTSurfaceLast = 1;
state->dataScheduleMgr->Schedule.allocate(1);
AllocateHeatBalArrays(*state);
EXPECT_FALSE(ErrorsFound); // expect no errors
state->dataZoneEquip->ZoneEquipConfig.allocate(1);

state->dataZoneEquip->ZoneEquipConfig(1).IsControlled = true;
state->dataZoneEquip->ZoneEquipConfig(1).NumInletNodes = 1;
state->dataZoneEquip->ZoneEquipConfig(1).InletNode.allocate(1);
state->dataZoneEquip->ZoneEquipConfig(1).InletNode(1) = 1;

state->dataZoneEquip->ZoneEquipConfig(1).ExhaustNode.allocate(1);
state->dataZoneEquip->ZoneEquipConfig(1).NumExhaustNodes = 1;
state->dataZoneEquip->ZoneEquipConfig(1).ExhaustNode(1) = 2;
state->dataGlobal->TimeStepZone = 0.25;

EMSManager::CheckIfAnyEMS(*state); // get EMS input

state->dataEMSMgr->FinishProcessingUserInput = true;

bool FirstHVACIteration(true);

if (state->dataPurchasedAirMgr->GetPurchAirInputFlag) {
GetPurchasedAir(*state);
state->dataPurchasedAirMgr->GetPurchAirInputFlag = false;
}

state->dataPurchasedAirMgr->PurchAir(1).EMSOverrideMdotOn = true;
state->dataPurchasedAirMgr->PurchAir(1).EMSOverrideSupplyTempOn = true;
state->dataPurchasedAirMgr->PurchAir(1).EMSOverrideSupplyHumRatOn = true;

DataLoopNode::Node(2).Temp = 25.0;
DataLoopNode::Node(2).HumRat = 0.001;

InitPurchasedAir(*state, 1, FirstHVACIteration, 1, 1);
Real64 SysOutputProvided;
Real64 MoistOutputProvided;

bool anyEMSRan;
ManageEMS(*state, EMSManager::EMSCallFrom::HVACIterationLoop, anyEMSRan, ObjexxFCL::Optional_int_const());

state->dataZoneEquip->ZoneEquipConfig(1).ZoneNode = 1;
state->dataPurchasedAirMgr->PurchAir(1).OutdoorAirNodeNum = 2;
state->dataPurchasedAirMgr->PurchAir(1).ZoneRecircAirNodeNum = 1;

CalcPurchAirLoads(*state, 1, SysOutputProvided, MoistOutputProvided, 1, 1);

EXPECT_EQ(state->dataPurchasedAirMgr->PurchAir(1).EMSValueSupplyTemp, 18.0);
EXPECT_EQ(state->dataPurchasedAirMgr->PurchAir(1).EMSValueSupplyHumRat, 0.01);

EXPECT_EQ(EnergyPlus::DataLoopNode::Node(1).Enthalpy, 43431.131);
EXPECT_EQ(EnergyPlus::DataLoopNode::Node(1).HumRat, 0.01);
EXPECT_EQ(EnergyPlus::DataLoopNode::Node(1).Temp, 18.0);
}

TEST_F(ZoneIdealLoadsTest, IdealLoads_EMSOverrideTest_Revised_ZeroFlow)
{
std::string const idf_objects = delimited_string({
"Zone,",
" EAST ZONE, !- Name",
" 0, !- Direction of Relative North{ deg }",
" 0, !- X Origin{ m }",
" 0, !- Y Origin{ m }",
" 0, !- Z Origin{ m }",
" 1, !- Type",
" 1, !- Multiplier",
" autocalculate, !- Ceiling Height{ m }",
" autocalculate; !- Volume{ m3 }",

"ZoneHVAC:IdealLoadsAirSystem,",
" ZONE 1 IDEAL LOADS, !- Name",
" , !- Availability Schedule Name",
" Zone Inlet Node, !- Zone Supply Air Node Name",
" Zone Exhaust Node, !- Zone Exhaust Air Node Name",
" , !- System Inlet Air Node Name",
" 50, !- Maximum Heating Supply Air Temperature{ C }",
" 13, !- Minimum Cooling Supply Air Temperature{ C }",
" 0.015, !- Maximum Heating Supply Air Humidity Ratio{ kgWater / kgDryAir }",
" 0.009, !- Minimum Cooling Supply Air Humidity Ratio{ kgWater / kgDryAir }",
" NoLimit, !- Heating Limit",
" autosize, !- Maximum Heating Air Flow Rate{ m3 / s }",
" , !- Maximum Sensible Heating Capacity{ W }",
" NoLimit, !- Cooling Limit",
" autosize, !- Maximum Cooling Air Flow Rate{ m3 / s }",
" , !- Maximum Total Cooling Capacity{ W }",
" , !- Heating Availability Schedule Name",
" , !- Cooling Availability Schedule Name",
" ConstantSupplyHumidityRatio, !- Dehumidification Control Type",
" , !- Cooling Sensible Heat Ratio{ dimensionless }",
" ConstantSupplyHumidityRatio, !- Humidification Control Type",
" , !- Design Specification Outdoor Air Object Name",
" , !- Outdoor Air Inlet Node Name",
" , !- Demand Controlled Ventilation Type",
" , !- Outdoor Air Economizer Type",
" , !- Heat Recovery Type",
" , !- Sensible Heat Recovery Effectiveness{ dimensionless }",
" ; !- Latent Heat Recovery Effectiveness{ dimensionless }",

"ZoneHVAC:EquipmentConnections,",
" EAST ZONE, !- Zone Name",
" ZoneEquipment, !- Zone Conditioning Equipment List Name",
" Zone Inlet Node, !- Zone Air Inlet Node or NodeList Name",
" Zone Exhaust Node, !- Zone Air Exhaust Node or NodeList Name",
" Zone Node, !- Zone Air Node Name",
" Zone Outlet Node; !- Zone Return Air Node Name",

"ZoneHVAC:EquipmentList,",
" ZoneEquipment, !- Name",
" SequentialLoad, !- Load Distribution Scheme",
" ZoneHVAC:IdealLoadsAirSystem, !- Zone Equipment 1 Object Type",
" ZONE 1 IDEAL LOADS, !- Zone Equipment 1 Name",
" 1, !- Zone Equipment 1 Cooling Sequence",
" 1; !- Zone Equipment 1 Heating or No - Load Sequence",

" Output:EnergyManagementSystem, ",
" Verbose, !- Actuator Availability Dictionary Reporting ",
" Verbose, !- Internal Variable Availability Dictionary Reporting ",
" Verbose; !- EMS Runtime Language Debug Output Level ",

"EnergyManagementSystem:Actuator,",
"Mdot,",
"ZONE 1 IDEAL LOADS,",
"Ideal Loads Air System,",
"Air Mass Flow Rate;",

"EnergyManagementSystem:Actuator,",
"Tsupply,",
"ZONE 1 IDEAL LOADS,",
"Ideal Loads Air System,",
"Air TEMPERATURE;",

"EnergyManagementSystem:Actuator,",
"HRsupply,",
"ZONE 1 IDEAL LOADS,",
"Ideal Loads Air System,",
"Air Humidity Ratio;",

"EnergyManagementSystem:Sensor,",
"ZoneAirTemp,",
"EAST ZONE,",
"Zone Mean Air Temperature;",

"EnergyManagementSystem:OutputVariable,",
"MassstromIdealLoad_EMS, ! - Name",
"Mdot, ! - EMS Variable Name",
"Averaged, ! - Type of Data in Variable",
"SystemTimeStep; ! - Update Frequency",

"EnergyManagementSystem:OutputVariable,",
"SupplyTempIdealLoad_EMS, ! - Name",
"Tsupply, ! - EMS Variable Name",
"Averaged, ! - Type of Data in Variable",
"SystemTimeStep; ! - Update Frequency",

"EnergyManagementSystem:ProgramCallingManager,",
"Test inside HVAC system iteration Loop,",
"InsideHVACSystemIterationLoop,",
"Test_InsideHVACSystemIterationLoop;",

"EnergyManagementSystem:Program,",
"Test_InsideHVACSystemIterationLoop,",
"set Mdot = 0.0,",
"set Tsupply = 18,",
"set HRsupply = 0.010;",
});

ASSERT_TRUE(process_idf(idf_objects)); // read idf objects

state->dataGlobal->DoWeathSim = true;

bool ErrorsFound = false;
GetZoneData(*state, ErrorsFound);
state->dataHeatBal->Zone(1).HTSurfaceFirst = 1;
state->dataHeatBal->Zone(1).HTSurfaceLast = 1;
state->dataScheduleMgr->Schedule.allocate(1);
AllocateHeatBalArrays(*state);
EXPECT_FALSE(ErrorsFound); // expect no errors
state->dataZoneEquip->ZoneEquipConfig.allocate(1);

state->dataZoneEquip->ZoneEquipConfig(1).IsControlled = true;
state->dataZoneEquip->ZoneEquipConfig(1).NumInletNodes = 1;
state->dataZoneEquip->ZoneEquipConfig(1).InletNode.allocate(1);
state->dataZoneEquip->ZoneEquipConfig(1).InletNode(1) = 1;

state->dataZoneEquip->ZoneEquipConfig(1).ExhaustNode.allocate(1);
state->dataZoneEquip->ZoneEquipConfig(1).NumExhaustNodes = 1;
state->dataZoneEquip->ZoneEquipConfig(1).ExhaustNode(1) = 2;
state->dataGlobal->TimeStepZone = 0.25;

EMSManager::CheckIfAnyEMS(*state); // get EMS input

state->dataEMSMgr->FinishProcessingUserInput = true;

bool FirstHVACIteration(true);

if (state->dataPurchasedAirMgr->GetPurchAirInputFlag) {
GetPurchasedAir(*state);
state->dataPurchasedAirMgr->GetPurchAirInputFlag = false;
}

state->dataPurchasedAirMgr->PurchAir(1).EMSOverrideMdotOn = true;
state->dataPurchasedAirMgr->PurchAir(1).EMSOverrideSupplyTempOn = true;
state->dataPurchasedAirMgr->PurchAir(1).EMSOverrideSupplyHumRatOn = true;

DataLoopNode::Node(2).Temp = 25.0;
DataLoopNode::Node(2).HumRat = 0.001;

InitPurchasedAir(*state, 1, FirstHVACIteration, 1, 1);
Real64 SysOutputProvided;
Real64 MoistOutputProvided;

bool anyEMSRan;
ManageEMS(*state, EMSManager::EMSCallFrom::HVACIterationLoop, anyEMSRan, ObjexxFCL::Optional_int_const());

state->dataZoneEquip->ZoneEquipConfig(1).ZoneNode = 1;
state->dataPurchasedAirMgr->PurchAir(1).OutdoorAirNodeNum = 2;
state->dataPurchasedAirMgr->PurchAir(1).ZoneRecircAirNodeNum = 1;

CalcPurchAirLoads(*state, 1, SysOutputProvided, MoistOutputProvided, 1, 1);

EXPECT_EQ(SysOutputProvided, 0.0);
EXPECT_EQ(MoistOutputProvided, 0.0);

EXPECT_EQ(state->dataPurchasedAirMgr->PurchAir(1).EMSValueSupplyTemp, 18.0);
EXPECT_EQ(state->dataPurchasedAirMgr->PurchAir(1).EMSValueSupplyHumRat, 0.01);

EXPECT_EQ(EnergyPlus::DataLoopNode::Node(1).Enthalpy, 0.0);
EXPECT_EQ(EnergyPlus::DataLoopNode::Node(1).HumRat, 0.0);
EXPECT_EQ(EnergyPlus::DataLoopNode::Node(1).Temp, 0.0);
}

5 comments on commit 5f676db

@nrel-bot-3
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

develop (Myoldmopar) - x86_64-MacOS-10.15-clang-11.0.0: OK (2339 of 2339 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2b
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

develop (Myoldmopar) - x86_64-Linux-Ubuntu-18.04-gcc-7.5: OK (2359 of 2359 tests passed, 0 test warnings)

Build Badge Test Badge

@nrel-bot-2b
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

develop (Myoldmopar) - x86_64-Linux-Ubuntu-18.04-gcc-7.5-UnitTestsCoverage-Debug: OK (1615 of 1615 tests passed, 0 test warnings)

Build Badge Test Badge Coverage Badge

@nrel-bot-2b
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

develop (Myoldmopar) - x86_64-Linux-Ubuntu-18.04-gcc-7.5-IntegrationCoverage-Debug: OK (726 of 727 tests passed, 0 test warnings)

Failures:\n

integration Test Summary

  • Passed: 726
  • Timeout: 1

Build Badge Test Badge Coverage Badge

@nrel-bot
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

develop (Myoldmopar) - Win64-Windows-10-VisualStudio-16: OK (2310 of 2310 tests passed, 0 test warnings)

Build Badge Test Badge

Please sign in to comment.