diff --git a/src/EnergyPlus/DataRuntimeLanguage.hh b/src/EnergyPlus/DataRuntimeLanguage.hh index 0106a94deb5..5bfc09c0425 100644 --- a/src/EnergyPlus/DataRuntimeLanguage.hh +++ b/src/EnergyPlus/DataRuntimeLanguage.hh @@ -394,9 +394,11 @@ namespace DataRuntimeLanguage { ErlValueType Value; // values taken by Erl variables bool ReadOnly; // true if Erl variable is read-only bool SetByExternalInterface; // set to true if value is set by ExternalInterface + bool SetByGlobalVariable; + bool SetByInternalVariable; // Default Constructor - ErlVariableType() : StackNum(0), ReadOnly(false), SetByExternalInterface(false) + ErlVariableType() : StackNum(0), ReadOnly(false), SetByExternalInterface(false), SetByGlobalVariable(false), SetByInternalVariable(false) { } }; diff --git a/src/EnergyPlus/EMSManager.cc b/src/EnergyPlus/EMSManager.cc index 9ab307a9618..60d9b47e610 100644 --- a/src/EnergyPlus/EMSManager.cc +++ b/src/EnergyPlus/EMSManager.cc @@ -809,6 +809,7 @@ namespace EMSManager { } else { VariableNum = RuntimeLanguageProcessor::NewEMSVariable(state, cAlphaArgs(1), 0); state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).ErlVariableNum = VariableNum; + state.dataRuntimeLang->ErlVariable(VariableNum).SetByInternalVariable = true; } state.dataRuntimeLang->EMSInternalVarsUsed(InternVarNum).UniqueIDName = cAlphaArgs(2); diff --git a/src/EnergyPlus/RuntimeLanguageProcessor.cc b/src/EnergyPlus/RuntimeLanguageProcessor.cc index 845d80a62f0..095f9ab902a 100644 --- a/src/EnergyPlus/RuntimeLanguageProcessor.cc +++ b/src/EnergyPlus/RuntimeLanguageProcessor.cc @@ -816,7 +816,6 @@ ErlValueType EvaluateStack(EnergyPlusData &state, int const StackNum) ReturnValue.Number = 0.0; auto const &thisErlStack = state.dataRuntimeLang->ErlStack(StackNum); - InstructionNum = 1; while (InstructionNum <= thisErlStack.NumInstructions) { @@ -1799,9 +1798,15 @@ ErlValueType EvaluateExpression(EnergyPlusData &state, int const ExpressionNum, if (thisErlVar.Value.initialized) { // check that value has been initialized thisOperand = thisErlVar.Value; } else { // value has never been set - ReturnValue.Type = Value::Error; - ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!"; - if (!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) { + // During setup (before simulation), we want to avoid initializing variables to zero without throwing an error. + // Throw the error, and write it to edd file, if variable is uninitialized and is *not* a global or internal variable. + // The assumption is that if we made it here for a global variable, it is initialized in another program. + // E.g., if it's initialized in a program with BeginNewEnvironment calling point, setup won't set it but simulation will. + if ((!state.dataGlobal->DoingSizing && !state.dataGlobal->KickOffSimulation && !state.dataEMSMgr->FinishProcessingUserInput) || + (!(thisErlVar.SetByGlobalVariable || thisErlVar.SetByInternalVariable))) { + + ReturnValue.Type = Value::Error; + ReturnValue.Error = "EvaluateExpression: Variable = '" + thisErlVar.Name + "' used in expression has not been initialized!"; // check if this is an arg in CurveValue, if (thisErlExpression.Operator != @@ -2972,6 +2977,8 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) // Initialize variables for the ExternalInterface variables. // This object requires an initial value. ExternalInterfaceInitializeErlVariable(state, VariableNum, SetErlValueNumber(rNumericArgs(1)), false); + } else { + state.dataRuntimeLang->ErlVariable(VariableNum).SetByGlobalVariable = true; } } } @@ -3007,7 +3014,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (!errFlag) { VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0); if (VariableNum > 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}", cAlphaFieldNames(1))); ShowContinueError(state, "Name conflicts with an existing variable name"); ErrorsFound = true; @@ -3022,11 +3029,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) int CurveIndexNum = GetCurveIndex(state, cAlphaArgs(2)); // curve name if (CurveIndexNum == 0) { if (lAlphaFieldBlanks(2)) { - ShowSevereError(state, format("{}{}=\"{} blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Blank {}", cAlphaFieldNames(2))); ShowContinueError(state, "Blank entry for curve or table name is not allowed"); } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "Curve or table was not found."); } @@ -3067,7 +3074,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (!errFlag) { VariableNum = FindEMSVariable(state, cAlphaArgs(1), 0); if (VariableNum > 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}", cAlphaFieldNames(1))); ShowContinueError(state, "Name conflicts with an existing variable name"); ErrorsFound = true; @@ -3085,11 +3092,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) if (ConstructNum == 0) { if (lAlphaFieldBlanks(2)) { - ShowSevereError(state, format("{}{}=\"{} blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" blank field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Blank {}", cAlphaFieldNames(2))); ShowContinueError(state, "Blank entry for construction name is not allowed"); } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "Construction was not found."); } @@ -3204,7 +3211,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) VariableNum = FindEMSVariable(state, cAlphaArgs(2), 0); // Still need to check for conflicts with program and function names too if (VariableNum == 0) { // did not find it - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "Did not find a match with an EMS variable name"); ErrorsFound = true; @@ -3238,7 +3245,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) state.dataRuntimeLang->TrendVariable(TrendNum).TimeARR(loop - 1) - state.dataGlobal->TimeStepZone; // fractional hours } } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={:.2T}", cNumericFieldNames(1), rNumericArgs(1))); ShowContinueError(state, "must be greater than zero"); ErrorsFound = true; @@ -3335,7 +3342,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!UnitsA.empty() && !UnitsB.empty()) { if (UnitsA != UnitsB) { - ShowWarningError(state, format("{}{}=\"{} mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowWarningError(state, format("{}{}=\"{}\" mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA)); ShowContinueError(state, format("...{}=\"{}\" (will be used)", cAlphaFieldNames(6), UnitsB)); } @@ -3361,7 +3368,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!Found) { StackNum = 0; - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(5), cAlphaArgs(5))); ShowContinueError(state, "EMS program or subroutine not found."); ErrorsFound = true; @@ -3374,11 +3381,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) if (VariableNum == 0) { if (lAlphaFieldBlanks(5)) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "EMS variable not found among global variables."); } else if (StackNum != 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, format("EMS variable not found among local variables in {}", cAlphaArgs(5))); } @@ -3397,7 +3404,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(3) == "SUMMED") { sovStoreType = OutputProcessor::StoreType::Sum; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(3), cAlphaArgs(3))); ShowContinueError(state, "...valid values are Averaged or Summed."); ErrorsFound = true; @@ -3408,7 +3415,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(4) == "SYSTEMTIMESTEP") { sovTimeStepType = OutputProcessor::TimeStepType::System; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4))); ShowContinueError(state, "...valid values are ZoneTimestep or SystemTimestep."); ErrorsFound = true; @@ -3508,7 +3515,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!UnitsA.empty() && !UnitsB.empty()) { if (UnitsA != UnitsB) { - ShowWarningError(state, format("{}{}=\"{} mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowWarningError(state, format("{}{}=\"{}\" mismatched units.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("...Units entered in {} (deprecated use)=\"{}\"", cAlphaFieldNames(1), UnitsA)); ShowContinueError(state, format("...{}=\"{}\" (will be used)", cAlphaFieldNames(9), UnitsB)); } @@ -3534,7 +3541,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } if (!Found) { StackNum = 0; - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4))); ShowContinueError(state, "EMS program or subroutine not found."); ErrorsFound = true; @@ -3546,11 +3553,11 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) VariableNum = FindEMSVariable(state, cAlphaArgs(2), StackNum); if (VariableNum == 0) { if (lAlphaFieldBlanks(4)) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, "EMS variable not found among global variables."); } else if (StackNum != 0) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(2), cAlphaArgs(2))); ShowContinueError(state, format("EMS variable not found among local variables in {}", cAlphaArgs(5))); } @@ -3571,7 +3578,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(3) == "SYSTEMTIMESTEP") { sovTimeStepType = OutputProcessor::TimeStepType::System; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(4), cAlphaArgs(4))); ShowContinueError(state, "...valid values are ZoneTimestep or SystemTimestep."); ErrorsFound = true; @@ -3582,7 +3589,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) static_cast(getEnumValue(Constant::eResourceNamesUC, Util::makeUPPER(cAlphaArgs(5)))); if (resource == Constant::eResource::Invalid) { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(5), cAlphaArgs(5))); ErrorsFound = true; } @@ -3599,7 +3606,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(6) == "SYSTEM") { sovGroup = OutputProcessor::Group::HVAC; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(6), cAlphaArgs(6))); ErrorsFound = true; } @@ -3650,7 +3657,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) } else if (cAlphaArgs(7) == "HEATRECOVERYFORHEATING") { sovEndUseCat = OutputProcessor::EndUseCat::HeatRecoveryForHeating; } else { - ShowSevereError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowSevereError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={}", cAlphaFieldNames(7), cAlphaArgs(7))); ErrorsFound = true; } @@ -3661,7 +3668,7 @@ void GetRuntimeLanguageUserInput(EnergyPlusData &state) sovEndUseCat == OutputProcessor::EndUseCat::Chillers || sovEndUseCat == OutputProcessor::EndUseCat::Boilers || sovEndUseCat == OutputProcessor::EndUseCat::Baseboard || sovEndUseCat == OutputProcessor::EndUseCat::HeatRecoveryForCooling || sovEndUseCat == OutputProcessor::EndUseCat::HeatRecoveryForHeating)) { - ShowWarningError(state, format("{}{}=\"{} invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); + ShowWarningError(state, format("{}{}=\"{}\" invalid field.", RoutineName, cCurrentModuleObject, cAlphaArgs(1))); ShowContinueError(state, format("Invalid {}={} for {}={}", cAlphaFieldNames(5), cAlphaArgs(5), cAlphaFieldNames(7), cAlphaArgs(7))); ShowContinueError(state, format("Field {} is reset from {} to EnergyTransfer", cAlphaFieldNames(5), cAlphaArgs(5))); diff --git a/src/EnergyPlus/SimulationManager.cc b/src/EnergyPlus/SimulationManager.cc index 0bd4e66358b..77272d52c8d 100644 --- a/src/EnergyPlus/SimulationManager.cc +++ b/src/EnergyPlus/SimulationManager.cc @@ -268,6 +268,7 @@ namespace SimulationManager { state.dataGlobal->KickOffSimulation = true; Weather::ResetEnvironmentCounter(state); + SetupSimulation(state, ErrorsFound); FaultsManager::CheckAndReadFaults(state); @@ -330,6 +331,7 @@ namespace SimulationManager { ReportNodeConnections(state); } SystemReports::CreateEnergyReportStructure(state); + bool anyEMSRan; // point to finish setup processing EMS, sensor ready now EMSManager::ManageEMS(state, EMSManager::EMSCallFrom::SetupSimulation, anyEMSRan, ObjexxFCL::Optional_int_const()); diff --git a/testfiles/HospitalBaselineReheatReportEMS.idf b/testfiles/HospitalBaselineReheatReportEMS.idf index f5ccd6a8798..e30e1ff97f4 100644 --- a/testfiles/HospitalBaselineReheatReportEMS.idf +++ b/testfiles/HospitalBaselineReheatReportEMS.idf @@ -77655,6 +77655,43 @@ Flr_1_Stor_DT2, !- Flr_1_Waiting_DT2; !- + EnergyManagementSystem:GlobalVariable, + A, !- Erl Variable 1 Name + B, !- Erl Variable 2 Name + C, !- Erl Variable 3 Name + D, !- + E, !- + F, !- + G, !- + H, !- + I, !- + J, !- + K, !- + L, !- + M, !- + N, !- + O, !- + P, !- + Q, !- + R, !- + S, !- + T, !- + U, !- + V, !- + W, !- + X, !- + Y, !- + Z, !- + AA, !- + BB, !- + CC, !- + DD, !- + EE, !- + FF, !- + GG, !- + HH, !- + II; !- + !- =========== ALL OBJECTS IN CLASS: ENERGYMANAGEMENTSYSTEM:OUTPUTVARIABLE =========== EnergyManagementSystem:OutputVariable, diff --git a/testfiles/RetailPackagedTESCoil.idf b/testfiles/RetailPackagedTESCoil.idf index 4117d73a7dd..d4bb2ebb435 100644 --- a/testfiles/RetailPackagedTESCoil.idf +++ b/testfiles/RetailPackagedTESCoil.idf @@ -7949,7 +7949,7 @@ SET SumReliefMCT = SumReliefMCT + (h_Relief_4 * mdotRelief_4 ); !- EnergyManagementSystem:Program, - IntializeParameters, !- Name + InitializeParameters, !- Name Set CV_Height = 1.0, !- Program Line 1 Set CV_effWidth = 40.0, !- Program Line 2 Set CV_crossSectArea = CV_Height * CV_effWidth, !- @@ -8066,8 +8066,10 @@ EnergyManagementSystem:GlobalVariable, Troof, !- Erl Variable 1 Name - CV_Height, !- Erl Variable 2 Name - CV_crossSectArea, !- Erl Variable 3 Name + DeltaT, !- Erl Variable 2 Name + ratioT, !- Erl Variable 3 Name + CV_Height, !- + CV_crossSectArea, !- C_v, !- rhoAir, !- CpAir, !- @@ -8101,7 +8103,7 @@ EnergyManagementSystem:ProgramCallingManager, Model Flat Roof Microclimate, !- Name BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point - IntializeParameters, !- Program Name 1 + InitializeParameters, !- Program Name 1 ModelFlatRoofMicroClime, !- Program Name 2 ApplyMicroClimeActuators;!- Program Name 3 @@ -8115,7 +8117,7 @@ Run SumReliefAirMCTterm, !- Run CalcWindTerms, !- Run CalcBouyancyTerms, !- - SEt Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- + Set Numerator = WindMCT + NatBouyMCT + SumHATroof + QdotCond + SumReliefMCT, !- Set Denominator = WindMC + NatBouyMC + SumHAroof + SumIntakeMdotCp, !- Set Troof = Numerator / Denominator, !- IF Ta < 2.0, !- diff --git a/testfiles/_ResidentialBase.idf b/testfiles/_ResidentialBase.idf index fc17d29a393..701e3cbcac0 100644 --- a/testfiles/_ResidentialBase.idf +++ b/testfiles/_ResidentialBase.idf @@ -7785,6 +7785,11 @@ EnergyManagementSystem:GlobalVariable, natural_vent_program_Qwhf; !- Erl Variable 1 Name + EnergyManagementSystem:GlobalVariable, + Qducts, !- Erl Variable 1 Name + Qsupply, !- Erl Variable 2 Name + Qexhaust; !- Erl Variable 3 Name + !- =========== ALL OBJECTS IN CLASS: ENERGYMANAGEMENTSYSTEM:OUTPUTVARIABLE =========== EnergyManagementSystem:OutputVariable, diff --git a/tst/EnergyPlus/unit/EMSManager.unit.cc b/tst/EnergyPlus/unit/EMSManager.unit.cc index db184e94756..ae89b884d98 100644 --- a/tst/EnergyPlus/unit/EMSManager.unit.cc +++ b/tst/EnergyPlus/unit/EMSManager.unit.cc @@ -52,6 +52,7 @@ // EnergyPlus Headers #include "Fixtures/EnergyPlusFixture.hh" +#include #include #include #include @@ -936,7 +937,7 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable2) state->dataEMSMgr->FinishProcessingUserInput = true; bool anyRan; EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); - // Expect the variable to not yet be initialized, call EvaluateExpresssion and check argument + // Expect the variable to not yet be initialized, call EvaluateExpression and check argument ErlValueType ReturnValue; bool seriousErrorFound = false; @@ -958,6 +959,181 @@ TEST_F(EnergyPlusFixture, TestUnInitializedEMSVariable2) EXPECT_FALSE(seriousErrorFound); } +TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef1) +{ + // test for #11360 - EMS variable initialized after reference, outside of ManageSimulation + std::string const idf_objects = delimited_string({ + + "EnergyManagementSystem:Program,", + " ev_discharge_program, !- Name", + " Set power_mult = site_temp_adj, !- Program Line 1", + " Set site_temp_adj = 0.1; !- Program Line 2", + + "EnergyManagementSystem:ProgramCallingManager,", + " ev_discharge_pcm, !- Name", + " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", + " ev_discharge_program; !- Program Name 1", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + state->init_state(*state); + + int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + EXPECT_EQ(internalVarNum, 0); + + bool anyRan; + EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::SetupSimulation, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyRan, ObjexxFCL::Optional_int_const()); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + EXPECT_FALSE(state->dataEMSMgr->GetEMSUserInput); + ASSERT_THROW(EMSManager::ManageEMS(*state, EMSManager::EMSCallFrom::BeginTimestepBeforePredictor, anyRan, ObjexxFCL::Optional_int_const()), + EnergyPlus::FatalError); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); + + // Expect the variable to not yet be initialized, call EvaluateExpression and check argument + bool seriousErrorFound = false; + ErlValueType ReturnValue = RuntimeLanguageProcessor::EvaluateExpression( + *state, + state->dataRuntimeLang->ErlStack(Util::FindItemInList("EV_DISCHARGE_PROGRAM", state->dataRuntimeLang->ErlStack)).Instruction(1).Argument2, + seriousErrorFound); + EXPECT_TRUE(seriousErrorFound); + + const std::string expected_error = delimited_string({ + " ** Severe ** Problem found in EMS EnergyPlus Runtime Language.", + " ** ~~~ ** Erl program name: EV_DISCHARGE_PROGRAM", + " ** ~~~ ** Erl program line number: 1", + " ** ~~~ ** Erl program line text: SET POWER_MULT = SITE_TEMP_ADJ", + " ** ~~~ ** Error message: *** Error: EvaluateExpression: Variable = 'SITE_TEMP_ADJ' used in expression has not been initialized! " + "*** ", + " ** ~~~ ** Environment=, at Simulation time= 00:-15 - 00:00", + " ** Fatal ** Previous EMS error caused program termination.", + " ...Summary of Errors that led to program termination:", + " ..... Reference severe error count=1", + " ..... Last severe error=Problem found in EMS EnergyPlus Runtime Language.", + }); + + compare_err_stream(expected_error); +} + +TEST_F(EnergyPlusFixture, TestEMSVariableInitAfterRef2) +{ + // test for #11360 - EMS variable initialized after reference, within ManageSimulation + std::string const idf_objects = delimited_string({ + "Version," + DataStringGlobals::MatchVersion + ";", + + "RunPeriod,", + " Run Period 1, !- Name", + " 1, !- Begin Month", + " 1, !- Begin Day of Month", + " 2007, !- Begin Year", + " 1, !- End Month", + " 1, !- End Day of Month", + " 2007, !- End Year", + " Monday, !- Day of Week for Start Day", + " No, !- Use Weather File Holidays and Special Days", + " No, !- Use Weather File Daylight Saving Period", + " No, !- Apply Weekend Holiday Rule", + " Yes, !- Use Weather File Rain Indicators", + " Yes; !- Use Weather File Snow Indicators", + + "SimulationControl,", + " No, !- Do Zone Sizing Calculation", + " No, !- Do System Sizing Calculation", + " No, !- Do Plant Sizing Calculation", + " No, !- Run Simulation for Sizing Periods", + " Yes, !- Run Simulation for Weather File Run Periods", + " , !- Do HVAC Sizing Simulation for Sizing Periods", + " ; !- Maximum Number of HVAC Sizing Simulation Passes", + + "Site:Location,", + " Denver Stapleton Intl Arpt CO USA WMO=724690, !- Name", + " 39.77, !- Latitude {deg}", + " -104.87, !- Longitude {deg}", + " -7.00, !- Time Zone {hr}", + " 1611.00; !- Elevation {m}", + + "Material,", + " Concrete Block, !- Name", + " MediumRough, !- Roughness", + " 0.1014984, !- Thickness {m}", + " 0.3805070, !- Conductivity {W/m-K}", + " 608.7016, !- Density {kg/m3}", + " 836.8000; !- Specific Heat {J/kg-K}", + + "Construction,", + " ConcConstruction, !- Name", + " Concrete Block; !- Outside Layer", + + "BuildingSurface:Detailed," + " Wall, !- Name", + " Wall, !- Surface Type", + " ConcConstruction, !- Construction Name", + " Zone, !- Zone Name", + " , !- Space Name", + " Outdoors, !- Outside Boundary Condition", + " , !- Outside Boundary Condition Object", + " SunExposed, !- Sun Exposure", + " WindExposed, !- Wind Exposure", + " 0.5000000, !- View Factor to Ground", + " 4, !- Number of Vertices", + " 0.000000,0.000000,10.00000, !- X,Y,Z ==> Vertex 1 {m}", + " 0.000000,0.000000,0, !- X,Y,Z ==> Vertex 2 {m}", + " 10.00000,0.000000,0, !- X,Y,Z ==> Vertex 3 {m}", + " 10.00000,0.000000,10.00000; !- X,Y,Z ==> Vertex 4 {m}", + + "Zone," + " Zone, !- Name", + " 0, !- Direction of Relative North {deg}", + " 6.000000, !- X Origin {m}", + " 6.000000, !- Y Origin {m}", + " 0, !- Z Origin {m}", + " 1, !- Type", + " 1, !- Multiplier", + " autocalculate, !- Ceiling Height {m}", + " autocalculate; !- Volume {m3}", + + "EnergyManagementSystem:Program,", + " ev_discharge_program, !- Name", + " Set power_mult = site_temp_adj, !- Program Line 1", + " Set site_temp_adj = 0.1; !- Program Line 2", + + "EnergyManagementSystem:ProgramCallingManager,", + " ev_discharge_pcm, !- Name", + " BeginTimestepBeforePredictor, !- EnergyPlus Model Calling Point", + " ev_discharge_program; !- Program Name 1", + }); + + ASSERT_TRUE(process_idf(idf_objects)); + state->init_state(*state); + + state->dataWeather->WeatherFileExists = true; + state->files.inputWeatherFilePath.filePath = configured_source_directory() / "weather/USA_CO_Golden-NREL.724666_TMY3.epw"; + + int internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + EXPECT_EQ(internalVarNum, 0); + + EXPECT_TRUE(state->dataEMSMgr->GetEMSUserInput); + ASSERT_THROW(SimulationManager::ManageSimulation(*state), EnergyPlus::FatalError); + + internalVarNum = RuntimeLanguageProcessor::FindEMSVariable(*state, "site_temp_adj", 1); + ASSERT_GT(internalVarNum, 0); + EXPECT_FALSE(state->dataRuntimeLang->ErlVariable(internalVarNum).Value.initialized); +} + TEST_F(EnergyPlusFixture, EMSManager_CheckIfAnyEMS_OutEMS) { std::string const idf_objects = delimited_string({