Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2024, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <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 Modifer 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 4 : 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) return;
1132 :
1133 : // Do the Begin Environment initializations
1134 19272 : if (state.dataGlobal->BeginEnvrnFlag && this->MyEnvrnFlag) {
1135 : // set the node max and min mass flow rates
1136 16 : PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1137 :
1138 16 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp = 20.0; // Set the node temperature, assuming freeze control
1139 16 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = 20.0;
1140 :
1141 16 : this->MyEnvrnFlag = false;
1142 : } // end environmental inits
1143 :
1144 19272 : if (!state.dataGlobal->BeginEnvrnFlag) {
1145 18992 : this->MyEnvrnFlag = true;
1146 : }
1147 :
1148 : // set/request flow rates
1149 19272 : if (FirstHVACIteration) {
1150 :
1151 : Real64 DesiredMassFlowRate;
1152 12414 : if (!RunFlag) {
1153 10310 : DesiredMassFlowRate = 0.0;
1154 :
1155 2104 : } else if (RunFlag && this->InternalFlowControl) {
1156 : // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
1157 0 : if (this->HeatRecFlowFTempPowCurveNum != 0) {
1158 0 : DesiredMassFlowRate =
1159 0 : this->DesignHeatRecMassFlowRate *
1160 0 : Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
1161 : } else {
1162 0 : DesiredMassFlowRate = this->DesignHeatRecMassFlowRate; // Assume modifier = 1 if curve not specified
1163 : }
1164 :
1165 0 : DesiredMassFlowRate = max(DataPrecisionGlobals::constant_zero, DesiredMassFlowRate); // protect from neg. curve result
1166 :
1167 2104 : } else if (RunFlag && (!this->InternalFlowControl)) {
1168 2104 : DesiredMassFlowRate = this->DesignHeatRecMassFlowRate;
1169 : }
1170 :
1171 12414 : PlantUtilities::SetComponentFlowRate(state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1172 : } else { // not FirstHVACIteration
1173 6858 : if (!RunFlag) {
1174 5594 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
1175 5594 : min(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMaxAvail);
1176 5594 : state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate =
1177 5594 : max(DataPrecisionGlobals::constant_zero, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRateMinAvail);
1178 :
1179 1264 : } else if (RunFlag && this->InternalFlowControl) {
1180 : // assume dispatch power in MyLoad is what gets produced (future, reset during calc routine and iterate)
1181 0 : if (this->HeatRecFlowFTempPowCurveNum != 0) {
1182 : Real64 DesiredMassFlowRate =
1183 0 : this->DesignHeatRecMassFlowRate *
1184 0 : Curve::CurveValue(state, this->HeatRecFlowFTempPowCurveNum, state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp, MyLoad);
1185 0 : PlantUtilities::SetComponentFlowRate(
1186 0 : state, DesiredMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1187 : } else {
1188 0 : PlantUtilities::SetComponentFlowRate(
1189 0 : state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1190 : }
1191 1264 : } else if (RunFlag && (!this->InternalFlowControl)) {
1192 1264 : PlantUtilities::SetComponentFlowRate(state, this->HeatRecMdot, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum, this->HRPlantLoc);
1193 : }
1194 : }
1195 : }
1196 :
1197 51343 : void MTGeneratorSpecs::CalcMTGeneratorModel(EnergyPlusData &state,
1198 : bool const RunFlag, // TRUE when generator is being asked to operate
1199 : Real64 const MyLoad) // Generator demand (W)
1200 : {
1201 : // SUBROUTINE INFORMATION:
1202 : // AUTHOR R. Raustad/D. Shirey
1203 : // DATE WRITTEN Mar 2008
1204 : // MODIFIED na
1205 : // RE-ENGINEERED na
1206 :
1207 : // PURPOSE OF THIS SUBROUTINE:
1208 : // Simulate a combustion generator.
1209 :
1210 : // METHODOLOGY EMPLOYED:
1211 : // Curve fits of performance data.
1212 :
1213 51343 : Real64 constexpr KJtoJ(1000.0); // Convert kilojoules to joules
1214 51343 : int constexpr MaxAncPowerIter(50); // Maximum number of iteration (subroutine ancillary power iteration loop)
1215 51343 : Real64 constexpr AncPowerDiffToler(5.0); // Tolerance for Ancillary Power Difference (W)
1216 51343 : Real64 constexpr RelaxFactor(0.7); // Relaxation factor for iteration loop
1217 : static constexpr std::string_view RoutineName("CalcMTGeneratorModel");
1218 :
1219 : // Load local variables from data structure (for code readability)
1220 : // Min allowed operating fraction at full load
1221 51343 : Real64 minPartLoadRat = this->MinPartLoadRat;
1222 :
1223 : // Max allowed operating fraction at full load
1224 51343 : Real64 maxPartLoadRat = this->MaxPartLoadRat;
1225 :
1226 : // Generator reference capacity (W)
1227 51343 : Real64 ReferencePowerOutput = this->RefElecPowerOutput;
1228 :
1229 : // Reference electrical efficiency
1230 51343 : Real64 RefElecEfficiency = this->RefElecEfficiencyLHV;
1231 :
1232 : // Initialize variables
1233 51343 : this->ElecPowerGenerated = 0.0;
1234 51343 : this->HeatRecInletTemp = 0.0;
1235 51343 : this->HeatRecOutletTemp = 0.0;
1236 51343 : this->HeatRecMdot = 0.0;
1237 51343 : this->QHeatRecovered = 0.0;
1238 51343 : this->ExhaustEnergyRec = 0.0;
1239 51343 : this->FuelEnergyUseRateHHV = 0.0;
1240 51343 : this->FuelMdot = 0.0;
1241 51343 : this->AncillaryPowerRate = 0.0;
1242 51343 : this->StandbyPowerRate = 0.0;
1243 51343 : this->FuelEnergyUseRateLHV = 0.0;
1244 51343 : this->ExhaustAirMassFlowRate = 0.0;
1245 51343 : this->ExhaustAirTemperature = 0.0;
1246 51343 : this->ExhaustAirHumRat = 0.0;
1247 :
1248 : Real64 HeatRecInTemp; // Heat recovery fluid inlet temperature (C)
1249 : Real64 heatRecMdot; // Heat recovery fluid mass flow rate (kg/s)
1250 : Real64 HeatRecCp; // Specific heat of the heat recovery fluid (J/kg-K)
1251 :
1252 51343 : if (this->HeatRecActive) {
1253 19272 : HeatRecInTemp = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).Temp;
1254 19272 : HeatRecCp = FluidProperties::GetSpecificHeatGlycol(state,
1255 19272 : state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidName,
1256 : HeatRecInTemp,
1257 19272 : state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidIndex,
1258 : RoutineName);
1259 19272 : heatRecMdot = state.dataLoopNodes->Node(this->HeatRecInletNodeNum).MassFlowRate;
1260 : } else {
1261 32071 : HeatRecInTemp = 0.0;
1262 32071 : HeatRecCp = 0.0;
1263 32071 : heatRecMdot = 0.0;
1264 : }
1265 :
1266 : Real64 CombustionAirInletTemp; // Combustion air inlet temperature (C)
1267 : Real64 CombustionAirInletPress; // Barometric pressure of combustion inlet air (Pa)
1268 : Real64 CombustionAirInletW; // Combustion air inlet humidity ratio (kg/kg)
1269 :
1270 : // Set combustion inlet air temperature, humidity ratio and pressure local variables
1271 51343 : if (this->CombustionAirInletNodeNum == 0) { // no inlet air node specified, so use weather file values
1272 24208 : CombustionAirInletTemp = state.dataEnvrn->OutDryBulbTemp;
1273 24208 : CombustionAirInletW = state.dataEnvrn->OutHumRat;
1274 24208 : CombustionAirInletPress = state.dataEnvrn->OutBaroPress;
1275 : } else { // use inlet node information
1276 27135 : CombustionAirInletTemp = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Temp;
1277 27135 : CombustionAirInletW = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).HumRat;
1278 27135 : CombustionAirInletPress = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Press;
1279 27135 : if (state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).Height > 0.0) {
1280 : }
1281 : // Initialize combustion outlet air conditions to inlet air conditions (all node properties)
1282 27135 : if (this->ExhAirCalcsActive) {
1283 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum) = state.dataLoopNodes->Node(this->CombustionAirInletNodeNum);
1284 : }
1285 : }
1286 :
1287 : // If no loop demand or generator OFF, set some variables and then return
1288 : // IF (.NOT. RunFlag .OR. MyLoad .LE. 0.0d0) THEN
1289 51343 : if (MyLoad <= 0.0) {
1290 32878 : this->HeatRecInletTemp = HeatRecInTemp;
1291 32878 : this->HeatRecOutletTemp = HeatRecInTemp;
1292 32878 : if (RunFlag) {
1293 0 : this->StandbyPowerRate = this->StandbyPower;
1294 : }
1295 32878 : this->ExhaustAirTemperature = CombustionAirInletTemp;
1296 32878 : this->ExhaustAirHumRat = CombustionAirInletW;
1297 32878 : return;
1298 : }
1299 :
1300 : // Calculate power modifier curve value (function of inlet air temperature and elevation)
1301 : // Power ratio as a function of inlet air temperature and elevation
1302 18465 : Real64 PowerFTempElev = Curve::CurveValue(state, this->ElecPowFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
1303 :
1304 : // Warn user if power modifier curve output is less than 0
1305 18465 : if (PowerFTempElev < 0.0) {
1306 0 : if (this->PowerFTempElevErrorIndex == 0) {
1307 : // MTGenerator(GeneratorNum)%PowerFTempElevErrorCount = MTGenerator(GeneratorNum)%PowerFTempElevErrorCount + 1
1308 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1309 0 : ShowContinueError(state,
1310 0 : format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
1311 : PowerFTempElev));
1312 0 : ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1313 0 : ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
1314 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1315 : }
1316 0 : ShowRecurringWarningErrorAtEnd(state,
1317 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1318 : "\": Electrical Power Modifier curve is less than zero warning continues...",
1319 0 : this->PowerFTempElevErrorIndex,
1320 : PowerFTempElev,
1321 : PowerFTempElev);
1322 0 : PowerFTempElev = 0.0;
1323 : }
1324 :
1325 : // Calculate available full-load power output. cannot exceed maximum full-load power output.
1326 : // Generator full-load power output at actual inlet conditions and elevation (W)
1327 18465 : Real64 FullLoadPowerOutput = min((ReferencePowerOutput * PowerFTempElev), this->MaxElecPowerOutput);
1328 : // Also can't be below the minimum full-load power output.
1329 18465 : FullLoadPowerOutput = max(FullLoadPowerOutput, this->MinElecPowerOutput);
1330 :
1331 : // Ancillary power used by pump (if not specified in manufacturers data)
1332 18465 : Real64 ancillaryPowerRate = this->AncillaryPower;
1333 :
1334 : // Difference between ancillary power rate and ancillary power rate last (last iteration)
1335 18465 : Real64 AncillaryPowerRateDiff = AncPowerDiffToler + 1.0; // Initialize to force through DO WHILE Loop at least once
1336 :
1337 18465 : Real64 PLR(0.0); // Generator operating part load ratio
1338 18465 : Real64 elecPowerGenerated(0.0); // Generator electric power output (W)
1339 18465 : Real64 FuelUseEnergyRateLHV(0.0); // Rate of fuel energy required to run microturbine, LHV basis (W)
1340 18465 : Real64 fuelHigherHeatingValue(0.0); // Higher heating value (LLV) of fuel kJ/kg)
1341 18465 : Real64 fuelLowerHeatingValue(0.0); // Lower heating value (LLV) of fuel kJ/kg)
1342 18465 : Real64 AnciPowerFMdotFuel(0.0); // Ancillary power as a function of fuel flow curve output
1343 18465 : int AncPowerCalcIterIndex = 0; // Index for subroutine iteration loop if Ancillary Power (function of fuel flow) is used
1344 :
1345 36930 : while (AncillaryPowerRateDiff > AncPowerDiffToler && AncPowerCalcIterIndex <= MaxAncPowerIter) {
1346 :
1347 18465 : ++AncPowerCalcIterIndex; // Increment iteration loop counter
1348 :
1349 : // Calculate operating power output (gross)
1350 18465 : elecPowerGenerated = min(max(0.0, MyLoad + ancillaryPowerRate), FullLoadPowerOutput);
1351 :
1352 : // Calculate PLR, but must be between the minPLR and maxPLR
1353 18465 : if (FullLoadPowerOutput > 0.0) {
1354 18465 : PLR = min(elecPowerGenerated / FullLoadPowerOutput, maxPartLoadRat);
1355 18465 : PLR = max(PLR, minPartLoadRat);
1356 : } else {
1357 0 : PLR = 0.0;
1358 : }
1359 :
1360 : // Recalculate elecPowerGenerated based on "final" PLR
1361 18465 : elecPowerGenerated = FullLoadPowerOutput * PLR;
1362 :
1363 : // Calculate electrical efficiency modifier curve output (function of temp)
1364 : // Electrical efficiency as a function of temperature curve output
1365 18465 : Real64 ElecEfficiencyFTemp = Curve::CurveValue(state, this->ElecEffFTempCurveNum, CombustionAirInletTemp);
1366 :
1367 : // Warn user if efficiency modifier curve output is less than 0
1368 18465 : if (ElecEfficiencyFTemp < 0.0) {
1369 0 : if (this->EffFTempErrorIndex == 0) {
1370 : // MTGenerator(GeneratorNum)%EffFTempErrorCount = MTGenerator(GeneratorNum)%EffFTempErrorCount + 1
1371 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1372 0 : ShowContinueError(
1373 : state,
1374 0 : format("... Electrical Efficiency Modifier (function of temperature) output is less than zero ({:.4T}).", ElecEfficiencyFTemp));
1375 0 : ShowContinueError(state, format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1376 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1377 : }
1378 0 : ShowRecurringWarningErrorAtEnd(
1379 : state,
1380 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1381 : "\": Electrical Efficiency Modifier (function of temperature) output is less than zero warning continues...",
1382 0 : this->EffFTempErrorIndex,
1383 : ElecEfficiencyFTemp,
1384 : ElecEfficiencyFTemp);
1385 0 : ElecEfficiencyFTemp = 0.0;
1386 : }
1387 :
1388 : // Calculate efficiency modifier curve output (function of PLR)
1389 : // Electrical efficiency as a function of PLR curve output
1390 18465 : Real64 ElecEfficiencyFPLR = Curve::CurveValue(state, this->ElecEffFPLRCurveNum, PLR);
1391 :
1392 : // Warn user if efficiency modifier curve output is less than 0
1393 18465 : if (ElecEfficiencyFPLR < 0.0) {
1394 0 : if (this->EffFPLRErrorIndex == 0) {
1395 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1396 0 : ShowContinueError(state,
1397 0 : format("... Electrical Efficiency Modifier (function of part-load ratio) output is less than zero ({:.4T}).",
1398 : ElecEfficiencyFPLR));
1399 0 : ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
1400 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1401 : }
1402 0 : ShowRecurringWarningErrorAtEnd(
1403 : state,
1404 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1405 : "\": Electrical Efficiency Modifier (function of part-load ratio) output is less than zero warning continues...",
1406 0 : this->EffFPLRErrorIndex,
1407 : ElecEfficiencyFPLR,
1408 : ElecEfficiencyFPLR);
1409 0 : ElecEfficiencyFPLR = 0.0;
1410 : }
1411 :
1412 : // Calculate operating electrical efficiency
1413 : // Actual operating efficiency
1414 18465 : Real64 OperatingElecEfficiency = RefElecEfficiency * ElecEfficiencyFTemp * ElecEfficiencyFPLR;
1415 :
1416 : // Calculate fuel use (W = J/s), LHV basis
1417 18465 : if (OperatingElecEfficiency > 0.0) {
1418 18465 : FuelUseEnergyRateLHV = elecPowerGenerated / OperatingElecEfficiency;
1419 : } else {
1420 0 : FuelUseEnergyRateLHV = 0.0; // If fuel use rate is zero, then
1421 0 : elecPowerGenerated = 0.0; // electric power generated must be zero.
1422 : }
1423 :
1424 : // Set fuel heating values
1425 18465 : fuelHigherHeatingValue = this->FuelHigherHeatingValue;
1426 18465 : fuelLowerHeatingValue = this->FuelLowerHeatingValue;
1427 :
1428 : // Calculate fuel mass flow rate
1429 18465 : this->FuelMdot = FuelUseEnergyRateLHV / (fuelLowerHeatingValue * KJtoJ);
1430 :
1431 : // Calculate ancillary power requirement
1432 18465 : if (this->AncillaryPowerFuelCurveNum > 0) {
1433 0 : AnciPowerFMdotFuel = Curve::CurveValue(state, this->AncillaryPowerFuelCurveNum, this->FuelMdot);
1434 : // Warn user if ancillary power modifier curve output is less than 0
1435 0 : if (AnciPowerFMdotFuel < 0.0) {
1436 0 : if (this->AnciPowerFMdotFuelErrorIndex == 0) {
1437 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1438 0 : ShowContinueError(
1439 : state,
1440 0 : format("... Ancillary Power Modifier (function of fuel input) output is less than zero ({:.4T}).", AnciPowerFMdotFuel));
1441 0 : ShowContinueError(state, format("... Value occurs using a fuel input mass flow rate of {:.4T} kg/s.", this->FuelMdot));
1442 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1443 : }
1444 0 : ShowRecurringWarningErrorAtEnd(
1445 : state,
1446 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1447 : "\": Ancillary Power Modifier (function of fuel input) output is less than zero warning continues...",
1448 0 : this->AnciPowerFMdotFuelErrorIndex,
1449 : AnciPowerFMdotFuel,
1450 : AnciPowerFMdotFuel);
1451 0 : AnciPowerFMdotFuel = 0.0;
1452 : }
1453 : } else {
1454 18465 : AnciPowerFMdotFuel = 1.0;
1455 : }
1456 :
1457 : // Ancillary power used by pump from last iteration (iteration loop within this subroutine)
1458 18465 : Real64 AncillaryPowerRateLast = ancillaryPowerRate;
1459 :
1460 18465 : if (this->AncillaryPowerFuelCurveNum > 0) {
1461 0 : ancillaryPowerRate = RelaxFactor * this->AncillaryPower * AnciPowerFMdotFuel - (1.0 - RelaxFactor) * AncillaryPowerRateLast;
1462 : }
1463 :
1464 18465 : AncillaryPowerRateDiff = std::abs(ancillaryPowerRate - AncillaryPowerRateLast);
1465 : }
1466 :
1467 18465 : if (AncPowerCalcIterIndex > MaxAncPowerIter) {
1468 :
1469 0 : if (this->AnciPowerIterErrorIndex == 0) {
1470 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1471 0 : ShowContinueError(state, "... Iteration loop for electric power generation is not converging within tolerance.");
1472 0 : ShowContinueError(state, "... Check the Ancillary Power Modifier Curve (function of fuel input).");
1473 0 : ShowContinueError(state, format("... Ancillary Power = {:.1T} W.", ancillaryPowerRate));
1474 0 : ShowContinueError(state, format("... Fuel input rate = {:.4T} kg/s.", AnciPowerFMdotFuel));
1475 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1476 : }
1477 0 : ShowRecurringWarningErrorAtEnd(state,
1478 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1479 : "\": Iteration loop for electric power generation is not converging within tolerance continues...",
1480 0 : this->AnciPowerIterErrorIndex);
1481 : }
1482 :
1483 : // Calculate electrical power generated
1484 18465 : this->ElecPowerGenerated = elecPowerGenerated - ancillaryPowerRate;
1485 :
1486 : // Report fuel energy use rate on HHV basis, which is the unit of measure when the fuel is sold
1487 18465 : this->FuelEnergyUseRateHHV = this->FuelMdot * fuelHigherHeatingValue * KJtoJ;
1488 18465 : this->AncillaryPowerRate = ancillaryPowerRate; // Move to data structure for later reporting
1489 18465 : this->FuelEnergyUseRateLHV = FuelUseEnergyRateLHV; // Move to data structure for reporting calculations
1490 :
1491 : // When generator operates, standby losses are 0
1492 18465 : this->StandbyPowerRate = 0.0;
1493 :
1494 18465 : Real64 QHeatRecToWater = 0.0; // Recovered waste heat to water (W)
1495 :
1496 : // Calculate heat recovery if active
1497 18465 : if (this->HeatRecActive) {
1498 :
1499 : // Thermal efficiency as a function of air temperature and elevation
1500 : Real64 ThermalEffFTempElev;
1501 3368 : if (this->ThermEffFTempElevCurveNum > 0) {
1502 3368 : ThermalEffFTempElev = Curve::CurveValue(state, this->ThermEffFTempElevCurveNum, CombustionAirInletTemp, state.dataEnvrn->Elevation);
1503 : // Warn user if power modifier curve output is less than 0
1504 3368 : if (ThermalEffFTempElev < 0.0) {
1505 0 : if (this->ThermEffFTempElevErrorIndex == 0) {
1506 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1507 0 : ShowContinueError(
1508 : state,
1509 0 : format("... Electrical Power Modifier curve (function of temperature and elevation) output is less than zero ({:.4T}).",
1510 : PowerFTempElev));
1511 0 : ShowContinueError(state,
1512 0 : format("... Value occurs using a combustion inlet air temperature of {:.2T} C.", CombustionAirInletTemp));
1513 0 : ShowContinueError(state, format("... and an elevation of {:.2T} m.", state.dataEnvrn->Elevation));
1514 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1515 : }
1516 0 : ShowRecurringWarningErrorAtEnd(state,
1517 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1518 : "\": Electrical Power Modifier curve is less than zero warning continues...",
1519 0 : this->ThermEffFTempElevErrorIndex,
1520 : ThermalEffFTempElev,
1521 : ThermalEffFTempElev);
1522 0 : ThermalEffFTempElev = 0.0;
1523 : }
1524 : } else {
1525 0 : ThermalEffFTempElev = 1.0; // If no curve provided, assume multiplier factor = 1.0
1526 : }
1527 :
1528 3368 : QHeatRecToWater = FuelUseEnergyRateLHV * this->RefThermalEffLHV * ThermalEffFTempElev;
1529 : Real64 HeatRecRateFPLR; // Heat recovery rate as a function of PLR curve output
1530 :
1531 : // Calculate heat recovery rate modifier curve output (function of PLR)
1532 3368 : if (this->HeatRecRateFPLRCurveNum > 0) {
1533 3368 : HeatRecRateFPLR = Curve::CurveValue(state, this->HeatRecRateFPLRCurveNum, PLR);
1534 : // Warn user if heat recovery modifier curve output is less than 0
1535 3368 : if (HeatRecRateFPLR < 0.0) {
1536 0 : if (this->HeatRecRateFPLRErrorIndex == 0) {
1537 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1538 0 : ShowContinueError(
1539 : state,
1540 0 : format("... Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero ({:.4T}).", HeatRecRateFPLR));
1541 0 : ShowContinueError(state, format("... Value occurs using a part-load ratio of {:.3T}.", PLR));
1542 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1543 : }
1544 0 : ShowRecurringWarningErrorAtEnd(
1545 : state,
1546 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1547 : "\": Heat Recovery Rate Modifier (function of part-load ratio) output is less than zero warning continues...",
1548 0 : this->HeatRecRateFPLRErrorIndex,
1549 : HeatRecRateFPLR,
1550 : HeatRecRateFPLR);
1551 0 : HeatRecRateFPLR = 0.0;
1552 : }
1553 : } else {
1554 0 : HeatRecRateFPLR = 1.0; // If no curve provided, assume multiplier factor = 1.0
1555 : }
1556 :
1557 : Real64 HeatRecRateFTemp; // Heat recovery rate as a function of inlet water temp curve output
1558 :
1559 : // Calculate heat recovery rate modifier curve output (function of inlet water temp)
1560 3368 : if (this->HeatRecRateFTempCurveNum > 0) {
1561 3368 : HeatRecRateFTemp = Curve::CurveValue(state, this->HeatRecRateFTempCurveNum, HeatRecInTemp);
1562 3368 : if (HeatRecRateFTemp < 0.0) {
1563 0 : if (this->HeatRecRateFTempErrorIndex == 0) {
1564 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1565 0 : ShowContinueError(state,
1566 0 : format("... Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero ({:.4T}).",
1567 : HeatRecRateFTemp));
1568 0 : ShowContinueError(state, format("... Value occurs using an inlet water temperature temperature of {:.2T} C.", HeatRecInTemp));
1569 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1570 : }
1571 0 : ShowRecurringWarningErrorAtEnd(
1572 : state,
1573 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1574 : "\": Heat Recovery Rate Modifier (function of inlet water temp) output is less than zero warning continues...",
1575 0 : this->HeatRecRateFTempErrorIndex,
1576 : HeatRecRateFTemp,
1577 : HeatRecRateFTemp);
1578 0 : HeatRecRateFTemp = 0.0;
1579 : }
1580 : } else {
1581 0 : HeatRecRateFTemp = 1.0; // If no curve provided, assume multiplier factor = 1.0
1582 : }
1583 :
1584 : Real64 HeatRecRateFFlow; // Heat recovery rate as a function of water flow rate curve output
1585 :
1586 : // Calculate heat recovery rate modifier curve output (function of water [volumetric] flow rate)
1587 3368 : if (this->HeatRecRateFWaterFlowCurveNum > 0) {
1588 3368 : Real64 rho = FluidProperties::GetDensityGlycol(state,
1589 3368 : state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidName,
1590 : HeatRecInTemp,
1591 3368 : state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidIndex,
1592 : RoutineName);
1593 :
1594 : // Heat recovery fluid flow rate (m3/s)
1595 3368 : Real64 HeatRecVolFlowRate = heatRecMdot / rho;
1596 3368 : HeatRecRateFFlow = Curve::CurveValue(state, this->HeatRecRateFWaterFlowCurveNum, HeatRecVolFlowRate);
1597 3368 : if (HeatRecRateFFlow < 0.0) {
1598 0 : if (this->HeatRecRateFFlowErrorIndex == 0) {
1599 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1600 0 : ShowContinueError(
1601 : state,
1602 0 : format("... Heat Recovery Rate Modifier (function of water flow rate) output is less than zero ({:.4T}).", HeatRecRateFFlow));
1603 0 : ShowContinueError(state, format("... Value occurs using a water flow rate of {:.4T} m3/s.", HeatRecVolFlowRate));
1604 0 : ShowContinueErrorTimeStamp(state, "... Resetting curve output to zero and continuing simulation.");
1605 : }
1606 0 : ShowRecurringWarningErrorAtEnd(
1607 : state,
1608 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1609 : "\": Heat Recovery Rate Modifier (function of water flow rate) output is less than zero warning continues...",
1610 0 : this->HeatRecRateFFlowErrorIndex,
1611 : HeatRecRateFFlow,
1612 : HeatRecRateFFlow);
1613 0 : HeatRecRateFFlow = 0.0;
1614 : }
1615 : } else {
1616 0 : HeatRecRateFFlow = 1.0; // If no curve provided, assume multiplier factor = 1.0
1617 : }
1618 :
1619 3368 : QHeatRecToWater *= HeatRecRateFPLR * HeatRecRateFTemp * HeatRecRateFFlow;
1620 :
1621 : Real64 HeatRecOutTemp; // Heat recovery fluid outlet temperature (C)
1622 :
1623 : // Check for divide by zero
1624 3368 : if ((heatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
1625 3368 : HeatRecOutTemp = HeatRecInTemp + QHeatRecToWater / (heatRecMdot * HeatRecCp);
1626 : } else {
1627 0 : heatRecMdot = 0.0;
1628 0 : HeatRecOutTemp = HeatRecInTemp;
1629 0 : QHeatRecToWater = 0.0;
1630 : }
1631 :
1632 : // Now verify the maximum heat recovery temperature was not exceeded
1633 3368 : if (HeatRecOutTemp > this->HeatRecMaxWaterTemp) {
1634 :
1635 1659 : Real64 MinHeatRecMdot = 0.0; // Heat recovery flow rate if minimal heat recovery is accomplished (kg/s)
1636 :
1637 1659 : if (this->HeatRecMaxWaterTemp != HeatRecInTemp) {
1638 1659 : MinHeatRecMdot = QHeatRecToWater / (HeatRecCp * (this->HeatRecMaxWaterTemp - HeatRecInTemp));
1639 1659 : if (MinHeatRecMdot < 0.0) MinHeatRecMdot = 0.0;
1640 : }
1641 :
1642 : // Recalculate outlet water temperature with minimum flow rate (will normally match the max water outlet temp,
1643 : // unless the inlet water temp is greater than the max outlet temp)
1644 : Real64 HRecRatio; // When maximum temperature is reached the amount of recovered heat has to be reduced
1645 :
1646 1659 : if ((MinHeatRecMdot > 0.0) && (HeatRecCp > 0.0)) {
1647 1651 : HeatRecOutTemp = QHeatRecToWater / (MinHeatRecMdot * HeatRecCp) + HeatRecInTemp;
1648 1651 : HRecRatio = heatRecMdot / MinHeatRecMdot;
1649 : } else {
1650 8 : HeatRecOutTemp = HeatRecInTemp;
1651 8 : HRecRatio = 0.0;
1652 : }
1653 1659 : QHeatRecToWater *= HRecRatio; // Scale heat recovery rate using HRecRatio. Don't adjust flow rate.
1654 : }
1655 :
1656 : // Check water mass flow rate against minimum
1657 3368 : if (this->HeatRecMinMassFlowRate > heatRecMdot && heatRecMdot > 0.0) {
1658 0 : if (this->HRMinFlowErrorIndex == 0) {
1659 0 : ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1660 0 : ShowContinueError(state,
1661 0 : format("...Heat reclaim water flow rate is below the generators minimum mass flow rate of ({:.4T}).",
1662 0 : this->HeatRecMinMassFlowRate));
1663 0 : ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
1664 0 : ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
1665 : }
1666 0 : ShowRecurringWarningErrorAtEnd(
1667 : state,
1668 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1669 : "\": Heat recovery water flow rate is below the generators minimum mass flow rate warning continues...",
1670 0 : this->HRMinFlowErrorIndex,
1671 : heatRecMdot,
1672 : heatRecMdot);
1673 : }
1674 :
1675 : // Check water mass flow rate against maximum
1676 3368 : if (heatRecMdot > this->HeatRecMaxMassFlowRate && heatRecMdot > 0.0) {
1677 0 : if (this->HRMaxFlowErrorIndex == 0) {
1678 0 : ShowWarningError(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1679 0 : ShowContinueError(state,
1680 0 : format("...Heat reclaim water flow rate is above the generators maximum mass flow rate of ({:.4T}).",
1681 0 : this->HeatRecMaxMassFlowRate));
1682 0 : ShowContinueError(state, format("...Heat reclaim water mass flow rate = {:.4T}.", heatRecMdot));
1683 0 : ShowContinueErrorTimeStamp(state, "...Check inputs for heat recovery water flow rate.");
1684 : }
1685 0 : ShowRecurringWarningErrorAtEnd(
1686 : state,
1687 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1688 : "\": Heat recovery water flow rate is above the generators maximum mass flow rate warning continues...",
1689 0 : this->HRMaxFlowErrorIndex,
1690 : heatRecMdot,
1691 : heatRecMdot);
1692 : }
1693 :
1694 : // Set report variables
1695 3368 : this->HeatRecInletTemp = HeatRecInTemp;
1696 3368 : this->HeatRecOutletTemp = HeatRecOutTemp;
1697 3368 : this->HeatRecMdot = heatRecMdot;
1698 3368 : this->QHeatRecovered = QHeatRecToWater;
1699 :
1700 : } // End of IF (MTGenerator(GeneratorNum)%HeatRecActive) THEN
1701 :
1702 : // Calculate combustion air outlet conditions if exhaust air calculations are active
1703 18465 : if (this->ExhAirCalcsActive) {
1704 :
1705 : Real64 ExhFlowFTemp; // Exhaust air flow rate as a function of temperature curve output
1706 :
1707 8666 : if (this->ExhFlowFTempCurveNum != 0) { // Exhaust Flow Rate versus Inlet Air Temp
1708 8666 : ExhFlowFTemp = Curve::CurveValue(state, this->ExhFlowFTempCurveNum, CombustionAirInletTemp);
1709 : // Warn user if exhaust modifier curve output is less than or equal to 0
1710 8666 : if (ExhFlowFTemp <= 0.0) {
1711 0 : if (this->ExhFlowFTempErrorIndex == 0) {
1712 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1713 0 : ShowContinueError(
1714 : state,
1715 0 : format("...Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
1716 : ExhFlowFTemp));
1717 0 : ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
1718 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1719 : }
1720 0 : ShowRecurringWarningErrorAtEnd(
1721 : state,
1722 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1723 : "\": Exhaust Air Flow Rate Modifier (function of temperature) output is less than or equal to zero warning continues...",
1724 0 : this->ExhFlowFTempErrorIndex,
1725 : ExhFlowFTemp,
1726 : ExhFlowFTemp);
1727 0 : ExhFlowFTemp = 0.0;
1728 : }
1729 : } else {
1730 0 : ExhFlowFTemp = 1.0; // No curve input means modifier = 1.0 always
1731 : }
1732 :
1733 : Real64 ExhFlowFPLR; // Exhaust air flow rate as a function of part-load ratio curve output
1734 :
1735 8666 : if (this->ExhFlowFPLRCurveNum != 0) { // Exhaust Flow Rate versus Part-Load Ratio
1736 8666 : ExhFlowFPLR = Curve::CurveValue(state, this->ExhFlowFPLRCurveNum, PLR);
1737 : // Warn user if exhaust modifier curve output is less than or equal to 0
1738 8666 : if (ExhFlowFPLR <= 0.0) {
1739 0 : if (this->ExhFlowFPLRErrorIndex == 0) {
1740 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1741 0 : ShowContinueError(
1742 : state,
1743 0 : format("...Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
1744 : ExhFlowFPLR));
1745 0 : ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
1746 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1747 : }
1748 0 : ShowRecurringWarningErrorAtEnd(state,
1749 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1750 : "\": Exhaust Air Flow Rate Modifier (function of part-load ratio) output is less than or "
1751 : "equal to zero warning continues...",
1752 0 : this->ExhFlowFPLRErrorIndex,
1753 : ExhFlowFPLR,
1754 : ExhFlowFPLR);
1755 0 : ExhFlowFPLR = 0.0;
1756 : }
1757 : } else {
1758 0 : ExhFlowFPLR = 1.0; // No curve input means modifier = 1.0 always
1759 : }
1760 :
1761 : // Calculate exhaust air mass flow, accounting for temperature and PLR modifier factors
1762 : // Actual exhaust air mass flow rate (accounting for temp and PLR modifier curves)
1763 8666 : Real64 ExhAirMassFlowRate = this->RefExhaustAirMassFlowRate * ExhFlowFTemp * ExhFlowFPLR;
1764 : // Adjust for difference in air density at reference conditions versus actual inlet air conditions
1765 :
1766 : // Density of air at actual combustion inlet air conditions (kg/m3)
1767 8666 : Real64 AirDensity = Psychrometrics::PsyRhoAirFnPbTdbW(state, CombustionAirInletPress, CombustionAirInletTemp, CombustionAirInletW);
1768 8666 : if (this->RefCombustAirInletDensity >= 0.0) {
1769 8666 : ExhAirMassFlowRate = max(0.0, ExhAirMassFlowRate * AirDensity / this->RefCombustAirInletDensity);
1770 : } else {
1771 0 : ExhAirMassFlowRate = 0.0;
1772 : }
1773 8666 : this->ExhaustAirMassFlowRate = ExhAirMassFlowRate;
1774 :
1775 : Real64 ExhAirTempFTemp; // Exhaust air temperature as a function of inlet air temp curve output
1776 :
1777 8666 : if (this->ExhAirTempFTempCurveNum != 0) { // Exhaust Air Temp versus Inlet Air Temp
1778 8666 : ExhAirTempFTemp = Curve::CurveValue(state, this->ExhAirTempFTempCurveNum, CombustionAirInletTemp);
1779 : // Warn user if exhaust modifier curve output is less than or equal to 0
1780 8666 : if (ExhAirTempFTemp <= 0.0) {
1781 0 : if (this->ExhTempFTempErrorIndex == 0) {
1782 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1783 0 : ShowContinueError(
1784 : state,
1785 0 : format("...Exhaust Air Temperature Modifier (function of temperature) output is less than or equal to zero ({:.4T}).",
1786 : ExhAirTempFTemp));
1787 0 : ShowContinueError(state, format("...Value occurs using a combustion inlet air temperature of {:.2T}.", CombustionAirInletTemp));
1788 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1789 : }
1790 0 : ShowRecurringWarningErrorAtEnd(state,
1791 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1792 : "\": Exhaust Air Temperature Modifier (function of temperature) output is less than or equal "
1793 : "to zero warning continues...",
1794 0 : this->ExhTempFTempErrorIndex,
1795 : ExhAirTempFTemp,
1796 : ExhAirTempFTemp);
1797 0 : ExhAirTempFTemp = 0.0;
1798 : }
1799 : } else {
1800 0 : ExhAirTempFTemp = 1.0; // No curve input means modifier = 1.0 always
1801 : }
1802 :
1803 : Real64 ExhAirTempFPLR; // Exhaust air temperature as a function of part-load ratio curve output
1804 :
1805 8666 : if (this->ExhAirTempFPLRCurveNum != 0) { // Exhaust Air Temp versus Part-Load Ratio
1806 8666 : ExhAirTempFPLR = Curve::CurveValue(state, this->ExhAirTempFPLRCurveNum, PLR);
1807 : // Warn user if exhaust modifier curve output is less than or equal to 0
1808 8666 : if (ExhAirTempFPLR <= 0.0) {
1809 0 : if (this->ExhTempFPLRErrorIndex == 0) {
1810 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1811 0 : ShowContinueError(
1812 : state,
1813 0 : format("...Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or equal to zero ({:.4T}).",
1814 : ExhAirTempFPLR));
1815 0 : ShowContinueError(state, format("...Value occurs using a part-load ratio of {:.2T}.", PLR));
1816 0 : ShowContinueErrorTimeStamp(state, "...Resetting curve output to zero and continuing simulation.");
1817 : }
1818 0 : ShowRecurringWarningErrorAtEnd(state,
1819 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1820 : "\": Exhaust Air Temperature Modifier (function of part-load ratio) output is less than or "
1821 : "equal to zero warning continues...",
1822 0 : this->ExhTempFPLRErrorIndex,
1823 : ExhAirTempFPLR,
1824 : ExhAirTempFPLR);
1825 0 : ExhAirTempFPLR = 0.0;
1826 : }
1827 : } else {
1828 0 : ExhAirTempFPLR = 1.0; // No curve input means modifier = 1.0 always
1829 : }
1830 :
1831 8666 : if (ExhAirMassFlowRate <= 0.0) {
1832 0 : this->ExhaustAirTemperature = CombustionAirInletTemp;
1833 0 : this->ExhaustAirHumRat = CombustionAirInletW;
1834 : } else {
1835 : // Calculate exhaust air temperature, accounting for inlet air temperature and PLR modifier factors
1836 : // Actual exhaust air temperature (accounting for temp and PLR modifier curves)
1837 8666 : Real64 ExhaustAirTemp = this->NomExhAirOutletTemp * ExhAirTempFTemp * ExhAirTempFPLR;
1838 8666 : this->ExhaustAirTemperature = ExhaustAirTemp;
1839 : // Adjust exhaust air temperature if heat recovery to water is being done
1840 8666 : if (QHeatRecToWater > 0.0) {
1841 3360 : Real64 CpAir = Psychrometrics::PsyCpAirFnW(CombustionAirInletW);
1842 3360 : if (CpAir > 0.0) {
1843 3360 : this->ExhaustAirTemperature = ExhaustAirTemp - QHeatRecToWater / (CpAir * ExhAirMassFlowRate);
1844 : }
1845 : }
1846 : // Calculate exhaust air humidity ratio
1847 :
1848 : // Heat of vaporization of water (J/kg)
1849 8666 : Real64 H2OHtOfVap = Psychrometrics::PsyHfgAirFnWTdb(1.0, 16.0); // W not used, passing 1.0 as dummy.
1850 : // Assume fuel is at 16C (ASHRAE HOF)
1851 8666 : if (H2OHtOfVap > 0.0) {
1852 8666 : this->ExhaustAirHumRat = CombustionAirInletW + this->FuelMdot *
1853 8666 : ((fuelHigherHeatingValue - fuelLowerHeatingValue) * KJtoJ / H2OHtOfVap) /
1854 : ExhAirMassFlowRate;
1855 : } else {
1856 0 : this->ExhaustAirHumRat = CombustionAirInletW;
1857 : }
1858 : }
1859 :
1860 8666 : if (this->ExhaustAirTemperature < CombustionAirInletTemp) {
1861 0 : if (this->ExhTempLTInletTempIndex == 0) {
1862 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1863 0 : ShowContinueError(state,
1864 : "...The model has calculated the exhaust air temperature to be less than the combustion air inlet temperature.");
1865 0 : ShowContinueError(state, format("...Value of exhaust air temperature ={:.4T} C.", this->ExhaustAirTemperature));
1866 0 : ShowContinueError(state, format("...Value of combustion air inlet temp ={:.4T} C.", CombustionAirInletTemp));
1867 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1868 : }
1869 0 : ShowRecurringWarningErrorAtEnd(state,
1870 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1871 : "\": Exhaust air temperature less than combustion air inlet temperature warning continues...",
1872 0 : this->ExhTempLTInletTempIndex,
1873 0 : this->ExhaustAirTemperature,
1874 0 : this->ExhaustAirTemperature);
1875 : }
1876 :
1877 8666 : if (this->ExhaustAirHumRat < CombustionAirInletW) {
1878 0 : if (this->ExhHRLTInletHRIndex == 0) {
1879 0 : ShowWarningMessage(state, format("GENERATOR:MICROTURBINE \"{}\"", this->Name));
1880 0 : ShowContinueError(
1881 : state, "...The model has calculated the exhaust air humidity ratio to be less than the combustion air inlet humidity ratio.");
1882 0 : ShowContinueError(state, format("...Value of exhaust air humidity ratio ={:.6T} kgWater/kgDryAir.", this->ExhaustAirHumRat));
1883 0 : ShowContinueError(state, format("...Value of combustion air inlet humidity ratio ={:.6T} kgWater/kgDryAir.", CombustionAirInletW));
1884 0 : ShowContinueErrorTimeStamp(state, "... Simulation will continue.");
1885 : }
1886 0 : ShowRecurringWarningErrorAtEnd(state,
1887 0 : "GENERATOR:MICROTURBINE \"" + this->Name +
1888 : "\": Exhaust air humidity ratio less than combustion air inlet humidity ratio warning continues...",
1889 0 : this->ExhHRLTInletHRIndex,
1890 0 : this->ExhaustAirHumRat,
1891 0 : this->ExhaustAirHumRat);
1892 : }
1893 : }
1894 : }
1895 :
1896 51343 : void MTGeneratorSpecs::UpdateMTGeneratorRecords(EnergyPlusData &state)
1897 : {
1898 : // SUBROUTINE INFORMATION:
1899 : // AUTHOR R. Raustad/D. Shirey
1900 : // DATE WRITTEN Mar 2008
1901 : // MODIFIED na
1902 : // RE-ENGINEERED na
1903 :
1904 : // PURPOSE OF THIS SUBROUTINE:
1905 : // Reporting and updating nodes if necessary.
1906 :
1907 51343 : if (this->HeatRecActive) {
1908 19272 : state.dataLoopNodes->Node(this->HeatRecOutletNodeNum).Temp = this->HeatRecOutletTemp;
1909 : }
1910 :
1911 51343 : if (this->ExhAirCalcsActive) {
1912 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
1913 27135 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRate = this->ExhaustAirMassFlowRate;
1914 :
1915 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).Temp = this->ExhaustAirTemperature;
1916 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).HumRat = this->ExhaustAirHumRat;
1917 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMaxAvail =
1918 27135 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMaxAvail;
1919 27135 : state.dataLoopNodes->Node(this->CombustionAirOutletNodeNum).MassFlowRateMinAvail =
1920 27135 : state.dataLoopNodes->Node(this->CombustionAirInletNodeNum).MassFlowRateMinAvail;
1921 : }
1922 :
1923 51343 : this->EnergyGen = this->ElecPowerGenerated * state.dataHVACGlobal->TimeStepSysSec;
1924 51343 : this->ExhaustEnergyRec = this->QHeatRecovered * state.dataHVACGlobal->TimeStepSysSec;
1925 51343 : this->FuelEnergyHHV = this->FuelEnergyUseRateHHV * state.dataHVACGlobal->TimeStepSysSec;
1926 51343 : if (this->FuelEnergyUseRateLHV > 0.0) {
1927 18465 : this->ElectricEfficiencyLHV = this->ElecPowerGenerated / this->FuelEnergyUseRateLHV;
1928 18465 : this->ThermalEfficiencyLHV = this->QHeatRecovered / this->FuelEnergyUseRateLHV;
1929 : } else {
1930 32878 : this->ElectricEfficiencyLHV = 0.0;
1931 32878 : this->ThermalEfficiencyLHV = 0.0;
1932 : }
1933 51343 : this->AncillaryEnergy = this->AncillaryPowerRate * state.dataHVACGlobal->TimeStepSysSec;
1934 51343 : this->StandbyEnergy = this->StandbyPowerRate * state.dataHVACGlobal->TimeStepSysSec;
1935 51343 : }
1936 51343 : void MTGeneratorSpecs::oneTimeInit(EnergyPlusData &state)
1937 : {
1938 :
1939 51343 : std::string const RoutineName("InitMTGenerators");
1940 : bool errFlag;
1941 :
1942 51343 : if (this->myFlag) {
1943 6 : this->setupOutputVars(state);
1944 6 : this->myFlag = false;
1945 : }
1946 :
1947 51343 : if (this->MyPlantScanFlag && allocated(state.dataPlnt->PlantLoop) && this->HeatRecActive) {
1948 2 : errFlag = false;
1949 4 : PlantUtilities::ScanPlantLoopsForObject(
1950 2 : state, this->Name, DataPlant::PlantEquipmentType::Generator_MicroTurbine, this->HRPlantLoc, errFlag, _, _, _, _, _);
1951 2 : if (errFlag) {
1952 0 : ShowFatalError(state, "InitMTGenerators: Program terminated due to previous condition(s).");
1953 : }
1954 :
1955 2 : this->MyPlantScanFlag = false;
1956 : }
1957 :
1958 51343 : if (this->MySizeAndNodeInitFlag && (!this->MyPlantScanFlag) && this->HeatRecActive) {
1959 :
1960 : // size mass flow rate
1961 4 : Real64 rho = FluidProperties::GetDensityGlycol(state,
1962 2 : state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidName,
1963 : Constant::InitConvTemp,
1964 2 : state.dataPlnt->PlantLoop(this->HRPlantLoc.loopNum).FluidIndex,
1965 : RoutineName);
1966 :
1967 2 : this->DesignHeatRecMassFlowRate = rho * this->RefHeatRecVolFlowRate;
1968 2 : this->HeatRecMaxMassFlowRate = rho * this->HeatRecMaxVolFlowRate;
1969 :
1970 2 : PlantUtilities::InitComponentNodes(state, 0.0, this->HeatRecMaxMassFlowRate, this->HeatRecInletNodeNum, this->HeatRecOutletNodeNum);
1971 :
1972 2 : this->MySizeAndNodeInitFlag = false;
1973 : }
1974 51343 : }
1975 :
1976 : } // namespace EnergyPlus::MicroturbineElectricGenerator
|