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 <cmath>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 :
55 : // EnergyPlus Headers
56 : #include <EnergyPlus/BranchNodeConnections.hh>
57 : #include <EnergyPlus/CurveManager.hh>
58 : #include <EnergyPlus/Data/EnergyPlusData.hh>
59 : #include <EnergyPlus/DataEnvironment.hh>
60 : #include <EnergyPlus/DataGlobalConstants.hh>
61 : #include <EnergyPlus/DataHVACGlobals.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DataLoopNode.hh>
64 : #include <EnergyPlus/DataPrecisionGlobals.hh>
65 : #include <EnergyPlus/FluidProperties.hh>
66 : #include <EnergyPlus/General.hh>
67 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
68 : #include <EnergyPlus/MicroturbineElectricGenerator.hh>
69 : #include <EnergyPlus/NodeInputManager.hh>
70 : #include <EnergyPlus/OutAirNodeManager.hh>
71 : #include <EnergyPlus/OutputProcessor.hh>
72 : #include <EnergyPlus/Plant/DataPlant.hh>
73 : #include <EnergyPlus/PlantUtilities.hh>
74 : #include <EnergyPlus/Psychrometrics.hh>
75 : #include <EnergyPlus/UtilityRoutines.hh>
76 :
77 : namespace EnergyPlus::MicroturbineElectricGenerator {
78 :
79 : // MODULE INFORMATION:
80 : // AUTHOR R. Raustad/D. Shirey
81 : // DATE WRITTEN Mar 2008
82 : // MODIFIED na
83 : // RE-ENGINEERED na
84 :
85 : // PURPOSE OF THIS MODULE:
86 : // This module simulates the performance of microturbine electric
87 : // generators.
88 :
89 : // METHODOLOGY EMPLOYED:
90 : // Once the electric power manager determines that the MT Generator
91 : // is available, it calls SimMTGenerator which in turn calls the
92 : // appropriate microturbine generator model.
93 : // MT Generator models are based on polynomial curve fits of generator
94 : // performance data.
95 :
96 6 : PlantComponent *MTGeneratorSpecs::factory(EnergyPlusData &state, std::string const &objectName)
97 : {
98 : // Process the input data for generator if it hasn't been done already
99 6 : if (state.dataMircoturbElectGen->GetMTInput) {
100 4 : GetMTGeneratorInput(state);
101 4 : state.dataMircoturbElectGen->GetMTInput = false;
102 : }
103 :
104 : // Now look for this particular gen in the list
105 9 : for (auto &thisMTG : state.dataMircoturbElectGen->MTGenerator) {
106 9 : if (thisMTG.Name == objectName) {
107 6 : return &thisMTG;
108 : }
109 : }
110 : // If we didn't find it, fatal
111 0 : ShowFatalError(
112 : state, format("LocalMicroTurbineGeneratorFactory: Error getting inputs for microturbine generator named: {}", objectName)); // LCOV_EXCL_LINE
113 : // Shut up the compiler
114 : return nullptr; // LCOV_EXCL_LINE
115 : }
116 :
117 5 : void GetMTGeneratorInput(EnergyPlusData &state)
118 : {
119 : // SUBROUTINE INFORMATION:
120 : // AUTHOR R. Raustad/D. Shirey
121 : // DATE WRITTEN Mar 2008
122 : // MODIFIED na
123 : // RE-ENGINEERED na
124 :
125 : // PURPOSE OF THIS SUBROUTINE:
126 : // This routine gets the input information for the Microturbine (MT) Generator model.
127 :
128 5 : bool ErrorsFound(false);
129 :
130 5 : state.dataIPShortCut->cCurrentModuleObject = "Generator:MicroTurbine";
131 10 : state.dataMircoturbElectGen->NumMTGenerators =
132 5 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
133 :
134 5 : if (state.dataMircoturbElectGen->NumMTGenerators <= 0) {
135 0 : ShowSevereError(state, format("No {} equipment specified in input file", state.dataIPShortCut->cCurrentModuleObject));
136 0 : ErrorsFound = true;
137 : }
138 :
139 : // ALLOCATE ARRAYS
140 5 : state.dataMircoturbElectGen->MTGenerator.allocate(state.dataMircoturbElectGen->NumMTGenerators);
141 :
142 : // LOAD ARRAYS WITH MICROTURBINE GENERATOR DATA
143 12 : for (int GeneratorNum = 1; GeneratorNum <= state.dataMircoturbElectGen->NumMTGenerators; ++GeneratorNum) {
144 : int NumAlphas;
145 : int NumNums;
146 : int IOStat;
147 7 : Array1D<Real64> NumArray(19);
148 7 : Array1D_string AlphArray(20);
149 21 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
150 7 : state.dataIPShortCut->cCurrentModuleObject,
151 : GeneratorNum,
152 : AlphArray,
153 : NumAlphas,
154 : NumArray,
155 : NumNums,
156 : IOStat,
157 7 : state.dataIPShortCut->lNumericFieldBlanks,
158 7 : state.dataIPShortCut->lAlphaFieldBlanks,
159 7 : state.dataIPShortCut->cAlphaFieldNames,
160 7 : state.dataIPShortCut->cNumericFieldNames);
161 7 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
162 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name = AlphArray(1);
163 :
164 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput = NumArray(1);
165 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput <= 0.0) {
166 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(1), NumArray(1)));
167 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
168 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(1)));
169 0 : ErrorsFound = true;
170 : }
171 :
172 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput = NumArray(2);
173 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput = NumArray(3);
174 :
175 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput < 0.0) {
176 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(2), NumArray(2)));
177 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
178 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(2)));
179 0 : ErrorsFound = true;
180 : }
181 :
182 7 : if (state.dataIPShortCut->lNumericFieldBlanks(3)) {
183 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput =
184 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput;
185 : } else {
186 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput <= 0.0) {
187 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(3), NumArray(3)));
188 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
189 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(3)));
190 0 : ErrorsFound = true;
191 : }
192 : }
193 :
194 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput >=
195 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput) {
196 0 : ShowSevereError(
197 0 : state, format("{}= {}", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
198 0 : ShowContinueError(state,
199 0 : format("{} [{:.2R}] > {} [{:.2R}]",
200 0 : state.dataIPShortCut->cNumericFieldNames(2),
201 : NumArray(2),
202 0 : state.dataIPShortCut->cNumericFieldNames(3),
203 : NumArray(3)));
204 0 : ShowContinueError(state, "Minimum Full Load Electrical Power Output must be less than or equal");
205 0 : ShowContinueError(state, "to Maximum Full Load Electrical Power Output.");
206 0 : ErrorsFound = true;
207 : }
208 :
209 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput >
210 14 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput ||
211 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput <
212 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput) {
213 0 : ShowSevereError(
214 0 : state, format("{}= {}", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
215 0 : ShowContinueError(state,
216 0 : format("{} must be >= {}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->cNumericFieldNames(2)));
217 0 : ShowContinueError(state,
218 0 : format("{} must be <= {}", state.dataIPShortCut->cNumericFieldNames(1), state.dataIPShortCut->cNumericFieldNames(3)));
219 0 : ShowContinueError(state, format("{} = {:.2R}", state.dataIPShortCut->cNumericFieldNames(1), NumArray(1)));
220 0 : ShowContinueError(state, format("{} = {:.2R}", state.dataIPShortCut->cNumericFieldNames(2), NumArray(2)));
221 0 : ShowContinueError(state, format("{} = {:.2R}", state.dataIPShortCut->cNumericFieldNames(3), NumArray(3)));
222 0 : ErrorsFound = true;
223 : }
224 :
225 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV = NumArray(4);
226 :
227 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV <= 0.0) {
228 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(4), NumArray(4)));
229 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
230 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(4)));
231 0 : ErrorsFound = true;
232 : }
233 :
234 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp = NumArray(5);
235 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat = NumArray(6);
236 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation = NumArray(7);
237 :
238 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat <= 0.0) {
239 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(6), NumArray(6)));
240 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
241 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(6)));
242 0 : ErrorsFound = true;
243 : } else {
244 : // Reference barometric pressure, adjusted for reference elevation (Pa)
245 : Real64 RefBaroPressure =
246 7 : 101325.0 * std::pow(1.0 - 2.25577e-05 * state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation, 5.2559);
247 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletDensity =
248 21 : Psychrometrics::PsyRhoAirFnPbTdbW(state,
249 : RefBaroPressure,
250 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
251 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat);
252 : }
253 :
254 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum =
255 7 : Curve::GetCurveIndex(state, AlphArray(2)); // Convert curve name to number
256 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum == 0) {
257 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(2), AlphArray(2)));
258 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
259 0 : ErrorsFound = true;
260 : } else {
261 : // Verify curve object, only legal type is BiQuadratic
262 :
263 7 : if (!ErrorsFound) {
264 : // Check electrical power output at reference combustion inlet temp and elevation
265 : // Output of Electrical Power Output Modifier Curve (function of temp and elev)
266 28 : Real64 ElectOutFTempElevOutput = Curve::CurveValue(state,
267 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum,
268 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
269 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation);
270 7 : if (std::abs(ElectOutFTempElevOutput - 1.0) > 0.1) {
271 0 : ShowWarningError(
272 : state,
273 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
274 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(2), AlphArray(2)));
275 0 : ShowContinueError(state, "... Curve output at reference conditions should equal 1 (+-10%).");
276 0 : ShowContinueError(state,
277 0 : format("...Reference combustion air inlet temperature = {:.4T} C",
278 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
279 0 : ShowContinueError(state,
280 0 : format("...Reference elevation = {:.4T} m",
281 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation));
282 0 : ShowContinueError(state, format("...Curve output = {:.4T}", ElectOutFTempElevOutput));
283 : }
284 : }
285 : }
286 :
287 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum =
288 7 : Curve::GetCurveIndex(state, AlphArray(3)); // Convert curve name to number
289 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum == 0) {
290 0 : ShowSevereError(
291 0 : state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
292 0 : ShowContinueError(state, format("{} not found = {}", state.dataIPShortCut->cAlphaFieldNames(3), AlphArray(3)));
293 0 : ErrorsFound = true;
294 : } else {
295 : // Verify curve object, only legal types are Quadratic and Cubic
296 :
297 7 : if (!ErrorsFound) {
298 : // Check electrical efficiency at reference combustion inlet temp
299 : // Output of Electrical Efficiency Modifier Curve (function of temp)
300 21 : Real64 ElecEfficFTempOutput = Curve::CurveValue(state,
301 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum,
302 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
303 7 : if (std::abs(ElecEfficFTempOutput - 1.0) > 0.1) {
304 0 : ShowWarningError(
305 : state,
306 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
307 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(3), AlphArray(3)));
308 0 : ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
309 0 : ShowContinueError(state,
310 0 : format("... Reference combustion air inlet temperature = {:.4T} C",
311 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
312 0 : ShowContinueError(state, format("... Curve output = {:.4T}", ElecEfficFTempOutput));
313 : }
314 : }
315 : }
316 :
317 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum =
318 7 : Curve::GetCurveIndex(state, AlphArray(4)); // Convert curve name to number
319 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum == 0) {
320 0 : ShowSevereError(
321 0 : state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
322 0 : ShowContinueError(state, format("{} not found = {}", state.dataIPShortCut->cAlphaFieldNames(4), AlphArray(4)));
323 0 : ErrorsFound = true;
324 : } else {
325 : // Verify curve object, only legal types are Quadratic and Cubic
326 :
327 7 : if (!ErrorsFound) {
328 : // Check electrical efficiency at PLR = 1
329 : // Output of Electrical Efficiency Modifier Curve (function of PLR)
330 : Real64 ElecEfficFPLROutput =
331 7 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum, 1.0);
332 7 : if (std::abs(ElecEfficFPLROutput - 1.0) > 0.1) {
333 0 : ShowWarningError(
334 : state,
335 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
336 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(4), AlphArray(4)));
337 0 : ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
338 0 : ShowContinueError(state, format("... Curve output = {:.4T}", ElecEfficFPLROutput));
339 : }
340 :
341 7 : Real64 Var1Min(0.0);
342 7 : Real64 Var1Max(0.0);
343 7 : Curve::GetCurveMinMaxValues(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum, Var1Min, Var1Max);
344 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinPartLoadRat = Var1Min;
345 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxPartLoadRat = Var1Max;
346 : }
347 : }
348 :
349 : // Validate fuel type input
350 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelType =
351 7 : static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, AlphArray(5)));
352 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelType == Constant::eFuel::Invalid) {
353 0 : ShowSevereError(
354 0 : state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
355 0 : ShowContinueError(state, format("Invalid {} = {}", state.dataIPShortCut->cAlphaFieldNames(5), AlphArray(5)));
356 0 : ErrorsFound = true;
357 : }
358 :
359 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelHigherHeatingValue = NumArray(8);
360 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue = NumArray(9);
361 :
362 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue <= 0.0) {
363 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(9), NumArray(9)));
364 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
365 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(9)));
366 0 : ErrorsFound = true;
367 : }
368 :
369 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelHigherHeatingValue <= 0.0) {
370 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(8), NumArray(8)));
371 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
372 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(8)));
373 0 : ErrorsFound = true;
374 : }
375 :
376 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue >
377 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelHigherHeatingValue) {
378 0 : ShowSevereError(
379 0 : state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
380 0 : ShowContinueError(
381 : state,
382 0 : format("{} must be greater than the {}", state.dataIPShortCut->cNumericFieldNames(8), state.dataIPShortCut->cNumericFieldNames(9)));
383 0 : ShowContinueError(state, format("{}={:.2R}", state.dataIPShortCut->cNumericFieldNames(8), NumArray(8)));
384 0 : ShowContinueError(state, format("{}={:.2R}", state.dataIPShortCut->cNumericFieldNames(9), NumArray(9)));
385 0 : ErrorsFound = true;
386 : }
387 :
388 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).StandbyPower = NumArray(10);
389 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).StandbyPower < 0.0) {
390 0 : ShowWarningError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(10), NumArray(10)));
391 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
392 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(10)));
393 0 : ShowContinueError(state, "Resetting to 0 and the simulation continues.");
394 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).StandbyPower = 0.0;
395 : }
396 :
397 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPower = NumArray(11);
398 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPower < 0.0) {
399 0 : ShowWarningError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(11), NumArray(11)));
400 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
401 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(11)));
402 0 : ShowContinueError(state, "Resetting to 0 and the simulation continues.");
403 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPower = 0.0;
404 : }
405 :
406 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum =
407 7 : Curve::GetCurveIndex(state, AlphArray(6)); // Convert curve name to number
408 : // If blank, then the calc routine assumes modifier curve value = 1 for entire simulation
409 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(6) && state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum == 0) {
410 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(6), AlphArray(6)));
411 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
412 0 : ErrorsFound = true;
413 7 : } else if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum > 0) {
414 : // Verify curve object, only legal type is Quadratic
415 :
416 0 : if (!ErrorsFound) {
417 : // Fuel mass flow rate at reference conditions (kg/s)
418 0 : Real64 RefFuelUseMdot = (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput /
419 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV) /
420 0 : (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue * 1000.0);
421 : // Output of Ancillary Power Modifier Curve (function of temps and fuel flow)
422 : Real64 AncillaryPowerOutput =
423 0 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum, RefFuelUseMdot);
424 0 : if (std::abs(AncillaryPowerOutput - 1.0) > 0.1) {
425 0 : ShowWarningError(
426 : state,
427 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
428 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(6), AlphArray(6)));
429 0 : ShowContinueError(state, "... Curve output at reference conditions should equal 1 (+-10%).");
430 0 : ShowContinueError(state,
431 0 : format("... Reference Electrical Power Output = {:.2T} W",
432 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput));
433 0 : ShowContinueError(state,
434 0 : format("... Reference Electrical Efficiency (LHV basis) = {:.4T}",
435 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV));
436 0 : ShowContinueError(state,
437 0 : format("... Fuel Lower Heating Value = {:.2T} kJ/kg",
438 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue));
439 0 : ShowContinueError(state, format("... Calculated fuel flow = {:.4T} kg/s", RefFuelUseMdot));
440 0 : ShowContinueError(state, format("... Curve output = {:.4T}", AncillaryPowerOutput));
441 : }
442 : }
443 : }
444 :
445 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
446 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum =
447 0 : NodeInputManager::GetOnlySingleNode(state,
448 0 : AlphArray(7),
449 : ErrorsFound,
450 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
451 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
452 : DataLoopNode::NodeFluidType::Water,
453 : DataLoopNode::ConnectionType::Inlet,
454 : NodeInputManager::CompFluidStream::Primary,
455 : DataLoopNode::ObjectIsNotParent);
456 : }
457 :
458 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(8)) {
459 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum =
460 0 : NodeInputManager::GetOnlySingleNode(state,
461 0 : AlphArray(8),
462 : ErrorsFound,
463 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
464 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
465 : DataLoopNode::NodeFluidType::Water,
466 : DataLoopNode::ConnectionType::Outlet,
467 : NodeInputManager::CompFluidStream::Primary,
468 : DataLoopNode::ObjectIsNotParent);
469 : }
470 :
471 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum > 0 &&
472 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum > 0) {
473 0 : BranchNodeConnections::TestCompSet(state,
474 0 : state.dataIPShortCut->cCurrentModuleObject,
475 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
476 0 : AlphArray(7),
477 0 : AlphArray(8),
478 : "Heat Recovery Nodes");
479 : }
480 :
481 7 : if ((state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum > 0 &&
482 14 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum == 0) ||
483 7 : (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum == 0 &&
484 7 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum > 0)) {
485 0 : ShowSevereError(
486 0 : state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
487 0 : ShowContinueError(state, "... If one Heat Recovery Water Node Name is specified, then both the Inlet and Outlet Heat Recovery");
488 0 : ShowContinueError(state, "... Water Node Names must be specified. Only one water node is being specified for this generator.");
489 0 : ErrorsFound = true;
490 : }
491 :
492 : // Heat recovery to water input fields only valid if water nodes are defined
493 7 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum != 0 &&
494 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum != 0) {
495 :
496 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecActive = true;
497 :
498 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV = NumArray(12);
499 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV < 0.0) {
500 0 : ShowWarningError(
501 : state,
502 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
503 0 : ShowContinueError(state, format("{} must be >= 0.", state.dataIPShortCut->cNumericFieldNames(12)));
504 0 : ShowContinueError(state, "Resetting to 0 and the simulation continues.");
505 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV = 0.0;
506 : }
507 :
508 : // Next store thermal power output ranges using nominal thermal to electrical efficiency ratio and electrical power data
509 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalPowerOutput =
510 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput *
511 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
512 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
513 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinThermalPowerOutput =
514 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput *
515 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
516 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
517 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxThermalPowerOutput =
518 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput *
519 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
520 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
521 :
522 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp = NumArray(13);
523 :
524 0 : if (Util::SameString(AlphArray(9), "InternalControl")) {
525 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).InternalFlowControl =
526 : true; // A9, \field Heat Recovery Water Flow Operating Mode
527 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).PlantFlowControl = false;
528 : }
529 0 : if ((!(Util::SameString(AlphArray(9), "InternalControl"))) && (!(Util::SameString(AlphArray(9), "PlantControl")))) {
530 0 : ShowSevereError(state, format("Invalid {}={}", state.dataIPShortCut->cAlphaFieldNames(9), AlphArray(9)));
531 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
532 0 : ShowContinueError(state, "Operating Mode must be INTERNAL CONTROL or PLANT CONTROL.");
533 0 : ErrorsFound = true;
534 : }
535 :
536 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate = NumArray(14);
537 :
538 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate <= 0.0) {
539 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(14), NumArray(14)));
540 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
541 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(14)));
542 0 : ErrorsFound = true;
543 : }
544 :
545 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).InternalFlowControl) { // Get Heat Recovery Water Flow Rate Modifier Curve
546 :
547 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecFlowFTempPowCurveNum = Curve::GetCurveIndex(state, AlphArray(10));
548 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecFlowFTempPowCurveNum != 0) {
549 : // Verify curve object, only legal type is BiQuadratic
550 : }
551 :
552 : } // End of IF (MTGenerator(GeneratorNum)%InternalFlowControl) THEN
553 :
554 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum =
555 0 : Curve::GetCurveIndex(state, AlphArray(11)); // convert curve name to number
556 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum != 0) {
557 : // Verify curve object, only legal types are BiQuadratic and BiCubic
558 :
559 0 : if (!ErrorsFound) {
560 : // Output of Thermal Efficiency Modifier Curve (function of temp and elevation)
561 : Real64 ThermalEffTempElevOutput =
562 0 : Curve::CurveValue(state,
563 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum,
564 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
565 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation);
566 :
567 0 : if (std::abs(ThermalEffTempElevOutput - 1.0) > 0.1) {
568 0 : ShowWarningError(state,
569 0 : format("{} \"{}\"",
570 0 : state.dataIPShortCut->cCurrentModuleObject,
571 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
572 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(11), AlphArray(11)));
573 0 : ShowContinueError(state, "... Curve output at reference conditions should equal 1 (+-10%).");
574 0 : ShowContinueError(state,
575 0 : format("... Reference combustion air inlet temperature = {:.4T} C",
576 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
577 0 : ShowContinueError(state,
578 0 : format("... Reference elevation = {:.4T} m",
579 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation));
580 : }
581 : }
582 : }
583 :
584 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum =
585 0 : Curve::GetCurveIndex(state, AlphArray(12)); // convert curve name to number
586 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum != 0) {
587 : // Verify curve object, only legal types are Quadratic or Cubic
588 :
589 0 : if (!ErrorsFound) {
590 : // Output of Heat Recovery Rate Modifier Curve (function of PLR)
591 : Real64 HeatRecRateFPLROutput =
592 0 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum, 1.0);
593 :
594 0 : if (std::abs(HeatRecRateFPLROutput - 1.0) > 0.1) {
595 0 : ShowWarningError(state,
596 0 : format("{} \"{}\"",
597 0 : state.dataIPShortCut->cCurrentModuleObject,
598 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
599 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(12), AlphArray(12)));
600 0 : ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
601 0 : ShowContinueError(state, format("... Curve output = {:.4T}", HeatRecRateFPLROutput));
602 : }
603 : }
604 : }
605 :
606 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum =
607 0 : Curve::GetCurveIndex(state, AlphArray(13)); // convert curve name to number
608 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum != 0) {
609 : // Verify curve object, only legal type is Quadratic
610 :
611 0 : if (!ErrorsFound) {
612 : // Output of Heat Recovery Rate Modifier Curve (function of inlet water temp)
613 0 : Real64 HeatRecRateFTempOutput = Curve::CurveValue(state,
614 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum,
615 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp);
616 :
617 0 : if (std::abs(HeatRecRateFTempOutput - 1.0) > 0.1) {
618 0 : ShowWarningError(state,
619 0 : format("{} \"{}\"",
620 0 : state.dataIPShortCut->cCurrentModuleObject,
621 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
622 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(13), AlphArray(13)));
623 0 : ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
624 0 : ShowContinueError(state,
625 0 : format("... Reference inlet water temperature temperature = {:.4T} C",
626 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp));
627 0 : ShowContinueError(state, format("... Curve output = {:.4T}", HeatRecRateFTempOutput));
628 : }
629 : }
630 : }
631 :
632 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum = Curve::GetCurveIndex(state, AlphArray(14));
633 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum != 0) {
634 : // Verify curve object, only legal type is Quadratic
635 :
636 0 : if (!ErrorsFound) {
637 : // Output of Heat Recovery Rate Modifier Curve (function of water flow rate)
638 : Real64 HeatRecRateFFlowOutput =
639 0 : Curve::CurveValue(state,
640 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum,
641 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate);
642 :
643 0 : if (std::abs(HeatRecRateFFlowOutput - 1.0) > 0.1) {
644 0 : ShowWarningError(state,
645 0 : format("{} \"{}\"",
646 0 : state.dataIPShortCut->cCurrentModuleObject,
647 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
648 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(14), AlphArray(14)));
649 0 : ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
650 0 : ShowContinueError(state,
651 0 : format("... Reference Heat Recovery Water Flow Rate = {:.4T} m3/s",
652 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate));
653 0 : ShowContinueError(state, format("... Curve output = {:.4T}", HeatRecRateFFlowOutput));
654 : }
655 : }
656 : }
657 :
658 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate = NumArray(15);
659 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate < 0.0) {
660 0 : ShowWarningError(
661 : state,
662 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
663 0 : ShowContinueError(state, format("{} must be >= 0.", state.dataIPShortCut->cNumericFieldNames(15)));
664 0 : ShowContinueError(state, "Resetting to 0 and the simulation continues.");
665 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate = 0.0;
666 : }
667 :
668 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate = NumArray(16);
669 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate < 0.0) {
670 0 : ShowWarningError(
671 : state,
672 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
673 0 : ShowContinueError(state, format("{} must be >= 0.", state.dataIPShortCut->cNumericFieldNames(16)));
674 0 : ShowContinueError(state, "Resetting to 0 and the simulation continues.");
675 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate = 0.0;
676 : }
677 :
678 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate <
679 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate) {
680 0 : ShowWarningError(
681 : state,
682 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
683 0 : ShowContinueError(
684 0 : state, format("{} must be >= {}", state.dataIPShortCut->cNumericFieldNames(16), state.dataIPShortCut->cNumericFieldNames(15)));
685 0 : ShowContinueError(state,
686 0 : format("Resetting {} = {} and the simulation continues.",
687 0 : state.dataIPShortCut->cNumericFieldNames(16),
688 0 : state.dataIPShortCut->cNumericFieldNames(15)));
689 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate =
690 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate;
691 : }
692 :
693 : // Check if reference heat recovery water flow rate is below the minimum flow rate
694 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate <
695 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate) {
696 0 : ShowWarningError(
697 : state,
698 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
699 0 : ShowContinueError(
700 0 : state, format("{} must be >= {}", state.dataIPShortCut->cNumericFieldNames(14), state.dataIPShortCut->cNumericFieldNames(15)));
701 0 : ShowContinueError(state,
702 0 : format("Resetting {} = {} and the simulation continues.",
703 0 : state.dataIPShortCut->cNumericFieldNames(14),
704 0 : state.dataIPShortCut->cNumericFieldNames(15)));
705 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate =
706 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate;
707 : }
708 :
709 : // Check if reference heat recovery water flow rate is above the maximum flow rate
710 0 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate >
711 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate) {
712 0 : ShowWarningError(
713 : state,
714 0 : format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
715 0 : ShowContinueError(
716 0 : state, format("{} must be <= {}", state.dataIPShortCut->cNumericFieldNames(14), state.dataIPShortCut->cNumericFieldNames(16)));
717 0 : ShowContinueError(state,
718 0 : format("Resetting {} = {} and the simulation continues.",
719 0 : state.dataIPShortCut->cNumericFieldNames(14),
720 0 : state.dataIPShortCut->cNumericFieldNames(16)));
721 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate =
722 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate;
723 : }
724 :
725 0 : PlantUtilities::RegisterPlantCompDesignFlow(state,
726 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum,
727 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate);
728 :
729 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxWaterTemp = NumArray(17);
730 :
731 : } // End of 'IF (MTGenerator(GeneratorNum)%HeatRecInletNodeNum .NE. 0 .AND. &
732 : // MTGenerator(GeneratorNum)%HeatRecOutletNodeNum .NE. 0) THEN'
733 :
734 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(15)) {
735 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum =
736 18 : NodeInputManager::GetOnlySingleNode(state,
737 6 : AlphArray(15),
738 : ErrorsFound,
739 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
740 6 : AlphArray(1),
741 : DataLoopNode::NodeFluidType::Air,
742 : DataLoopNode::ConnectionType::Inlet,
743 : NodeInputManager::CompFluidStream::Secondary,
744 : DataLoopNode::ObjectIsNotParent);
745 : }
746 :
747 : // Combustion air inlet node must be an outside air node
748 13 : if (!state.dataIPShortCut->lAlphaFieldBlanks(15) &&
749 6 : !OutAirNodeManager::CheckOutAirNodeNumber(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum)) {
750 0 : ShowSevereError(
751 0 : state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
752 0 : ShowContinueError(state, format("{} is not a valid Outdoor Air Node = {}", state.dataIPShortCut->cAlphaFieldNames(15), AlphArray(15)));
753 0 : ShowContinueError(state, "it does not appear in an OutdoorAir:NodeList or as an OutdoorAir:Node.");
754 0 : ErrorsFound = true;
755 : }
756 :
757 7 : if (!state.dataIPShortCut->lAlphaFieldBlanks(16)) {
758 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum =
759 18 : NodeInputManager::GetOnlySingleNode(state,
760 6 : AlphArray(16),
761 : ErrorsFound,
762 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
763 6 : AlphArray(1),
764 : DataLoopNode::NodeFluidType::Air,
765 : DataLoopNode::ConnectionType::Outlet,
766 : NodeInputManager::CompFluidStream::Secondary,
767 : DataLoopNode::ObjectIsNotParent);
768 : }
769 :
770 13 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum > 0 &&
771 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum == 0) {
772 0 : ShowSevereError(
773 0 : state, format("{} \"{}\"", state.dataIPShortCut->cCurrentModuleObject, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
774 0 : ShowContinueError(state,
775 0 : format("A {} must be specified when a {} is specified.",
776 0 : state.dataIPShortCut->cAlphaFieldNames(15),
777 0 : state.dataIPShortCut->cAlphaFieldNames(16)));
778 0 : ErrorsFound = true;
779 : }
780 :
781 : // Get other exhaust air inputs only if combustion air inlet and outlet nodes are valid
782 13 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum > 0 &&
783 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum > 0) {
784 :
785 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirCalcsActive = true;
786 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefExhaustAirMassFlowRate = NumArray(18);
787 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefExhaustAirMassFlowRate <= 0.0 &&
788 0 : !state.dataIPShortCut->lNumericFieldBlanks(18)) {
789 0 : ShowSevereError(state, format("Invalid {}={:.2R}", state.dataIPShortCut->cNumericFieldNames(18), NumArray(18)));
790 0 : ShowContinueError(state, format("Entered in {}={}", state.dataIPShortCut->cCurrentModuleObject, AlphArray(1)));
791 0 : ShowContinueError(state, format("{} must be greater than 0.", state.dataIPShortCut->cNumericFieldNames(18)));
792 0 : ErrorsFound = true;
793 : }
794 :
795 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum = Curve::GetCurveIndex(state, AlphArray(17));
796 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum != 0) {
797 : // Verify curve object, only legal types are Quadratic and Cubic
798 :
799 6 : if (!ErrorsFound) {
800 : // Output of Exhaust Air Flow Modifier Curve (function of inlet air temp)
801 18 : Real64 ExhFlowFTempOutput = Curve::CurveValue(state,
802 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum,
803 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
804 :
805 6 : if (std::abs(ExhFlowFTempOutput - 1.0) > 0.1) {
806 0 : ShowWarningError(state,
807 0 : format("{} \"{}\"",
808 0 : state.dataIPShortCut->cCurrentModuleObject,
809 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
810 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(17), AlphArray(17)));
811 0 : ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
812 0 : ShowContinueError(state,
813 0 : format("... Reference combustion air inlet temperature = {:.4T} C",
814 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
815 0 : ShowContinueError(state, format("... Curve output = {:.4T}", ExhFlowFTempOutput));
816 : }
817 : }
818 : }
819 :
820 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum =
821 6 : Curve::GetCurveIndex(state, AlphArray(18)); // convert curve name to number
822 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum != 0) {
823 : // Verify curve object, legal types are Quadratic or Cubic
824 :
825 6 : if (!ErrorsFound) {
826 : // Output of Exhaust Air Flow Modifier Curve (function of PLR)
827 : Real64 ExhFlowFPLROutput =
828 6 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum, 1.0);
829 :
830 6 : if (std::abs(ExhFlowFPLROutput - 1.0) > 0.1) {
831 0 : ShowWarningError(state,
832 0 : format("{} \"{}\"",
833 0 : state.dataIPShortCut->cCurrentModuleObject,
834 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
835 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(18), AlphArray(18)));
836 0 : ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
837 0 : ShowContinueError(state, format("... Curve output = {:.4T}", ExhFlowFPLROutput));
838 : }
839 : }
840 : }
841 :
842 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).NomExhAirOutletTemp = NumArray(19);
843 :
844 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum = Curve::GetCurveIndex(state, AlphArray(19));
845 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum != 0) {
846 : // Verify curve object, only legal types are Quadratic and Cubic
847 :
848 6 : if (!ErrorsFound) {
849 : // Output of Exhaust Air Temperature Modifier Curve (function of inlet air temp)
850 18 : Real64 ExhAirTempFTempOutput = Curve::CurveValue(state,
851 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum,
852 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
853 :
854 6 : if (std::abs(ExhAirTempFTempOutput - 1.0) > 0.1) {
855 0 : ShowWarningError(state,
856 0 : format("{} \"{}\"",
857 0 : state.dataIPShortCut->cCurrentModuleObject,
858 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
859 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(19), AlphArray(19)));
860 0 : ShowContinueError(state, "... Curve output at reference condition should equal 1 (+-10%).");
861 0 : ShowContinueError(state,
862 0 : format("... Reference combustion air inlet temperature = {:.4T} C",
863 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp));
864 0 : ShowContinueError(state, format("... Curve output = {:.4T}", ExhAirTempFTempOutput));
865 : }
866 : }
867 : }
868 :
869 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum =
870 6 : Curve::GetCurveIndex(state, AlphArray(20)); // convert curve name to number
871 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum != 0) {
872 : // Verify curve object, legal types are Quadratic or Cubic
873 :
874 6 : if (!ErrorsFound) {
875 : // Output of Exhaust Air Temperature Modifier Curve (function of PLR)
876 : Real64 ExhOutAirTempFPLROutput =
877 6 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum, 1.0);
878 :
879 6 : if (std::abs(ExhOutAirTempFPLROutput - 1.0) > 0.1) {
880 0 : ShowWarningError(state,
881 0 : format("{} \"{}\"",
882 0 : state.dataIPShortCut->cCurrentModuleObject,
883 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name));
884 0 : ShowContinueError(state, format("{} = {}", state.dataIPShortCut->cAlphaFieldNames(20), AlphArray(20)));
885 0 : ShowContinueError(state, "... Curve output at a part-load ratio of 1 should equal 1 (+-10%).");
886 0 : ShowContinueError(state, format("... Curve output = {:.4T}", ExhOutAirTempFPLROutput));
887 : }
888 : }
889 : }
890 :
891 : } // End of ' IF (MTGenerator(GeneratorNum)%CombustionAirOutletNodeNum .GT. 0 .AND. &
892 : // MTGenerator(GeneratorNum)%CombustionAirInletNodeNum .GT. 0) THEN
893 7 : }
894 :
895 5 : if (ErrorsFound) {
896 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
897 : }
898 5 : }
899 :
900 0 : void MTGeneratorSpecs::setupOutputVars(EnergyPlusData &state)
901 : {
902 0 : std::string_view const sFuelType = Constant::eFuelNames[static_cast<int>(this->FuelType)];
903 0 : SetupOutputVariable(state,
904 : "Generator Produced AC Electricity Rate",
905 : Constant::Units::W,
906 0 : this->ElecPowerGenerated,
907 : OutputProcessor::TimeStepType::System,
908 : OutputProcessor::StoreType::Average,
909 0 : this->Name);
910 :
911 0 : SetupOutputVariable(state,
912 : "Generator Produced AC Electricity Energy",
913 : Constant::Units::J,
914 0 : this->EnergyGen,
915 : OutputProcessor::TimeStepType::System,
916 : OutputProcessor::StoreType::Sum,
917 0 : this->Name,
918 : Constant::eResource::ElectricityProduced,
919 : OutputProcessor::Group::Plant,
920 : OutputProcessor::EndUseCat::Cogeneration);
921 :
922 0 : SetupOutputVariable(state,
923 : "Generator LHV Basis Electric Efficiency",
924 : Constant::Units::None,
925 0 : this->ElectricEfficiencyLHV,
926 : OutputProcessor::TimeStepType::System,
927 : OutputProcessor::StoreType::Average,
928 0 : this->Name);
929 :
930 : // Fuel specific report variables
931 0 : SetupOutputVariable(state,
932 0 : format("Generator {} HHV Basis Rate", sFuelType),
933 : Constant::Units::W,
934 0 : this->FuelEnergyUseRateHHV,
935 : OutputProcessor::TimeStepType::System,
936 : OutputProcessor::StoreType::Average,
937 0 : this->Name);
938 :
939 0 : SetupOutputVariable(state,
940 0 : format("Generator {} HHV Basis Energy", sFuelType),
941 : Constant::Units::J,
942 0 : this->FuelEnergyHHV,
943 : OutputProcessor::TimeStepType::System,
944 : OutputProcessor::StoreType::Sum,
945 0 : this->Name,
946 0 : Constant::eFuel2eResource[(int)this->FuelType],
947 : OutputProcessor::Group::Plant,
948 : OutputProcessor::EndUseCat::Cogeneration);
949 :
950 0 : SetupOutputVariable(state,
951 0 : format("Generator {} Mass Flow Rate", sFuelType),
952 : Constant::Units::kg_s,
953 0 : this->FuelMdot,
954 : OutputProcessor::TimeStepType::System,
955 : OutputProcessor::StoreType::Average,
956 0 : this->Name);
957 :
958 : // general fuel use report (to match other generators)
959 0 : SetupOutputVariable(state,
960 : "Generator Fuel HHV Basis Rate",
961 : Constant::Units::W,
962 0 : this->FuelEnergyUseRateHHV,
963 : OutputProcessor::TimeStepType::System,
964 : OutputProcessor::StoreType::Average,
965 0 : this->Name);
966 :
967 0 : SetupOutputVariable(state,
968 : "Generator Fuel HHV Basis Energy",
969 : Constant::Units::J,
970 0 : this->FuelEnergyHHV,
971 : OutputProcessor::TimeStepType::System,
972 : OutputProcessor::StoreType::Sum,
973 0 : this->Name);
974 :
975 : // Heat recovery (to water) report variables
976 0 : if (this->HeatRecActive) {
977 :
978 0 : SetupOutputVariable(state,
979 : "Generator Produced Thermal Rate",
980 : Constant::Units::W,
981 0 : this->QHeatRecovered,
982 : OutputProcessor::TimeStepType::System,
983 : OutputProcessor::StoreType::Average,
984 0 : this->Name);
985 :
986 0 : SetupOutputVariable(state,
987 : "Generator Produced Thermal Energy",
988 : Constant::Units::J,
989 0 : this->ExhaustEnergyRec,
990 : OutputProcessor::TimeStepType::System,
991 : OutputProcessor::StoreType::Sum,
992 0 : this->Name,
993 : Constant::eResource::EnergyTransfer,
994 : OutputProcessor::Group::Plant,
995 : OutputProcessor::EndUseCat::HeatRecovery);
996 :
997 0 : SetupOutputVariable(state,
998 : "Generator Thermal Efficiency LHV Basis",
999 : Constant::Units::None,
1000 0 : this->ThermalEfficiencyLHV,
1001 : OutputProcessor::TimeStepType::System,
1002 : OutputProcessor::StoreType::Average,
1003 0 : this->Name);
1004 :
1005 0 : SetupOutputVariable(state,
1006 : "Generator Heat Recovery Inlet Temperature",
1007 : Constant::Units::C,
1008 0 : this->HeatRecInletTemp,
1009 : OutputProcessor::TimeStepType::System,
1010 : OutputProcessor::StoreType::Average,
1011 0 : this->Name);
1012 :
1013 0 : SetupOutputVariable(state,
1014 : "Generator Heat Recovery Outlet Temperature",
1015 : Constant::Units::C,
1016 0 : this->HeatRecOutletTemp,
1017 : OutputProcessor::TimeStepType::System,
1018 : OutputProcessor::StoreType::Average,
1019 0 : this->Name);
1020 :
1021 0 : SetupOutputVariable(state,
1022 : "Generator Heat Recovery Water Mass Flow Rate",
1023 : Constant::Units::kg_s,
1024 0 : this->HeatRecMdot,
1025 : OutputProcessor::TimeStepType::System,
1026 : OutputProcessor::StoreType::Average,
1027 0 : this->Name);
1028 : }
1029 :
1030 0 : if (this->StandbyPower > 0.0) { // Report Standby Power if entered by user
1031 0 : SetupOutputVariable(state,
1032 : "Generator Standby Electricity Rate",
1033 : Constant::Units::W,
1034 0 : this->StandbyPowerRate,
1035 : OutputProcessor::TimeStepType::System,
1036 : OutputProcessor::StoreType::Average,
1037 0 : this->Name);
1038 :
1039 0 : SetupOutputVariable(state,
1040 : "Generator Standby Electricity Energy",
1041 : Constant::Units::J,
1042 0 : this->StandbyEnergy,
1043 : OutputProcessor::TimeStepType::System,
1044 : OutputProcessor::StoreType::Sum,
1045 0 : this->Name,
1046 : Constant::eResource::Electricity,
1047 : OutputProcessor::Group::Plant,
1048 : OutputProcessor::EndUseCat::Cogeneration);
1049 : }
1050 :
1051 0 : if (this->AncillaryPower > 0.0) { // Report Ancillary Power if entered by user
1052 0 : SetupOutputVariable(state,
1053 : "Generator Ancillary Electricity Rate",
1054 : Constant::Units::W,
1055 0 : this->AncillaryPowerRate,
1056 : OutputProcessor::TimeStepType::System,
1057 : OutputProcessor::StoreType::Average,
1058 0 : this->Name);
1059 :
1060 0 : SetupOutputVariable(state,
1061 : "Generator Ancillary Electricity Energy",
1062 : Constant::Units::J,
1063 0 : this->AncillaryEnergy,
1064 : OutputProcessor::TimeStepType::System,
1065 : OutputProcessor::StoreType::Sum,
1066 0 : this->Name);
1067 : }
1068 :
1069 : // Report combustion air outlet conditions if exhaust air calculations are active
1070 0 : if (this->ExhAirCalcsActive) {
1071 0 : SetupOutputVariable(state,
1072 : "Generator Exhaust Air Mass Flow Rate",
1073 : Constant::Units::kg_s,
1074 0 : this->ExhaustAirMassFlowRate,
1075 : OutputProcessor::TimeStepType::System,
1076 : OutputProcessor::StoreType::Average,
1077 0 : this->Name);
1078 :
1079 0 : SetupOutputVariable(state,
1080 : "Generator Exhaust Air Temperature",
1081 : Constant::Units::C,
1082 0 : this->ExhaustAirTemperature,
1083 : OutputProcessor::TimeStepType::System,
1084 : OutputProcessor::StoreType::Average,
1085 0 : this->Name);
1086 : }
1087 0 : }
1088 :
1089 0 : void MTGeneratorSpecs::simulate([[maybe_unused]] EnergyPlusData &state,
1090 : [[maybe_unused]] const PlantLocation &calledFromLocation,
1091 : [[maybe_unused]] bool FirstHVACIteration,
1092 : [[maybe_unused]] Real64 &CurLoad,
1093 : [[maybe_unused]] bool RunFlag)
1094 : {
1095 : // empty function to emulate current behavior as of conversion to using the PlantComponent calling structure.
1096 : // calls from the plant side... do nothing.
1097 : // calls from the ElectricPowerServiceManger call the init, calc, and update worker functions
1098 0 : }
1099 :
1100 0 : void MTGeneratorSpecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
1101 : [[maybe_unused]] const PlantLocation &calledFromLocation,
1102 : Real64 &MaxLoad,
1103 : Real64 &MinLoad,
1104 : Real64 &OptLoad)
1105 : {
1106 0 : MaxLoad = 0.0;
1107 0 : MinLoad = 0.0;
1108 0 : OptLoad = 0.0;
1109 0 : }
1110 :
1111 0 : void MTGeneratorSpecs::InitMTGenerators(EnergyPlusData &state,
1112 : bool const RunFlag,
1113 : Real64 const MyLoad, // electrical load in W
1114 : bool const FirstHVACIteration)
1115 : {
1116 :
1117 : // SUBROUTINE INFORMATION:
1118 : // AUTHOR R. Raustad/D. Shirey
1119 : // DATE WRITTEN Mar 2008
1120 : // MODIFIED na
1121 : // RE-ENGINEERED B. Griffith, Sept 2010, plant upgrades, general fluid props
1122 :
1123 : // PURPOSE OF THIS SUBROUTINE:
1124 : // This subroutine is for initializations of the CT generators.
1125 :
1126 : // METHODOLOGY EMPLOYED:
1127 : // Uses the status flags to trigger initializations.
1128 :
1129 0 : this->oneTimeInit(state); // end one time inits
1130 :
1131 0 : if (!this->HeatRecActive) return;
1132 :
1133 : // Do the Begin Environment initializations
1134 0 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
1135 : // set the node max and min mass flow rates
1136 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1137 :
1138 0 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp = 20.0; // Set the node temperature, assuming freeze control
1139 0 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = 20.0;
1140 :
1141 0 : this->MyEnvrnFlag = false;
1142 : } // end environmental inits
1143 :
1144 0 : if (!state.dataGlobal->BeginEnvrnFlag) {
1145 0 : this->MyEnvrnFlag = true;
1146 : }
1147 :
1148 : // set/request flow rates
1149 0 : if (FirstHVACIteration) {
1150 :
1151 : Real64 DesiredMassFlowRate;
1152 0 : if (!RunFlag) {
1153 0 : DesiredMassFlowRate = 0.0;
1154 :
1155 0 : } else if (RunFlag && this->InternalFlowControl) {
1156 : // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
1157 0 : if (this->HeatRecFlowFTempPowCurveNum != 0) {
1158 0 : DesiredMassFlowRate =
1159 0 : this->DesignHeatRecMassFlowRate *
1160 0 : Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
1161 : } else {
1162 0 : DesiredMassFlowRate = this->DesignHeatRecMassFlowRate; // Assume modifier = 1 if curve not specified
1163 : }
1164 :
1165 0 : DesiredMassFlowRate = max(DataPrecisionGlobals::constant_zero, DesiredMassFlowRate); // protect from neg. curve result
1166 :
1167 0 : } else if (RunFlag && (!this->InternalFlowControl)) {
1168 0 : DesiredMassFlowRate = this->DesignHeatRecMassFlowRate;
1169 : }
1170 :
1171 0 : PlantUtilities::SetComponentFlowRate(state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1172 : } else { // not FirstHVACIteration
1173 0 : if (!RunFlag) {
1174 0 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
1175 0 : min(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMaxAvail);
1176 0 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
1177 0 : max(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMinAvail);
1178 :
1179 0 : } else if (RunFlag && this->InternalFlowControl) {
1180 : // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
1181 0 : if (this->HeatRecFlowFTempPowCurveNum != 0) {
1182 : Real64 DesiredMassFlowRate =
1183 0 : this->DesignHeatRecMassFlowRate *
1184 0 : Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
1185 0 : PlantUtilities::SetComponentFlowRate(
1186 0 : state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1187 : } else {
1188 0 : PlantUtilities::SetComponentFlowRate(
1189 0 : state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1190 : }
1191 0 : } else if (RunFlag && (!this->InternalFlowControl)) {
1192 0 : PlantUtilities::SetComponentFlowRate(state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1193 : }
1194 : }
1195 : }
1196 :
1197 0 : void MTGeneratorSpecs::CalcMTGeneratorModel(EnergyPlusData &state,
1198 : bool const RunFlag, // TRUE when generator is being asked to operate
1199 : Real64 const MyLoad) // Generator demand (W)
1200 : {
1201 : // SUBROUTINE INFORMATION:
1202 : // AUTHOR R. Raustad/D. Shirey
1203 : // DATE WRITTEN Mar 2008
1204 : // MODIFIED na
1205 : // RE-ENGINEERED na
1206 :
1207 : // PURPOSE OF THIS SUBROUTINE:
1208 : // Simulate a combustion generator.
1209 :
1210 : // METHODOLOGY EMPLOYED:
1211 : // Curve fits of performance data.
1212 :
1213 0 : Real64 constexpr KJtoJ(1000.0); // Convert kilojoules to joules
1214 0 : int constexpr MaxAncPowerIter(50); // Maximum number of iteration (subroutine ancillary power iteration loop)
1215 0 : Real64 constexpr AncPowerDiffToler(5.0); // Tolerance for Ancillary Power Difference (W)
1216 0 : Real64 constexpr RelaxFactor(0.7); // Relaxation factor for iteration loop
1217 : static constexpr std::string_view RoutineName("CalcMTGeneratorModel");
1218 :
1219 : // Load local variables from data structure (for code readability)
1220 : // Min allowed operating fraction at full load
1221 0 : Real64 minPartLoadRat = this->MinPartLoadRat;
1222 :
1223 : // Max allowed operating fraction at full load
1224 0 : Real64 maxPartLoadRat = this->MaxPartLoadRat;
1225 :
1226 : // Generator reference capacity (W)
1227 0 : Real64 ReferencePowerOutput = this->RefElecPowerOutput;
1228 :
1229 : // Reference electrical efficiency
1230 0 : Real64 RefElecEfficiency = this->RefElecEfficiencyLHV;
1231 :
1232 : // Initialize variables
1233 0 : this->ElecPowerGenerated = 0.0;
1234 0 : this->HeatRecInletTemp = 0.0;
1235 0 : this->HeatRecOutletTemp = 0.0;
1236 0 : this->HeatRecMdot = 0.0;
1237 0 : this->QHeatRecovered = 0.0;
1238 0 : this->ExhaustEnergyRec = 0.0;
1239 0 : this->FuelEnergyUseRateHHV = 0.0;
1240 0 : this->FuelMdot = 0.0;
1241 0 : this->AncillaryPowerRate = 0.0;
1242 0 : this->StandbyPowerRate = 0.0;
1243 0 : this->FuelEnergyUseRateLHV = 0.0;
1244 0 : this->ExhaustAirMassFlowRate = 0.0;
1245 0 : this->ExhaustAirTemperature = 0.0;
1246 0 : this->ExhaustAirHumRat = 0.0;
1247 :
1248 : Real64 HeatRecInTemp; // Heat recovery fluid inlet temperature (C)
1249 : Real64 heatRecMdot; // Heat recovery fluid mass flow rate (kg/s)
1250 : Real64 HeatRecCp; // Specific heat of the heat recovery fluid (J/kg-K)
1251 :
1252 0 : if (this->HeatRecActive) {
1253 0 : HeatRecInTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
1254 0 : HeatRecCp = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getSpecificHeat(state, HeatRecInTemp, RoutineName);
1255 0 : heatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
1256 : } else {
1257 0 : HeatRecInTemp = 0.0;
1258 0 : HeatRecCp = 0.0;
1259 0 : heatRecMdot = 0.0;
1260 : }
1261 :
1262 : Real64 CombustionAirInletTemp; // Combustion air inlet temperature (C)
1263 : Real64 CombustionAirInletPress; // Barometric pressure of combustion inlet air (Pa)
1264 : Real64 CombustionAirInletW; // Combustion air inlet humidity ratio (kg/kg)
1265 :
1266 : // Set combustion inlet air temperature, humidity ratio and pressure local variables
1267 0 : if (this->CombustionAirInletNodeNum == 0) { // no inlet air node specified, so use weather file values
1268 0 : CombustionAirInletTemp = state.dataEnvrn->OutDryBulbTemp;
1269 0 : CombustionAirInletW = state.dataEnvrn->OutHumRat;
1270 0 : CombustionAirInletPress = state.dataEnvrn->OutBaroPress;
1271 : } else { // use inlet node information
1272 0 : CombustionAirInletTemp = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Temp;
1273 0 : CombustionAirInletW = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).HumRat;
1274 0 : CombustionAirInletPress = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Press;
1275 0 : if (state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Height > 0.0) {
1276 : }
1277 : // Initialize combustion outlet air conditions to inlet air conditions (all node properties)
1278 0 : if (this->ExhAirCalcsActive) {
1279 0 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum) = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum);
1280 : }
1281 : }
1282 :
1283 : // If no loop demand or generator OFF, set some variables and then return
1284 : // IF (.NOT. RunFlag .OR. MyLoad .LE. 0.0d0) THEN
1285 0 : if (MyLoad <= 0.0) {
1286 0 : this->HeatRecInletTemp = HeatRecInTemp;
1287 0 : this->HeatRecOutletTemp = HeatRecInTemp;
1288 0 : if (RunFlag) {
1289 0 : this->StandbyPowerRate = this->StandbyPower;
1290 : }
1291 0 : this->ExhaustAirTemperature = CombustionAirInletTemp;
1292 0 : this->ExhaustAirHumRat = CombustionAirInletW;
1293 0 : return;
1294 : }
1295 :
1296 : // Calculate power modifier curve value (function of inlet air temperature and elevation)
1297 : // Power ratio as a function of inlet air temperature and elevation
1298 0 : Real64 PowerFTempElev = Curve::CurveValue(state, this->ElecPowFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
1299 :
1300 : // Warn user if power modifier curve output is less than 0
1301 0 : if (PowerFTempElev < 0.0) {
1302 0 : if (this->PowerFTempElevErrorIndex == 0) {
1303 : // MTGenerator(GeneratorNum)%PowerFTempElevErrorCount = MTGenerator(GeneratorNum)%PowerFTempElevErrorCount + 1
1304 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1305 0 : ShowContinueError(state,
1306 0 : format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
1307 : PowerFTempElev));
1308 0 : ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1309 0 : ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
1310 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1311 : }
1312 0 : ShowRecurringWarningErrorAtEnd(state,
1313 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1314 : "\": Electrical Power Modifier curve is less than zero warning continues...",
1315 0 : this->PowerFTempElevErrorIndex,
1316 : PowerFTempElev,
1317 : PowerFTempElev);
1318 0 : PowerFTempElev = 0.0;
1319 : }
1320 :
1321 : // Calculate available full-load power output. cannot exceed maximum full-load power output.
1322 : // Generator full-load power output at actual inlet conditions and elevation (W)
1323 0 : Real64 FullLoadPowerOutput = min((ReferencePowerOutput * PowerFTempElev), this->MaxElecPowerOutput);
1324 : // Also can't be below the minimum full-load power output.
1325 0 : FullLoadPowerOutput = max(FullLoadPowerOutput, this->MinElecPowerOutput);
1326 :
1327 : // Ancillary power used by pump (if not specified in manufacturers data)
1328 0 : Real64 ancillaryPowerRate = this->AncillaryPower;
1329 :
1330 : // Difference between ancillary power rate and ancillary power rate last (last iteration)
1331 0 : Real64 AncillaryPowerRateDiff = AncPowerDiffToler + 1.0; // Initialize to force through DO WHILE Loop at least once
1332 :
1333 0 : Real64 PLR(0.0); // Generator operating part load ratio
1334 0 : Real64 elecPowerGenerated(0.0); // Generator electric power output (W)
1335 0 : Real64 FuelUseEnergyRateLHV(0.0); // Rate of fuel energy required to run microturbine, LHV basis (W)
1336 0 : Real64 fuelHigherHeatingValue(0.0); // Higher heating value (LLV) of fuel kJ/kg)
1337 0 : Real64 fuelLowerHeatingValue(0.0); // Lower heating value (LLV) of fuel kJ/kg)
1338 0 : Real64 AnciPowerFMdotFuel(0.0); // Ancillary power as a function of fuel flow curve output
1339 0 : int AncPowerCalcIterIndex = 0; // Index for subroutine iteration loop if Ancillary Power (function of fuel flow) is used
1340 :
1341 0 : while (AncillaryPowerRateDiff > AncPowerDiffToler && AncPowerCalcIterIndex <= MaxAncPowerIter) {
1342 :
1343 0 : ++AncPowerCalcIterIndex; // Increment iteration loop counter
1344 :
1345 : // Calculate operating power output (gross)
1346 0 : elecPowerGenerated = min(max(0.0, MyLoad + ancillaryPowerRate), FullLoadPowerOutput);
1347 :
1348 : // Calculate PLR, but must be between the minPLR and maxPLR
1349 0 : if (FullLoadPowerOutput > 0.0) {
1350 0 : PLR = min(elecPowerGenerated / FullLoadPowerOutput, maxPartLoadRat);
1351 0 : PLR = max(PLR, minPartLoadRat);
1352 : } else {
1353 0 : PLR = 0.0;
1354 : }
1355 :
1356 : // Recalculate elecPowerGenerated based on "final" PLR
1357 0 : elecPowerGenerated = FullLoadPowerOutput * PLR;
1358 :
1359 : // Calculate electrical efficiency modifier curve output (function of temp)
1360 : // Electrical efficiency as a function of temperature curve output
1361 0 : Real64 ElecEfficiencyFTemp = Curve::CurveValue(state, this->ElecEffFTempCurveNum, CombustionAirInletTemp);
1362 :
1363 : // Warn user if efficiency modifier curve output is less than 0
1364 0 : if (ElecEfficiencyFTemp < 0.0) {
1365 0 : if (this->EffFTempErrorIndex == 0) {
1366 : // MTGenerator(GeneratorNum)%EffFTempErrorCount = MTGenerator(GeneratorNum)%EffFTempErrorCount + 1
1367 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1368 0 : ShowContinueError(
1369 : state,
1370 0 : format("... Electrical Efficiency Modifier (function of temperature) output is less than zero ({:.4T}).", ElecEfficiencyFTemp));
1371 0 : ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1372 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1373 : }
1374 0 : ShowRecurringWarningErrorAtEnd(
1375 : state,
1376 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1377 : "\": Electrical Efficiency Modifier (function of temperature) output is less than zero warning continues...",
1378 0 : this->EffFTempErrorIndex,
1379 : ElecEfficiencyFTemp,
1380 : ElecEfficiencyFTemp);
1381 0 : ElecEfficiencyFTemp = 0.0;
1382 : }
1383 :
1384 : // Calculate efficiency modifier curve output (function of PLR)
1385 : // Electrical efficiency as a function of PLR curve output
1386 0 : Real64 ElecEfficiencyFPLR = Curve::CurveValue(state, this->ElecEffFPLRCurveNum, PLR);
1387 :
1388 : // Warn user if efficiency modifier curve output is less than 0
1389 0 : if (ElecEfficiencyFPLR < 0.0) {
1390 0 : if (this->EffFPLRErrorIndex == 0) {
1391 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1392 0 : ShowContinueError(state,
1393 0 : format("... Electrical Efficiency Modifier (function of part-load ratio) output is less than zero ({:.4T}).",
1394 : ElecEfficiencyFPLR));
1395 0 : ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
1396 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1397 : }
1398 0 : ShowRecurringWarningErrorAtEnd(
1399 : state,
1400 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1401 : "\": Electrical Efficiency Modifier (function of part-load ratio) output is less than zero warning continues...",
1402 0 : this->EffFPLRErrorIndex,
1403 : ElecEfficiencyFPLR,
1404 : ElecEfficiencyFPLR);
1405 0 : ElecEfficiencyFPLR = 0.0;
1406 : }
1407 :
1408 : // Calculate operating electrical efficiency
1409 : // Actual operating efficiency
1410 0 : Real64 OperatingElecEfficiency = RefElecEfficiency * ElecEfficiencyFTemp * ElecEfficiencyFPLR;
1411 :
1412 : // Calculate fuel use (W = J/s), LHV basis
1413 0 : if (OperatingElecEfficiency > 0.0) {
1414 0 : FuelUseEnergyRateLHV = elecPowerGenerated / OperatingElecEfficiency;
1415 : } else {
1416 0 : FuelUseEnergyRateLHV = 0.0; // If fuel use rate is zero, then
1417 0 : elecPowerGenerated = 0.0; // electric power generated must be zero.
1418 : }
1419 :
1420 : // Set fuel heating values
1421 0 : fuelHigherHeatingValue = this->FuelHigherHeatingValue;
1422 0 : fuelLowerHeatingValue = this->FuelLowerHeatingValue;
1423 :
1424 : // Calculate fuel mass flow rate
1425 0 : this->FuelMdot = FuelUseEnergyRateLHV / (fuelLowerHeatingValue * KJtoJ);
1426 :
1427 : // Calculate ancillary power requirement
1428 0 : if (this->AncillaryPowerFuelCurveNum > 0) {
1429 0 : AnciPowerFMdotFuel = Curve::CurveValue(state, this->AncillaryPowerFuelCurveNum, this->FuelMdot);
1430 : // Warn user if ancillary power modifier curve output is less than 0
1431 0 : if (AnciPowerFMdotFuel < 0.0) {
1432 0 : if (this->AnciPowerFMdotFuelErrorIndex == 0) {
1433 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1434 0 : ShowContinueError(
1435 : state,
1436 0 : format("... Ancillary Power Modifier (function of fuel input) output is less than zero ({:.4T}).", AnciPowerFMdotFuel));
1437 0 : ShowContinueError(state, format("... Value occurs using a fuel input mass flow rate of {:.4T} kg/s.", this->FuelMdot));
1438 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1439 : }
1440 0 : ShowRecurringWarningErrorAtEnd(
1441 : state,
1442 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1443 : "\": Ancillary Power Modifier (function of fuel input) output is less than zero warning continues...",
1444 0 : this->AnciPowerFMdotFuelErrorIndex,
1445 : AnciPowerFMdotFuel,
1446 : AnciPowerFMdotFuel);
1447 0 : AnciPowerFMdotFuel = 0.0;
1448 : }
1449 : } else {
1450 0 : AnciPowerFMdotFuel = 1.0;
1451 : }
1452 :
1453 : // Ancillary power used by pump from last iteration (iteration loop within this subroutine)
1454 0 : Real64 AncillaryPowerRateLast = ancillaryPowerRate;
1455 :
1456 0 : if (this->AncillaryPowerFuelCurveNum > 0) {
1457 0 : ancillaryPowerRate = RelaxFactor * this->AncillaryPower * AnciPowerFMdotFuel - (1.0 - RelaxFactor) * AncillaryPowerRateLast;
1458 : }
1459 :
1460 0 : AncillaryPowerRateDiff = std::abs(ancillaryPowerRate - AncillaryPowerRateLast);
1461 : }
1462 :
1463 0 : if (AncPowerCalcIterIndex > MaxAncPowerIter) {
1464 :
1465 0 : if (this->AnciPowerIterErrorIndex == 0) {
1466 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1467 0 : ShowContinueError(state, "... Iteration loop for electric power generation is not converging within tolerance.");
1468 0 : ShowContinueError(state, "... Check the Ancillary Power Modifier Curve (function of fuel input).");
1469 0 : ShowContinueError(state, format("... Ancillary Power = {:.1T} W.", ancillaryPowerRate));
1470 0 : ShowContinueError(state, format("... Fuel input rate = {:.4T} kg/s.", AnciPowerFMdotFuel));
1471 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1472 : }
1473 0 : ShowRecurringWarningErrorAtEnd(state,
1474 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1475 : "\": Iteration loop for electric power generation is not converging within tolerance continues...",
1476 0 : this->AnciPowerIterErrorIndex);
1477 : }
1478 :
1479 : // Calculate electrical power generated
1480 0 : this->ElecPowerGenerated = elecPowerGenerated - ancillaryPowerRate;
1481 :
1482 : // Report fuel energy use rate on HHV basis, which is the unit of measure when the fuel is sold
1483 0 : this->FuelEnergyUseRateHHV = this->FuelMdot * fuelHigherHeatingValue * KJtoJ;
1484 0 : this->AncillaryPowerRate = ancillaryPowerRate; // Move to data structure for later reporting
1485 0 : this->FuelEnergyUseRateLHV = FuelUseEnergyRateLHV; // Move to data structure for reporting calculations
1486 :
1487 : // When generator operates, standby losses are 0
1488 0 : this->StandbyPowerRate = 0.0;
1489 :
1490 0 : Real64 QHeatRecToWater = 0.0; // Recovered waste heat to water (W)
1491 :
1492 : // Calculate heat recovery if active
1493 0 : if (this->HeatRecActive) {
1494 :
1495 : // Thermal efficiency as a function of air temperature and elevation
1496 : Real64 ThermalEffFTempElev;
1497 0 : if (this->ThermEffFTempElevCurveNum > 0) {
1498 0 : ThermalEffFTempElev = Curve::CurveValue(state, this->ThermEffFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
1499 : // Warn user if power modifier curve output is less than 0
1500 0 : if (ThermalEffFTempElev < 0.0) {
1501 0 : if (this->ThermEffFTempElevErrorIndex == 0) {
1502 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1503 0 : ShowContinueError(
1504 : state,
1505 0 : format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
1506 : PowerFTempElev));
1507 0 : ShowContinueError(state,
1508 0 : format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1509 0 : ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
1510 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1511 : }
1512 0 : ShowRecurringWarningErrorAtEnd(state,
1513 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1514 : "\": Electrical Power Modifier curve is less than zero warning continues...",
1515 0 : this->ThermEffFTempElevErrorIndex,
1516 : ThermalEffFTempElev,
1517 : ThermalEffFTempElev);
1518 0 : ThermalEffFTempElev = 0.0;
1519 : }
1520 : } else {
1521 0 : ThermalEffFTempElev = 1.0; // If no curve provided, assume multiplier factor = 1.0
1522 : }
1523 :
1524 0 : QHeatRecToWater = FuelUseEnergyRateLHV * this->RefThermalEffLHV * ThermalEffFTempElev;
1525 : Real64 HeatRecRateFPLR; // Heat recovery rate as a function of PLR curve output
1526 :
1527 : // Calculate heat recovery rate modifier curve output (function of PLR)
1528 0 : if (this->HeatRecRateFPLRCurveNum > 0) {
1529 0 : HeatRecRateFPLR = Curve::CurveValue(state, this->HeatRecRateFPLRCurveNum, PLR);
1530 : // Warn user if heat recovery modifier curve output is less than 0
1531 0 : if (HeatRecRateFPLR < 0.0) {
1532 0 : if (this->HeatRecRateFPLRErrorIndex == 0) {
1533 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1534 0 : ShowContinueError(
1535 : state,
1536 0 : format("... Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero ({:.4T}).", HeatRecRateFPLR));
1537 0 : ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
1538 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1539 : }
1540 0 : ShowRecurringWarningErrorAtEnd(
1541 : state,
1542 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1543 : "\": Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero warning continues...",
1544 0 : this->HeatRecRateFPLRErrorIndex,
1545 : HeatRecRateFPLR,
1546 : HeatRecRateFPLR);
1547 0 : HeatRecRateFPLR = 0.0;
1548 : }
1549 : } else {
1550 0 : HeatRecRateFPLR = 1.0; // If no curve provided, assume multiplier factor = 1.0
1551 : }
1552 :
1553 : Real64 HeatRecRateFTemp; // Heat recovery rate as a function of inlet water temp curve output
1554 :
1555 : // Calculate heat recovery rate modifier curve output (function of inlet water temp)
1556 0 : if (this->HeatRecRateFTempCurveNum > 0) {
1557 0 : HeatRecRateFTemp = Curve::CurveValue(state, this->HeatRecRateFTempCurveNum, HeatRecInTemp);
1558 0 : if (HeatRecRateFTemp < 0.0) {
1559 0 : if (this->HeatRecRateFTempErrorIndex == 0) {
1560 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1561 0 : ShowContinueError(state,
1562 0 : format("... Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero ({:.4T}).",
1563 : HeatRecRateFTemp));
1564 0 : ShowContinueError(state, format("... Value occurs using an inlet water temperature temperature of {:.2T} C.", HeatRecInTemp));
1565 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1566 : }
1567 0 : ShowRecurringWarningErrorAtEnd(
1568 : state,
1569 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1570 : "\": Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero warning continues...",
1571 0 : this->HeatRecRateFTempErrorIndex,
1572 : HeatRecRateFTemp,
1573 : HeatRecRateFTemp);
1574 0 : HeatRecRateFTemp = 0.0;
1575 : }
1576 : } else {
1577 0 : HeatRecRateFTemp = 1.0; // If no curve provided, assume multiplier factor = 1.0
1578 : }
1579 :
1580 : Real64 HeatRecRateFFlow; // Heat recovery rate as a function of water flow rate curve output
1581 :
1582 : // Calculate heat recovery rate modifier curve output (function of water [volumetric] flow rate)
1583 0 : if (this->HeatRecRateFWaterFlowCurveNum > 0) {
1584 0 : Real64 rho = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getDensity(state, HeatRecInTemp, RoutineName);
1585 :
1586 : // Heat recovery fluid flow rate (m3/s)
1587 0 : Real64 HeatRecVolFlowRate = heatRecMdot / rho;
1588 0 : HeatRecRateFFlow = Curve::CurveValue(state, this->HeatRecRateFWaterFlowCurveNum, HeatRecVolFlowRate);
1589 0 : if (HeatRecRateFFlow < 0.0) {
1590 0 : if (this->HeatRecRateFFlowErrorIndex == 0) {
1591 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1592 0 : ShowContinueError(
1593 : state,
1594 0 : format("... Heat Recovery Rate Modifier (function of water flow rate) output is less than zero ({:.4T}).", HeatRecRateFFlow));
1595 0 : ShowContinueError(state, format("... Value occurs using a water flow rate of {:.4T} m3/s.", HeatRecVolFlowRate));
1596 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1597 : }
1598 0 : ShowRecurringWarningErrorAtEnd(
1599 : state,
1600 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1601 : "\": Heat Recovery Rate Modifier (function of water flow rate) output is less than zero warning continues...",
1602 0 : this->HeatRecRateFFlowErrorIndex,
1603 : HeatRecRateFFlow,
1604 : HeatRecRateFFlow);
1605 0 : HeatRecRateFFlow = 0.0;
1606 : }
1607 : } else {
1608 0 : HeatRecRateFFlow = 1.0; // If no curve provided, assume multiplier factor = 1.0
1609 : }
1610 :
1611 0 : QHeatRecToWater *= HeatRecRateFPLR * HeatRecRateFTemp * HeatRecRateFFlow;
1612 :
1613 : Real64 HeatRecOutTemp; // Heat recovery fluid outlet temperature (C)
1614 :
1615 : // Check for divide by zero
1616 0 : if ((heatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
1617 0 : HeatRecOutTemp = HeatRecInTemp + QHeatRecToWater / (heatRecMdot * HeatRecCp);
1618 : } else {
1619 0 : heatRecMdot = 0.0;
1620 0 : HeatRecOutTemp = HeatRecInTemp;
1621 0 : QHeatRecToWater = 0.0;
1622 : }
1623 :
1624 : // Now verify the maximum heat recovery temperature was not exceeded
1625 0 : if (HeatRecOutTemp > this->HeatRecMaxWaterTemp) {
1626 :
1627 0 : Real64 MinHeatRecMdot = 0.0; // Heat recovery flow rate if minimal heat recovery is accomplished (kg/s)
1628 :
1629 0 : if (this->HeatRecMaxWaterTemp != HeatRecInTemp) {
1630 0 : MinHeatRecMdot = QHeatRecToWater / (HeatRecCp * (this->HeatRecMaxWaterTemp - HeatRecInTemp));
1631 0 : if (MinHeatRecMdot < 0.0) MinHeatRecMdot = 0.0;
1632 : }
1633 :
1634 : // Recalculate outlet water temperature with minimum flow rate (will normally match the max water outlet temp,
1635 : // unless the inlet water temp is greater than the max outlet temp)
1636 : Real64 HRecRatio; // When maximum temperature is reached the amount of recovered heat has to be reduced
1637 :
1638 0 : if ((MinHeatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
1639 0 : HeatRecOutTemp = QHeatRecToWater / (MinHeatRecMdot * HeatRecCp) + HeatRecInTemp;
1640 0 : HRecRatio = heatRecMdot / MinHeatRecMdot;
1641 : } else {
1642 0 : HeatRecOutTemp = HeatRecInTemp;
1643 0 : HRecRatio = 0.0;
1644 : }
1645 0 : QHeatRecToWater *= HRecRatio; // Scale heat recovery rate using HRecRatio. Don't adjust flow rate.
1646 : }
1647 :
1648 : // Check water mass flow rate against minimum
1649 0 : if (this->HeatRecMinMassFlowRate > heatRecMdot && heatRecMdot > 0.0) {
1650 0 : if (this->HRMinFlowErrorIndex == 0) {
1651 0 : ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1652 0 : ShowContinueError(state,
1653 0 : format("...Heat reclaim water flow rate is below the generators minimum mass flow rate of ({:.4T}).",
1654 0 : this->HeatRecMinMassFlowRate));
1655 0 : ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
1656 0 : ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
1657 : }
1658 0 : ShowRecurringWarningErrorAtEnd(
1659 : state,
1660 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1661 : "\": Heat recovery water flow rate is below the generators minimum mass flow rate warning continues...",
1662 0 : this->HRMinFlowErrorIndex,
1663 : heatRecMdot,
1664 : heatRecMdot);
1665 : }
1666 :
1667 : // Check water mass flow rate against maximum
1668 0 : if (heatRecMdot > this->HeatRecMaxMassFlowRate && heatRecMdot > 0.0) {
1669 0 : if (this->HRMaxFlowErrorIndex == 0) {
1670 0 : ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1671 0 : ShowContinueError(state,
1672 0 : format("...Heat reclaim water flow rate is above the generators maximum mass flow rate of ({:.4T}).",
1673 0 : this->HeatRecMaxMassFlowRate));
1674 0 : ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
1675 0 : ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
1676 : }
1677 0 : ShowRecurringWarningErrorAtEnd(
1678 : state,
1679 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1680 : "\": Heat recovery water flow rate is above the generators maximum mass flow rate warning continues...",
1681 0 : this->HRMaxFlowErrorIndex,
1682 : heatRecMdot,
1683 : heatRecMdot);
1684 : }
1685 :
1686 : // Set report variables
1687 0 : this->HeatRecInletTemp = HeatRecInTemp;
1688 0 : this->HeatRecOutletTemp = HeatRecOutTemp;
1689 0 : this->HeatRecMdot = heatRecMdot;
1690 0 : this->QHeatRecovered = QHeatRecToWater;
1691 :
1692 : } // End of IF (MTGenerator(GeneratorNum)%HeatRecActive) THEN
1693 :
1694 : // Calculate combustion air outlet conditions if exhaust air calculations are active
1695 0 : if (this->ExhAirCalcsActive) {
1696 :
1697 : Real64 ExhFlowFTemp; // Exhaust air flow rate as a function of temperature curve output
1698 :
1699 0 : if (this->ExhFlowFTempCurveNum != 0) { // Exhaust Flow Rate versus Inlet Air Temp
1700 0 : ExhFlowFTemp = Curve::CurveValue(state, this->ExhFlowFTempCurveNum, CombustionAirInletTemp);
1701 : // Warn user if exhaust modifier curve output is less than or equal to 0
1702 0 : if (ExhFlowFTemp <= 0.0) {
1703 0 : if (this->ExhFlowFTempErrorIndex == 0) {
1704 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1705 0 : ShowContinueError(
1706 : state,
1707 0 : format("...Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
1708 : ExhFlowFTemp));
1709 0 : ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
1710 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1711 : }
1712 0 : ShowRecurringWarningErrorAtEnd(
1713 : state,
1714 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1715 : "\": Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero warning continues...",
1716 0 : this->ExhFlowFTempErrorIndex,
1717 : ExhFlowFTemp,
1718 : ExhFlowFTemp);
1719 0 : ExhFlowFTemp = 0.0;
1720 : }
1721 : } else {
1722 0 : ExhFlowFTemp = 1.0; // No curve input means modifier = 1.0 always
1723 : }
1724 :
1725 : Real64 ExhFlowFPLR; // Exhaust air flow rate as a function of part-load ratio curve output
1726 :
1727 0 : if (this->ExhFlowFPLRCurveNum != 0) { // Exhaust Flow Rate versus Part-Load Ratio
1728 0 : ExhFlowFPLR = Curve::CurveValue(state, this->ExhFlowFPLRCurveNum, PLR);
1729 : // Warn user if exhaust modifier curve output is less than or equal to 0
1730 0 : if (ExhFlowFPLR <= 0.0) {
1731 0 : if (this->ExhFlowFPLRErrorIndex == 0) {
1732 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1733 0 : ShowContinueError(
1734 : state,
1735 0 : format("...Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
1736 : ExhFlowFPLR));
1737 0 : ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
1738 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1739 : }
1740 0 : ShowRecurringWarningErrorAtEnd(state,
1741 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1742 : "\": Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or "
1743 : "equal to zero warning continues...",
1744 0 : this->ExhFlowFPLRErrorIndex,
1745 : ExhFlowFPLR,
1746 : ExhFlowFPLR);
1747 0 : ExhFlowFPLR = 0.0;
1748 : }
1749 : } else {
1750 0 : ExhFlowFPLR = 1.0; // No curve input means modifier = 1.0 always
1751 : }
1752 :
1753 : // Calculate exhaust air mass flow, accounting for temperature and PLR modifier factors
1754 : // Actual exhaust air mass flow rate (accounting for temp and PLR modifier curves)
1755 0 : Real64 ExhAirMassFlowRate = this->RefExhaustAirMassFlowRate * ExhFlowFTemp * ExhFlowFPLR;
1756 : // Adjust for difference in air density at reference conditions versus actual inlet air conditions
1757 :
1758 : // Density of air at actual combustion inlet air conditions (kg/m3)
1759 0 : Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, CombustionAirInletPress, CombustionAirInletTemp, CombustionAirInletW);
1760 0 : if (this->RefCombustAirInletDensity >= 0.0) {
1761 0 : ExhAirMassFlowRate = max(0.0, ExhAirMassFlowRate * AirDensity / this->RefCombustAirInletDensity);
1762 : } else {
1763 0 : ExhAirMassFlowRate = 0.0;
1764 : }
1765 0 : this->ExhaustAirMassFlowRate = ExhAirMassFlowRate;
1766 :
1767 : Real64 ExhAirTempFTemp; // Exhaust air temperature as a function of inlet air temp curve output
1768 :
1769 0 : if (this->ExhAirTempFTempCurveNum != 0) { // Exhaust Air Temp versus Inlet Air Temp
1770 0 : ExhAirTempFTemp = Curve::CurveValue(state, this->ExhAirTempFTempCurveNum, CombustionAirInletTemp);
1771 : // Warn user if exhaust modifier curve output is less than or equal to 0
1772 0 : if (ExhAirTempFTemp <= 0.0) {
1773 0 : if (this->ExhTempFTempErrorIndex == 0) {
1774 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1775 0 : ShowContinueError(
1776 : state,
1777 0 : format("...Exhaust Air Temperature Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
1778 : ExhAirTempFTemp));
1779 0 : ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
1780 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1781 : }
1782 0 : ShowRecurringWarningErrorAtEnd(state,
1783 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1784 : "\": Exhaust Air Temperature Modifier (function of temperature) output is less than or equal "
1785 : "to zero warning continues...",
1786 0 : this->ExhTempFTempErrorIndex,
1787 : ExhAirTempFTemp,
1788 : ExhAirTempFTemp);
1789 0 : ExhAirTempFTemp = 0.0;
1790 : }
1791 : } else {
1792 0 : ExhAirTempFTemp = 1.0; // No curve input means modifier = 1.0 always
1793 : }
1794 :
1795 : Real64 ExhAirTempFPLR; // Exhaust air temperature as a function of part-load ratio curve output
1796 :
1797 0 : if (this->ExhAirTempFPLRCurveNum != 0) { // Exhaust Air Temp versus Part-Load Ratio
1798 0 : ExhAirTempFPLR = Curve::CurveValue(state, this->ExhAirTempFPLRCurveNum, PLR);
1799 : // Warn user if exhaust modifier curve output is less than or equal to 0
1800 0 : if (ExhAirTempFPLR <= 0.0) {
1801 0 : if (this->ExhTempFPLRErrorIndex == 0) {
1802 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1803 0 : ShowContinueError(
1804 : state,
1805 0 : format("...Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
1806 : ExhAirTempFPLR));
1807 0 : ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
1808 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1809 : }
1810 0 : ShowRecurringWarningErrorAtEnd(state,
1811 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1812 : "\": Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or "
1813 : "equal to zero warning continues...",
1814 0 : this->ExhTempFPLRErrorIndex,
1815 : ExhAirTempFPLR,
1816 : ExhAirTempFPLR);
1817 0 : ExhAirTempFPLR = 0.0;
1818 : }
1819 : } else {
1820 0 : ExhAirTempFPLR = 1.0; // No curve input means modifier = 1.0 always
1821 : }
1822 :
1823 0 : if (ExhAirMassFlowRate <= 0.0) {
1824 0 : this->ExhaustAirTemperature = CombustionAirInletTemp;
1825 0 : this->ExhaustAirHumRat = CombustionAirInletW;
1826 : } else {
1827 : // Calculate exhaust air temperature, accounting for inlet air temperature and PLR modifier factors
1828 : // Actual exhaust air temperature (accounting for temp and PLR modifier curves)
1829 0 : Real64 ExhaustAirTemp = this->NomExhAirOutletTemp * ExhAirTempFTemp * ExhAirTempFPLR;
1830 0 : this->ExhaustAirTemperature = ExhaustAirTemp;
1831 : // Adjust exhaust air temperature if heat recovery to water is being done
1832 0 : if (QHeatRecToWater > 0.0) {
1833 0 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(CombustionAirInletW);
1834 0 : if (CpAir > 0.0) {
1835 0 : this->ExhaustAirTemperature = ExhaustAirTemp - QHeatRecToWater / (CpAir * ExhAirMassFlowRate);
1836 : }
1837 : }
1838 : // Calculate exhaust air humidity ratio
1839 :
1840 : // Heat of vaporization of water (J/kg)
1841 0 : Real64 H2OHtOfVap = Psychrometrics::PsyHfgAirFnWTdb(1.0, 16.0); // W not used, passing 1.0 as dummy.
1842 : // Assume fuel is at 16C (ASHRAE HOF)
1843 0 : if (H2OHtOfVap > 0.0) {
1844 0 : this->ExhaustAirHumRat = CombustionAirInletW + this->FuelMdot *
1845 0 : ((fuelHigherHeatingValue - fuelLowerHeatingValue) * KJtoJ / H2OHtOfVap) /
1846 : ExhAirMassFlowRate;
1847 : } else {
1848 0 : this->ExhaustAirHumRat = CombustionAirInletW;
1849 : }
1850 : }
1851 :
1852 0 : if (this->ExhaustAirTemperature < CombustionAirInletTemp) {
1853 0 : if (this->ExhTempLTInletTempIndex == 0) {
1854 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1855 0 : ShowContinueError(state,
1856 : "...The model has calculated the exhaust air temperature to be less than the combustion air inlet temperature.");
1857 0 : ShowContinueError(state, format("...Value of exhaust air temperature ={:.4T} C.", this->ExhaustAirTemperature));
1858 0 : ShowContinueError(state, format("...Value of combustion air inlet temp ={:.4T} C.", CombustionAirInletTemp));
1859 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1860 : }
1861 0 : ShowRecurringWarningErrorAtEnd(state,
1862 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1863 : "\": Exhaust air temperature less than combustion air inlet temperature warning continues...",
1864 0 : this->ExhTempLTInletTempIndex,
1865 0 : this->ExhaustAirTemperature,
1866 0 : this->ExhaustAirTemperature);
1867 : }
1868 :
1869 0 : if (this->ExhaustAirHumRat < CombustionAirInletW) {
1870 0 : if (this->ExhHRLTInletHRIndex == 0) {
1871 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1872 0 : ShowContinueError(
1873 : state, "...The model has calculated the exhaust air humidity ratio to be less than the combustion air inlet humidity ratio.");
1874 0 : ShowContinueError(state, format("...Value of exhaust air humidity ratio ={:.6T} kgWater/kgDryAir.", this->ExhaustAirHumRat));
1875 0 : ShowContinueError(state, format("...Value of combustion air inlet humidity ratio ={:.6T} kgWater/kgDryAir.", CombustionAirInletW));
1876 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1877 : }
1878 0 : ShowRecurringWarningErrorAtEnd(state,
1879 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1880 : "\": Exhaust air humidity ratio less than combustion air inlet humidity ratio warning continues...",
1881 0 : this->ExhHRLTInletHRIndex,
1882 0 : this->ExhaustAirHumRat,
1883 0 : this->ExhaustAirHumRat);
1884 : }
1885 : }
1886 : }
1887 :
1888 0 : void MTGeneratorSpecs::UpdateMTGeneratorRecords(EnergyPlusData &state)
1889 : {
1890 : // SUBROUTINE INFORMATION:
1891 : // AUTHOR R. Raustad/D. Shirey
1892 : // DATE WRITTEN Mar 2008
1893 : // MODIFIED na
1894 : // RE-ENGINEERED na
1895 :
1896 : // PURPOSE OF THIS SUBROUTINE:
1897 : // Reporting and updating nodes if necessary.
1898 :
1899 0 : if (this->HeatRecActive) {
1900 0 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
1901 : }
1902 :
1903 0 : if (this->ExhAirCalcsActive) {
1904 0 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
1905 0 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
1906 :
1907 0 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).Temp = this->ExhaustAirTemperature;
1908 0 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).HumRat = this->ExhaustAirHumRat;
1909 0 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMaxAvail =
1910 0 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMaxAvail;
1911 0 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMinAvail =
1912 0 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMinAvail;
1913 : }
1914 :
1915 0 : this->EnergyGen = this->ElecPowerGenerated * state.dataHVACGlobal->TimeStepSysSec;
1916 0 : this->ExhaustEnergyRec = this->QHeatRecovered * state.dataHVACGlobal->TimeStepSysSec;
1917 0 : this->FuelEnergyHHV = this->FuelEnergyUseRateHHV * state.dataHVACGlobal->TimeStepSysSec;
1918 0 : if (this->FuelEnergyUseRateLHV > 0.0) {
1919 0 : this->ElectricEfficiencyLHV = this->ElecPowerGenerated / this->FuelEnergyUseRateLHV;
1920 0 : this->ThermalEfficiencyLHV = this->QHeatRecovered / this->FuelEnergyUseRateLHV;
1921 : } else {
1922 0 : this->ElectricEfficiencyLHV = 0.0;
1923 0 : this->ThermalEfficiencyLHV = 0.0;
1924 : }
1925 0 : this->AncillaryEnergy = this->AncillaryPowerRate * state.dataHVACGlobal->TimeStepSysSec;
1926 0 : this->StandbyEnergy = this->StandbyPowerRate * state.dataHVACGlobal->TimeStepSysSec;
1927 0 : }
1928 0 : void MTGeneratorSpecs::oneTimeInit(EnergyPlusData &state)
1929 : {
1930 :
1931 0 : std::string const RoutineName("InitMTGenerators");
1932 : bool errFlag;
1933 :
1934 0 : if (this->myFlag) {
1935 0 : this->setupOutputVars(state);
1936 0 : this->myFlag = false;
1937 : }
1938 :
1939 0 : if (this->MyPlantScanFlag && allocated(state.dataPlnt->PlantLoop) && this->HeatRecActive) {
1940 0 : errFlag = false;
1941 0 : PlantUtilities::ScanPlantLoopsForObject(
1942 0 : state, this->Name, DataPlant::PlantEquipmentType::Generator_MicroTurbine, this->HRPlantLoc, errFlag, _, _, _, _, _);
1943 0 : if (errFlag) {
1944 0 : ShowFatalError(state, "InitMTGenerators: Program terminated due to previous condition(s).");
1945 : }
1946 :
1947 0 : this->MyPlantScanFlag = false;
1948 : }
1949 :
1950 0 : if (this->MySizeAndNodeInitFlag && (!this->MyPlantScanFlag) && this->HeatRecActive) {
1951 :
1952 : // size mass flow rate
1953 0 : Real64 rho = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
1954 :
1955 0 : this->DesignHeatRecMassFlowRate = rho * this->RefHeatRecVolFlowRate;
1956 0 : this->HeatRecMaxMassFlowRate = rho * this->HeatRecMaxVolFlowRate;
1957 :
1958 0 : PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1959 :
1960 0 : this->MySizeAndNodeInitFlag = false;
1961 : }
1962 0 : }
1963 :
1964 : } // namespace EnergyPlus::MicroturbineElectricGenerator
|