Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <vector>
50 :
51 : // EnergyPlus Headers
52 : #include <EnergyPlus/Data/EnergyPlusData.hh>
53 : #include <EnergyPlus/DataErrorTracking.hh>
54 : #include <EnergyPlus/DataReportingFlags.hh>
55 : #include <EnergyPlus/DataSizing.hh>
56 : #include <EnergyPlus/DataSystemVariables.hh>
57 : #include <EnergyPlus/DisplayRoutines.hh>
58 : #include <EnergyPlus/EMSManager.hh>
59 : #include <EnergyPlus/ExteriorEnergyUse.hh>
60 : #include <EnergyPlus/FluidProperties.hh>
61 : #include <EnergyPlus/HVACSizingSimulationManager.hh>
62 : #include <EnergyPlus/HeatBalanceManager.hh>
63 : #include <EnergyPlus/Plant/DataPlant.hh>
64 : #include <EnergyPlus/PlantPipingSystemsManager.hh>
65 : #include <EnergyPlus/SQLiteProcedures.hh>
66 : #include <EnergyPlus/SimulationManager.hh>
67 : #include <EnergyPlus/UtilityRoutines.hh>
68 : #include <EnergyPlus/WeatherManager.hh>
69 :
70 : namespace EnergyPlus {
71 :
72 4 : void HVACSizingSimulationManager::DetermineSizingAnalysesNeeded(EnergyPlusData &state)
73 : {
74 : // currently the only type of advanced sizing analysis available is for coincident plant sizing
75 : // expect more specialized sizing analysis objects to be added, so minimizing code here and jump to a worker method once we know an instance is to
76 : // be created.
77 :
78 : // Loop over PlantSizData struct and find those plant loops that are to use coincident sizing
79 8 : for (int i = 1; i <= state.dataSize->NumPltSizInput; ++i) {
80 :
81 4 : if (state.dataSize->PlantSizData(i).ConcurrenceOption == DataSizing::Coincident) {
82 :
83 : // create an instance of analysis object for each loop
84 4 : CreateNewCoincidentPlantAnalysisObject(state, state.dataSize->PlantSizData(i).PlantLoopName, i);
85 : }
86 : }
87 4 : }
88 :
89 4 : void HVACSizingSimulationManager::CreateNewCoincidentPlantAnalysisObject(EnergyPlusData &state,
90 : std::string const &PlantLoopName,
91 : int const PlantSizingIndex)
92 : {
93 : Real64 density;
94 : Real64 cp;
95 :
96 : // find plant loop number
97 8 : for (int i = 1; i <= state.dataPlnt->TotNumLoops; ++i) {
98 4 : if (PlantLoopName == state.dataPlnt->PlantLoop(i).Name) { // found it
99 :
100 4 : density = state.dataPlnt->PlantLoop(i).glycol->getDensity(state, Constant::CWInitConvTemp, "createNewCoincidentPlantAnalysisObject");
101 4 : cp = state.dataPlnt->PlantLoop(i).glycol->getSpecificHeat(state, Constant::CWInitConvTemp, "createNewCoincidentPlantAnalysisObject");
102 :
103 8 : plantCoincAnalyObjs.emplace_back(PlantLoopName,
104 : i,
105 4 : state.dataPlnt->PlantLoop(i).LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumIn,
106 : density,
107 : cp,
108 4 : state.dataSize->PlantSizData(PlantSizingIndex).NumTimeStepsInAvg,
109 : PlantSizingIndex);
110 : }
111 : }
112 4 : }
113 :
114 4 : void HVACSizingSimulationManager::SetupSizingAnalyses(EnergyPlusData &state)
115 : {
116 :
117 8 : for (auto &P : plantCoincAnalyObjs) {
118 : // call setup log routine for each coincident plant analysis object
119 4 : P.supplyInletNodeFlow_LogIndex =
120 4 : sizingLogger.SetupVariableSizingLog(state, state.dataLoopNodes->Node(P.supplySideInletNodeNum).MassFlowRate, P.numTimeStepsInAvg);
121 4 : P.supplyInletNodeTemp_LogIndex =
122 4 : sizingLogger.SetupVariableSizingLog(state, state.dataLoopNodes->Node(P.supplySideInletNodeNum).Temp, P.numTimeStepsInAvg);
123 4 : if (state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == DataSizing::TypeOfPlantLoop::Heating ||
124 0 : state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == DataSizing::TypeOfPlantLoop::Steam) {
125 4 : P.loopDemand_LogIndex =
126 4 : sizingLogger.SetupVariableSizingLog(state, state.dataPlnt->PlantLoop(P.plantLoopIndex).HeatingDemand, P.numTimeStepsInAvg);
127 0 : } else if (state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == DataSizing::TypeOfPlantLoop::Cooling ||
128 0 : state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == DataSizing::TypeOfPlantLoop::Condenser) {
129 0 : P.loopDemand_LogIndex =
130 0 : sizingLogger.SetupVariableSizingLog(state, state.dataPlnt->PlantLoop(P.plantLoopIndex).CoolingDemand, P.numTimeStepsInAvg);
131 : }
132 : }
133 4 : }
134 :
135 4 : void HVACSizingSimulationManager::PostProcessLogs()
136 : {
137 : // this function calls methods on log objects to do general processing on all the logged data in the framework
138 16 : for (auto &L : sizingLogger.logObjs) {
139 12 : L.AverageSysTimeSteps(); // collapse subtimestep data into zone step data
140 12 : L.ProcessRunningAverage(); // apply zone step moving average
141 : }
142 4 : }
143 :
144 5 : void HVACSizingSimulationManager::ProcessCoincidentPlantSizeAdjustments(EnergyPlusData &state, int const HVACSizingIterCount)
145 : {
146 : // first pass through coincident plant objects to check new sizes and see if more iteration needed
147 5 : plantCoinAnalyRequestsAnotherIteration = false;
148 10 : for (auto &P : plantCoincAnalyObjs) {
149 : // step 1 find maximum flow rate on concurrent return temp and load
150 5 : P.newFoundMassFlowRateTimeStamp = sizingLogger.logObjs[P.supplyInletNodeFlow_LogIndex].GetLogVariableDataMax(state);
151 5 : P.peakMdotCoincidentDemand = sizingLogger.logObjs[P.loopDemand_LogIndex].GetLogVariableDataAtTimestamp(P.newFoundMassFlowRateTimeStamp);
152 5 : P.peakMdotCoincidentReturnTemp =
153 5 : sizingLogger.logObjs[P.supplyInletNodeTemp_LogIndex].GetLogVariableDataAtTimestamp(P.newFoundMassFlowRateTimeStamp);
154 :
155 : // step 2 find maximum load and concurrent flow and return temp
156 5 : P.NewFoundMaxDemandTimeStamp = sizingLogger.logObjs[P.loopDemand_LogIndex].GetLogVariableDataMax(state);
157 5 : P.peakDemandMassFlow = sizingLogger.logObjs[P.supplyInletNodeFlow_LogIndex].GetLogVariableDataAtTimestamp(P.NewFoundMaxDemandTimeStamp);
158 5 : P.peakDemandReturnTemp = sizingLogger.logObjs[P.supplyInletNodeTemp_LogIndex].GetLogVariableDataAtTimestamp(P.NewFoundMaxDemandTimeStamp);
159 :
160 5 : P.ResolveDesignFlowRate(state, HVACSizingIterCount);
161 5 : if (P.anotherIterationDesired) {
162 4 : plantCoinAnalyRequestsAnotherIteration = true;
163 : }
164 : }
165 :
166 : // as more sizing adjustments are added this will need to change to consider all not just plant coincident
167 : // state.dataGlobal->FinalSizingHVACSizingSimIteration = plantCoinAnalyRequestsAnotherIteration;
168 5 : }
169 0 : void HVACSizingSimulationManager::RedoKickOffAndResize(EnergyPlusData &state)
170 : {
171 0 : bool ErrorsFound = false;
172 0 : state.dataGlobal->KickOffSimulation = true;
173 0 : state.dataGlobal->RedoSizesHVACSimulation = true;
174 :
175 0 : Weather::ResetEnvironmentCounter(state);
176 0 : SimulationManager::SetupSimulation(state, ErrorsFound);
177 :
178 0 : state.dataGlobal->KickOffSimulation = false;
179 0 : state.dataGlobal->RedoSizesHVACSimulation = false;
180 0 : }
181 :
182 0 : void HVACSizingSimulationManager::UpdateSizingLogsZoneStep(EnergyPlusData &state)
183 : {
184 0 : sizingLogger.UpdateSizingLogValuesZoneStep(state);
185 0 : }
186 :
187 0 : void HVACSizingSimulationManager::UpdateSizingLogsSystemStep(EnergyPlusData &state)
188 : {
189 0 : sizingLogger.UpdateSizingLogValuesSystemStep(state);
190 0 : }
191 :
192 0 : void ManageHVACSizingSimulation(EnergyPlusData &state, bool &ErrorsFound)
193 : {
194 0 : auto &hvacSizingSimulationManager = state.dataHVACSizingSimMgr->hvacSizingSimulationManager;
195 :
196 0 : hvacSizingSimulationManager = std::make_unique<HVACSizingSimulationManager>();
197 :
198 : int HVACSizingIterCount;
199 :
200 0 : hvacSizingSimulationManager->DetermineSizingAnalysesNeeded(state);
201 :
202 0 : hvacSizingSimulationManager->SetupSizingAnalyses(state);
203 :
204 0 : DisplayString(state, "Beginning HVAC Sizing Simulation");
205 0 : state.dataGlobal->DoingHVACSizingSimulations = true;
206 0 : state.dataGlobal->DoOutputReporting = true;
207 :
208 0 : Weather::ResetEnvironmentCounter(state);
209 :
210 : // iterations over set of sizing periods for HVAC sizing Simulation, will break out if no more are needed
211 0 : for (HVACSizingIterCount = 1; HVACSizingIterCount <= state.dataGlobal->HVACSizingSimMaxIterations; ++HVACSizingIterCount) {
212 :
213 : // need to extend Environment structure array to distinguish the HVAC Sizing Simulations from the regular run of that sizing period, repeats
214 : // for each set
215 0 : Weather::AddDesignSetToEnvironmentStruct(state, HVACSizingIterCount);
216 :
217 0 : state.dataGlobal->WarmupFlag = true;
218 0 : bool Available = true;
219 0 : for (int i = 1; i <= state.dataWeather->NumOfEnvrn; ++i) { // loop over environments
220 :
221 0 : Weather::GetNextEnvironment(state, Available, ErrorsFound);
222 0 : if (ErrorsFound) break;
223 0 : if (!Available) continue;
224 :
225 0 : hvacSizingSimulationManager->sizingLogger.SetupSizingLogsNewEnvironment(state);
226 :
227 : // if (!DoDesDaySim) continue; // not sure about this, may need to force users to set this on input for this method, but maybe not
228 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) continue;
229 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) continue;
230 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodDesign) continue;
231 :
232 0 : if (state.dataWeather->Environment(state.dataWeather->Envrn).HVACSizingIterationNum != HVACSizingIterCount) continue;
233 :
234 0 : if (state.dataSysVars->ReportDuringHVACSizingSimulation) {
235 0 : if (state.dataSQLiteProcedures->sqlite) {
236 0 : state.dataSQLiteProcedures->sqlite->sqliteBegin();
237 0 : state.dataSQLiteProcedures->sqlite->createSQLiteEnvironmentPeriodRecord(
238 0 : state.dataEnvrn->CurEnvirNum, state.dataEnvrn->EnvironmentName, state.dataGlobal->KindOfSim);
239 0 : state.dataSQLiteProcedures->sqlite->sqliteCommit();
240 : }
241 : }
242 0 : state.dataErrTracking->ExitDuringSimulations = true;
243 :
244 0 : DisplayString(state, "Initializing New Environment Parameters, HVAC Sizing Simulation");
245 :
246 0 : state.dataGlobal->BeginEnvrnFlag = true;
247 0 : state.dataGlobal->EndEnvrnFlag = false;
248 : // EndMonthFlag = false;
249 0 : state.dataGlobal->WarmupFlag = true;
250 0 : state.dataGlobal->DayOfSim = 0;
251 0 : state.dataGlobal->DayOfSimChr = "0";
252 0 : state.dataReportFlag->NumOfWarmupDays = 0;
253 :
254 : bool anyEMSRan;
255 0 : ManageEMS(state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point
256 :
257 0 : while ((state.dataGlobal->DayOfSim < state.dataGlobal->NumOfDayInEnvrn) || (state.dataGlobal->WarmupFlag)) { // Begin day loop ...
258 :
259 : // Let's always do a transaction, except we'll roll it back if need be
260 : // if (ReportDuringHVACSizingSimulation) {
261 0 : if (state.dataSQLiteProcedures->sqlite) state.dataSQLiteProcedures->sqlite->sqliteBegin(); // setup for one transaction per day
262 : // }
263 0 : ++state.dataGlobal->DayOfSim;
264 0 : state.dataGlobal->DayOfSimChr = fmt::to_string(state.dataGlobal->DayOfSim);
265 0 : if (!state.dataGlobal->WarmupFlag) {
266 0 : ++state.dataEnvrn->CurrentOverallSimDay;
267 0 : DisplaySimDaysProgress(state, state.dataEnvrn->CurrentOverallSimDay, state.dataEnvrn->TotalOverallSimDays);
268 : } else {
269 0 : state.dataGlobal->DayOfSimChr = "0";
270 : }
271 0 : state.dataGlobal->BeginDayFlag = true;
272 0 : state.dataGlobal->EndDayFlag = false;
273 :
274 0 : if (state.dataGlobal->WarmupFlag) {
275 0 : ++state.dataReportFlag->NumOfWarmupDays;
276 0 : state.dataReportFlag->cWarmupDay = fmt::to_string(state.dataReportFlag->NumOfWarmupDays);
277 0 : DisplayString(state, "Warming up {" + state.dataReportFlag->cWarmupDay + '}');
278 0 : } else if (state.dataGlobal->DayOfSim == 1) {
279 0 : DisplayString(
280 : state,
281 0 : fmt::format("Starting HVAC Sizing Simulation at {} for {}", state.dataEnvrn->CurMnDy, state.dataEnvrn->EnvironmentName));
282 : static constexpr std::string_view Format_700("Environment:WarmupDays,{:3}\n");
283 0 : print(state.files.eio, Format_700, state.dataReportFlag->NumOfWarmupDays);
284 0 : } else if (state.dataReportFlag->DisplayPerfSimulationFlag) {
285 0 : DisplayString(state, "Continuing Simulation at " + state.dataEnvrn->CurMnDy + " for " + state.dataEnvrn->EnvironmentName);
286 0 : state.dataReportFlag->DisplayPerfSimulationFlag = false;
287 : }
288 :
289 0 : for (state.dataGlobal->HourOfDay = 1; state.dataGlobal->HourOfDay <= 24; ++state.dataGlobal->HourOfDay) { // Begin hour loop ...
290 :
291 0 : state.dataGlobal->BeginHourFlag = true;
292 0 : state.dataGlobal->EndHourFlag = false;
293 :
294 0 : for (state.dataGlobal->TimeStep = 1; state.dataGlobal->TimeStep <= state.dataGlobal->TimeStepsInHour;
295 0 : ++state.dataGlobal->TimeStep) {
296 0 : if (state.dataGlobal->AnySlabsInModel || state.dataGlobal->AnyBasementsInModel) {
297 0 : PlantPipingSystemsManager::SimulateGroundDomains(state, false);
298 : }
299 :
300 0 : state.dataGlobal->BeginTimeStepFlag = true;
301 :
302 : // Set the End__Flag variables to true if necessary. Note that
303 : // each flag builds on the previous level. EndDayFlag cannot be
304 : // .TRUE. unless EndHourFlag is also .TRUE., etc. Note that the
305 : // EndEnvrnFlag and the EndSimFlag cannot be set during warmup.
306 : // Note also that BeginTimeStepFlag, EndTimeStepFlag, and the
307 : // SubTimeStepFlags can/will be set/reset in the HVAC Manager.
308 :
309 0 : if (state.dataGlobal->TimeStep == state.dataGlobal->TimeStepsInHour) {
310 0 : state.dataGlobal->EndHourFlag = true;
311 0 : if (state.dataGlobal->HourOfDay == 24) {
312 0 : state.dataGlobal->EndDayFlag = true;
313 0 : if (!state.dataGlobal->WarmupFlag && (state.dataGlobal->DayOfSim == state.dataGlobal->NumOfDayInEnvrn)) {
314 0 : state.dataGlobal->EndEnvrnFlag = true;
315 : }
316 : }
317 : }
318 :
319 0 : Weather::ManageWeather(state);
320 :
321 0 : ExteriorEnergyUse::ManageExteriorEnergyUse(state);
322 :
323 0 : HeatBalanceManager::ManageHeatBalance(state);
324 :
325 0 : state.dataGlobal->BeginHourFlag = false;
326 0 : state.dataGlobal->BeginDayFlag = false;
327 0 : state.dataGlobal->BeginEnvrnFlag = false;
328 0 : state.dataGlobal->BeginSimFlag = false;
329 :
330 : } // TimeStep loop
331 :
332 0 : state.dataGlobal->PreviousHour = state.dataGlobal->HourOfDay;
333 :
334 : } // ... End hour loop.
335 0 : if (state.dataSQLiteProcedures->sqlite) {
336 0 : if (state.dataSysVars->ReportDuringHVACSizingSimulation) {
337 0 : state.dataSQLiteProcedures->sqlite->sqliteCommit(); // one transaction per day
338 : } else {
339 0 : state.dataSQLiteProcedures->sqlite->sqliteRollback(); // Cancel transaction
340 : }
341 : }
342 : } // ... End day loop.
343 :
344 : } // ... End environment loop.
345 :
346 0 : if (ErrorsFound) {
347 0 : ShowFatalError(state, "Error condition occurred. Previous Severe Errors cause termination.");
348 : }
349 :
350 0 : hvacSizingSimulationManager->PostProcessLogs();
351 :
352 0 : hvacSizingSimulationManager->ProcessCoincidentPlantSizeAdjustments(state, HVACSizingIterCount);
353 :
354 0 : hvacSizingSimulationManager->RedoKickOffAndResize(state);
355 :
356 0 : if (!hvacSizingSimulationManager->plantCoinAnalyRequestsAnotherIteration) {
357 : // jump out of for loop, or change for to a while
358 0 : break;
359 : }
360 :
361 0 : hvacSizingSimulationManager->sizingLogger.IncrementSizingPeriodSet();
362 :
363 : } // End HVAC Sizing Iteration loop
364 :
365 0 : state.dataGlobal->WarmupFlag = false;
366 0 : state.dataGlobal->DoOutputReporting = true;
367 0 : state.dataGlobal->DoingHVACSizingSimulations = false;
368 0 : hvacSizingSimulationManager.reset(); // delete/reset unique_ptr
369 0 : }
370 : } // namespace EnergyPlus
|