Line data Source code
1 : // EnergyPlus, Copyright (c) 1996-2025, The Board of Trustees of the University of Illinois,
2 : // The Regents of the University of California, through Lawrence Berkeley National Laboratory
3 : // (subject to receipt of any required approvals from the U.S. Dept. of Energy), Oak Ridge
4 : // National Laboratory, managed by UT-Battelle, Alliance for Sustainable Energy, LLC, and other
5 : // contributors. All rights reserved.
6 : //
7 : // NOTICE: This Software was developed under funding from the U.S. Department of Energy and the
8 : // U.S. Government consequently retains certain rights. As such, the U.S. Government has been
9 : // granted for itself and others acting on its behalf a paid-up, nonexclusive, irrevocable,
10 : // worldwide license in the Software to reproduce, distribute copies to the public, prepare
11 : // derivative works, and perform publicly and display publicly, and to permit others to do so.
12 : //
13 : // Redistribution and use in source and binary forms, with or without modification, are permitted
14 : // provided that the following conditions are met:
15 : //
16 : // (1) Redistributions of source code must retain the above copyright notice, this list of
17 : // conditions and the following disclaimer.
18 : //
19 : // (2) Redistributions in binary form must reproduce the above copyright notice, this list of
20 : // conditions and the following disclaimer in the documentation and/or other materials
21 : // provided with the distribution.
22 : //
23 : // (3) Neither the name of the University of California, Lawrence Berkeley National Laboratory,
24 : // the University of Illinois, U.S. Dept. of Energy nor the names of its contributors may be
25 : // used to endorse or promote products derived from this software without specific prior
26 : // written permission.
27 : //
28 : // (4) Use of EnergyPlus(TM) Name. If Licensee (i) distributes the software in stand-alone form
29 : // without changes from the version obtained under this License, or (ii) Licensee makes a
30 : // reference solely to the software portion of its product, Licensee must refer to the
31 : // software as "EnergyPlus version X" software, where "X" is the version number Licensee
32 : // obtained under this License and may not use a different name for the software. Except as
33 : // specifically required in this Section (4), Licensee shall not use in a company name, a
34 : // product name, in advertising, publicity, or other promotional activities any name, trade
35 : // name, trademark, logo, or other designation of "EnergyPlus", "E+", "e+" or confusingly
36 : // similar designation, without the U.S. Department of Energy's prior written consent.
37 : //
38 : // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
39 : // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
40 : // AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
41 : // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
42 : // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
43 : // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
44 : // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
45 : // OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
46 : // POSSIBILITY OF SUCH DAMAGE.
47 :
48 : // C++ Headers
49 : #include <cassert>
50 :
51 : // ObjexxFCL Headers
52 : #include <ObjexxFCL/Array.functions.hh>
53 : #include <ObjexxFCL/Fmath.hh>
54 : #include <ObjexxFCL/numeric.hh>
55 : #include <ObjexxFCL/string.functions.hh>
56 :
57 : // EnergyPlus Headers
58 : #include <EnergyPlus/CostEstimateManager.hh>
59 : #include <EnergyPlus/Data/EnergyPlusData.hh>
60 : #include <EnergyPlus/DataEnvironment.hh>
61 : #include <EnergyPlus/DataGlobalConstants.hh>
62 : #include <EnergyPlus/DataIPShortCuts.hh>
63 : #include <EnergyPlus/DisplayRoutines.hh>
64 : #include <EnergyPlus/EconomicTariff.hh>
65 : #include <EnergyPlus/General.hh>
66 : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
67 : #include <EnergyPlus/OutputProcessor.hh>
68 : #include <EnergyPlus/OutputReportPredefined.hh>
69 : #include <EnergyPlus/OutputReportTabular.hh>
70 : #include <EnergyPlus/ResultsFramework.hh>
71 : #include <EnergyPlus/SQLiteProcedures.hh>
72 : #include <EnergyPlus/ScheduleManager.hh>
73 : #include <EnergyPlus/UtilityRoutines.hh>
74 :
75 : namespace EnergyPlus::EconomicTariff {
76 :
77 : // MODULE INFORMATION:
78 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
79 : // DATE WRITTEN May 2004
80 :
81 : // Compute utility bills for a building based on energy
82 : // use estimate.
83 :
84 : constexpr std::array<std::string_view, (int)EconConv::Num> convEnergyStrings = {
85 : "", "kWh", "Therm", "MMBtu", "MJ", "kBTU", "MCF", "CCF", "m3", "gal", "kgal"};
86 : constexpr std::array<std::string_view, (int)EconConv::Num> convDemandStrings = {
87 : "", "kW", "Therm", "MMBtu", "MJ", "kBTU", "MCF", "CCF", "m3", "gal", "kgal"};
88 : constexpr std::array<std::string_view, (int)EconConv::Num> econConvNamesUC = {
89 : "USERDEFINED", "KWH", "THERM", "MMBTU", "MJ", "KBTU", "MCF", "CCF", "M3", "GAL", "KGAL"};
90 :
91 : constexpr std::array<std::string_view, (int)DemandWindow::Num> demandWindowStrings = {"/Hr", "/Hr", "/Hr", "/Day", "/Wk"};
92 :
93 : constexpr std::array<std::string_view, (int)BuySell::Num> buySellNames = {"BuyFromUtility", "SellToUtility", "NetMetering"};
94 : constexpr std::array<std::string_view, (int)BuySell::Num> buySellNamesUC = {"BUYFROMUTILITY", "SELLTOUTILITY", "NETMETERING"};
95 :
96 : constexpr std::array<std::string_view, (int)Season::Num> seasonNames = {"Unused", "Winter", "Spring", "Summer", "Fall", "Annual", "Monthly"};
97 : constexpr std::array<std::string_view, (int)Season::Num> seasonNamesUC = {"Unused", "WINTER", "SPRING", "SUMMER", "FALL", "ANNUAL", "MONTHLY"};
98 :
99 : constexpr std::array<std::string_view, (int)Op::Num> opNamesUC = {"SUM",
100 : "MULTIPLY",
101 : "SUBTRACT",
102 : "DIVIDE",
103 : "ABSOLUTE",
104 : "INTEGER",
105 : "SIGN",
106 : "ROUND",
107 : "MAXIMUM",
108 : "MINIMUM",
109 : "EXCEEDS",
110 : "ANNUALMINIMUM",
111 : "ANNUALMAXIMUM",
112 : "ANNUALSUM",
113 : "ANNUALAVERAGE",
114 : "ANNUALOR",
115 : "ANNUALAND",
116 : "ANNUALMAXIMUMZERO",
117 : "ANNUALMINIMUMZERO",
118 : "IF",
119 : "GREATERTHAN",
120 : "GREATEREQUAL",
121 : "LESSTHAN",
122 : "LESSEQUAL",
123 : "EQUAL",
124 : "NOTEQUAL",
125 : "AND",
126 : "OR",
127 : "NOT",
128 : "ADD",
129 : "FROM"};
130 :
131 : constexpr std::array<std::string_view, (int)Op::Num> opNames2UC = {
132 : "SUM", "MULT", "SUBT", "DIV", "ABS", "INT", "SIGN", "ROUND", "MAX", "MIN", "EXCEEDS", "ANMIN", "ANMAX", "ANSUM", "ANAVG", "ANOR",
133 : "ANAND", "ANMAXZ", "ANMINZ", "IF", "GT", "GE", "LT", "LE", "EQ", "NE", "AND", "OR", "NOT", "ADD", "NOOP"};
134 :
135 : constexpr std::array<std::string_view, (int)Cat::Num> catNames = {
136 : "EnergyCharges", "DemandCharges", "ServiceCharges", "Basis", "Adjustment", "Surcharge", "Subtotal", "Taxes", "Total", "NotIncluded"};
137 : constexpr std::array<std::string_view, (int)Cat::Num> catNamesUC = {
138 : "ENERGYCHARGES", "DEMANDCHARGES", "SERVICECHARGES", "BASIS", "ADJUSTMENT", "SURCHARGE", "SUBTOTAL", "TAXES", "TOTAL", "NOTINCLUDED"};
139 :
140 : constexpr std::array<std::string_view, (int)Native::Num> nativeNames = {"TotalEnergy",
141 : "TotalDemand",
142 : "PeakEnergy",
143 : "PeakDemand",
144 : "ShoulderEnergy",
145 : "ShoulderDemand",
146 : "OffPeakEnergy",
147 : "OffPeakDemand",
148 : "MidPeakEnergy",
149 : "MidPeakDemand",
150 : "PeakExceedsOffPeak",
151 : "OffPeakExceedsPeak",
152 : "PeakExceedsMidPeak",
153 : "MidPeakExceedsPeak",
154 : "PeakExceedsShoulder",
155 : "ShoulderExceedsPeak",
156 : "IsWinter",
157 : "IsNotWinter",
158 : "IsSpring",
159 : "IsNotSpring",
160 : "IsSummer",
161 : "IsNotSummer",
162 : "IsAutumn",
163 : "IsNotAutumn",
164 : "PeakAndShoulderEnergy",
165 : "PeakAndShoulderDemand",
166 : "PeakAndMidPeakEnergy",
167 : "PeakAndMidPeakDemand",
168 : "ShoulderAndOffPeakEnergy",
169 : "ShoulderAndOffPeakDemand",
170 : "PeakAndOffPeakEnergy",
171 : "PeakAndOffPeakDemand",
172 : "RealTimePriceCosts",
173 : "AboveCustomerBaseCosts",
174 : "BelowCustomerBaseCosts",
175 : "AboveCustomerBaseEnergy",
176 : "BelowCustomerBaseEnergy"};
177 : constexpr std::array<std::string_view, (int)Native::Num> nativeNamesUC = {"TOTALENERGY",
178 : "TOTALDEMAND",
179 : "PEAKENERGY",
180 : "PEAKDEMAND",
181 : "SHOULDERENERGY",
182 : "SHOULDERDEMAND",
183 : "OFFPEAKENERGY",
184 : "OFFPEAKDEMAND",
185 : "MIDPEAKENERGY",
186 : "MIDPEAKDEMAND",
187 : "PEAKEXCEEDSOFFPEAK",
188 : "OFFPEAKEXCEEDSPEAK",
189 : "PEAKEXCEEDSMIDPEAK",
190 : "MIDPEAKEXCEEDSPEAK",
191 : "PEAKEXCEEDSSHOULDER",
192 : "SHOULDEREXCEEDSPEAK",
193 : "ISWINTER",
194 : "ISNOTWINTER",
195 : "ISSPRING",
196 : "ISNOTSPRING",
197 : "ISSUMMER",
198 : "ISNOTSUMMER",
199 : "ISAUTUMN",
200 : "ISNOTAUTUMN",
201 : "PEAKANDSHOULDERENERGY",
202 : "PEAKANDSHOULDERDEMAND",
203 : "PEAKANDMIDPEAKENERGY",
204 : "PEAKANDMIDPEAKDEMAND",
205 : "SHOULDERANDOFFPEAKENERGY",
206 : "SHOULDERANDOFFPEAKDEMAND",
207 : "PEAKANDOFFPEAKENERGY",
208 : "PEAKANDOFFPEAKDEMAND",
209 : "REALTIMEPRICECOSTS",
210 : "ABOVECUSTOMERBASECOSTS",
211 : "BELOWCUSTOMERBASECOSTS",
212 : "ABOVECUSTOMERBASEENERGY",
213 : "BELOWCUSTOMERBASEENERGY"};
214 :
215 : constexpr std::array<std::string_view, (int)VarUnitType::Num> varUnitTypeNames = {"Energy", "Demand", "Dimensionless", "Currency"};
216 : constexpr std::array<std::string_view, (int)VarUnitType::Num> varUnitTypeNamesUC = {"ENERGY", "DEMAND", "DIMENSIONLESS", "CURRENCY"};
217 :
218 491880 : void UpdateUtilityBills(EnergyPlusData &state)
219 : {
220 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
221 : // DATE WRITTEN September 2003
222 :
223 : // Single routine used to call all get input
224 : // routines for economics.
225 :
226 491880 : auto &s_econ = state.dataEconTariff;
227 :
228 491880 : if (s_econ->Update_GetInput) {
229 799 : bool ErrorsFound = false;
230 :
231 799 : GetInputEconomicsTariff(state, ErrorsFound);
232 : // do rest of GetInput only if at least one tariff is defined.
233 799 : GetInputEconomicsCurrencyType(state, ErrorsFound);
234 799 : if (s_econ->numTariff >= 1) {
235 101 : if (!ErrorsFound && state.dataOutRptTab->displayEconomicResultSummary) {
236 128 : OutputReportTabular::AddTOCEntry(state, "Economics Results Summary Report", "Entire Facility");
237 : }
238 101 : CreateCategoryNativeVariables(state);
239 101 : GetInputEconomicsQualify(state, ErrorsFound);
240 101 : GetInputEconomicsChargeSimple(state, ErrorsFound);
241 101 : GetInputEconomicsChargeBlock(state, ErrorsFound);
242 101 : GetInputEconomicsRatchet(state, ErrorsFound);
243 101 : GetInputEconomicsVariable(state, ErrorsFound);
244 101 : GetInputEconomicsComputation(state, ErrorsFound);
245 101 : CreateDefaultComputation(state);
246 : }
247 799 : s_econ->Update_GetInput = false;
248 799 : if (ErrorsFound) {
249 0 : ShowFatalError(state, "UpdateUtilityBills: Preceding errors cause termination.");
250 : }
251 : }
252 491880 : if (state.dataGlobal->DoOutputReporting && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) {
253 254136 : GatherForEconomics(state);
254 : }
255 491880 : }
256 :
257 : //======================================================================================================================
258 : //======================================================================================================================
259 :
260 : // GET INPUT ROUTINES
261 :
262 : //======================================================================================================================
263 : //======================================================================================================================
264 :
265 799 : void GetInputEconomicsTariff(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
266 : {
267 : // SUBROUTINE INFORMATION:
268 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
269 : // DATE WRITTEN May 2004
270 : // MODIFIED Aug. 2017, Julien Marrec of EffiBEM. Handled conversions factor based on meter resources
271 : //
272 : // PURPOSE OF THIS SUBROUTINE:
273 : // This subroutine reads the input file for "UtilityCost:Tariff" objects
274 : // It will be the right conversion factors based on the associated meter resource type
275 : // meaning if "CCF" is picked, the conversion factor isn't the same whether it's a water meter or a fuel meter.
276 :
277 : static constexpr std::string_view RoutineName("GetInputEconomicsTariff: ");
278 : static constexpr std::string_view routineName = "GetInputEconomicsTariff";
279 :
280 : int NumAlphas; // Number of elements in the alpha array
281 : int NumNums; // Number of elements in the numeric array
282 : int IOStat; // IO Status when calling get input subroutine
283 : bool isNotNumeric;
284 : // variables for getting report variable/meter index
285 : int KeyCount;
286 : OutputProcessor::VariableType TypeVar;
287 : OutputProcessor::StoreType AvgSumVar;
288 : OutputProcessor::TimeStepType StepTypeVar;
289 799 : Constant::Units UnitsVar = Constant::Units::None; // Units sting, may be blank
290 799 : Array1D_string NamesOfKeys; // Specific key name
291 799 : Array1D_int IndexesForKeyVar; // Array index
292 :
293 799 : auto &s_ipsc = state.dataIPShortCut;
294 799 : auto &s_econ = state.dataEconTariff;
295 :
296 799 : std::string_view CurrentModuleObject = "UtilityCost:Tariff";
297 799 : s_econ->numTariff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
298 799 : s_econ->tariff.allocate(s_econ->numTariff);
299 1100 : for (int iInObj = 1; iInObj <= s_econ->numTariff; ++iInObj) {
300 602 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
301 : CurrentModuleObject,
302 : iInObj,
303 301 : s_ipsc->cAlphaArgs,
304 : NumAlphas,
305 301 : s_ipsc->rNumericArgs,
306 : NumNums,
307 : IOStat,
308 301 : s_ipsc->lNumericFieldBlanks,
309 301 : s_ipsc->lAlphaFieldBlanks,
310 301 : s_ipsc->cAlphaFieldNames,
311 301 : s_ipsc->cNumericFieldNames);
312 :
313 301 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
314 301 : auto &tariff = s_econ->tariff(iInObj);
315 :
316 : // check to make sure none of the values are another economic object
317 3802 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
318 : // args are always turned to upper case but this is okay...
319 3501 : if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
320 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
321 0 : ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
322 : }
323 : }
324 : // name of the tariff
325 301 : tariff.tariffName = s_ipsc->cAlphaArgs(1);
326 : // check if tariff name is unique
327 301 : int found = 0;
328 704 : for (int jObj = 1; jObj <= iInObj - 1; ++jObj) {
329 403 : if (tariff.tariffName == s_econ->tariff(jObj).tariffName) {
330 0 : found = jObj;
331 0 : break;
332 : }
333 : }
334 301 : if (found > 0) {
335 0 : ShowSevereDuplicateName(state, eoh);
336 0 : ErrorsFound = true;
337 : }
338 : // name of the report meter
339 301 : tariff.reportMeter = s_ipsc->cAlphaArgs(2);
340 : // call the key count function but only need count during this pass
341 301 : GetVariableKeyCountandType(state, tariff.reportMeter, KeyCount, TypeVar, AvgSumVar, StepTypeVar, UnitsVar);
342 : // if no meters found for that name
343 301 : if (KeyCount == 0) {
344 1 : ShowWarningError(state, format("{}{}=\"{}\" missing meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
345 2 : ShowContinueError(
346 : state,
347 2 : format("Meter referenced is not present due to a lack of equipment that uses that energy source/meter:\"{}\".", tariff.reportMeter));
348 1 : tariff.reportMeterIndx = -1;
349 : } else {
350 300 : NamesOfKeys.allocate(KeyCount);
351 300 : IndexesForKeyVar.allocate(KeyCount);
352 300 : GetVariableKeys(state, tariff.reportMeter, TypeVar, NamesOfKeys, IndexesForKeyVar);
353 : // although this retrieves all keys for a variable, we only need one so the first one is chosen
354 300 : if (KeyCount > 1) {
355 0 : ShowWarningError(state, format("{}{}=\"{}\" multiple keys", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
356 0 : ShowContinueError(state, "... Multiple keys for variable select. First key will be used.");
357 : }
358 : // assign the index
359 300 : tariff.reportMeterIndx = IndexesForKeyVar(1);
360 : // get rid of the arrays used to get the variable number
361 300 : NamesOfKeys.deallocate();
362 300 : IndexesForKeyVar.deallocate();
363 : }
364 :
365 : // Start by checking what type of meter we do have, some units can be used for several resources with different conversion factors
366 : // Explicitly assume it's not a water meter nor an electric meter nor a gas meter (was already done in constructor though)
367 301 : tariff.kindMtr = MeterType::Other;
368 :
369 : // Determine whether this meter is related to electricity, or water, or gas
370 301 : if (tariff.reportMeterIndx != -1) {
371 300 : switch (state.dataOutputProcessor->meters[tariff.reportMeterIndx]->resource) {
372 : // Various types of electricity meters
373 195 : case Constant::eResource::Electricity: {
374 195 : tariff.kindMtr = MeterType::ElecSimple;
375 195 : } break;
376 0 : case Constant::eResource::ElectricityProduced: {
377 0 : tariff.kindMtr = MeterType::ElecProduced;
378 0 : } break;
379 11 : case Constant::eResource::ElectricityPurchased: {
380 11 : tariff.kindMtr = MeterType::ElecPurchased;
381 11 : } break;
382 1 : case Constant::eResource::ElectricitySurplusSold: {
383 1 : tariff.kindMtr = MeterType::ElecSurplusSold;
384 1 : } break;
385 7 : case Constant::eResource::ElectricityNet: {
386 7 : tariff.kindMtr = MeterType::ElecNet;
387 7 : } break;
388 : // Handle the case where its a water meter
389 1 : case Constant::eResource::Water:
390 : case Constant::eResource::OnSiteWater:
391 : case Constant::eResource::MainsWater:
392 : case Constant::eResource::RainWater:
393 : case Constant::eResource::WellWater:
394 : case Constant::eResource::Condensate: {
395 1 : tariff.kindMtr = MeterType::Water;
396 1 : } break;
397 : // Or a Natural Gas meter
398 85 : case Constant::eResource::NaturalGas: {
399 85 : tariff.kindMtr = MeterType::Gas;
400 85 : } break;
401 0 : default: {
402 0 : tariff.kindMtr = MeterType::Other; // Do or assert something here?
403 0 : } break;
404 : } // switch
405 : }
406 :
407 : // Assign the right conversion factors based on the resource type
408 :
409 : // If it's a water meter
410 : // We set demandConv to something analogous to m3/h
411 301 : switch (tariff.kindMtr) {
412 1 : case MeterType::Water: {
413 : // conversion factor
414 1 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
415 1 : switch (tariff.convChoice) {
416 1 : case EconConv::USERDEF: {
417 1 : tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
418 1 : tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
419 1 : } break;
420 :
421 0 : case EconConv::M3: {
422 0 : tariff.energyConv = 1.0;
423 0 : tariff.demandConv = 3600.0;
424 0 : } break;
425 :
426 0 : case EconConv::CCF: {
427 0 : tariff.energyConv = 0.35314666721488586;
428 0 : tariff.demandConv = 0.35314666721488586 * 3600;
429 0 : } break;
430 :
431 0 : case EconConv::GAL: {
432 0 : tariff.energyConv = 264.1720523602524;
433 0 : tariff.demandConv = 264.1720523602524 * 3600;
434 0 : } break;
435 :
436 0 : case EconConv::KGAL: {
437 0 : tariff.energyConv = 0.2641720523602524;
438 0 : tariff.demandConv = 0.2641720523602524 * 3600;
439 0 : } break;
440 :
441 0 : default: { // ERROR: not a valid conversion, default to M3
442 0 : tariff.convChoice = EconConv::M3;
443 0 : tariff.energyConv = 1.0;
444 0 : tariff.demandConv = 3600.0;
445 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "M3");
446 0 : } break;
447 : } // switch (tariff.convChoice)
448 :
449 1 : } break;
450 :
451 : // If it's an electric meter
452 : // Volumetric units such as MCF or CCF doesn't make sense IMHO (JM)
453 : // THERM is strange for an electric meter but currently I accept but issue a warning
454 214 : case MeterType::ElecSimple:
455 : case MeterType::ElecProduced:
456 : case MeterType::ElecPurchased:
457 : case MeterType::ElecSurplusSold:
458 : case MeterType::ElecNet: {
459 214 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
460 :
461 214 : switch (tariff.convChoice) {
462 0 : case EconConv::USERDEF: {
463 0 : tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
464 0 : tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
465 0 : } break;
466 :
467 214 : case EconConv::KWH: {
468 214 : tariff.energyConv = 0.0000002778;
469 214 : tariff.demandConv = 0.001;
470 214 : } break;
471 :
472 0 : case EconConv::MJ: {
473 0 : tariff.energyConv = 0.000001;
474 0 : tariff.demandConv = 0.0036;
475 0 : } break;
476 :
477 0 : case EconConv::MMBTU: {
478 0 : tariff.energyConv = 9.4781712e-10;
479 0 : tariff.demandConv = 0.000003412;
480 0 : } break;
481 :
482 0 : case EconConv::KBTU: {
483 0 : tariff.energyConv = 9.4781712e-7;
484 0 : tariff.demandConv = 0.003412;
485 0 : } break;
486 :
487 : // We accept the following choices, but issue a warning
488 0 : case EconConv::THERM: {
489 0 : tariff.energyConv = 9.4781712e-9;
490 0 : tariff.demandConv = 0.00003412;
491 0 : ShowWarningCustom(
492 : state,
493 : eoh,
494 0 : format("{}=\"{}\", Therm is an unusual choice for an electric resource.", s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3)));
495 0 : } break;
496 :
497 : // Otherwise, default to kWh
498 0 : default: {
499 0 : tariff.convChoice = EconConv::KWH;
500 0 : tariff.energyConv = 0.0000002778;
501 0 : tariff.demandConv = 0.001;
502 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
503 0 : } break;
504 : } // switch (tariff.convChoice)
505 214 : } break;
506 :
507 : // If it's a gas meter
508 85 : case MeterType::Gas: {
509 85 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
510 85 : switch (tariff.convChoice) {
511 0 : case EconConv::USERDEF: {
512 0 : tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
513 0 : tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
514 0 : } break;
515 :
516 0 : case EconConv::KWH: {
517 0 : tariff.energyConv = 0.0000002778;
518 0 : tariff.demandConv = 0.001;
519 0 : } break;
520 :
521 1 : case EconConv::THERM: {
522 1 : tariff.energyConv = 9.4781712e-9;
523 1 : tariff.demandConv = 0.00003412;
524 1 : } break;
525 :
526 0 : case EconConv::MMBTU: {
527 0 : tariff.energyConv = 9.4781712e-10;
528 0 : tariff.demandConv = 0.000003412;
529 0 : } break;
530 :
531 0 : case EconConv::MJ: {
532 0 : tariff.energyConv = 0.000001;
533 0 : tariff.demandConv = 0.0036;
534 0 : } break;
535 :
536 0 : case EconConv::KBTU: {
537 0 : tariff.energyConv = 9.4781712e-7;
538 0 : tariff.demandConv = 0.003412;
539 0 : } break;
540 : // Volumetric units for natural gas
541 : // Actually assuming 1 therm = 1 CCF (= 100 ft^3)
542 84 : case EconConv::MCF: {
543 84 : tariff.energyConv = 9.4781712e-10;
544 84 : tariff.demandConv = 0.000003412;
545 84 : } break;
546 :
547 0 : case EconConv::CCF: {
548 0 : tariff.energyConv = 9.4781712e-9;
549 0 : tariff.demandConv = 0.00003412;
550 0 : } break;
551 :
552 : // Obtained from converting CCF above to m^3 so the same heat content of natural gas is used (1 therm = 1 CCF)
553 0 : case EconConv::M3: {
554 0 : tariff.energyConv = 2.6839192e-10;
555 0 : tariff.demandConv = 9.6617081E-05;
556 0 : } break;
557 :
558 : // Otherwise, default to kWh
559 0 : default: {
560 0 : tariff.convChoice = EconConv::KWH;
561 0 : tariff.energyConv = 0.0000002778;
562 0 : tariff.demandConv = 0.001;
563 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
564 0 : } break;
565 : } // witch (tariff.convChoice)
566 85 : } break;
567 :
568 : // It it's neither an electric, water or gas meter, we cannot accept volumetric units
569 : // because we cannot infer the heat content
570 1 : case MeterType::Other: {
571 1 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
572 1 : switch (tariff.convChoice) {
573 0 : case EconConv::USERDEF: {
574 0 : tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
575 0 : tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
576 0 : } break;
577 :
578 0 : case EconConv::KWH: {
579 0 : tariff.energyConv = 0.0000002778;
580 0 : tariff.demandConv = 0.001;
581 0 : } break;
582 :
583 0 : case EconConv::THERM: {
584 0 : tariff.energyConv = 9.4781712e-9;
585 0 : tariff.demandConv = 0.00003412;
586 0 : } break;
587 :
588 0 : case EconConv::MMBTU: {
589 0 : tariff.energyConv = 9.4781712e-10;
590 0 : tariff.demandConv = 0.000003412;
591 0 : } break;
592 :
593 0 : case EconConv::MJ: {
594 0 : tariff.energyConv = 0.000001;
595 0 : tariff.demandConv = 0.0036;
596 0 : } break;
597 :
598 0 : case EconConv::KBTU: {
599 0 : tariff.energyConv = 9.4781712e-7;
600 0 : tariff.demandConv = 0.003412;
601 0 : } break;
602 :
603 : // Otherwise, default to kWh
604 1 : default: {
605 1 : tariff.convChoice = EconConv::KWH;
606 1 : tariff.energyConv = 0.0000002778;
607 1 : tariff.demandConv = 0.001;
608 1 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
609 1 : } break;
610 : } // switch (tariff.convChoice)
611 1 : } break;
612 :
613 0 : default: {
614 0 : } break;
615 : } // Default conversion factors have been applied from here on
616 :
617 : // schedules
618 : // period schedule
619 301 : if (len(s_ipsc->cAlphaArgs(4)) > 0) {
620 15 : if ((tariff.periodSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(4))) == nullptr) {
621 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4));
622 0 : ErrorsFound = true;
623 : }
624 : }
625 :
626 : // season schedule
627 301 : if (len(s_ipsc->cAlphaArgs(5)) > 0) {
628 31 : if ((tariff.seasonSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(5))) == nullptr) {
629 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5));
630 0 : ErrorsFound = true;
631 : }
632 : }
633 :
634 : // month schedule
635 301 : if (len(s_ipsc->cAlphaArgs(6)) > 0) {
636 0 : if ((tariff.monthSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(6))) == nullptr) {
637 0 : ShowSevereItemNotFound(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6));
638 0 : ErrorsFound = true;
639 : }
640 : }
641 : // type of demand window
642 301 : if (Util::SameString(s_ipsc->cAlphaArgs(7), "QuarterHour")) {
643 : // check to make sure that the demand window and the TIMESTEP IN HOUR are consistent.
644 : { // Why is this a nested scope?
645 1 : switch (state.dataGlobal->TimeStepsInHour) {
646 0 : case 1:
647 : case 3:
648 : case 5:
649 : case 15: {
650 0 : tariff.demandWindow = DemandWindow::Hour;
651 0 : tariff.demWinTime = 1.00;
652 0 : ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
653 0 : ShowContinueError(state,
654 0 : format("Demand window of QuarterHour is not consistent with number of timesteps per hour [{}].",
655 0 : state.dataGlobal->TimeStepsInHour));
656 0 : ShowContinueError(state, "Demand window will be set to FullHour, and the simulation continues.");
657 0 : } break;
658 0 : case 2:
659 : case 6:
660 : case 10:
661 : case 30: {
662 0 : tariff.demandWindow = DemandWindow::Half;
663 0 : tariff.demWinTime = 0.50;
664 0 : ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
665 0 : ShowContinueError(state,
666 0 : format("Demand window of QuarterHour is not consistent with number of timesteps per hour [{}].",
667 0 : state.dataGlobal->TimeStepsInHour));
668 0 : ShowContinueError(state, "Demand window will be set to HalfHour, and the simulation continues.");
669 0 : } break;
670 1 : case 4:
671 : case 12:
672 : case 20:
673 : case 60: {
674 1 : tariff.demandWindow = DemandWindow::Quarter;
675 1 : tariff.demWinTime = 0.25;
676 1 : } break;
677 0 : default: {
678 0 : assert(false);
679 : } break;
680 : }
681 : }
682 300 : } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "HalfHour")) {
683 : {
684 111 : switch (state.dataGlobal->TimeStepsInHour) {
685 0 : case 1:
686 : case 3:
687 : case 5:
688 : case 15: {
689 0 : tariff.demandWindow = DemandWindow::Hour;
690 0 : tariff.demWinTime = 1.00;
691 0 : ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
692 0 : ShowContinueError(state,
693 0 : format("Demand window of HalfHour is not consistent with number of timesteps per hour [{}].",
694 0 : state.dataGlobal->TimeStepsInHour));
695 0 : ShowContinueError(state, "Demand window will be set to FullHour, and the simulation continues.");
696 0 : } break;
697 111 : case 2:
698 : case 4:
699 : case 6:
700 : case 10:
701 : case 12:
702 : case 20:
703 : case 30:
704 : case 60: {
705 111 : tariff.demandWindow = DemandWindow::Half;
706 111 : tariff.demWinTime = 0.50;
707 111 : } break;
708 0 : default: {
709 : // assert(false); // EconomicTariff unit test gets here with NumOfTimeStepInHour == 0
710 0 : } break;
711 : }
712 : }
713 189 : } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "FullHour")) {
714 0 : tariff.demandWindow = DemandWindow::Hour;
715 0 : tariff.demWinTime = 1.00;
716 189 : } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "Day")) {
717 0 : tariff.demandWindow = DemandWindow::Day;
718 0 : tariff.demWinTime = 24.00;
719 189 : } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "Week")) {
720 0 : tariff.demandWindow = DemandWindow::Week;
721 0 : tariff.demWinTime = 24.0 * 7.0;
722 : } else {
723 : // if not entered default to the same logic as quarter of an hour
724 : {
725 189 : switch (state.dataGlobal->TimeStepsInHour) {
726 0 : case 1:
727 : case 3:
728 : case 5:
729 : case 15: {
730 0 : tariff.demandWindow = DemandWindow::Hour;
731 0 : tariff.demWinTime = 1.00;
732 0 : } break;
733 116 : case 2:
734 : case 6:
735 : case 10:
736 : case 30: {
737 116 : tariff.demandWindow = DemandWindow::Half;
738 116 : tariff.demWinTime = 0.50;
739 116 : } break;
740 73 : case 4:
741 : case 12:
742 : case 20:
743 : case 60: {
744 73 : tariff.demandWindow = DemandWindow::Quarter;
745 73 : tariff.demWinTime = 0.25;
746 73 : } break;
747 0 : default: {
748 : // assert(false); // EconomicTariff unit test got here with NumOfTimeStepInHour == 0
749 0 : } break;
750 : }
751 : }
752 : }
753 : // monthly charge
754 301 : tariff.monthChgVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(8), isNotNumeric);
755 301 : tariff.monthChgPt =
756 301 : AssignVariablePt(state, s_ipsc->cAlphaArgs(8), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, iInObj);
757 : // minimum monthly charge
758 301 : if (len(s_ipsc->cAlphaArgs(9)) > 0) {
759 2 : tariff.minMonthChgVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(9), isNotNumeric);
760 : } else {
761 299 : tariff.minMonthChgVal = -HUGE_(-1.0); // set to a very negative value
762 : }
763 301 : tariff.minMonthChgPt =
764 301 : AssignVariablePt(state, s_ipsc->cAlphaArgs(9), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, iInObj);
765 : // real time pricing
766 301 : tariff.chargeSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(10));
767 301 : tariff.baseUseSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(11));
768 : // group name for separate distribution and transmission rates
769 301 : tariff.groupName = s_ipsc->cAlphaArgs(12);
770 : // buy or sell option
771 :
772 301 : if (s_ipsc->lAlphaFieldBlanks(13)) {
773 298 : tariff.buyOrSell = BuySell::BuyFromUtility;
774 3 : } else if ((tariff.buyOrSell = static_cast<BuySell>(getEnumValue(buySellNamesUC, s_ipsc->cAlphaArgs(13)))) == BuySell::Invalid) {
775 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(13), s_ipsc->cAlphaArgs(13));
776 0 : ErrorsFound = true;
777 : }
778 :
779 : // check if meter is consistent with buy or sell option
780 301 : if (tariff.buyOrSell == BuySell::SellToUtility) {
781 1 : if (!Util::SameString(tariff.reportMeter, "ELECTRICITYSURPLUSSOLD:FACILITY")) {
782 0 : ShowWarningError(state, format("{}{}=\"{}\" atypical meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
783 0 : ShowContinueError(state, format("The meter chosen \"{}\" is not typically used with the sellToUtility option.", tariff.reportMeter));
784 0 : ShowContinueError(state, "Usually the ElectricitySurplusSold:Facility meter is selected when the sellToUtility option is used.");
785 : }
786 300 : } else if (tariff.buyOrSell == BuySell::NetMetering) {
787 1 : if (!Util::SameString(tariff.reportMeter, "ELECTRICITYNET:FACILITY")) {
788 0 : ShowWarningError(state, format("{}{}=\"{}\" atypical meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
789 0 : ShowContinueError(state, format("The meter chosen \"{}\" is not typically used with the netMetering option.", tariff.reportMeter));
790 0 : ShowContinueError(state, "Usually the ElectricityNet:Facility meter is selected when the netMetering option is used.");
791 : }
792 299 : } else if (tariff.buyOrSell == BuySell::BuyFromUtility) {
793 299 : if (hasi(tariff.reportMeter, "Elec")) { // test if electric meter
794 229 : if (!(Util::SameString(tariff.reportMeter, "Electricity:Facility") ||
795 229 : Util::SameString(tariff.reportMeter, "ElectricityPurchased:Facility"))) {
796 6 : ShowWarningError(state, format("{}{}=\"{}\" atypical meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
797 12 : ShowContinueError(state,
798 12 : format("The meter chosen \"{}\" is not typically used with the buyFromUtility option.", tariff.reportMeter));
799 18 : ShowContinueError(state,
800 : "Usually the Electricity:Facility meter or the ElectricityPurchased:Facility is selected when the "
801 : "buyFromUtility option is used.");
802 : }
803 : }
804 : }
805 :
806 : // initialize gathering arrays
807 3913 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
808 3612 : tariff.seasonForMonth(kMonth) = Season::Invalid;
809 21672 : for (int lPeriod = 0; lPeriod < (int)Period::Num; ++lPeriod) {
810 18060 : tariff.gatherEnergy(kMonth)[lPeriod] = 0.0;
811 18060 : tariff.gatherDemand(kMonth)[lPeriod] = 0.0;
812 : }
813 : }
814 :
815 : // assume that the tariff is qualified
816 301 : tariff.isQualified = true;
817 301 : tariff.ptDisqualifier = 0;
818 : // assume that the tariff is not selected
819 301 : tariff.isSelected = false;
820 301 : tariff.totalAnnualCost = 0.0;
821 : // now create the Table Of Contents entries for an HTML file
822 301 : if (state.dataOutRptTab->displayTariffReport) {
823 282 : OutputReportTabular::AddTOCEntry(state, "Tariff Report", tariff.tariffName);
824 : }
825 : // associate the resource number with each tariff
826 301 : if (tariff.reportMeterIndx != -1) {
827 300 : tariff.resource = state.dataOutputProcessor->meters[tariff.reportMeterIndx]->resource;
828 : }
829 : }
830 799 : }
831 :
832 101 : void GetInputEconomicsQualify(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
833 : {
834 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
835 : // DATE WRITTEN May 2004
836 :
837 : // Read the input file for "Economics:Qualify" objects.
838 :
839 : static constexpr std::string_view RoutineName("GetInputEconomicsQualify: ");
840 : static constexpr std::string_view routineName = "GetInputEconomicsQualify";
841 :
842 : int iInObj; // loop index variable for reading in objects
843 : int NumAlphas; // Number of elements in the alpha array
844 : int NumNums; // Number of elements in the numeric array
845 : int IOStat; // IO Status when calling get input subroutine
846 : bool isNotNumeric;
847 : int jFld;
848 :
849 101 : auto &s_econ = state.dataEconTariff;
850 101 : auto &s_ipsc = state.dataIPShortCut;
851 :
852 101 : s_ipsc->cCurrentModuleObject = "UtilityCost:Qualify";
853 101 : s_econ->numQualify = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
854 101 : s_econ->qualify.allocate(s_econ->numQualify);
855 :
856 319 : for (iInObj = 1; iInObj <= s_econ->numQualify; ++iInObj) {
857 436 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
858 218 : s_ipsc->cCurrentModuleObject,
859 : iInObj,
860 218 : s_ipsc->cAlphaArgs,
861 : NumAlphas,
862 218 : s_ipsc->rNumericArgs,
863 : NumNums,
864 : IOStat,
865 218 : s_ipsc->lNumericFieldBlanks,
866 218 : s_ipsc->lAlphaFieldBlanks,
867 218 : s_ipsc->cAlphaFieldNames,
868 218 : s_ipsc->cNumericFieldNames);
869 :
870 218 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
871 :
872 218 : auto &qualify = s_econ->qualify(iInObj);
873 :
874 : // check to make sure none of the values are another economic object
875 1744 : for (jFld = 1; jFld <= NumAlphas; ++jFld) {
876 1526 : if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
877 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
878 0 : ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
879 : }
880 : }
881 : // index of the tariff name in the tariff array
882 218 : qualify.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
883 218 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), qualify.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
884 218 : qualify.namePt =
885 218 : AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::Qualify, iInObj, qualify.tariffIndx);
886 : // index of the variable in the variable array
887 218 : qualify.sourcePt =
888 218 : AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, qualify.tariffIndx);
889 : // indicator if maximum test otherwise minimum
890 218 : if (s_ipsc->cAlphaArgs(4) == "MINIMUM") {
891 110 : qualify.isMaximum = false;
892 108 : } else if (s_ipsc->cAlphaArgs(4) == "MAXIMUM") {
893 108 : qualify.isMaximum = true;
894 : } else {
895 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4), "Maximum");
896 0 : qualify.isMaximum = true;
897 : }
898 : // value of the threshold
899 218 : qualify.thresholdVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(5), isNotNumeric);
900 218 : qualify.thresholdPt =
901 218 : AssignVariablePt(state, s_ipsc->cAlphaArgs(5), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, qualify.tariffIndx);
902 : // enumerated list of the kind of season
903 218 : if ((qualify.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(6)))) == Season::Invalid) {
904 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(6), "Annual");
905 0 : qualify.season = Season::Annual;
906 : }
907 :
908 : // indicator if consecutive months otherwise count
909 218 : if (s_ipsc->cAlphaArgs(7) == "COUNT") {
910 218 : qualify.isConsecutive = false;
911 0 : } else if (s_ipsc->cAlphaArgs(7) == "CONSECUTIVE") {
912 0 : qualify.isConsecutive = true;
913 : } else {
914 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), "Consecutive");
915 0 : qualify.isConsecutive = true;
916 : }
917 : // number of months the test must be good for
918 218 : qualify.numberOfMonths = s_ipsc->rNumericArgs(1);
919 : }
920 101 : }
921 :
922 101 : void GetInputEconomicsChargeSimple(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
923 : {
924 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
925 : // DATE WRITTEN May 2004
926 :
927 : // Read the input file for "Economics:Charge:Simple" objects.
928 :
929 : static constexpr std::string_view RoutineName("GetInputEconomicsChargeSimple: ");
930 : static constexpr std::string_view routineName = "GetInputEconomicsChargeSimple";
931 : int NumAlphas; // Number of elements in the alpha array
932 : int NumNums; // Number of elements in the numeric array
933 : int IOStat; // IO Status when calling get input subroutine
934 : bool isNotNumeric;
935 :
936 101 : auto &s_econ = state.dataEconTariff;
937 101 : auto &s_ipsc = state.dataIPShortCut;
938 101 : s_ipsc->cCurrentModuleObject = "UtilityCost:Charge:Simple";
939 :
940 101 : s_econ->numChargeSimple = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
941 101 : s_econ->chargeSimple.allocate(s_econ->numChargeSimple);
942 1715 : for (int iInObj = 1; iInObj <= s_econ->numChargeSimple; ++iInObj) {
943 1614 : auto &chargeSimple = s_econ->chargeSimple(iInObj);
944 3228 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
945 1614 : s_ipsc->cCurrentModuleObject,
946 : iInObj,
947 1614 : s_ipsc->cAlphaArgs,
948 : NumAlphas,
949 1614 : s_ipsc->rNumericArgs,
950 : NumNums,
951 : IOStat,
952 1614 : s_ipsc->lNumericFieldBlanks,
953 1614 : s_ipsc->lAlphaFieldBlanks,
954 1614 : s_ipsc->cAlphaFieldNames,
955 1614 : s_ipsc->cNumericFieldNames);
956 :
957 1614 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
958 :
959 : // check to make sure none of the values are another economic object
960 11298 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
961 9684 : if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
962 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
963 0 : ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
964 : }
965 : }
966 : // index of the tariff name in the tariff array
967 1614 : chargeSimple.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
968 1614 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), chargeSimple.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
969 1614 : chargeSimple.namePt = AssignVariablePt(
970 1614 : state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::ChargeSimple, iInObj, chargeSimple.tariffIndx);
971 : // index of the variable in the variable array
972 1614 : chargeSimple.sourcePt =
973 1614 : AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeSimple.tariffIndx);
974 : // enumerated list of the kind of season
975 1614 : chargeSimple.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(4)));
976 1614 : if (chargeSimple.season == Season::Invalid) {
977 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4), "Annual");
978 0 : chargeSimple.season = Season::Annual;
979 : }
980 :
981 : // check to make sure a seasonal schedule is specified if the season is not annual
982 1614 : if (chargeSimple.season != Season::Annual) {
983 147 : if (chargeSimple.tariffIndx != 0) {
984 147 : if (s_econ->tariff(chargeSimple.tariffIndx).seasonSched == nullptr) {
985 0 : ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
986 0 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
987 0 : ShowContinueError(state,
988 : " a Season other than Annual is used but no Season Schedule Name is specified in the UtilityCost:Tariff.");
989 : }
990 : }
991 : }
992 : // index of the category in the variable array
993 1614 : chargeSimple.categoryPt =
994 1614 : AssignVariablePt(state, s_ipsc->cAlphaArgs(5), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeSimple.tariffIndx);
995 : // cost per unit value or variable
996 1614 : chargeSimple.costPerVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(6), isNotNumeric);
997 1614 : chargeSimple.costPerPt = AssignVariablePt(
998 1614 : state, s_ipsc->cAlphaArgs(6), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeSimple.tariffIndx);
999 : }
1000 101 : }
1001 :
1002 101 : void GetInputEconomicsChargeBlock(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
1003 : {
1004 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1005 : // DATE WRITTEN May 2004
1006 :
1007 : // Read the input file for "Economics:Charge:Block" objects.
1008 :
1009 : static constexpr std::string_view RoutineName("GetInputEconomicsChargeBlock: ");
1010 : static constexpr std::string_view routineName = "GetInputEconomicsChargeBlock";
1011 :
1012 : int NumAlphas; // Number of elements in the alpha array
1013 : int NumNums; // Number of elements in the numeric array
1014 : int IOStat; // IO Status when calling get input subroutine
1015 : bool isNotNumeric;
1016 : int alphaOffset; // offset used in blocks for alpha array
1017 101 : Real64 hugeNumber(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
1018 :
1019 101 : auto &s_econ = state.dataEconTariff;
1020 101 : auto &s_ipsc = state.dataIPShortCut;
1021 101 : s_ipsc->cCurrentModuleObject = "UtilityCost:Charge:Block";
1022 :
1023 101 : hugeNumber = HUGE_(hugeNumber);
1024 101 : s_econ->numChargeBlock = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1025 101 : s_econ->chargeBlock.allocate(s_econ->numChargeBlock);
1026 386 : for (int iInObj = 1; iInObj <= s_econ->numChargeBlock; ++iInObj) {
1027 285 : auto &chargeBlock = s_econ->chargeBlock(iInObj);
1028 570 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1029 285 : s_ipsc->cCurrentModuleObject,
1030 : iInObj,
1031 285 : s_ipsc->cAlphaArgs,
1032 : NumAlphas,
1033 285 : s_ipsc->rNumericArgs,
1034 : NumNums,
1035 : IOStat,
1036 285 : s_ipsc->lNumericFieldBlanks,
1037 285 : s_ipsc->lAlphaFieldBlanks,
1038 285 : s_ipsc->cAlphaFieldNames,
1039 285 : s_ipsc->cNumericFieldNames);
1040 :
1041 285 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1042 :
1043 : // check to make sure none of the values are another economic object
1044 4178 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
1045 3893 : if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
1046 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1047 0 : ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
1048 : }
1049 : }
1050 : // index of the tariff name in the tariff array
1051 285 : chargeBlock.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
1052 285 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), chargeBlock.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
1053 285 : chargeBlock.namePt = AssignVariablePt(
1054 285 : state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::ChargeBlock, iInObj, chargeBlock.tariffIndx);
1055 : // index of the variable in the variable array
1056 285 : chargeBlock.sourcePt =
1057 285 : AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeBlock.tariffIndx);
1058 : // enumerated list of the kind of season
1059 285 : chargeBlock.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(4)));
1060 285 : if (chargeBlock.season == Season::Invalid) {
1061 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4), "Annual");
1062 0 : chargeBlock.season = Season::Annual;
1063 : }
1064 :
1065 : // check to make sure a seasonal schedule is specified if the season is not annual
1066 285 : if (chargeBlock.season != Season::Annual) {
1067 27 : if (chargeBlock.tariffIndx != 0) {
1068 27 : if (s_econ->tariff(chargeBlock.tariffIndx).seasonSched == nullptr) {
1069 0 : ShowWarningError(state, format("{}{}=\"{}\" invalid data", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1070 0 : ShowContinueError(state, format("{}=\"{}\".", s_ipsc->cAlphaFieldNames(4), s_ipsc->cAlphaArgs(4)));
1071 0 : ShowContinueError(state,
1072 : " a Season other than Annual is used but no Season Schedule Name is specified in the UtilityCost:Tariff.");
1073 : }
1074 : }
1075 : }
1076 : // index of the category in the variable array
1077 285 : chargeBlock.categoryPt =
1078 285 : AssignVariablePt(state, s_ipsc->cAlphaArgs(5), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeBlock.tariffIndx);
1079 : // index of the remaining into variable in the variable array
1080 285 : chargeBlock.remainingPt =
1081 285 : AssignVariablePt(state, s_ipsc->cAlphaArgs(6), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeBlock.tariffIndx);
1082 : // block size multiplier
1083 285 : if (len(s_ipsc->cAlphaArgs(7)) == 0) { // if blank
1084 190 : chargeBlock.blkSzMultVal = 1.0; // default is 1 if left blank
1085 190 : chargeBlock.blkSzMultPt = 0;
1086 : } else {
1087 95 : chargeBlock.blkSzMultVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(7), isNotNumeric);
1088 95 : chargeBlock.blkSzMultPt = AssignVariablePt(
1089 95 : state, s_ipsc->cAlphaArgs(7), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeBlock.tariffIndx);
1090 : }
1091 : // number of blocks used
1092 285 : chargeBlock.numBlk = (NumAlphas - 7) / 2;
1093 1234 : for (int jBlk = 1; jBlk <= chargeBlock.numBlk; ++jBlk) {
1094 949 : alphaOffset = 7 + (jBlk - 1) * 2;
1095 : // catch the "remaining" code word for the block size
1096 949 : if (Util::SameString(s_ipsc->cAlphaArgs(alphaOffset + 1), "REMAINING")) {
1097 284 : chargeBlock.blkSzVal(jBlk) = hugeNumber / 1000000; // using small portion of largest possible value to prevent overflow
1098 284 : chargeBlock.blkSzPt(jBlk) = 0;
1099 : } else {
1100 : // array of block size
1101 665 : chargeBlock.blkSzVal(jBlk) = Util::ProcessNumber(s_ipsc->cAlphaArgs(alphaOffset + 1), isNotNumeric);
1102 :
1103 665 : chargeBlock.blkSzPt(jBlk) = AssignVariablePt(state,
1104 665 : s_ipsc->cAlphaArgs(alphaOffset + 1),
1105 : isNotNumeric,
1106 : varIsArgument,
1107 : varNotYetDefined,
1108 : ObjType::Invalid,
1109 : 0,
1110 : chargeBlock.tariffIndx);
1111 : }
1112 : // array of block cost
1113 949 : chargeBlock.blkCostVal(jBlk) = Util::ProcessNumber(s_ipsc->cAlphaArgs(alphaOffset + 2), isNotNumeric);
1114 949 : chargeBlock.blkCostPt(jBlk) = AssignVariablePt(state,
1115 949 : s_ipsc->cAlphaArgs(alphaOffset + 2),
1116 : isNotNumeric,
1117 : varIsArgument,
1118 : varNotYetDefined,
1119 : ObjType::Invalid,
1120 : 0,
1121 : chargeBlock.tariffIndx);
1122 : }
1123 : }
1124 101 : }
1125 :
1126 101 : void GetInputEconomicsRatchet(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
1127 : {
1128 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1129 : // DATE WRITTEN May 2004
1130 :
1131 : // Read the input file for "Economics:Ratchet" objects.
1132 :
1133 : static constexpr std::string_view RoutineName("GetInputEconomicsRatchet: ");
1134 : static constexpr std::string_view routineName = "GetInputEconomicsRatchet";
1135 :
1136 : int NumAlphas; // Number of elements in the alpha array
1137 : int NumNums; // Number of elements in the numeric array
1138 : int IOStat; // IO Status when calling get input subroutine
1139 : bool isNotNumeric;
1140 :
1141 101 : auto &s_econ = state.dataEconTariff;
1142 101 : auto &s_ipsc = state.dataIPShortCut;
1143 101 : s_ipsc->cCurrentModuleObject = "UtilityCost:Ratchet";
1144 :
1145 101 : s_econ->numRatchet = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1146 101 : s_econ->ratchet.allocate(s_econ->numRatchet);
1147 102 : for (int iInObj = 1; iInObj <= s_econ->numRatchet; ++iInObj) {
1148 1 : auto &ratchet = s_econ->ratchet(iInObj);
1149 :
1150 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1151 1 : s_ipsc->cCurrentModuleObject,
1152 : iInObj,
1153 1 : s_ipsc->cAlphaArgs,
1154 : NumAlphas,
1155 1 : s_ipsc->rNumericArgs,
1156 : NumNums,
1157 : IOStat,
1158 1 : s_ipsc->lNumericFieldBlanks,
1159 1 : s_ipsc->lAlphaFieldBlanks,
1160 1 : s_ipsc->cAlphaFieldNames,
1161 1 : s_ipsc->cNumericFieldNames);
1162 :
1163 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1164 :
1165 : // check to make sure none of the values are another economic object
1166 9 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
1167 8 : if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
1168 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1169 0 : ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
1170 : }
1171 : }
1172 : // index of the tariff name in the tariff array
1173 1 : ratchet.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
1174 1 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), ratchet.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
1175 1 : ratchet.namePt =
1176 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::Ratchet, iInObj, ratchet.tariffIndx);
1177 : // index of the variable in the variable array
1178 1 : ratchet.baselinePt =
1179 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Ratchet, iInObj, ratchet.tariffIndx);
1180 : // index of the variable in the variable array
1181 1 : ratchet.adjustmentPt =
1182 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(4), true, varIsArgument, varNotYetDefined, ObjType::Ratchet, iInObj, ratchet.tariffIndx);
1183 : // seasons to and from
1184 1 : ratchet.seasonFrom = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(5)));
1185 1 : if (ratchet.seasonFrom == Season::Invalid) {
1186 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(5), s_ipsc->cAlphaArgs(5), "Annual");
1187 0 : ratchet.seasonFrom = Season::Annual;
1188 : }
1189 1 : ratchet.seasonTo = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(6)));
1190 1 : if (ratchet.seasonTo == Season::Invalid) {
1191 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(6), s_ipsc->cAlphaArgs(56), "Annual");
1192 0 : ratchet.seasonTo = Season::Annual;
1193 : }
1194 :
1195 : // ratchet multiplier
1196 1 : ratchet.multiplierVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(7), isNotNumeric);
1197 1 : ratchet.multiplierPt =
1198 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(7), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, ratchet.tariffIndx);
1199 : // ratchet offset
1200 1 : ratchet.offsetVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(8), isNotNumeric);
1201 1 : ratchet.offsetPt =
1202 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(8), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, ratchet.tariffIndx);
1203 : }
1204 101 : }
1205 :
1206 101 : void GetInputEconomicsVariable(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
1207 : {
1208 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1209 : // DATE WRITTEN May 2004
1210 :
1211 : // Read the input file for "Economics:Variable" objects.
1212 :
1213 : static constexpr std::string_view RoutineName("GetInputEconomicsVariable: ");
1214 : static constexpr std::string_view routineName = "GetInputEconomicsVariable";
1215 :
1216 : int NumAlphas; // Number of elements in the alpha array
1217 : int NumNums; // Number of elements in the numeric array
1218 : int IOStat; // IO Status when calling get input subroutine
1219 :
1220 101 : auto &s_econ = state.dataEconTariff;
1221 101 : auto &s_ipsc = state.dataIPShortCut;
1222 :
1223 101 : s_ipsc->cCurrentModuleObject = "UtilityCost:Variable";
1224 101 : int numEconVarObj = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1225 187 : for (int iInObj = 1; iInObj <= numEconVarObj; ++iInObj) {
1226 172 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1227 86 : s_ipsc->cCurrentModuleObject,
1228 : iInObj,
1229 86 : s_ipsc->cAlphaArgs,
1230 : NumAlphas,
1231 86 : s_ipsc->rNumericArgs,
1232 : NumNums,
1233 : IOStat,
1234 86 : s_ipsc->lNumericFieldBlanks,
1235 86 : s_ipsc->lAlphaFieldBlanks,
1236 86 : s_ipsc->cAlphaFieldNames,
1237 86 : s_ipsc->cNumericFieldNames);
1238 :
1239 86 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
1240 :
1241 : // check to make sure none of the values are another economic object
1242 344 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
1243 258 : if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
1244 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1245 0 : ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
1246 : }
1247 : }
1248 86 : int tariffPt = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
1249 86 : int variablePt = AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsArgument, varUserDefined, ObjType::Variable, iInObj, tariffPt);
1250 86 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), tariffPt, ErrorsFound, s_ipsc->cCurrentModuleObject);
1251 86 : auto &econVar = s_econ->econVar(variablePt);
1252 :
1253 : // validate the kind of variable - not used internally except for validation
1254 86 : econVar.varUnitType = static_cast<VarUnitType>(getEnumValue(varUnitTypeNamesUC, s_ipsc->cAlphaArgs(3)));
1255 86 : if (econVar.varUnitType == VarUnitType::Invalid) {
1256 0 : ShowSevereInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3));
1257 0 : ErrorsFound = true;
1258 0 : econVar.varUnitType = VarUnitType::Dimensionless;
1259 : }
1260 :
1261 : // move number inputs into econVar
1262 1118 : for (int jVal = 1; jVal <= NumNums; ++jVal) {
1263 1032 : econVar.values(jVal) = s_ipsc->rNumericArgs(jVal);
1264 : }
1265 : // fill the rest of the array with the last value entered
1266 86 : if (NumNums < NumMonths) {
1267 0 : for (int jVal = NumNums + 1; jVal <= NumMonths; ++jVal) {
1268 0 : econVar.values(jVal) = s_ipsc->rNumericArgs(NumNums);
1269 : }
1270 : }
1271 : }
1272 101 : }
1273 :
1274 101 : void GetInputEconomicsComputation(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
1275 : {
1276 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1277 : // DATE WRITTEN May 2004
1278 :
1279 : // Read the input file for "Economics:Computation" objects.
1280 : // This object is only used for very complex rates.
1281 :
1282 : static constexpr std::string_view RoutineName("GetInputEconomicsComputation: ");
1283 :
1284 : int NumAlphas; // Number of elements in the alpha array
1285 : int NumNums; // Number of elements in the numeric array
1286 : int IOStat; // IO Status when calling get input subroutine
1287 :
1288 101 : auto &s_econ = state.dataEconTariff;
1289 101 : auto &s_ipsc = state.dataIPShortCut;
1290 :
1291 101 : s_ipsc->cCurrentModuleObject = "UtilityCost:Computation";
1292 101 : s_econ->numComputation = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1293 101 : s_econ->computation.allocate(s_econ->numTariff); // not the number of Computations but the number of tariffs
1294 : // set default values for computation
1295 402 : for (auto &e : s_econ->computation) {
1296 301 : e.computeName.clear();
1297 301 : e.firstStep = 0;
1298 301 : e.lastStep = -1;
1299 301 : e.isUserDef = false;
1300 101 : }
1301 102 : for (int iInObj = 1; iInObj <= s_econ->numComputation; ++iInObj) {
1302 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1303 1 : s_ipsc->cCurrentModuleObject,
1304 : iInObj,
1305 1 : s_ipsc->cAlphaArgs,
1306 : NumAlphas,
1307 1 : s_ipsc->rNumericArgs,
1308 : NumNums,
1309 : IOStat,
1310 1 : s_ipsc->lNumericFieldBlanks,
1311 1 : s_ipsc->lAlphaFieldBlanks,
1312 1 : s_ipsc->cAlphaFieldNames,
1313 1 : s_ipsc->cNumericFieldNames);
1314 : // check to make sure none of the values are another economic object
1315 9 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
1316 8 : if (hasi(s_ipsc->cAlphaArgs(jFld), "UtilityCost:")) {
1317 0 : ShowWarningError(state, format("{}{}=\"{}\".", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1318 0 : ShowContinueError(state, "... a field was found containing UtilityCost: which may indicate a missing comma.");
1319 : }
1320 : }
1321 1 : int tariffPt = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
1322 1 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), tariffPt, ErrorsFound, s_ipsc->cCurrentModuleObject);
1323 : // tariff and computation share the same index, the tariff index
1324 : // so all references are to the tariffPt
1325 1 : auto &computation = s_econ->computation(tariffPt);
1326 :
1327 1 : if (isWithinRange(state, tariffPt, 1, s_econ->numTariff)) {
1328 1 : computation.computeName = s_ipsc->cAlphaArgs(1);
1329 1 : computation.firstStep = s_econ->numSteps + 1;
1330 7 : for (int jLine = 3; jLine <= NumAlphas; ++jLine) {
1331 6 : parseComputeLine(state, s_ipsc->cAlphaArgs(jLine), tariffPt);
1332 : }
1333 1 : computation.lastStep = s_econ->numSteps;
1334 : // check to make sure that some steps were defined
1335 1 : if (computation.firstStep >= computation.lastStep) {
1336 0 : computation.firstStep = 0;
1337 0 : computation.lastStep = -1;
1338 0 : computation.isUserDef = false;
1339 0 : ShowSevereError(state, format("{}{}=\"{}\" invalid data.", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1340 0 : ShowContinueError(state, "... No lines in the computation can be interpreted ");
1341 0 : ErrorsFound = true;
1342 : } else {
1343 1 : computation.isUserDef = true;
1344 : }
1345 : } else {
1346 0 : ShowSevereError(state, format("{}{}=\"{}\" invalid data.", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1347 0 : ShowContinueError(state, format("... not found {}=\"{}\".", s_ipsc->cAlphaFieldNames(2), s_ipsc->cAlphaArgs(2)));
1348 0 : ErrorsFound = true;
1349 : }
1350 : }
1351 101 : }
1352 :
1353 799 : void GetInputEconomicsCurrencyType(EnergyPlusData &state, bool &ErrorsFound) // true if errors found during getting input objects.
1354 : {
1355 : // AUTHOR Jason Glazer
1356 : // DATE WRITTEN August 2008
1357 :
1358 : // Sets the type of currency (U.S. Dollar, Euro, Yen, etc.. )
1359 : // This is a "unique" object.
1360 :
1361 : static constexpr std::string_view RoutineName("GetInputEconomicsCurrencyType: ");
1362 :
1363 : int NumCurrencyType;
1364 : int NumAlphas; // Number of elements in the alpha array
1365 : int NumNums; // Number of elements in the numeric array
1366 : int IOStat; // IO Status when calling get input subroutine
1367 : int i;
1368 :
1369 799 : auto &s_ipsc = state.dataIPShortCut;
1370 799 : s_ipsc->cCurrentModuleObject = "CurrencyType";
1371 :
1372 799 : initializeMonetaryUnit(state);
1373 799 : NumCurrencyType = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1374 799 : state.dataCostEstimateManager->selectedMonetaryUnit = 0; // invalid
1375 799 : if (NumCurrencyType == 0) {
1376 797 : state.dataCostEstimateManager->selectedMonetaryUnit = 1; // USD - U.S. Dollar
1377 2 : } else if (NumCurrencyType == 1) {
1378 4 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1379 2 : s_ipsc->cCurrentModuleObject,
1380 : 1,
1381 2 : s_ipsc->cAlphaArgs,
1382 : NumAlphas,
1383 2 : s_ipsc->rNumericArgs,
1384 : NumNums,
1385 : IOStat,
1386 2 : s_ipsc->lNumericFieldBlanks,
1387 2 : s_ipsc->lAlphaFieldBlanks,
1388 2 : s_ipsc->cAlphaFieldNames,
1389 2 : s_ipsc->cNumericFieldNames);
1390 : // Monetary Unit
1391 2 : for (i = 1; i <= (int)state.dataCostEstimateManager->monetaryUnit.size(); ++i) {
1392 2 : if (Util::SameString(s_ipsc->cAlphaArgs(1), state.dataCostEstimateManager->monetaryUnit(i).code)) {
1393 2 : state.dataCostEstimateManager->selectedMonetaryUnit = i;
1394 2 : break;
1395 : }
1396 : }
1397 2 : if (state.dataCostEstimateManager->selectedMonetaryUnit == 0) {
1398 0 : ShowSevereError(state, format("{}{}=\"{}\" invalid data.", RoutineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)));
1399 0 : ShowContinueError(state, format("... invalid {}.", s_ipsc->cAlphaFieldNames(1)));
1400 0 : ErrorsFound = true;
1401 : }
1402 0 : } else if (NumCurrencyType > 1) {
1403 0 : ShowWarningError(state,
1404 0 : format("{}{} Only one instance of this object is allowed. USD will be used.", RoutineName, s_ipsc->cCurrentModuleObject));
1405 0 : state.dataCostEstimateManager->selectedMonetaryUnit = 1; // USD - U.S. Dollar
1406 : }
1407 799 : }
1408 :
1409 6 : void parseComputeLine(EnergyPlusData &state, std::string const &lineOfCompute, int const fromTariff)
1410 : {
1411 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1412 : // DATE WRITTEN June 2004
1413 :
1414 : // Converts a single line in the ECONOMICS:COMPUTE
1415 : // command into tokens for computation
1416 :
1417 : // Scan the line from the end of the line to the front of the
1418 : // line and search for operators and variables. All items
1419 : // are put into the step array.
1420 :
1421 6 : auto &s_econ = state.dataEconTariff;
1422 :
1423 6 : std::string word;
1424 :
1425 6 : size_t endOfWord = len(lineOfCompute) - 1;
1426 32 : while (endOfWord != std::string::npos) {
1427 : // get a single word (text string delimited by spaces)
1428 26 : GetLastWord(lineOfCompute, endOfWord, word);
1429 : // first see if word is an operator
1430 26 : Op op = static_cast<Op>(getEnumValue(opNamesUC, word));
1431 26 : if (op == Op::Invalid) {
1432 20 : static_cast<Op>(getEnumValue(opNames2UC, word));
1433 : }
1434 :
1435 : // if not an operator then look for
1436 26 : if (op != Op::Invalid) {
1437 6 : incrementSteps(state);
1438 6 : s_econ->steps(s_econ->numSteps).type = StepType::Op;
1439 6 : s_econ->steps(s_econ->numSteps).op = op;
1440 :
1441 : } else {
1442 : int varNum;
1443 : // see if argument or assignment (assignment will be first string on line)
1444 20 : if (endOfWord != std::string::npos) {
1445 14 : varNum = AssignVariablePt(state, word, true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, fromTariff);
1446 : } else {
1447 6 : varNum = AssignVariablePt(state, word, true, varIsAssigned, varNotYetDefined, ObjType::AssignCompute, 0, fromTariff);
1448 : }
1449 :
1450 : // if a token is found then put it into step array
1451 20 : if (varNum == 0) {
1452 0 : ShowWarningError(state, format("In UtilityCost:Computation line: {}", lineOfCompute));
1453 0 : ShowContinueError(state, format(" Do not recognize: {} Will skip.", word));
1454 : } else {
1455 20 : incrementSteps(state);
1456 20 : s_econ->steps(s_econ->numSteps).type = StepType::Var;
1457 20 : s_econ->steps(s_econ->numSteps).varNum = varNum;
1458 : }
1459 : }
1460 : }
1461 :
1462 6 : incrementSteps(state);
1463 6 : s_econ->steps(s_econ->numSteps).type = StepType::EOL; // at the end of the line show a zero to clear the stack
1464 6 : }
1465 :
1466 26 : void GetLastWord(std::string const &lineOfText, std::string::size_type &endOfScan, std::string &aWord)
1467 : {
1468 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1469 : // DATE WRITTEN June 2004
1470 :
1471 : // Returns the last substring of the line of text to the
1472 : // left of the endOfSubStrg pointer. A substring is
1473 : // delimited by spaces. Quotes are not significant
1474 : // (they are treated just like any other non-space character)
1475 :
1476 : // Scan the string from the end.
1477 :
1478 26 : size_t curEndOfScan = endOfScan;
1479 26 : if (curEndOfScan != std::string::npos) {
1480 26 : if (curEndOfScan >= len(lineOfText)) {
1481 0 : curEndOfScan = len(lineOfText) - 1;
1482 : }
1483 : // check if currently on a space or not
1484 : bool isInWord;
1485 : size_t beginOfWord;
1486 : size_t endOfWord;
1487 26 : if (lineOfText[curEndOfScan] == ' ') {
1488 20 : isInWord = false;
1489 20 : beginOfWord = 0;
1490 20 : endOfWord = 0;
1491 : } else {
1492 6 : isInWord = true;
1493 6 : beginOfWord = curEndOfScan;
1494 6 : endOfWord = curEndOfScan;
1495 : }
1496 : // scan backwards from
1497 : bool isSpace;
1498 274 : for (size_t iString = curEndOfScan; iString <= curEndOfScan; --iString) { // Unsigned will wrap to npos after 0
1499 268 : if (lineOfText[iString] == ' ') {
1500 40 : isSpace = true;
1501 : } else {
1502 228 : isSpace = false;
1503 : }
1504 : // all logical conditions of isSpace and isInWord
1505 268 : if (isSpace) {
1506 40 : if (isInWord) {
1507 : // found the space in front of the word
1508 20 : break;
1509 : } else {
1510 : // still have not found the back of the word
1511 : // do nothing
1512 : }
1513 : } else {
1514 228 : if (isInWord) {
1515 : // still have not found the space in front of the word
1516 208 : beginOfWord = iString;
1517 : } else {
1518 : // found the last character of the word
1519 20 : endOfWord = iString;
1520 20 : beginOfWord = iString;
1521 20 : isInWord = true;
1522 : }
1523 : }
1524 : }
1525 26 : aWord = lineOfText.substr(beginOfWord, endOfWord - beginOfWord + 1);
1526 26 : endOfScan = beginOfWord - 1;
1527 : } else {
1528 0 : endOfScan = std::string::npos;
1529 0 : aWord = "";
1530 : }
1531 26 : }
1532 :
1533 799 : void initializeMonetaryUnit(EnergyPlusData &state)
1534 : {
1535 : // AUTHOR Jason Glazer
1536 : // DATE WRITTEN August 2008
1537 :
1538 : // Sets the type of monetary unit array.
1539 :
1540 : // Uses get input structure similar to other objects
1541 : // The monetaryUnitSymbols.xls spreadsheet helps create the code for this routine
1542 :
1543 : // www.xe.com/symbols.php
1544 :
1545 799 : int numMonetaryUnit = 111;
1546 799 : state.dataCostEstimateManager->monetaryUnit.allocate(numMonetaryUnit);
1547 799 : state.dataCostEstimateManager->monetaryUnit(1).code = "USD";
1548 799 : state.dataCostEstimateManager->monetaryUnit(2).code = "AFN";
1549 799 : state.dataCostEstimateManager->monetaryUnit(3).code = "ALL";
1550 799 : state.dataCostEstimateManager->monetaryUnit(4).code = "ANG";
1551 799 : state.dataCostEstimateManager->monetaryUnit(5).code = "ARS";
1552 799 : state.dataCostEstimateManager->monetaryUnit(6).code = "AUD";
1553 799 : state.dataCostEstimateManager->monetaryUnit(7).code = "AWG";
1554 799 : state.dataCostEstimateManager->monetaryUnit(8).code = "AZN";
1555 799 : state.dataCostEstimateManager->monetaryUnit(9).code = "BAM";
1556 799 : state.dataCostEstimateManager->monetaryUnit(10).code = "BBD";
1557 799 : state.dataCostEstimateManager->monetaryUnit(11).code = "BGN";
1558 799 : state.dataCostEstimateManager->monetaryUnit(12).code = "BMD";
1559 799 : state.dataCostEstimateManager->monetaryUnit(13).code = "BND";
1560 799 : state.dataCostEstimateManager->monetaryUnit(14).code = "BOB";
1561 799 : state.dataCostEstimateManager->monetaryUnit(15).code = "BRL";
1562 799 : state.dataCostEstimateManager->monetaryUnit(16).code = "BSD";
1563 799 : state.dataCostEstimateManager->monetaryUnit(17).code = "BWP";
1564 799 : state.dataCostEstimateManager->monetaryUnit(18).code = "BYR";
1565 799 : state.dataCostEstimateManager->monetaryUnit(19).code = "BZD";
1566 799 : state.dataCostEstimateManager->monetaryUnit(20).code = "CAD";
1567 799 : state.dataCostEstimateManager->monetaryUnit(21).code = "CHF";
1568 799 : state.dataCostEstimateManager->monetaryUnit(22).code = "CLP";
1569 799 : state.dataCostEstimateManager->monetaryUnit(23).code = "CNY";
1570 799 : state.dataCostEstimateManager->monetaryUnit(24).code = "COP";
1571 799 : state.dataCostEstimateManager->monetaryUnit(25).code = "CRC";
1572 799 : state.dataCostEstimateManager->monetaryUnit(26).code = "CUP";
1573 799 : state.dataCostEstimateManager->monetaryUnit(27).code = "CZK";
1574 799 : state.dataCostEstimateManager->monetaryUnit(28).code = "DKK";
1575 799 : state.dataCostEstimateManager->monetaryUnit(29).code = "DOP";
1576 799 : state.dataCostEstimateManager->monetaryUnit(30).code = "EEK";
1577 799 : state.dataCostEstimateManager->monetaryUnit(31).code = "EGP";
1578 799 : state.dataCostEstimateManager->monetaryUnit(32).code = "EUR";
1579 799 : state.dataCostEstimateManager->monetaryUnit(33).code = "FJD";
1580 799 : state.dataCostEstimateManager->monetaryUnit(34).code = "GBP";
1581 799 : state.dataCostEstimateManager->monetaryUnit(35).code = "GHC";
1582 799 : state.dataCostEstimateManager->monetaryUnit(36).code = "GIP";
1583 799 : state.dataCostEstimateManager->monetaryUnit(37).code = "GTQ";
1584 799 : state.dataCostEstimateManager->monetaryUnit(38).code = "GYD";
1585 799 : state.dataCostEstimateManager->monetaryUnit(39).code = "HKD";
1586 799 : state.dataCostEstimateManager->monetaryUnit(40).code = "HNL";
1587 799 : state.dataCostEstimateManager->monetaryUnit(41).code = "HRK";
1588 799 : state.dataCostEstimateManager->monetaryUnit(42).code = "HUF";
1589 799 : state.dataCostEstimateManager->monetaryUnit(43).code = "IDR";
1590 799 : state.dataCostEstimateManager->monetaryUnit(44).code = "ILS";
1591 799 : state.dataCostEstimateManager->monetaryUnit(45).code = "IMP";
1592 799 : state.dataCostEstimateManager->monetaryUnit(46).code = "INR";
1593 799 : state.dataCostEstimateManager->monetaryUnit(47).code = "IRR";
1594 799 : state.dataCostEstimateManager->monetaryUnit(48).code = "ISK";
1595 799 : state.dataCostEstimateManager->monetaryUnit(49).code = "JEP";
1596 799 : state.dataCostEstimateManager->monetaryUnit(50).code = "JMD";
1597 799 : state.dataCostEstimateManager->monetaryUnit(51).code = "JPY";
1598 799 : state.dataCostEstimateManager->monetaryUnit(52).code = "KGS";
1599 799 : state.dataCostEstimateManager->monetaryUnit(53).code = "KHR";
1600 799 : state.dataCostEstimateManager->monetaryUnit(54).code = "KPW";
1601 799 : state.dataCostEstimateManager->monetaryUnit(55).code = "KRW";
1602 799 : state.dataCostEstimateManager->monetaryUnit(56).code = "KYD";
1603 799 : state.dataCostEstimateManager->monetaryUnit(57).code = "KZT";
1604 799 : state.dataCostEstimateManager->monetaryUnit(58).code = "LAK";
1605 799 : state.dataCostEstimateManager->monetaryUnit(59).code = "LBP";
1606 799 : state.dataCostEstimateManager->monetaryUnit(60).code = "LKR";
1607 799 : state.dataCostEstimateManager->monetaryUnit(61).code = "LRD";
1608 799 : state.dataCostEstimateManager->monetaryUnit(62).code = "LTL";
1609 799 : state.dataCostEstimateManager->monetaryUnit(63).code = "LVL";
1610 799 : state.dataCostEstimateManager->monetaryUnit(64).code = "MKD";
1611 799 : state.dataCostEstimateManager->monetaryUnit(65).code = "MNT";
1612 799 : state.dataCostEstimateManager->monetaryUnit(66).code = "MUR";
1613 799 : state.dataCostEstimateManager->monetaryUnit(67).code = "MXN";
1614 799 : state.dataCostEstimateManager->monetaryUnit(68).code = "MYR";
1615 799 : state.dataCostEstimateManager->monetaryUnit(69).code = "MZN";
1616 799 : state.dataCostEstimateManager->monetaryUnit(70).code = "NAD";
1617 799 : state.dataCostEstimateManager->monetaryUnit(71).code = "NGN";
1618 799 : state.dataCostEstimateManager->monetaryUnit(72).code = "NIO";
1619 799 : state.dataCostEstimateManager->monetaryUnit(73).code = "NOK";
1620 799 : state.dataCostEstimateManager->monetaryUnit(74).code = "NPR";
1621 799 : state.dataCostEstimateManager->monetaryUnit(75).code = "NZD";
1622 799 : state.dataCostEstimateManager->monetaryUnit(76).code = "OMR";
1623 799 : state.dataCostEstimateManager->monetaryUnit(77).code = "PAB";
1624 799 : state.dataCostEstimateManager->monetaryUnit(78).code = "PEN";
1625 799 : state.dataCostEstimateManager->monetaryUnit(79).code = "PHP";
1626 799 : state.dataCostEstimateManager->monetaryUnit(80).code = "PKR";
1627 799 : state.dataCostEstimateManager->monetaryUnit(81).code = "PLN";
1628 799 : state.dataCostEstimateManager->monetaryUnit(82).code = "PYG";
1629 799 : state.dataCostEstimateManager->monetaryUnit(83).code = "QAR";
1630 799 : state.dataCostEstimateManager->monetaryUnit(84).code = "RON";
1631 799 : state.dataCostEstimateManager->monetaryUnit(85).code = "RSD";
1632 799 : state.dataCostEstimateManager->monetaryUnit(86).code = "RUB";
1633 799 : state.dataCostEstimateManager->monetaryUnit(87).code = "SAR";
1634 799 : state.dataCostEstimateManager->monetaryUnit(88).code = "SBD";
1635 799 : state.dataCostEstimateManager->monetaryUnit(89).code = "SCR";
1636 799 : state.dataCostEstimateManager->monetaryUnit(90).code = "SEK";
1637 799 : state.dataCostEstimateManager->monetaryUnit(91).code = "SGD";
1638 799 : state.dataCostEstimateManager->monetaryUnit(92).code = "SHP";
1639 799 : state.dataCostEstimateManager->monetaryUnit(93).code = "SOS";
1640 799 : state.dataCostEstimateManager->monetaryUnit(94).code = "SRD";
1641 799 : state.dataCostEstimateManager->monetaryUnit(95).code = "SVC";
1642 799 : state.dataCostEstimateManager->monetaryUnit(96).code = "SYP";
1643 799 : state.dataCostEstimateManager->monetaryUnit(97).code = "THB";
1644 799 : state.dataCostEstimateManager->monetaryUnit(98).code = "TRL";
1645 799 : state.dataCostEstimateManager->monetaryUnit(99).code = "TRY";
1646 799 : state.dataCostEstimateManager->monetaryUnit(100).code = "TTD";
1647 799 : state.dataCostEstimateManager->monetaryUnit(101).code = "TVD";
1648 799 : state.dataCostEstimateManager->monetaryUnit(102).code = "TWD";
1649 799 : state.dataCostEstimateManager->monetaryUnit(103).code = "UAH";
1650 799 : state.dataCostEstimateManager->monetaryUnit(104).code = "UYU";
1651 799 : state.dataCostEstimateManager->monetaryUnit(105).code = "UZS";
1652 799 : state.dataCostEstimateManager->monetaryUnit(106).code = "VEF";
1653 799 : state.dataCostEstimateManager->monetaryUnit(107).code = "VND";
1654 799 : state.dataCostEstimateManager->monetaryUnit(108).code = "XCD";
1655 799 : state.dataCostEstimateManager->monetaryUnit(109).code = "YER";
1656 799 : state.dataCostEstimateManager->monetaryUnit(110).code = "ZAR";
1657 799 : state.dataCostEstimateManager->monetaryUnit(111).code = "ZWD";
1658 :
1659 799 : state.dataCostEstimateManager->monetaryUnit(1).txt = "$";
1660 799 : state.dataCostEstimateManager->monetaryUnit(2).txt = "AFN";
1661 799 : state.dataCostEstimateManager->monetaryUnit(3).txt = "Lek";
1662 799 : state.dataCostEstimateManager->monetaryUnit(4).txt = "ANG";
1663 799 : state.dataCostEstimateManager->monetaryUnit(5).txt = "$";
1664 799 : state.dataCostEstimateManager->monetaryUnit(6).txt = "$";
1665 799 : state.dataCostEstimateManager->monetaryUnit(7).txt = "AWG";
1666 799 : state.dataCostEstimateManager->monetaryUnit(8).txt = "AZN";
1667 799 : state.dataCostEstimateManager->monetaryUnit(9).txt = "KM";
1668 799 : state.dataCostEstimateManager->monetaryUnit(10).txt = "$";
1669 799 : state.dataCostEstimateManager->monetaryUnit(11).txt = "BGN";
1670 799 : state.dataCostEstimateManager->monetaryUnit(12).txt = "$";
1671 799 : state.dataCostEstimateManager->monetaryUnit(13).txt = "$";
1672 799 : state.dataCostEstimateManager->monetaryUnit(14).txt = "$b";
1673 799 : state.dataCostEstimateManager->monetaryUnit(15).txt = "R$";
1674 799 : state.dataCostEstimateManager->monetaryUnit(16).txt = "$";
1675 799 : state.dataCostEstimateManager->monetaryUnit(17).txt = "P";
1676 799 : state.dataCostEstimateManager->monetaryUnit(18).txt = "p.";
1677 799 : state.dataCostEstimateManager->monetaryUnit(19).txt = "BZ$";
1678 799 : state.dataCostEstimateManager->monetaryUnit(20).txt = "$";
1679 799 : state.dataCostEstimateManager->monetaryUnit(21).txt = "CHF";
1680 799 : state.dataCostEstimateManager->monetaryUnit(22).txt = "$";
1681 799 : state.dataCostEstimateManager->monetaryUnit(23).txt = "CNY";
1682 799 : state.dataCostEstimateManager->monetaryUnit(24).txt = "$";
1683 799 : state.dataCostEstimateManager->monetaryUnit(25).txt = "CRC";
1684 799 : state.dataCostEstimateManager->monetaryUnit(26).txt = "CUP";
1685 799 : state.dataCostEstimateManager->monetaryUnit(27).txt = "CZK";
1686 799 : state.dataCostEstimateManager->monetaryUnit(28).txt = "kr";
1687 799 : state.dataCostEstimateManager->monetaryUnit(29).txt = "RD$";
1688 799 : state.dataCostEstimateManager->monetaryUnit(30).txt = "kr";
1689 799 : state.dataCostEstimateManager->monetaryUnit(31).txt = "£";
1690 799 : state.dataCostEstimateManager->monetaryUnit(32).txt = "EUR";
1691 799 : state.dataCostEstimateManager->monetaryUnit(33).txt = "$";
1692 799 : state.dataCostEstimateManager->monetaryUnit(34).txt = "£";
1693 799 : state.dataCostEstimateManager->monetaryUnit(35).txt = "¢";
1694 799 : state.dataCostEstimateManager->monetaryUnit(36).txt = "£";
1695 799 : state.dataCostEstimateManager->monetaryUnit(37).txt = "Q";
1696 799 : state.dataCostEstimateManager->monetaryUnit(38).txt = "$";
1697 799 : state.dataCostEstimateManager->monetaryUnit(39).txt = "HK$";
1698 799 : state.dataCostEstimateManager->monetaryUnit(40).txt = "L";
1699 799 : state.dataCostEstimateManager->monetaryUnit(41).txt = "kn";
1700 799 : state.dataCostEstimateManager->monetaryUnit(42).txt = "Ft";
1701 799 : state.dataCostEstimateManager->monetaryUnit(43).txt = "Rp";
1702 799 : state.dataCostEstimateManager->monetaryUnit(44).txt = "ILS";
1703 799 : state.dataCostEstimateManager->monetaryUnit(45).txt = "£";
1704 799 : state.dataCostEstimateManager->monetaryUnit(46).txt = "INR";
1705 799 : state.dataCostEstimateManager->monetaryUnit(47).txt = "IRR";
1706 799 : state.dataCostEstimateManager->monetaryUnit(48).txt = "kr";
1707 799 : state.dataCostEstimateManager->monetaryUnit(49).txt = "£";
1708 799 : state.dataCostEstimateManager->monetaryUnit(50).txt = "J$";
1709 799 : state.dataCostEstimateManager->monetaryUnit(51).txt = "Â¥";
1710 799 : state.dataCostEstimateManager->monetaryUnit(52).txt = "KGS";
1711 799 : state.dataCostEstimateManager->monetaryUnit(53).txt = "KHR";
1712 799 : state.dataCostEstimateManager->monetaryUnit(54).txt = "KPW";
1713 799 : state.dataCostEstimateManager->monetaryUnit(55).txt = "KRW";
1714 799 : state.dataCostEstimateManager->monetaryUnit(56).txt = "$";
1715 799 : state.dataCostEstimateManager->monetaryUnit(57).txt = "KZT";
1716 799 : state.dataCostEstimateManager->monetaryUnit(58).txt = "LAK";
1717 799 : state.dataCostEstimateManager->monetaryUnit(59).txt = "£";
1718 799 : state.dataCostEstimateManager->monetaryUnit(60).txt = "LKR";
1719 799 : state.dataCostEstimateManager->monetaryUnit(61).txt = "$";
1720 799 : state.dataCostEstimateManager->monetaryUnit(62).txt = "Lt";
1721 799 : state.dataCostEstimateManager->monetaryUnit(63).txt = "Ls";
1722 799 : state.dataCostEstimateManager->monetaryUnit(64).txt = "MKD";
1723 799 : state.dataCostEstimateManager->monetaryUnit(65).txt = "MNT";
1724 799 : state.dataCostEstimateManager->monetaryUnit(66).txt = "MUR";
1725 799 : state.dataCostEstimateManager->monetaryUnit(67).txt = "$";
1726 799 : state.dataCostEstimateManager->monetaryUnit(68).txt = "RM";
1727 799 : state.dataCostEstimateManager->monetaryUnit(69).txt = "MT";
1728 799 : state.dataCostEstimateManager->monetaryUnit(70).txt = "$";
1729 799 : state.dataCostEstimateManager->monetaryUnit(71).txt = "NGN";
1730 799 : state.dataCostEstimateManager->monetaryUnit(72).txt = "C$";
1731 799 : state.dataCostEstimateManager->monetaryUnit(73).txt = "kr";
1732 799 : state.dataCostEstimateManager->monetaryUnit(74).txt = "NPR";
1733 799 : state.dataCostEstimateManager->monetaryUnit(75).txt = "$";
1734 799 : state.dataCostEstimateManager->monetaryUnit(76).txt = "OMR";
1735 799 : state.dataCostEstimateManager->monetaryUnit(77).txt = "B/.";
1736 799 : state.dataCostEstimateManager->monetaryUnit(78).txt = "S/.";
1737 799 : state.dataCostEstimateManager->monetaryUnit(79).txt = "Php";
1738 799 : state.dataCostEstimateManager->monetaryUnit(80).txt = "PKR";
1739 799 : state.dataCostEstimateManager->monetaryUnit(81).txt = "PLN";
1740 799 : state.dataCostEstimateManager->monetaryUnit(82).txt = "Gs";
1741 799 : state.dataCostEstimateManager->monetaryUnit(83).txt = "QAR";
1742 799 : state.dataCostEstimateManager->monetaryUnit(84).txt = "lei";
1743 799 : state.dataCostEstimateManager->monetaryUnit(85).txt = "RSD";
1744 799 : state.dataCostEstimateManager->monetaryUnit(86).txt = "RUB";
1745 799 : state.dataCostEstimateManager->monetaryUnit(87).txt = "SAR";
1746 799 : state.dataCostEstimateManager->monetaryUnit(88).txt = "$";
1747 799 : state.dataCostEstimateManager->monetaryUnit(89).txt = "SCR";
1748 799 : state.dataCostEstimateManager->monetaryUnit(90).txt = "kr";
1749 799 : state.dataCostEstimateManager->monetaryUnit(91).txt = "$";
1750 799 : state.dataCostEstimateManager->monetaryUnit(92).txt = "£";
1751 799 : state.dataCostEstimateManager->monetaryUnit(93).txt = "S";
1752 799 : state.dataCostEstimateManager->monetaryUnit(94).txt = "$";
1753 799 : state.dataCostEstimateManager->monetaryUnit(95).txt = "$";
1754 799 : state.dataCostEstimateManager->monetaryUnit(96).txt = "£";
1755 799 : state.dataCostEstimateManager->monetaryUnit(97).txt = "THB";
1756 799 : state.dataCostEstimateManager->monetaryUnit(98).txt = "TRL";
1757 799 : state.dataCostEstimateManager->monetaryUnit(99).txt = "YTL";
1758 799 : state.dataCostEstimateManager->monetaryUnit(100).txt = "TT$";
1759 799 : state.dataCostEstimateManager->monetaryUnit(101).txt = "$";
1760 799 : state.dataCostEstimateManager->monetaryUnit(102).txt = "NT$";
1761 799 : state.dataCostEstimateManager->monetaryUnit(103).txt = "UAH";
1762 799 : state.dataCostEstimateManager->monetaryUnit(104).txt = "$U";
1763 799 : state.dataCostEstimateManager->monetaryUnit(105).txt = "UZS";
1764 799 : state.dataCostEstimateManager->monetaryUnit(106).txt = "Bs";
1765 799 : state.dataCostEstimateManager->monetaryUnit(107).txt = "VND";
1766 799 : state.dataCostEstimateManager->monetaryUnit(108).txt = "$";
1767 799 : state.dataCostEstimateManager->monetaryUnit(109).txt = "YER";
1768 799 : state.dataCostEstimateManager->monetaryUnit(110).txt = "R";
1769 799 : state.dataCostEstimateManager->monetaryUnit(111).txt = "Z$";
1770 :
1771 799 : state.dataCostEstimateManager->monetaryUnit(1).html = "$";
1772 799 : state.dataCostEstimateManager->monetaryUnit(2).html = "؋";
1773 799 : state.dataCostEstimateManager->monetaryUnit(3).html = "Lek";
1774 799 : state.dataCostEstimateManager->monetaryUnit(4).html = "ƒ";
1775 799 : state.dataCostEstimateManager->monetaryUnit(5).html = "$";
1776 799 : state.dataCostEstimateManager->monetaryUnit(6).html = "$";
1777 799 : state.dataCostEstimateManager->monetaryUnit(7).html = "ƒ";
1778 799 : state.dataCostEstimateManager->monetaryUnit(8).html = "ман";
1779 799 : state.dataCostEstimateManager->monetaryUnit(9).html = "KM";
1780 799 : state.dataCostEstimateManager->monetaryUnit(10).html = "$";
1781 799 : state.dataCostEstimateManager->monetaryUnit(11).html = "лв";
1782 799 : state.dataCostEstimateManager->monetaryUnit(12).html = "$";
1783 799 : state.dataCostEstimateManager->monetaryUnit(13).html = "$";
1784 799 : state.dataCostEstimateManager->monetaryUnit(14).html = "$b";
1785 799 : state.dataCostEstimateManager->monetaryUnit(15).html = "R$";
1786 799 : state.dataCostEstimateManager->monetaryUnit(16).html = "$";
1787 799 : state.dataCostEstimateManager->monetaryUnit(17).html = "P";
1788 799 : state.dataCostEstimateManager->monetaryUnit(18).html = "p.";
1789 799 : state.dataCostEstimateManager->monetaryUnit(19).html = "BZ$";
1790 799 : state.dataCostEstimateManager->monetaryUnit(20).html = "$";
1791 799 : state.dataCostEstimateManager->monetaryUnit(21).html = "CHF";
1792 799 : state.dataCostEstimateManager->monetaryUnit(22).html = "$";
1793 799 : state.dataCostEstimateManager->monetaryUnit(23).html = "元";
1794 799 : state.dataCostEstimateManager->monetaryUnit(24).html = "$";
1795 799 : state.dataCostEstimateManager->monetaryUnit(25).html = "₡";
1796 799 : state.dataCostEstimateManager->monetaryUnit(26).html = "₱";
1797 799 : state.dataCostEstimateManager->monetaryUnit(27).html = "Kč";
1798 799 : state.dataCostEstimateManager->monetaryUnit(28).html = "kr";
1799 799 : state.dataCostEstimateManager->monetaryUnit(29).html = "RD$";
1800 799 : state.dataCostEstimateManager->monetaryUnit(30).html = "kr";
1801 799 : state.dataCostEstimateManager->monetaryUnit(31).html = "£";
1802 799 : state.dataCostEstimateManager->monetaryUnit(32).html = "€";
1803 799 : state.dataCostEstimateManager->monetaryUnit(33).html = "$";
1804 799 : state.dataCostEstimateManager->monetaryUnit(34).html = "£";
1805 799 : state.dataCostEstimateManager->monetaryUnit(35).html = "¢";
1806 799 : state.dataCostEstimateManager->monetaryUnit(36).html = "£";
1807 799 : state.dataCostEstimateManager->monetaryUnit(37).html = "Q";
1808 799 : state.dataCostEstimateManager->monetaryUnit(38).html = "$";
1809 799 : state.dataCostEstimateManager->monetaryUnit(39).html = "HK$";
1810 799 : state.dataCostEstimateManager->monetaryUnit(40).html = "L";
1811 799 : state.dataCostEstimateManager->monetaryUnit(41).html = "kn";
1812 799 : state.dataCostEstimateManager->monetaryUnit(42).html = "Ft";
1813 799 : state.dataCostEstimateManager->monetaryUnit(43).html = "Rp";
1814 799 : state.dataCostEstimateManager->monetaryUnit(44).html = "₪";
1815 799 : state.dataCostEstimateManager->monetaryUnit(45).html = "£";
1816 799 : state.dataCostEstimateManager->monetaryUnit(46).html = "₨";
1817 799 : state.dataCostEstimateManager->monetaryUnit(47).html = "﷼";
1818 799 : state.dataCostEstimateManager->monetaryUnit(48).html = "kr";
1819 799 : state.dataCostEstimateManager->monetaryUnit(49).html = "£";
1820 799 : state.dataCostEstimateManager->monetaryUnit(50).html = "J$";
1821 799 : state.dataCostEstimateManager->monetaryUnit(51).html = "Â¥";
1822 799 : state.dataCostEstimateManager->monetaryUnit(52).html = "лв";
1823 799 : state.dataCostEstimateManager->monetaryUnit(53).html = "៛";
1824 799 : state.dataCostEstimateManager->monetaryUnit(54).html = "₩";
1825 799 : state.dataCostEstimateManager->monetaryUnit(55).html = "₩";
1826 799 : state.dataCostEstimateManager->monetaryUnit(56).html = "$";
1827 799 : state.dataCostEstimateManager->monetaryUnit(57).html = "лв";
1828 799 : state.dataCostEstimateManager->monetaryUnit(58).html = "₭";
1829 799 : state.dataCostEstimateManager->monetaryUnit(59).html = "£";
1830 799 : state.dataCostEstimateManager->monetaryUnit(60).html = "₨";
1831 799 : state.dataCostEstimateManager->monetaryUnit(61).html = "$";
1832 799 : state.dataCostEstimateManager->monetaryUnit(62).html = "Lt";
1833 799 : state.dataCostEstimateManager->monetaryUnit(63).html = "Ls";
1834 799 : state.dataCostEstimateManager->monetaryUnit(64).html = "ден";
1835 799 : state.dataCostEstimateManager->monetaryUnit(65).html = "₮";
1836 799 : state.dataCostEstimateManager->monetaryUnit(66).html = "₨";
1837 799 : state.dataCostEstimateManager->monetaryUnit(67).html = "$";
1838 799 : state.dataCostEstimateManager->monetaryUnit(68).html = "RM";
1839 799 : state.dataCostEstimateManager->monetaryUnit(69).html = "MT";
1840 799 : state.dataCostEstimateManager->monetaryUnit(70).html = "$";
1841 799 : state.dataCostEstimateManager->monetaryUnit(71).html = "₦";
1842 799 : state.dataCostEstimateManager->monetaryUnit(72).html = "C$";
1843 799 : state.dataCostEstimateManager->monetaryUnit(73).html = "kr";
1844 799 : state.dataCostEstimateManager->monetaryUnit(74).html = "₨";
1845 799 : state.dataCostEstimateManager->monetaryUnit(75).html = "$";
1846 799 : state.dataCostEstimateManager->monetaryUnit(76).html = "﷼";
1847 799 : state.dataCostEstimateManager->monetaryUnit(77).html = "B/.";
1848 799 : state.dataCostEstimateManager->monetaryUnit(78).html = "S/.";
1849 799 : state.dataCostEstimateManager->monetaryUnit(79).html = "Php";
1850 799 : state.dataCostEstimateManager->monetaryUnit(80).html = "₨";
1851 799 : state.dataCostEstimateManager->monetaryUnit(81).html = "zł";
1852 799 : state.dataCostEstimateManager->monetaryUnit(82).html = "Gs";
1853 799 : state.dataCostEstimateManager->monetaryUnit(83).html = "﷼";
1854 799 : state.dataCostEstimateManager->monetaryUnit(84).html = "lei";
1855 799 : state.dataCostEstimateManager->monetaryUnit(85).html = "Дин.";
1856 799 : state.dataCostEstimateManager->monetaryUnit(86).html = "руб";
1857 799 : state.dataCostEstimateManager->monetaryUnit(87).html = "﷼";
1858 799 : state.dataCostEstimateManager->monetaryUnit(88).html = "$";
1859 799 : state.dataCostEstimateManager->monetaryUnit(89).html = "₨";
1860 799 : state.dataCostEstimateManager->monetaryUnit(90).html = "kr";
1861 799 : state.dataCostEstimateManager->monetaryUnit(91).html = "$";
1862 799 : state.dataCostEstimateManager->monetaryUnit(92).html = "£";
1863 799 : state.dataCostEstimateManager->monetaryUnit(93).html = "S";
1864 799 : state.dataCostEstimateManager->monetaryUnit(94).html = "$";
1865 799 : state.dataCostEstimateManager->monetaryUnit(95).html = "$";
1866 799 : state.dataCostEstimateManager->monetaryUnit(96).html = "£";
1867 799 : state.dataCostEstimateManager->monetaryUnit(97).html = "฿";
1868 799 : state.dataCostEstimateManager->monetaryUnit(98).html = "₤";
1869 799 : state.dataCostEstimateManager->monetaryUnit(99).html = "YTL";
1870 799 : state.dataCostEstimateManager->monetaryUnit(100).html = "TT$";
1871 799 : state.dataCostEstimateManager->monetaryUnit(101).html = "$";
1872 799 : state.dataCostEstimateManager->monetaryUnit(102).html = "NT$";
1873 799 : state.dataCostEstimateManager->monetaryUnit(103).html = "₴";
1874 799 : state.dataCostEstimateManager->monetaryUnit(104).html = "$U";
1875 799 : state.dataCostEstimateManager->monetaryUnit(105).html = "лв";
1876 799 : state.dataCostEstimateManager->monetaryUnit(106).html = "Bs";
1877 799 : state.dataCostEstimateManager->monetaryUnit(107).html = "₫";
1878 799 : state.dataCostEstimateManager->monetaryUnit(108).html = "$";
1879 799 : state.dataCostEstimateManager->monetaryUnit(109).html = "﷼";
1880 799 : state.dataCostEstimateManager->monetaryUnit(110).html = "R";
1881 799 : state.dataCostEstimateManager->monetaryUnit(111).html = "Z$";
1882 799 : }
1883 :
1884 2205 : int FindTariffIndex(
1885 : EnergyPlusData &state, std::string const &nameOfTariff, std::string const &nameOfReferingObj, bool &ErrorsFound, std::string const &nameOfCurObj)
1886 : {
1887 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1888 : // DATE WRITTEN May 2004
1889 :
1890 : // Find the index for the tariff string provided or else
1891 : // raise a warning.
1892 :
1893 2205 : auto &s_econ = state.dataEconTariff;
1894 :
1895 : int FindTariffIndex;
1896 2205 : int found = 0;
1897 :
1898 4050 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
1899 4050 : if (Util::SameString(nameOfTariff, s_econ->tariff(iTariff).tariffName)) {
1900 2205 : found = iTariff;
1901 2205 : break;
1902 : }
1903 : }
1904 2205 : if (found > 0) {
1905 2205 : FindTariffIndex = found;
1906 : } else {
1907 0 : ShowSevereError(state, format("{}=\"{}\" invalid tariff referenced", nameOfCurObj, nameOfReferingObj));
1908 0 : ShowContinueError(state, format("not found UtilityCost:Tariff=\"{}\".", nameOfTariff));
1909 0 : ErrorsFound = true;
1910 0 : FindTariffIndex = 0;
1911 : }
1912 2205 : return FindTariffIndex;
1913 : }
1914 :
1915 2205 : void warnIfNativeVarname(
1916 : EnergyPlusData &state, std::string const &objName, int const curTariffIndex, bool &ErrorsFound, std::string const &curobjName)
1917 : {
1918 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1919 : // DATE WRITTEN March 2007
1920 :
1921 : // Issue a warning if the variable name (usually the object name) is
1922 : // one of the names of native variables
1923 2205 : auto &s_econ = state.dataEconTariff;
1924 :
1925 2205 : bool throwError = false;
1926 2205 : if (getEnumValue(nativeNamesUC, objName) != -1) {
1927 0 : throwError = true;
1928 2205 : } else if (getEnumValue(catNamesUC, objName) != -1) {
1929 0 : throwError = true;
1930 : }
1931 :
1932 2205 : if (throwError) {
1933 0 : ErrorsFound = true;
1934 0 : if (curTariffIndex >= 1 && curTariffIndex <= s_econ->numTariff) {
1935 0 : ShowSevereError(state, format("UtilityCost:Tariff=\"{}\" invalid referenced name", s_econ->tariff(curTariffIndex).tariffName));
1936 0 : ShowContinueError(state, format("{}=\"{}\" You cannot name an object using the same name as a native variable.", curobjName, objName));
1937 : } else {
1938 0 : ShowSevereError(state, format("{}=\"{}\" You cannot name an object using the same name as a native variable.", curobjName, objName));
1939 : }
1940 : }
1941 2205 : }
1942 :
1943 24819 : int AssignVariablePt(EnergyPlusData &state,
1944 : std::string_view const stringIn,
1945 : bool const flagIfNotNumeric,
1946 : int const useOfVar,
1947 : int const varSpecific,
1948 : ObjType const econObjKind,
1949 : int const objIndex,
1950 : int const tariffPt)
1951 : {
1952 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
1953 : // DATE WRITTEN May 2004
1954 :
1955 : // If the string is not numeric, check if it is a valid string to use as
1956 : // a variable name. Check if name has been used before and if not create
1957 : // the variable using the string as its name.
1958 : // Return the index of the variable.
1959 :
1960 24819 : auto &s_econ = state.dataEconTariff;
1961 : int AssignVariablePt;
1962 :
1963 24819 : if (flagIfNotNumeric && (len(stringIn) >= 1)) {
1964 20571 : std::string inNoSpaces = RemoveSpaces(state, stringIn);
1965 20571 : int found = 0;
1966 20571 : if (allocated(s_econ->econVar)) {
1967 1804304 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
1968 1788067 : if (s_econ->econVar(iVar).tariffIndx == tariffPt) {
1969 470786 : if (Util::SameString(s_econ->econVar(iVar).name, inNoSpaces)) {
1970 4233 : found = iVar;
1971 4233 : break;
1972 : }
1973 : }
1974 : }
1975 : }
1976 20571 : if (found > 0) {
1977 4233 : AssignVariablePt = found;
1978 4233 : if (s_econ->econVar(found).kindOfObj == ObjType::Invalid) {
1979 88 : s_econ->econVar(found).kindOfObj = econObjKind;
1980 88 : if (s_econ->econVar(found).index == 0) {
1981 88 : s_econ->econVar(found).index = objIndex;
1982 : }
1983 : }
1984 : } else {
1985 16338 : incrementEconVar(state);
1986 16338 : s_econ->econVar(s_econ->numEconVar).name = inNoSpaces;
1987 16338 : s_econ->econVar(s_econ->numEconVar).kindOfObj = econObjKind;
1988 16338 : s_econ->econVar(s_econ->numEconVar).index = objIndex;
1989 16338 : AssignVariablePt = s_econ->numEconVar;
1990 : }
1991 : // now set the flag for the type of usage the variable has
1992 20571 : if (useOfVar == varIsArgument) {
1993 13537 : s_econ->econVar(AssignVariablePt).isArgument = true;
1994 7034 : } else if (useOfVar == varIsAssigned) {
1995 7034 : s_econ->econVar(AssignVariablePt).isAssigned = true;
1996 : }
1997 20571 : s_econ->econVar(AssignVariablePt).tariffIndx = tariffPt;
1998 : // if the user defines the UtilityCost:Computation then this is called when reading the
1999 : // UtilityCost:Tariff with varNotYetDefined but they are already defined because
2000 : // the subroutine CreateCategoryNativeVariables has already been called.
2001 :
2002 : // if (!((varSpecific == varNotYetDefined) && (econVar(AssignVariablePt).specific >= catEnergyCharges))) {
2003 26909 : if ((varSpecific != varNotYetDefined) ||
2004 6338 : (s_econ->econVar(AssignVariablePt).kindOfObj != ObjType::Category && s_econ->econVar(AssignVariablePt).kindOfObj != ObjType::Native)) {
2005 16448 : s_econ->econVar(AssignVariablePt).specific = varSpecific;
2006 : }
2007 20571 : } else { // if the string was numeric return a zero
2008 4248 : AssignVariablePt = 0;
2009 : }
2010 24819 : return AssignVariablePt;
2011 : }
2012 :
2013 16338 : void incrementEconVar(EnergyPlusData &state)
2014 : {
2015 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2016 : // DATE WRITTEN May 2004
2017 :
2018 : // Increment the Increase the size of the
2019 :
2020 16338 : int constexpr sizeIncrement(100);
2021 16338 : auto &s_econ = state.dataEconTariff;
2022 :
2023 16338 : if (!allocated(s_econ->econVar)) {
2024 101 : s_econ->econVar.allocate(sizeIncrement);
2025 101 : s_econ->sizeEconVar = sizeIncrement;
2026 101 : s_econ->numEconVar = 1;
2027 : } else {
2028 16237 : ++s_econ->numEconVar;
2029 : // if larger than current size grow the array
2030 16237 : if (s_econ->numEconVar > s_econ->sizeEconVar) {
2031 105 : s_econ->econVar.redimension(s_econ->sizeEconVar += sizeIncrement);
2032 : }
2033 : }
2034 16338 : auto &econVar = s_econ->econVar(s_econ->numEconVar);
2035 :
2036 : // initialize new record) //Autodesk Most of these match default initialization so not needed
2037 16338 : econVar.name = "";
2038 16338 : econVar.tariffIndx = 0;
2039 16338 : econVar.kindOfObj = ObjType::Invalid;
2040 16338 : econVar.index = 0;
2041 16338 : std::fill(econVar.values.begin(), econVar.values.end(), 0.0);
2042 16338 : econVar.isArgument = false;
2043 16338 : econVar.isAssigned = false;
2044 16338 : econVar.specific = varNotYetDefined;
2045 : // econVar( numEconVar ).values = 0.0; //Autodesk Already initialized above
2046 : // Autodesk Don't initialize cntMeDependOn
2047 16338 : econVar.Operator = Op::Invalid;
2048 16338 : econVar.firstOperand = 1; // Autodesk Default initialization sets this to 0
2049 16338 : econVar.lastOperand = 0;
2050 16338 : econVar.activeNow = false;
2051 16338 : econVar.isEvaluated = false;
2052 : // Autodesk Don't initialize isReported
2053 : // Autodesk Don't initialize varUnitType
2054 16338 : }
2055 :
2056 17494 : void incrementSteps(EnergyPlusData &state)
2057 : {
2058 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2059 : // DATE WRITTEN June 2004
2060 :
2061 : // Increment the step array counter and if
2062 : // necessary increase the size of the array.
2063 :
2064 17494 : auto &s_econ = state.dataEconTariff;
2065 17494 : int constexpr sizeIncrement(100);
2066 :
2067 17494 : if (!allocated(s_econ->steps)) {
2068 101 : s_econ->steps.allocate(sizeIncrement);
2069 101 : s_econ->sizeSteps = sizeIncrement;
2070 101 : s_econ->numSteps = 1;
2071 : } else {
2072 17393 : ++s_econ->numSteps;
2073 : // if larger than current size grow the array
2074 17393 : if (s_econ->numSteps > s_econ->sizeSteps) {
2075 101 : s_econ->steps.redimension(s_econ->sizeSteps += sizeIncrement);
2076 : }
2077 : }
2078 : // initialize new record
2079 17494 : s_econ->steps(s_econ->numSteps).type = StepType::EOL;
2080 17494 : }
2081 :
2082 20571 : std::string RemoveSpaces(EnergyPlusData &state, std::string_view const StringIn)
2083 : {
2084 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2085 : // DATE WRITTEN May 2004
2086 :
2087 : // Return the string with all spaces removed.
2088 :
2089 20571 : std::string StringOut;
2090 20571 : bool foundSpaces = false;
2091 324553 : for (std::string::size_type iString = 0; iString < len(StringIn); ++iString) {
2092 303982 : if (StringIn[iString] != ' ') {
2093 303982 : StringOut += StringIn[iString];
2094 : } else {
2095 0 : foundSpaces = true;
2096 : }
2097 : }
2098 20571 : if (foundSpaces) {
2099 0 : ShowWarningError(state, format("UtilityCost: Spaces were removed from the variable=\"{}\".", StringIn));
2100 0 : ShowContinueError(state, format("...Resultant variable=\"{}\".", StringOut));
2101 : }
2102 20571 : return StringOut;
2103 0 : }
2104 :
2105 101 : void CreateCategoryNativeVariables(EnergyPlusData &state)
2106 : {
2107 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2108 : // DATE WRITTEN May 2004
2109 :
2110 : // For each tariff create variables that are used for the
2111 : // categories (i.e., EnergyCharges).
2112 :
2113 101 : auto &s_econ = state.dataEconTariff;
2114 402 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2115 301 : auto &tariff = s_econ->tariff(iTariff);
2116 :
2117 : // category variables first
2118 3311 : for (int iCat = 0; iCat < (int)Cat::Num; ++iCat) {
2119 3010 : tariff.cats[iCat] = AssignVariablePt(state, catNames[iCat], true, varIsAssigned, iCat, ObjType::Category, 0, iTariff);
2120 : }
2121 :
2122 301 : tariff.firstCategory = tariff.cats[(int)Cat::EnergyCharges];
2123 301 : tariff.lastCategory = tariff.cats[(int)Cat::NotIncluded];
2124 :
2125 : // category variables first
2126 :
2127 11438 : for (int iNative = 0; iNative < (int)Native::Num; ++iNative) {
2128 11137 : tariff.natives[iNative] = AssignVariablePt(state, nativeNames[iNative], true, varIsArgument, iNative, ObjType::Native, 0, iTariff);
2129 : }
2130 301 : tariff.firstNative = tariff.natives[(int)Native::TotalEnergy];
2131 301 : tariff.lastNative = tariff.natives[(int)Native::BelowCustomerBaseEnergy];
2132 : }
2133 101 : }
2134 :
2135 : //======================================================================================================================
2136 : //======================================================================================================================
2137 :
2138 : // DEFAULT COMPUTATION RELATED ROUTINES
2139 :
2140 : //======================================================================================================================
2141 : //======================================================================================================================
2142 :
2143 101 : void CreateDefaultComputation(EnergyPlusData &state)
2144 : {
2145 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2146 : // DATE WRITTEN June 2004
2147 :
2148 : // PURPOSE OF THIS SUBROUTINE:
2149 : // For most tariffs defined in EnergyPlus no specific
2150 : // ECONOMICS:COMPUTATION will be entered. In that case,
2151 : // a default sequence of computation steps needs to be
2152 : // created. This routine creates the default
2153 : // computation steps.
2154 : // Object Fields Depend On Fields
2155 : // Qualify namePt sourcePt
2156 : // thresholdPt
2157 : // Charge:Simple namePt sourcePt
2158 : // categoryPt costPerPt
2159 : // Charge:Block namePt sourcePt
2160 : // categoryPt blkSzMultPt
2161 : // remainingPt blkSzPt
2162 : // blkCostPt
2163 : // Ratchet namePt baselinePt
2164 : // adjustmentPt
2165 : // multiplierPt
2166 : // offsetPt
2167 : // These will be formed into expressions that look like
2168 : // namePt NOOP sourcePt thresholdPt
2169 : // The different Charges are combined using the SUM operation
2170 : // into categories.
2171 : // category SUM chg1Name chg2Name chg3Name
2172 : // Since the dependency array has one target and multiple
2173 : // parameters, remainingPt is shown as a separate equation that
2174 : // depends on namePt for Charge:Block. The equation will not be
2175 : // displayed or processed except in the sort.
2176 : // remainingPt NOOP namePt
2177 : // Many lines of the computation will include just the name of
2178 : // a single variable which triggers the calculation for that
2179 : // charge, ratchet or qualify.
2180 : // chg1Name
2181 : // It is also possible that two variables referenced within one
2182 : // object could include a dependency relationship also. For
2183 : // example, the blkSzPt could be calculated using the same sourePt
2184 : // in Charge:Block.
2185 :
2186 : // METHODOLOGY EMPLOYED:
2187 : // Since some ECONOMCIS:* objects depend on other variables
2188 : // first must create the order of when to perform the
2189 : // computations. First a dependency table is created that
2190 : // indicates what variables are dependent on other variables.
2191 : // A directed acyclic graph (DAG) describes the general
2192 : // problem which is usually solved using a topological
2193 : // sorting algorithm.
2194 : // Each line/step is generated and put into the depend
2195 : // array. Also in the array are counts of how many items it
2196 : // depends on and a list of entries that are dependent on that
2197 : // line.
2198 :
2199 101 : auto &s_econ = state.dataEconTariff;
2200 :
2201 : // for each tariff that does not have a UtilityCost:Computation object go through the variables
2202 402 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2203 301 : auto &tariff = s_econ->tariff(iTariff);
2204 301 : auto &computation = s_econ->computation(iTariff);
2205 301 : if (!computation.isUserDef) {
2206 : // clear all variables so that they are not active
2207 58847 : for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
2208 58547 : s_econ->econVar(jVar).activeNow = false;
2209 : }
2210 : // make all native variables active
2211 11400 : for (int jVar = tariff.firstNative; jVar <= tariff.lastNative; ++jVar) {
2212 11100 : s_econ->econVar(jVar).activeNow = true;
2213 : }
2214 : //"clear" the dependOn array
2215 300 : s_econ->numOperand = 0;
2216 : // Define the preset equations (category summation)
2217 300 : int curTotal = tariff.cats[(int)Cat::Total];
2218 300 : int curSubtotal = tariff.cats[(int)Cat::Subtotal];
2219 300 : int curBasis = tariff.cats[(int)Cat::Basis];
2220 : // total SUM subtotal taxes
2221 300 : s_econ->econVar(curTotal).Operator = Op::SUM;
2222 300 : s_econ->econVar(curTotal).activeNow = true;
2223 300 : addOperand(state, curTotal, curSubtotal);
2224 300 : addOperand(state, curTotal, tariff.cats[(int)Cat::Taxes]);
2225 : // subtotal SUM basis adjustments surcharges
2226 300 : s_econ->econVar(curSubtotal).Operator = Op::SUM;
2227 300 : s_econ->econVar(curSubtotal).activeNow = true;
2228 300 : addOperand(state, curSubtotal, curBasis);
2229 300 : addOperand(state, curSubtotal, tariff.cats[(int)Cat::Adjustment]);
2230 300 : addOperand(state, curSubtotal, tariff.cats[(int)Cat::Surcharge]);
2231 : // basis SUM EnergyCharges DemandCharges ServiceCharges
2232 300 : s_econ->econVar(curBasis).Operator = Op::SUM;
2233 300 : s_econ->econVar(curBasis).activeNow = true;
2234 300 : addOperand(state, curBasis, tariff.cats[(int)Cat::EnergyCharges]);
2235 300 : addOperand(state, curBasis, tariff.cats[(int)Cat::DemandCharges]);
2236 300 : addOperand(state, curBasis, tariff.cats[(int)Cat::ServiceCharges]);
2237 : // set up the equations for other objects
2238 300 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::EnergyCharges]);
2239 300 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::DemandCharges]);
2240 300 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::ServiceCharges]);
2241 300 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Adjustment]);
2242 300 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Surcharge]);
2243 300 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Taxes]);
2244 : // add the real time pricing to the energy charges
2245 300 : if (tariff.chargeSched != nullptr) {
2246 1 : addOperand(state, tariff.cats[(int)Cat::EnergyCharges], tariff.natives[(int)Native::RealTimePriceCosts]);
2247 : }
2248 : // now add equations with NOOP to represent each object with its
2249 : // dependencies
2250 : // Qualify
2251 1048 : for (int kObj = 1; kObj <= s_econ->numQualify; ++kObj) {
2252 748 : auto const &qualify = s_econ->qualify(kObj);
2253 748 : if (qualify.tariffIndx == iTariff) {
2254 217 : int curObject = qualify.namePt;
2255 217 : s_econ->econVar(curObject).Operator = Op::NOOP;
2256 217 : s_econ->econVar(curObject).activeNow = true;
2257 217 : addOperand(state, curObject, qualify.sourcePt);
2258 217 : addOperand(state, curObject, qualify.thresholdPt);
2259 : }
2260 : }
2261 : // Ratchet
2262 314 : for (int kObj = 1; kObj <= s_econ->numRatchet; ++kObj) {
2263 14 : auto const &ratchet = s_econ->ratchet(kObj);
2264 14 : if (ratchet.tariffIndx == iTariff) {
2265 1 : int curObject = ratchet.namePt;
2266 1 : s_econ->econVar(curObject).Operator = Op::NOOP;
2267 1 : s_econ->econVar(curObject).activeNow = true;
2268 1 : addOperand(state, curObject, ratchet.baselinePt);
2269 1 : addOperand(state, curObject, ratchet.adjustmentPt);
2270 1 : addOperand(state, curObject, ratchet.multiplierPt);
2271 1 : addOperand(state, curObject, ratchet.offsetPt);
2272 : }
2273 : }
2274 : // ChargeSimple
2275 5498 : for (int kObj = 1; kObj <= s_econ->numChargeSimple; ++kObj) {
2276 5198 : auto const &chargeSimple = s_econ->chargeSimple(kObj);
2277 5198 : if (chargeSimple.tariffIndx == iTariff) {
2278 1610 : int curObject = chargeSimple.namePt;
2279 1610 : s_econ->econVar(curObject).Operator = Op::NOOP;
2280 1610 : s_econ->econVar(curObject).activeNow = true;
2281 1610 : addOperand(state, curObject, chargeSimple.sourcePt);
2282 1610 : addOperand(state, curObject, chargeSimple.costPerPt);
2283 : }
2284 : }
2285 : // ChargeBlock
2286 1282 : for (int kObj = 1; kObj <= s_econ->numChargeBlock; ++kObj) {
2287 982 : auto const &chargeBlock = s_econ->chargeBlock(kObj);
2288 982 : if (chargeBlock.tariffIndx == iTariff) {
2289 285 : int curObject = chargeBlock.namePt;
2290 285 : s_econ->econVar(curObject).Operator = Op::NOOP;
2291 285 : s_econ->econVar(curObject).activeNow = true;
2292 285 : addOperand(state, curObject, chargeBlock.sourcePt);
2293 285 : addOperand(state, curObject, chargeBlock.blkSzMultPt);
2294 1234 : for (int mBlock = 1; mBlock <= chargeBlock.numBlk; ++mBlock) {
2295 949 : addOperand(state, curObject, chargeBlock.blkSzPt(mBlock));
2296 949 : addOperand(state, curObject, chargeBlock.blkCostPt(mBlock));
2297 : }
2298 : // now add a new "equation" for dependency of remainingPt on namePt
2299 285 : int remainPt = chargeBlock.remainingPt;
2300 285 : if (remainPt > 0) {
2301 1 : s_econ->econVar(remainPt).Operator = Op::NOOP;
2302 1 : s_econ->econVar(remainPt).activeNow = true;
2303 1 : addOperand(state, remainPt, curObject);
2304 : }
2305 : }
2306 : }
2307 : // Economic:Variable
2308 : // make all of the user defined variables as active
2309 58847 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2310 58547 : if (s_econ->econVar(iVar).tariffIndx == iTariff) {
2311 16284 : if (s_econ->econVar(iVar).kindOfObj == ObjType::Variable) {
2312 86 : s_econ->econVar(iVar).activeNow = true;
2313 : }
2314 : }
2315 : }
2316 : // make sure no computation is already user defined
2317 300 : if (computation.firstStep != 0) {
2318 0 : ShowWarningError(state, format("In UtilityCost:Tariff: Overwriting user defined tariff {}", tariff.tariffName));
2319 : }
2320 : // initialize the computation
2321 300 : computation.computeName = "Autogenerated - " + tariff.tariffName;
2322 300 : computation.firstStep = s_econ->numSteps + 1;
2323 300 : computation.lastStep = -1; // this will be incremented by addStep
2324 300 : computation.isUserDef = false;
2325 : // now all "equations" are defined, treat the variables with the list
2326 : // of dependencies as a directed acyclic graph and use "count down" algorithm
2327 : // to do a topological sort of the variables into the order for computation
2328 : // First, clear the counters
2329 58847 : for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
2330 58547 : s_econ->econVar(jVar).cntMeDependOn = 0;
2331 : }
2332 : // Second, add up the number of dependencies on each variable
2333 58847 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2334 58547 : if (s_econ->econVar(iVar).activeNow) {
2335 15984 : if (s_econ->econVar(iVar).lastOperand >= s_econ->econVar(iVar).firstOperand) {
2336 3624 : s_econ->econVar(iVar).cntMeDependOn = 1 + s_econ->econVar(iVar).lastOperand - s_econ->econVar(iVar).firstOperand;
2337 : }
2338 : }
2339 : }
2340 : // Third, start removing items with zero connections and decrease each
2341 : // counter.
2342 300 : int numNoDepend = -1;
2343 300 : int loopCount = 0;
2344 1565 : while ((numNoDepend != 0) || (loopCount > 100000)) {
2345 1265 : numNoDepend = 0;
2346 240114 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2347 238849 : if (s_econ->econVar(iVar).activeNow) {
2348 : // find a variable that has no more dangling dependencies
2349 18947 : if (s_econ->econVar(iVar).cntMeDependOn == 0) {
2350 : // If the variable is a native variable then
2351 : // IF (econVar(iVar)%kindOfObj .NE. iEconVarObjType::Native) THEN
2352 15984 : if ((s_econ->econVar(iVar).kindOfObj != ObjType::Native) && (s_econ->econVar(iVar).kindOfObj != ObjType::Variable)) {
2353 4798 : if (s_econ->econVar(iVar).lastOperand >= s_econ->econVar(iVar).firstOperand) {
2354 : // transfer variables and operator to the computation and list of steps
2355 : // go through the operands backwards (end of line is evaluated first)
2356 10214 : for (int kOperand = s_econ->econVar(iVar).lastOperand; kOperand >= s_econ->econVar(iVar).firstOperand;
2357 : --kOperand) {
2358 6590 : incrementSteps(state);
2359 6590 : s_econ->steps(s_econ->numSteps) = s_econ->operands(kOperand);
2360 : }
2361 : // append the operator (either SUM or NOOP)
2362 3624 : incrementSteps(state);
2363 3624 : s_econ->steps(s_econ->numSteps).type = StepType::Op;
2364 3624 : s_econ->steps(s_econ->numSteps).op = s_econ->econVar(iVar).Operator;
2365 : // append the variable itself
2366 3624 : incrementSteps(state);
2367 3624 : s_econ->steps(s_econ->numSteps).type = StepType::Var;
2368 3624 : s_econ->steps(s_econ->numSteps).varNum = iVar;
2369 : // at the end of the line show a zero to clear the stack
2370 3624 : incrementSteps(state);
2371 3624 : s_econ->steps(s_econ->numSteps).type = StepType::EOL;
2372 : }
2373 : }
2374 : // go through each other variable looking for places where this variable is used
2375 : // and decrement their counters.
2376 3099009 : for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
2377 3083025 : if (s_econ->econVar(jVar).activeNow) {
2378 760876 : for (int kOperand = s_econ->econVar(jVar).firstOperand; kOperand <= s_econ->econVar(jVar).lastOperand;
2379 : ++kOperand) {
2380 325003 : int referVar = s_econ->operands(kOperand).varNum;
2381 325003 : if (iVar == referVar) {
2382 6590 : --s_econ->econVar(jVar).cntMeDependOn;
2383 : // for each variable that has been decremented to zero increment the counter
2384 6590 : if (s_econ->econVar(jVar).cntMeDependOn <= 0) {
2385 3624 : ++numNoDepend;
2386 : }
2387 : }
2388 : }
2389 : }
2390 : }
2391 : // make the variable inactive
2392 15984 : s_econ->econVar(iVar).activeNow = false;
2393 : }
2394 : }
2395 : }
2396 1265 : ++loopCount;
2397 : }
2398 300 : if (loopCount > 100000) {
2399 0 : ShowWarningError(state,
2400 0 : format("UtilityCost:Tariff: Loop count exceeded when counting dependencies in tariff: {}", tariff.tariffName));
2401 : }
2402 : // make sure that all variables associated with the tariff are included
2403 300 : bool remainingVarFlag = false;
2404 58847 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2405 58547 : if (s_econ->econVar(iVar).activeNow) {
2406 0 : remainingVarFlag = true;
2407 : }
2408 : }
2409 300 : if (remainingVarFlag) {
2410 0 : ShowWarningError(state,
2411 0 : format("CreateDefaultComputation: In UtilityCost:Computation: Circular or invalid dependencies found in tariff: {}",
2412 0 : tariff.tariffName));
2413 0 : ShowContinueError(state, " UtilityCost variables that may have invalid dependencies and the variables they are dependent on.");
2414 0 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2415 0 : if (s_econ->econVar(iVar).tariffIndx == iTariff) {
2416 0 : if (s_econ->econVar(iVar).activeNow) {
2417 0 : ShowContinueError(state, format(" {}", s_econ->econVar(iVar).name));
2418 0 : for (int kOperand = s_econ->econVar(iVar).firstOperand; kOperand <= s_econ->econVar(iVar).lastOperand; ++kOperand) {
2419 0 : ShowContinueError(state, format(" -> {}", s_econ->econVar(s_econ->operands(kOperand).varNum).name));
2420 : }
2421 : }
2422 : }
2423 : }
2424 : }
2425 : // set the end of the computations
2426 300 : computation.lastStep = s_econ->numSteps;
2427 300 : if (computation.firstStep >= computation.lastStep) {
2428 0 : computation.firstStep = 0;
2429 0 : computation.lastStep = -1;
2430 0 : ShowWarningError(state,
2431 0 : format("CreateDefaultComputation: In UtilityCost:Computation: No lines in the auto-generated computation can be "
2432 : "interpreted in tariff: {}",
2433 0 : tariff.tariffName));
2434 : }
2435 : }
2436 : }
2437 101 : }
2438 :
2439 10422 : void addOperand(EnergyPlusData &state, int const varMe, int const varOperand)
2440 : {
2441 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2442 : // DATE WRITTEN July 2004
2443 :
2444 : // Used by CreateDefaultComputation to create the dependency
2445 : // relationship in the EconVar array
2446 :
2447 10422 : int constexpr sizeIncrement(100);
2448 10422 : auto &s_econ = state.dataEconTariff;
2449 :
2450 10422 : if (varOperand != 0) {
2451 : // increment the numOperand and allocate/reallocate the array
2452 : // if necessary
2453 6590 : if (!allocated(s_econ->operands)) {
2454 101 : s_econ->operands.allocate(sizeIncrement);
2455 101 : s_econ->sizeOperand = sizeIncrement;
2456 101 : s_econ->numOperand = 1;
2457 : } else {
2458 6489 : ++s_econ->numOperand;
2459 : // if larger than current size grow the array
2460 6489 : if (s_econ->numOperand > s_econ->sizeOperand) {
2461 0 : s_econ->operands.redimension(s_econ->sizeOperand += sizeIncrement);
2462 : }
2463 : }
2464 6590 : auto &econVar = s_econ->econVar(varMe);
2465 :
2466 : // now add the dependency relationship
2467 6590 : s_econ->operands(s_econ->numOperand).type = StepType::Var;
2468 6590 : s_econ->operands(s_econ->numOperand).varNum = varOperand;
2469 6590 : econVar.lastOperand = s_econ->numOperand;
2470 : // if it is the first time addOperand was called with the varMe value
2471 : // then set the first pointer as well
2472 6590 : if (varMe != s_econ->addOperand_prevVarMe) {
2473 3624 : econVar.firstOperand = s_econ->numOperand;
2474 3624 : s_econ->addOperand_prevVarMe = varMe;
2475 : }
2476 : }
2477 10422 : }
2478 :
2479 1800 : void addChargesToOperand(EnergyPlusData &state, int const curTariff, int const curPointer)
2480 : {
2481 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2482 : // DATE WRITTEN July 2004
2483 :
2484 : // Used by CreateDefaultComputation to create the "equation"
2485 : // for the categories that are summations of ECONOMICS:CHARGES:BLOCK
2486 : // and ECONOMICS:CHARGES:SIMPLE
2487 :
2488 1800 : auto const &s_econ = state.dataEconTariff;
2489 1800 : auto const &chargeSimple = s_econ->chargeSimple;
2490 1800 : auto const &chargeBlock = s_econ->chargeBlock;
2491 :
2492 1800 : s_econ->econVar(curPointer).Operator = Op::SUM;
2493 1800 : s_econ->econVar(curPointer).activeNow = true;
2494 32988 : for (int kObj = 1; kObj <= s_econ->numChargeSimple; ++kObj) {
2495 31188 : if (chargeSimple(kObj).tariffIndx == curTariff) {
2496 9660 : if (chargeSimple(kObj).categoryPt == curPointer) {
2497 1610 : addOperand(state, curPointer, chargeSimple(kObj).namePt);
2498 : }
2499 : }
2500 : }
2501 7692 : for (int kObj = 1; kObj <= s_econ->numChargeBlock; ++kObj) {
2502 5892 : if (chargeBlock(kObj).tariffIndx == curTariff) {
2503 1710 : if (chargeBlock(kObj).categoryPt == curPointer) {
2504 284 : addOperand(state, curPointer, chargeBlock(kObj).namePt);
2505 : }
2506 : }
2507 : }
2508 1800 : }
2509 :
2510 : //======================================================================================================================
2511 : //======================================================================================================================
2512 :
2513 : // GATHER TIMESTEP VALUES ROUTINE
2514 :
2515 : //======================================================================================================================
2516 : //======================================================================================================================
2517 :
2518 254136 : void GatherForEconomics(EnergyPlusData &state)
2519 : {
2520 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2521 : // DATE WRITTEN June 2004
2522 :
2523 : // Gathers the data each timestep and updates the arrays
2524 : // holding the data that will be used by the tariff
2525 : // calculation.
2526 :
2527 : Real64 curInstantValue;
2528 : Real64 curDemand;
2529 : Real64 curEnergy;
2530 : Real64 curRTPprice; // real time price
2531 : Real64 curRTPbaseline; // real time price customer baseline load
2532 : Real64 curRTPenergy; // energy applied to real time price
2533 : Real64 curRTPcost; // cost for energy for current time
2534 :
2535 254136 : auto &s_econ = state.dataEconTariff;
2536 :
2537 254136 : if (s_econ->numTariff >= 1) {
2538 70080 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2539 35040 : auto &tariff = s_econ->tariff(iTariff);
2540 : // if the meter is defined get the value
2541 35040 : if (tariff.reportMeterIndx != -1) {
2542 35040 : curInstantValue = GetCurrentMeterValue(state, tariff.reportMeterIndx);
2543 : } else {
2544 0 : curInstantValue = 0.0;
2545 : }
2546 : // remember the demand is still energy over a period of time divided by the
2547 : // length of time. This gathers the energy also.
2548 35040 : tariff.collectEnergy += curInstantValue;
2549 35040 : tariff.collectTime += state.dataGlobal->TimeStepZoneSec;
2550 : // added *SecInHour when adding RTP support August 2008
2551 35040 : if (tariff.collectTime >= tariff.demWinTime * Constant::rSecsInHour) {
2552 : // get current value that has been converted into desired units
2553 35040 : curDemand = tariff.demandConv * tariff.collectEnergy / tariff.collectTime;
2554 35040 : curEnergy = tariff.energyConv * tariff.collectEnergy;
2555 : // get the schedule values
2556 : // remember no confirmation of schedule values occurs prior to now
2557 : // The season schedule
2558 35040 : Season curSeason = (tariff.seasonSched != nullptr) ? static_cast<Season>(tariff.seasonSched->getCurrentVal()) : Season::Winter;
2559 35040 : int curPeriod = (tariff.periodSched != nullptr) ? tariff.periodSched->getCurrentVal() : 1;
2560 :
2561 : int curMonth =
2562 0 : (tariff.monthSched != nullptr) ? tariff.monthSched->getCurrentVal() :
2563 : // #7814 - Have to be careful with DST. tariff::seasonForMonth is overwritten at each timestep, and
2564 : // only the last value is retained, so make sure to capture the right one
2565 70080 : (((state.dataGlobal->HourOfDay + state.dataEnvrn->DSTIndicator) <= Constant::iHoursInDay) ? state.dataEnvrn->Month
2566 105120 : : state.dataEnvrn->MonthTomorrow);
2567 :
2568 35040 : bool isGood = false;
2569 35040 : if (curSeason == Season::Winter || curSeason == Season::Spring || curSeason == Season::Summer || curSeason == Season::Fall ||
2570 : curSeason == Season::Annual) {
2571 35040 : if (isWithinRange(state, curPeriod, 1, 4)) {
2572 35040 : if (isWithinRange(state, curMonth, 1, 12)) {
2573 35040 : isGood = true;
2574 : }
2575 : }
2576 : }
2577 35040 : if (isGood) {
2578 35040 : tariff.seasonForMonth(curMonth) = curSeason;
2579 35040 : tariff.gatherEnergy(curMonth)[(int)curPeriod] += curEnergy;
2580 35040 : if (tariff.gatherDemand(curMonth)[(int)curPeriod] < curDemand) {
2581 377 : tariff.gatherDemand(curMonth)[(int)curPeriod] = curDemand;
2582 : }
2583 : } else {
2584 0 : ShowWarningError(state, format("UtilityCost:Tariff: While gathering for: {}", tariff.tariffName));
2585 0 : ShowContinueError(state, "Invalid schedule values - outside of range");
2586 : }
2587 : // Real Time Pricing
2588 35040 : if (tariff.chargeSched != nullptr) {
2589 0 : curRTPprice = tariff.chargeSched->getCurrentVal();
2590 : // if customer baseline load schedule is used, subtract that off of the
2591 : // current energy
2592 0 : if (tariff.baseUseSched != nullptr) {
2593 0 : curRTPbaseline = tariff.baseUseSched->getCurrentVal();
2594 0 : curRTPenergy = curEnergy - curRTPbaseline;
2595 : } else {
2596 0 : curRTPenergy = curEnergy;
2597 : }
2598 : // calculate the real time cost for current times energy
2599 0 : curRTPcost = curRTPenergy * curRTPprice;
2600 0 : tariff.RTPcost(curMonth) += curRTPcost;
2601 0 : if (curRTPcost > 0) {
2602 0 : tariff.RTPaboveBaseCost(curMonth) += curRTPcost;
2603 : } else {
2604 0 : tariff.RTPbelowBaseCost(curMonth) += curRTPcost;
2605 : }
2606 0 : if (curRTPenergy > 0) {
2607 0 : tariff.RTPaboveBaseEnergy(curMonth) += curRTPenergy;
2608 : } else {
2609 0 : tariff.RTPbelowBaseEnergy(curMonth) += curRTPenergy;
2610 : }
2611 : }
2612 : // reset the counters
2613 35040 : tariff.collectEnergy = 0.0;
2614 35040 : tariff.collectTime = 0.0;
2615 : }
2616 : }
2617 : }
2618 254136 : }
2619 :
2620 71598 : bool isWithinRange(EnergyPlusData &state, int const testVal, int const minThreshold, int const maxThreshold)
2621 : {
2622 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2623 : // DATE WRITTEN July 2004
2624 :
2625 : // Simple function to check if an integer is equal to or between
2626 : // two other values.
2627 :
2628 : bool isWithinRange;
2629 :
2630 71598 : if (maxThreshold < minThreshold) {
2631 0 : ShowWarningError(state, "UtilityCost: Invalid thresholds in IsWithinRange routine.");
2632 : }
2633 71598 : if ((testVal <= maxThreshold) && (testVal >= minThreshold)) {
2634 71598 : isWithinRange = true;
2635 : } else {
2636 0 : isWithinRange = false;
2637 : }
2638 71598 : return isWithinRange;
2639 : }
2640 :
2641 : //======================================================================================================================
2642 : //======================================================================================================================
2643 :
2644 : // COMPUTE THE UTILITY BILLS AND CREATE REPORTS
2645 :
2646 : //======================================================================================================================
2647 : //======================================================================================================================
2648 :
2649 799 : void ComputeTariff(EnergyPlusData &state)
2650 : {
2651 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
2652 : // DATE WRITTEN July 2004
2653 :
2654 : // Perform the calculation steps to compute the monthly
2655 : // utility bills for the user entered tariffs.
2656 : // The list of steps for the tariff computation are in order
2657 : // for stack based computation (reverse polish notation)
2658 :
2659 799 : auto &s_econ = state.dataEconTariff;
2660 :
2661 : // values used in specific operations
2662 799 : Array1D<Real64> a(NumMonths);
2663 799 : Array1D<Real64> b(NumMonths);
2664 799 : Array1D<Real64> c(NumMonths);
2665 799 : Array1D<Real64> d(NumMonths);
2666 :
2667 799 : int constexpr noVar(0);
2668 :
2669 : Real64 annualAggregate;
2670 :
2671 799 : if (!state.files.outputControl.writeTabular(state)) {
2672 1 : state.dataOutRptTab->WriteTabularFiles = false;
2673 1 : return;
2674 : }
2675 :
2676 798 : Real64 hugeValue = HUGE_(Real64());
2677 : // Clear the isEvaluated flags for all economics variables.
2678 16971 : for (int nVar = 1; nVar <= s_econ->numEconVar; ++nVar) {
2679 16173 : s_econ->econVar(nVar).isEvaluated = false;
2680 : }
2681 :
2682 798 : if (s_econ->numTariff == 0) {
2683 698 : return;
2684 : }
2685 :
2686 100 : state.dataOutRptTab->WriteTabularFiles = true;
2687 100 : setNativeVariables(state);
2688 : int aPt;
2689 : int bPt;
2690 : int cPt;
2691 398 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2692 17608 : for (int jStep = s_econ->computation(iTariff).firstStep; jStep <= s_econ->computation(iTariff).lastStep; ++jStep) {
2693 17310 : auto const &step = s_econ->steps(jStep);
2694 17310 : int annualCnt = 0;
2695 :
2696 : // end of line - assign variable and clear stack
2697 : // if the stack still has two items on it then assign the values to the
2698 : // pointer otherwise if it follows a NOOP line it will only have one item
2699 : // that has already been assigned and no further action is required.
2700 17310 : if (step.type == StepType::EOL) {
2701 3592 : if (s_econ->topOfStack >= 2) {
2702 1517 : popStack(state, b, bPt); // pop the variable pointer
2703 1517 : popStack(state, a, aPt); // pop the values
2704 1517 : if (isWithinRange(state, bPt, 1, s_econ->numEconVar)) {
2705 1517 : s_econ->econVar(bPt).values = a;
2706 : }
2707 : }
2708 3592 : s_econ->topOfStack = 0;
2709 :
2710 : // Variable
2711 13718 : } else if (step.type == StepType::Var) {
2712 10126 : pushStack(state, s_econ->econVar(step.varNum).values, step.varNum);
2713 :
2714 : // Operator
2715 3592 : } else if (step.type == StepType::Op) {
2716 3592 : switch (step.op) {
2717 :
2718 1517 : case Op::SUM: {
2719 1517 : a = 0.0;
2720 5781 : for (int kStack = 1, kStack_end = s_econ->topOfStack; kStack <= kStack_end; ++kStack) { // popStack modifies topOfStack
2721 4264 : popStack(state, b, bPt);
2722 4264 : a += b;
2723 : }
2724 1517 : pushStack(state, a, noVar);
2725 1517 : } break;
2726 :
2727 0 : case Op::MULTIPLY: {
2728 0 : popStack(state, b, bPt);
2729 0 : popStack(state, a, aPt);
2730 0 : pushStack(state, a * b, noVar);
2731 0 : } break;
2732 :
2733 0 : case Op::SUBTRACT: {
2734 0 : popStack(state, b, bPt);
2735 0 : popStack(state, a, aPt);
2736 0 : pushStack(state, b - a, noVar);
2737 0 : } break;
2738 :
2739 0 : case Op::DIVIDE: {
2740 0 : popStack(state, a, aPt);
2741 0 : popStack(state, b, bPt);
2742 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2743 0 : c(lMonth) = (b(lMonth) != 0.0) ? (a(lMonth) / b(lMonth)) : 0.0;
2744 : }
2745 0 : pushStack(state, c, noVar);
2746 0 : } break;
2747 :
2748 0 : case Op::ABSOLUTEVALUE: {
2749 0 : popStack(state, a, aPt);
2750 0 : pushStack(state, ObjexxFCL::abs(a), noVar);
2751 0 : } break;
2752 :
2753 0 : case Op::INTEGER: {
2754 0 : popStack(state, a, aPt);
2755 0 : pushStack(state, Array1D_double(Array1D_int(a)), noVar);
2756 0 : } break;
2757 :
2758 0 : case Op::SIGN: {
2759 0 : popStack(state, a, aPt);
2760 0 : pushStack(state, sign(1.0, a), noVar);
2761 : // CASE (opROUND)
2762 : // CALL popStack(b,bPt)
2763 : // CALL popStack(a,aPt)
2764 : // DO lMonth = 1,MaxNumMonths
2765 : // IF ((b(lMonth) .LE. 5) .AND. (b(lMonth) .GE. -5)) THEN
2766 : // c(lMonth) = FLOAT(INT(a(lMonth) / (10 ** b(lMonth))) * (10 ** b(lMonth)))
2767 : // END IF
2768 : // END DO
2769 : // CALL pushStack(c,noVar)
2770 0 : } break;
2771 :
2772 0 : case Op::MAXIMUM: {
2773 0 : a = -hugeValue;
2774 0 : for (int kStack = 1, kStack_end = s_econ->topOfStack; kStack <= kStack_end; ++kStack) { // popStack modifies topOfStack
2775 0 : popStack(state, b, bPt);
2776 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2777 0 : if (b(lMonth) > a(lMonth)) {
2778 0 : a(lMonth) = b(lMonth);
2779 : }
2780 : }
2781 : }
2782 0 : pushStack(state, a, noVar);
2783 0 : } break;
2784 :
2785 0 : case Op::MINIMUM: {
2786 0 : a = hugeValue;
2787 0 : for (int kStack = 1, kStack_end = s_econ->topOfStack; kStack <= kStack_end; ++kStack) { // popStack modifies topOfStack
2788 0 : popStack(state, b, bPt);
2789 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2790 0 : if (b(lMonth) < a(lMonth)) {
2791 0 : a(lMonth) = b(lMonth);
2792 : }
2793 : }
2794 : }
2795 0 : pushStack(state, a, noVar);
2796 0 : } break;
2797 :
2798 0 : case Op::EXCEEDS: {
2799 0 : popStack(state, b, bPt);
2800 0 : popStack(state, a, aPt);
2801 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2802 0 : if (a(lMonth) > b(lMonth)) {
2803 0 : c(lMonth) = a(lMonth) - b(lMonth);
2804 : } else {
2805 0 : c(lMonth) = 0.0;
2806 : }
2807 : }
2808 0 : pushStack(state, c, noVar);
2809 0 : } break;
2810 :
2811 0 : case Op::ANNUALMINIMUM: {
2812 : // takes the minimum but ignores zeros
2813 0 : annualAggregate = hugeValue;
2814 0 : popStack(state, a, aPt);
2815 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2816 0 : if (a(lMonth) != 0) {
2817 0 : if (a(lMonth) < annualAggregate) {
2818 0 : annualAggregate = a(lMonth);
2819 : }
2820 : }
2821 : }
2822 : // if all months are zero then hugeValue still in annual but should be zero
2823 0 : if (annualAggregate == hugeValue) {
2824 0 : annualAggregate = 0.0;
2825 : }
2826 0 : c = annualAggregate;
2827 0 : pushStack(state, c, noVar);
2828 0 : } break;
2829 :
2830 0 : case Op::ANNUALMAXIMUM: {
2831 : // takes the maximum but ignores zeros
2832 0 : annualAggregate = -hugeValue;
2833 0 : popStack(state, a, aPt);
2834 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2835 0 : if (a(lMonth) != 0) {
2836 0 : if (a(lMonth) > annualAggregate) {
2837 0 : annualAggregate = a(lMonth);
2838 : }
2839 : }
2840 : }
2841 : // if all months are zero then hugeValue still in annual but should be zero
2842 0 : if (annualAggregate == -hugeValue) {
2843 0 : annualAggregate = 0.0;
2844 : }
2845 0 : c = annualAggregate;
2846 0 : pushStack(state, c, noVar);
2847 0 : } break;
2848 :
2849 0 : case Op::ANNUALSUM: {
2850 : // takes the maximum but ignores zeros
2851 0 : annualAggregate = 0.0;
2852 0 : popStack(state, a, aPt);
2853 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2854 0 : annualAggregate += a(lMonth);
2855 : }
2856 0 : c = annualAggregate;
2857 0 : pushStack(state, c, noVar);
2858 0 : } break;
2859 :
2860 0 : case Op::ANNUALAVERAGE: {
2861 : // takes the annual sum but ignores zeros
2862 0 : annualAggregate = 0.0;
2863 0 : popStack(state, a, aPt);
2864 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2865 0 : if (a(lMonth) != 0) {
2866 0 : annualAggregate += a(lMonth);
2867 0 : ++annualCnt;
2868 : }
2869 : }
2870 : // if all months are zero then return zero
2871 0 : c = (annualCnt != 0) ? (annualAggregate / annualCnt) : 0.0;
2872 0 : pushStack(state, c, noVar);
2873 0 : } break;
2874 :
2875 0 : case Op::ANNUALOR: {
2876 0 : popStack(state, a, aPt);
2877 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2878 0 : if (a(lMonth) != 0) {
2879 0 : ++annualCnt;
2880 : }
2881 : }
2882 : // if any months is not zero then "true"
2883 0 : c = (annualCnt >= 1) ? 1.0 : 0.0;
2884 0 : pushStack(state, c, noVar);
2885 0 : } break;
2886 :
2887 0 : case Op::ANNUALAND: {
2888 0 : popStack(state, a, aPt);
2889 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2890 0 : if (a(lMonth) != 0) {
2891 0 : ++annualCnt;
2892 : }
2893 : }
2894 : // if all months are not zero then "true"
2895 0 : c = (annualCnt == NumMonths) ? 1.0 : 0.0;
2896 0 : pushStack(state, c, noVar);
2897 0 : } break;
2898 :
2899 0 : case Op::ANNUALMAXIMUMZERO: {
2900 : // takes the maximum including zeros
2901 0 : annualAggregate = -hugeValue;
2902 0 : popStack(state, a, aPt);
2903 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2904 0 : if (a(lMonth) > annualAggregate) {
2905 0 : annualAggregate = a(lMonth);
2906 : }
2907 : }
2908 0 : c = annualAggregate;
2909 0 : pushStack(state, c, noVar);
2910 0 : } break;
2911 :
2912 0 : case Op::ANNUALMINIMUMZERO: {
2913 : // takes the maximum including zeros
2914 0 : annualAggregate = hugeValue;
2915 0 : popStack(state, a, aPt);
2916 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2917 0 : if (a(lMonth) < annualAggregate) {
2918 0 : annualAggregate = a(lMonth);
2919 : }
2920 : }
2921 0 : c = annualAggregate;
2922 0 : pushStack(state, c, noVar);
2923 0 : } break;
2924 :
2925 0 : case Op::IF: {
2926 0 : popStack(state, c, cPt);
2927 0 : popStack(state, b, bPt);
2928 0 : popStack(state, a, aPt);
2929 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2930 0 : d(lMonth) = (a(lMonth) != 0) ? b(lMonth) : c(lMonth);
2931 : }
2932 0 : pushStack(state, d, noVar);
2933 0 : } break;
2934 :
2935 0 : case Op::GREATERTHAN: {
2936 0 : popStack(state, b, bPt);
2937 0 : popStack(state, a, aPt);
2938 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2939 0 : c(lMonth) = (a(lMonth) > b(lMonth)) ? 1.0 : 0.0;
2940 : }
2941 0 : pushStack(state, c, noVar);
2942 0 : } break;
2943 :
2944 0 : case Op::GREATEREQUAL: {
2945 0 : popStack(state, b, bPt);
2946 0 : popStack(state, a, aPt);
2947 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2948 0 : if (a(lMonth) >= b(lMonth)) {
2949 0 : c(lMonth) = 1.0;
2950 : } else {
2951 0 : c(lMonth) = 0.0;
2952 : }
2953 : }
2954 0 : pushStack(state, c, noVar);
2955 0 : } break;
2956 :
2957 0 : case Op::LESSTHAN: {
2958 0 : popStack(state, b, bPt);
2959 0 : popStack(state, a, aPt);
2960 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2961 0 : c(lMonth) = (a(lMonth) < b(lMonth)) ? 1.0 : 0.0;
2962 : }
2963 0 : pushStack(state, c, noVar);
2964 0 : } break;
2965 :
2966 0 : case Op::LESSEQUAL: {
2967 0 : popStack(state, b, bPt);
2968 0 : popStack(state, a, aPt);
2969 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2970 0 : c(lMonth) = (a(lMonth) <= b(lMonth)) ? 1.0 : 0.0;
2971 : }
2972 0 : pushStack(state, c, noVar);
2973 0 : } break;
2974 :
2975 0 : case Op::EQUAL: {
2976 0 : popStack(state, b, bPt);
2977 0 : popStack(state, a, aPt);
2978 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2979 0 : c(lMonth) = (a(lMonth) == b(lMonth)) ? 1.0 : 0.0;
2980 : }
2981 0 : pushStack(state, c, noVar);
2982 0 : } break;
2983 :
2984 0 : case Op::NOTEQUAL: {
2985 0 : popStack(state, b, bPt);
2986 0 : popStack(state, a, aPt);
2987 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2988 0 : c(lMonth) = (a(lMonth) != b(lMonth)) ? 1.0 : 0.0;
2989 : }
2990 0 : pushStack(state, c, noVar);
2991 0 : } break;
2992 :
2993 0 : case Op::AND: {
2994 0 : popStack(state, b, bPt);
2995 0 : popStack(state, a, aPt);
2996 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
2997 0 : c(lMonth) = ((a(lMonth) != 0) && (b(lMonth) != 0)) ? 1.0 : 0.0;
2998 : }
2999 0 : pushStack(state, c, noVar);
3000 0 : } break;
3001 :
3002 0 : case Op::OR: {
3003 0 : popStack(state, b, bPt);
3004 0 : popStack(state, a, aPt);
3005 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
3006 0 : c(lMonth) = ((a(lMonth) != 0) || (b(lMonth) != 0)) ? 1.0 : 0.0;
3007 : }
3008 0 : pushStack(state, c, noVar);
3009 0 : } break;
3010 :
3011 0 : case Op::NOT: {
3012 0 : popStack(state, a, aPt);
3013 0 : for (int lMonth = 1; lMonth <= NumMonths; ++lMonth) {
3014 0 : c(lMonth) = (a(lMonth) == 0) ? 1.0 : 0.0;
3015 : }
3016 0 : pushStack(state, c, noVar);
3017 0 : } break;
3018 :
3019 0 : case Op::ADD: {
3020 0 : popStack(state, b, bPt);
3021 0 : popStack(state, a, aPt);
3022 0 : pushStack(state, a + b, noVar);
3023 0 : } break;
3024 :
3025 2075 : case Op::NOOP: {
3026 : // do nothing but clear the stack
3027 2075 : s_econ->topOfStack = 0;
3028 : // No longer pushing a zero to fix bug
3029 : // and push zero
3030 : // a = 0
3031 2075 : } break;
3032 :
3033 0 : default: {
3034 0 : } break;
3035 : }
3036 : }
3037 : }
3038 298 : checkMinimumMonthlyCharge(state, iTariff);
3039 : }
3040 100 : selectTariff(state);
3041 100 : LEEDtariffReporting(state);
3042 2896 : }
3043 :
3044 11643 : void pushStack(EnergyPlusData &state, Array1A<Real64> const monthlyArray, int const variablePointer)
3045 : {
3046 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3047 : // DATE WRITTEN July 2004
3048 :
3049 : // A stack is used in the evaluation of the tariff since
3050 : // the variables and operators are in a reverse polish
3051 : // notation order. The stack operates on a last-in
3052 : // first out basis. The stack consists of both a pointer
3053 : // to the variable and the twelve monthly values.
3054 : // This routine puts an item on the top of the stack.
3055 :
3056 11643 : monthlyArray.dim(NumMonths);
3057 :
3058 11643 : Array1D<Real64> curMonthlyArray(NumMonths);
3059 11643 : int constexpr sizeIncrement(50);
3060 :
3061 11643 : auto &s_econ = state.dataEconTariff;
3062 11643 : auto &stack = s_econ->stack;
3063 11643 : auto const &econVar = s_econ->econVar;
3064 11643 : auto const &tariff = s_econ->tariff;
3065 :
3066 11643 : curMonthlyArray = monthlyArray;
3067 11643 : if (!allocated(stack)) {
3068 100 : stack.allocate(sizeIncrement);
3069 100 : s_econ->sizeStack = sizeIncrement;
3070 100 : s_econ->topOfStack = 1;
3071 : } else {
3072 11543 : ++s_econ->topOfStack;
3073 : // if larger than current size grow the array
3074 11543 : if (s_econ->topOfStack > s_econ->sizeStack) {
3075 0 : stack.redimension(s_econ->sizeStack += sizeIncrement);
3076 : }
3077 : }
3078 : // now push the values on to the stack
3079 11643 : stack(s_econ->topOfStack).varPt = variablePointer;
3080 : // check if variable has been evaluated if it is CHARGE:SIMPLE, CHARGE:BLOCK, RATCHET, or QUALIFY
3081 : // if it has not overwrite the values for monthlyArray with the evaluated values
3082 11643 : if (variablePointer != 0) {
3083 10126 : if (!econVar(variablePointer).isEvaluated) {
3084 :
3085 8249 : switch (econVar(variablePointer).kindOfObj) {
3086 1585 : case ObjType::ChargeSimple:
3087 1585 : evaluateChargeSimple(state, variablePointer);
3088 1585 : break;
3089 277 : case ObjType::ChargeBlock:
3090 277 : evaluateChargeBlock(state, variablePointer);
3091 277 : break;
3092 1 : case ObjType::Ratchet:
3093 1 : evaluateRatchet(state, variablePointer);
3094 1 : break;
3095 215 : case ObjType::Qualify:
3096 215 : evaluateQualify(state, variablePointer);
3097 215 : break;
3098 0 : case ObjType::Invalid:
3099 0 : ShowWarningError(state, format("UtilityCost variable not defined: {}", econVar(variablePointer).name));
3100 0 : ShowContinueError(state, format(" In tariff: {}", tariff(econVar(variablePointer).tariffIndx).tariffName));
3101 0 : ShowContinueError(state, " This may be the result of a misspelled variable name in the UtilityCost:Computation object.");
3102 0 : ShowContinueError(state, " All zero values will be assumed for this variable.");
3103 0 : break;
3104 6171 : case ObjType::Variable:
3105 : case ObjType::Category:
3106 : case ObjType::Native:
3107 : case ObjType::AssignCompute:
3108 : case ObjType::Tariff:
3109 : case ObjType::Computation:
3110 : // do nothing
3111 6171 : break;
3112 0 : default:
3113 0 : ShowWarningError(state,
3114 0 : format("UtilityCost Debugging issue. Invalid kind of variable used (pushStack). {} in tariff: {}",
3115 0 : econVar(variablePointer).kindOfObj,
3116 0 : tariff(econVar(variablePointer).tariffIndx).tariffName));
3117 : }
3118 : // if the serviceCharges are being evaluated add in the monthly charges
3119 8249 : if (econVar(variablePointer).kindOfObj == ObjType::Category && econVar(variablePointer).specific == (int)Cat::ServiceCharges) {
3120 298 : addMonthlyCharge(state, variablePointer);
3121 : }
3122 : // get the results of performing the evaluation - should have been
3123 : // put into the econVar values
3124 8249 : curMonthlyArray = econVar(variablePointer).values;
3125 : }
3126 : }
3127 : // now assign
3128 11643 : stack(s_econ->topOfStack).values = curMonthlyArray;
3129 11643 : }
3130 :
3131 7298 : void popStack(EnergyPlusData &state, Array1A<Real64> monthlyArray, int &variablePointer)
3132 : {
3133 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3134 : // DATE WRITTEN July 2004
3135 :
3136 : // A stack is used in the evaluation of the tariff since
3137 : // the variables and operators are in a reverse polish
3138 : // notation order. The stack operates on a last-in
3139 : // first out basis. The stack consists of both a pointer
3140 : // to the variable and the twelve monthly values.
3141 : // This routine returns the item on the top of the stack
3142 : // and removes it from the stack.
3143 :
3144 7298 : monthlyArray.dim(NumMonths);
3145 :
3146 7298 : auto &s_econ = state.dataEconTariff;
3147 7298 : auto const &stack = s_econ->stack;
3148 :
3149 7298 : if (s_econ->topOfStack >= 1) {
3150 7298 : variablePointer = stack(s_econ->topOfStack).varPt;
3151 7298 : monthlyArray = stack(s_econ->topOfStack).values;
3152 : } else {
3153 0 : ShowWarningError(
3154 : state,
3155 0 : format("UtilityCost:Tariff: stack underflow in calculation of utility bills. On variable: {}", s_econ->econVar(variablePointer).name));
3156 0 : variablePointer = 0;
3157 0 : monthlyArray = {0.0};
3158 0 : s_econ->topOfStack = 0;
3159 : }
3160 7298 : --s_econ->topOfStack;
3161 7298 : }
3162 :
3163 1585 : void evaluateChargeSimple(EnergyPlusData &state, int const usingVariable)
3164 : {
3165 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3166 : // DATE WRITTEN July 2004
3167 :
3168 1585 : Array1D<Real64> sourceVals(NumMonths);
3169 1585 : Array1D<Real64> costPer(NumMonths);
3170 1585 : Array1D<Real64> resultChg(NumMonths);
3171 1585 : Array1D<Real64> seasonMask(NumMonths);
3172 :
3173 1585 : auto &s_econ = state.dataEconTariff;
3174 1585 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3175 1585 : auto const &tariff = s_econ->tariff(curTariff);
3176 1585 : int indexInChg = s_econ->econVar(usingVariable).index;
3177 1585 : auto const &chargeSimple = s_econ->chargeSimple(indexInChg);
3178 :
3179 : // check the tariff - make sure they match
3180 1585 : if (chargeSimple.namePt != usingVariable) {
3181 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. ChargeSimple index does not match variable pointer.");
3182 0 : ShowContinueError(state, format(" Between: {}", s_econ->econVar(usingVariable).name));
3183 0 : ShowContinueError(state, format(" And: {}", s_econ->econVar(chargeSimple.namePt).name));
3184 : }
3185 1585 : if (chargeSimple.tariffIndx != curTariff) {
3186 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. ChargeSimple index does not match tariff index.");
3187 0 : ShowContinueError(state, format(" Between: {}", tariff.tariffName));
3188 0 : ShowContinueError(state, format(" And: {}", s_econ->tariff(chargeSimple.tariffIndx).tariffName));
3189 : }
3190 : // data from the Charge:Simple
3191 1585 : sourceVals = s_econ->econVar(chargeSimple.sourcePt).values;
3192 : // determine if costPer should be based on variable or value
3193 1585 : if (chargeSimple.costPerPt != 0) {
3194 84 : costPer = s_econ->econVar(chargeSimple.costPerPt).values;
3195 : } else {
3196 1501 : costPer = chargeSimple.costPerVal;
3197 : }
3198 : // find proper season mask
3199 1585 : if (chargeSimple.season == Season::Summer) {
3200 87 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3201 1498 : } else if (chargeSimple.season == Season::Winter) {
3202 57 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3203 1441 : } else if (chargeSimple.season == Season::Spring) {
3204 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3205 1441 : } else if (chargeSimple.season == Season::Fall) {
3206 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3207 1441 : } else if (chargeSimple.season == Season::Annual) {
3208 1441 : seasonMask = 1.0; // all months are 1
3209 : }
3210 :
3211 : // finally perform calculations
3212 1585 : resultChg = sourceVals * costPer * seasonMask;
3213 : // store the cost in the name of the variable
3214 1585 : s_econ->econVar(usingVariable).values = resultChg;
3215 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3216 1585 : s_econ->econVar(usingVariable).isEvaluated = true;
3217 1585 : }
3218 :
3219 277 : void evaluateChargeBlock(EnergyPlusData &state, int const usingVariable)
3220 : {
3221 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3222 : // DATE WRITTEN July 2004
3223 :
3224 277 : Array1D<Real64> sourceVals(NumMonths);
3225 277 : Array1D<Real64> blkSzMult(NumMonths);
3226 277 : Array1D<Real64> remainVals(NumMonths);
3227 277 : Array1D<Real64> resultChg(NumMonths);
3228 277 : Array1D<Real64> amountForBlk(NumMonths);
3229 277 : Array1D<Real64> curBlkSz(NumMonths);
3230 277 : Array1D<Real64> curBlkCost(NumMonths);
3231 277 : Array1D<Real64> seasonMask(NumMonths);
3232 :
3233 277 : auto &s_econ = state.dataEconTariff;
3234 277 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3235 277 : auto const &tariff = s_econ->tariff(curTariff);
3236 277 : int indexInChg = s_econ->econVar(usingVariable).index;
3237 277 : auto const &chargeBlock = s_econ->chargeBlock(indexInChg);
3238 :
3239 : // check the tariff - make sure they match
3240 277 : if (chargeBlock.namePt != usingVariable) {
3241 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. chargeBlock index does not match variable pointer.");
3242 0 : ShowContinueError(state, format(" Between: {}", s_econ->econVar(usingVariable).name));
3243 0 : ShowContinueError(state, format(" And: {}", s_econ->econVar(chargeBlock.namePt).name));
3244 : }
3245 277 : if (chargeBlock.tariffIndx != curTariff) {
3246 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. chargeBlock index does not match tariff index.");
3247 0 : ShowContinueError(state, format(" Between: {}", tariff.tariffName));
3248 0 : ShowContinueError(state, format(" And: {}", s_econ->tariff(chargeBlock.tariffIndx).tariffName));
3249 : }
3250 : // data from the chargeBlock
3251 277 : sourceVals = s_econ->econVar(chargeBlock.sourcePt).values;
3252 : // find proper season mask
3253 :
3254 277 : if (chargeBlock.season == Season::Summer) {
3255 16 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3256 261 : } else if (chargeBlock.season == Season::Winter) {
3257 6 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3258 255 : } else if (chargeBlock.season == Season::Spring) {
3259 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3260 255 : } else if (chargeBlock.season == Season::Fall) {
3261 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3262 255 : } else if (chargeBlock.season == Season::Annual) {
3263 255 : seasonMask = 1.0; // all months are 1
3264 : }
3265 : // get block size multiplier
3266 277 : if (chargeBlock.blkSzMultPt != 0) {
3267 89 : blkSzMult = s_econ->econVar(chargeBlock.blkSzMultPt).values;
3268 : } else {
3269 188 : blkSzMult = chargeBlock.blkSzMultVal;
3270 : }
3271 : // initially set the remaining energy or demand to the source
3272 277 : remainVals = sourceVals;
3273 : // initially set the result (cost) to zero
3274 277 : resultChg = 0.0;
3275 : // loop through the blocks performing calculations
3276 1200 : for (int iBlk = 1; iBlk <= chargeBlock.numBlk; ++iBlk) {
3277 923 : if (chargeBlock.blkSzPt(iBlk) != 0) {
3278 0 : curBlkSz = s_econ->econVar(chargeBlock.blkSzPt(iBlk)).values;
3279 : } else {
3280 923 : curBlkSz = chargeBlock.blkSzVal(iBlk);
3281 : }
3282 923 : if (chargeBlock.blkCostPt(iBlk) != 0) {
3283 0 : curBlkCost = s_econ->econVar(chargeBlock.blkCostPt(iBlk)).values;
3284 : } else {
3285 923 : curBlkCost = chargeBlock.blkCostVal(iBlk);
3286 : }
3287 : // loop through the months
3288 11999 : for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
3289 11076 : if (seasonMask(jMonth) == 1) {
3290 : // IF ((curBlkSz(jMonth) * blkSzMult(jMonth)) .GT. remainVals(jMonth)) THEN - CR 6547
3291 10392 : if (blkSzMult(jMonth) != 0) {
3292 7716 : if (curBlkSz(jMonth) > (remainVals(jMonth) / blkSzMult(jMonth))) {
3293 7715 : amountForBlk(jMonth) = remainVals(jMonth);
3294 : } else {
3295 1 : amountForBlk(jMonth) = curBlkSz(jMonth) * blkSzMult(jMonth);
3296 : }
3297 : } else {
3298 2676 : amountForBlk(jMonth) = 0.0;
3299 : }
3300 10392 : resultChg(jMonth) += amountForBlk(jMonth) * curBlkCost(jMonth);
3301 10392 : remainVals(jMonth) -= amountForBlk(jMonth);
3302 : }
3303 : }
3304 : }
3305 : // store the amount remaining if a variable is specified
3306 277 : if (chargeBlock.remainingPt != 0) {
3307 1 : s_econ->econVar(chargeBlock.remainingPt).values = remainVals;
3308 : } else {
3309 276 : bool flagAllZero = true;
3310 3588 : for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
3311 3312 : if (seasonMask(jMonth) == 1) {
3312 3048 : if (remainVals(jMonth) != 0) {
3313 0 : flagAllZero = false;
3314 : }
3315 : }
3316 : }
3317 276 : if (!flagAllZero) {
3318 0 : ShowWarningError(
3319 : state,
3320 0 : format("UtilityCost:Tariff Not all energy or demand was assigned in the block charge: {}", s_econ->econVar(usingVariable).name));
3321 : }
3322 : }
3323 : // store the cost in the name of the variable
3324 277 : s_econ->econVar(usingVariable).values = resultChg;
3325 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3326 277 : s_econ->econVar(usingVariable).isEvaluated = true;
3327 277 : }
3328 :
3329 1 : void evaluateRatchet(EnergyPlusData &state, int const usingVariable)
3330 : {
3331 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3332 : // DATE WRITTEN July 2004
3333 :
3334 1 : Array1D<Real64> baselineVals(NumMonths);
3335 1 : Array1D<Real64> adjustmentVals(NumMonths);
3336 1 : Array1D<Real64> multiplierVals(NumMonths);
3337 1 : Array1D<Real64> offsetVals(NumMonths);
3338 1 : Array1D<Real64> seasonFromMask(NumMonths);
3339 1 : Array1D<Real64> seasonToMask(NumMonths);
3340 1 : Array1D<Real64> adjSeasonal(NumMonths);
3341 1 : Array1D<Real64> adjPeak(NumMonths);
3342 1 : Array1D<Real64> maxAdjBase(NumMonths);
3343 1 : Array1D<Real64> finalResult(NumMonths);
3344 :
3345 1 : auto &s_econ = state.dataEconTariff;
3346 1 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3347 1 : auto const &tariff = s_econ->tariff(curTariff);
3348 1 : int indexInChg = s_econ->econVar(usingVariable).index;
3349 1 : auto const &ratchet = s_econ->ratchet(indexInChg);
3350 1 : bool isMonthly = false;
3351 :
3352 : // check the tariff - make sure they match
3353 1 : if (ratchet.namePt != usingVariable) {
3354 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Ratchet index does not match variable pointer.");
3355 0 : ShowContinueError(state, format(" Between: {}", s_econ->econVar(usingVariable).name));
3356 0 : ShowContinueError(state, format(" And: {}", s_econ->econVar(ratchet.namePt).name));
3357 : }
3358 1 : if (ratchet.tariffIndx != curTariff) {
3359 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Ratchet index does not match tariff index.");
3360 0 : ShowContinueError(state, format(" Between: {}", tariff.tariffName));
3361 0 : ShowContinueError(state, format(" And: {}", s_econ->tariff(ratchet.tariffIndx).tariffName));
3362 : }
3363 : // data from the Ratchet
3364 1 : baselineVals = s_econ->econVar(ratchet.baselinePt).values;
3365 1 : adjustmentVals = s_econ->econVar(ratchet.adjustmentPt).values;
3366 : // determine if multiplier should be based on variable or value
3367 1 : if (ratchet.multiplierPt != 0) {
3368 0 : multiplierVals = s_econ->econVar(ratchet.multiplierPt).values;
3369 : } else {
3370 1 : multiplierVals = ratchet.multiplierVal;
3371 : }
3372 : // determine if offset should be based on variable or value
3373 1 : if (ratchet.offsetPt != 0) {
3374 0 : offsetVals = s_econ->econVar(ratchet.offsetPt).values;
3375 : } else {
3376 1 : offsetVals = ratchet.offsetVal;
3377 : }
3378 : // find proper season from mask
3379 1 : if (ratchet.seasonFrom == Season::Summer) {
3380 1 : seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3381 1 : isMonthly = false;
3382 0 : } else if (ratchet.seasonFrom == Season::Winter) {
3383 0 : seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3384 0 : isMonthly = false;
3385 0 : } else if (ratchet.seasonFrom == Season::Spring) {
3386 0 : seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3387 0 : isMonthly = false;
3388 0 : } else if (ratchet.seasonFrom == Season::Fall) {
3389 0 : seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3390 0 : isMonthly = false;
3391 0 : } else if (ratchet.seasonFrom == Season::Annual) {
3392 0 : seasonFromMask = 1.0; // all months are 1
3393 0 : isMonthly = false;
3394 0 : } else if (ratchet.seasonFrom == Season::Monthly) {
3395 0 : seasonFromMask = 1.0; // all months are 1
3396 0 : isMonthly = true;
3397 : } else {
3398 0 : assert(false);
3399 : }
3400 :
3401 : // find proper season to mask
3402 1 : if (ratchet.seasonTo == Season::Summer) {
3403 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3404 1 : } else if (ratchet.seasonTo == Season::Winter) {
3405 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3406 1 : } else if (ratchet.seasonTo == Season::Spring) {
3407 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3408 1 : } else if (ratchet.seasonTo == Season::Fall) {
3409 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3410 1 : } else if (ratchet.seasonTo == Season::Annual) {
3411 1 : seasonToMask = 1.0; // all months are 1
3412 : }
3413 : // finally perform calculations
3414 1 : if (isMonthly) {
3415 0 : adjSeasonal = adjustmentVals;
3416 : } else {
3417 1 : Real64 maximumVal = -HUGE_(Real64());
3418 13 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3419 12 : if (seasonFromMask(iMonth) == 1) {
3420 0 : if (adjustmentVals(iMonth) > maximumVal) {
3421 0 : maximumVal = adjustmentVals(iMonth);
3422 : }
3423 : }
3424 : }
3425 1 : adjSeasonal = maximumVal;
3426 : }
3427 13 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3428 : // calculate adjusted peak value after offset and multiplier
3429 12 : adjPeak(iMonth) = (adjSeasonal(iMonth) + offsetVals(iMonth)) * multiplierVals(iMonth);
3430 : // the maximum of the adjustment and the baseline
3431 12 : if (adjPeak(iMonth) > baselineVals(iMonth)) {
3432 0 : maxAdjBase(iMonth) = adjPeak(iMonth);
3433 : } else {
3434 12 : maxAdjBase(iMonth) = baselineVals(iMonth);
3435 : }
3436 : }
3437 13 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3438 12 : if (seasonToMask(iMonth) == 1) {
3439 12 : finalResult(iMonth) = maxAdjBase(iMonth);
3440 : } else {
3441 0 : finalResult(iMonth) = baselineVals(iMonth);
3442 : }
3443 : }
3444 : // store the cost in the name of the variable
3445 1 : s_econ->econVar(usingVariable).values = finalResult;
3446 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3447 1 : s_econ->econVar(usingVariable).isEvaluated = true;
3448 1 : }
3449 :
3450 215 : void evaluateQualify(EnergyPlusData &state, int const usingVariable)
3451 : {
3452 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3453 : // DATE WRITTEN July 2004
3454 :
3455 215 : Array1D<Real64> sourceVals(NumMonths);
3456 215 : Array1D<Real64> thresholdVals(NumMonths);
3457 215 : Array1D_int monthsQualify(NumMonths);
3458 215 : Array1D<Real64> seasonMask(NumMonths);
3459 : int adjNumberOfMonths;
3460 : bool isQualified;
3461 :
3462 215 : auto &s_econ = state.dataEconTariff;
3463 215 : auto &econVar = s_econ->econVar(usingVariable);
3464 :
3465 215 : int curTariff = econVar.tariffIndx;
3466 215 : auto &tariff = s_econ->tariff(curTariff);
3467 215 : int indexInQual = econVar.index;
3468 215 : auto const &qualify = s_econ->qualify(indexInQual);
3469 : // check the tariff - make sure they match
3470 215 : if (qualify.namePt != usingVariable) {
3471 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Qualify index does not match variable pointer.");
3472 0 : ShowContinueError(state, format(" Between: {}", econVar.name));
3473 0 : ShowContinueError(state, format(" And: {}", s_econ->econVar(qualify.namePt).name));
3474 : }
3475 215 : if (qualify.tariffIndx != curTariff) {
3476 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Qualify index does not match tariff index.");
3477 0 : ShowContinueError(state, format(" Between: {}", tariff.tariffName));
3478 0 : ShowContinueError(state, format(" And: {}", s_econ->tariff(qualify.tariffIndx).tariffName));
3479 : }
3480 : // data from the Qualify
3481 215 : sourceVals = s_econ->econVar(qualify.sourcePt).values;
3482 215 : bool curIsMaximum = qualify.isMaximum;
3483 215 : bool curIsConsecutive = qualify.isConsecutive;
3484 215 : int curNumberOfMonths = qualify.numberOfMonths;
3485 : // determine if threshold should be based on variable or value
3486 215 : if (qualify.thresholdPt != 0) {
3487 0 : thresholdVals = s_econ->econVar(qualify.thresholdPt).values;
3488 : } else {
3489 215 : thresholdVals = qualify.thresholdVal;
3490 : }
3491 : // find proper season mask
3492 :
3493 215 : if (qualify.season == Season::Summer) {
3494 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3495 215 : } else if (qualify.season == Season::Winter) {
3496 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3497 215 : } else if (qualify.season == Season::Spring) {
3498 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3499 215 : } else if (qualify.season == Season::Fall) {
3500 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3501 215 : } else if (qualify.season == Season::Annual) {
3502 215 : seasonMask = 1.0; // all months are 1
3503 : }
3504 :
3505 : // any months with no energy use are excluded from the qualification process
3506 2795 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3507 2580 : if (s_econ->econVar(tariff.natives[(int)Native::TotalEnergy]).values(iMonth) == 0) {
3508 2580 : seasonMask(iMonth) = 0.0;
3509 : }
3510 : }
3511 : // finally perform calculations
3512 : // loop through the months
3513 215 : int monthsInSeason = 0;
3514 2795 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3515 2580 : if (seasonMask(iMonth) == 1) {
3516 0 : ++monthsInSeason;
3517 : // use threshold as maximum or minimum
3518 0 : if (curIsMaximum) {
3519 0 : if (sourceVals(iMonth) > thresholdVals(iMonth)) {
3520 0 : monthsQualify(iMonth) = 0; // greater than maximum threshold so it is not qualified
3521 : } else {
3522 0 : monthsQualify(iMonth) = 1; // less than maximum threshold so it is qualified
3523 : }
3524 : } else {
3525 0 : if (sourceVals(iMonth) < thresholdVals(iMonth)) {
3526 0 : monthsQualify(iMonth) = 0; // less than minimum threshold so it is not qualified
3527 : } else {
3528 0 : monthsQualify(iMonth) = 1; // greater than minimum threshold so it is qualified
3529 : }
3530 : }
3531 : } else {
3532 2580 : monthsQualify(iMonth) = -1; // flag that indicates not part of the season
3533 : }
3534 : }
3535 : // see if the number of months is longer then the number of months and adjust
3536 215 : if (curNumberOfMonths > monthsInSeason) {
3537 215 : adjNumberOfMonths = monthsInSeason;
3538 : } else {
3539 0 : adjNumberOfMonths = curNumberOfMonths;
3540 : }
3541 : // now that each month is qualified or not, depending on the type of test see if the entire qualify pass or not
3542 215 : int cntAllQualMonths = 0;
3543 215 : int cntConsecQualMonths = 0;
3544 215 : int maxConsecQualMonths = 0;
3545 2795 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3546 : {
3547 2580 : int const SELECT_CASE_var(monthsQualify(iMonth));
3548 2580 : if (SELECT_CASE_var == 1) { // qualified
3549 0 : ++cntAllQualMonths;
3550 0 : ++cntConsecQualMonths;
3551 : // see if the count is greater then the previous count and if it is make it the new count
3552 0 : if (cntConsecQualMonths > maxConsecQualMonths) {
3553 0 : maxConsecQualMonths = cntConsecQualMonths;
3554 : }
3555 2580 : } else if (SELECT_CASE_var == 0) { // not qualified
3556 : // reset the counter on consecutive months
3557 0 : cntConsecQualMonths = 0;
3558 : }
3559 : }
3560 : }
3561 : // if test is for consecutive months
3562 215 : if (curIsConsecutive) {
3563 0 : if (maxConsecQualMonths >= adjNumberOfMonths) {
3564 0 : isQualified = true;
3565 : } else {
3566 0 : isQualified = false;
3567 : }
3568 : } else { // count not consecutive
3569 215 : if (cntAllQualMonths >= adjNumberOfMonths) {
3570 215 : isQualified = true;
3571 : } else {
3572 0 : isQualified = false;
3573 : }
3574 : }
3575 : // now update the tariff level qualifier - only update if the tariff is still qualified
3576 : // and the current qualifier fails.
3577 215 : if (tariff.isQualified) {
3578 215 : if (!isQualified) {
3579 0 : tariff.isQualified = false;
3580 0 : tariff.ptDisqualifier = usingVariable;
3581 : }
3582 : }
3583 : // store the cost in the name of the variable
3584 215 : econVar.values = monthsQualify;
3585 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3586 215 : econVar.isEvaluated = true;
3587 215 : }
3588 :
3589 298 : void addMonthlyCharge(EnergyPlusData &state, int const usingVariable)
3590 : {
3591 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3592 : // DATE WRITTEN July 2004
3593 :
3594 : // Include the monthly charges in the calculations
3595 :
3596 298 : auto &s_econ = state.dataEconTariff;
3597 298 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3598 298 : auto const &tariff = s_econ->tariff(curTariff);
3599 : // check the tariff - make sure they match
3600 298 : if (tariff.cats[(int)Cat::ServiceCharges] != usingVariable) {
3601 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging issue. Tariff index for service charge does not match variable pointer.");
3602 0 : ShowContinueError(state, format(" Between: {}", tariff.tariffName));
3603 0 : ShowContinueError(state, format(" And: {}", s_econ->tariff(tariff.cats[(int)Cat::ServiceCharges]).tariffName));
3604 : }
3605 298 : if (tariff.monthChgPt != 0) {
3606 1 : s_econ->econVar(usingVariable).values += s_econ->econVar(tariff.monthChgPt).values;
3607 : } else {
3608 297 : s_econ->econVar(usingVariable).values += tariff.monthChgVal;
3609 : }
3610 : // zero out months with no energy consumption
3611 : // curTotalEnergy = tariff.nativeTotalEnergy
3612 : // DO iMonth = 1, NumMonths
3613 : // IF (s_econ->econVar(curTotalEnergy)%values(iMonth) .EQ. 0) THEN
3614 : // s_econ->econVar(usingVariable)%values(iMonth) = 0
3615 : // END IF
3616 : // END DO
3617 298 : }
3618 :
3619 298 : void checkMinimumMonthlyCharge(EnergyPlusData &state, int const curTariff)
3620 : {
3621 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3622 : // DATE WRITTEN August 2008
3623 :
3624 : // Check if the total is as big as the minimum monthly charge
3625 :
3626 298 : auto &s_econ = state.dataEconTariff;
3627 298 : auto const &tariff = s_econ->tariff(curTariff);
3628 :
3629 298 : int totalVar = tariff.cats[(int)Cat::Total];
3630 298 : int minMonVar = tariff.minMonthChgPt;
3631 : // if a variable is defined use that
3632 298 : if (minMonVar != 0) {
3633 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3634 0 : if (s_econ->econVar(totalVar).values(iMonth) < s_econ->econVar(minMonVar).values(iMonth)) {
3635 0 : s_econ->econVar(totalVar).values(iMonth) = s_econ->econVar(minMonVar).values(iMonth);
3636 : }
3637 : }
3638 : } else { // use the constant value
3639 3874 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3640 3576 : if (s_econ->econVar(totalVar).values(iMonth) < tariff.minMonthChgVal) {
3641 24 : s_econ->econVar(totalVar).values(iMonth) = tariff.minMonthChgVal;
3642 : }
3643 : }
3644 : }
3645 298 : }
3646 :
3647 100 : void setNativeVariables(EnergyPlusData &state)
3648 : {
3649 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3650 : // DATE WRITTEN July 2004
3651 :
3652 : // Set up the "built in" i.e. native variables that hold
3653 : // the energy and demand from the simulation.
3654 :
3655 100 : auto &s_econ = state.dataEconTariff;
3656 :
3657 100 : Array1D<Real64> monthVal(NumMonths);
3658 100 : Real64 bigNumber(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
3659 :
3660 100 : bigNumber = HUGE_(bigNumber);
3661 398 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
3662 298 : auto &tariff = s_econ->tariff(iTariff);
3663 : // nativeTotalEnergy
3664 298 : monthVal = 0.0;
3665 3874 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3666 21456 : for (int jPeriod = 0; jPeriod < (int)Period::Num; ++jPeriod) {
3667 17880 : monthVal(kMonth) += tariff.gatherEnergy(kMonth)[jPeriod];
3668 : }
3669 : }
3670 298 : s_econ->econVar(tariff.natives[(int)Native::TotalEnergy]).values = monthVal;
3671 : // nativeTotalDemand
3672 298 : monthVal = -bigNumber;
3673 3874 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3674 21456 : for (int jPeriod = 0; jPeriod < (int)Period::Num; ++jPeriod) {
3675 17880 : if (tariff.gatherDemand(kMonth)[jPeriod] > monthVal(kMonth)) {
3676 3588 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[jPeriod];
3677 : }
3678 : }
3679 : }
3680 : // if no maximum was set just set to zero
3681 3874 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3682 3576 : if (monthVal(kMonth) == -bigNumber) {
3683 0 : monthVal(kMonth) = 0.0;
3684 : }
3685 : }
3686 298 : s_econ->econVar(tariff.natives[(int)Native::TotalDemand]).values = monthVal;
3687 3874 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3688 : // nativePeakEnergy
3689 3576 : s_econ->econVar(tariff.natives[(int)Native::PeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::Peak];
3690 : // nativePeakDemand
3691 3576 : s_econ->econVar(tariff.natives[(int)Native::PeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3692 : // nativeShoulderEnergy
3693 3576 : s_econ->econVar(tariff.natives[(int)Native::ShoulderEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::Shoulder];
3694 : // nativeShoulderDemand
3695 3576 : s_econ->econVar(tariff.natives[(int)Native::ShoulderDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
3696 : // nativeOffPeakEnergy
3697 3576 : s_econ->econVar(tariff.natives[(int)Native::OffPeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
3698 : // nativeOffPeakDemand
3699 3576 : s_econ->econVar(tariff.natives[(int)Native::OffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3700 : // nativeMidPeakEnergy
3701 3576 : s_econ->econVar(tariff.natives[(int)Native::MidPeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::MidPeak];
3702 : // nativeMidPeakDemand
3703 3576 : s_econ->econVar(tariff.natives[(int)Native::MidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
3704 : // nativePeakExceedsOffPeak
3705 3576 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3706 3576 : if (monthVal(kMonth) > 0) {
3707 12 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = monthVal(kMonth);
3708 : } else {
3709 3564 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = 0.0;
3710 : }
3711 : // nativeOffPeakExceedsPeak
3712 3576 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
3713 3576 : if (monthVal(kMonth) > 0) {
3714 0 : s_econ->econVar(tariff.natives[(int)Native::OffPeakExceedsPeak]).values(kMonth) = monthVal(kMonth);
3715 : } else {
3716 3576 : s_econ->econVar(tariff.natives[(int)Native::OffPeakExceedsPeak]).values(kMonth) = 0.0;
3717 : }
3718 : // nativePeakExceedsMidPeak
3719 3576 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
3720 3576 : if (monthVal(kMonth) > 0) {
3721 12 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsMidPeak]).values(kMonth) = monthVal(kMonth);
3722 : } else {
3723 3564 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = 0.0;
3724 : }
3725 : // nativeMidPeakExceedsPeak
3726 3576 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
3727 3576 : if (monthVal(kMonth) > 0) {
3728 0 : s_econ->econVar(tariff.natives[(int)Native::MidPeakExceedsPeak]).values(kMonth) = monthVal(kMonth);
3729 : } else {
3730 3576 : s_econ->econVar(tariff.natives[(int)Native::MidPeakExceedsPeak]).values(kMonth) = 0.0;
3731 : }
3732 : // nativePeakExceedsShoulder
3733 3576 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
3734 3576 : if (monthVal(kMonth) > 0) {
3735 12 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsShoulder]).values(kMonth) = monthVal(kMonth);
3736 : } else {
3737 3564 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsShoulder]).values(kMonth) = 0.0;
3738 : }
3739 : // nativeShoulderExceedsPeak
3740 3576 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Shoulder] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
3741 3576 : if (monthVal(kMonth) > 0) {
3742 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderExceedsPeak]).values(kMonth) = monthVal(kMonth);
3743 : } else {
3744 3576 : s_econ->econVar(tariff.natives[(int)Native::ShoulderExceedsPeak]).values(kMonth) = 0.0;
3745 : }
3746 : // nativeIsWinter
3747 : // nativeIsNotWinter
3748 3576 : if (tariff.seasonForMonth(kMonth) == Season::Winter) {
3749 12 : s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values(kMonth) = 1.0;
3750 12 : s_econ->econVar(tariff.natives[(int)Native::IsNotWinter]).values(kMonth) = 0.0;
3751 : } else {
3752 3564 : s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values(kMonth) = 0.0;
3753 3564 : s_econ->econVar(tariff.natives[(int)Native::IsNotWinter]).values(kMonth) = 1.0;
3754 : }
3755 : // nativeIsSpring
3756 : // nativeIsNotSpring
3757 3576 : if (tariff.seasonForMonth(kMonth) == Season::Spring) {
3758 0 : s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values(kMonth) = 1.0;
3759 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotSpring]).values(kMonth) = 0.0;
3760 : } else {
3761 3576 : s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values(kMonth) = 0.0;
3762 3576 : s_econ->econVar(tariff.natives[(int)Native::IsNotSpring]).values(kMonth) = 1.0;
3763 : }
3764 : // nativeIsSummer
3765 : // nativeIsNotSummer
3766 3576 : if (tariff.seasonForMonth(kMonth) == Season::Summer) {
3767 0 : s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values(kMonth) = 1.0;
3768 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotSummer]).values(kMonth) = 0.0;
3769 : } else {
3770 3576 : s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values(kMonth) = 0.0;
3771 3576 : s_econ->econVar(tariff.natives[(int)Native::IsNotSummer]).values(kMonth) = 1.0;
3772 : }
3773 : // nativeIsAutumn
3774 : // nativeIsNotAutumn
3775 3576 : if (tariff.seasonForMonth(kMonth) == Season::Fall) {
3776 0 : s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values(kMonth) = 1.0;
3777 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotAutumn]).values(kMonth) = 0.0;
3778 : } else {
3779 3576 : s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values(kMonth) = 0.0;
3780 3576 : s_econ->econVar(tariff.natives[(int)Native::IsNotAutumn]).values(kMonth) = 1.0;
3781 : }
3782 : // nativePeakAndShoulderEnergy
3783 3576 : s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderEnergy]).values(kMonth) =
3784 3576 : tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::Shoulder];
3785 : // nativePeakAndShoulderDemand
3786 3576 : if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::Shoulder]) {
3787 12 : s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3788 : } else {
3789 3564 : s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderDemand]).values(kMonth) =
3790 3564 : tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
3791 : }
3792 : // nativePeakAndMidPeakEnergy
3793 3576 : s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakEnergy]).values(kMonth) =
3794 3576 : tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::MidPeak];
3795 : // nativePeakAndMidPeakDemand
3796 3576 : if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::MidPeak]) {
3797 12 : s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3798 : } else {
3799 3564 : s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
3800 : }
3801 : // nativeShoulderAndOffPeakEnergy
3802 3576 : s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakEnergy]).values(kMonth) =
3803 3576 : tariff.gatherEnergy(kMonth)[(int)Period::Shoulder] + tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
3804 : // nativeShoulderAndOffPeakDemand
3805 3576 : if (tariff.gatherDemand(kMonth)[(int)Period::Shoulder] > tariff.gatherDemand(kMonth)[(int)Period::OffPeak]) {
3806 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakDemand]).values(kMonth) =
3807 0 : tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
3808 : } else {
3809 3576 : s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakDemand]).values(kMonth) =
3810 3576 : tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3811 : }
3812 : // nativePeakAndOffPeakEnergy
3813 3576 : s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakEnergy]).values(kMonth) =
3814 3576 : tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
3815 : // nativePeakAndOffPeakDemand
3816 3576 : if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::OffPeak]) {
3817 12 : s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3818 : } else {
3819 3564 : s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3820 : }
3821 : // nativeRealTimePriceCosts
3822 3576 : s_econ->econVar(tariff.natives[(int)Native::RealTimePriceCosts]).values(kMonth) = tariff.RTPcost(kMonth);
3823 : // nativeAboveCustomerBaseCosts
3824 3576 : s_econ->econVar(tariff.natives[(int)Native::AboveCustomerBaseCosts]).values(kMonth) = tariff.RTPaboveBaseCost(kMonth);
3825 : // nativeBelowCustomerBaseCosts
3826 3576 : s_econ->econVar(tariff.natives[(int)Native::BelowCustomerBaseCosts]).values(kMonth) = tariff.RTPbelowBaseCost(kMonth);
3827 : // nativeAboveCustomerBaseEnergy
3828 3576 : s_econ->econVar(tariff.natives[(int)Native::AboveCustomerBaseEnergy]).values(kMonth) = tariff.RTPaboveBaseEnergy(kMonth);
3829 : // nativeBelowCustomerBaseEnergy
3830 3576 : s_econ->econVar(tariff.natives[(int)Native::BelowCustomerBaseEnergy]).values(kMonth) = tariff.RTPbelowBaseEnergy(kMonth);
3831 : }
3832 : }
3833 100 : }
3834 :
3835 100 : void LEEDtariffReporting(EnergyPlusData &state)
3836 : {
3837 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3838 : // DATE WRITTEN October 2012
3839 :
3840 : // Write the economic results for LEED reporting
3841 :
3842 : Real64 elecTotalEne;
3843 : Real64 gasTotalEne;
3844 : Real64 distCoolTotalEne;
3845 : Real64 distHeatWaterTotalEne;
3846 : Real64 distHeatSteamTotalEne;
3847 : Real64 otherTotalEne;
3848 : Real64 elecTotalCost;
3849 : Real64 gasTotalCost;
3850 : Real64 otherTotalCost;
3851 : Real64 distCoolTotalCost;
3852 : Real64 distHeatWaterTotalCost;
3853 : Real64 distHeatSteamTotalCost;
3854 : Real64 allTotalCost;
3855 : EconConv elecUnits;
3856 : EconConv gasUnits;
3857 : EconConv distCoolUnits;
3858 : EconConv distHeatWaterUnits;
3859 : EconConv distHeatSteamUnits;
3860 : EconConv othrUnits;
3861 : DemandWindow gasDemWindowUnits;
3862 : DemandWindow distCoolDemWindowUnits;
3863 : DemandWindow distHeatWaterDemWindowUnits;
3864 : DemandWindow distHeatSteamDemWindowUnits;
3865 : DemandWindow othrDemWindowUnits;
3866 :
3867 100 : auto &s_orp = state.dataOutRptPredefined;
3868 :
3869 100 : auto &s_econ = state.dataEconTariff;
3870 :
3871 100 : if (s_econ->numTariff > 0) {
3872 200 : int distCoolFacilMeter = GetMeterIndex(state, "DISTRICTCOOLING:FACILITY");
3873 200 : int distHeatWaterFacilMeter = GetMeterIndex(state, "DISTRICTHEATINGWATER:FACILITY");
3874 100 : int distHeatSteamFacilMeter = GetMeterIndex(state, "DISTRICTHEATINGSTEAM:FACILITY");
3875 100 : elecTotalEne = 0.0;
3876 100 : gasTotalEne = 0.0;
3877 100 : distCoolTotalEne = 0.0;
3878 100 : distHeatWaterTotalEne = 0.0;
3879 100 : distHeatSteamTotalEne = 0.0;
3880 100 : otherTotalEne = 0.0;
3881 100 : elecTotalCost = 0.0;
3882 100 : gasTotalCost = 0.0;
3883 100 : distCoolTotalCost = 0.0;
3884 100 : distHeatWaterTotalCost = 0.0;
3885 100 : distHeatSteamTotalCost = 0.0;
3886 100 : otherTotalCost = 0.0;
3887 100 : allTotalCost = 0.0;
3888 100 : elecUnits = EconConv::USERDEF;
3889 100 : gasUnits = EconConv::USERDEF;
3890 100 : distCoolUnits = EconConv::USERDEF;
3891 100 : distHeatWaterUnits = EconConv::USERDEF;
3892 100 : distHeatSteamUnits = EconConv::USERDEF;
3893 100 : othrUnits = EconConv::USERDEF;
3894 100 : gasDemWindowUnits = DemandWindow::Invalid;
3895 100 : othrDemWindowUnits = DemandWindow::Invalid;
3896 200 : std::string elecTariffNames = "";
3897 200 : std::string gasTariffNames = "";
3898 200 : std::string distCoolTariffNames = "";
3899 200 : std::string distHeatWaterTariffNames = "";
3900 200 : std::string distHeatSteamTariffNames = "";
3901 100 : std::string othrTariffNames = "";
3902 398 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
3903 298 : auto &tariff = s_econ->tariff(iTariff);
3904 298 : if (tariff.isSelected) {
3905 187 : allTotalCost += tariff.totalAnnualCost;
3906 187 : if (tariff.kindMtr == MeterType::ElecSimple || tariff.kindMtr == MeterType::ElecProduced ||
3907 91 : tariff.kindMtr == MeterType::ElecPurchased || tariff.kindMtr == MeterType::ElecSurplusSold ||
3908 89 : tariff.kindMtr == MeterType::ElecNet) {
3909 101 : if (tariff.totalAnnualEnergy > elecTotalEne) {
3910 1 : elecTotalEne = tariff.totalAnnualEnergy;
3911 : }
3912 101 : elecTotalCost += tariff.totalAnnualCost;
3913 101 : elecTariffNames += ' ' + tariff.tariffName;
3914 101 : elecUnits = tariff.convChoice;
3915 86 : } else if (tariff.kindMtr == MeterType::Gas) {
3916 84 : if (tariff.totalAnnualEnergy > gasTotalEne) {
3917 0 : gasTotalEne = tariff.totalAnnualEnergy;
3918 : }
3919 84 : gasTotalCost += tariff.totalAnnualCost;
3920 84 : gasTariffNames += ' ' + tariff.tariffName;
3921 84 : gasUnits = tariff.convChoice;
3922 84 : gasDemWindowUnits = tariff.demandWindow;
3923 2 : } else if (tariff.reportMeterIndx == distCoolFacilMeter) {
3924 1 : if (tariff.totalAnnualEnergy > distCoolTotalEne) {
3925 0 : distCoolTotalEne = tariff.totalAnnualEnergy;
3926 : }
3927 1 : distCoolTotalCost += tariff.totalAnnualCost;
3928 1 : distCoolTariffNames += ' ' + tariff.tariffName;
3929 1 : distCoolUnits = tariff.convChoice;
3930 1 : distCoolDemWindowUnits = tariff.demandWindow;
3931 1 : } else if (tariff.reportMeterIndx == distHeatWaterFacilMeter) {
3932 0 : if (tariff.totalAnnualEnergy > distHeatWaterTotalEne) {
3933 0 : distHeatWaterTotalEne = tariff.totalAnnualEnergy;
3934 : }
3935 0 : distHeatWaterTotalCost += tariff.totalAnnualCost;
3936 0 : distHeatWaterTariffNames += ' ' + tariff.tariffName;
3937 0 : distHeatWaterUnits = tariff.convChoice;
3938 0 : distHeatWaterDemWindowUnits = tariff.demandWindow;
3939 1 : } else if (tariff.reportMeterIndx == distHeatSteamFacilMeter) {
3940 0 : if (tariff.totalAnnualEnergy > distHeatSteamTotalEne) {
3941 0 : distHeatSteamTotalEne = tariff.totalAnnualEnergy;
3942 : }
3943 0 : distHeatSteamTotalCost += tariff.totalAnnualCost;
3944 0 : distHeatSteamTariffNames += ' ' + tariff.tariffName;
3945 0 : distHeatSteamUnits = tariff.convChoice;
3946 0 : distHeatSteamDemWindowUnits = tariff.demandWindow;
3947 1 : } else if (tariff.kindMtr != MeterType::Water) {
3948 0 : if (tariff.totalAnnualEnergy > otherTotalEne) {
3949 0 : otherTotalEne = tariff.totalAnnualEnergy;
3950 : }
3951 0 : otherTotalCost += tariff.totalAnnualCost;
3952 0 : othrTariffNames += ' ' + tariff.tariffName;
3953 0 : othrUnits = tariff.convChoice;
3954 0 : othrDemWindowUnits = tariff.demandWindow;
3955 : } else {
3956 : }
3957 : }
3958 : }
3959 : // names of the rates
3960 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Electricity", elecTariffNames);
3961 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Natural Gas", gasTariffNames);
3962 100 : if (distCoolTotalEne != 0) {
3963 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Cooling", distCoolTariffNames);
3964 : }
3965 100 : if (distHeatWaterTotalEne != 0) {
3966 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Heating Water", distHeatWaterTariffNames);
3967 : }
3968 100 : if (distHeatSteamTotalEne != 0) {
3969 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Heating Steam", distHeatSteamTariffNames);
3970 : }
3971 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Other", othrTariffNames);
3972 : // virtual rate
3973 100 : if (elecTotalEne != 0) {
3974 1 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Electricity", elecTotalCost / elecTotalEne, 3);
3975 : }
3976 100 : if (gasTotalEne != 0) {
3977 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Natural Gas", gasTotalCost / gasTotalEne, 3);
3978 : }
3979 100 : if (otherTotalEne != 0) {
3980 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Other", otherTotalCost / otherTotalEne, 3);
3981 : }
3982 : // units
3983 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Electricity", format("{}", convEnergyStrings[(int)elecUnits]));
3984 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Natural Gas", format("{}", convEnergyStrings[(int)gasUnits]));
3985 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Other", format("{}", convEnergyStrings[(int)othrUnits]));
3986 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsDemUnt, "Electricity", format("{}", convDemandStrings[(int)elecUnits]));
3987 200 : OutputReportPredefined::PreDefTableEntry(
3988 : state,
3989 100 : s_orp->pdchLeedEtsDemUnt,
3990 : "Natural Gas",
3991 200 : format("{}{}",
3992 100 : convDemandStrings[(int)gasUnits],
3993 100 : (gasDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)gasDemWindowUnits]));
3994 200 : OutputReportPredefined::PreDefTableEntry(
3995 : state,
3996 100 : s_orp->pdchLeedEtsDemUnt,
3997 : "Other",
3998 200 : format("{}{}",
3999 100 : convDemandStrings[(int)othrUnits],
4000 100 : (othrDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)othrDemWindowUnits]));
4001 :
4002 : // total cost
4003 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Electricity", elecTotalCost, 2);
4004 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Natural Gas", gasTotalCost, 2);
4005 100 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Other", otherTotalCost, 2);
4006 : // show district energy if used
4007 100 : if (distCoolTotalEne != 0) {
4008 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "District Cooling", distCoolTotalCost / distCoolTotalEne, 3);
4009 0 : OutputReportPredefined::PreDefTableEntry(
4010 0 : state, s_orp->pdchLeedEtsEneUnt, "District Cooling", format("{}", convEnergyStrings[(int)distCoolUnits]));
4011 0 : OutputReportPredefined::PreDefTableEntry(
4012 : state,
4013 0 : s_orp->pdchLeedEtsDemUnt,
4014 : "District Cooling",
4015 0 : format("{}{}",
4016 0 : convDemandStrings[(int)distCoolUnits],
4017 0 : (distCoolDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distCoolDemWindowUnits]));
4018 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Cooling", distCoolTotalCost, 2);
4019 : }
4020 100 : if (distHeatWaterTotalEne != 0) {
4021 0 : OutputReportPredefined::PreDefTableEntry(
4022 0 : state, s_orp->pdchLeedEtsVirt, "District Heating Water", distHeatWaterTotalCost / distHeatWaterTotalEne, 3);
4023 0 : OutputReportPredefined::PreDefTableEntry(
4024 0 : state, s_orp->pdchLeedEtsEneUnt, "District Heating Water", format("{}", convEnergyStrings[(int)distHeatWaterUnits]));
4025 0 : OutputReportPredefined::PreDefTableEntry(
4026 : state,
4027 0 : s_orp->pdchLeedEtsDemUnt,
4028 : "District Heating Water",
4029 0 : format("{}{}",
4030 0 : convDemandStrings[(int)distHeatWaterUnits],
4031 0 : (distHeatWaterDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distHeatWaterDemWindowUnits]));
4032 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Heating Water", distHeatWaterTotalCost, 2);
4033 : }
4034 100 : if (distHeatSteamTotalEne != 0) {
4035 0 : OutputReportPredefined::PreDefTableEntry(
4036 0 : state, s_orp->pdchLeedEtsVirt, "District Heating Steam", distHeatSteamTotalCost / distHeatSteamTotalEne, 3);
4037 0 : OutputReportPredefined::PreDefTableEntry(
4038 0 : state, s_orp->pdchLeedEtsEneUnt, "District Heating Steam", format("{}", convEnergyStrings[(int)distHeatSteamUnits]));
4039 0 : OutputReportPredefined::PreDefTableEntry(
4040 : state,
4041 0 : s_orp->pdchLeedEtsDemUnt,
4042 : "District Heating Steam",
4043 0 : format("{}{}",
4044 0 : convDemandStrings[(int)distHeatSteamUnits],
4045 0 : (distHeatSteamDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distHeatSteamDemWindowUnits]));
4046 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Heating Steam", distHeatSteamTotalCost, 2);
4047 : }
4048 : // save the total costs for later to compute process fraction
4049 100 : s_orp->LEEDelecCostTotal = elecTotalCost;
4050 100 : s_orp->LEEDgasCostTotal = gasTotalCost;
4051 100 : s_orp->LEEDothrCostTotal = distCoolTotalCost + distHeatWaterTotalCost + distHeatSteamTotalCost + otherTotalCost;
4052 100 : OutputReportPredefined::PreDefTableEntry(state,
4053 100 : s_orp->pdchLeedEcsTotal,
4054 : "Total",
4055 100 : elecTotalCost + gasTotalCost + distCoolTotalCost + distHeatWaterTotalCost + distHeatSteamTotalCost +
4056 : otherTotalCost,
4057 100 : 2);
4058 100 : }
4059 100 : }
4060 :
4061 799 : void WriteTabularTariffReports(EnergyPlusData &state)
4062 : {
4063 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
4064 : // DATE WRITTEN July 2004
4065 : // MODIFIED January 2010, Kyle Benne
4066 : // Added SQLite output
4067 :
4068 : // all arrays are in the format: (row, column)
4069 799 : Array1D_string columnHead;
4070 799 : Array1D_int columnWidth;
4071 799 : Array1D_string rowHead;
4072 799 : Array2D_string tableBody;
4073 : // other local variables
4074 : Real64 elecTotalCost;
4075 : Real64 gasTotalCost;
4076 : Real64 otherTotalCost;
4077 : Real64 allTotalCost;
4078 799 : Real64 perAreaUnitConv(0.0);
4079 :
4080 799 : auto &s_econ = state.dataEconTariff;
4081 :
4082 : // Here to it is ready to assign ort->unitStyle_SQLite (not in SQLiteProcedures.cc)
4083 : // when ort->unitsStyle inputs should have been concretely processed and assigned.
4084 : // Included this here to make sure the units specifications are correctly updated.
4085 799 : if (state.dataOutRptTab->unitsStyle_SQLite == OutputReportTabular::UnitsStyle::NotFound) {
4086 0 : state.dataOutRptTab->unitsStyle_SQLite = state.dataOutRptTab->unitsStyle; // This is the default UseOutputControlTableStyles
4087 : }
4088 :
4089 : // compute floor area if no ABUPS
4090 799 : if (state.dataOutRptTab->buildingConditionedFloorArea == 0.0) {
4091 123 : OutputReportTabular::DetermineBuildingFloorArea(state);
4092 : }
4093 :
4094 799 : if (s_econ->numTariff > 0) {
4095 101 : auto &econVar = s_econ->econVar;
4096 :
4097 101 : if (state.dataOutRptTab->displayEconomicResultSummary) {
4098 32 : DisplayString(state, "Writing Tariff Reports");
4099 6732 : for (auto &e : econVar) {
4100 6700 : e.isReported = false;
4101 : }
4102 32 : showWarningsBasedOnTotal(state);
4103 : //---------------------------------
4104 : // Economics Results Summary Report
4105 : //---------------------------------
4106 96 : OutputReportTabular::WriteReportHeaders(
4107 : state, "Economics Results Summary Report", "Entire Facility", OutputProcessor::StoreType::Average);
4108 :
4109 64 : for (int iUnitSystem = 0; iUnitSystem <= 1; iUnitSystem++) {
4110 64 : OutputReportTabular::UnitsStyle unitsStyle_cur = state.dataOutRptTab->unitsStyle;
4111 64 : bool produceTabular = true;
4112 64 : bool produceSQLite = false;
4113 64 : if (produceDualUnitsFlags(iUnitSystem,
4114 64 : state.dataOutRptTab->unitsStyle,
4115 64 : state.dataOutRptTab->unitsStyle_SQLite,
4116 : unitsStyle_cur,
4117 : produceTabular,
4118 : produceSQLite)) {
4119 32 : break;
4120 : }
4121 :
4122 : // do unit conversions if necessary
4123 32 : std::string perAreaUnitName;
4124 32 : if ((unitsStyle_cur == OutputReportTabular::UnitsStyle::InchPound) ||
4125 32 : (unitsStyle_cur == OutputReportTabular::UnitsStyle::InchPoundExceptElectricity)) {
4126 0 : int unitConvIndex = 0;
4127 0 : std::string SIunit = "[~~$~~/m2]";
4128 0 : OutputReportTabular::LookupSItoIP(state, SIunit, unitConvIndex, perAreaUnitName);
4129 0 : perAreaUnitConv = OutputReportTabular::ConvertIP(state, unitConvIndex, 1.0);
4130 0 : } else {
4131 32 : perAreaUnitName = "[~~$~~/m2]";
4132 32 : perAreaUnitConv = 1.0;
4133 : }
4134 :
4135 : //---- Annual Summary
4136 32 : rowHead.allocate(3);
4137 32 : columnHead.allocate(4);
4138 32 : columnWidth.allocate(4);
4139 32 : tableBody.allocate(4, 3);
4140 32 : tableBody = "";
4141 32 : columnHead(1) = "Electricity";
4142 32 : columnHead(2) = "Natural Gas";
4143 32 : columnHead(3) = "Other";
4144 32 : columnHead(4) = "Total";
4145 32 : rowHead(1) = "Cost [~~$~~]";
4146 32 : rowHead(2) = "Cost per Total Building Area " + perAreaUnitName;
4147 32 : rowHead(3) = "Cost per Net Conditioned Building Area " + perAreaUnitName;
4148 32 : elecTotalCost = 0.0;
4149 32 : gasTotalCost = 0.0;
4150 32 : otherTotalCost = 0.0;
4151 32 : allTotalCost = 0.0;
4152 126 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4153 94 : auto const &tariff = s_econ->tariff(iTariff);
4154 94 : if (tariff.isSelected) {
4155 52 : allTotalCost += tariff.totalAnnualCost;
4156 52 : if (tariff.kindMtr == MeterType::ElecSimple || tariff.kindMtr == MeterType::ElecProduced ||
4157 24 : tariff.kindMtr == MeterType::ElecPurchased || tariff.kindMtr == MeterType::ElecSurplusSold ||
4158 22 : tariff.kindMtr == MeterType::ElecNet) {
4159 33 : elecTotalCost += tariff.totalAnnualCost;
4160 19 : } else if (tariff.kindMtr == MeterType::Gas) {
4161 18 : gasTotalCost += tariff.totalAnnualCost;
4162 1 : } else if (tariff.kindMtr != MeterType::Water) {
4163 0 : otherTotalCost += tariff.totalAnnualCost;
4164 : // removed because this was confusing columnHead(3) = tariff.reportMeter
4165 : }
4166 : }
4167 : }
4168 32 : tableBody(1, 1) = OutputReportTabular::RealToStr(elecTotalCost, 2);
4169 32 : tableBody(2, 1) = OutputReportTabular::RealToStr(gasTotalCost, 2);
4170 32 : tableBody(3, 1) = OutputReportTabular::RealToStr(otherTotalCost, 2);
4171 32 : tableBody(4, 1) = OutputReportTabular::RealToStr(allTotalCost, 2);
4172 32 : if (state.dataOutRptTab->buildingGrossFloorArea > 0.0) {
4173 32 : tableBody(1, 2) =
4174 64 : OutputReportTabular::RealToStr((elecTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4175 32 : tableBody(2, 2) =
4176 64 : OutputReportTabular::RealToStr((gasTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4177 32 : tableBody(3, 2) =
4178 64 : OutputReportTabular::RealToStr((otherTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4179 32 : tableBody(4, 2) =
4180 64 : OutputReportTabular::RealToStr((allTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4181 : }
4182 32 : if (state.dataOutRptTab->buildingConditionedFloorArea > 0.0) {
4183 32 : tableBody(1, 3) =
4184 64 : OutputReportTabular::RealToStr((elecTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4185 32 : tableBody(2, 3) =
4186 64 : OutputReportTabular::RealToStr((gasTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4187 32 : tableBody(3, 3) =
4188 64 : OutputReportTabular::RealToStr((otherTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4189 32 : tableBody(4, 3) =
4190 64 : OutputReportTabular::RealToStr((allTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4191 : }
4192 32 : columnWidth = 14; // array assignment - same for all columns
4193 32 : if (produceTabular) {
4194 32 : OutputReportTabular::WriteSubtitle(state, "Annual Cost");
4195 32 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4196 : }
4197 32 : if (produceSQLite) {
4198 32 : if (state.dataSQLiteProcedures->sqlite) {
4199 10 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
4200 : tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Annual Cost");
4201 : }
4202 : }
4203 32 : if (produceTabular) {
4204 32 : if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
4205 0 : state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
4206 : tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Annual Cost");
4207 : }
4208 : }
4209 32 : columnHead.deallocate();
4210 32 : rowHead.deallocate();
4211 32 : columnWidth.deallocate();
4212 32 : tableBody.deallocate();
4213 32 : }
4214 : //---- Tariff Summary
4215 32 : rowHead.allocate(s_econ->numTariff);
4216 32 : columnHead.allocate(6);
4217 32 : columnWidth.allocate(6);
4218 32 : tableBody.allocate(6, s_econ->numTariff);
4219 32 : tableBody = "";
4220 32 : columnHead(1) = "Selected";
4221 32 : columnHead(2) = "Qualified";
4222 32 : columnHead(3) = "Meter";
4223 32 : columnHead(4) = "Buy or Sell";
4224 32 : columnHead(5) = "Group";
4225 32 : columnHead(6) = "Annual Cost (~~$~~)";
4226 126 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4227 94 : auto const &tariff = s_econ->tariff(iTariff);
4228 94 : rowHead(iTariff) = tariff.tariffName;
4229 94 : tableBody(1, iTariff) = yesNoNames[(int)tariff.isSelected];
4230 94 : tableBody(2, iTariff) = yesNoNames[(int)tariff.isQualified];
4231 :
4232 94 : tableBody(3, iTariff) = tariff.reportMeter;
4233 :
4234 94 : if (tariff.buyOrSell == BuySell::BuyFromUtility) {
4235 92 : tableBody(4, iTariff) = "Buy";
4236 2 : } else if (tariff.buyOrSell == BuySell::SellToUtility) {
4237 1 : tableBody(4, iTariff) = "Sell";
4238 1 : } else if (tariff.buyOrSell == BuySell::NetMetering) {
4239 1 : tableBody(4, iTariff) = "Net";
4240 : }
4241 :
4242 94 : if (tariff.groupName == "") {
4243 22 : tableBody(5, iTariff) = "(none)";
4244 : } else {
4245 72 : tableBody(5, iTariff) = tariff.groupName;
4246 : }
4247 94 : tableBody(6, iTariff) = OutputReportTabular::RealToStr(tariff.totalAnnualCost, 2);
4248 : }
4249 32 : columnWidth = 14; // array assignment - same for all columns
4250 32 : OutputReportTabular::WriteSubtitle(state, "Tariff Summary");
4251 32 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4252 32 : if (state.dataSQLiteProcedures->sqlite) {
4253 10 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
4254 : tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Tariff Summary");
4255 : }
4256 32 : if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
4257 0 : state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
4258 : tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Tariff Summary");
4259 : }
4260 32 : columnHead.deallocate();
4261 32 : rowHead.deallocate();
4262 32 : columnWidth.deallocate();
4263 32 : tableBody.deallocate();
4264 : }
4265 : //---------------------------------
4266 : // Tariff Report
4267 : //---------------------------------
4268 101 : if (state.dataOutRptTab->displayTariffReport) {
4269 126 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4270 94 : auto const &tariff = s_econ->tariff(iTariff);
4271 94 : auto const &computation = s_econ->computation(iTariff);
4272 188 : OutputReportTabular::WriteReportHeaders(state, "Tariff Report", tariff.tariffName, OutputProcessor::StoreType::Average);
4273 94 : rowHead.allocate(7);
4274 94 : columnHead.allocate(1);
4275 94 : columnWidth.allocate(1);
4276 94 : tableBody.allocate(1, 7);
4277 94 : tableBody = "";
4278 94 : columnHead(1) = "Parameter";
4279 94 : rowHead(1) = "Meter";
4280 94 : rowHead(2) = "Selected";
4281 94 : rowHead(3) = "Group";
4282 94 : rowHead(4) = "Qualified";
4283 94 : rowHead(5) = "Disqualifier";
4284 94 : rowHead(6) = "Computation";
4285 94 : rowHead(7) = "Units";
4286 94 : tableBody(1, 1) = tariff.reportMeter;
4287 94 : if (tariff.isSelected) {
4288 52 : tableBody(1, 2) = "Yes";
4289 : } else {
4290 42 : tableBody(1, 2) = "No";
4291 : }
4292 94 : if (tariff.groupName == "") {
4293 22 : tableBody(1, 3) = "(none)";
4294 : } else {
4295 72 : tableBody(1, 3) = tariff.groupName;
4296 : }
4297 94 : if (tariff.isQualified) {
4298 94 : tableBody(1, 4) = "Yes";
4299 : } else {
4300 0 : tableBody(1, 4) = "No";
4301 : }
4302 94 : if (tariff.isQualified) {
4303 94 : tableBody(1, 5) = "n/a";
4304 : } else {
4305 0 : tableBody(1, 5) = econVar(tariff.ptDisqualifier).name;
4306 : }
4307 94 : if (computation.isUserDef) {
4308 1 : tableBody(1, 6) = computation.computeName;
4309 : } else {
4310 93 : tableBody(1, 6) = "automatic";
4311 : }
4312 94 : switch (tariff.convChoice) {
4313 1 : case EconConv::USERDEF: {
4314 1 : tableBody(1, 7) = "User Defined";
4315 1 : } break;
4316 75 : case EconConv::KWH: {
4317 75 : tableBody(1, 7) = "kWh";
4318 75 : } break;
4319 1 : case EconConv::THERM: {
4320 1 : tableBody(1, 7) = "Therm";
4321 1 : } break;
4322 0 : case EconConv::MMBTU: {
4323 0 : tableBody(1, 7) = "MMBtu";
4324 0 : } break;
4325 0 : case EconConv::MJ: {
4326 0 : tableBody(1, 7) = "MJ";
4327 0 : } break;
4328 0 : case EconConv::KBTU: {
4329 0 : tableBody(1, 7) = "kBtu";
4330 0 : } break;
4331 17 : case EconConv::MCF: {
4332 17 : tableBody(1, 7) = "MCF";
4333 17 : } break;
4334 0 : case EconConv::CCF: {
4335 0 : tableBody(1, 7) = "CCF";
4336 0 : } break;
4337 0 : default:
4338 0 : break;
4339 : }
4340 94 : columnWidth = 14; // array assignment - same for all columns
4341 94 : OutputReportTabular::WriteSubtitle(state, "General");
4342 94 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4343 94 : if (state.dataSQLiteProcedures->sqlite) {
4344 28 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
4345 : tableBody, rowHead, columnHead, "Tariff Report", tariff.tariffName, "General");
4346 : }
4347 94 : if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
4348 0 : state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
4349 0 : tableBody, rowHead, columnHead, "Tariff Report", tariff.tariffName, "General");
4350 : }
4351 94 : columnHead.deallocate();
4352 94 : rowHead.deallocate();
4353 94 : columnWidth.deallocate();
4354 94 : tableBody.deallocate();
4355 : //---- Categories
4356 29994 : for (auto &e : econVar) {
4357 29900 : e.activeNow = false;
4358 : }
4359 94 : econVar(tariff.cats[(int)Cat::EnergyCharges]).activeNow = true;
4360 94 : econVar(tariff.cats[(int)Cat::DemandCharges]).activeNow = true;
4361 94 : econVar(tariff.cats[(int)Cat::ServiceCharges]).activeNow = true;
4362 94 : econVar(tariff.cats[(int)Cat::Basis]).activeNow = true;
4363 94 : econVar(tariff.cats[(int)Cat::Adjustment]).activeNow = true;
4364 94 : econVar(tariff.cats[(int)Cat::Surcharge]).activeNow = true;
4365 94 : econVar(tariff.cats[(int)Cat::Subtotal]).activeNow = true;
4366 94 : econVar(tariff.cats[(int)Cat::Taxes]).activeNow = true;
4367 94 : econVar(tariff.cats[(int)Cat::Total]).activeNow = true;
4368 188 : ReportEconomicVariable(state, "Categories", false, true, tariff.tariffName);
4369 : //---- Charges
4370 29994 : for (auto &e : econVar) {
4371 29900 : e.activeNow = false;
4372 : }
4373 24878 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4374 24784 : if (econVar(kVar).tariffIndx == iTariff) {
4375 4950 : if ((econVar(kVar).kindOfObj == ObjType::ChargeSimple) || (econVar(kVar).kindOfObj == ObjType::ChargeBlock)) {
4376 433 : econVar(kVar).activeNow = true;
4377 : }
4378 : }
4379 : }
4380 188 : ReportEconomicVariable(state, "Charges", true, true, tariff.tariffName);
4381 : //---- Sources for Charges
4382 29994 : for (auto &e : econVar) {
4383 29900 : e.activeNow = false;
4384 : }
4385 24878 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4386 24784 : if (econVar(kVar).tariffIndx == iTariff) {
4387 4950 : int indexInChg = econVar(kVar).index;
4388 4950 : if (econVar(kVar).kindOfObj == ObjType::ChargeSimple) {
4389 352 : auto &chargeSimple = s_econ->chargeSimple(indexInChg);
4390 352 : if (chargeSimple.sourcePt > 0) {
4391 352 : econVar(chargeSimple.sourcePt).activeNow = true;
4392 : }
4393 4598 : } else if (econVar(kVar).kindOfObj == ObjType::ChargeBlock) {
4394 81 : auto &chargeBlock = s_econ->chargeBlock(indexInChg);
4395 81 : if (chargeBlock.sourcePt > 0) {
4396 81 : econVar(chargeBlock.sourcePt).activeNow = true;
4397 : }
4398 : }
4399 : }
4400 : }
4401 188 : ReportEconomicVariable(state, "Corresponding Sources for Charges", false, false, tariff.tariffName);
4402 : //---- Rachets
4403 29994 : for (auto &e : econVar) {
4404 29900 : e.activeNow = false;
4405 : }
4406 24878 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4407 24784 : if (econVar(kVar).tariffIndx == iTariff) {
4408 4950 : if (econVar(kVar).kindOfObj == ObjType::Ratchet) {
4409 1 : econVar(kVar).activeNow = true;
4410 : }
4411 : }
4412 : }
4413 188 : ReportEconomicVariable(state, "Ratchets", false, false, tariff.tariffName);
4414 : //---- Qualifies
4415 29994 : for (auto &e : econVar) {
4416 29900 : e.activeNow = false;
4417 : }
4418 24878 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4419 24784 : if (econVar(kVar).tariffIndx == iTariff) {
4420 4950 : if (econVar(kVar).kindOfObj == ObjType::Qualify) {
4421 77 : econVar(kVar).activeNow = true;
4422 : }
4423 : }
4424 : }
4425 188 : ReportEconomicVariable(state, "Qualifies", false, false, tariff.tariffName);
4426 : //---- Native Variables
4427 29994 : for (auto &e : econVar) {
4428 29900 : e.activeNow = false;
4429 : }
4430 3572 : for (int kVar = tariff.firstNative; kVar <= tariff.lastNative; ++kVar) {
4431 3478 : econVar(kVar).activeNow = true;
4432 : }
4433 188 : ReportEconomicVariable(state, "Native Variables", false, false, tariff.tariffName);
4434 : //---- Other Variables
4435 29994 : for (auto &e : econVar) {
4436 29900 : e.activeNow = false;
4437 : }
4438 24878 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4439 24784 : if (econVar(kVar).tariffIndx == iTariff) {
4440 4950 : if (!econVar(kVar).isReported) {
4441 114 : econVar(kVar).activeNow = true;
4442 : }
4443 : }
4444 : }
4445 188 : ReportEconomicVariable(state, "Other Variables", false, false, tariff.tariffName);
4446 : //---- Computation
4447 94 : if (computation.isUserDef) {
4448 2 : OutputReportTabular::WriteTextLine(state, "Computation - User Defined", true);
4449 : } else {
4450 186 : OutputReportTabular::WriteTextLine(state, "Computation - Automatic", true);
4451 : }
4452 188 : std::string outString = "";
4453 4858 : for (int lStep = computation.firstStep; lStep <= computation.lastStep; ++lStep) {
4454 4764 : auto &step = s_econ->steps(lStep);
4455 :
4456 4764 : if (step.type == StepType::EOL) {
4457 997 : OutputReportTabular::WriteTextLine(state, rstrip(outString));
4458 997 : outString = "";
4459 3767 : } else if (step.type == StepType::Var) {
4460 2770 : outString = econVar(step.varNum).name + ' ' + outString;
4461 997 : } else if (step.type == StepType::Op) {
4462 997 : outString = format("{} {}", opNamesUC[(int)step.op], outString);
4463 : }
4464 : }
4465 : }
4466 : }
4467 : }
4468 799 : }
4469 :
4470 32 : void showWarningsBasedOnTotal(EnergyPlusData &state)
4471 : {
4472 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
4473 : // DATE WRITTEN July 2004
4474 :
4475 : // Get the annual maximum and sum for the econVariable.
4476 :
4477 32 : auto &s_econ = state.dataEconTariff;
4478 126 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4479 94 : auto const &tariff = s_econ->tariff(iTariff);
4480 94 : if (tariff.buyOrSell == BuySell::BuyFromUtility) {
4481 92 : if (tariff.totalAnnualCost < 0) {
4482 0 : ShowWarningError(state, "UtilityCost:Tariff: A negative annual total cost when buying electricity from a utility is unusual. ");
4483 0 : ShowContinueError(state, format(" In UtilityCost:Tariff named {}", tariff.tariffName));
4484 : }
4485 2 : } else if (tariff.buyOrSell == BuySell::SellToUtility) {
4486 1 : if (tariff.totalAnnualCost > 0) {
4487 0 : ShowWarningError(state, "UtilityCost:Tariff: A positive annual total cost when selling electricity to a utility is unusual. ");
4488 0 : ShowContinueError(state, format(" In UtilityCost:Tariff named {}", tariff.tariffName));
4489 : }
4490 : }
4491 : }
4492 32 : }
4493 :
4494 5197 : void getMaxAndSum(EnergyPlusData &state, int const varPointer, Real64 &sumResult, Real64 &maxResult)
4495 : {
4496 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
4497 : // DATE WRITTEN July 2004
4498 :
4499 : // Get the annual maximum and sum for the econVariable.
4500 :
4501 5197 : Real64 maximumVal(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
4502 :
4503 5197 : auto const &s_econ = state.dataEconTariff;
4504 5197 : auto const &econVar = s_econ->econVar(varPointer);
4505 :
4506 5197 : Real64 sumVal = 0.0;
4507 5197 : maximumVal = -HUGE_(maximumVal);
4508 67561 : for (int jMonth = 1; jMonth <= 12; ++jMonth) { // note not all months get printed out if more than 12 are used.- need to fix this later
4509 62364 : Real64 curVal = econVar.values(jMonth);
4510 62364 : sumVal += curVal;
4511 62364 : if (curVal > maximumVal) {
4512 5429 : maximumVal = curVal;
4513 : }
4514 : }
4515 5197 : sumResult = sumVal;
4516 5197 : maxResult = maximumVal;
4517 5197 : }
4518 :
4519 658 : void ReportEconomicVariable(
4520 : EnergyPlusData &state, std::string const &titleString, bool const includeCategory, bool const showCurrencySymbol, std::string const &forString)
4521 : {
4522 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
4523 : // DATE WRITTEN July 2004
4524 : // MODIFIED January 2010, Kyle Benne
4525 : // Added sqlite output
4526 :
4527 : // Report all econVar that show as activeNow
4528 :
4529 : // all arrays are in the format: (row, column)
4530 658 : Array1D_string columnHead;
4531 658 : Array1D_int columnWidth;
4532 658 : Array1D_string rowHead;
4533 658 : Array2D_string tableBody;
4534 : Real64 sumVal;
4535 : Real64 maximumVal;
4536 : Real64 curVal;
4537 : int curIndex;
4538 : int curCatPt;
4539 : int curCategory;
4540 :
4541 : int iVar;
4542 : int jMonth;
4543 : int cntOfVar;
4544 : int nCntOfVar;
4545 :
4546 658 : auto const &s_econ = state.dataEconTariff;
4547 658 : auto const &econVar = s_econ->econVar;
4548 658 : auto const &chargeBlock = s_econ->chargeBlock;
4549 658 : auto const &chargeSimple = s_econ->chargeSimple;
4550 :
4551 658 : cntOfVar = 0;
4552 174146 : for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
4553 173488 : if (econVar(iVar).activeNow) {
4554 5197 : ++cntOfVar;
4555 : }
4556 : }
4557 658 : if (includeCategory) {
4558 94 : rowHead.allocate(cntOfVar);
4559 94 : columnHead.allocate(15);
4560 94 : columnWidth.allocate(15);
4561 94 : tableBody.allocate(15, cntOfVar);
4562 : } else {
4563 564 : rowHead.allocate(cntOfVar);
4564 564 : columnHead.allocate(14);
4565 564 : columnWidth.allocate(14);
4566 564 : tableBody.allocate(14, cntOfVar);
4567 : }
4568 : // column names
4569 658 : columnHead(1) = "Jan";
4570 658 : columnHead(2) = "Feb";
4571 658 : columnHead(3) = "Mar";
4572 658 : columnHead(4) = "Apr";
4573 658 : columnHead(5) = "May";
4574 658 : columnHead(6) = "Jun";
4575 658 : columnHead(7) = "Jul";
4576 658 : columnHead(8) = "Aug";
4577 658 : columnHead(9) = "Sep";
4578 658 : columnHead(10) = "Oct";
4579 658 : columnHead(11) = "Nov";
4580 658 : columnHead(12) = "Dec";
4581 658 : columnHead(13) = "Sum";
4582 658 : columnHead(14) = "Max";
4583 658 : if (includeCategory) {
4584 94 : columnHead(15) = "Category";
4585 : }
4586 658 : nCntOfVar = 0;
4587 : // row names
4588 174146 : for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
4589 173488 : if (econVar(iVar).activeNow) {
4590 5197 : ++nCntOfVar;
4591 5197 : if (showCurrencySymbol) {
4592 1279 : rowHead(nCntOfVar) = econVar(iVar).name + " (~~$~~)";
4593 : } else {
4594 3918 : rowHead(nCntOfVar) = econVar(iVar).name;
4595 : }
4596 : }
4597 : }
4598 : // fill the body
4599 658 : nCntOfVar = 0;
4600 174146 : for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
4601 173488 : if (econVar(iVar).activeNow) {
4602 5197 : ++nCntOfVar;
4603 67561 : for (jMonth = 1; jMonth <= 12; ++jMonth) { // note not all months get printed out if more than 12 are used.- need to fix this later
4604 62364 : curVal = econVar(iVar).values(jMonth);
4605 62364 : if ((curVal > 0) && (curVal < 1)) {
4606 480 : tableBody(jMonth, nCntOfVar) = OutputReportTabular::RealToStr(curVal, 4);
4607 : } else {
4608 61884 : tableBody(jMonth, nCntOfVar) = OutputReportTabular::RealToStr(curVal, 2);
4609 : }
4610 : }
4611 5197 : getMaxAndSum(state, iVar, sumVal, maximumVal);
4612 5197 : tableBody(13, nCntOfVar) = OutputReportTabular::RealToStr(sumVal, 2);
4613 5197 : tableBody(14, nCntOfVar) = OutputReportTabular::RealToStr(maximumVal, 2);
4614 5197 : if (includeCategory) {
4615 : // first find category
4616 433 : curCategory = 0;
4617 433 : curIndex = econVar(iVar).index;
4618 :
4619 433 : switch (econVar(iVar).kindOfObj) {
4620 352 : case ObjType::ChargeSimple:
4621 352 : if ((curIndex >= 1) && (curIndex <= s_econ->numChargeSimple)) {
4622 352 : curCatPt = chargeSimple(curIndex).categoryPt;
4623 : }
4624 352 : break;
4625 81 : case ObjType::ChargeBlock:
4626 81 : if ((curIndex >= 1) && (curIndex <= s_econ->numChargeBlock)) {
4627 81 : curCatPt = chargeBlock(curIndex).categoryPt;
4628 : }
4629 81 : break;
4630 0 : default:
4631 0 : break;
4632 : }
4633 :
4634 433 : if ((curCatPt >= 1) && (curCatPt <= s_econ->numEconVar)) {
4635 433 : curCategory = econVar(curCatPt).specific;
4636 : }
4637 :
4638 : // In this specific table, "NotIncluded" is written as "none" so need a special case for that
4639 433 : tableBody(15, nCntOfVar) =
4640 433 : (econVar(curCatPt).kindOfObj == ObjType::Category)
4641 866 : ? ((econVar(curCatPt).specific == (int)Cat::NotIncluded) ? "none" : catNames[econVar(curCatPt).specific])
4642 433 : : "none";
4643 : }
4644 5197 : s_econ->econVar(iVar).isReported = true;
4645 : }
4646 : }
4647 658 : columnWidth = 14; // array assignment - same for all columns
4648 658 : OutputReportTabular::WriteSubtitle(state, titleString);
4649 658 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4650 658 : if (state.dataSQLiteProcedures->sqlite) {
4651 196 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(tableBody, rowHead, columnHead, "Tariff Report", forString, titleString);
4652 : }
4653 658 : if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
4654 0 : state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
4655 : tableBody, rowHead, columnHead, "Tariff Report", forString, titleString);
4656 : }
4657 658 : columnHead.deallocate();
4658 658 : rowHead.deallocate();
4659 658 : columnWidth.deallocate();
4660 658 : tableBody.deallocate();
4661 658 : }
4662 :
4663 100 : void selectTariff(EnergyPlusData &state)
4664 : {
4665 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
4666 : // DATE WRITTEN July 2004
4667 :
4668 : // To select tariffs for each combination of meter and
4669 : // group. If multiple tariffs have the same meter and
4670 : // group, then select the one with the lowest cost.
4671 : // For electric tariffs, since they may have buy, sell, or
4672 : // netmetering, they need to be combined more carefully.
4673 : // Multiple meters are used but buy + sell might be more or
4674 : // less expensive than netmeter.
4675 :
4676 100 : Array1D_int groupIndex; // index number (in tariff) for the group name
4677 100 : Array1D_int MinTariffIndex; // tariff index for the Minimum value
4678 : int curMinTariffIndex;
4679 :
4680 100 : auto const &s_econ = state.dataEconTariff;
4681 100 : auto const &econVar(s_econ->econVar);
4682 :
4683 100 : groupIndex.dimension(s_econ->numTariff, 0);
4684 100 : int groupCount = 0;
4685 100 : int numMins = 0;
4686 100 : MinTariffIndex.dimension(s_econ->numTariff, 0);
4687 398 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4688 298 : auto &tariff = s_econ->tariff(iTariff);
4689 : // compute the total annual cost of each tariff
4690 298 : int totalVarPt = tariff.cats[(int)Cat::Total];
4691 298 : int totEneVarPt = tariff.natives[(int)Native::TotalEnergy];
4692 298 : Real64 annualTotal = 0.0;
4693 298 : Real64 annEneTotal = 0.0;
4694 3874 : for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
4695 3576 : annualTotal += econVar(totalVarPt).values(jMonth);
4696 3576 : annEneTotal += econVar(totEneVarPt).values(jMonth);
4697 : }
4698 298 : tariff.totalAnnualCost = annualTotal;
4699 298 : tariff.totalAnnualEnergy = annEneTotal;
4700 : // Set the groupIndex
4701 298 : if (groupIndex(iTariff) == 0) {
4702 : // set the current item to the tariff index
4703 184 : ++groupCount;
4704 184 : groupIndex(iTariff) = groupCount;
4705 : // set all remaining matching items to the same index
4706 383 : for (int kTariff = iTariff + 1; kTariff <= s_econ->numTariff; ++kTariff) {
4707 199 : if (Util::SameString(s_econ->tariff(kTariff).groupName, tariff.groupName)) {
4708 114 : groupIndex(kTariff) = groupCount;
4709 : }
4710 : }
4711 : }
4712 : }
4713 : // First process the all tariff and identify the lowest cost for each type of meter and group.
4714 398 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4715 298 : auto &tariff = s_econ->tariff(iTariff);
4716 298 : if (tariff.isQualified) {
4717 298 : bool isFound = false;
4718 523 : for (int lMin = 1; lMin <= numMins; ++lMin) {
4719 225 : curMinTariffIndex = MinTariffIndex(lMin);
4720 : // find matching meter and group
4721 225 : if (tariff.reportMeterIndx == s_econ->tariff(curMinTariffIndex).reportMeterIndx) {
4722 110 : if (groupIndex(iTariff) == groupIndex(curMinTariffIndex)) {
4723 110 : isFound = true;
4724 : // found the matching mater and group now test if smaller Min is current tariff
4725 110 : if (tariff.totalAnnualCost < s_econ->tariff(curMinTariffIndex).totalAnnualCost) {
4726 98 : MinTariffIndex(lMin) = iTariff;
4727 : // select the new Minimum tariff and deselect the one that was just exceeded
4728 98 : s_econ->tariff(curMinTariffIndex).isSelected = false;
4729 98 : tariff.isSelected = true;
4730 : }
4731 : }
4732 : }
4733 : }
4734 298 : if (!isFound) {
4735 188 : ++numMins;
4736 188 : if (numMins > s_econ->numTariff) {
4737 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging error numMins greater than numTariff.");
4738 : }
4739 188 : MinTariffIndex(numMins) = iTariff;
4740 : // tariff(numMins)%isSelected = .TRUE. !original
4741 188 : tariff.isSelected = true; // BTG changed 2/7/2005 CR6573
4742 : }
4743 : }
4744 : }
4745 : // Now select for the electric meters. If electric buying and selling and netmetering all are going
4746 : // on, need to determine which combination should be selected. Within each group select just one set
4747 : // of electric results. The electric results can be either the buy rate only, the buy rate plus the
4748 : // sell rate, or the netmetering rate, whichever of these three is the lowest combination.
4749 : // (The kindElectricMtr was assigned in GetInputEconomicsTariff)
4750 284 : for (int mGroup = 1; mGroup <= groupCount; ++mGroup) {
4751 184 : int lowestSimpleTariff = 0;
4752 184 : int lowestPurchaseTariff = 0;
4753 184 : int lowestSurplusSoldTariff = 0;
4754 184 : int lowestNetMeterTariff = 0;
4755 746 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4756 562 : auto &tariff = s_econ->tariff(iTariff);
4757 562 : if (tariff.isQualified) {
4758 562 : if (tariff.isSelected) {
4759 356 : if (groupIndex(iTariff) == mGroup) {
4760 188 : if (tariff.kindMtr == MeterType::ElecSimple) {
4761 96 : lowestSimpleTariff = iTariff;
4762 92 : } else if (tariff.kindMtr == MeterType::ElecProduced) {
4763 : // don't show electric produced rates as ever selected since surplus sold is more relevant
4764 0 : tariff.isSelected = false;
4765 92 : } else if (tariff.kindMtr == MeterType::ElecPurchased) {
4766 1 : lowestPurchaseTariff = iTariff;
4767 91 : } else if (tariff.kindMtr == MeterType::ElecSurplusSold) {
4768 1 : lowestSurplusSoldTariff = iTariff;
4769 90 : } else if (tariff.kindMtr == MeterType::ElecNet) {
4770 4 : lowestNetMeterTariff = iTariff;
4771 : }
4772 : }
4773 : }
4774 : }
4775 : }
4776 : // compare the simple and purchased metered tariffs
4777 184 : if ((lowestSimpleTariff > 0) && (lowestPurchaseTariff > 0)) {
4778 0 : if (s_econ->tariff(lowestSimpleTariff).totalAnnualCost < s_econ->tariff(lowestPurchaseTariff).totalAnnualCost) {
4779 0 : s_econ->tariff(lowestPurchaseTariff).isSelected = false;
4780 0 : lowestPurchaseTariff = 0;
4781 : } else {
4782 0 : s_econ->tariff(lowestSimpleTariff).isSelected = false;
4783 0 : lowestSimpleTariff = 0;
4784 : }
4785 : }
4786 : // if surplus sold is negative use it otherwise don't
4787 184 : if (lowestSurplusSoldTariff > 0) {
4788 1 : if (s_econ->tariff(lowestSurplusSoldTariff).totalAnnualCost > 0) {
4789 0 : s_econ->tariff(lowestSurplusSoldTariff).isSelected = false;
4790 0 : lowestSurplusSoldTariff = 0;
4791 : }
4792 : }
4793 : // if netmetering is used compare it to simple plus surplus
4794 184 : if (((lowestNetMeterTariff > 0) && (lowestSurplusSoldTariff > 0)) && (lowestSimpleTariff > 0)) {
4795 0 : if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost <
4796 0 : (s_econ->tariff(lowestSimpleTariff).totalAnnualCost + s_econ->tariff(lowestSurplusSoldTariff).totalAnnualCost)) {
4797 0 : s_econ->tariff(lowestSimpleTariff).isSelected = false;
4798 0 : lowestSimpleTariff = 0;
4799 0 : s_econ->tariff(lowestSurplusSoldTariff).isSelected = false;
4800 0 : lowestSurplusSoldTariff = 0;
4801 : } else {
4802 0 : s_econ->tariff(lowestNetMeterTariff).isSelected = false;
4803 0 : lowestNetMeterTariff = 0;
4804 : }
4805 : }
4806 : // if netmetering is used compare it to purchased plus surplus
4807 184 : if (((lowestNetMeterTariff > 0) && (lowestSurplusSoldTariff > 0)) && (lowestPurchaseTariff > 0)) {
4808 1 : if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost <
4809 1 : (s_econ->tariff(lowestPurchaseTariff).totalAnnualCost + s_econ->tariff(lowestSurplusSoldTariff).totalAnnualCost)) {
4810 0 : s_econ->tariff(lowestPurchaseTariff).isSelected = false;
4811 0 : lowestPurchaseTariff = 0;
4812 0 : s_econ->tariff(lowestSurplusSoldTariff).isSelected = false;
4813 : // lowestSurplusSoldTariff = 0; // not used after this point
4814 : } else {
4815 1 : s_econ->tariff(lowestNetMeterTariff).isSelected = false;
4816 1 : lowestNetMeterTariff = 0;
4817 : }
4818 : }
4819 : // if netmetering is used compare it to simple only
4820 184 : if ((lowestNetMeterTariff > 0) && (lowestSimpleTariff > 0)) {
4821 0 : if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost < s_econ->tariff(lowestSimpleTariff).totalAnnualCost) {
4822 0 : s_econ->tariff(lowestSimpleTariff).isSelected = false;
4823 : // lowestSimpleTariff = 0; // not used after this point
4824 : } else {
4825 0 : s_econ->tariff(lowestNetMeterTariff).isSelected = false;
4826 0 : lowestNetMeterTariff = 0;
4827 : }
4828 : }
4829 : // if netmetering is used compare it to purchased only
4830 184 : if ((lowestNetMeterTariff > 0) && (lowestPurchaseTariff > 0)) {
4831 0 : if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost < s_econ->tariff(lowestPurchaseTariff).totalAnnualCost) {
4832 0 : s_econ->tariff(lowestPurchaseTariff).isSelected = false;
4833 : // lowestPurchaseTariff = 0; // not used after this point
4834 : } else {
4835 0 : s_econ->tariff(lowestNetMeterTariff).isSelected = false;
4836 : // lowestNetMeterTariff = 0; // not used after this point
4837 : }
4838 : }
4839 : }
4840 100 : groupIndex.deallocate();
4841 100 : MinTariffIndex.deallocate();
4842 100 : }
4843 :
4844 96 : void GetMonthlyCostForResource(EnergyPlusData &state, Constant::eResource const inResourceNumber, Array1A<Real64> outMonthlyCosts)
4845 : {
4846 : // AUTHOR Jason Glazer
4847 : // DATE WRITTEN May 2010
4848 :
4849 : // Return the total annual cost for a given resource number.
4850 :
4851 : // Argument array dimensioning
4852 96 : auto const &s_econ = state.dataEconTariff;
4853 :
4854 96 : outMonthlyCosts.dim(12);
4855 :
4856 96 : outMonthlyCosts = 0.0;
4857 816 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4858 720 : auto const &tariff = s_econ->tariff(iTariff);
4859 720 : if (tariff.isSelected) {
4860 192 : if (tariff.resource == inResourceNumber) {
4861 4 : auto const &econVar = s_econ->econVar(tariff.cats[(int)Cat::Total]);
4862 52 : for (int jMonth = 1; jMonth <= 12; ++jMonth) { // use 12 because LCC assume 12 months
4863 48 : outMonthlyCosts(jMonth) += econVar.values(jMonth);
4864 : }
4865 : }
4866 : }
4867 : }
4868 96 : }
4869 :
4870 : } // namespace EnergyPlus::EconomicTariff
|