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 18787 : 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 18787 : auto &s_econ = state.dataEconTariff;
227 :
228 18787 : if (s_econ->Update_GetInput) {
229 80 : bool ErrorsFound = false;
230 :
231 80 : GetInputEconomicsTariff(state, ErrorsFound);
232 : // do rest of GetInput only if at least one tariff is defined.
233 80 : GetInputEconomicsCurrencyType(state, ErrorsFound);
234 80 : if (s_econ->numTariff >= 1) {
235 7 : if (!ErrorsFound && state.dataOutRptTab->displayEconomicResultSummary) {
236 0 : OutputReportTabular::AddTOCEntry(state, "Economics Results Summary Report", "Entire Facility");
237 : }
238 7 : CreateCategoryNativeVariables(state);
239 7 : GetInputEconomicsQualify(state, ErrorsFound);
240 7 : GetInputEconomicsChargeSimple(state, ErrorsFound);
241 7 : GetInputEconomicsChargeBlock(state, ErrorsFound);
242 7 : GetInputEconomicsRatchet(state, ErrorsFound);
243 7 : GetInputEconomicsVariable(state, ErrorsFound);
244 7 : GetInputEconomicsComputation(state, ErrorsFound);
245 7 : CreateDefaultComputation(state);
246 : }
247 80 : s_econ->Update_GetInput = false;
248 80 : if (ErrorsFound) {
249 0 : ShowFatalError(state, "UpdateUtilityBills: Preceding errors cause termination.");
250 : }
251 : }
252 18787 : if (state.dataGlobal->DoOutputReporting && (state.dataGlobal->KindOfSim == Constant::KindOfSim::RunPeriodWeather)) {
253 3 : GatherForEconomics(state);
254 : }
255 18787 : }
256 :
257 : //======================================================================================================================
258 : //======================================================================================================================
259 :
260 : // GET INPUT ROUTINES
261 :
262 : //======================================================================================================================
263 : //======================================================================================================================
264 :
265 80 : 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 80 : Constant::Units UnitsVar = Constant::Units::None; // Units sting, may be blank
290 80 : Array1D_string NamesOfKeys; // Specific key name
291 80 : Array1D_int IndexesForKeyVar; // Array index
292 :
293 80 : auto &s_ipsc = state.dataIPShortCut;
294 80 : auto &s_econ = state.dataEconTariff;
295 :
296 80 : std::string_view CurrentModuleObject = "UtilityCost:Tariff";
297 80 : s_econ->numTariff = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, CurrentModuleObject);
298 80 : s_econ->tariff.allocate(s_econ->numTariff);
299 87 : for (int iInObj = 1; iInObj <= s_econ->numTariff; ++iInObj) {
300 14 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
301 : CurrentModuleObject,
302 : iInObj,
303 7 : s_ipsc->cAlphaArgs,
304 : NumAlphas,
305 7 : s_ipsc->rNumericArgs,
306 : NumNums,
307 : IOStat,
308 7 : s_ipsc->lNumericFieldBlanks,
309 7 : s_ipsc->lAlphaFieldBlanks,
310 7 : s_ipsc->cAlphaFieldNames,
311 7 : s_ipsc->cNumericFieldNames);
312 :
313 7 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
314 7 : auto &tariff = s_econ->tariff(iInObj);
315 :
316 : // check to make sure none of the values are another economic object
317 73 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
318 : // args are always turned to upper case but this is okay...
319 66 : 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 7 : tariff.tariffName = s_ipsc->cAlphaArgs(1);
326 : // check if tariff name is unique
327 7 : int found = 0;
328 7 : for (int jObj = 1; jObj <= iInObj - 1; ++jObj) {
329 0 : if (tariff.tariffName == s_econ->tariff(jObj).tariffName) {
330 0 : found = jObj;
331 0 : break;
332 : }
333 : }
334 7 : if (found > 0) {
335 0 : ShowSevereDuplicateName(state, eoh);
336 0 : ErrorsFound = true;
337 : }
338 : // name of the report meter
339 7 : tariff.reportMeter = s_ipsc->cAlphaArgs(2);
340 : // call the key count function but only need count during this pass
341 7 : GetVariableKeyCountandType(state, tariff.reportMeter, KeyCount, TypeVar, AvgSumVar, StepTypeVar, UnitsVar);
342 : // if no meters found for that name
343 7 : if (KeyCount == 0) {
344 3 : ShowWarningError(state, format("{}{}=\"{}\" missing meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
345 6 : ShowContinueError(
346 : state,
347 6 : format("Meter referenced is not present due to a lack of equipment that uses that energy source/meter:\"{}\".", tariff.reportMeter));
348 3 : tariff.reportMeterIndx = -1;
349 : } else {
350 4 : NamesOfKeys.allocate(KeyCount);
351 4 : IndexesForKeyVar.allocate(KeyCount);
352 4 : 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 4 : 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 4 : tariff.reportMeterIndx = IndexesForKeyVar(1);
360 : // get rid of the arrays used to get the variable number
361 4 : NamesOfKeys.deallocate();
362 4 : 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 7 : tariff.kindMtr = MeterType::Other;
368 :
369 : // Determine whether this meter is related to electricity, or water, or gas
370 7 : if (tariff.reportMeterIndx != -1) {
371 4 : switch (state.dataOutputProcessor->meters[tariff.reportMeterIndx]->resource) {
372 : // Various types of electricity meters
373 1 : case Constant::eResource::Electricity: {
374 1 : tariff.kindMtr = MeterType::ElecSimple;
375 1 : } break;
376 0 : case Constant::eResource::ElectricityProduced: {
377 0 : tariff.kindMtr = MeterType::ElecProduced;
378 0 : } break;
379 0 : case Constant::eResource::ElectricityPurchased: {
380 0 : tariff.kindMtr = MeterType::ElecPurchased;
381 0 : } break;
382 0 : case Constant::eResource::ElectricitySurplusSold: {
383 0 : tariff.kindMtr = MeterType::ElecSurplusSold;
384 0 : } break;
385 0 : case Constant::eResource::ElectricityNet: {
386 0 : tariff.kindMtr = MeterType::ElecNet;
387 0 : } break;
388 : // Handle the case where its a water meter
389 2 : 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 2 : tariff.kindMtr = MeterType::Water;
396 2 : } break;
397 : // Or a Natural Gas meter
398 1 : case Constant::eResource::NaturalGas: {
399 1 : tariff.kindMtr = MeterType::Gas;
400 1 : } 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 7 : switch (tariff.kindMtr) {
412 2 : case MeterType::Water: {
413 : // conversion factor
414 2 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
415 2 : switch (tariff.convChoice) {
416 0 : case EconConv::USERDEF: {
417 0 : tariff.energyConv = s_ipsc->rNumericArgs(1); // energy conversion factor
418 0 : tariff.demandConv = s_ipsc->rNumericArgs(2); // demand conversion factor
419 0 : } break;
420 :
421 0 : case EconConv::M3: {
422 0 : tariff.energyConv = 1.0;
423 0 : tariff.demandConv = 3600.0;
424 0 : } break;
425 :
426 1 : case EconConv::CCF: {
427 1 : tariff.energyConv = 0.35314666721488586;
428 1 : tariff.demandConv = 0.35314666721488586 * 3600;
429 1 : } 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 1 : default: { // ERROR: not a valid conversion, default to M3
442 1 : tariff.convChoice = EconConv::M3;
443 1 : tariff.energyConv = 1.0;
444 1 : tariff.demandConv = 3600.0;
445 1 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "M3");
446 1 : } break;
447 : } // switch (tariff.convChoice)
448 :
449 2 : } 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 1 : case MeterType::ElecSimple:
455 : case MeterType::ElecProduced:
456 : case MeterType::ElecPurchased:
457 : case MeterType::ElecSurplusSold:
458 : case MeterType::ElecNet: {
459 1 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
460 :
461 1 : 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 0 : case EconConv::KWH: {
468 0 : tariff.energyConv = 0.0000002778;
469 0 : tariff.demandConv = 0.001;
470 0 : } 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 1 : default: {
499 1 : tariff.convChoice = EconConv::KWH;
500 1 : tariff.energyConv = 0.0000002778;
501 1 : tariff.demandConv = 0.001;
502 1 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
503 1 : } break;
504 : } // switch (tariff.convChoice)
505 1 : } break;
506 :
507 : // If it's a gas meter
508 1 : case MeterType::Gas: {
509 1 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
510 1 : 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 0 : case EconConv::THERM: {
522 0 : tariff.energyConv = 9.4781712e-9;
523 0 : tariff.demandConv = 0.00003412;
524 0 : } 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 0 : case EconConv::MCF: {
543 0 : tariff.energyConv = 9.4781712e-10;
544 0 : tariff.demandConv = 0.000003412;
545 0 : } break;
546 :
547 1 : case EconConv::CCF: {
548 1 : tariff.energyConv = 9.4781712e-9;
549 1 : tariff.demandConv = 0.00003412;
550 1 : } 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 1 : } 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 3 : case MeterType::Other: {
571 3 : tariff.convChoice = static_cast<EconConv>(getEnumValue(econConvNamesUC, s_ipsc->cAlphaArgs(3)));
572 3 : 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 3 : case EconConv::KWH: {
579 3 : tariff.energyConv = 0.0000002778;
580 3 : tariff.demandConv = 0.001;
581 3 : } 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 0 : default: {
605 0 : tariff.convChoice = EconConv::KWH;
606 0 : tariff.energyConv = 0.0000002778;
607 0 : tariff.demandConv = 0.001;
608 0 : ShowWarningInvalidKey(state, eoh, s_ipsc->cAlphaFieldNames(3), s_ipsc->cAlphaArgs(3), "KWH");
609 0 : } break;
610 : } // switch (tariff.convChoice)
611 3 : } 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 7 : if (len(s_ipsc->cAlphaArgs(4)) > 0) {
620 1 : 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 7 : if (len(s_ipsc->cAlphaArgs(5)) > 0) {
628 3 : 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 7 : 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 7 : 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 0 : 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 0 : case 4:
671 : case 12:
672 : case 20:
673 : case 60: {
674 0 : tariff.demandWindow = DemandWindow::Quarter;
675 0 : tariff.demWinTime = 0.25;
676 0 : } break;
677 0 : default: {
678 0 : assert(false);
679 : } break;
680 : }
681 : }
682 7 : } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "HalfHour")) {
683 : {
684 0 : 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 0 : case 2:
698 : case 4:
699 : case 6:
700 : case 10:
701 : case 12:
702 : case 20:
703 : case 30:
704 : case 60: {
705 0 : tariff.demandWindow = DemandWindow::Half;
706 0 : tariff.demWinTime = 0.50;
707 0 : } break;
708 0 : default: {
709 : // assert(false); // EconomicTariff unit test gets here with NumOfTimeStepInHour == 0
710 0 : } break;
711 : }
712 : }
713 7 : } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "FullHour")) {
714 0 : tariff.demandWindow = DemandWindow::Hour;
715 0 : tariff.demWinTime = 1.00;
716 7 : } else if (Util::SameString(s_ipsc->cAlphaArgs(7), "Day")) {
717 0 : tariff.demandWindow = DemandWindow::Day;
718 0 : tariff.demWinTime = 24.00;
719 7 : } 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 7 : 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 0 : case 2:
734 : case 6:
735 : case 10:
736 : case 30: {
737 0 : tariff.demandWindow = DemandWindow::Half;
738 0 : tariff.demWinTime = 0.50;
739 0 : } break;
740 7 : case 4:
741 : case 12:
742 : case 20:
743 : case 60: {
744 7 : tariff.demandWindow = DemandWindow::Quarter;
745 7 : tariff.demWinTime = 0.25;
746 7 : } 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 7 : tariff.monthChgVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(8), isNotNumeric);
755 7 : tariff.monthChgPt =
756 7 : AssignVariablePt(state, s_ipsc->cAlphaArgs(8), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, iInObj);
757 : // minimum monthly charge
758 7 : if (len(s_ipsc->cAlphaArgs(9)) > 0) {
759 0 : tariff.minMonthChgVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(9), isNotNumeric);
760 : } else {
761 7 : tariff.minMonthChgVal = -HUGE_(-1.0); // set to a very negative value
762 : }
763 7 : tariff.minMonthChgPt =
764 7 : AssignVariablePt(state, s_ipsc->cAlphaArgs(9), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, iInObj);
765 : // real time pricing
766 7 : tariff.chargeSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(10));
767 7 : tariff.baseUseSched = Sched::GetSchedule(state, s_ipsc->cAlphaArgs(11));
768 : // group name for separate distribution and transmission rates
769 7 : tariff.groupName = s_ipsc->cAlphaArgs(12);
770 : // buy or sell option
771 :
772 7 : if (s_ipsc->lAlphaFieldBlanks(13)) {
773 5 : tariff.buyOrSell = BuySell::BuyFromUtility;
774 2 : } 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 7 : if (tariff.buyOrSell == BuySell::SellToUtility) {
781 0 : 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 7 : } else if (tariff.buyOrSell == BuySell::NetMetering) {
787 2 : 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 5 : } else if (tariff.buyOrSell == BuySell::BuyFromUtility) {
793 5 : if (hasi(tariff.reportMeter, "Elec")) { // test if electric meter
794 3 : if (!(Util::SameString(tariff.reportMeter, "Electricity:Facility") ||
795 3 : Util::SameString(tariff.reportMeter, "ElectricityPurchased:Facility"))) {
796 0 : ShowWarningError(state, format("{}{}=\"{}\" atypical meter", RoutineName, CurrentModuleObject, s_ipsc->cAlphaArgs(1)));
797 0 : ShowContinueError(state,
798 0 : format("The meter chosen \"{}\" is not typically used with the buyFromUtility option.", tariff.reportMeter));
799 0 : 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 91 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
808 84 : tariff.seasonForMonth(kMonth) = Season::Invalid;
809 504 : for (int lPeriod = 0; lPeriod < (int)Period::Num; ++lPeriod) {
810 420 : tariff.gatherEnergy(kMonth)[lPeriod] = 0.0;
811 420 : tariff.gatherDemand(kMonth)[lPeriod] = 0.0;
812 : }
813 : }
814 :
815 : // assume that the tariff is qualified
816 7 : tariff.isQualified = true;
817 7 : tariff.ptDisqualifier = 0;
818 : // assume that the tariff is not selected
819 7 : tariff.isSelected = false;
820 7 : tariff.totalAnnualCost = 0.0;
821 : // now create the Table Of Contents entries for an HTML file
822 7 : if (state.dataOutRptTab->displayTariffReport) {
823 0 : OutputReportTabular::AddTOCEntry(state, "Tariff Report", tariff.tariffName);
824 : }
825 : // associate the resource number with each tariff
826 7 : if (tariff.reportMeterIndx != -1) {
827 4 : tariff.resource = state.dataOutputProcessor->meters[tariff.reportMeterIndx]->resource;
828 : }
829 : }
830 80 : }
831 :
832 7 : 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 7 : auto &s_econ = state.dataEconTariff;
850 7 : auto &s_ipsc = state.dataIPShortCut;
851 :
852 7 : s_ipsc->cCurrentModuleObject = "UtilityCost:Qualify";
853 7 : s_econ->numQualify = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
854 7 : s_econ->qualify.allocate(s_econ->numQualify);
855 :
856 8 : for (iInObj = 1; iInObj <= s_econ->numQualify; ++iInObj) {
857 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
858 1 : s_ipsc->cCurrentModuleObject,
859 : iInObj,
860 1 : s_ipsc->cAlphaArgs,
861 : NumAlphas,
862 1 : s_ipsc->rNumericArgs,
863 : NumNums,
864 : IOStat,
865 1 : s_ipsc->lNumericFieldBlanks,
866 1 : s_ipsc->lAlphaFieldBlanks,
867 1 : s_ipsc->cAlphaFieldNames,
868 1 : s_ipsc->cNumericFieldNames);
869 :
870 1 : ErrorObjectHeader eoh{routineName, s_ipsc->cCurrentModuleObject, s_ipsc->cAlphaArgs(1)};
871 :
872 1 : auto &qualify = s_econ->qualify(iInObj);
873 :
874 : // check to make sure none of the values are another economic object
875 8 : for (jFld = 1; jFld <= NumAlphas; ++jFld) {
876 7 : 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 1 : qualify.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
883 1 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), qualify.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
884 1 : qualify.namePt =
885 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::Qualify, iInObj, qualify.tariffIndx);
886 : // index of the variable in the variable array
887 1 : qualify.sourcePt =
888 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, qualify.tariffIndx);
889 : // indicator if maximum test otherwise minimum
890 1 : if (s_ipsc->cAlphaArgs(4) == "MINIMUM") {
891 1 : qualify.isMaximum = false;
892 0 : } else if (s_ipsc->cAlphaArgs(4) == "MAXIMUM") {
893 0 : 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 1 : qualify.thresholdVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(5), isNotNumeric);
900 1 : qualify.thresholdPt =
901 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(5), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, qualify.tariffIndx);
902 : // enumerated list of the kind of season
903 1 : 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 1 : if (s_ipsc->cAlphaArgs(7) == "COUNT") {
910 1 : 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 1 : qualify.numberOfMonths = s_ipsc->rNumericArgs(1);
919 : }
920 7 : }
921 :
922 7 : 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 7 : auto &s_econ = state.dataEconTariff;
937 7 : auto &s_ipsc = state.dataIPShortCut;
938 7 : s_ipsc->cCurrentModuleObject = "UtilityCost:Charge:Simple";
939 :
940 7 : s_econ->numChargeSimple = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
941 7 : s_econ->chargeSimple.allocate(s_econ->numChargeSimple);
942 15 : for (int iInObj = 1; iInObj <= s_econ->numChargeSimple; ++iInObj) {
943 8 : auto &chargeSimple = s_econ->chargeSimple(iInObj);
944 16 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
945 8 : s_ipsc->cCurrentModuleObject,
946 : iInObj,
947 8 : s_ipsc->cAlphaArgs,
948 : NumAlphas,
949 8 : s_ipsc->rNumericArgs,
950 : NumNums,
951 : IOStat,
952 8 : s_ipsc->lNumericFieldBlanks,
953 8 : s_ipsc->lAlphaFieldBlanks,
954 8 : s_ipsc->cAlphaFieldNames,
955 8 : s_ipsc->cNumericFieldNames);
956 :
957 8 : 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 56 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
961 48 : 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 8 : chargeSimple.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
968 8 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), chargeSimple.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
969 8 : chargeSimple.namePt = AssignVariablePt(
970 8 : state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::ChargeSimple, iInObj, chargeSimple.tariffIndx);
971 : // index of the variable in the variable array
972 8 : chargeSimple.sourcePt =
973 8 : AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeSimple.tariffIndx);
974 : // enumerated list of the kind of season
975 8 : chargeSimple.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(4)));
976 8 : 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 8 : if (chargeSimple.season != Season::Annual) {
983 7 : if (chargeSimple.tariffIndx != 0) {
984 7 : 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 8 : chargeSimple.categoryPt =
994 8 : AssignVariablePt(state, s_ipsc->cAlphaArgs(5), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeSimple.tariffIndx);
995 : // cost per unit value or variable
996 8 : chargeSimple.costPerVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(6), isNotNumeric);
997 8 : chargeSimple.costPerPt = AssignVariablePt(
998 8 : state, s_ipsc->cAlphaArgs(6), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeSimple.tariffIndx);
999 : }
1000 7 : }
1001 :
1002 7 : 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 7 : Real64 hugeNumber(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
1018 :
1019 7 : auto &s_econ = state.dataEconTariff;
1020 7 : auto &s_ipsc = state.dataIPShortCut;
1021 7 : s_ipsc->cCurrentModuleObject = "UtilityCost:Charge:Block";
1022 :
1023 7 : hugeNumber = HUGE_(hugeNumber);
1024 7 : s_econ->numChargeBlock = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1025 7 : s_econ->chargeBlock.allocate(s_econ->numChargeBlock);
1026 8 : for (int iInObj = 1; iInObj <= s_econ->numChargeBlock; ++iInObj) {
1027 1 : auto &chargeBlock = s_econ->chargeBlock(iInObj);
1028 2 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1029 1 : s_ipsc->cCurrentModuleObject,
1030 : iInObj,
1031 1 : s_ipsc->cAlphaArgs,
1032 : NumAlphas,
1033 1 : s_ipsc->rNumericArgs,
1034 : NumNums,
1035 : IOStat,
1036 1 : s_ipsc->lNumericFieldBlanks,
1037 1 : s_ipsc->lAlphaFieldBlanks,
1038 1 : s_ipsc->cAlphaFieldNames,
1039 1 : s_ipsc->cNumericFieldNames);
1040 :
1041 1 : 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 14 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
1045 13 : 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 1 : chargeBlock.tariffIndx = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
1052 1 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), chargeBlock.tariffIndx, ErrorsFound, s_ipsc->cCurrentModuleObject);
1053 1 : chargeBlock.namePt = AssignVariablePt(
1054 1 : state, s_ipsc->cAlphaArgs(1), true, varIsAssigned, varNotYetDefined, ObjType::ChargeBlock, iInObj, chargeBlock.tariffIndx);
1055 : // index of the variable in the variable array
1056 1 : chargeBlock.sourcePt =
1057 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(3), true, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeBlock.tariffIndx);
1058 : // enumerated list of the kind of season
1059 1 : chargeBlock.season = static_cast<Season>(getEnumValue(seasonNamesUC, s_ipsc->cAlphaArgs(4)));
1060 1 : 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 1 : if (chargeBlock.season != Season::Annual) {
1067 1 : if (chargeBlock.tariffIndx != 0) {
1068 1 : 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 1 : chargeBlock.categoryPt =
1078 1 : 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 1 : chargeBlock.remainingPt =
1081 1 : AssignVariablePt(state, s_ipsc->cAlphaArgs(6), true, varIsAssigned, varNotYetDefined, ObjType::Category, iInObj, chargeBlock.tariffIndx);
1082 : // block size multiplier
1083 1 : if (len(s_ipsc->cAlphaArgs(7)) == 0) { // if blank
1084 1 : chargeBlock.blkSzMultVal = 1.0; // default is 1 if left blank
1085 1 : chargeBlock.blkSzMultPt = 0;
1086 : } else {
1087 0 : chargeBlock.blkSzMultVal = Util::ProcessNumber(s_ipsc->cAlphaArgs(7), isNotNumeric);
1088 0 : chargeBlock.blkSzMultPt = AssignVariablePt(
1089 0 : state, s_ipsc->cAlphaArgs(7), isNotNumeric, varIsArgument, varNotYetDefined, ObjType::Invalid, 0, chargeBlock.tariffIndx);
1090 : }
1091 : // number of blocks used
1092 1 : chargeBlock.numBlk = (NumAlphas - 7) / 2;
1093 4 : for (int jBlk = 1; jBlk <= chargeBlock.numBlk; ++jBlk) {
1094 3 : alphaOffset = 7 + (jBlk - 1) * 2;
1095 : // catch the "remaining" code word for the block size
1096 3 : if (Util::SameString(s_ipsc->cAlphaArgs(alphaOffset + 1), "REMAINING")) {
1097 1 : chargeBlock.blkSzVal(jBlk) = hugeNumber / 1000000; // using small portion of largest possible value to prevent overflow
1098 1 : chargeBlock.blkSzPt(jBlk) = 0;
1099 : } else {
1100 : // array of block size
1101 2 : chargeBlock.blkSzVal(jBlk) = Util::ProcessNumber(s_ipsc->cAlphaArgs(alphaOffset + 1), isNotNumeric);
1102 :
1103 2 : chargeBlock.blkSzPt(jBlk) = AssignVariablePt(state,
1104 2 : 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 3 : chargeBlock.blkCostVal(jBlk) = Util::ProcessNumber(s_ipsc->cAlphaArgs(alphaOffset + 2), isNotNumeric);
1114 3 : chargeBlock.blkCostPt(jBlk) = AssignVariablePt(state,
1115 3 : s_ipsc->cAlphaArgs(alphaOffset + 2),
1116 : isNotNumeric,
1117 : varIsArgument,
1118 : varNotYetDefined,
1119 : ObjType::Invalid,
1120 : 0,
1121 : chargeBlock.tariffIndx);
1122 : }
1123 : }
1124 7 : }
1125 :
1126 7 : 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 7 : auto &s_econ = state.dataEconTariff;
1142 7 : auto &s_ipsc = state.dataIPShortCut;
1143 7 : s_ipsc->cCurrentModuleObject = "UtilityCost:Ratchet";
1144 :
1145 7 : s_econ->numRatchet = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1146 7 : s_econ->ratchet.allocate(s_econ->numRatchet);
1147 8 : 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 7 : }
1205 :
1206 11 : 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 11 : auto &s_econ = state.dataEconTariff;
1221 11 : auto &s_ipsc = state.dataIPShortCut;
1222 :
1223 11 : s_ipsc->cCurrentModuleObject = "UtilityCost:Variable";
1224 11 : int numEconVarObj = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1225 15 : for (int iInObj = 1; iInObj <= numEconVarObj; ++iInObj) {
1226 8 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1227 4 : s_ipsc->cCurrentModuleObject,
1228 : iInObj,
1229 4 : s_ipsc->cAlphaArgs,
1230 : NumAlphas,
1231 4 : s_ipsc->rNumericArgs,
1232 : NumNums,
1233 : IOStat,
1234 4 : s_ipsc->lNumericFieldBlanks,
1235 4 : s_ipsc->lAlphaFieldBlanks,
1236 4 : s_ipsc->cAlphaFieldNames,
1237 4 : s_ipsc->cNumericFieldNames);
1238 :
1239 4 : 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 16 : for (int jFld = 1; jFld <= NumAlphas; ++jFld) {
1243 12 : 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 4 : int tariffPt = FindTariffIndex(state, s_ipsc->cAlphaArgs(2), s_ipsc->cAlphaArgs(1), ErrorsFound, s_ipsc->cCurrentModuleObject);
1249 4 : int variablePt = AssignVariablePt(state, s_ipsc->cAlphaArgs(1), true, varIsArgument, varUserDefined, ObjType::Variable, iInObj, tariffPt);
1250 4 : warnIfNativeVarname(state, s_ipsc->cAlphaArgs(1), tariffPt, ErrorsFound, s_ipsc->cCurrentModuleObject);
1251 4 : auto &econVar = s_econ->econVar(variablePt);
1252 :
1253 : // validate the kind of variable - not used internally except for validation
1254 4 : econVar.varUnitType = static_cast<VarUnitType>(getEnumValue(varUnitTypeNamesUC, s_ipsc->cAlphaArgs(3)));
1255 4 : 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 52 : for (int jVal = 1; jVal <= NumNums; ++jVal) {
1263 48 : econVar.values(jVal) = s_ipsc->rNumericArgs(jVal);
1264 : }
1265 : // fill the rest of the array with the last value entered
1266 4 : 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 11 : }
1273 :
1274 7 : 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 7 : auto &s_econ = state.dataEconTariff;
1289 7 : auto &s_ipsc = state.dataIPShortCut;
1290 :
1291 7 : s_ipsc->cCurrentModuleObject = "UtilityCost:Computation";
1292 7 : s_econ->numComputation = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1293 7 : s_econ->computation.allocate(s_econ->numTariff); // not the number of Computations but the number of tariffs
1294 : // set default values for computation
1295 14 : for (auto &e : s_econ->computation) {
1296 7 : e.computeName.clear();
1297 7 : e.firstStep = 0;
1298 7 : e.lastStep = -1;
1299 7 : e.isUserDef = false;
1300 7 : }
1301 8 : 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 7 : }
1352 :
1353 80 : 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 80 : auto &s_ipsc = state.dataIPShortCut;
1370 80 : s_ipsc->cCurrentModuleObject = "CurrencyType";
1371 :
1372 80 : initializeMonetaryUnit(state);
1373 80 : NumCurrencyType = state.dataInputProcessing->inputProcessor->getNumObjectsFound(state, s_ipsc->cCurrentModuleObject);
1374 80 : state.dataCostEstimateManager->selectedMonetaryUnit = 0; // invalid
1375 80 : if (NumCurrencyType == 0) {
1376 80 : state.dataCostEstimateManager->selectedMonetaryUnit = 1; // USD - U.S. Dollar
1377 0 : } else if (NumCurrencyType == 1) {
1378 0 : state.dataInputProcessing->inputProcessor->getObjectItem(state,
1379 0 : s_ipsc->cCurrentModuleObject,
1380 : 1,
1381 0 : s_ipsc->cAlphaArgs,
1382 : NumAlphas,
1383 0 : s_ipsc->rNumericArgs,
1384 : NumNums,
1385 : IOStat,
1386 0 : s_ipsc->lNumericFieldBlanks,
1387 0 : s_ipsc->lAlphaFieldBlanks,
1388 0 : s_ipsc->cAlphaFieldNames,
1389 0 : s_ipsc->cNumericFieldNames);
1390 : // Monetary Unit
1391 0 : for (i = 1; i <= (int)state.dataCostEstimateManager->monetaryUnit.size(); ++i) {
1392 0 : if (Util::SameString(s_ipsc->cAlphaArgs(1), state.dataCostEstimateManager->monetaryUnit(i).code)) {
1393 0 : state.dataCostEstimateManager->selectedMonetaryUnit = i;
1394 0 : break;
1395 : }
1396 : }
1397 0 : 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 80 : }
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 80 : 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 80 : int numMonetaryUnit = 111;
1546 80 : state.dataCostEstimateManager->monetaryUnit.allocate(numMonetaryUnit);
1547 80 : state.dataCostEstimateManager->monetaryUnit(1).code = "USD";
1548 80 : state.dataCostEstimateManager->monetaryUnit(2).code = "AFN";
1549 80 : state.dataCostEstimateManager->monetaryUnit(3).code = "ALL";
1550 80 : state.dataCostEstimateManager->monetaryUnit(4).code = "ANG";
1551 80 : state.dataCostEstimateManager->monetaryUnit(5).code = "ARS";
1552 80 : state.dataCostEstimateManager->monetaryUnit(6).code = "AUD";
1553 80 : state.dataCostEstimateManager->monetaryUnit(7).code = "AWG";
1554 80 : state.dataCostEstimateManager->monetaryUnit(8).code = "AZN";
1555 80 : state.dataCostEstimateManager->monetaryUnit(9).code = "BAM";
1556 80 : state.dataCostEstimateManager->monetaryUnit(10).code = "BBD";
1557 80 : state.dataCostEstimateManager->monetaryUnit(11).code = "BGN";
1558 80 : state.dataCostEstimateManager->monetaryUnit(12).code = "BMD";
1559 80 : state.dataCostEstimateManager->monetaryUnit(13).code = "BND";
1560 80 : state.dataCostEstimateManager->monetaryUnit(14).code = "BOB";
1561 80 : state.dataCostEstimateManager->monetaryUnit(15).code = "BRL";
1562 80 : state.dataCostEstimateManager->monetaryUnit(16).code = "BSD";
1563 80 : state.dataCostEstimateManager->monetaryUnit(17).code = "BWP";
1564 80 : state.dataCostEstimateManager->monetaryUnit(18).code = "BYR";
1565 80 : state.dataCostEstimateManager->monetaryUnit(19).code = "BZD";
1566 80 : state.dataCostEstimateManager->monetaryUnit(20).code = "CAD";
1567 80 : state.dataCostEstimateManager->monetaryUnit(21).code = "CHF";
1568 80 : state.dataCostEstimateManager->monetaryUnit(22).code = "CLP";
1569 80 : state.dataCostEstimateManager->monetaryUnit(23).code = "CNY";
1570 80 : state.dataCostEstimateManager->monetaryUnit(24).code = "COP";
1571 80 : state.dataCostEstimateManager->monetaryUnit(25).code = "CRC";
1572 80 : state.dataCostEstimateManager->monetaryUnit(26).code = "CUP";
1573 80 : state.dataCostEstimateManager->monetaryUnit(27).code = "CZK";
1574 80 : state.dataCostEstimateManager->monetaryUnit(28).code = "DKK";
1575 80 : state.dataCostEstimateManager->monetaryUnit(29).code = "DOP";
1576 80 : state.dataCostEstimateManager->monetaryUnit(30).code = "EEK";
1577 80 : state.dataCostEstimateManager->monetaryUnit(31).code = "EGP";
1578 80 : state.dataCostEstimateManager->monetaryUnit(32).code = "EUR";
1579 80 : state.dataCostEstimateManager->monetaryUnit(33).code = "FJD";
1580 80 : state.dataCostEstimateManager->monetaryUnit(34).code = "GBP";
1581 80 : state.dataCostEstimateManager->monetaryUnit(35).code = "GHC";
1582 80 : state.dataCostEstimateManager->monetaryUnit(36).code = "GIP";
1583 80 : state.dataCostEstimateManager->monetaryUnit(37).code = "GTQ";
1584 80 : state.dataCostEstimateManager->monetaryUnit(38).code = "GYD";
1585 80 : state.dataCostEstimateManager->monetaryUnit(39).code = "HKD";
1586 80 : state.dataCostEstimateManager->monetaryUnit(40).code = "HNL";
1587 80 : state.dataCostEstimateManager->monetaryUnit(41).code = "HRK";
1588 80 : state.dataCostEstimateManager->monetaryUnit(42).code = "HUF";
1589 80 : state.dataCostEstimateManager->monetaryUnit(43).code = "IDR";
1590 80 : state.dataCostEstimateManager->monetaryUnit(44).code = "ILS";
1591 80 : state.dataCostEstimateManager->monetaryUnit(45).code = "IMP";
1592 80 : state.dataCostEstimateManager->monetaryUnit(46).code = "INR";
1593 80 : state.dataCostEstimateManager->monetaryUnit(47).code = "IRR";
1594 80 : state.dataCostEstimateManager->monetaryUnit(48).code = "ISK";
1595 80 : state.dataCostEstimateManager->monetaryUnit(49).code = "JEP";
1596 80 : state.dataCostEstimateManager->monetaryUnit(50).code = "JMD";
1597 80 : state.dataCostEstimateManager->monetaryUnit(51).code = "JPY";
1598 80 : state.dataCostEstimateManager->monetaryUnit(52).code = "KGS";
1599 80 : state.dataCostEstimateManager->monetaryUnit(53).code = "KHR";
1600 80 : state.dataCostEstimateManager->monetaryUnit(54).code = "KPW";
1601 80 : state.dataCostEstimateManager->monetaryUnit(55).code = "KRW";
1602 80 : state.dataCostEstimateManager->monetaryUnit(56).code = "KYD";
1603 80 : state.dataCostEstimateManager->monetaryUnit(57).code = "KZT";
1604 80 : state.dataCostEstimateManager->monetaryUnit(58).code = "LAK";
1605 80 : state.dataCostEstimateManager->monetaryUnit(59).code = "LBP";
1606 80 : state.dataCostEstimateManager->monetaryUnit(60).code = "LKR";
1607 80 : state.dataCostEstimateManager->monetaryUnit(61).code = "LRD";
1608 80 : state.dataCostEstimateManager->monetaryUnit(62).code = "LTL";
1609 80 : state.dataCostEstimateManager->monetaryUnit(63).code = "LVL";
1610 80 : state.dataCostEstimateManager->monetaryUnit(64).code = "MKD";
1611 80 : state.dataCostEstimateManager->monetaryUnit(65).code = "MNT";
1612 80 : state.dataCostEstimateManager->monetaryUnit(66).code = "MUR";
1613 80 : state.dataCostEstimateManager->monetaryUnit(67).code = "MXN";
1614 80 : state.dataCostEstimateManager->monetaryUnit(68).code = "MYR";
1615 80 : state.dataCostEstimateManager->monetaryUnit(69).code = "MZN";
1616 80 : state.dataCostEstimateManager->monetaryUnit(70).code = "NAD";
1617 80 : state.dataCostEstimateManager->monetaryUnit(71).code = "NGN";
1618 80 : state.dataCostEstimateManager->monetaryUnit(72).code = "NIO";
1619 80 : state.dataCostEstimateManager->monetaryUnit(73).code = "NOK";
1620 80 : state.dataCostEstimateManager->monetaryUnit(74).code = "NPR";
1621 80 : state.dataCostEstimateManager->monetaryUnit(75).code = "NZD";
1622 80 : state.dataCostEstimateManager->monetaryUnit(76).code = "OMR";
1623 80 : state.dataCostEstimateManager->monetaryUnit(77).code = "PAB";
1624 80 : state.dataCostEstimateManager->monetaryUnit(78).code = "PEN";
1625 80 : state.dataCostEstimateManager->monetaryUnit(79).code = "PHP";
1626 80 : state.dataCostEstimateManager->monetaryUnit(80).code = "PKR";
1627 80 : state.dataCostEstimateManager->monetaryUnit(81).code = "PLN";
1628 80 : state.dataCostEstimateManager->monetaryUnit(82).code = "PYG";
1629 80 : state.dataCostEstimateManager->monetaryUnit(83).code = "QAR";
1630 80 : state.dataCostEstimateManager->monetaryUnit(84).code = "RON";
1631 80 : state.dataCostEstimateManager->monetaryUnit(85).code = "RSD";
1632 80 : state.dataCostEstimateManager->monetaryUnit(86).code = "RUB";
1633 80 : state.dataCostEstimateManager->monetaryUnit(87).code = "SAR";
1634 80 : state.dataCostEstimateManager->monetaryUnit(88).code = "SBD";
1635 80 : state.dataCostEstimateManager->monetaryUnit(89).code = "SCR";
1636 80 : state.dataCostEstimateManager->monetaryUnit(90).code = "SEK";
1637 80 : state.dataCostEstimateManager->monetaryUnit(91).code = "SGD";
1638 80 : state.dataCostEstimateManager->monetaryUnit(92).code = "SHP";
1639 80 : state.dataCostEstimateManager->monetaryUnit(93).code = "SOS";
1640 80 : state.dataCostEstimateManager->monetaryUnit(94).code = "SRD";
1641 80 : state.dataCostEstimateManager->monetaryUnit(95).code = "SVC";
1642 80 : state.dataCostEstimateManager->monetaryUnit(96).code = "SYP";
1643 80 : state.dataCostEstimateManager->monetaryUnit(97).code = "THB";
1644 80 : state.dataCostEstimateManager->monetaryUnit(98).code = "TRL";
1645 80 : state.dataCostEstimateManager->monetaryUnit(99).code = "TRY";
1646 80 : state.dataCostEstimateManager->monetaryUnit(100).code = "TTD";
1647 80 : state.dataCostEstimateManager->monetaryUnit(101).code = "TVD";
1648 80 : state.dataCostEstimateManager->monetaryUnit(102).code = "TWD";
1649 80 : state.dataCostEstimateManager->monetaryUnit(103).code = "UAH";
1650 80 : state.dataCostEstimateManager->monetaryUnit(104).code = "UYU";
1651 80 : state.dataCostEstimateManager->monetaryUnit(105).code = "UZS";
1652 80 : state.dataCostEstimateManager->monetaryUnit(106).code = "VEF";
1653 80 : state.dataCostEstimateManager->monetaryUnit(107).code = "VND";
1654 80 : state.dataCostEstimateManager->monetaryUnit(108).code = "XCD";
1655 80 : state.dataCostEstimateManager->monetaryUnit(109).code = "YER";
1656 80 : state.dataCostEstimateManager->monetaryUnit(110).code = "ZAR";
1657 80 : state.dataCostEstimateManager->monetaryUnit(111).code = "ZWD";
1658 :
1659 80 : state.dataCostEstimateManager->monetaryUnit(1).txt = "$";
1660 80 : state.dataCostEstimateManager->monetaryUnit(2).txt = "AFN";
1661 80 : state.dataCostEstimateManager->monetaryUnit(3).txt = "Lek";
1662 80 : state.dataCostEstimateManager->monetaryUnit(4).txt = "ANG";
1663 80 : state.dataCostEstimateManager->monetaryUnit(5).txt = "$";
1664 80 : state.dataCostEstimateManager->monetaryUnit(6).txt = "$";
1665 80 : state.dataCostEstimateManager->monetaryUnit(7).txt = "AWG";
1666 80 : state.dataCostEstimateManager->monetaryUnit(8).txt = "AZN";
1667 80 : state.dataCostEstimateManager->monetaryUnit(9).txt = "KM";
1668 80 : state.dataCostEstimateManager->monetaryUnit(10).txt = "$";
1669 80 : state.dataCostEstimateManager->monetaryUnit(11).txt = "BGN";
1670 80 : state.dataCostEstimateManager->monetaryUnit(12).txt = "$";
1671 80 : state.dataCostEstimateManager->monetaryUnit(13).txt = "$";
1672 80 : state.dataCostEstimateManager->monetaryUnit(14).txt = "$b";
1673 80 : state.dataCostEstimateManager->monetaryUnit(15).txt = "R$";
1674 80 : state.dataCostEstimateManager->monetaryUnit(16).txt = "$";
1675 80 : state.dataCostEstimateManager->monetaryUnit(17).txt = "P";
1676 80 : state.dataCostEstimateManager->monetaryUnit(18).txt = "p.";
1677 80 : state.dataCostEstimateManager->monetaryUnit(19).txt = "BZ$";
1678 80 : state.dataCostEstimateManager->monetaryUnit(20).txt = "$";
1679 80 : state.dataCostEstimateManager->monetaryUnit(21).txt = "CHF";
1680 80 : state.dataCostEstimateManager->monetaryUnit(22).txt = "$";
1681 80 : state.dataCostEstimateManager->monetaryUnit(23).txt = "CNY";
1682 80 : state.dataCostEstimateManager->monetaryUnit(24).txt = "$";
1683 80 : state.dataCostEstimateManager->monetaryUnit(25).txt = "CRC";
1684 80 : state.dataCostEstimateManager->monetaryUnit(26).txt = "CUP";
1685 80 : state.dataCostEstimateManager->monetaryUnit(27).txt = "CZK";
1686 80 : state.dataCostEstimateManager->monetaryUnit(28).txt = "kr";
1687 80 : state.dataCostEstimateManager->monetaryUnit(29).txt = "RD$";
1688 80 : state.dataCostEstimateManager->monetaryUnit(30).txt = "kr";
1689 80 : state.dataCostEstimateManager->monetaryUnit(31).txt = "£";
1690 80 : state.dataCostEstimateManager->monetaryUnit(32).txt = "EUR";
1691 80 : state.dataCostEstimateManager->monetaryUnit(33).txt = "$";
1692 80 : state.dataCostEstimateManager->monetaryUnit(34).txt = "£";
1693 80 : state.dataCostEstimateManager->monetaryUnit(35).txt = "¢";
1694 80 : state.dataCostEstimateManager->monetaryUnit(36).txt = "£";
1695 80 : state.dataCostEstimateManager->monetaryUnit(37).txt = "Q";
1696 80 : state.dataCostEstimateManager->monetaryUnit(38).txt = "$";
1697 80 : state.dataCostEstimateManager->monetaryUnit(39).txt = "HK$";
1698 80 : state.dataCostEstimateManager->monetaryUnit(40).txt = "L";
1699 80 : state.dataCostEstimateManager->monetaryUnit(41).txt = "kn";
1700 80 : state.dataCostEstimateManager->monetaryUnit(42).txt = "Ft";
1701 80 : state.dataCostEstimateManager->monetaryUnit(43).txt = "Rp";
1702 80 : state.dataCostEstimateManager->monetaryUnit(44).txt = "ILS";
1703 80 : state.dataCostEstimateManager->monetaryUnit(45).txt = "£";
1704 80 : state.dataCostEstimateManager->monetaryUnit(46).txt = "INR";
1705 80 : state.dataCostEstimateManager->monetaryUnit(47).txt = "IRR";
1706 80 : state.dataCostEstimateManager->monetaryUnit(48).txt = "kr";
1707 80 : state.dataCostEstimateManager->monetaryUnit(49).txt = "£";
1708 80 : state.dataCostEstimateManager->monetaryUnit(50).txt = "J$";
1709 80 : state.dataCostEstimateManager->monetaryUnit(51).txt = "Â¥";
1710 80 : state.dataCostEstimateManager->monetaryUnit(52).txt = "KGS";
1711 80 : state.dataCostEstimateManager->monetaryUnit(53).txt = "KHR";
1712 80 : state.dataCostEstimateManager->monetaryUnit(54).txt = "KPW";
1713 80 : state.dataCostEstimateManager->monetaryUnit(55).txt = "KRW";
1714 80 : state.dataCostEstimateManager->monetaryUnit(56).txt = "$";
1715 80 : state.dataCostEstimateManager->monetaryUnit(57).txt = "KZT";
1716 80 : state.dataCostEstimateManager->monetaryUnit(58).txt = "LAK";
1717 80 : state.dataCostEstimateManager->monetaryUnit(59).txt = "£";
1718 80 : state.dataCostEstimateManager->monetaryUnit(60).txt = "LKR";
1719 80 : state.dataCostEstimateManager->monetaryUnit(61).txt = "$";
1720 80 : state.dataCostEstimateManager->monetaryUnit(62).txt = "Lt";
1721 80 : state.dataCostEstimateManager->monetaryUnit(63).txt = "Ls";
1722 80 : state.dataCostEstimateManager->monetaryUnit(64).txt = "MKD";
1723 80 : state.dataCostEstimateManager->monetaryUnit(65).txt = "MNT";
1724 80 : state.dataCostEstimateManager->monetaryUnit(66).txt = "MUR";
1725 80 : state.dataCostEstimateManager->monetaryUnit(67).txt = "$";
1726 80 : state.dataCostEstimateManager->monetaryUnit(68).txt = "RM";
1727 80 : state.dataCostEstimateManager->monetaryUnit(69).txt = "MT";
1728 80 : state.dataCostEstimateManager->monetaryUnit(70).txt = "$";
1729 80 : state.dataCostEstimateManager->monetaryUnit(71).txt = "NGN";
1730 80 : state.dataCostEstimateManager->monetaryUnit(72).txt = "C$";
1731 80 : state.dataCostEstimateManager->monetaryUnit(73).txt = "kr";
1732 80 : state.dataCostEstimateManager->monetaryUnit(74).txt = "NPR";
1733 80 : state.dataCostEstimateManager->monetaryUnit(75).txt = "$";
1734 80 : state.dataCostEstimateManager->monetaryUnit(76).txt = "OMR";
1735 80 : state.dataCostEstimateManager->monetaryUnit(77).txt = "B/.";
1736 80 : state.dataCostEstimateManager->monetaryUnit(78).txt = "S/.";
1737 80 : state.dataCostEstimateManager->monetaryUnit(79).txt = "Php";
1738 80 : state.dataCostEstimateManager->monetaryUnit(80).txt = "PKR";
1739 80 : state.dataCostEstimateManager->monetaryUnit(81).txt = "PLN";
1740 80 : state.dataCostEstimateManager->monetaryUnit(82).txt = "Gs";
1741 80 : state.dataCostEstimateManager->monetaryUnit(83).txt = "QAR";
1742 80 : state.dataCostEstimateManager->monetaryUnit(84).txt = "lei";
1743 80 : state.dataCostEstimateManager->monetaryUnit(85).txt = "RSD";
1744 80 : state.dataCostEstimateManager->monetaryUnit(86).txt = "RUB";
1745 80 : state.dataCostEstimateManager->monetaryUnit(87).txt = "SAR";
1746 80 : state.dataCostEstimateManager->monetaryUnit(88).txt = "$";
1747 80 : state.dataCostEstimateManager->monetaryUnit(89).txt = "SCR";
1748 80 : state.dataCostEstimateManager->monetaryUnit(90).txt = "kr";
1749 80 : state.dataCostEstimateManager->monetaryUnit(91).txt = "$";
1750 80 : state.dataCostEstimateManager->monetaryUnit(92).txt = "£";
1751 80 : state.dataCostEstimateManager->monetaryUnit(93).txt = "S";
1752 80 : state.dataCostEstimateManager->monetaryUnit(94).txt = "$";
1753 80 : state.dataCostEstimateManager->monetaryUnit(95).txt = "$";
1754 80 : state.dataCostEstimateManager->monetaryUnit(96).txt = "£";
1755 80 : state.dataCostEstimateManager->monetaryUnit(97).txt = "THB";
1756 80 : state.dataCostEstimateManager->monetaryUnit(98).txt = "TRL";
1757 80 : state.dataCostEstimateManager->monetaryUnit(99).txt = "YTL";
1758 80 : state.dataCostEstimateManager->monetaryUnit(100).txt = "TT$";
1759 80 : state.dataCostEstimateManager->monetaryUnit(101).txt = "$";
1760 80 : state.dataCostEstimateManager->monetaryUnit(102).txt = "NT$";
1761 80 : state.dataCostEstimateManager->monetaryUnit(103).txt = "UAH";
1762 80 : state.dataCostEstimateManager->monetaryUnit(104).txt = "$U";
1763 80 : state.dataCostEstimateManager->monetaryUnit(105).txt = "UZS";
1764 80 : state.dataCostEstimateManager->monetaryUnit(106).txt = "Bs";
1765 80 : state.dataCostEstimateManager->monetaryUnit(107).txt = "VND";
1766 80 : state.dataCostEstimateManager->monetaryUnit(108).txt = "$";
1767 80 : state.dataCostEstimateManager->monetaryUnit(109).txt = "YER";
1768 80 : state.dataCostEstimateManager->monetaryUnit(110).txt = "R";
1769 80 : state.dataCostEstimateManager->monetaryUnit(111).txt = "Z$";
1770 :
1771 80 : state.dataCostEstimateManager->monetaryUnit(1).html = "$";
1772 80 : state.dataCostEstimateManager->monetaryUnit(2).html = "؋";
1773 80 : state.dataCostEstimateManager->monetaryUnit(3).html = "Lek";
1774 80 : state.dataCostEstimateManager->monetaryUnit(4).html = "ƒ";
1775 80 : state.dataCostEstimateManager->monetaryUnit(5).html = "$";
1776 80 : state.dataCostEstimateManager->monetaryUnit(6).html = "$";
1777 80 : state.dataCostEstimateManager->monetaryUnit(7).html = "ƒ";
1778 80 : state.dataCostEstimateManager->monetaryUnit(8).html = "ман";
1779 80 : state.dataCostEstimateManager->monetaryUnit(9).html = "KM";
1780 80 : state.dataCostEstimateManager->monetaryUnit(10).html = "$";
1781 80 : state.dataCostEstimateManager->monetaryUnit(11).html = "лв";
1782 80 : state.dataCostEstimateManager->monetaryUnit(12).html = "$";
1783 80 : state.dataCostEstimateManager->monetaryUnit(13).html = "$";
1784 80 : state.dataCostEstimateManager->monetaryUnit(14).html = "$b";
1785 80 : state.dataCostEstimateManager->monetaryUnit(15).html = "R$";
1786 80 : state.dataCostEstimateManager->monetaryUnit(16).html = "$";
1787 80 : state.dataCostEstimateManager->monetaryUnit(17).html = "P";
1788 80 : state.dataCostEstimateManager->monetaryUnit(18).html = "p.";
1789 80 : state.dataCostEstimateManager->monetaryUnit(19).html = "BZ$";
1790 80 : state.dataCostEstimateManager->monetaryUnit(20).html = "$";
1791 80 : state.dataCostEstimateManager->monetaryUnit(21).html = "CHF";
1792 80 : state.dataCostEstimateManager->monetaryUnit(22).html = "$";
1793 80 : state.dataCostEstimateManager->monetaryUnit(23).html = "元";
1794 80 : state.dataCostEstimateManager->monetaryUnit(24).html = "$";
1795 80 : state.dataCostEstimateManager->monetaryUnit(25).html = "₡";
1796 80 : state.dataCostEstimateManager->monetaryUnit(26).html = "₱";
1797 80 : state.dataCostEstimateManager->monetaryUnit(27).html = "Kč";
1798 80 : state.dataCostEstimateManager->monetaryUnit(28).html = "kr";
1799 80 : state.dataCostEstimateManager->monetaryUnit(29).html = "RD$";
1800 80 : state.dataCostEstimateManager->monetaryUnit(30).html = "kr";
1801 80 : state.dataCostEstimateManager->monetaryUnit(31).html = "£";
1802 80 : state.dataCostEstimateManager->monetaryUnit(32).html = "€";
1803 80 : state.dataCostEstimateManager->monetaryUnit(33).html = "$";
1804 80 : state.dataCostEstimateManager->monetaryUnit(34).html = "£";
1805 80 : state.dataCostEstimateManager->monetaryUnit(35).html = "¢";
1806 80 : state.dataCostEstimateManager->monetaryUnit(36).html = "£";
1807 80 : state.dataCostEstimateManager->monetaryUnit(37).html = "Q";
1808 80 : state.dataCostEstimateManager->monetaryUnit(38).html = "$";
1809 80 : state.dataCostEstimateManager->monetaryUnit(39).html = "HK$";
1810 80 : state.dataCostEstimateManager->monetaryUnit(40).html = "L";
1811 80 : state.dataCostEstimateManager->monetaryUnit(41).html = "kn";
1812 80 : state.dataCostEstimateManager->monetaryUnit(42).html = "Ft";
1813 80 : state.dataCostEstimateManager->monetaryUnit(43).html = "Rp";
1814 80 : state.dataCostEstimateManager->monetaryUnit(44).html = "₪";
1815 80 : state.dataCostEstimateManager->monetaryUnit(45).html = "£";
1816 80 : state.dataCostEstimateManager->monetaryUnit(46).html = "₨";
1817 80 : state.dataCostEstimateManager->monetaryUnit(47).html = "﷼";
1818 80 : state.dataCostEstimateManager->monetaryUnit(48).html = "kr";
1819 80 : state.dataCostEstimateManager->monetaryUnit(49).html = "£";
1820 80 : state.dataCostEstimateManager->monetaryUnit(50).html = "J$";
1821 80 : state.dataCostEstimateManager->monetaryUnit(51).html = "Â¥";
1822 80 : state.dataCostEstimateManager->monetaryUnit(52).html = "лв";
1823 80 : state.dataCostEstimateManager->monetaryUnit(53).html = "៛";
1824 80 : state.dataCostEstimateManager->monetaryUnit(54).html = "₩";
1825 80 : state.dataCostEstimateManager->monetaryUnit(55).html = "₩";
1826 80 : state.dataCostEstimateManager->monetaryUnit(56).html = "$";
1827 80 : state.dataCostEstimateManager->monetaryUnit(57).html = "лв";
1828 80 : state.dataCostEstimateManager->monetaryUnit(58).html = "₭";
1829 80 : state.dataCostEstimateManager->monetaryUnit(59).html = "£";
1830 80 : state.dataCostEstimateManager->monetaryUnit(60).html = "₨";
1831 80 : state.dataCostEstimateManager->monetaryUnit(61).html = "$";
1832 80 : state.dataCostEstimateManager->monetaryUnit(62).html = "Lt";
1833 80 : state.dataCostEstimateManager->monetaryUnit(63).html = "Ls";
1834 80 : state.dataCostEstimateManager->monetaryUnit(64).html = "ден";
1835 80 : state.dataCostEstimateManager->monetaryUnit(65).html = "₮";
1836 80 : state.dataCostEstimateManager->monetaryUnit(66).html = "₨";
1837 80 : state.dataCostEstimateManager->monetaryUnit(67).html = "$";
1838 80 : state.dataCostEstimateManager->monetaryUnit(68).html = "RM";
1839 80 : state.dataCostEstimateManager->monetaryUnit(69).html = "MT";
1840 80 : state.dataCostEstimateManager->monetaryUnit(70).html = "$";
1841 80 : state.dataCostEstimateManager->monetaryUnit(71).html = "₦";
1842 80 : state.dataCostEstimateManager->monetaryUnit(72).html = "C$";
1843 80 : state.dataCostEstimateManager->monetaryUnit(73).html = "kr";
1844 80 : state.dataCostEstimateManager->monetaryUnit(74).html = "₨";
1845 80 : state.dataCostEstimateManager->monetaryUnit(75).html = "$";
1846 80 : state.dataCostEstimateManager->monetaryUnit(76).html = "﷼";
1847 80 : state.dataCostEstimateManager->monetaryUnit(77).html = "B/.";
1848 80 : state.dataCostEstimateManager->monetaryUnit(78).html = "S/.";
1849 80 : state.dataCostEstimateManager->monetaryUnit(79).html = "Php";
1850 80 : state.dataCostEstimateManager->monetaryUnit(80).html = "₨";
1851 80 : state.dataCostEstimateManager->monetaryUnit(81).html = "zł";
1852 80 : state.dataCostEstimateManager->monetaryUnit(82).html = "Gs";
1853 80 : state.dataCostEstimateManager->monetaryUnit(83).html = "﷼";
1854 80 : state.dataCostEstimateManager->monetaryUnit(84).html = "lei";
1855 80 : state.dataCostEstimateManager->monetaryUnit(85).html = "Дин.";
1856 80 : state.dataCostEstimateManager->monetaryUnit(86).html = "руб";
1857 80 : state.dataCostEstimateManager->monetaryUnit(87).html = "﷼";
1858 80 : state.dataCostEstimateManager->monetaryUnit(88).html = "$";
1859 80 : state.dataCostEstimateManager->monetaryUnit(89).html = "₨";
1860 80 : state.dataCostEstimateManager->monetaryUnit(90).html = "kr";
1861 80 : state.dataCostEstimateManager->monetaryUnit(91).html = "$";
1862 80 : state.dataCostEstimateManager->monetaryUnit(92).html = "£";
1863 80 : state.dataCostEstimateManager->monetaryUnit(93).html = "S";
1864 80 : state.dataCostEstimateManager->monetaryUnit(94).html = "$";
1865 80 : state.dataCostEstimateManager->monetaryUnit(95).html = "$";
1866 80 : state.dataCostEstimateManager->monetaryUnit(96).html = "£";
1867 80 : state.dataCostEstimateManager->monetaryUnit(97).html = "฿";
1868 80 : state.dataCostEstimateManager->monetaryUnit(98).html = "₤";
1869 80 : state.dataCostEstimateManager->monetaryUnit(99).html = "YTL";
1870 80 : state.dataCostEstimateManager->monetaryUnit(100).html = "TT$";
1871 80 : state.dataCostEstimateManager->monetaryUnit(101).html = "$";
1872 80 : state.dataCostEstimateManager->monetaryUnit(102).html = "NT$";
1873 80 : state.dataCostEstimateManager->monetaryUnit(103).html = "₴";
1874 80 : state.dataCostEstimateManager->monetaryUnit(104).html = "$U";
1875 80 : state.dataCostEstimateManager->monetaryUnit(105).html = "лв";
1876 80 : state.dataCostEstimateManager->monetaryUnit(106).html = "Bs";
1877 80 : state.dataCostEstimateManager->monetaryUnit(107).html = "₫";
1878 80 : state.dataCostEstimateManager->monetaryUnit(108).html = "$";
1879 80 : state.dataCostEstimateManager->monetaryUnit(109).html = "﷼";
1880 80 : state.dataCostEstimateManager->monetaryUnit(110).html = "R";
1881 80 : state.dataCostEstimateManager->monetaryUnit(111).html = "Z$";
1882 80 : }
1883 :
1884 16 : 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 16 : auto &s_econ = state.dataEconTariff;
1894 :
1895 : int FindTariffIndex;
1896 16 : int found = 0;
1897 :
1898 16 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
1899 12 : if (Util::SameString(nameOfTariff, s_econ->tariff(iTariff).tariffName)) {
1900 12 : found = iTariff;
1901 12 : break;
1902 : }
1903 : }
1904 16 : if (found > 0) {
1905 12 : FindTariffIndex = found;
1906 : } else {
1907 4 : ShowSevereError(state, format("{}=\"{}\" invalid tariff referenced", nameOfCurObj, nameOfReferingObj));
1908 4 : ShowContinueError(state, format("not found UtilityCost:Tariff=\"{}\".", nameOfTariff));
1909 4 : ErrorsFound = true;
1910 4 : FindTariffIndex = 0;
1911 : }
1912 16 : return FindTariffIndex;
1913 : }
1914 :
1915 16 : 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 16 : auto &s_econ = state.dataEconTariff;
1924 :
1925 16 : bool throwError = false;
1926 16 : if (getEnumValue(nativeNamesUC, objName) != -1) {
1927 0 : throwError = true;
1928 16 : } else if (getEnumValue(catNamesUC, objName) != -1) {
1929 0 : throwError = true;
1930 : }
1931 :
1932 16 : 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 16 : }
1942 :
1943 416 : 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 416 : auto &s_econ = state.dataEconTariff;
1961 : int AssignVariablePt;
1962 :
1963 416 : if (flagIfNotNumeric && (len(stringIn) >= 1)) {
1964 385 : std::string inNoSpaces = RemoveSpaces(state, stringIn);
1965 385 : int found = 0;
1966 385 : if (allocated(s_econ->econVar)) {
1967 9071 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
1968 8736 : if (s_econ->econVar(iVar).tariffIndx == tariffPt) {
1969 8736 : if (Util::SameString(s_econ->econVar(iVar).name, inNoSpaces)) {
1970 39 : found = iVar;
1971 39 : break;
1972 : }
1973 : }
1974 : }
1975 : }
1976 385 : if (found > 0) {
1977 39 : AssignVariablePt = found;
1978 39 : if (s_econ->econVar(found).kindOfObj == ObjType::Invalid) {
1979 0 : s_econ->econVar(found).kindOfObj = econObjKind;
1980 0 : if (s_econ->econVar(found).index == 0) {
1981 0 : s_econ->econVar(found).index = objIndex;
1982 : }
1983 : }
1984 : } else {
1985 346 : incrementEconVar(state);
1986 346 : s_econ->econVar(s_econ->numEconVar).name = inNoSpaces;
1987 346 : s_econ->econVar(s_econ->numEconVar).kindOfObj = econObjKind;
1988 346 : s_econ->econVar(s_econ->numEconVar).index = objIndex;
1989 346 : AssignVariablePt = s_econ->numEconVar;
1990 : }
1991 : // now set the flag for the type of usage the variable has
1992 385 : if (useOfVar == varIsArgument) {
1993 289 : s_econ->econVar(AssignVariablePt).isArgument = true;
1994 96 : } else if (useOfVar == varIsAssigned) {
1995 96 : s_econ->econVar(AssignVariablePt).isAssigned = true;
1996 : }
1997 385 : 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 437 : if ((varSpecific != varNotYetDefined) ||
2004 52 : (s_econ->econVar(AssignVariablePt).kindOfObj != ObjType::Category && s_econ->econVar(AssignVariablePt).kindOfObj != ObjType::Native)) {
2005 352 : s_econ->econVar(AssignVariablePt).specific = varSpecific;
2006 : }
2007 385 : } else { // if the string was numeric return a zero
2008 31 : AssignVariablePt = 0;
2009 : }
2010 416 : return AssignVariablePt;
2011 : }
2012 :
2013 346 : 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 346 : int constexpr sizeIncrement(100);
2021 346 : auto &s_econ = state.dataEconTariff;
2022 :
2023 346 : if (!allocated(s_econ->econVar)) {
2024 11 : s_econ->econVar.allocate(sizeIncrement);
2025 11 : s_econ->sizeEconVar = sizeIncrement;
2026 11 : s_econ->numEconVar = 1;
2027 : } else {
2028 335 : ++s_econ->numEconVar;
2029 : // if larger than current size grow the array
2030 335 : if (s_econ->numEconVar > s_econ->sizeEconVar) {
2031 0 : s_econ->econVar.redimension(s_econ->sizeEconVar += sizeIncrement);
2032 : }
2033 : }
2034 346 : auto &econVar = s_econ->econVar(s_econ->numEconVar);
2035 :
2036 : // initialize new record) //Autodesk Most of these match default initialization so not needed
2037 346 : econVar.name = "";
2038 346 : econVar.tariffIndx = 0;
2039 346 : econVar.kindOfObj = ObjType::Invalid;
2040 346 : econVar.index = 0;
2041 346 : std::fill(econVar.values.begin(), econVar.values.end(), 0.0);
2042 346 : econVar.isArgument = false;
2043 346 : econVar.isAssigned = false;
2044 346 : econVar.specific = varNotYetDefined;
2045 : // econVar( numEconVar ).values = 0.0; //Autodesk Already initialized above
2046 : // Autodesk Don't initialize cntMeDependOn
2047 346 : econVar.Operator = Op::Invalid;
2048 346 : econVar.firstOperand = 1; // Autodesk Default initialization sets this to 0
2049 346 : econVar.lastOperand = 0;
2050 346 : econVar.activeNow = false;
2051 346 : econVar.isEvaluated = false;
2052 : // Autodesk Don't initialize isReported
2053 : // Autodesk Don't initialize varUnitType
2054 346 : }
2055 :
2056 168 : 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 168 : auto &s_econ = state.dataEconTariff;
2065 168 : int constexpr sizeIncrement(100);
2066 :
2067 168 : if (!allocated(s_econ->steps)) {
2068 7 : s_econ->steps.allocate(sizeIncrement);
2069 7 : s_econ->sizeSteps = sizeIncrement;
2070 7 : s_econ->numSteps = 1;
2071 : } else {
2072 161 : ++s_econ->numSteps;
2073 : // if larger than current size grow the array
2074 161 : if (s_econ->numSteps > s_econ->sizeSteps) {
2075 0 : s_econ->steps.redimension(s_econ->sizeSteps += sizeIncrement);
2076 : }
2077 : }
2078 : // initialize new record
2079 168 : s_econ->steps(s_econ->numSteps).type = StepType::EOL;
2080 168 : }
2081 :
2082 385 : 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 385 : std::string StringOut;
2090 385 : bool foundSpaces = false;
2091 5884 : for (std::string::size_type iString = 0; iString < len(StringIn); ++iString) {
2092 5499 : if (StringIn[iString] != ' ') {
2093 5499 : StringOut += StringIn[iString];
2094 : } else {
2095 0 : foundSpaces = true;
2096 : }
2097 : }
2098 385 : 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 385 : return StringOut;
2103 0 : }
2104 :
2105 7 : 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 7 : auto &s_econ = state.dataEconTariff;
2114 14 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2115 7 : auto &tariff = s_econ->tariff(iTariff);
2116 :
2117 : // category variables first
2118 77 : for (int iCat = 0; iCat < (int)Cat::Num; ++iCat) {
2119 70 : tariff.cats[iCat] = AssignVariablePt(state, catNames[iCat], true, varIsAssigned, iCat, ObjType::Category, 0, iTariff);
2120 : }
2121 :
2122 7 : tariff.firstCategory = tariff.cats[(int)Cat::EnergyCharges];
2123 7 : tariff.lastCategory = tariff.cats[(int)Cat::NotIncluded];
2124 :
2125 : // category variables first
2126 :
2127 266 : for (int iNative = 0; iNative < (int)Native::Num; ++iNative) {
2128 259 : tariff.natives[iNative] = AssignVariablePt(state, nativeNames[iNative], true, varIsArgument, iNative, ObjType::Native, 0, iTariff);
2129 : }
2130 7 : tariff.firstNative = tariff.natives[(int)Native::TotalEnergy];
2131 7 : tariff.lastNative = tariff.natives[(int)Native::BelowCustomerBaseEnergy];
2132 : }
2133 7 : }
2134 :
2135 : //======================================================================================================================
2136 : //======================================================================================================================
2137 :
2138 : // DEFAULT COMPUTATION RELATED ROUTINES
2139 :
2140 : //======================================================================================================================
2141 : //======================================================================================================================
2142 :
2143 7 : 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 7 : auto &s_econ = state.dataEconTariff;
2200 :
2201 : // for each tariff that does not have a UtilityCost:Computation object go through the variables
2202 14 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2203 7 : auto &tariff = s_econ->tariff(iTariff);
2204 7 : auto &computation = s_econ->computation(iTariff);
2205 7 : if (!computation.isUserDef) {
2206 : // clear all variables so that they are not active
2207 293 : for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
2208 287 : s_econ->econVar(jVar).activeNow = false;
2209 : }
2210 : // make all native variables active
2211 228 : for (int jVar = tariff.firstNative; jVar <= tariff.lastNative; ++jVar) {
2212 222 : s_econ->econVar(jVar).activeNow = true;
2213 : }
2214 : //"clear" the dependOn array
2215 6 : s_econ->numOperand = 0;
2216 : // Define the preset equations (category summation)
2217 6 : int curTotal = tariff.cats[(int)Cat::Total];
2218 6 : int curSubtotal = tariff.cats[(int)Cat::Subtotal];
2219 6 : int curBasis = tariff.cats[(int)Cat::Basis];
2220 : // total SUM subtotal taxes
2221 6 : s_econ->econVar(curTotal).Operator = Op::SUM;
2222 6 : s_econ->econVar(curTotal).activeNow = true;
2223 6 : addOperand(state, curTotal, curSubtotal);
2224 6 : addOperand(state, curTotal, tariff.cats[(int)Cat::Taxes]);
2225 : // subtotal SUM basis adjustments surcharges
2226 6 : s_econ->econVar(curSubtotal).Operator = Op::SUM;
2227 6 : s_econ->econVar(curSubtotal).activeNow = true;
2228 6 : addOperand(state, curSubtotal, curBasis);
2229 6 : addOperand(state, curSubtotal, tariff.cats[(int)Cat::Adjustment]);
2230 6 : addOperand(state, curSubtotal, tariff.cats[(int)Cat::Surcharge]);
2231 : // basis SUM EnergyCharges DemandCharges ServiceCharges
2232 6 : s_econ->econVar(curBasis).Operator = Op::SUM;
2233 6 : s_econ->econVar(curBasis).activeNow = true;
2234 6 : addOperand(state, curBasis, tariff.cats[(int)Cat::EnergyCharges]);
2235 6 : addOperand(state, curBasis, tariff.cats[(int)Cat::DemandCharges]);
2236 6 : addOperand(state, curBasis, tariff.cats[(int)Cat::ServiceCharges]);
2237 : // set up the equations for other objects
2238 6 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::EnergyCharges]);
2239 6 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::DemandCharges]);
2240 6 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::ServiceCharges]);
2241 6 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Adjustment]);
2242 6 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Surcharge]);
2243 6 : addChargesToOperand(state, iTariff, tariff.cats[(int)Cat::Taxes]);
2244 : // add the real time pricing to the energy charges
2245 6 : if (tariff.chargeSched != nullptr) {
2246 0 : 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 6 : for (int kObj = 1; kObj <= s_econ->numQualify; ++kObj) {
2252 0 : auto const &qualify = s_econ->qualify(kObj);
2253 0 : if (qualify.tariffIndx == iTariff) {
2254 0 : int curObject = qualify.namePt;
2255 0 : s_econ->econVar(curObject).Operator = Op::NOOP;
2256 0 : s_econ->econVar(curObject).activeNow = true;
2257 0 : addOperand(state, curObject, qualify.sourcePt);
2258 0 : addOperand(state, curObject, qualify.thresholdPt);
2259 : }
2260 : }
2261 : // Ratchet
2262 6 : for (int kObj = 1; kObj <= s_econ->numRatchet; ++kObj) {
2263 0 : auto const &ratchet = s_econ->ratchet(kObj);
2264 0 : if (ratchet.tariffIndx == iTariff) {
2265 0 : int curObject = ratchet.namePt;
2266 0 : s_econ->econVar(curObject).Operator = Op::NOOP;
2267 0 : s_econ->econVar(curObject).activeNow = true;
2268 0 : addOperand(state, curObject, ratchet.baselinePt);
2269 0 : addOperand(state, curObject, ratchet.adjustmentPt);
2270 0 : addOperand(state, curObject, ratchet.multiplierPt);
2271 0 : addOperand(state, curObject, ratchet.offsetPt);
2272 : }
2273 : }
2274 : // ChargeSimple
2275 11 : for (int kObj = 1; kObj <= s_econ->numChargeSimple; ++kObj) {
2276 5 : auto const &chargeSimple = s_econ->chargeSimple(kObj);
2277 5 : if (chargeSimple.tariffIndx == iTariff) {
2278 5 : int curObject = chargeSimple.namePt;
2279 5 : s_econ->econVar(curObject).Operator = Op::NOOP;
2280 5 : s_econ->econVar(curObject).activeNow = true;
2281 5 : addOperand(state, curObject, chargeSimple.sourcePt);
2282 5 : addOperand(state, curObject, chargeSimple.costPerPt);
2283 : }
2284 : }
2285 : // ChargeBlock
2286 6 : for (int kObj = 1; kObj <= s_econ->numChargeBlock; ++kObj) {
2287 0 : auto const &chargeBlock = s_econ->chargeBlock(kObj);
2288 0 : if (chargeBlock.tariffIndx == iTariff) {
2289 0 : int curObject = chargeBlock.namePt;
2290 0 : s_econ->econVar(curObject).Operator = Op::NOOP;
2291 0 : s_econ->econVar(curObject).activeNow = true;
2292 0 : addOperand(state, curObject, chargeBlock.sourcePt);
2293 0 : addOperand(state, curObject, chargeBlock.blkSzMultPt);
2294 0 : for (int mBlock = 1; mBlock <= chargeBlock.numBlk; ++mBlock) {
2295 0 : addOperand(state, curObject, chargeBlock.blkSzPt(mBlock));
2296 0 : addOperand(state, curObject, chargeBlock.blkCostPt(mBlock));
2297 : }
2298 : // now add a new "equation" for dependency of remainingPt on namePt
2299 0 : int remainPt = chargeBlock.remainingPt;
2300 0 : if (remainPt > 0) {
2301 0 : s_econ->econVar(remainPt).Operator = Op::NOOP;
2302 0 : s_econ->econVar(remainPt).activeNow = true;
2303 0 : addOperand(state, remainPt, curObject);
2304 : }
2305 : }
2306 : }
2307 : // Economic:Variable
2308 : // make all of the user defined variables as active
2309 293 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2310 287 : if (s_econ->econVar(iVar).tariffIndx == iTariff) {
2311 287 : if (s_econ->econVar(iVar).kindOfObj == ObjType::Variable) {
2312 0 : s_econ->econVar(iVar).activeNow = true;
2313 : }
2314 : }
2315 : }
2316 : // make sure no computation is already user defined
2317 6 : if (computation.firstStep != 0) {
2318 0 : ShowWarningError(state, format("In UtilityCost:Tariff: Overwriting user defined tariff {}", tariff.tariffName));
2319 : }
2320 : // initialize the computation
2321 6 : computation.computeName = "Autogenerated - " + tariff.tariffName;
2322 6 : computation.firstStep = s_econ->numSteps + 1;
2323 6 : computation.lastStep = -1; // this will be incremented by addStep
2324 6 : 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 293 : for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
2330 287 : s_econ->econVar(jVar).cntMeDependOn = 0;
2331 : }
2332 : // Second, add up the number of dependencies on each variable
2333 293 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2334 287 : if (s_econ->econVar(iVar).activeNow) {
2335 281 : if (s_econ->econVar(iVar).lastOperand >= s_econ->econVar(iVar).firstOperand) {
2336 26 : 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 6 : int numNoDepend = -1;
2343 6 : int loopCount = 0;
2344 21 : while ((numNoDepend != 0) || (loopCount > 100000)) {
2345 15 : numNoDepend = 0;
2346 735 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2347 720 : if (s_econ->econVar(iVar).activeNow) {
2348 : // find a variable that has no more dangling dependencies
2349 293 : 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 281 : if ((s_econ->econVar(iVar).kindOfObj != ObjType::Native) && (s_econ->econVar(iVar).kindOfObj != ObjType::Variable)) {
2353 59 : 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 84 : for (int kOperand = s_econ->econVar(iVar).lastOperand; kOperand >= s_econ->econVar(iVar).firstOperand;
2357 : --kOperand) {
2358 58 : incrementSteps(state);
2359 58 : s_econ->steps(s_econ->numSteps) = s_econ->operands(kOperand);
2360 : }
2361 : // append the operator (either SUM or NOOP)
2362 26 : incrementSteps(state);
2363 26 : s_econ->steps(s_econ->numSteps).type = StepType::Op;
2364 26 : s_econ->steps(s_econ->numSteps).op = s_econ->econVar(iVar).Operator;
2365 : // append the variable itself
2366 26 : incrementSteps(state);
2367 26 : s_econ->steps(s_econ->numSteps).type = StepType::Var;
2368 26 : s_econ->steps(s_econ->numSteps).varNum = iVar;
2369 : // at the end of the line show a zero to clear the stack
2370 26 : incrementSteps(state);
2371 26 : 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 13727 : for (int jVar = 1; jVar <= s_econ->numEconVar; ++jVar) {
2377 13446 : if (s_econ->econVar(jVar).activeNow) {
2378 8434 : for (int kOperand = s_econ->econVar(jVar).firstOperand; kOperand <= s_econ->econVar(jVar).lastOperand;
2379 : ++kOperand) {
2380 1711 : int referVar = s_econ->operands(kOperand).varNum;
2381 1711 : if (iVar == referVar) {
2382 58 : --s_econ->econVar(jVar).cntMeDependOn;
2383 : // for each variable that has been decremented to zero increment the counter
2384 58 : if (s_econ->econVar(jVar).cntMeDependOn <= 0) {
2385 26 : ++numNoDepend;
2386 : }
2387 : }
2388 : }
2389 : }
2390 : }
2391 : // make the variable inactive
2392 281 : s_econ->econVar(iVar).activeNow = false;
2393 : }
2394 : }
2395 : }
2396 15 : ++loopCount;
2397 : }
2398 6 : 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 6 : bool remainingVarFlag = false;
2404 293 : for (int iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
2405 287 : if (s_econ->econVar(iVar).activeNow) {
2406 0 : remainingVarFlag = true;
2407 : }
2408 : }
2409 6 : 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 6 : computation.lastStep = s_econ->numSteps;
2427 6 : 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 7 : }
2438 :
2439 63 : 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 63 : int constexpr sizeIncrement(100);
2448 63 : auto &s_econ = state.dataEconTariff;
2449 :
2450 63 : if (varOperand != 0) {
2451 : // increment the numOperand and allocate/reallocate the array
2452 : // if necessary
2453 58 : if (!allocated(s_econ->operands)) {
2454 6 : s_econ->operands.allocate(sizeIncrement);
2455 6 : s_econ->sizeOperand = sizeIncrement;
2456 6 : s_econ->numOperand = 1;
2457 : } else {
2458 52 : ++s_econ->numOperand;
2459 : // if larger than current size grow the array
2460 52 : if (s_econ->numOperand > s_econ->sizeOperand) {
2461 0 : s_econ->operands.redimension(s_econ->sizeOperand += sizeIncrement);
2462 : }
2463 : }
2464 58 : auto &econVar = s_econ->econVar(varMe);
2465 :
2466 : // now add the dependency relationship
2467 58 : s_econ->operands(s_econ->numOperand).type = StepType::Var;
2468 58 : s_econ->operands(s_econ->numOperand).varNum = varOperand;
2469 58 : 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 58 : if (varMe != s_econ->addOperand_prevVarMe) {
2473 26 : econVar.firstOperand = s_econ->numOperand;
2474 26 : s_econ->addOperand_prevVarMe = varMe;
2475 : }
2476 : }
2477 63 : }
2478 :
2479 36 : 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 36 : auto const &s_econ = state.dataEconTariff;
2489 36 : auto const &chargeSimple = s_econ->chargeSimple;
2490 36 : auto const &chargeBlock = s_econ->chargeBlock;
2491 :
2492 36 : s_econ->econVar(curPointer).Operator = Op::SUM;
2493 36 : s_econ->econVar(curPointer).activeNow = true;
2494 66 : for (int kObj = 1; kObj <= s_econ->numChargeSimple; ++kObj) {
2495 30 : if (chargeSimple(kObj).tariffIndx == curTariff) {
2496 30 : if (chargeSimple(kObj).categoryPt == curPointer) {
2497 5 : addOperand(state, curPointer, chargeSimple(kObj).namePt);
2498 : }
2499 : }
2500 : }
2501 36 : for (int kObj = 1; kObj <= s_econ->numChargeBlock; ++kObj) {
2502 0 : if (chargeBlock(kObj).tariffIndx == curTariff) {
2503 0 : if (chargeBlock(kObj).categoryPt == curPointer) {
2504 0 : addOperand(state, curPointer, chargeBlock(kObj).namePt);
2505 : }
2506 : }
2507 : }
2508 36 : }
2509 :
2510 : //======================================================================================================================
2511 : //======================================================================================================================
2512 :
2513 : // GATHER TIMESTEP VALUES ROUTINE
2514 :
2515 : //======================================================================================================================
2516 : //======================================================================================================================
2517 :
2518 4 : 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 4 : auto &s_econ = state.dataEconTariff;
2536 :
2537 4 : if (s_econ->numTariff >= 1) {
2538 8 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2539 4 : auto &tariff = s_econ->tariff(iTariff);
2540 : // if the meter is defined get the value
2541 4 : if (tariff.reportMeterIndx != -1) {
2542 1 : curInstantValue = GetCurrentMeterValue(state, tariff.reportMeterIndx);
2543 : } else {
2544 3 : 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 4 : tariff.collectEnergy += curInstantValue;
2549 4 : tariff.collectTime += state.dataGlobal->TimeStepZoneSec;
2550 : // added *SecInHour when adding RTP support August 2008
2551 4 : if (tariff.collectTime >= tariff.demWinTime * Constant::rSecsInHour) {
2552 : // get current value that has been converted into desired units
2553 4 : curDemand = tariff.demandConv * tariff.collectEnergy / tariff.collectTime;
2554 4 : 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 4 : Season curSeason = (tariff.seasonSched != nullptr) ? static_cast<Season>(tariff.seasonSched->getCurrentVal()) : Season::Winter;
2559 4 : 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 7 : (((state.dataGlobal->HourOfDay + state.dataEnvrn->DSTIndicator) <= Constant::iHoursInDay) ? state.dataEnvrn->Month
2566 11 : : state.dataEnvrn->MonthTomorrow);
2567 :
2568 4 : bool isGood = false;
2569 4 : if (curSeason == Season::Winter || curSeason == Season::Spring || curSeason == Season::Summer || curSeason == Season::Fall ||
2570 : curSeason == Season::Annual) {
2571 4 : if (isWithinRange(state, curPeriod, 1, 4)) {
2572 4 : if (isWithinRange(state, curMonth, 1, 12)) {
2573 4 : isGood = true;
2574 : }
2575 : }
2576 : }
2577 4 : if (isGood) {
2578 4 : tariff.seasonForMonth(curMonth) = curSeason;
2579 4 : tariff.gatherEnergy(curMonth)[(int)curPeriod] += curEnergy;
2580 4 : if (tariff.gatherDemand(curMonth)[(int)curPeriod] < curDemand) {
2581 0 : 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 4 : 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 4 : tariff.collectEnergy = 0.0;
2614 4 : tariff.collectTime = 0.0;
2615 : }
2616 : }
2617 : }
2618 4 : }
2619 :
2620 9 : 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 9 : if (maxThreshold < minThreshold) {
2631 0 : ShowWarningError(state, "UtilityCost: Invalid thresholds in IsWithinRange routine.");
2632 : }
2633 9 : if ((testVal <= maxThreshold) && (testVal >= minThreshold)) {
2634 9 : isWithinRange = true;
2635 : } else {
2636 0 : isWithinRange = false;
2637 : }
2638 9 : return isWithinRange;
2639 : }
2640 :
2641 : //======================================================================================================================
2642 : //======================================================================================================================
2643 :
2644 : // COMPUTE THE UTILITY BILLS AND CREATE REPORTS
2645 :
2646 : //======================================================================================================================
2647 : //======================================================================================================================
2648 :
2649 73 : 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 73 : auto &s_econ = state.dataEconTariff;
2660 :
2661 : // values used in specific operations
2662 73 : Array1D<Real64> a(NumMonths);
2663 73 : Array1D<Real64> b(NumMonths);
2664 73 : Array1D<Real64> c(NumMonths);
2665 73 : Array1D<Real64> d(NumMonths);
2666 :
2667 73 : int constexpr noVar(0);
2668 :
2669 : Real64 annualAggregate;
2670 :
2671 73 : if (!state.files.outputControl.writeTabular(state)) {
2672 0 : state.dataOutRptTab->WriteTabularFiles = false;
2673 0 : return;
2674 : }
2675 :
2676 73 : Real64 hugeValue = HUGE_(Real64());
2677 : // Clear the isEvaluated flags for all economics variables.
2678 73 : for (int nVar = 1; nVar <= s_econ->numEconVar; ++nVar) {
2679 0 : s_econ->econVar(nVar).isEvaluated = false;
2680 : }
2681 :
2682 73 : if (s_econ->numTariff == 0) {
2683 73 : return;
2684 : }
2685 :
2686 0 : state.dataOutRptTab->WriteTabularFiles = true;
2687 0 : setNativeVariables(state);
2688 : int aPt;
2689 : int bPt;
2690 : int cPt;
2691 0 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
2692 0 : for (int jStep = s_econ->computation(iTariff).firstStep; jStep <= s_econ->computation(iTariff).lastStep; ++jStep) {
2693 0 : auto const &step = s_econ->steps(jStep);
2694 0 : 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 0 : if (step.type == StepType::EOL) {
2701 0 : if (s_econ->topOfStack >= 2) {
2702 0 : popStack(state, b, bPt); // pop the variable pointer
2703 0 : popStack(state, a, aPt); // pop the values
2704 0 : if (isWithinRange(state, bPt, 1, s_econ->numEconVar)) {
2705 0 : s_econ->econVar(bPt).values = a;
2706 : }
2707 : }
2708 0 : s_econ->topOfStack = 0;
2709 :
2710 : // Variable
2711 0 : } else if (step.type == StepType::Var) {
2712 0 : pushStack(state, s_econ->econVar(step.varNum).values, step.varNum);
2713 :
2714 : // Operator
2715 0 : } else if (step.type == StepType::Op) {
2716 0 : switch (step.op) {
2717 :
2718 0 : case Op::SUM: {
2719 0 : a = 0.0;
2720 0 : for (int kStack = 1, kStack_end = s_econ->topOfStack; kStack <= kStack_end; ++kStack) { // popStack modifies topOfStack
2721 0 : popStack(state, b, bPt);
2722 0 : a += b;
2723 : }
2724 0 : pushStack(state, a, noVar);
2725 0 : } 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 0 : case Op::NOOP: {
3026 : // do nothing but clear the stack
3027 0 : s_econ->topOfStack = 0;
3028 : // No longer pushing a zero to fix bug
3029 : // and push zero
3030 : // a = 0
3031 0 : } break;
3032 :
3033 0 : default: {
3034 0 : } break;
3035 : }
3036 : }
3037 : }
3038 0 : checkMinimumMonthlyCharge(state, iTariff);
3039 : }
3040 0 : selectTariff(state);
3041 0 : LEEDtariffReporting(state);
3042 292 : }
3043 :
3044 3 : 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 3 : monthlyArray.dim(NumMonths);
3057 :
3058 3 : Array1D<Real64> curMonthlyArray(NumMonths);
3059 3 : int constexpr sizeIncrement(50);
3060 :
3061 3 : auto &s_econ = state.dataEconTariff;
3062 3 : auto &stack = s_econ->stack;
3063 3 : auto const &econVar = s_econ->econVar;
3064 3 : auto const &tariff = s_econ->tariff;
3065 :
3066 3 : curMonthlyArray = monthlyArray;
3067 3 : if (!allocated(stack)) {
3068 1 : stack.allocate(sizeIncrement);
3069 1 : s_econ->sizeStack = sizeIncrement;
3070 1 : s_econ->topOfStack = 1;
3071 : } else {
3072 2 : ++s_econ->topOfStack;
3073 : // if larger than current size grow the array
3074 2 : 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 3 : 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 3 : if (variablePointer != 0) {
3083 1 : if (!econVar(variablePointer).isEvaluated) {
3084 :
3085 1 : switch (econVar(variablePointer).kindOfObj) {
3086 0 : case ObjType::ChargeSimple:
3087 0 : evaluateChargeSimple(state, variablePointer);
3088 0 : break;
3089 0 : case ObjType::ChargeBlock:
3090 0 : evaluateChargeBlock(state, variablePointer);
3091 0 : break;
3092 0 : case ObjType::Ratchet:
3093 0 : evaluateRatchet(state, variablePointer);
3094 0 : break;
3095 0 : case ObjType::Qualify:
3096 0 : evaluateQualify(state, variablePointer);
3097 0 : 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 1 : 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 1 : 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 1 : if (econVar(variablePointer).kindOfObj == ObjType::Category && econVar(variablePointer).specific == (int)Cat::ServiceCharges) {
3120 0 : addMonthlyCharge(state, variablePointer);
3121 : }
3122 : // get the results of performing the evaluation - should have been
3123 : // put into the econVar values
3124 1 : curMonthlyArray = econVar(variablePointer).values;
3125 : }
3126 : }
3127 : // now assign
3128 3 : stack(s_econ->topOfStack).values = curMonthlyArray;
3129 3 : }
3130 :
3131 3 : 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 3 : monthlyArray.dim(NumMonths);
3145 :
3146 3 : auto &s_econ = state.dataEconTariff;
3147 3 : auto const &stack = s_econ->stack;
3148 :
3149 3 : if (s_econ->topOfStack >= 1) {
3150 3 : variablePointer = stack(s_econ->topOfStack).varPt;
3151 3 : 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 3 : --s_econ->topOfStack;
3161 3 : }
3162 :
3163 3 : void evaluateChargeSimple(EnergyPlusData &state, int const usingVariable)
3164 : {
3165 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3166 : // DATE WRITTEN July 2004
3167 :
3168 3 : Array1D<Real64> sourceVals(NumMonths);
3169 3 : Array1D<Real64> costPer(NumMonths);
3170 3 : Array1D<Real64> resultChg(NumMonths);
3171 3 : Array1D<Real64> seasonMask(NumMonths);
3172 :
3173 3 : auto &s_econ = state.dataEconTariff;
3174 3 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3175 3 : auto const &tariff = s_econ->tariff(curTariff);
3176 3 : int indexInChg = s_econ->econVar(usingVariable).index;
3177 3 : auto const &chargeSimple = s_econ->chargeSimple(indexInChg);
3178 :
3179 : // check the tariff - make sure they match
3180 3 : 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 3 : 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 3 : sourceVals = s_econ->econVar(chargeSimple.sourcePt).values;
3192 : // determine if costPer should be based on variable or value
3193 3 : if (chargeSimple.costPerPt != 0) {
3194 1 : costPer = s_econ->econVar(chargeSimple.costPerPt).values;
3195 : } else {
3196 2 : costPer = chargeSimple.costPerVal;
3197 : }
3198 : // find proper season mask
3199 3 : if (chargeSimple.season == Season::Summer) {
3200 1 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3201 2 : } else if (chargeSimple.season == Season::Winter) {
3202 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3203 2 : } else if (chargeSimple.season == Season::Spring) {
3204 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3205 2 : } else if (chargeSimple.season == Season::Fall) {
3206 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3207 2 : } else if (chargeSimple.season == Season::Annual) {
3208 2 : seasonMask = 1.0; // all months are 1
3209 : }
3210 :
3211 : // finally perform calculations
3212 3 : resultChg = sourceVals * costPer * seasonMask;
3213 : // store the cost in the name of the variable
3214 3 : s_econ->econVar(usingVariable).values = resultChg;
3215 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3216 3 : s_econ->econVar(usingVariable).isEvaluated = true;
3217 3 : }
3218 :
3219 1 : void evaluateChargeBlock(EnergyPlusData &state, int const usingVariable)
3220 : {
3221 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3222 : // DATE WRITTEN July 2004
3223 :
3224 1 : Array1D<Real64> sourceVals(NumMonths);
3225 1 : Array1D<Real64> blkSzMult(NumMonths);
3226 1 : Array1D<Real64> remainVals(NumMonths);
3227 1 : Array1D<Real64> resultChg(NumMonths);
3228 1 : Array1D<Real64> amountForBlk(NumMonths);
3229 1 : Array1D<Real64> curBlkSz(NumMonths);
3230 1 : Array1D<Real64> curBlkCost(NumMonths);
3231 1 : Array1D<Real64> seasonMask(NumMonths);
3232 :
3233 1 : auto &s_econ = state.dataEconTariff;
3234 1 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3235 1 : auto const &tariff = s_econ->tariff(curTariff);
3236 1 : int indexInChg = s_econ->econVar(usingVariable).index;
3237 1 : auto const &chargeBlock = s_econ->chargeBlock(indexInChg);
3238 :
3239 : // check the tariff - make sure they match
3240 1 : 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 1 : 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 1 : sourceVals = s_econ->econVar(chargeBlock.sourcePt).values;
3252 : // find proper season mask
3253 :
3254 1 : if (chargeBlock.season == Season::Summer) {
3255 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3256 1 : } else if (chargeBlock.season == Season::Winter) {
3257 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3258 1 : } else if (chargeBlock.season == Season::Spring) {
3259 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3260 1 : } else if (chargeBlock.season == Season::Fall) {
3261 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3262 1 : } else if (chargeBlock.season == Season::Annual) {
3263 1 : seasonMask = 1.0; // all months are 1
3264 : }
3265 : // get block size multiplier
3266 1 : if (chargeBlock.blkSzMultPt != 0) {
3267 0 : blkSzMult = s_econ->econVar(chargeBlock.blkSzMultPt).values;
3268 : } else {
3269 1 : blkSzMult = chargeBlock.blkSzMultVal;
3270 : }
3271 : // initially set the remaining energy or demand to the source
3272 1 : remainVals = sourceVals;
3273 : // initially set the result (cost) to zero
3274 1 : resultChg = 0.0;
3275 : // loop through the blocks performing calculations
3276 4 : for (int iBlk = 1; iBlk <= chargeBlock.numBlk; ++iBlk) {
3277 3 : if (chargeBlock.blkSzPt(iBlk) != 0) {
3278 0 : curBlkSz = s_econ->econVar(chargeBlock.blkSzPt(iBlk)).values;
3279 : } else {
3280 3 : curBlkSz = chargeBlock.blkSzVal(iBlk);
3281 : }
3282 3 : if (chargeBlock.blkCostPt(iBlk) != 0) {
3283 0 : curBlkCost = s_econ->econVar(chargeBlock.blkCostPt(iBlk)).values;
3284 : } else {
3285 3 : curBlkCost = chargeBlock.blkCostVal(iBlk);
3286 : }
3287 : // loop through the months
3288 39 : for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
3289 36 : if (seasonMask(jMonth) == 1) {
3290 : // IF ((curBlkSz(jMonth) * blkSzMult(jMonth)) .GT. remainVals(jMonth)) THEN - CR 6547
3291 36 : if (blkSzMult(jMonth) != 0) {
3292 36 : if (curBlkSz(jMonth) > (remainVals(jMonth) / blkSzMult(jMonth))) {
3293 21 : amountForBlk(jMonth) = remainVals(jMonth);
3294 : } else {
3295 15 : amountForBlk(jMonth) = curBlkSz(jMonth) * blkSzMult(jMonth);
3296 : }
3297 : } else {
3298 0 : amountForBlk(jMonth) = 0.0;
3299 : }
3300 36 : resultChg(jMonth) += amountForBlk(jMonth) * curBlkCost(jMonth);
3301 36 : remainVals(jMonth) -= amountForBlk(jMonth);
3302 : }
3303 : }
3304 : }
3305 : // store the amount remaining if a variable is specified
3306 1 : if (chargeBlock.remainingPt != 0) {
3307 0 : s_econ->econVar(chargeBlock.remainingPt).values = remainVals;
3308 : } else {
3309 1 : bool flagAllZero = true;
3310 13 : for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
3311 12 : if (seasonMask(jMonth) == 1) {
3312 12 : if (remainVals(jMonth) != 0) {
3313 0 : flagAllZero = false;
3314 : }
3315 : }
3316 : }
3317 1 : 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 1 : s_econ->econVar(usingVariable).values = resultChg;
3325 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3326 1 : s_econ->econVar(usingVariable).isEvaluated = true;
3327 1 : }
3328 :
3329 0 : void evaluateRatchet(EnergyPlusData &state, int const usingVariable)
3330 : {
3331 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3332 : // DATE WRITTEN July 2004
3333 :
3334 0 : Array1D<Real64> baselineVals(NumMonths);
3335 0 : Array1D<Real64> adjustmentVals(NumMonths);
3336 0 : Array1D<Real64> multiplierVals(NumMonths);
3337 0 : Array1D<Real64> offsetVals(NumMonths);
3338 0 : Array1D<Real64> seasonFromMask(NumMonths);
3339 0 : Array1D<Real64> seasonToMask(NumMonths);
3340 0 : Array1D<Real64> adjSeasonal(NumMonths);
3341 0 : Array1D<Real64> adjPeak(NumMonths);
3342 0 : Array1D<Real64> maxAdjBase(NumMonths);
3343 0 : Array1D<Real64> finalResult(NumMonths);
3344 :
3345 0 : auto &s_econ = state.dataEconTariff;
3346 0 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3347 0 : auto const &tariff = s_econ->tariff(curTariff);
3348 0 : int indexInChg = s_econ->econVar(usingVariable).index;
3349 0 : auto const &ratchet = s_econ->ratchet(indexInChg);
3350 0 : bool isMonthly = false;
3351 :
3352 : // check the tariff - make sure they match
3353 0 : 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 0 : 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 0 : baselineVals = s_econ->econVar(ratchet.baselinePt).values;
3365 0 : adjustmentVals = s_econ->econVar(ratchet.adjustmentPt).values;
3366 : // determine if multiplier should be based on variable or value
3367 0 : if (ratchet.multiplierPt != 0) {
3368 0 : multiplierVals = s_econ->econVar(ratchet.multiplierPt).values;
3369 : } else {
3370 0 : multiplierVals = ratchet.multiplierVal;
3371 : }
3372 : // determine if offset should be based on variable or value
3373 0 : if (ratchet.offsetPt != 0) {
3374 0 : offsetVals = s_econ->econVar(ratchet.offsetPt).values;
3375 : } else {
3376 0 : offsetVals = ratchet.offsetVal;
3377 : }
3378 : // find proper season from mask
3379 0 : if (ratchet.seasonFrom == Season::Summer) {
3380 0 : seasonFromMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3381 0 : 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 0 : if (ratchet.seasonTo == Season::Summer) {
3403 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3404 0 : } else if (ratchet.seasonTo == Season::Winter) {
3405 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3406 0 : } else if (ratchet.seasonTo == Season::Spring) {
3407 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3408 0 : } else if (ratchet.seasonTo == Season::Fall) {
3409 0 : seasonToMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3410 0 : } else if (ratchet.seasonTo == Season::Annual) {
3411 0 : seasonToMask = 1.0; // all months are 1
3412 : }
3413 : // finally perform calculations
3414 0 : if (isMonthly) {
3415 0 : adjSeasonal = adjustmentVals;
3416 : } else {
3417 0 : Real64 maximumVal = -HUGE_(Real64());
3418 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3419 0 : if (seasonFromMask(iMonth) == 1) {
3420 0 : if (adjustmentVals(iMonth) > maximumVal) {
3421 0 : maximumVal = adjustmentVals(iMonth);
3422 : }
3423 : }
3424 : }
3425 0 : adjSeasonal = maximumVal;
3426 : }
3427 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3428 : // calculate adjusted peak value after offset and multiplier
3429 0 : adjPeak(iMonth) = (adjSeasonal(iMonth) + offsetVals(iMonth)) * multiplierVals(iMonth);
3430 : // the maximum of the adjustment and the baseline
3431 0 : if (adjPeak(iMonth) > baselineVals(iMonth)) {
3432 0 : maxAdjBase(iMonth) = adjPeak(iMonth);
3433 : } else {
3434 0 : maxAdjBase(iMonth) = baselineVals(iMonth);
3435 : }
3436 : }
3437 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3438 0 : if (seasonToMask(iMonth) == 1) {
3439 0 : 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 0 : s_econ->econVar(usingVariable).values = finalResult;
3446 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3447 0 : s_econ->econVar(usingVariable).isEvaluated = true;
3448 0 : }
3449 :
3450 0 : void evaluateQualify(EnergyPlusData &state, int const usingVariable)
3451 : {
3452 : // AUTHOR Jason Glazer of GARD Analytics, Inc.
3453 : // DATE WRITTEN July 2004
3454 :
3455 0 : Array1D<Real64> sourceVals(NumMonths);
3456 0 : Array1D<Real64> thresholdVals(NumMonths);
3457 0 : Array1D_int monthsQualify(NumMonths);
3458 0 : Array1D<Real64> seasonMask(NumMonths);
3459 : int adjNumberOfMonths;
3460 : bool isQualified;
3461 :
3462 0 : auto &s_econ = state.dataEconTariff;
3463 0 : auto &econVar = s_econ->econVar(usingVariable);
3464 :
3465 0 : int curTariff = econVar.tariffIndx;
3466 0 : auto &tariff = s_econ->tariff(curTariff);
3467 0 : int indexInQual = econVar.index;
3468 0 : auto const &qualify = s_econ->qualify(indexInQual);
3469 : // check the tariff - make sure they match
3470 0 : 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 0 : 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 0 : sourceVals = s_econ->econVar(qualify.sourcePt).values;
3482 0 : bool curIsMaximum = qualify.isMaximum;
3483 0 : bool curIsConsecutive = qualify.isConsecutive;
3484 0 : int curNumberOfMonths = qualify.numberOfMonths;
3485 : // determine if threshold should be based on variable or value
3486 0 : if (qualify.thresholdPt != 0) {
3487 0 : thresholdVals = s_econ->econVar(qualify.thresholdPt).values;
3488 : } else {
3489 0 : thresholdVals = qualify.thresholdVal;
3490 : }
3491 : // find proper season mask
3492 :
3493 0 : if (qualify.season == Season::Summer) {
3494 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values;
3495 0 : } else if (qualify.season == Season::Winter) {
3496 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values;
3497 0 : } else if (qualify.season == Season::Spring) {
3498 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values;
3499 0 : } else if (qualify.season == Season::Fall) {
3500 0 : seasonMask = s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values;
3501 0 : } else if (qualify.season == Season::Annual) {
3502 0 : seasonMask = 1.0; // all months are 1
3503 : }
3504 :
3505 : // any months with no energy use are excluded from the qualification process
3506 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3507 0 : if (s_econ->econVar(tariff.natives[(int)Native::TotalEnergy]).values(iMonth) == 0) {
3508 0 : seasonMask(iMonth) = 0.0;
3509 : }
3510 : }
3511 : // finally perform calculations
3512 : // loop through the months
3513 0 : int monthsInSeason = 0;
3514 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3515 0 : 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 0 : 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 0 : if (curNumberOfMonths > monthsInSeason) {
3537 0 : 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 0 : int cntAllQualMonths = 0;
3543 0 : int cntConsecQualMonths = 0;
3544 0 : int maxConsecQualMonths = 0;
3545 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3546 : {
3547 0 : int const SELECT_CASE_var(monthsQualify(iMonth));
3548 0 : 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 0 : } 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 0 : if (curIsConsecutive) {
3563 0 : if (maxConsecQualMonths >= adjNumberOfMonths) {
3564 0 : isQualified = true;
3565 : } else {
3566 0 : isQualified = false;
3567 : }
3568 : } else { // count not consecutive
3569 0 : if (cntAllQualMonths >= adjNumberOfMonths) {
3570 0 : 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 0 : if (tariff.isQualified) {
3578 0 : 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 0 : econVar.values = monthsQualify;
3585 : // set the flag that it has been evaluated so it won't be evaluated multiple times
3586 0 : econVar.isEvaluated = true;
3587 0 : }
3588 :
3589 0 : 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 0 : auto &s_econ = state.dataEconTariff;
3597 0 : int curTariff = s_econ->econVar(usingVariable).tariffIndx;
3598 0 : auto const &tariff = s_econ->tariff(curTariff);
3599 : // check the tariff - make sure they match
3600 0 : 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 0 : if (tariff.monthChgPt != 0) {
3606 0 : s_econ->econVar(usingVariable).values += s_econ->econVar(tariff.monthChgPt).values;
3607 : } else {
3608 0 : 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 0 : }
3618 :
3619 0 : 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 0 : auto &s_econ = state.dataEconTariff;
3627 0 : auto const &tariff = s_econ->tariff(curTariff);
3628 :
3629 0 : int totalVar = tariff.cats[(int)Cat::Total];
3630 0 : int minMonVar = tariff.minMonthChgPt;
3631 : // if a variable is defined use that
3632 0 : 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 0 : for (int iMonth = 1; iMonth <= NumMonths; ++iMonth) {
3640 0 : if (s_econ->econVar(totalVar).values(iMonth) < tariff.minMonthChgVal) {
3641 0 : s_econ->econVar(totalVar).values(iMonth) = tariff.minMonthChgVal;
3642 : }
3643 : }
3644 : }
3645 0 : }
3646 :
3647 0 : 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 0 : auto &s_econ = state.dataEconTariff;
3656 :
3657 0 : Array1D<Real64> monthVal(NumMonths);
3658 0 : Real64 bigNumber(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
3659 :
3660 0 : bigNumber = HUGE_(bigNumber);
3661 0 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
3662 0 : auto &tariff = s_econ->tariff(iTariff);
3663 : // nativeTotalEnergy
3664 0 : monthVal = 0.0;
3665 0 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3666 0 : for (int jPeriod = 0; jPeriod < (int)Period::Num; ++jPeriod) {
3667 0 : monthVal(kMonth) += tariff.gatherEnergy(kMonth)[jPeriod];
3668 : }
3669 : }
3670 0 : s_econ->econVar(tariff.natives[(int)Native::TotalEnergy]).values = monthVal;
3671 : // nativeTotalDemand
3672 0 : monthVal = -bigNumber;
3673 0 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3674 0 : for (int jPeriod = 0; jPeriod < (int)Period::Num; ++jPeriod) {
3675 0 : if (tariff.gatherDemand(kMonth)[jPeriod] > monthVal(kMonth)) {
3676 0 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[jPeriod];
3677 : }
3678 : }
3679 : }
3680 : // if no maximum was set just set to zero
3681 0 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3682 0 : if (monthVal(kMonth) == -bigNumber) {
3683 0 : monthVal(kMonth) = 0.0;
3684 : }
3685 : }
3686 0 : s_econ->econVar(tariff.natives[(int)Native::TotalDemand]).values = monthVal;
3687 0 : for (int kMonth = 1; kMonth <= NumMonths; ++kMonth) {
3688 : // nativePeakEnergy
3689 0 : s_econ->econVar(tariff.natives[(int)Native::PeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::Peak];
3690 : // nativePeakDemand
3691 0 : s_econ->econVar(tariff.natives[(int)Native::PeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3692 : // nativeShoulderEnergy
3693 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::Shoulder];
3694 : // nativeShoulderDemand
3695 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
3696 : // nativeOffPeakEnergy
3697 0 : s_econ->econVar(tariff.natives[(int)Native::OffPeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
3698 : // nativeOffPeakDemand
3699 0 : s_econ->econVar(tariff.natives[(int)Native::OffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3700 : // nativeMidPeakEnergy
3701 0 : s_econ->econVar(tariff.natives[(int)Native::MidPeakEnergy]).values(kMonth) = tariff.gatherEnergy(kMonth)[(int)Period::MidPeak];
3702 : // nativeMidPeakDemand
3703 0 : s_econ->econVar(tariff.natives[(int)Native::MidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
3704 : // nativePeakExceedsOffPeak
3705 0 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3706 0 : if (monthVal(kMonth) > 0) {
3707 0 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = monthVal(kMonth);
3708 : } else {
3709 0 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = 0.0;
3710 : }
3711 : // nativeOffPeakExceedsPeak
3712 0 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
3713 0 : if (monthVal(kMonth) > 0) {
3714 0 : s_econ->econVar(tariff.natives[(int)Native::OffPeakExceedsPeak]).values(kMonth) = monthVal(kMonth);
3715 : } else {
3716 0 : s_econ->econVar(tariff.natives[(int)Native::OffPeakExceedsPeak]).values(kMonth) = 0.0;
3717 : }
3718 : // nativePeakExceedsMidPeak
3719 0 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
3720 0 : if (monthVal(kMonth) > 0) {
3721 0 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsMidPeak]).values(kMonth) = monthVal(kMonth);
3722 : } else {
3723 0 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsOffPeak]).values(kMonth) = 0.0;
3724 : }
3725 : // nativeMidPeakExceedsPeak
3726 0 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
3727 0 : if (monthVal(kMonth) > 0) {
3728 0 : s_econ->econVar(tariff.natives[(int)Native::MidPeakExceedsPeak]).values(kMonth) = monthVal(kMonth);
3729 : } else {
3730 0 : s_econ->econVar(tariff.natives[(int)Native::MidPeakExceedsPeak]).values(kMonth) = 0.0;
3731 : }
3732 : // nativePeakExceedsShoulder
3733 0 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak] - tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
3734 0 : if (monthVal(kMonth) > 0) {
3735 0 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsShoulder]).values(kMonth) = monthVal(kMonth);
3736 : } else {
3737 0 : s_econ->econVar(tariff.natives[(int)Native::PeakExceedsShoulder]).values(kMonth) = 0.0;
3738 : }
3739 : // nativeShoulderExceedsPeak
3740 0 : monthVal(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Shoulder] - tariff.gatherDemand(kMonth)[(int)Period::Peak];
3741 0 : if (monthVal(kMonth) > 0) {
3742 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderExceedsPeak]).values(kMonth) = monthVal(kMonth);
3743 : } else {
3744 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderExceedsPeak]).values(kMonth) = 0.0;
3745 : }
3746 : // nativeIsWinter
3747 : // nativeIsNotWinter
3748 0 : if (tariff.seasonForMonth(kMonth) == Season::Winter) {
3749 0 : s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values(kMonth) = 1.0;
3750 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotWinter]).values(kMonth) = 0.0;
3751 : } else {
3752 0 : s_econ->econVar(tariff.natives[(int)Native::IsWinter]).values(kMonth) = 0.0;
3753 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotWinter]).values(kMonth) = 1.0;
3754 : }
3755 : // nativeIsSpring
3756 : // nativeIsNotSpring
3757 0 : 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 0 : s_econ->econVar(tariff.natives[(int)Native::IsSpring]).values(kMonth) = 0.0;
3762 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotSpring]).values(kMonth) = 1.0;
3763 : }
3764 : // nativeIsSummer
3765 : // nativeIsNotSummer
3766 0 : 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 0 : s_econ->econVar(tariff.natives[(int)Native::IsSummer]).values(kMonth) = 0.0;
3771 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotSummer]).values(kMonth) = 1.0;
3772 : }
3773 : // nativeIsAutumn
3774 : // nativeIsNotAutumn
3775 0 : 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 0 : s_econ->econVar(tariff.natives[(int)Native::IsAutumn]).values(kMonth) = 0.0;
3780 0 : s_econ->econVar(tariff.natives[(int)Native::IsNotAutumn]).values(kMonth) = 1.0;
3781 : }
3782 : // nativePeakAndShoulderEnergy
3783 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderEnergy]).values(kMonth) =
3784 0 : tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::Shoulder];
3785 : // nativePeakAndShoulderDemand
3786 0 : if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::Shoulder]) {
3787 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3788 : } else {
3789 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndShoulderDemand]).values(kMonth) =
3790 0 : tariff.gatherDemand(kMonth)[(int)Period::Shoulder];
3791 : }
3792 : // nativePeakAndMidPeakEnergy
3793 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakEnergy]).values(kMonth) =
3794 0 : tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::MidPeak];
3795 : // nativePeakAndMidPeakDemand
3796 0 : if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::MidPeak]) {
3797 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3798 : } else {
3799 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndMidPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::MidPeak];
3800 : }
3801 : // nativeShoulderAndOffPeakEnergy
3802 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakEnergy]).values(kMonth) =
3803 0 : tariff.gatherEnergy(kMonth)[(int)Period::Shoulder] + tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
3804 : // nativeShoulderAndOffPeakDemand
3805 0 : 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 0 : s_econ->econVar(tariff.natives[(int)Native::ShoulderAndOffPeakDemand]).values(kMonth) =
3810 0 : tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3811 : }
3812 : // nativePeakAndOffPeakEnergy
3813 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakEnergy]).values(kMonth) =
3814 0 : tariff.gatherEnergy(kMonth)[(int)Period::Peak] + tariff.gatherEnergy(kMonth)[(int)Period::OffPeak];
3815 : // nativePeakAndOffPeakDemand
3816 0 : if (tariff.gatherDemand(kMonth)[(int)Period::Peak] > tariff.gatherDemand(kMonth)[(int)Period::OffPeak]) {
3817 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::Peak];
3818 : } else {
3819 0 : s_econ->econVar(tariff.natives[(int)Native::PeakAndOffPeakDemand]).values(kMonth) = tariff.gatherDemand(kMonth)[(int)Period::OffPeak];
3820 : }
3821 : // nativeRealTimePriceCosts
3822 0 : s_econ->econVar(tariff.natives[(int)Native::RealTimePriceCosts]).values(kMonth) = tariff.RTPcost(kMonth);
3823 : // nativeAboveCustomerBaseCosts
3824 0 : s_econ->econVar(tariff.natives[(int)Native::AboveCustomerBaseCosts]).values(kMonth) = tariff.RTPaboveBaseCost(kMonth);
3825 : // nativeBelowCustomerBaseCosts
3826 0 : s_econ->econVar(tariff.natives[(int)Native::BelowCustomerBaseCosts]).values(kMonth) = tariff.RTPbelowBaseCost(kMonth);
3827 : // nativeAboveCustomerBaseEnergy
3828 0 : s_econ->econVar(tariff.natives[(int)Native::AboveCustomerBaseEnergy]).values(kMonth) = tariff.RTPaboveBaseEnergy(kMonth);
3829 : // nativeBelowCustomerBaseEnergy
3830 0 : s_econ->econVar(tariff.natives[(int)Native::BelowCustomerBaseEnergy]).values(kMonth) = tariff.RTPbelowBaseEnergy(kMonth);
3831 : }
3832 : }
3833 0 : }
3834 :
3835 2 : 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 2 : auto &s_orp = state.dataOutRptPredefined;
3868 :
3869 2 : auto &s_econ = state.dataEconTariff;
3870 :
3871 2 : if (s_econ->numTariff > 0) {
3872 4 : int distCoolFacilMeter = GetMeterIndex(state, "DISTRICTCOOLING:FACILITY");
3873 4 : int distHeatWaterFacilMeter = GetMeterIndex(state, "DISTRICTHEATINGWATER:FACILITY");
3874 2 : int distHeatSteamFacilMeter = GetMeterIndex(state, "DISTRICTHEATINGSTEAM:FACILITY");
3875 2 : elecTotalEne = 0.0;
3876 2 : gasTotalEne = 0.0;
3877 2 : distCoolTotalEne = 0.0;
3878 2 : distHeatWaterTotalEne = 0.0;
3879 2 : distHeatSteamTotalEne = 0.0;
3880 2 : otherTotalEne = 0.0;
3881 2 : elecTotalCost = 0.0;
3882 2 : gasTotalCost = 0.0;
3883 2 : distCoolTotalCost = 0.0;
3884 2 : distHeatWaterTotalCost = 0.0;
3885 2 : distHeatSteamTotalCost = 0.0;
3886 2 : otherTotalCost = 0.0;
3887 2 : allTotalCost = 0.0;
3888 2 : elecUnits = EconConv::USERDEF;
3889 2 : gasUnits = EconConv::USERDEF;
3890 2 : distCoolUnits = EconConv::USERDEF;
3891 2 : distHeatWaterUnits = EconConv::USERDEF;
3892 2 : distHeatSteamUnits = EconConv::USERDEF;
3893 2 : othrUnits = EconConv::USERDEF;
3894 2 : gasDemWindowUnits = DemandWindow::Invalid;
3895 2 : othrDemWindowUnits = DemandWindow::Invalid;
3896 4 : std::string elecTariffNames = "";
3897 4 : std::string gasTariffNames = "";
3898 4 : std::string distCoolTariffNames = "";
3899 4 : std::string distHeatWaterTariffNames = "";
3900 4 : std::string distHeatSteamTariffNames = "";
3901 2 : std::string othrTariffNames = "";
3902 13 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
3903 11 : auto &tariff = s_econ->tariff(iTariff);
3904 11 : if (tariff.isSelected) {
3905 11 : allTotalCost += tariff.totalAnnualCost;
3906 11 : if (tariff.kindMtr == MeterType::ElecSimple || tariff.kindMtr == MeterType::ElecProduced ||
3907 11 : tariff.kindMtr == MeterType::ElecPurchased || tariff.kindMtr == MeterType::ElecSurplusSold ||
3908 8 : tariff.kindMtr == MeterType::ElecNet) {
3909 3 : if (tariff.totalAnnualEnergy > elecTotalEne) {
3910 2 : elecTotalEne = tariff.totalAnnualEnergy;
3911 : }
3912 3 : elecTotalCost += tariff.totalAnnualCost;
3913 3 : elecTariffNames += ' ' + tariff.tariffName;
3914 3 : elecUnits = tariff.convChoice;
3915 8 : } else if (tariff.kindMtr == MeterType::Gas) {
3916 3 : if (tariff.totalAnnualEnergy > gasTotalEne) {
3917 1 : gasTotalEne = tariff.totalAnnualEnergy;
3918 : }
3919 3 : gasTotalCost += tariff.totalAnnualCost;
3920 3 : gasTariffNames += ' ' + tariff.tariffName;
3921 3 : gasUnits = tariff.convChoice;
3922 3 : gasDemWindowUnits = tariff.demandWindow;
3923 5 : } else if (tariff.reportMeterIndx == distCoolFacilMeter) {
3924 2 : if (tariff.totalAnnualEnergy > distCoolTotalEne) {
3925 2 : distCoolTotalEne = tariff.totalAnnualEnergy;
3926 : }
3927 2 : distCoolTotalCost += tariff.totalAnnualCost;
3928 2 : distCoolTariffNames += ' ' + tariff.tariffName;
3929 2 : distCoolUnits = tariff.convChoice;
3930 2 : distCoolDemWindowUnits = tariff.demandWindow;
3931 3 : } else if (tariff.reportMeterIndx == distHeatWaterFacilMeter) {
3932 2 : if (tariff.totalAnnualEnergy > distHeatWaterTotalEne) {
3933 2 : distHeatWaterTotalEne = tariff.totalAnnualEnergy;
3934 : }
3935 2 : distHeatWaterTotalCost += tariff.totalAnnualCost;
3936 2 : distHeatWaterTariffNames += ' ' + tariff.tariffName;
3937 2 : distHeatWaterUnits = tariff.convChoice;
3938 2 : 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 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Electricity", elecTariffNames);
3961 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Natural Gas", gasTariffNames);
3962 2 : if (distCoolTotalEne != 0) {
3963 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Cooling", distCoolTariffNames);
3964 : }
3965 2 : if (distHeatWaterTotalEne != 0) {
3966 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Heating Water", distHeatWaterTariffNames);
3967 : }
3968 2 : if (distHeatSteamTotalEne != 0) {
3969 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "District Heating Steam", distHeatSteamTariffNames);
3970 : }
3971 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsRtNm, "Other", othrTariffNames);
3972 : // virtual rate
3973 2 : if (elecTotalEne != 0) {
3974 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Electricity", elecTotalCost / elecTotalEne, 3);
3975 : }
3976 2 : if (gasTotalEne != 0) {
3977 1 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Natural Gas", gasTotalCost / gasTotalEne, 3);
3978 : }
3979 2 : if (otherTotalEne != 0) {
3980 0 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "Other", otherTotalCost / otherTotalEne, 3);
3981 : }
3982 : // units
3983 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Electricity", format("{}", convEnergyStrings[(int)elecUnits]));
3984 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Natural Gas", format("{}", convEnergyStrings[(int)gasUnits]));
3985 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsEneUnt, "Other", format("{}", convEnergyStrings[(int)othrUnits]));
3986 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsDemUnt, "Electricity", format("{}", convDemandStrings[(int)elecUnits]));
3987 4 : OutputReportPredefined::PreDefTableEntry(
3988 : state,
3989 2 : s_orp->pdchLeedEtsDemUnt,
3990 : "Natural Gas",
3991 4 : format("{}{}",
3992 2 : convDemandStrings[(int)gasUnits],
3993 2 : (gasDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)gasDemWindowUnits]));
3994 4 : OutputReportPredefined::PreDefTableEntry(
3995 : state,
3996 2 : s_orp->pdchLeedEtsDemUnt,
3997 : "Other",
3998 4 : format("{}{}",
3999 2 : convDemandStrings[(int)othrUnits],
4000 2 : (othrDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)othrDemWindowUnits]));
4001 :
4002 : // total cost
4003 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Electricity", elecTotalCost, 2);
4004 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Natural Gas", gasTotalCost, 2);
4005 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "Other", otherTotalCost, 2);
4006 : // show district energy if used
4007 2 : if (distCoolTotalEne != 0) {
4008 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEtsVirt, "District Cooling", distCoolTotalCost / distCoolTotalEne, 3);
4009 4 : OutputReportPredefined::PreDefTableEntry(
4010 6 : state, s_orp->pdchLeedEtsEneUnt, "District Cooling", format("{}", convEnergyStrings[(int)distCoolUnits]));
4011 4 : OutputReportPredefined::PreDefTableEntry(
4012 : state,
4013 2 : s_orp->pdchLeedEtsDemUnt,
4014 : "District Cooling",
4015 4 : format("{}{}",
4016 2 : convDemandStrings[(int)distCoolUnits],
4017 2 : (distCoolDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distCoolDemWindowUnits]));
4018 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Cooling", distCoolTotalCost, 2);
4019 : }
4020 2 : if (distHeatWaterTotalEne != 0) {
4021 4 : OutputReportPredefined::PreDefTableEntry(
4022 4 : state, s_orp->pdchLeedEtsVirt, "District Heating Water", distHeatWaterTotalCost / distHeatWaterTotalEne, 3);
4023 4 : OutputReportPredefined::PreDefTableEntry(
4024 6 : state, s_orp->pdchLeedEtsEneUnt, "District Heating Water", format("{}", convEnergyStrings[(int)distHeatWaterUnits]));
4025 4 : OutputReportPredefined::PreDefTableEntry(
4026 : state,
4027 2 : s_orp->pdchLeedEtsDemUnt,
4028 : "District Heating Water",
4029 4 : format("{}{}",
4030 2 : convDemandStrings[(int)distHeatWaterUnits],
4031 2 : (distHeatWaterDemWindowUnits == DemandWindow::Invalid) ? "" : demandWindowStrings[(int)distHeatWaterDemWindowUnits]));
4032 2 : OutputReportPredefined::PreDefTableEntry(state, s_orp->pdchLeedEcsTotal, "District Heating Water", distHeatWaterTotalCost, 2);
4033 : }
4034 2 : 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 2 : s_orp->LEEDelecCostTotal = elecTotalCost;
4050 2 : s_orp->LEEDgasCostTotal = gasTotalCost;
4051 2 : s_orp->LEEDothrCostTotal = distCoolTotalCost + distHeatWaterTotalCost + distHeatSteamTotalCost + otherTotalCost;
4052 2 : OutputReportPredefined::PreDefTableEntry(state,
4053 2 : s_orp->pdchLeedEcsTotal,
4054 : "Total",
4055 2 : elecTotalCost + gasTotalCost + distCoolTotalCost + distHeatWaterTotalCost + distHeatSteamTotalCost +
4056 : otherTotalCost,
4057 2 : 2);
4058 2 : }
4059 2 : }
4060 :
4061 75 : 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 75 : Array1D_string columnHead;
4070 75 : Array1D_int columnWidth;
4071 75 : Array1D_string rowHead;
4072 75 : Array2D_string tableBody;
4073 : // other local variables
4074 : Real64 elecTotalCost;
4075 : Real64 gasTotalCost;
4076 : Real64 otherTotalCost;
4077 : Real64 allTotalCost;
4078 75 : Real64 perAreaUnitConv(0.0);
4079 :
4080 75 : 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 75 : 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 75 : if (state.dataOutRptTab->buildingConditionedFloorArea == 0.0) {
4091 59 : OutputReportTabular::DetermineBuildingFloorArea(state);
4092 : }
4093 :
4094 75 : if (s_econ->numTariff > 0) {
4095 2 : auto &econVar = s_econ->econVar;
4096 :
4097 2 : if (state.dataOutRptTab->displayEconomicResultSummary) {
4098 2 : DisplayString(state, "Writing Tariff Reports");
4099 202 : for (auto &e : econVar) {
4100 200 : e.isReported = false;
4101 : }
4102 2 : showWarningsBasedOnTotal(state);
4103 : //---------------------------------
4104 : // Economics Results Summary Report
4105 : //---------------------------------
4106 6 : OutputReportTabular::WriteReportHeaders(
4107 : state, "Economics Results Summary Report", "Entire Facility", OutputProcessor::StoreType::Average);
4108 :
4109 5 : for (int iUnitSystem = 0; iUnitSystem <= 1; iUnitSystem++) {
4110 4 : OutputReportTabular::UnitsStyle unitsStyle_cur = state.dataOutRptTab->unitsStyle;
4111 4 : bool produceTabular = true;
4112 4 : bool produceSQLite = false;
4113 4 : if (produceDualUnitsFlags(iUnitSystem,
4114 4 : state.dataOutRptTab->unitsStyle,
4115 4 : state.dataOutRptTab->unitsStyle_SQLite,
4116 : unitsStyle_cur,
4117 : produceTabular,
4118 : produceSQLite)) {
4119 1 : break;
4120 : }
4121 :
4122 : // do unit conversions if necessary
4123 3 : std::string perAreaUnitName;
4124 3 : if ((unitsStyle_cur == OutputReportTabular::UnitsStyle::InchPound) ||
4125 2 : (unitsStyle_cur == OutputReportTabular::UnitsStyle::InchPoundExceptElectricity)) {
4126 1 : int unitConvIndex = 0;
4127 1 : std::string SIunit = "[~~$~~/m2]";
4128 1 : OutputReportTabular::LookupSItoIP(state, SIunit, unitConvIndex, perAreaUnitName);
4129 1 : perAreaUnitConv = OutputReportTabular::ConvertIP(state, unitConvIndex, 1.0);
4130 1 : } else {
4131 2 : perAreaUnitName = "[~~$~~/m2]";
4132 2 : perAreaUnitConv = 1.0;
4133 : }
4134 :
4135 : //---- Annual Summary
4136 3 : rowHead.allocate(3);
4137 3 : columnHead.allocate(4);
4138 3 : columnWidth.allocate(4);
4139 3 : tableBody.allocate(4, 3);
4140 3 : tableBody = "";
4141 3 : columnHead(1) = "Electricity";
4142 3 : columnHead(2) = "Natural Gas";
4143 3 : columnHead(3) = "Other";
4144 3 : columnHead(4) = "Total";
4145 3 : rowHead(1) = "Cost [~~$~~]";
4146 3 : rowHead(2) = "Cost per Total Building Area " + perAreaUnitName;
4147 3 : rowHead(3) = "Cost per Net Conditioned Building Area " + perAreaUnitName;
4148 3 : elecTotalCost = 0.0;
4149 3 : gasTotalCost = 0.0;
4150 3 : otherTotalCost = 0.0;
4151 3 : allTotalCost = 0.0;
4152 6 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4153 3 : auto const &tariff = s_econ->tariff(iTariff);
4154 3 : if (tariff.isSelected) {
4155 3 : allTotalCost += tariff.totalAnnualCost;
4156 3 : if (tariff.kindMtr == MeterType::ElecSimple || tariff.kindMtr == MeterType::ElecProduced ||
4157 3 : tariff.kindMtr == MeterType::ElecPurchased || tariff.kindMtr == MeterType::ElecSurplusSold ||
4158 3 : tariff.kindMtr == MeterType::ElecNet) {
4159 0 : elecTotalCost += tariff.totalAnnualCost;
4160 3 : } else if (tariff.kindMtr == MeterType::Gas) {
4161 0 : gasTotalCost += tariff.totalAnnualCost;
4162 3 : } else if (tariff.kindMtr != MeterType::Water) {
4163 3 : otherTotalCost += tariff.totalAnnualCost;
4164 : // removed because this was confusing columnHead(3) = tariff.reportMeter
4165 : }
4166 : }
4167 : }
4168 3 : tableBody(1, 1) = OutputReportTabular::RealToStr(elecTotalCost, 2);
4169 3 : tableBody(2, 1) = OutputReportTabular::RealToStr(gasTotalCost, 2);
4170 3 : tableBody(3, 1) = OutputReportTabular::RealToStr(otherTotalCost, 2);
4171 3 : tableBody(4, 1) = OutputReportTabular::RealToStr(allTotalCost, 2);
4172 3 : if (state.dataOutRptTab->buildingGrossFloorArea > 0.0) {
4173 3 : tableBody(1, 2) =
4174 6 : OutputReportTabular::RealToStr((elecTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4175 3 : tableBody(2, 2) =
4176 6 : OutputReportTabular::RealToStr((gasTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4177 3 : tableBody(3, 2) =
4178 6 : OutputReportTabular::RealToStr((otherTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4179 3 : tableBody(4, 2) =
4180 6 : OutputReportTabular::RealToStr((allTotalCost / state.dataOutRptTab->buildingGrossFloorArea) * perAreaUnitConv, 2);
4181 : }
4182 3 : if (state.dataOutRptTab->buildingConditionedFloorArea > 0.0) {
4183 3 : tableBody(1, 3) =
4184 6 : OutputReportTabular::RealToStr((elecTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4185 3 : tableBody(2, 3) =
4186 6 : OutputReportTabular::RealToStr((gasTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4187 3 : tableBody(3, 3) =
4188 6 : OutputReportTabular::RealToStr((otherTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4189 3 : tableBody(4, 3) =
4190 6 : OutputReportTabular::RealToStr((allTotalCost / state.dataOutRptTab->buildingConditionedFloorArea) * perAreaUnitConv, 2);
4191 : }
4192 3 : columnWidth = 14; // array assignment - same for all columns
4193 3 : if (produceTabular) {
4194 2 : OutputReportTabular::WriteSubtitle(state, "Annual Cost");
4195 2 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4196 : }
4197 3 : if (produceSQLite) {
4198 2 : if (state.dataSQLiteProcedures->sqlite) {
4199 2 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
4200 : tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Annual Cost");
4201 : }
4202 : }
4203 3 : if (produceTabular) {
4204 2 : 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 3 : columnHead.deallocate();
4210 3 : rowHead.deallocate();
4211 3 : columnWidth.deallocate();
4212 3 : tableBody.deallocate();
4213 3 : }
4214 : //---- Tariff Summary
4215 2 : rowHead.allocate(s_econ->numTariff);
4216 2 : columnHead.allocate(6);
4217 2 : columnWidth.allocate(6);
4218 2 : tableBody.allocate(6, s_econ->numTariff);
4219 2 : tableBody = "";
4220 2 : columnHead(1) = "Selected";
4221 2 : columnHead(2) = "Qualified";
4222 2 : columnHead(3) = "Meter";
4223 2 : columnHead(4) = "Buy or Sell";
4224 2 : columnHead(5) = "Group";
4225 2 : columnHead(6) = "Annual Cost (~~$~~)";
4226 4 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4227 2 : auto const &tariff = s_econ->tariff(iTariff);
4228 2 : rowHead(iTariff) = tariff.tariffName;
4229 2 : tableBody(1, iTariff) = yesNoNames[(int)tariff.isSelected];
4230 2 : tableBody(2, iTariff) = yesNoNames[(int)tariff.isQualified];
4231 :
4232 2 : tableBody(3, iTariff) = tariff.reportMeter;
4233 :
4234 2 : if (tariff.buyOrSell == BuySell::BuyFromUtility) {
4235 0 : tableBody(4, iTariff) = "Buy";
4236 2 : } else if (tariff.buyOrSell == BuySell::SellToUtility) {
4237 0 : tableBody(4, iTariff) = "Sell";
4238 2 : } else if (tariff.buyOrSell == BuySell::NetMetering) {
4239 2 : tableBody(4, iTariff) = "Net";
4240 : }
4241 :
4242 2 : if (tariff.groupName == "") {
4243 2 : tableBody(5, iTariff) = "(none)";
4244 : } else {
4245 0 : tableBody(5, iTariff) = tariff.groupName;
4246 : }
4247 2 : tableBody(6, iTariff) = OutputReportTabular::RealToStr(tariff.totalAnnualCost, 2);
4248 : }
4249 2 : columnWidth = 14; // array assignment - same for all columns
4250 2 : OutputReportTabular::WriteSubtitle(state, "Tariff Summary");
4251 2 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4252 2 : if (state.dataSQLiteProcedures->sqlite) {
4253 2 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
4254 : tableBody, rowHead, columnHead, "Economics Results Summary Report", "Entire Facility", "Tariff Summary");
4255 : }
4256 2 : 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 2 : columnHead.deallocate();
4261 2 : rowHead.deallocate();
4262 2 : columnWidth.deallocate();
4263 2 : tableBody.deallocate();
4264 : }
4265 : //---------------------------------
4266 : // Tariff Report
4267 : //---------------------------------
4268 2 : if (state.dataOutRptTab->displayTariffReport) {
4269 0 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4270 0 : auto const &tariff = s_econ->tariff(iTariff);
4271 0 : auto const &computation = s_econ->computation(iTariff);
4272 0 : OutputReportTabular::WriteReportHeaders(state, "Tariff Report", tariff.tariffName, OutputProcessor::StoreType::Average);
4273 0 : rowHead.allocate(7);
4274 0 : columnHead.allocate(1);
4275 0 : columnWidth.allocate(1);
4276 0 : tableBody.allocate(1, 7);
4277 0 : tableBody = "";
4278 0 : columnHead(1) = "Parameter";
4279 0 : rowHead(1) = "Meter";
4280 0 : rowHead(2) = "Selected";
4281 0 : rowHead(3) = "Group";
4282 0 : rowHead(4) = "Qualified";
4283 0 : rowHead(5) = "Disqualifier";
4284 0 : rowHead(6) = "Computation";
4285 0 : rowHead(7) = "Units";
4286 0 : tableBody(1, 1) = tariff.reportMeter;
4287 0 : if (tariff.isSelected) {
4288 0 : tableBody(1, 2) = "Yes";
4289 : } else {
4290 0 : tableBody(1, 2) = "No";
4291 : }
4292 0 : if (tariff.groupName == "") {
4293 0 : tableBody(1, 3) = "(none)";
4294 : } else {
4295 0 : tableBody(1, 3) = tariff.groupName;
4296 : }
4297 0 : if (tariff.isQualified) {
4298 0 : tableBody(1, 4) = "Yes";
4299 : } else {
4300 0 : tableBody(1, 4) = "No";
4301 : }
4302 0 : if (tariff.isQualified) {
4303 0 : tableBody(1, 5) = "n/a";
4304 : } else {
4305 0 : tableBody(1, 5) = econVar(tariff.ptDisqualifier).name;
4306 : }
4307 0 : if (computation.isUserDef) {
4308 0 : tableBody(1, 6) = computation.computeName;
4309 : } else {
4310 0 : tableBody(1, 6) = "automatic";
4311 : }
4312 0 : switch (tariff.convChoice) {
4313 0 : case EconConv::USERDEF: {
4314 0 : tableBody(1, 7) = "User Defined";
4315 0 : } break;
4316 0 : case EconConv::KWH: {
4317 0 : tableBody(1, 7) = "kWh";
4318 0 : } break;
4319 0 : case EconConv::THERM: {
4320 0 : tableBody(1, 7) = "Therm";
4321 0 : } 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 0 : case EconConv::MCF: {
4332 0 : tableBody(1, 7) = "MCF";
4333 0 : } break;
4334 0 : case EconConv::CCF: {
4335 0 : tableBody(1, 7) = "CCF";
4336 0 : } break;
4337 0 : default:
4338 0 : break;
4339 : }
4340 0 : columnWidth = 14; // array assignment - same for all columns
4341 0 : OutputReportTabular::WriteSubtitle(state, "General");
4342 0 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4343 0 : if (state.dataSQLiteProcedures->sqlite) {
4344 0 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(
4345 : tableBody, rowHead, columnHead, "Tariff Report", tariff.tariffName, "General");
4346 : }
4347 0 : if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
4348 0 : state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
4349 0 : tableBody, rowHead, columnHead, "Tariff Report", tariff.tariffName, "General");
4350 : }
4351 0 : columnHead.deallocate();
4352 0 : rowHead.deallocate();
4353 0 : columnWidth.deallocate();
4354 0 : tableBody.deallocate();
4355 : //---- Categories
4356 0 : for (auto &e : econVar) {
4357 0 : e.activeNow = false;
4358 : }
4359 0 : econVar(tariff.cats[(int)Cat::EnergyCharges]).activeNow = true;
4360 0 : econVar(tariff.cats[(int)Cat::DemandCharges]).activeNow = true;
4361 0 : econVar(tariff.cats[(int)Cat::ServiceCharges]).activeNow = true;
4362 0 : econVar(tariff.cats[(int)Cat::Basis]).activeNow = true;
4363 0 : econVar(tariff.cats[(int)Cat::Adjustment]).activeNow = true;
4364 0 : econVar(tariff.cats[(int)Cat::Surcharge]).activeNow = true;
4365 0 : econVar(tariff.cats[(int)Cat::Subtotal]).activeNow = true;
4366 0 : econVar(tariff.cats[(int)Cat::Taxes]).activeNow = true;
4367 0 : econVar(tariff.cats[(int)Cat::Total]).activeNow = true;
4368 0 : ReportEconomicVariable(state, "Categories", false, true, tariff.tariffName);
4369 : //---- Charges
4370 0 : for (auto &e : econVar) {
4371 0 : e.activeNow = false;
4372 : }
4373 0 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4374 0 : if (econVar(kVar).tariffIndx == iTariff) {
4375 0 : if ((econVar(kVar).kindOfObj == ObjType::ChargeSimple) || (econVar(kVar).kindOfObj == ObjType::ChargeBlock)) {
4376 0 : econVar(kVar).activeNow = true;
4377 : }
4378 : }
4379 : }
4380 0 : ReportEconomicVariable(state, "Charges", true, true, tariff.tariffName);
4381 : //---- Sources for Charges
4382 0 : for (auto &e : econVar) {
4383 0 : e.activeNow = false;
4384 : }
4385 0 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4386 0 : if (econVar(kVar).tariffIndx == iTariff) {
4387 0 : int indexInChg = econVar(kVar).index;
4388 0 : if (econVar(kVar).kindOfObj == ObjType::ChargeSimple) {
4389 0 : auto &chargeSimple = s_econ->chargeSimple(indexInChg);
4390 0 : if (chargeSimple.sourcePt > 0) {
4391 0 : econVar(chargeSimple.sourcePt).activeNow = true;
4392 : }
4393 0 : } else if (econVar(kVar).kindOfObj == ObjType::ChargeBlock) {
4394 0 : auto &chargeBlock = s_econ->chargeBlock(indexInChg);
4395 0 : if (chargeBlock.sourcePt > 0) {
4396 0 : econVar(chargeBlock.sourcePt).activeNow = true;
4397 : }
4398 : }
4399 : }
4400 : }
4401 0 : ReportEconomicVariable(state, "Corresponding Sources for Charges", false, false, tariff.tariffName);
4402 : //---- Rachets
4403 0 : for (auto &e : econVar) {
4404 0 : e.activeNow = false;
4405 : }
4406 0 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4407 0 : if (econVar(kVar).tariffIndx == iTariff) {
4408 0 : if (econVar(kVar).kindOfObj == ObjType::Ratchet) {
4409 0 : econVar(kVar).activeNow = true;
4410 : }
4411 : }
4412 : }
4413 0 : ReportEconomicVariable(state, "Ratchets", false, false, tariff.tariffName);
4414 : //---- Qualifies
4415 0 : for (auto &e : econVar) {
4416 0 : e.activeNow = false;
4417 : }
4418 0 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4419 0 : if (econVar(kVar).tariffIndx == iTariff) {
4420 0 : if (econVar(kVar).kindOfObj == ObjType::Qualify) {
4421 0 : econVar(kVar).activeNow = true;
4422 : }
4423 : }
4424 : }
4425 0 : ReportEconomicVariable(state, "Qualifies", false, false, tariff.tariffName);
4426 : //---- Native Variables
4427 0 : for (auto &e : econVar) {
4428 0 : e.activeNow = false;
4429 : }
4430 0 : for (int kVar = tariff.firstNative; kVar <= tariff.lastNative; ++kVar) {
4431 0 : econVar(kVar).activeNow = true;
4432 : }
4433 0 : ReportEconomicVariable(state, "Native Variables", false, false, tariff.tariffName);
4434 : //---- Other Variables
4435 0 : for (auto &e : econVar) {
4436 0 : e.activeNow = false;
4437 : }
4438 0 : for (int kVar = 1; kVar <= s_econ->numEconVar; ++kVar) {
4439 0 : if (econVar(kVar).tariffIndx == iTariff) {
4440 0 : if (!econVar(kVar).isReported) {
4441 0 : econVar(kVar).activeNow = true;
4442 : }
4443 : }
4444 : }
4445 0 : ReportEconomicVariable(state, "Other Variables", false, false, tariff.tariffName);
4446 : //---- Computation
4447 0 : if (computation.isUserDef) {
4448 0 : OutputReportTabular::WriteTextLine(state, "Computation - User Defined", true);
4449 : } else {
4450 0 : OutputReportTabular::WriteTextLine(state, "Computation - Automatic", true);
4451 : }
4452 0 : std::string outString = "";
4453 0 : for (int lStep = computation.firstStep; lStep <= computation.lastStep; ++lStep) {
4454 0 : auto &step = s_econ->steps(lStep);
4455 :
4456 0 : if (step.type == StepType::EOL) {
4457 0 : OutputReportTabular::WriteTextLine(state, rstrip(outString));
4458 0 : outString = "";
4459 0 : } else if (step.type == StepType::Var) {
4460 0 : outString = econVar(step.varNum).name + ' ' + outString;
4461 0 : } else if (step.type == StepType::Op) {
4462 0 : outString = format("{} {}", opNamesUC[(int)step.op], outString);
4463 : }
4464 : }
4465 : }
4466 : }
4467 : }
4468 75 : }
4469 :
4470 2 : 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 2 : auto &s_econ = state.dataEconTariff;
4478 4 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4479 2 : auto const &tariff = s_econ->tariff(iTariff);
4480 2 : if (tariff.buyOrSell == BuySell::BuyFromUtility) {
4481 0 : 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 0 : 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 2 : }
4493 :
4494 0 : 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 0 : Real64 maximumVal(0.0); // Autodesk Value not used but suppresses warning about HUGE_() call
4502 :
4503 0 : auto const &s_econ = state.dataEconTariff;
4504 0 : auto const &econVar = s_econ->econVar(varPointer);
4505 :
4506 0 : Real64 sumVal = 0.0;
4507 0 : maximumVal = -HUGE_(maximumVal);
4508 0 : 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 0 : Real64 curVal = econVar.values(jMonth);
4510 0 : sumVal += curVal;
4511 0 : if (curVal > maximumVal) {
4512 0 : maximumVal = curVal;
4513 : }
4514 : }
4515 0 : sumResult = sumVal;
4516 0 : maxResult = maximumVal;
4517 0 : }
4518 :
4519 0 : 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 0 : Array1D_string columnHead;
4531 0 : Array1D_int columnWidth;
4532 0 : Array1D_string rowHead;
4533 0 : 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 0 : auto const &s_econ = state.dataEconTariff;
4547 0 : auto const &econVar = s_econ->econVar;
4548 0 : auto const &chargeBlock = s_econ->chargeBlock;
4549 0 : auto const &chargeSimple = s_econ->chargeSimple;
4550 :
4551 0 : cntOfVar = 0;
4552 0 : for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
4553 0 : if (econVar(iVar).activeNow) {
4554 0 : ++cntOfVar;
4555 : }
4556 : }
4557 0 : if (includeCategory) {
4558 0 : rowHead.allocate(cntOfVar);
4559 0 : columnHead.allocate(15);
4560 0 : columnWidth.allocate(15);
4561 0 : tableBody.allocate(15, cntOfVar);
4562 : } else {
4563 0 : rowHead.allocate(cntOfVar);
4564 0 : columnHead.allocate(14);
4565 0 : columnWidth.allocate(14);
4566 0 : tableBody.allocate(14, cntOfVar);
4567 : }
4568 : // column names
4569 0 : columnHead(1) = "Jan";
4570 0 : columnHead(2) = "Feb";
4571 0 : columnHead(3) = "Mar";
4572 0 : columnHead(4) = "Apr";
4573 0 : columnHead(5) = "May";
4574 0 : columnHead(6) = "Jun";
4575 0 : columnHead(7) = "Jul";
4576 0 : columnHead(8) = "Aug";
4577 0 : columnHead(9) = "Sep";
4578 0 : columnHead(10) = "Oct";
4579 0 : columnHead(11) = "Nov";
4580 0 : columnHead(12) = "Dec";
4581 0 : columnHead(13) = "Sum";
4582 0 : columnHead(14) = "Max";
4583 0 : if (includeCategory) {
4584 0 : columnHead(15) = "Category";
4585 : }
4586 0 : nCntOfVar = 0;
4587 : // row names
4588 0 : for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
4589 0 : if (econVar(iVar).activeNow) {
4590 0 : ++nCntOfVar;
4591 0 : if (showCurrencySymbol) {
4592 0 : rowHead(nCntOfVar) = econVar(iVar).name + " (~~$~~)";
4593 : } else {
4594 0 : rowHead(nCntOfVar) = econVar(iVar).name;
4595 : }
4596 : }
4597 : }
4598 : // fill the body
4599 0 : nCntOfVar = 0;
4600 0 : for (iVar = 1; iVar <= s_econ->numEconVar; ++iVar) {
4601 0 : if (econVar(iVar).activeNow) {
4602 0 : ++nCntOfVar;
4603 0 : 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 0 : curVal = econVar(iVar).values(jMonth);
4605 0 : if ((curVal > 0) && (curVal < 1)) {
4606 0 : tableBody(jMonth, nCntOfVar) = OutputReportTabular::RealToStr(curVal, 4);
4607 : } else {
4608 0 : tableBody(jMonth, nCntOfVar) = OutputReportTabular::RealToStr(curVal, 2);
4609 : }
4610 : }
4611 0 : getMaxAndSum(state, iVar, sumVal, maximumVal);
4612 0 : tableBody(13, nCntOfVar) = OutputReportTabular::RealToStr(sumVal, 2);
4613 0 : tableBody(14, nCntOfVar) = OutputReportTabular::RealToStr(maximumVal, 2);
4614 0 : if (includeCategory) {
4615 : // first find category
4616 0 : curCategory = 0;
4617 0 : curIndex = econVar(iVar).index;
4618 :
4619 0 : switch (econVar(iVar).kindOfObj) {
4620 0 : case ObjType::ChargeSimple:
4621 0 : if ((curIndex >= 1) && (curIndex <= s_econ->numChargeSimple)) {
4622 0 : curCatPt = chargeSimple(curIndex).categoryPt;
4623 : }
4624 0 : break;
4625 0 : case ObjType::ChargeBlock:
4626 0 : if ((curIndex >= 1) && (curIndex <= s_econ->numChargeBlock)) {
4627 0 : curCatPt = chargeBlock(curIndex).categoryPt;
4628 : }
4629 0 : break;
4630 0 : default:
4631 0 : break;
4632 : }
4633 :
4634 0 : if ((curCatPt >= 1) && (curCatPt <= s_econ->numEconVar)) {
4635 0 : curCategory = econVar(curCatPt).specific;
4636 : }
4637 :
4638 : // In this specific table, "NotIncluded" is written as "none" so need a special case for that
4639 0 : tableBody(15, nCntOfVar) =
4640 0 : (econVar(curCatPt).kindOfObj == ObjType::Category)
4641 0 : ? ((econVar(curCatPt).specific == (int)Cat::NotIncluded) ? "none" : catNames[econVar(curCatPt).specific])
4642 0 : : "none";
4643 : }
4644 0 : s_econ->econVar(iVar).isReported = true;
4645 : }
4646 : }
4647 0 : columnWidth = 14; // array assignment - same for all columns
4648 0 : OutputReportTabular::WriteSubtitle(state, titleString);
4649 0 : OutputReportTabular::WriteTable(state, tableBody, rowHead, columnHead, columnWidth);
4650 0 : if (state.dataSQLiteProcedures->sqlite) {
4651 0 : state.dataSQLiteProcedures->sqlite->createSQLiteTabularDataRecords(tableBody, rowHead, columnHead, "Tariff Report", forString, titleString);
4652 : }
4653 0 : if (state.dataResultsFramework->resultsFramework->timeSeriesAndTabularEnabled()) {
4654 0 : state.dataResultsFramework->resultsFramework->TabularReportsCollection.addReportTable(
4655 : tableBody, rowHead, columnHead, "Tariff Report", forString, titleString);
4656 : }
4657 0 : columnHead.deallocate();
4658 0 : rowHead.deallocate();
4659 0 : columnWidth.deallocate();
4660 0 : tableBody.deallocate();
4661 0 : }
4662 :
4663 0 : 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 0 : Array1D_int groupIndex; // index number (in tariff) for the group name
4677 0 : Array1D_int MinTariffIndex; // tariff index for the Minimum value
4678 : int curMinTariffIndex;
4679 :
4680 0 : auto const &s_econ = state.dataEconTariff;
4681 0 : auto const &econVar(s_econ->econVar);
4682 :
4683 0 : groupIndex.dimension(s_econ->numTariff, 0);
4684 0 : int groupCount = 0;
4685 0 : int numMins = 0;
4686 0 : MinTariffIndex.dimension(s_econ->numTariff, 0);
4687 0 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4688 0 : auto &tariff = s_econ->tariff(iTariff);
4689 : // compute the total annual cost of each tariff
4690 0 : int totalVarPt = tariff.cats[(int)Cat::Total];
4691 0 : int totEneVarPt = tariff.natives[(int)Native::TotalEnergy];
4692 0 : Real64 annualTotal = 0.0;
4693 0 : Real64 annEneTotal = 0.0;
4694 0 : for (int jMonth = 1; jMonth <= NumMonths; ++jMonth) {
4695 0 : annualTotal += econVar(totalVarPt).values(jMonth);
4696 0 : annEneTotal += econVar(totEneVarPt).values(jMonth);
4697 : }
4698 0 : tariff.totalAnnualCost = annualTotal;
4699 0 : tariff.totalAnnualEnergy = annEneTotal;
4700 : // Set the groupIndex
4701 0 : if (groupIndex(iTariff) == 0) {
4702 : // set the current item to the tariff index
4703 0 : ++groupCount;
4704 0 : groupIndex(iTariff) = groupCount;
4705 : // set all remaining matching items to the same index
4706 0 : for (int kTariff = iTariff + 1; kTariff <= s_econ->numTariff; ++kTariff) {
4707 0 : if (Util::SameString(s_econ->tariff(kTariff).groupName, tariff.groupName)) {
4708 0 : 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 0 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4715 0 : auto &tariff = s_econ->tariff(iTariff);
4716 0 : if (tariff.isQualified) {
4717 0 : bool isFound = false;
4718 0 : for (int lMin = 1; lMin <= numMins; ++lMin) {
4719 0 : curMinTariffIndex = MinTariffIndex(lMin);
4720 : // find matching meter and group
4721 0 : if (tariff.reportMeterIndx == s_econ->tariff(curMinTariffIndex).reportMeterIndx) {
4722 0 : if (groupIndex(iTariff) == groupIndex(curMinTariffIndex)) {
4723 0 : isFound = true;
4724 : // found the matching mater and group now test if smaller Min is current tariff
4725 0 : if (tariff.totalAnnualCost < s_econ->tariff(curMinTariffIndex).totalAnnualCost) {
4726 0 : MinTariffIndex(lMin) = iTariff;
4727 : // select the new Minimum tariff and deselect the one that was just exceeded
4728 0 : s_econ->tariff(curMinTariffIndex).isSelected = false;
4729 0 : tariff.isSelected = true;
4730 : }
4731 : }
4732 : }
4733 : }
4734 0 : if (!isFound) {
4735 0 : ++numMins;
4736 0 : if (numMins > s_econ->numTariff) {
4737 0 : ShowWarningError(state, "UtilityCost:Tariff Debugging error numMins greater than numTariff.");
4738 : }
4739 0 : MinTariffIndex(numMins) = iTariff;
4740 : // tariff(numMins)%isSelected = .TRUE. !original
4741 0 : 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 0 : for (int mGroup = 1; mGroup <= groupCount; ++mGroup) {
4751 0 : int lowestSimpleTariff = 0;
4752 0 : int lowestPurchaseTariff = 0;
4753 0 : int lowestSurplusSoldTariff = 0;
4754 0 : int lowestNetMeterTariff = 0;
4755 0 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4756 0 : auto &tariff = s_econ->tariff(iTariff);
4757 0 : if (tariff.isQualified) {
4758 0 : if (tariff.isSelected) {
4759 0 : if (groupIndex(iTariff) == mGroup) {
4760 0 : if (tariff.kindMtr == MeterType::ElecSimple) {
4761 0 : lowestSimpleTariff = iTariff;
4762 0 : } 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 0 : } else if (tariff.kindMtr == MeterType::ElecPurchased) {
4766 0 : lowestPurchaseTariff = iTariff;
4767 0 : } else if (tariff.kindMtr == MeterType::ElecSurplusSold) {
4768 0 : lowestSurplusSoldTariff = iTariff;
4769 0 : } else if (tariff.kindMtr == MeterType::ElecNet) {
4770 0 : lowestNetMeterTariff = iTariff;
4771 : }
4772 : }
4773 : }
4774 : }
4775 : }
4776 : // compare the simple and purchased metered tariffs
4777 0 : 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 0 : if (lowestSurplusSoldTariff > 0) {
4788 0 : 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 0 : 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 0 : if (((lowestNetMeterTariff > 0) && (lowestSurplusSoldTariff > 0)) && (lowestPurchaseTariff > 0)) {
4808 0 : if (s_econ->tariff(lowestNetMeterTariff).totalAnnualCost <
4809 0 : (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 0 : s_econ->tariff(lowestNetMeterTariff).isSelected = false;
4816 0 : lowestNetMeterTariff = 0;
4817 : }
4818 : }
4819 : // if netmetering is used compare it to simple only
4820 0 : 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 0 : 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 0 : groupIndex.deallocate();
4841 0 : MinTariffIndex.deallocate();
4842 0 : }
4843 :
4844 48 : 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 48 : auto const &s_econ = state.dataEconTariff;
4853 :
4854 48 : outMonthlyCosts.dim(12);
4855 :
4856 48 : outMonthlyCosts = 0.0;
4857 96 : for (int iTariff = 1; iTariff <= s_econ->numTariff; ++iTariff) {
4858 48 : auto const &tariff = s_econ->tariff(iTariff);
4859 48 : if (tariff.isSelected) {
4860 48 : if (tariff.resource == inResourceNumber) {
4861 1 : auto const &econVar = s_econ->econVar(tariff.cats[(int)Cat::Total]);
4862 13 : for (int jMonth = 1; jMonth <= 12; ++jMonth) { // use 12 because LCC assume 12 months
4863 12 : outMonthlyCosts(jMonth) += econVar.values(jMonth);
4864 : }
4865 : }
4866 : }
4867 : }
4868 48 : }
4869 :
4870 : } // namespace EnergyPlus::EconomicTariff
|