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 51346 : 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 51346 : if (state.dataMircoturbElectGen->GetMTInput) {
100 6 : GetMTGeneratorInput(state);
101 6 : state.dataMircoturbElectGen->GetMTInput = false;
102 : }
103 :
104 : // Now look for this particular gen in the list
105 51346 : for (auto &thisMTG : state.dataMircoturbElectGen->MTGenerator) {
106 51346 : if (thisMTG.Name == objectName) {
107 51346 : return &thisMTG;
108 : }
109 102692 : }
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 6 : 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 6 : bool ErrorsFound(false);
129 :
130 6 : state.dataIPShortCut->cCurrentModuleObject = "Generator:MicroTurbine";
131 12 : state.dataMircoturbElectGen->NumMTGenerators =
132 6 : state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, state.dataIPShortCut->cCurrentModuleObject);
133 :
134 6 : 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 6 : 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 6 : Array1D<Real64> NumArray(19);
148 6 : Array1D_string AlphArray(20);
149 18 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
150 6 : state.dataIPShortCut->cCurrentModuleObject,
151 : GeneratorNum,
152 : AlphArray,
153 : NumAlphas,
154 : NumArray,
155 : NumNums,
156 : IOStat,
157 6 : state.dataIPShortCut->lNumericFieldBlanks,
158 6 : state.dataIPShortCut->lAlphaFieldBlanks,
159 6 : state.dataIPShortCut->cAlphaFieldNames,
160 6 : state.dataIPShortCut->cNumericFieldNames);
161 6 : Util::IsNameEmpty(state, state.dataIPShortCut->cAlphaArgs(1), state.dataIPShortCut->cCurrentModuleObject, ErrorsFound);
162 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name = AlphArray(1);
163 :
164 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput = NumArray(1);
165 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput = NumArray(2);
173 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput = NumArray(3);
174 :
175 6 : 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 6 : if (state.dataIPShortCut->lNumericFieldBlanks(3)) {
183 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput =
184 0 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput;
185 : } else {
186 6 : 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 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput >=
195 6 : 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 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput >
210 12 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput ||
211 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput <
212 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV = NumArray(4);
226 :
227 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp = NumArray(5);
235 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat = NumArray(6);
236 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation = NumArray(7);
237 :
238 6 : 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 6 : 101325.0 * std::pow(1.0 - 2.25577e-05 * state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation, 5.2559);
247 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletDensity =
248 18 : Psychrometrics::PsyRhoAirFnPbTdbW(state,
249 : RefBaroPressure,
250 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
251 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletHumRat);
252 : }
253 :
254 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum =
255 6 : Curve::GetCurveIndex(state, AlphArray(2)); // Convert curve name to number
256 6 : 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 6 : 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 24 : Real64 ElectOutFTempElevOutput = Curve::CurveValue(state,
267 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecPowFTempElevCurveNum,
268 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
269 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation);
270 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum =
288 6 : Curve::GetCurveIndex(state, AlphArray(3)); // Convert curve name to number
289 6 : 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 6 : if (!ErrorsFound) {
298 : // Check electrical efficiency at reference combustion inlet temp
299 : // Output of Electrical Efficiency Modifier Curve (function of temp)
300 18 : Real64 ElecEfficFTempOutput = Curve::CurveValue(state,
301 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFTempCurveNum,
302 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
303 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum =
318 6 : Curve::GetCurveIndex(state, AlphArray(4)); // Convert curve name to number
319 6 : 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 6 : if (!ErrorsFound) {
328 : // Check electrical efficiency at PLR = 1
329 : // Output of Electrical Efficiency Modifier Curve (function of PLR)
330 : Real64 ElecEfficFPLROutput =
331 6 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum, 1.0);
332 6 : 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 6 : Real64 Var1Min(0.0);
342 6 : Real64 Var1Max(0.0);
343 6 : Curve::GetCurveMinMaxValues(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ElecEffFPLRCurveNum, Var1Min, Var1Max);
344 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinPartLoadRat = Var1Min;
345 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxPartLoadRat = Var1Max;
346 : }
347 : }
348 :
349 : // Validate fuel type input
350 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelType =
351 6 : static_cast<Constant::eFuel>(getEnumValue(Constant::eFuelNamesUC, AlphArray(5)));
352 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelHigherHeatingValue = NumArray(8);
360 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue = NumArray(9);
361 :
362 6 : 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 6 : 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 6 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).FuelLowerHeatingValue >
377 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).StandbyPower = NumArray(10);
389 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPower = NumArray(11);
398 6 : 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 6 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).AncillaryPowerFuelCurveNum =
407 6 : 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 6 : 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 6 : } 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 6 : if (!state.dataIPShortCut->lAlphaFieldBlanks(7)) {
446 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum =
447 6 : NodeInputManager::GetOnlySingleNode(state,
448 2 : AlphArray(7),
449 : ErrorsFound,
450 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
451 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
452 : DataLoopNode::NodeFluidType::Water,
453 : DataLoopNode::ConnectionType::Inlet,
454 : NodeInputManager::CompFluidStream::Primary,
455 : DataLoopNode::ObjectIsNotParent);
456 : }
457 :
458 6 : if (!state.dataIPShortCut->lAlphaFieldBlanks(8)) {
459 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum =
460 6 : NodeInputManager::GetOnlySingleNode(state,
461 2 : AlphArray(8),
462 : ErrorsFound,
463 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
464 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
465 : DataLoopNode::NodeFluidType::Water,
466 : DataLoopNode::ConnectionType::Outlet,
467 : NodeInputManager::CompFluidStream::Primary,
468 : DataLoopNode::ObjectIsNotParent);
469 : }
470 :
471 8 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum > 0 &&
472 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum > 0) {
473 6 : BranchNodeConnections::TestCompSet(state,
474 2 : state.dataIPShortCut->cCurrentModuleObject,
475 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).Name,
476 2 : AlphArray(7),
477 2 : AlphArray(8),
478 : "Heat Recovery Nodes");
479 : }
480 :
481 6 : if ((state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum > 0 &&
482 12 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum == 0) ||
483 6 : (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum == 0 &&
484 4 : 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 8 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum != 0 &&
494 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecOutletNodeNum != 0) {
495 :
496 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecActive = true;
497 :
498 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV = NumArray(12);
499 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalPowerOutput =
510 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecPowerOutput *
511 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
512 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
513 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinThermalPowerOutput =
514 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MinElecPowerOutput *
515 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
516 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
517 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxThermalPowerOutput =
518 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).MaxElecPowerOutput *
519 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefThermalEffLHV /
520 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElecEfficiencyLHV;
521 :
522 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp = NumArray(13);
523 :
524 2 : 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 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate = NumArray(14);
537 :
538 2 : 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 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum =
555 2 : Curve::GetCurveIndex(state, AlphArray(11)); // convert curve name to number
556 2 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum != 0) {
557 : // Verify curve object, only legal types are BiQuadratic and BiCubic
558 :
559 2 : if (!ErrorsFound) {
560 : // Output of Thermal Efficiency Modifier Curve (function of temp and elevation)
561 : Real64 ThermalEffTempElevOutput =
562 8 : Curve::CurveValue(state,
563 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ThermEffFTempElevCurveNum,
564 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp,
565 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefElevation);
566 :
567 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum =
585 2 : Curve::GetCurveIndex(state, AlphArray(12)); // convert curve name to number
586 2 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum != 0) {
587 : // Verify curve object, only legal types are Quadratic or Cubic
588 :
589 2 : if (!ErrorsFound) {
590 : // Output of Heat Recovery Rate Modifier Curve (function of PLR)
591 : Real64 HeatRecRateFPLROutput =
592 2 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFPLRCurveNum, 1.0);
593 :
594 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum =
607 2 : Curve::GetCurveIndex(state, AlphArray(13)); // convert curve name to number
608 2 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum != 0) {
609 : // Verify curve object, only legal type is Quadratic
610 :
611 2 : if (!ErrorsFound) {
612 : // Output of Heat Recovery Rate Modifier Curve (function of inlet water temp)
613 6 : Real64 HeatRecRateFTempOutput = Curve::CurveValue(state,
614 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFTempCurveNum,
615 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefInletWaterTemp);
616 :
617 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum = Curve::GetCurveIndex(state, AlphArray(14));
633 2 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum != 0) {
634 : // Verify curve object, only legal type is Quadratic
635 :
636 2 : if (!ErrorsFound) {
637 : // Output of Heat Recovery Rate Modifier Curve (function of water flow rate)
638 : Real64 HeatRecRateFFlowOutput =
639 6 : Curve::CurveValue(state,
640 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecRateFWaterFlowCurveNum,
641 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate);
642 :
643 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMinVolFlowRate = NumArray(15);
659 2 : 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 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate = NumArray(16);
669 2 : 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 2 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate <
679 2 : 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 2 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate <
695 2 : 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 2 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefHeatRecVolFlowRate >
711 2 : 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 4 : PlantUtilities::RegisterPlantCompDesignFlow(state,
726 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecInletNodeNum,
727 2 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).HeatRecMaxVolFlowRate);
728 :
729 2 : 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 6 : if (!state.dataIPShortCut->lAlphaFieldBlanks(15)) {
735 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum =
736 9 : NodeInputManager::GetOnlySingleNode(state,
737 3 : AlphArray(15),
738 : ErrorsFound,
739 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
740 3 : 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 9 : if (!state.dataIPShortCut->lAlphaFieldBlanks(15) &&
749 3 : !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 6 : if (!state.dataIPShortCut->lAlphaFieldBlanks(16)) {
758 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum =
759 9 : NodeInputManager::GetOnlySingleNode(state,
760 3 : AlphArray(16),
761 : ErrorsFound,
762 : DataLoopNode::ConnectionObjectType::GeneratorMicroTurbine,
763 3 : AlphArray(1),
764 : DataLoopNode::NodeFluidType::Air,
765 : DataLoopNode::ConnectionType::Outlet,
766 : NodeInputManager::CompFluidStream::Secondary,
767 : DataLoopNode::ObjectIsNotParent);
768 : }
769 :
770 9 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum > 0 &&
771 3 : 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 9 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirOutletNodeNum > 0 &&
783 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).CombustionAirInletNodeNum > 0) {
784 :
785 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirCalcsActive = true;
786 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefExhaustAirMassFlowRate = NumArray(18);
787 3 : 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 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum = Curve::GetCurveIndex(state, AlphArray(17));
796 3 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum != 0) {
797 : // Verify curve object, only legal types are Quadratic and Cubic
798 :
799 3 : if (!ErrorsFound) {
800 : // Output of Exhaust Air Flow Modifier Curve (function of inlet air temp)
801 9 : Real64 ExhFlowFTempOutput = Curve::CurveValue(state,
802 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFTempCurveNum,
803 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
804 :
805 3 : 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 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum =
821 3 : Curve::GetCurveIndex(state, AlphArray(18)); // convert curve name to number
822 3 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum != 0) {
823 : // Verify curve object, legal types are Quadratic or Cubic
824 :
825 3 : if (!ErrorsFound) {
826 : // Output of Exhaust Air Flow Modifier Curve (function of PLR)
827 : Real64 ExhFlowFPLROutput =
828 3 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhFlowFPLRCurveNum, 1.0);
829 :
830 3 : 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 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).NomExhAirOutletTemp = NumArray(19);
843 :
844 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum = Curve::GetCurveIndex(state, AlphArray(19));
845 3 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum != 0) {
846 : // Verify curve object, only legal types are Quadratic and Cubic
847 :
848 3 : if (!ErrorsFound) {
849 : // Output of Exhaust Air Temperature Modifier Curve (function of inlet air temp)
850 9 : Real64 ExhAirTempFTempOutput = Curve::CurveValue(state,
851 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFTempCurveNum,
852 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).RefCombustAirInletTemp);
853 :
854 3 : 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 3 : state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum =
870 3 : Curve::GetCurveIndex(state, AlphArray(20)); // convert curve name to number
871 3 : if (state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum != 0) {
872 : // Verify curve object, legal types are Quadratic or Cubic
873 :
874 3 : if (!ErrorsFound) {
875 : // Output of Exhaust Air Temperature Modifier Curve (function of PLR)
876 : Real64 ExhOutAirTempFPLROutput =
877 3 : Curve::CurveValue(state, state.dataMircoturbElectGen->MTGenerator(GeneratorNum).ExhAirTempFPLRCurveNum, 1.0);
878 :
879 3 : 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 6 : }
894 :
895 6 : if (ErrorsFound) {
896 0 : ShowFatalError(state, format("Errors found in processing input for {}", state.dataIPShortCut->cCurrentModuleObject));
897 : }
898 6 : }
899 :
900 6 : void MTGeneratorSpecs::setupOutputVars(EnergyPlusData &state)
901 : {
902 6 : std::string_view const sFuelType = Constant::eFuelNames[static_cast<int>(this->FuelType)];
903 12 : SetupOutputVariable(state,
904 : "Generator Produced AC Electricity Rate",
905 : Constant::Units::W,
906 6 : this->ElecPowerGenerated,
907 : OutputProcessor::TimeStepType::System,
908 : OutputProcessor::StoreType::Average,
909 6 : this->Name);
910 :
911 12 : SetupOutputVariable(state,
912 : "Generator Produced AC Electricity Energy",
913 : Constant::Units::J,
914 6 : this->EnergyGen,
915 : OutputProcessor::TimeStepType::System,
916 : OutputProcessor::StoreType::Sum,
917 6 : this->Name,
918 : Constant::eResource::ElectricityProduced,
919 : OutputProcessor::Group::Plant,
920 : OutputProcessor::EndUseCat::Cogeneration);
921 :
922 12 : SetupOutputVariable(state,
923 : "Generator LHV Basis Electric Efficiency",
924 : Constant::Units::None,
925 6 : this->ElectricEfficiencyLHV,
926 : OutputProcessor::TimeStepType::System,
927 : OutputProcessor::StoreType::Average,
928 6 : this->Name);
929 :
930 : // Fuel specific report variables
931 18 : SetupOutputVariable(state,
932 12 : format("Generator {} HHV Basis Rate", sFuelType),
933 : Constant::Units::W,
934 6 : this->FuelEnergyUseRateHHV,
935 : OutputProcessor::TimeStepType::System,
936 : OutputProcessor::StoreType::Average,
937 6 : this->Name);
938 :
939 18 : SetupOutputVariable(state,
940 12 : format("Generator {} HHV Basis Energy", sFuelType),
941 : Constant::Units::J,
942 6 : this->FuelEnergyHHV,
943 : OutputProcessor::TimeStepType::System,
944 : OutputProcessor::StoreType::Sum,
945 6 : this->Name,
946 6 : Constant::eFuel2eResource[(int)this->FuelType],
947 : OutputProcessor::Group::Plant,
948 : OutputProcessor::EndUseCat::Cogeneration);
949 :
950 18 : SetupOutputVariable(state,
951 12 : format("Generator {} Mass Flow Rate", sFuelType),
952 : Constant::Units::kg_s,
953 6 : this->FuelMdot,
954 : OutputProcessor::TimeStepType::System,
955 : OutputProcessor::StoreType::Average,
956 6 : this->Name);
957 :
958 : // general fuel use report (to match other generators)
959 12 : SetupOutputVariable(state,
960 : "Generator Fuel HHV Basis Rate",
961 : Constant::Units::W,
962 6 : this->FuelEnergyUseRateHHV,
963 : OutputProcessor::TimeStepType::System,
964 : OutputProcessor::StoreType::Average,
965 6 : this->Name);
966 :
967 12 : SetupOutputVariable(state,
968 : "Generator Fuel HHV Basis Energy",
969 : Constant::Units::J,
970 6 : this->FuelEnergyHHV,
971 : OutputProcessor::TimeStepType::System,
972 : OutputProcessor::StoreType::Sum,
973 6 : this->Name);
974 :
975 : // Heat recovery (to water) report variables
976 6 : if (this->HeatRecActive) {
977 :
978 4 : SetupOutputVariable(state,
979 : "Generator Produced Thermal Rate",
980 : Constant::Units::W,
981 2 : this->QHeatRecovered,
982 : OutputProcessor::TimeStepType::System,
983 : OutputProcessor::StoreType::Average,
984 2 : this->Name);
985 :
986 4 : SetupOutputVariable(state,
987 : "Generator Produced Thermal Energy",
988 : Constant::Units::J,
989 2 : this->ExhaustEnergyRec,
990 : OutputProcessor::TimeStepType::System,
991 : OutputProcessor::StoreType::Sum,
992 2 : this->Name,
993 : Constant::eResource::EnergyTransfer,
994 : OutputProcessor::Group::Plant,
995 : OutputProcessor::EndUseCat::HeatRecovery);
996 :
997 4 : SetupOutputVariable(state,
998 : "Generator Thermal Efficiency LHV Basis",
999 : Constant::Units::None,
1000 2 : this->ThermalEfficiencyLHV,
1001 : OutputProcessor::TimeStepType::System,
1002 : OutputProcessor::StoreType::Average,
1003 2 : this->Name);
1004 :
1005 4 : SetupOutputVariable(state,
1006 : "Generator Heat Recovery Inlet Temperature",
1007 : Constant::Units::C,
1008 2 : this->HeatRecInletTemp,
1009 : OutputProcessor::TimeStepType::System,
1010 : OutputProcessor::StoreType::Average,
1011 2 : this->Name);
1012 :
1013 4 : SetupOutputVariable(state,
1014 : "Generator Heat Recovery Outlet Temperature",
1015 : Constant::Units::C,
1016 2 : this->HeatRecOutletTemp,
1017 : OutputProcessor::TimeStepType::System,
1018 : OutputProcessor::StoreType::Average,
1019 2 : this->Name);
1020 :
1021 4 : SetupOutputVariable(state,
1022 : "Generator Heat Recovery Water Mass Flow Rate",
1023 : Constant::Units::kg_s,
1024 2 : this->HeatRecMdot,
1025 : OutputProcessor::TimeStepType::System,
1026 : OutputProcessor::StoreType::Average,
1027 2 : this->Name);
1028 : }
1029 :
1030 6 : if (this->StandbyPower > 0.0) { // Report Standby Power if entered by user
1031 10 : SetupOutputVariable(state,
1032 : "Generator Standby Electricity Rate",
1033 : Constant::Units::W,
1034 5 : this->StandbyPowerRate,
1035 : OutputProcessor::TimeStepType::System,
1036 : OutputProcessor::StoreType::Average,
1037 5 : this->Name);
1038 :
1039 10 : SetupOutputVariable(state,
1040 : "Generator Standby Electricity Energy",
1041 : Constant::Units::J,
1042 5 : this->StandbyEnergy,
1043 : OutputProcessor::TimeStepType::System,
1044 : OutputProcessor::StoreType::Sum,
1045 5 : this->Name,
1046 : Constant::eResource::Electricity,
1047 : OutputProcessor::Group::Plant,
1048 : OutputProcessor::EndUseCat::Cogeneration);
1049 : }
1050 :
1051 6 : if (this->AncillaryPower > 0.0) { // Report Ancillary Power if entered by user
1052 10 : SetupOutputVariable(state,
1053 : "Generator Ancillary Electricity Rate",
1054 : Constant::Units::W,
1055 5 : this->AncillaryPowerRate,
1056 : OutputProcessor::TimeStepType::System,
1057 : OutputProcessor::StoreType::Average,
1058 5 : this->Name);
1059 :
1060 10 : SetupOutputVariable(state,
1061 : "Generator Ancillary Electricity Energy",
1062 : Constant::Units::J,
1063 5 : this->AncillaryEnergy,
1064 : OutputProcessor::TimeStepType::System,
1065 : OutputProcessor::StoreType::Sum,
1066 5 : this->Name);
1067 : }
1068 :
1069 : // Report combustion air outlet conditions if exhaust air calculations are active
1070 6 : if (this->ExhAirCalcsActive) {
1071 6 : SetupOutputVariable(state,
1072 : "Generator Exhaust Air Mass Flow Rate",
1073 : Constant::Units::kg_s,
1074 3 : this->ExhaustAirMassFlowRate,
1075 : OutputProcessor::TimeStepType::System,
1076 : OutputProcessor::StoreType::Average,
1077 3 : this->Name);
1078 :
1079 6 : SetupOutputVariable(state,
1080 : "Generator Exhaust Air Temperature",
1081 : Constant::Units::C,
1082 3 : this->ExhaustAirTemperature,
1083 : OutputProcessor::TimeStepType::System,
1084 : OutputProcessor::StoreType::Average,
1085 3 : this->Name);
1086 : }
1087 6 : }
1088 :
1089 84490 : 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 84490 : }
1099 :
1100 10 : void MTGeneratorSpecs::getDesignCapacities([[maybe_unused]] EnergyPlusData &state,
1101 : [[maybe_unused]] const PlantLocation &calledFromLocation,
1102 : Real64 &MaxLoad,
1103 : Real64 &MinLoad,
1104 : Real64 &OptLoad)
1105 : {
1106 10 : MaxLoad = 0.0;
1107 10 : MinLoad = 0.0;
1108 10 : OptLoad = 0.0;
1109 10 : }
1110 :
1111 51343 : 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 51343 : this->oneTimeInit(state); // end one time inits
1130 :
1131 51343 : if (!this->HeatRecActive) {
1132 32071 : return;
1133 : }
1134 :
1135 : // Do the Begin Environment initializations
1136 19272 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
1137 : // set the node max and min mass flow rates
1138 16 : PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1139 :
1140 16 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp = 20.0; // Set the node temperature, assuming freeze control
1141 16 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = 20.0;
1142 :
1143 16 : this->MyEnvrnFlag = false;
1144 : } // end environmental inits
1145 :
1146 19272 : if (!state.dataGlobal->BeginEnvrnFlag) {
1147 18992 : this->MyEnvrnFlag = true;
1148 : }
1149 :
1150 : // set/request flow rates
1151 19272 : if (FirstHVACIteration) {
1152 :
1153 : Real64 DesiredMassFlowRate;
1154 12414 : if (!RunFlag) {
1155 10310 : DesiredMassFlowRate = 0.0;
1156 :
1157 2104 : } else if (RunFlag && this->InternalFlowControl) {
1158 : // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
1159 0 : if (this->HeatRecFlowFTempPowCurveNum != 0) {
1160 0 : DesiredMassFlowRate =
1161 0 : this->DesignHeatRecMassFlowRate *
1162 0 : Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
1163 : } else {
1164 0 : DesiredMassFlowRate = this->DesignHeatRecMassFlowRate; // Assume modifier = 1 if curve not specified
1165 : }
1166 :
1167 0 : DesiredMassFlowRate = max(DataPrecisionGlobals::constant_zero, DesiredMassFlowRate); // protect from neg. curve result
1168 :
1169 2104 : } else if (RunFlag && (!this->InternalFlowControl)) {
1170 2104 : DesiredMassFlowRate = this->DesignHeatRecMassFlowRate;
1171 : }
1172 :
1173 12414 : PlantUtilities::SetComponentFlowRate(state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1174 : } else { // not FirstHVACIteration
1175 6858 : if (!RunFlag) {
1176 5594 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
1177 5594 : min(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMaxAvail);
1178 5594 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
1179 5594 : max(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMinAvail);
1180 :
1181 1264 : } else if (RunFlag && this->InternalFlowControl) {
1182 : // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
1183 0 : if (this->HeatRecFlowFTempPowCurveNum != 0) {
1184 : Real64 DesiredMassFlowRate =
1185 0 : this->DesignHeatRecMassFlowRate *
1186 0 : Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
1187 0 : PlantUtilities::SetComponentFlowRate(
1188 0 : state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1189 : } else {
1190 0 : PlantUtilities::SetComponentFlowRate(
1191 0 : state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1192 : }
1193 1264 : } else if (RunFlag && (!this->InternalFlowControl)) {
1194 1264 : PlantUtilities::SetComponentFlowRate(state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1195 : }
1196 : }
1197 : }
1198 :
1199 51343 : void MTGeneratorSpecs::CalcMTGeneratorModel(EnergyPlusData &state,
1200 : bool const RunFlag, // TRUE when generator is being asked to operate
1201 : Real64 const MyLoad) // Generator demand (W)
1202 : {
1203 : // SUBROUTINE INFORMATION:
1204 : // AUTHOR R. Raustad/D. Shirey
1205 : // DATE WRITTEN Mar 2008
1206 : // MODIFIED na
1207 : // RE-ENGINEERED na
1208 :
1209 : // PURPOSE OF THIS SUBROUTINE:
1210 : // Simulate a combustion generator.
1211 :
1212 : // METHODOLOGY EMPLOYED:
1213 : // Curve fits of performance data.
1214 :
1215 51343 : Real64 constexpr KJtoJ(1000.0); // Convert kilojoules to joules
1216 51343 : int constexpr MaxAncPowerIter(50); // Maximum number of iteration (subroutine ancillary power iteration loop)
1217 51343 : Real64 constexpr AncPowerDiffToler(5.0); // Tolerance for Ancillary Power Difference (W)
1218 51343 : Real64 constexpr RelaxFactor(0.7); // Relaxation factor for iteration loop
1219 : static constexpr std::string_view RoutineName("CalcMTGeneratorModel");
1220 :
1221 : // Load local variables from data structure (for code readability)
1222 : // Min allowed operating fraction at full load
1223 51343 : Real64 minPartLoadRat = this->MinPartLoadRat;
1224 :
1225 : // Max allowed operating fraction at full load
1226 51343 : Real64 maxPartLoadRat = this->MaxPartLoadRat;
1227 :
1228 : // Generator reference capacity (W)
1229 51343 : Real64 ReferencePowerOutput = this->RefElecPowerOutput;
1230 :
1231 : // Reference electrical efficiency
1232 51343 : Real64 RefElecEfficiency = this->RefElecEfficiencyLHV;
1233 :
1234 : // Initialize variables
1235 51343 : this->ElecPowerGenerated = 0.0;
1236 51343 : this->HeatRecInletTemp = 0.0;
1237 51343 : this->HeatRecOutletTemp = 0.0;
1238 51343 : this->HeatRecMdot = 0.0;
1239 51343 : this->QHeatRecovered = 0.0;
1240 51343 : this->ExhaustEnergyRec = 0.0;
1241 51343 : this->FuelEnergyUseRateHHV = 0.0;
1242 51343 : this->FuelMdot = 0.0;
1243 51343 : this->AncillaryPowerRate = 0.0;
1244 51343 : this->StandbyPowerRate = 0.0;
1245 51343 : this->FuelEnergyUseRateLHV = 0.0;
1246 51343 : this->ExhaustAirMassFlowRate = 0.0;
1247 51343 : this->ExhaustAirTemperature = 0.0;
1248 51343 : this->ExhaustAirHumRat = 0.0;
1249 :
1250 : Real64 HeatRecInTemp; // Heat recovery fluid inlet temperature (C)
1251 : Real64 heatRecMdot; // Heat recovery fluid mass flow rate (kg/s)
1252 : Real64 HeatRecCp; // Specific heat of the heat recovery fluid (J/kg-K)
1253 :
1254 51343 : if (this->HeatRecActive) {
1255 19272 : HeatRecInTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
1256 19272 : HeatRecCp = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getSpecificHeat(state, HeatRecInTemp, RoutineName);
1257 19272 : heatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
1258 : } else {
1259 32071 : HeatRecInTemp = 0.0;
1260 32071 : HeatRecCp = 0.0;
1261 32071 : heatRecMdot = 0.0;
1262 : }
1263 :
1264 : Real64 CombustionAirInletTemp; // Combustion air inlet temperature (C)
1265 : Real64 CombustionAirInletPress; // Barometric pressure of combustion inlet air (Pa)
1266 : Real64 CombustionAirInletW; // Combustion air inlet humidity ratio (kg/kg)
1267 :
1268 : // Set combustion inlet air temperature, humidity ratio and pressure local variables
1269 51343 : if (this->CombustionAirInletNodeNum == 0) { // no inlet air node specified, so use weather file values
1270 24208 : CombustionAirInletTemp = state.dataEnvrn->OutDryBulbTemp;
1271 24208 : CombustionAirInletW = state.dataEnvrn->OutHumRat;
1272 24208 : CombustionAirInletPress = state.dataEnvrn->OutBaroPress;
1273 : } else { // use inlet node information
1274 27135 : CombustionAirInletTemp = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Temp;
1275 27135 : CombustionAirInletW = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).HumRat;
1276 27135 : CombustionAirInletPress = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Press;
1277 27135 : if (state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Height > 0.0) {
1278 : }
1279 : // Initialize combustion outlet air conditions to inlet air conditions (all node properties)
1280 27135 : if (this->ExhAirCalcsActive) {
1281 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum) = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum);
1282 : }
1283 : }
1284 :
1285 : // If no loop demand or generator OFF, set some variables and then return
1286 : // IF (.NOT. RunFlag .OR. MyLoad .LE. 0.0d0) THEN
1287 51343 : if (MyLoad <= 0.0) {
1288 32878 : this->HeatRecInletTemp = HeatRecInTemp;
1289 32878 : this->HeatRecOutletTemp = HeatRecInTemp;
1290 32878 : if (RunFlag) {
1291 0 : this->StandbyPowerRate = this->StandbyPower;
1292 : }
1293 32878 : this->ExhaustAirTemperature = CombustionAirInletTemp;
1294 32878 : this->ExhaustAirHumRat = CombustionAirInletW;
1295 32878 : return;
1296 : }
1297 :
1298 : // Calculate power modifier curve value (function of inlet air temperature and elevation)
1299 : // Power ratio as a function of inlet air temperature and elevation
1300 18465 : Real64 PowerFTempElev = Curve::CurveValue(state, this->ElecPowFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
1301 :
1302 : // Warn user if power modifier curve output is less than 0
1303 18465 : if (PowerFTempElev < 0.0) {
1304 0 : if (this->PowerFTempElevErrorIndex == 0) {
1305 : // MTGenerator(GeneratorNum)%PowerFTempElevErrorCount = MTGenerator(GeneratorNum)%PowerFTempElevErrorCount + 1
1306 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1307 0 : ShowContinueError(state,
1308 0 : format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
1309 : PowerFTempElev));
1310 0 : ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1311 0 : ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
1312 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1313 : }
1314 0 : ShowRecurringWarningErrorAtEnd(state,
1315 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1316 : "\": Electrical Power Modifier curve is less than zero warning continues...",
1317 0 : this->PowerFTempElevErrorIndex,
1318 : PowerFTempElev,
1319 : PowerFTempElev);
1320 0 : PowerFTempElev = 0.0;
1321 : }
1322 :
1323 : // Calculate available full-load power output. cannot exceed maximum full-load power output.
1324 : // Generator full-load power output at actual inlet conditions and elevation (W)
1325 18465 : Real64 FullLoadPowerOutput = min((ReferencePowerOutput * PowerFTempElev), this->MaxElecPowerOutput);
1326 : // Also can't be below the minimum full-load power output.
1327 18465 : FullLoadPowerOutput = max(FullLoadPowerOutput, this->MinElecPowerOutput);
1328 :
1329 : // Ancillary power used by pump (if not specified in manufacturers data)
1330 18465 : Real64 ancillaryPowerRate = this->AncillaryPower;
1331 :
1332 : // Difference between ancillary power rate and ancillary power rate last (last iteration)
1333 18465 : Real64 AncillaryPowerRateDiff = AncPowerDiffToler + 1.0; // Initialize to force through DO WHILE Loop at least once
1334 :
1335 18465 : Real64 PLR(0.0); // Generator operating part load ratio
1336 18465 : Real64 elecPowerGenerated(0.0); // Generator electric power output (W)
1337 18465 : Real64 FuelUseEnergyRateLHV(0.0); // Rate of fuel energy required to run microturbine, LHV basis (W)
1338 18465 : Real64 fuelHigherHeatingValue(0.0); // Higher heating value (LLV) of fuel kJ/kg)
1339 18465 : Real64 fuelLowerHeatingValue(0.0); // Lower heating value (LLV) of fuel kJ/kg)
1340 18465 : Real64 AnciPowerFMdotFuel(0.0); // Ancillary power as a function of fuel flow curve output
1341 18465 : int AncPowerCalcIterIndex = 0; // Index for subroutine iteration loop if Ancillary Power (function of fuel flow) is used
1342 :
1343 36930 : while (AncillaryPowerRateDiff > AncPowerDiffToler && AncPowerCalcIterIndex <= MaxAncPowerIter) {
1344 :
1345 18465 : ++AncPowerCalcIterIndex; // Increment iteration loop counter
1346 :
1347 : // Calculate operating power output (gross)
1348 18465 : elecPowerGenerated = min(max(0.0, MyLoad + ancillaryPowerRate), FullLoadPowerOutput);
1349 :
1350 : // Calculate PLR, but must be between the minPLR and maxPLR
1351 18465 : if (FullLoadPowerOutput > 0.0) {
1352 18465 : PLR = min(elecPowerGenerated / FullLoadPowerOutput, maxPartLoadRat);
1353 18465 : PLR = max(PLR, minPartLoadRat);
1354 : } else {
1355 0 : PLR = 0.0;
1356 : }
1357 :
1358 : // Recalculate elecPowerGenerated based on "final" PLR
1359 18465 : elecPowerGenerated = FullLoadPowerOutput * PLR;
1360 :
1361 : // Calculate electrical efficiency modifier curve output (function of temp)
1362 : // Electrical efficiency as a function of temperature curve output
1363 18465 : Real64 ElecEfficiencyFTemp = Curve::CurveValue(state, this->ElecEffFTempCurveNum, CombustionAirInletTemp);
1364 :
1365 : // Warn user if efficiency modifier curve output is less than 0
1366 18465 : if (ElecEfficiencyFTemp < 0.0) {
1367 0 : if (this->EffFTempErrorIndex == 0) {
1368 : // MTGenerator(GeneratorNum)%EffFTempErrorCount = MTGenerator(GeneratorNum)%EffFTempErrorCount + 1
1369 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1370 0 : ShowContinueError(
1371 : state,
1372 0 : format("... Electrical Efficiency Modifier (function of temperature) output is less than zero ({:.4T}).", ElecEfficiencyFTemp));
1373 0 : ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1374 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1375 : }
1376 0 : ShowRecurringWarningErrorAtEnd(
1377 : state,
1378 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1379 : "\": Electrical Efficiency Modifier (function of temperature) output is less than zero warning continues...",
1380 0 : this->EffFTempErrorIndex,
1381 : ElecEfficiencyFTemp,
1382 : ElecEfficiencyFTemp);
1383 0 : ElecEfficiencyFTemp = 0.0;
1384 : }
1385 :
1386 : // Calculate efficiency modifier curve output (function of PLR)
1387 : // Electrical efficiency as a function of PLR curve output
1388 18465 : Real64 ElecEfficiencyFPLR = Curve::CurveValue(state, this->ElecEffFPLRCurveNum, PLR);
1389 :
1390 : // Warn user if efficiency modifier curve output is less than 0
1391 18465 : if (ElecEfficiencyFPLR < 0.0) {
1392 0 : if (this->EffFPLRErrorIndex == 0) {
1393 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1394 0 : ShowContinueError(state,
1395 0 : format("... Electrical Efficiency Modifier (function of part-load ratio) output is less than zero ({:.4T}).",
1396 : ElecEfficiencyFPLR));
1397 0 : ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
1398 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1399 : }
1400 0 : ShowRecurringWarningErrorAtEnd(
1401 : state,
1402 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1403 : "\": Electrical Efficiency Modifier (function of part-load ratio) output is less than zero warning continues...",
1404 0 : this->EffFPLRErrorIndex,
1405 : ElecEfficiencyFPLR,
1406 : ElecEfficiencyFPLR);
1407 0 : ElecEfficiencyFPLR = 0.0;
1408 : }
1409 :
1410 : // Calculate operating electrical efficiency
1411 : // Actual operating efficiency
1412 18465 : Real64 OperatingElecEfficiency = RefElecEfficiency * ElecEfficiencyFTemp * ElecEfficiencyFPLR;
1413 :
1414 : // Calculate fuel use (W = J/s), LHV basis
1415 18465 : if (OperatingElecEfficiency > 0.0) {
1416 18465 : FuelUseEnergyRateLHV = elecPowerGenerated / OperatingElecEfficiency;
1417 : } else {
1418 0 : FuelUseEnergyRateLHV = 0.0; // If fuel use rate is zero, then
1419 0 : elecPowerGenerated = 0.0; // electric power generated must be zero.
1420 : }
1421 :
1422 : // Set fuel heating values
1423 18465 : fuelHigherHeatingValue = this->FuelHigherHeatingValue;
1424 18465 : fuelLowerHeatingValue = this->FuelLowerHeatingValue;
1425 :
1426 : // Calculate fuel mass flow rate
1427 18465 : this->FuelMdot = FuelUseEnergyRateLHV / (fuelLowerHeatingValue * KJtoJ);
1428 :
1429 : // Calculate ancillary power requirement
1430 18465 : if (this->AncillaryPowerFuelCurveNum > 0) {
1431 0 : AnciPowerFMdotFuel = Curve::CurveValue(state, this->AncillaryPowerFuelCurveNum, this->FuelMdot);
1432 : // Warn user if ancillary power modifier curve output is less than 0
1433 0 : if (AnciPowerFMdotFuel < 0.0) {
1434 0 : if (this->AnciPowerFMdotFuelErrorIndex == 0) {
1435 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1436 0 : ShowContinueError(
1437 : state,
1438 0 : format("... Ancillary Power Modifier (function of fuel input) output is less than zero ({:.4T}).", AnciPowerFMdotFuel));
1439 0 : ShowContinueError(state, format("... Value occurs using a fuel input mass flow rate of {:.4T} kg/s.", this->FuelMdot));
1440 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1441 : }
1442 0 : ShowRecurringWarningErrorAtEnd(
1443 : state,
1444 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1445 : "\": Ancillary Power Modifier (function of fuel input) output is less than zero warning continues...",
1446 0 : this->AnciPowerFMdotFuelErrorIndex,
1447 : AnciPowerFMdotFuel,
1448 : AnciPowerFMdotFuel);
1449 0 : AnciPowerFMdotFuel = 0.0;
1450 : }
1451 : } else {
1452 18465 : AnciPowerFMdotFuel = 1.0;
1453 : }
1454 :
1455 : // Ancillary power used by pump from last iteration (iteration loop within this subroutine)
1456 18465 : Real64 AncillaryPowerRateLast = ancillaryPowerRate;
1457 :
1458 18465 : if (this->AncillaryPowerFuelCurveNum > 0) {
1459 0 : ancillaryPowerRate = RelaxFactor * this->AncillaryPower * AnciPowerFMdotFuel - (1.0 - RelaxFactor) * AncillaryPowerRateLast;
1460 : }
1461 :
1462 18465 : AncillaryPowerRateDiff = std::abs(ancillaryPowerRate - AncillaryPowerRateLast);
1463 : }
1464 :
1465 18465 : if (AncPowerCalcIterIndex > MaxAncPowerIter) {
1466 :
1467 0 : if (this->AnciPowerIterErrorIndex == 0) {
1468 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1469 0 : ShowContinueError(state, "... Iteration loop for electric power generation is not converging within tolerance.");
1470 0 : ShowContinueError(state, "... Check the Ancillary Power Modifier Curve (function of fuel input).");
1471 0 : ShowContinueError(state, format("... Ancillary Power = {:.1T} W.", ancillaryPowerRate));
1472 0 : ShowContinueError(state, format("... Fuel input rate = {:.4T} kg/s.", AnciPowerFMdotFuel));
1473 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1474 : }
1475 0 : ShowRecurringWarningErrorAtEnd(state,
1476 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1477 : "\": Iteration loop for electric power generation is not converging within tolerance continues...",
1478 0 : this->AnciPowerIterErrorIndex);
1479 : }
1480 :
1481 : // Calculate electrical power generated
1482 18465 : this->ElecPowerGenerated = elecPowerGenerated - ancillaryPowerRate;
1483 :
1484 : // Report fuel energy use rate on HHV basis, which is the unit of measure when the fuel is sold
1485 18465 : this->FuelEnergyUseRateHHV = this->FuelMdot * fuelHigherHeatingValue * KJtoJ;
1486 18465 : this->AncillaryPowerRate = ancillaryPowerRate; // Move to data structure for later reporting
1487 18465 : this->FuelEnergyUseRateLHV = FuelUseEnergyRateLHV; // Move to data structure for reporting calculations
1488 :
1489 : // When generator operates, standby losses are 0
1490 18465 : this->StandbyPowerRate = 0.0;
1491 :
1492 18465 : Real64 QHeatRecToWater = 0.0; // Recovered waste heat to water (W)
1493 :
1494 : // Calculate heat recovery if active
1495 18465 : if (this->HeatRecActive) {
1496 :
1497 : // Thermal efficiency as a function of air temperature and elevation
1498 : Real64 ThermalEffFTempElev;
1499 3368 : if (this->ThermEffFTempElevCurveNum > 0) {
1500 3368 : ThermalEffFTempElev = Curve::CurveValue(state, this->ThermEffFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
1501 : // Warn user if power modifier curve output is less than 0
1502 3368 : if (ThermalEffFTempElev < 0.0) {
1503 0 : if (this->ThermEffFTempElevErrorIndex == 0) {
1504 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1505 0 : ShowContinueError(
1506 : state,
1507 0 : format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
1508 : PowerFTempElev));
1509 0 : ShowContinueError(state,
1510 0 : format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1511 0 : ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
1512 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1513 : }
1514 0 : ShowRecurringWarningErrorAtEnd(state,
1515 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1516 : "\": Electrical Power Modifier curve is less than zero warning continues...",
1517 0 : this->ThermEffFTempElevErrorIndex,
1518 : ThermalEffFTempElev,
1519 : ThermalEffFTempElev);
1520 0 : ThermalEffFTempElev = 0.0;
1521 : }
1522 : } else {
1523 0 : ThermalEffFTempElev = 1.0; // If no curve provided, assume multiplier factor = 1.0
1524 : }
1525 :
1526 3368 : QHeatRecToWater = FuelUseEnergyRateLHV * this->RefThermalEffLHV * ThermalEffFTempElev;
1527 : Real64 HeatRecRateFPLR; // Heat recovery rate as a function of PLR curve output
1528 :
1529 : // Calculate heat recovery rate modifier curve output (function of PLR)
1530 3368 : if (this->HeatRecRateFPLRCurveNum > 0) {
1531 3368 : HeatRecRateFPLR = Curve::CurveValue(state, this->HeatRecRateFPLRCurveNum, PLR);
1532 : // Warn user if heat recovery modifier curve output is less than 0
1533 3368 : if (HeatRecRateFPLR < 0.0) {
1534 0 : if (this->HeatRecRateFPLRErrorIndex == 0) {
1535 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1536 0 : ShowContinueError(
1537 : state,
1538 0 : format("... Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero ({:.4T}).", HeatRecRateFPLR));
1539 0 : ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
1540 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1541 : }
1542 0 : ShowRecurringWarningErrorAtEnd(
1543 : state,
1544 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1545 : "\": Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero warning continues...",
1546 0 : this->HeatRecRateFPLRErrorIndex,
1547 : HeatRecRateFPLR,
1548 : HeatRecRateFPLR);
1549 0 : HeatRecRateFPLR = 0.0;
1550 : }
1551 : } else {
1552 0 : HeatRecRateFPLR = 1.0; // If no curve provided, assume multiplier factor = 1.0
1553 : }
1554 :
1555 : Real64 HeatRecRateFTemp; // Heat recovery rate as a function of inlet water temp curve output
1556 :
1557 : // Calculate heat recovery rate modifier curve output (function of inlet water temp)
1558 3368 : if (this->HeatRecRateFTempCurveNum > 0) {
1559 3368 : HeatRecRateFTemp = Curve::CurveValue(state, this->HeatRecRateFTempCurveNum, HeatRecInTemp);
1560 3368 : if (HeatRecRateFTemp < 0.0) {
1561 0 : if (this->HeatRecRateFTempErrorIndex == 0) {
1562 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1563 0 : ShowContinueError(state,
1564 0 : format("... Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero ({:.4T}).",
1565 : HeatRecRateFTemp));
1566 0 : ShowContinueError(state, format("... Value occurs using an inlet water temperature temperature of {:.2T} C.", HeatRecInTemp));
1567 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1568 : }
1569 0 : ShowRecurringWarningErrorAtEnd(
1570 : state,
1571 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1572 : "\": Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero warning continues...",
1573 0 : this->HeatRecRateFTempErrorIndex,
1574 : HeatRecRateFTemp,
1575 : HeatRecRateFTemp);
1576 0 : HeatRecRateFTemp = 0.0;
1577 : }
1578 : } else {
1579 0 : HeatRecRateFTemp = 1.0; // If no curve provided, assume multiplier factor = 1.0
1580 : }
1581 :
1582 : Real64 HeatRecRateFFlow; // Heat recovery rate as a function of water flow rate curve output
1583 :
1584 : // Calculate heat recovery rate modifier curve output (function of water [volumetric] flow rate)
1585 3368 : if (this->HeatRecRateFWaterFlowCurveNum > 0) {
1586 3368 : Real64 rho = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getDensity(state, HeatRecInTemp, RoutineName);
1587 :
1588 : // Heat recovery fluid flow rate (m3/s)
1589 3368 : Real64 HeatRecVolFlowRate = heatRecMdot / rho;
1590 3368 : HeatRecRateFFlow = Curve::CurveValue(state, this->HeatRecRateFWaterFlowCurveNum, HeatRecVolFlowRate);
1591 3368 : if (HeatRecRateFFlow < 0.0) {
1592 0 : if (this->HeatRecRateFFlowErrorIndex == 0) {
1593 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1594 0 : ShowContinueError(
1595 : state,
1596 0 : format("... Heat Recovery Rate Modifier (function of water flow rate) output is less than zero ({:.4T}).", HeatRecRateFFlow));
1597 0 : ShowContinueError(state, format("... Value occurs using a water flow rate of {:.4T} m3/s.", HeatRecVolFlowRate));
1598 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1599 : }
1600 0 : ShowRecurringWarningErrorAtEnd(
1601 : state,
1602 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1603 : "\": Heat Recovery Rate Modifier (function of water flow rate) output is less than zero warning continues...",
1604 0 : this->HeatRecRateFFlowErrorIndex,
1605 : HeatRecRateFFlow,
1606 : HeatRecRateFFlow);
1607 0 : HeatRecRateFFlow = 0.0;
1608 : }
1609 : } else {
1610 0 : HeatRecRateFFlow = 1.0; // If no curve provided, assume multiplier factor = 1.0
1611 : }
1612 :
1613 3368 : QHeatRecToWater *= HeatRecRateFPLR * HeatRecRateFTemp * HeatRecRateFFlow;
1614 :
1615 : Real64 HeatRecOutTemp; // Heat recovery fluid outlet temperature (C)
1616 :
1617 : // Check for divide by zero
1618 3368 : if ((heatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
1619 3368 : HeatRecOutTemp = HeatRecInTemp + QHeatRecToWater / (heatRecMdot * HeatRecCp);
1620 : } else {
1621 0 : heatRecMdot = 0.0;
1622 0 : HeatRecOutTemp = HeatRecInTemp;
1623 0 : QHeatRecToWater = 0.0;
1624 : }
1625 :
1626 : // Now verify the maximum heat recovery temperature was not exceeded
1627 3368 : if (HeatRecOutTemp > this->HeatRecMaxWaterTemp) {
1628 :
1629 1659 : Real64 MinHeatRecMdot = 0.0; // Heat recovery flow rate if minimal heat recovery is accomplished (kg/s)
1630 :
1631 1659 : if (this->HeatRecMaxWaterTemp != HeatRecInTemp) {
1632 1659 : MinHeatRecMdot = QHeatRecToWater / (HeatRecCp * (this->HeatRecMaxWaterTemp - HeatRecInTemp));
1633 1659 : if (MinHeatRecMdot < 0.0) {
1634 8 : MinHeatRecMdot = 0.0;
1635 : }
1636 : }
1637 :
1638 : // Recalculate outlet water temperature with minimum flow rate (will normally match the max water outlet temp,
1639 : // unless the inlet water temp is greater than the max outlet temp)
1640 : Real64 HRecRatio; // When maximum temperature is reached the amount of recovered heat has to be reduced
1641 :
1642 1659 : if ((MinHeatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
1643 1651 : HeatRecOutTemp = QHeatRecToWater / (MinHeatRecMdot * HeatRecCp) + HeatRecInTemp;
1644 1651 : HRecRatio = heatRecMdot / MinHeatRecMdot;
1645 : } else {
1646 8 : HeatRecOutTemp = HeatRecInTemp;
1647 8 : HRecRatio = 0.0;
1648 : }
1649 1659 : QHeatRecToWater *= HRecRatio; // Scale heat recovery rate using HRecRatio. Don't adjust flow rate.
1650 : }
1651 :
1652 : // Check water mass flow rate against minimum
1653 3368 : if (this->HeatRecMinMassFlowRate > heatRecMdot && heatRecMdot > 0.0) {
1654 0 : if (this->HRMinFlowErrorIndex == 0) {
1655 0 : ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1656 0 : ShowContinueError(state,
1657 0 : format("...Heat reclaim water flow rate is below the generators minimum mass flow rate of ({:.4T}).",
1658 0 : this->HeatRecMinMassFlowRate));
1659 0 : ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
1660 0 : ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
1661 : }
1662 0 : ShowRecurringWarningErrorAtEnd(
1663 : state,
1664 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1665 : "\": Heat recovery water flow rate is below the generators minimum mass flow rate warning continues...",
1666 0 : this->HRMinFlowErrorIndex,
1667 : heatRecMdot,
1668 : heatRecMdot);
1669 : }
1670 :
1671 : // Check water mass flow rate against maximum
1672 3368 : if (heatRecMdot > this->HeatRecMaxMassFlowRate && heatRecMdot > 0.0) {
1673 0 : if (this->HRMaxFlowErrorIndex == 0) {
1674 0 : ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1675 0 : ShowContinueError(state,
1676 0 : format("...Heat reclaim water flow rate is above the generators maximum mass flow rate of ({:.4T}).",
1677 0 : this->HeatRecMaxMassFlowRate));
1678 0 : ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
1679 0 : ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
1680 : }
1681 0 : ShowRecurringWarningErrorAtEnd(
1682 : state,
1683 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1684 : "\": Heat recovery water flow rate is above the generators maximum mass flow rate warning continues...",
1685 0 : this->HRMaxFlowErrorIndex,
1686 : heatRecMdot,
1687 : heatRecMdot);
1688 : }
1689 :
1690 : // Set report variables
1691 3368 : this->HeatRecInletTemp = HeatRecInTemp;
1692 3368 : this->HeatRecOutletTemp = HeatRecOutTemp;
1693 3368 : this->HeatRecMdot = heatRecMdot;
1694 3368 : this->QHeatRecovered = QHeatRecToWater;
1695 :
1696 : } // End of IF (MTGenerator(GeneratorNum)%HeatRecActive) THEN
1697 :
1698 : // Calculate combustion air outlet conditions if exhaust air calculations are active
1699 18465 : if (this->ExhAirCalcsActive) {
1700 :
1701 : Real64 ExhFlowFTemp; // Exhaust air flow rate as a function of temperature curve output
1702 :
1703 8666 : if (this->ExhFlowFTempCurveNum != 0) { // Exhaust Flow Rate versus Inlet Air Temp
1704 8666 : ExhFlowFTemp = Curve::CurveValue(state, this->ExhFlowFTempCurveNum, CombustionAirInletTemp);
1705 : // Warn user if exhaust modifier curve output is less than or equal to 0
1706 8666 : if (ExhFlowFTemp <= 0.0) {
1707 0 : if (this->ExhFlowFTempErrorIndex == 0) {
1708 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1709 0 : ShowContinueError(
1710 : state,
1711 0 : format("...Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
1712 : ExhFlowFTemp));
1713 0 : ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
1714 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1715 : }
1716 0 : ShowRecurringWarningErrorAtEnd(
1717 : state,
1718 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1719 : "\": Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero warning continues...",
1720 0 : this->ExhFlowFTempErrorIndex,
1721 : ExhFlowFTemp,
1722 : ExhFlowFTemp);
1723 0 : ExhFlowFTemp = 0.0;
1724 : }
1725 : } else {
1726 0 : ExhFlowFTemp = 1.0; // No curve input means modifier = 1.0 always
1727 : }
1728 :
1729 : Real64 ExhFlowFPLR; // Exhaust air flow rate as a function of part-load ratio curve output
1730 :
1731 8666 : if (this->ExhFlowFPLRCurveNum != 0) { // Exhaust Flow Rate versus Part-Load Ratio
1732 8666 : ExhFlowFPLR = Curve::CurveValue(state, this->ExhFlowFPLRCurveNum, PLR);
1733 : // Warn user if exhaust modifier curve output is less than or equal to 0
1734 8666 : if (ExhFlowFPLR <= 0.0) {
1735 0 : if (this->ExhFlowFPLRErrorIndex == 0) {
1736 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1737 0 : ShowContinueError(
1738 : state,
1739 0 : format("...Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
1740 : ExhFlowFPLR));
1741 0 : ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
1742 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1743 : }
1744 0 : ShowRecurringWarningErrorAtEnd(state,
1745 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1746 : "\": Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or "
1747 : "equal to zero warning continues...",
1748 0 : this->ExhFlowFPLRErrorIndex,
1749 : ExhFlowFPLR,
1750 : ExhFlowFPLR);
1751 0 : ExhFlowFPLR = 0.0;
1752 : }
1753 : } else {
1754 0 : ExhFlowFPLR = 1.0; // No curve input means modifier = 1.0 always
1755 : }
1756 :
1757 : // Calculate exhaust air mass flow, accounting for temperature and PLR modifier factors
1758 : // Actual exhaust air mass flow rate (accounting for temp and PLR modifier curves)
1759 8666 : Real64 ExhAirMassFlowRate = this->RefExhaustAirMassFlowRate * ExhFlowFTemp * ExhFlowFPLR;
1760 : // Adjust for difference in air density at reference conditions versus actual inlet air conditions
1761 :
1762 : // Density of air at actual combustion inlet air conditions (kg/m3)
1763 8666 : Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, CombustionAirInletPress, CombustionAirInletTemp, CombustionAirInletW);
1764 8666 : if (this->RefCombustAirInletDensity >= 0.0) {
1765 8666 : ExhAirMassFlowRate = max(0.0, ExhAirMassFlowRate * AirDensity / this->RefCombustAirInletDensity);
1766 : } else {
1767 0 : ExhAirMassFlowRate = 0.0;
1768 : }
1769 8666 : this->ExhaustAirMassFlowRate = ExhAirMassFlowRate;
1770 :
1771 : Real64 ExhAirTempFTemp; // Exhaust air temperature as a function of inlet air temp curve output
1772 :
1773 8666 : if (this->ExhAirTempFTempCurveNum != 0) { // Exhaust Air Temp versus Inlet Air Temp
1774 8666 : ExhAirTempFTemp = Curve::CurveValue(state, this->ExhAirTempFTempCurveNum, CombustionAirInletTemp);
1775 : // Warn user if exhaust modifier curve output is less than or equal to 0
1776 8666 : if (ExhAirTempFTemp <= 0.0) {
1777 0 : if (this->ExhTempFTempErrorIndex == 0) {
1778 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1779 0 : ShowContinueError(
1780 : state,
1781 0 : format("...Exhaust Air Temperature Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
1782 : ExhAirTempFTemp));
1783 0 : ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
1784 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1785 : }
1786 0 : ShowRecurringWarningErrorAtEnd(state,
1787 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1788 : "\": Exhaust Air Temperature Modifier (function of temperature) output is less than or equal "
1789 : "to zero warning continues...",
1790 0 : this->ExhTempFTempErrorIndex,
1791 : ExhAirTempFTemp,
1792 : ExhAirTempFTemp);
1793 0 : ExhAirTempFTemp = 0.0;
1794 : }
1795 : } else {
1796 0 : ExhAirTempFTemp = 1.0; // No curve input means modifier = 1.0 always
1797 : }
1798 :
1799 : Real64 ExhAirTempFPLR; // Exhaust air temperature as a function of part-load ratio curve output
1800 :
1801 8666 : if (this->ExhAirTempFPLRCurveNum != 0) { // Exhaust Air Temp versus Part-Load Ratio
1802 8666 : ExhAirTempFPLR = Curve::CurveValue(state, this->ExhAirTempFPLRCurveNum, PLR);
1803 : // Warn user if exhaust modifier curve output is less than or equal to 0
1804 8666 : if (ExhAirTempFPLR <= 0.0) {
1805 0 : if (this->ExhTempFPLRErrorIndex == 0) {
1806 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1807 0 : ShowContinueError(
1808 : state,
1809 0 : format("...Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
1810 : ExhAirTempFPLR));
1811 0 : ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
1812 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1813 : }
1814 0 : ShowRecurringWarningErrorAtEnd(state,
1815 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1816 : "\": Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or "
1817 : "equal to zero warning continues...",
1818 0 : this->ExhTempFPLRErrorIndex,
1819 : ExhAirTempFPLR,
1820 : ExhAirTempFPLR);
1821 0 : ExhAirTempFPLR = 0.0;
1822 : }
1823 : } else {
1824 0 : ExhAirTempFPLR = 1.0; // No curve input means modifier = 1.0 always
1825 : }
1826 :
1827 8666 : if (ExhAirMassFlowRate <= 0.0) {
1828 0 : this->ExhaustAirTemperature = CombustionAirInletTemp;
1829 0 : this->ExhaustAirHumRat = CombustionAirInletW;
1830 : } else {
1831 : // Calculate exhaust air temperature, accounting for inlet air temperature and PLR modifier factors
1832 : // Actual exhaust air temperature (accounting for temp and PLR modifier curves)
1833 8666 : Real64 ExhaustAirTemp = this->NomExhAirOutletTemp * ExhAirTempFTemp * ExhAirTempFPLR;
1834 8666 : this->ExhaustAirTemperature = ExhaustAirTemp;
1835 : // Adjust exhaust air temperature if heat recovery to water is being done
1836 8666 : if (QHeatRecToWater > 0.0) {
1837 3360 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(CombustionAirInletW);
1838 3360 : if (CpAir > 0.0) {
1839 3360 : this->ExhaustAirTemperature = ExhaustAirTemp - QHeatRecToWater / (CpAir * ExhAirMassFlowRate);
1840 : }
1841 : }
1842 : // Calculate exhaust air humidity ratio
1843 :
1844 : // Heat of vaporization of water (J/kg)
1845 8666 : Real64 H2OHtOfVap = Psychrometrics::PsyHfgAirFnWTdb(1.0, 16.0); // W not used, passing 1.0 as dummy.
1846 : // Assume fuel is at 16C (ASHRAE HOF)
1847 8666 : if (H2OHtOfVap > 0.0) {
1848 8666 : this->ExhaustAirHumRat = CombustionAirInletW + this->FuelMdot *
1849 8666 : ((fuelHigherHeatingValue - fuelLowerHeatingValue) * KJtoJ / H2OHtOfVap) /
1850 : ExhAirMassFlowRate;
1851 : } else {
1852 0 : this->ExhaustAirHumRat = CombustionAirInletW;
1853 : }
1854 : }
1855 :
1856 8666 : if (this->ExhaustAirTemperature < CombustionAirInletTemp) {
1857 0 : if (this->ExhTempLTInletTempIndex == 0) {
1858 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1859 0 : ShowContinueError(state,
1860 : "...The model has calculated the exhaust air temperature to be less than the combustion air inlet temperature.");
1861 0 : ShowContinueError(state, format("...Value of exhaust air temperature ={:.4T} C.", this->ExhaustAirTemperature));
1862 0 : ShowContinueError(state, format("...Value of combustion air inlet temp ={:.4T} C.", CombustionAirInletTemp));
1863 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1864 : }
1865 0 : ShowRecurringWarningErrorAtEnd(state,
1866 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1867 : "\": Exhaust air temperature less than combustion air inlet temperature warning continues...",
1868 0 : this->ExhTempLTInletTempIndex,
1869 0 : this->ExhaustAirTemperature,
1870 0 : this->ExhaustAirTemperature);
1871 : }
1872 :
1873 8666 : if (this->ExhaustAirHumRat < CombustionAirInletW) {
1874 0 : if (this->ExhHRLTInletHRIndex == 0) {
1875 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1876 0 : ShowContinueError(
1877 : state, "...The model has calculated the exhaust air humidity ratio to be less than the combustion air inlet humidity ratio.");
1878 0 : ShowContinueError(state, format("...Value of exhaust air humidity ratio ={:.6T} kgWater/kgDryAir.", this->ExhaustAirHumRat));
1879 0 : ShowContinueError(state, format("...Value of combustion air inlet humidity ratio ={:.6T} kgWater/kgDryAir.", CombustionAirInletW));
1880 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1881 : }
1882 0 : ShowRecurringWarningErrorAtEnd(state,
1883 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1884 : "\": Exhaust air humidity ratio less than combustion air inlet humidity ratio warning continues...",
1885 0 : this->ExhHRLTInletHRIndex,
1886 0 : this->ExhaustAirHumRat,
1887 0 : this->ExhaustAirHumRat);
1888 : }
1889 : }
1890 : }
1891 :
1892 51343 : void MTGeneratorSpecs::UpdateMTGeneratorRecords(EnergyPlusData &state)
1893 : {
1894 : // SUBROUTINE INFORMATION:
1895 : // AUTHOR R. Raustad/D. Shirey
1896 : // DATE WRITTEN Mar 2008
1897 : // MODIFIED na
1898 : // RE-ENGINEERED na
1899 :
1900 : // PURPOSE OF THIS SUBROUTINE:
1901 : // Reporting and updating nodes if necessary.
1902 :
1903 51343 : if (this->HeatRecActive) {
1904 19272 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
1905 : }
1906 :
1907 51343 : if (this->ExhAirCalcsActive) {
1908 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
1909 27135 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
1910 :
1911 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).Temp = this->ExhaustAirTemperature;
1912 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).HumRat = this->ExhaustAirHumRat;
1913 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMaxAvail =
1914 27135 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMaxAvail;
1915 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMinAvail =
1916 27135 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMinAvail;
1917 : }
1918 :
1919 51343 : this->EnergyGen = this->ElecPowerGenerated * state.dataHVACGlobal->TimeStepSysSec;
1920 51343 : this->ExhaustEnergyRec = this->QHeatRecovered * state.dataHVACGlobal->TimeStepSysSec;
1921 51343 : this->FuelEnergyHHV = this->FuelEnergyUseRateHHV * state.dataHVACGlobal->TimeStepSysSec;
1922 51343 : if (this->FuelEnergyUseRateLHV > 0.0) {
1923 18465 : this->ElectricEfficiencyLHV = this->ElecPowerGenerated / this->FuelEnergyUseRateLHV;
1924 18465 : this->ThermalEfficiencyLHV = this->QHeatRecovered / this->FuelEnergyUseRateLHV;
1925 : } else {
1926 32878 : this->ElectricEfficiencyLHV = 0.0;
1927 32878 : this->ThermalEfficiencyLHV = 0.0;
1928 : }
1929 51343 : this->AncillaryEnergy = this->AncillaryPowerRate * state.dataHVACGlobal->TimeStepSysSec;
1930 51343 : this->StandbyEnergy = this->StandbyPowerRate * state.dataHVACGlobal->TimeStepSysSec;
1931 51343 : }
1932 51343 : void MTGeneratorSpecs::oneTimeInit(EnergyPlusData &state)
1933 : {
1934 :
1935 51343 : std::string const RoutineName("InitMTGenerators");
1936 : bool errFlag;
1937 :
1938 51343 : if (this->myFlag) {
1939 6 : this->setupOutputVars(state);
1940 6 : this->myFlag = false;
1941 : }
1942 :
1943 51343 : if (this->MyPlantScanFlag && allocated(state.dataPlnt->PlantLoop) && this->HeatRecActive) {
1944 2 : errFlag = false;
1945 4 : PlantUtilities::ScanPlantLoopsForObject(
1946 2 : state, this->Name, DataPlant::PlantEquipmentType::Generator_MicroTurbine, this->HRPlantLoc, errFlag, _, _, _, _, _);
1947 2 : if (errFlag) {
1948 0 : ShowFatalError(state, "InitMTGenerators: Program terminated due to previous condition(s).");
1949 : }
1950 :
1951 2 : this->MyPlantScanFlag = false;
1952 : }
1953 :
1954 51343 : if (this->MySizeAndNodeInitFlag && (!this->MyPlantScanFlag) && this->HeatRecActive) {
1955 :
1956 : // size mass flow rate
1957 2 : Real64 rho = state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).glycol->getDensity(state, Constant::InitConvTemp, RoutineName);
1958 :
1959 2 : this->DesignHeatRecMassFlowRate = rho * this->RefHeatRecVolFlowRate;
1960 2 : this->HeatRecMaxMassFlowRate = rho * this->HeatRecMaxVolFlowRate;
1961 :
1962 2 : PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1963 :
1964 2 : this->MySizeAndNodeInitFlag = false;
1965 : }
1966 51343 : }
1967 :
1968 : } // namespace EnergyPlus::MicroturbineElectricGenerator
|