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