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 4 : }
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 4 : }
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 5 : }
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) {
223 0 : break;
224 : }
225 0 : if (!Available) {
226 0 : continue;
227 : }
228 :
229 0 : hvacSizingSimulationManager->sizingLogger.SetupSizingLogsNewEnvironment(state);
230 :
231 : // if (!DoDesDaySim) continue; // not sure about this, may need to force users to set this on input for this method, but maybe not
232 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather) {
233 0 : continue;
234 : }
235 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::DesignDay) {
236 0 : continue;
237 : }
238 0 : if (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodDesign) {
239 0 : continue;
240 : }
241 :
242 0 : if (state.dataWeather->Environment(state.dataWeather->Envrn).HVACSizingIterationNum != HVACSizingIterCount) {
243 0 : continue;
244 : }
245 :
246 0 : if (state.dataSysVars->ReportDuringHVACSizingSimulation) {
247 0 : if (state.dataSQLiteProcedures->sqlite) {
248 0 : state.dataSQLiteProcedures->sqlite->sqliteBegin();
249 0 : state.dataSQLiteProcedures->sqlite->createSQLiteEnvironmentPeriodRecord(
250 0 : state.dataEnvrn->CurEnvirNum, state.dataEnvrn->EnvironmentName, state.dataGlobal->KindOfSim);
251 0 : state.dataSQLiteProcedures->sqlite->sqliteCommit();
252 : }
253 : }
254 0 : state.dataErrTracking->ExitDuringSimulations = true;
255 :
256 0 : DisplayString(state, "Initializing New Environment Parameters, HVAC Sizing Simulation");
257 :
258 0 : state.dataGlobal->BeginEnvrnFlag = true;
259 0 : state.dataGlobal->EndEnvrnFlag = false;
260 : // EndMonthFlag = false;
261 0 : state.dataGlobal->WarmupFlag = true;
262 0 : state.dataGlobal->DayOfSim = 0;
263 0 : state.dataGlobal->DayOfSimChr = "0";
264 0 : state.dataReportFlag->NumOfWarmupDays = 0;
265 :
266 : bool anyEMSRan;
267 0 : ManageEMS(state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point
268 :
269 0 : while ((state.dataGlobal->DayOfSim < state.dataGlobal->NumOfDayInEnvrn) || (state.dataGlobal->WarmupFlag)) { // Begin day loop ...
270 :
271 : // Let's always do a transaction, except we'll roll it back if need be
272 : // if (ReportDuringHVACSizingSimulation) {
273 0 : if (state.dataSQLiteProcedures->sqlite) {
274 0 : state.dataSQLiteProcedures->sqlite->sqliteBegin(); // setup for one transaction per day
275 : }
276 : // }
277 0 : ++state.dataGlobal->DayOfSim;
278 0 : state.dataGlobal->DayOfSimChr = fmt::to_string(state.dataGlobal->DayOfSim);
279 0 : if (!state.dataGlobal->WarmupFlag) {
280 0 : ++state.dataEnvrn->CurrentOverallSimDay;
281 0 : DisplaySimDaysProgress(state, state.dataEnvrn->CurrentOverallSimDay, state.dataEnvrn->TotalOverallSimDays);
282 : } else {
283 0 : state.dataGlobal->DayOfSimChr = "0";
284 : }
285 0 : state.dataGlobal->BeginDayFlag = true;
286 0 : state.dataGlobal->EndDayFlag = false;
287 :
288 0 : if (state.dataGlobal->WarmupFlag) {
289 0 : ++state.dataReportFlag->NumOfWarmupDays;
290 0 : state.dataReportFlag->cWarmupDay = fmt::to_string(state.dataReportFlag->NumOfWarmupDays);
291 0 : DisplayString(state, "Warming up {" + state.dataReportFlag->cWarmupDay + '}');
292 0 : } else if (state.dataGlobal->DayOfSim == 1) {
293 0 : DisplayString(
294 : state,
295 0 : fmt::format("Starting HVAC Sizing Simulation at {} for {}", state.dataEnvrn->CurMnDy, state.dataEnvrn->EnvironmentName));
296 : static constexpr std::string_view Format_700("Environment:WarmupDays,{:3}\n");
297 0 : print(state.files.eio, Format_700, state.dataReportFlag->NumOfWarmupDays);
298 0 : } else if (state.dataReportFlag->DisplayPerfSimulationFlag) {
299 0 : DisplayString(state, "Continuing Simulation at " + state.dataEnvrn->CurMnDy + " for " + state.dataEnvrn->EnvironmentName);
300 0 : state.dataReportFlag->DisplayPerfSimulationFlag = false;
301 : }
302 :
303 0 : for (state.dataGlobal->HourOfDay = 1; state.dataGlobal->HourOfDay <= 24; ++state.dataGlobal->HourOfDay) { // Begin hour loop ...
304 :
305 0 : state.dataGlobal->BeginHourFlag = true;
306 0 : state.dataGlobal->EndHourFlag = false;
307 :
308 0 : for (state.dataGlobal->TimeStep = 1; state.dataGlobal->TimeStep <= state.dataGlobal->TimeStepsInHour;
309 0 : ++state.dataGlobal->TimeStep) {
310 0 : if (state.dataGlobal->AnySlabsInModel || state.dataGlobal->AnyBasementsInModel) {
311 0 : PlantPipingSystemsManager::SimulateGroundDomains(state, false);
312 : }
313 :
314 0 : state.dataGlobal->BeginTimeStepFlag = true;
315 :
316 : // Set the End__Flag variables to true if necessary. Note that
317 : // each flag builds on the previous level. EndDayFlag cannot be
318 : // .TRUE. unless EndHourFlag is also .TRUE., etc. Note that the
319 : // EndEnvrnFlag and the EndSimFlag cannot be set during warmup.
320 : // Note also that BeginTimeStepFlag, EndTimeStepFlag, and the
321 : // SubTimeStepFlags can/will be set/reset in the HVAC Manager.
322 :
323 0 : if (state.dataGlobal->TimeStep == state.dataGlobal->TimeStepsInHour) {
324 0 : state.dataGlobal->EndHourFlag = true;
325 0 : if (state.dataGlobal->HourOfDay == 24) {
326 0 : state.dataGlobal->EndDayFlag = true;
327 0 : if (!state.dataGlobal->WarmupFlag && (state.dataGlobal->DayOfSim == state.dataGlobal->NumOfDayInEnvrn)) {
328 0 : state.dataGlobal->EndEnvrnFlag = true;
329 : }
330 : }
331 : }
332 :
333 0 : Weather::ManageWeather(state);
334 :
335 0 : ExteriorEnergyUse::ManageExteriorEnergyUse(state);
336 :
337 0 : HeatBalanceManager::ManageHeatBalance(state);
338 :
339 0 : state.dataGlobal->BeginHourFlag = false;
340 0 : state.dataGlobal->BeginDayFlag = false;
341 0 : state.dataGlobal->BeginEnvrnFlag = false;
342 0 : state.dataGlobal->BeginSimFlag = false;
343 :
344 : } // TimeStep loop
345 :
346 0 : state.dataGlobal->PreviousHour = state.dataGlobal->HourOfDay;
347 :
348 : } // ... End hour loop.
349 0 : if (state.dataSQLiteProcedures->sqlite) {
350 0 : if (state.dataSysVars->ReportDuringHVACSizingSimulation) {
351 0 : state.dataSQLiteProcedures->sqlite->sqliteCommit(); // one transaction per day
352 : } else {
353 0 : state.dataSQLiteProcedures->sqlite->sqliteRollback(); // Cancel transaction
354 : }
355 : }
356 : } // ... End day loop.
357 :
358 : } // ... End environment loop.
359 :
360 0 : if (ErrorsFound) {
361 0 : ShowFatalError(state, "Error condition occurred. Previous Severe Errors cause termination.");
362 : }
363 :
364 0 : hvacSizingSimulationManager->PostProcessLogs();
365 :
366 0 : hvacSizingSimulationManager->ProcessCoincidentPlantSizeAdjustments(state, HVACSizingIterCount);
367 :
368 0 : hvacSizingSimulationManager->RedoKickOffAndResize(state);
369 :
370 0 : if (!hvacSizingSimulationManager->plantCoinAnalyRequestsAnotherIteration) {
371 : // jump out of for loop, or change for to a while
372 0 : break;
373 : }
374 :
375 0 : hvacSizingSimulationManager->sizingLogger.IncrementSizingPeriodSet();
376 :
377 : } // End HVAC Sizing Iteration loop
378 :
379 0 : state.dataGlobal->WarmupFlag = false;
380 0 : state.dataGlobal->DoOutputReporting = true;
381 0 : state.dataGlobal->DoingHVACSizingSimulations = false;
382 0 : hvacSizingSimulationManager.reset(); // delete/reset unique_ptr
383 0 : }
384 : } // namespace EnergyPlus
|