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