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