Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2023, 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 11 : void HVACSizingSimulationManager::DetermineSizingAnalysesNeeded(EnergyPlusData &state)
73 : {
74 : using DataSizing::Coincident;
75 :
76 : // currently the only type of advanced sizing analysis available is for coincident plant sizing
77 : // 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
78 : // be created.
79 :
80 : // Loop over PlantSizData struct and find those plant loops that are to use coincident sizing
81 52 : for (int i = 1; i <= state.dataSize->NumPltSizInput; ++i) {
82 :
83 41 : if (state.dataSize->PlantSizData(i).ConcurrenceOption == Coincident) {
84 :
85 : // create an instance of analysis object for each loop
86 26 : CreateNewCoincidentPlantAnalysisObject(state, state.dataSize->PlantSizData(i).PlantLoopName, i);
87 : }
88 : }
89 11 : }
90 :
91 26 : void HVACSizingSimulationManager::CreateNewCoincidentPlantAnalysisObject(EnergyPlusData &state,
92 : std::string const &PlantLoopName,
93 : int const PlantSizingIndex)
94 : {
95 : using namespace FluidProperties;
96 :
97 : Real64 density;
98 : Real64 cp;
99 :
100 : // find plant loop number
101 128 : for (int i = 1; i <= state.dataPlnt->TotNumLoops; ++i) {
102 102 : if (PlantLoopName == state.dataPlnt->PlantLoop(i).Name) { // found it
103 :
104 52 : density = GetDensityGlycol(state,
105 26 : state.dataPlnt->PlantLoop(i).FluidName,
106 : DataGlobalConstants::CWInitConvTemp,
107 26 : state.dataPlnt->PlantLoop(i).FluidIndex,
108 26 : "createNewCoincidentPlantAnalysisObject");
109 52 : cp = GetSpecificHeatGlycol(state,
110 26 : state.dataPlnt->PlantLoop(i).FluidName,
111 : DataGlobalConstants::CWInitConvTemp,
112 26 : state.dataPlnt->PlantLoop(i).FluidIndex,
113 26 : "createNewCoincidentPlantAnalysisObject");
114 :
115 26 : plantCoincAnalyObjs.emplace_back(PlantLoopName,
116 : i,
117 26 : state.dataPlnt->PlantLoop(i).LoopSide(DataPlant::LoopSideLocation::Supply).NodeNumIn,
118 : density,
119 : cp,
120 26 : state.dataSize->PlantSizData(PlantSizingIndex).NumTimeStepsInAvg,
121 78 : PlantSizingIndex);
122 : }
123 : }
124 26 : }
125 :
126 11 : void HVACSizingSimulationManager::SetupSizingAnalyses(EnergyPlusData &state)
127 : {
128 : using DataSizing::CondenserLoop;
129 : using DataSizing::CoolingLoop;
130 : using DataSizing::HeatingLoop;
131 : using DataSizing::SteamLoop;
132 :
133 37 : for (auto &P : plantCoincAnalyObjs) {
134 : // call setup log routine for each coincident plant analysis object
135 26 : P.supplyInletNodeFlow_LogIndex =
136 26 : sizingLogger.SetupVariableSizingLog(state, state.dataLoopNodes->Node(P.supplySideInletNodeNum).MassFlowRate, P.numTimeStepsInAvg);
137 26 : P.supplyInletNodeTemp_LogIndex =
138 26 : sizingLogger.SetupVariableSizingLog(state, state.dataLoopNodes->Node(P.supplySideInletNodeNum).Temp, P.numTimeStepsInAvg);
139 41 : if (state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == HeatingLoop ||
140 15 : state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == SteamLoop) {
141 11 : P.loopDemand_LogIndex =
142 11 : sizingLogger.SetupVariableSizingLog(state, state.dataPlnt->PlantLoop(P.plantLoopIndex).HeatingDemand, P.numTimeStepsInAvg);
143 17 : } else if (state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == CoolingLoop ||
144 2 : state.dataSize->PlantSizData(P.plantSizingIndex).LoopType == CondenserLoop) {
145 15 : P.loopDemand_LogIndex =
146 15 : sizingLogger.SetupVariableSizingLog(state, state.dataPlnt->PlantLoop(P.plantLoopIndex).CoolingDemand, P.numTimeStepsInAvg);
147 : }
148 : }
149 11 : }
150 :
151 16 : void HVACSizingSimulationManager::PostProcessLogs()
152 : {
153 : // this function calls methods on log objects to do general processing on all the logged data in the framework
154 124 : for (auto &L : sizingLogger.logObjs) {
155 108 : L.AverageSysTimeSteps(); // collapse subtimestep data into zone step data
156 108 : L.ProcessRunningAverage(); // apply zone step moving average
157 : }
158 16 : }
159 :
160 16 : void HVACSizingSimulationManager::ProcessCoincidentPlantSizeAdjustments(EnergyPlusData &state, int const HVACSizingIterCount)
161 : {
162 : using namespace DataPlant;
163 : using namespace PlantManager;
164 : using namespace DataSizing;
165 :
166 : // first pass through coincident plant objects to check new sizes and see if more iteration needed
167 16 : plantCoinAnalyRequestsAnotherIteration = false;
168 52 : for (auto &P : plantCoincAnalyObjs) {
169 : // step 1 find maximum flow rate on concurrent return temp and load
170 36 : P.newFoundMassFlowRateTimeStamp = sizingLogger.logObjs[P.supplyInletNodeFlow_LogIndex].GetLogVariableDataMax(state);
171 36 : P.peakMdotCoincidentDemand = sizingLogger.logObjs[P.loopDemand_LogIndex].GetLogVariableDataAtTimestamp(P.newFoundMassFlowRateTimeStamp);
172 36 : P.peakMdotCoincidentReturnTemp =
173 72 : sizingLogger.logObjs[P.supplyInletNodeTemp_LogIndex].GetLogVariableDataAtTimestamp(P.newFoundMassFlowRateTimeStamp);
174 :
175 : // step 2 find maximum load and concurrent flow and return temp
176 36 : P.NewFoundMaxDemandTimeStamp = sizingLogger.logObjs[P.loopDemand_LogIndex].GetLogVariableDataMax(state);
177 36 : P.peakDemandMassFlow = sizingLogger.logObjs[P.supplyInletNodeFlow_LogIndex].GetLogVariableDataAtTimestamp(P.NewFoundMaxDemandTimeStamp);
178 36 : P.peakDemandReturnTemp = sizingLogger.logObjs[P.supplyInletNodeTemp_LogIndex].GetLogVariableDataAtTimestamp(P.NewFoundMaxDemandTimeStamp);
179 :
180 36 : P.ResolveDesignFlowRate(state, HVACSizingIterCount);
181 36 : if (P.anotherIterationDesired) {
182 25 : plantCoinAnalyRequestsAnotherIteration = true;
183 : }
184 : }
185 :
186 : // as more sizing adjustments are added this will need to change to consider all not just plant coincident
187 : // state.dataGlobal->FinalSizingHVACSizingSimIteration = plantCoinAnalyRequestsAnotherIteration;
188 16 : }
189 16 : void HVACSizingSimulationManager::RedoKickOffAndResize(EnergyPlusData &state)
190 : {
191 : using namespace WeatherManager;
192 : using namespace SimulationManager;
193 16 : bool ErrorsFound(false);
194 16 : state.dataGlobal->KickOffSimulation = true;
195 16 : state.dataGlobal->RedoSizesHVACSimulation = true;
196 :
197 16 : ResetEnvironmentCounter(state);
198 16 : SetupSimulation(state, ErrorsFound);
199 :
200 16 : state.dataGlobal->KickOffSimulation = false;
201 16 : state.dataGlobal->RedoSizesHVACSimulation = false;
202 16 : }
203 :
204 4224 : void HVACSizingSimulationManager::UpdateSizingLogsZoneStep(EnergyPlusData &state)
205 : {
206 4224 : sizingLogger.UpdateSizingLogValuesZoneStep(state);
207 4224 : }
208 :
209 8741 : void HVACSizingSimulationManager::UpdateSizingLogsSystemStep(EnergyPlusData &state)
210 : {
211 8741 : sizingLogger.UpdateSizingLogValuesSystemStep(state);
212 8741 : }
213 :
214 11 : void ManageHVACSizingSimulation(EnergyPlusData &state, bool &ErrorsFound)
215 : {
216 : using EMSManager::ManageEMS;
217 : using ExteriorEnergyUse::ManageExteriorEnergyUse;
218 : using PlantPipingSystemsManager::SimulateGroundDomains;
219 : using namespace WeatherManager;
220 : using namespace HeatBalanceManager;
221 :
222 11 : auto &hvacSizingSimulationManager = state.dataHVACSizingSimMgr->hvacSizingSimulationManager;
223 :
224 11 : hvacSizingSimulationManager = std::make_unique<HVACSizingSimulationManager>();
225 :
226 : bool Available; // an environment is available to process
227 : int HVACSizingIterCount;
228 :
229 11 : hvacSizingSimulationManager->DetermineSizingAnalysesNeeded(state);
230 :
231 11 : hvacSizingSimulationManager->SetupSizingAnalyses(state);
232 :
233 11 : DisplayString(state, "Beginning HVAC Sizing Simulation");
234 11 : state.dataGlobal->DoingHVACSizingSimulations = true;
235 11 : state.dataGlobal->DoOutputReporting = true;
236 :
237 11 : ResetEnvironmentCounter(state);
238 :
239 : // iterations over set of sizing periods for HVAC sizing Simulation, will break out if no more are needed
240 24 : for (HVACSizingIterCount = 1; HVACSizingIterCount <= state.dataGlobal->HVACSizingSimMaxIterations; ++HVACSizingIterCount) {
241 :
242 : // need to extend Environment structure array to distinguish the HVAC Sizing Simulations from the regular run of that sizing period, repeats
243 : // for each set
244 16 : AddDesignSetToEnvironmentStruct(state, HVACSizingIterCount);
245 :
246 16 : state.dataGlobal->WarmupFlag = true;
247 16 : Available = true;
248 111 : for (int i = 1; i <= state.dataWeatherManager->NumOfEnvrn; ++i) { // loop over environments
249 :
250 95 : GetNextEnvironment(state, Available, ErrorsFound);
251 95 : if (ErrorsFound) break;
252 158 : if (!Available) continue;
253 :
254 95 : hvacSizingSimulationManager->sizingLogger.SetupSizingLogsNewEnvironment(state);
255 :
256 : // if (!DoDesDaySim) continue; // not sure about this, may need to force users to set this on input for this method, but maybe not
257 95 : if (state.dataGlobal->KindOfSim == DataGlobalConstants::KindOfSim::RunPeriodWeather) continue;
258 74 : if (state.dataGlobal->KindOfSim == DataGlobalConstants::KindOfSim::DesignDay) continue;
259 42 : if (state.dataGlobal->KindOfSim == DataGlobalConstants::KindOfSim::RunPeriodDesign) continue;
260 :
261 42 : if (state.dataWeatherManager->Environment(state.dataWeatherManager->Envrn).HVACSizingIterationNum != HVACSizingIterCount) continue;
262 :
263 32 : if (state.dataSysVars->ReportDuringHVACSizingSimulation) {
264 0 : if (state.dataSQLiteProcedures->sqlite) {
265 0 : state.dataSQLiteProcedures->sqlite->sqliteBegin();
266 0 : state.dataSQLiteProcedures->sqlite->createSQLiteEnvironmentPeriodRecord(
267 0 : state.dataEnvrn->CurEnvirNum, state.dataEnvrn->EnvironmentName, state.dataGlobal->KindOfSim);
268 0 : state.dataSQLiteProcedures->sqlite->sqliteCommit();
269 : }
270 : }
271 32 : state.dataErrTracking->ExitDuringSimulations = true;
272 :
273 32 : DisplayString(state, "Initializing New Environment Parameters, HVAC Sizing Simulation");
274 :
275 32 : state.dataGlobal->BeginEnvrnFlag = true;
276 32 : state.dataGlobal->EndEnvrnFlag = false;
277 : // EndMonthFlag = false;
278 32 : state.dataGlobal->WarmupFlag = true;
279 32 : state.dataGlobal->DayOfSim = 0;
280 32 : state.dataGlobal->DayOfSimChr = "0";
281 32 : state.dataReportFlag->NumOfWarmupDays = 0;
282 :
283 : bool anyEMSRan;
284 32 : ManageEMS(state, EMSManager::EMSCallFrom::BeginNewEnvironment, anyEMSRan, ObjexxFCL::Optional_int_const()); // calling point
285 :
286 480 : while ((state.dataGlobal->DayOfSim < state.dataGlobal->NumOfDayInEnvrn) || (state.dataGlobal->WarmupFlag)) { // Begin day loop ...
287 :
288 : // Let's always do a transaction, except we'll roll it back if need be
289 : // if (ReportDuringHVACSizingSimulation) {
290 224 : if (state.dataSQLiteProcedures->sqlite) state.dataSQLiteProcedures->sqlite->sqliteBegin(); // setup for one transaction per day
291 : // }
292 224 : ++state.dataGlobal->DayOfSim;
293 224 : state.dataGlobal->DayOfSimChr = fmt::to_string(state.dataGlobal->DayOfSim);
294 224 : if (!state.dataGlobal->WarmupFlag) {
295 32 : ++state.dataEnvrn->CurrentOverallSimDay;
296 32 : DisplaySimDaysProgress(state, state.dataEnvrn->CurrentOverallSimDay, state.dataEnvrn->TotalOverallSimDays);
297 : } else {
298 192 : state.dataGlobal->DayOfSimChr = "0";
299 : }
300 224 : state.dataGlobal->BeginDayFlag = true;
301 224 : state.dataGlobal->EndDayFlag = false;
302 :
303 224 : if (state.dataGlobal->WarmupFlag) {
304 192 : ++state.dataReportFlag->NumOfWarmupDays;
305 192 : state.dataReportFlag->cWarmupDay = fmt::to_string(state.dataReportFlag->NumOfWarmupDays);
306 192 : DisplayString(state, "Warming up {" + state.dataReportFlag->cWarmupDay + '}');
307 32 : } else if (state.dataGlobal->DayOfSim == 1) {
308 32 : DisplayString(
309 : state,
310 64 : fmt::format("Starting HVAC Sizing Simulation at {} for {}", state.dataEnvrn->CurMnDy, state.dataEnvrn->EnvironmentName));
311 : static constexpr std::string_view Format_700("Environment:WarmupDays,{:3}\n");
312 32 : print(state.files.eio, Format_700, state.dataReportFlag->NumOfWarmupDays);
313 0 : } else if (state.dataReportFlag->DisplayPerfSimulationFlag) {
314 0 : DisplayString(state, "Continuing Simulation at " + state.dataEnvrn->CurMnDy + " for " + state.dataEnvrn->EnvironmentName);
315 0 : state.dataReportFlag->DisplayPerfSimulationFlag = false;
316 : }
317 :
318 5600 : for (state.dataGlobal->HourOfDay = 1; state.dataGlobal->HourOfDay <= 24; ++state.dataGlobal->HourOfDay) { // Begin hour loop ...
319 :
320 5376 : state.dataGlobal->BeginHourFlag = true;
321 5376 : state.dataGlobal->EndHourFlag = false;
322 :
323 34944 : for (state.dataGlobal->TimeStep = 1; state.dataGlobal->TimeStep <= state.dataGlobal->NumOfTimeStepInHour;
324 29568 : ++state.dataGlobal->TimeStep) {
325 29568 : if (state.dataGlobal->AnySlabsInModel || state.dataGlobal->AnyBasementsInModel) {
326 0 : SimulateGroundDomains(state, false);
327 : }
328 :
329 29568 : state.dataGlobal->BeginTimeStepFlag = true;
330 :
331 : // Set the End__Flag variables to true if necessary. Note that
332 : // each flag builds on the previous level. EndDayFlag cannot be
333 : // .TRUE. unless EndHourFlag is also .TRUE., etc. Note that the
334 : // EndEnvrnFlag and the EndSimFlag cannot be set during warmup.
335 : // Note also that BeginTimeStepFlag, EndTimeStepFlag, and the
336 : // SubTimeStepFlags can/will be set/reset in the HVAC Manager.
337 :
338 29568 : if (state.dataGlobal->TimeStep == state.dataGlobal->NumOfTimeStepInHour) {
339 5376 : state.dataGlobal->EndHourFlag = true;
340 5376 : if (state.dataGlobal->HourOfDay == 24) {
341 224 : state.dataGlobal->EndDayFlag = true;
342 224 : if (!state.dataGlobal->WarmupFlag && (state.dataGlobal->DayOfSim == state.dataGlobal->NumOfDayInEnvrn)) {
343 32 : state.dataGlobal->EndEnvrnFlag = true;
344 : }
345 : }
346 : }
347 :
348 29568 : ManageWeather(state);
349 :
350 29568 : ManageExteriorEnergyUse(state);
351 :
352 29568 : ManageHeatBalance(state);
353 :
354 29568 : state.dataGlobal->BeginHourFlag = false;
355 29568 : state.dataGlobal->BeginDayFlag = false;
356 29568 : state.dataGlobal->BeginEnvrnFlag = false;
357 29568 : state.dataGlobal->BeginSimFlag = false;
358 :
359 : } // TimeStep loop
360 :
361 5376 : state.dataGlobal->PreviousHour = state.dataGlobal->HourOfDay;
362 :
363 : } // ... End hour loop.
364 224 : if (state.dataSQLiteProcedures->sqlite) {
365 182 : if (state.dataSysVars->ReportDuringHVACSizingSimulation) {
366 0 : state.dataSQLiteProcedures->sqlite->sqliteCommit(); // one transaction per day
367 : } else {
368 182 : state.dataSQLiteProcedures->sqlite->sqliteRollback(); // Cancel transaction
369 : }
370 : }
371 : } // ... End day loop.
372 :
373 : } // ... End environment loop.
374 :
375 16 : if (ErrorsFound) {
376 0 : ShowFatalError(state, "Error condition occurred. Previous Severe Errors cause termination.");
377 : }
378 :
379 16 : hvacSizingSimulationManager->PostProcessLogs();
380 :
381 16 : hvacSizingSimulationManager->ProcessCoincidentPlantSizeAdjustments(state, HVACSizingIterCount);
382 :
383 16 : hvacSizingSimulationManager->RedoKickOffAndResize(state);
384 :
385 16 : if (!hvacSizingSimulationManager->plantCoinAnalyRequestsAnotherIteration) {
386 : // jump out of for loop, or change for to a while
387 3 : break;
388 : }
389 :
390 13 : hvacSizingSimulationManager->sizingLogger.IncrementSizingPeriodSet();
391 :
392 : } // End HVAC Sizing Iteration loop
393 :
394 11 : state.dataGlobal->WarmupFlag = false;
395 11 : state.dataGlobal->DoOutputReporting = true;
396 11 : state.dataGlobal->DoingHVACSizingSimulations = false;
397 11 : hvacSizingSimulationManager.reset(); // delete/reset unique_ptr
398 11 : }
399 2313 : } // namespace EnergyPlus
|