LCOV - code coverage report
Current view: top level - EnergyPlus/api - datatransfer.cc (source / functions) Coverage Total Hit
Test: lcov.output.filtered Lines: 29.1 % 794 231
Test Date: 2025-05-22 16:09:37 Functions: 31.8 % 88 28

            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              : #include <cmath>
      49              : 
      50              : #include <ObjexxFCL/ArrayS.functions.hh>
      51              : #include <ObjexxFCL/time.hh>
      52              : 
      53              : #include <EnergyPlus/Construction.hh>
      54              : #include <EnergyPlus/Data/EnergyPlusData.hh>
      55              : #include <EnergyPlus/DataEnvironment.hh>
      56              : #include <EnergyPlus/DataGlobalConstants.hh>
      57              : #include <EnergyPlus/DataHVACGlobals.hh>
      58              : #include <EnergyPlus/DataRuntimeLanguage.hh>
      59              : #include <EnergyPlus/DataStringGlobals.hh>
      60              : #include <EnergyPlus/HeatBalFiniteDiffManager.hh>
      61              : #include <EnergyPlus/InputProcessing/InputProcessor.hh>
      62              : #include <EnergyPlus/OutputProcessor.hh>
      63              : #include <EnergyPlus/PluginManager.hh>
      64              : #include <EnergyPlus/UtilityRoutines.hh>
      65              : #include <EnergyPlus/WeatherManager.hh>
      66              : #include <EnergyPlus/api/datatransfer.h>
      67              : #include <EnergyPlus/api/runtime.h>
      68              : 
      69              : using namespace EnergyPlus;
      70              : 
      71            2 : APIDataEntry *getAPIData(EnergyPlusState state, unsigned int *resultingSize)
      72              : {
      73              :     struct LocalAPIDataEntry
      74              :     {
      75              :         std::string what;
      76              :         std::string name;
      77              :         std::string type;
      78              :         std::string key;
      79              :         std::string unit;
      80              : 
      81          294 :         LocalAPIDataEntry(std::string _what, std::string _name, std::string _type, std::string _key, std::string _unit)
      82          294 :             : what(std::move(_what)), name(std::move(_name)), type(std::move(_type)), key(std::move(_key)), unit(std::move(_unit))
      83              :         {
      84          294 :         }
      85              :     };
      86            2 :     std::vector<LocalAPIDataEntry> localDataEntries;
      87            2 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
      88          136 :     for (auto const &availActuator : thisState->dataRuntimeLang->EMSActuatorAvailable) {
      89          136 :         if (availActuator.ComponentTypeName.empty() && availActuator.UniqueIDName.empty() && availActuator.ControlTypeName.empty()) {
      90            2 :             break;
      91              :         }
      92          134 :         localDataEntries.emplace_back(
      93          134 :             "Actuator", availActuator.ComponentTypeName, availActuator.ControlTypeName, availActuator.UniqueIDName, availActuator.Units);
      94              :     }
      95           14 :     for (auto const &availVariable : thisState->dataRuntimeLang->EMSInternalVarsAvailable) {
      96           14 :         if (availVariable.DataTypeName.empty() && availVariable.UniqueIDName.empty()) {
      97            2 :             break;
      98              :         }
      99           12 :         localDataEntries.emplace_back("InternalVariable", availVariable.DataTypeName, "", availVariable.UniqueIDName, availVariable.Units);
     100              :     }
     101            2 :     for (auto const &gVarName : thisState->dataPluginManager->globalVariableNames) {
     102            0 :         localDataEntries.emplace_back("PluginGlobalVariable", "", "", gVarName, "");
     103              :     }
     104            2 :     for (auto const &trend : thisState->dataPluginManager->trends) {
     105            0 :         localDataEntries.emplace_back("PluginTrendVariable,", "", "", trend.name, "");
     106              :     }
     107           58 :     for (auto const *meter : thisState->dataOutputProcessor->meters) {
     108           56 :         if (meter->Name.empty()) {
     109            0 :             break;
     110              :         }
     111           56 :         localDataEntries.emplace_back("OutputMeter", "", "", meter->Name, format("{}", EnergyPlus::Constant::unitNames[(int)meter->units]));
     112              :     }
     113           98 :     for (auto const *variable : thisState->dataOutputProcessor->outVars) {
     114           96 :         if (variable->varType != EnergyPlus::OutputProcessor::VariableType::Real) continue;
     115           92 :         if (variable->name.empty() && variable->keyUC.empty()) {
     116            0 :             break;
     117              :         }
     118           92 :         localDataEntries.emplace_back("OutputVariable",
     119           92 :                                       variable->name,
     120              :                                       "",
     121           92 :                                       variable->keyUC,
     122           92 :                                       variable->units == EnergyPlus::Constant::Units::customEMS
     123          276 :                                           ? variable->unitNameCustomEMS
     124           92 :                                           : format("{}", EnergyPlus::Constant::unitNames[(int)variable->units]));
     125              :     }
     126            2 :     *resultingSize = localDataEntries.size();
     127            2 :     auto *data = new APIDataEntry[*resultingSize];
     128          296 :     for (unsigned int i = 0; i < *resultingSize; i++) {
     129          294 :         data[i].what = new char[std::strlen(localDataEntries[i].what.c_str()) + 1];
     130          294 :         std::strcpy(data[i].what, localDataEntries[i].what.c_str());
     131          294 :         data[i].name = new char[std::strlen(localDataEntries[i].name.c_str()) + 1];
     132          294 :         std::strcpy(data[i].name, localDataEntries[i].name.c_str());
     133          294 :         data[i].key = new char[std::strlen(localDataEntries[i].key.c_str()) + 1];
     134          294 :         std::strcpy(data[i].key, localDataEntries[i].key.c_str());
     135          294 :         data[i].type = new char[std::strlen(localDataEntries[i].type.c_str()) + 1];
     136          294 :         std::strcpy(data[i].type, localDataEntries[i].type.c_str());
     137          294 :         data[i].unit = new char[std::strlen(localDataEntries[i].unit.c_str()) + 1];
     138          294 :         std::strcpy(data[i].unit, localDataEntries[i].unit.c_str());
     139              :     }
     140            2 :     return data;
     141            2 : }
     142              : 
     143            2 : void freeAPIData(const APIDataEntry *data, const unsigned int arraySize)
     144              : {
     145          155 :     for (unsigned int i = 0; i < arraySize; i++) {
     146          153 :         delete[] data[i].what;
     147          153 :         delete[] data[i].name;
     148          153 :         delete[] data[i].key;
     149          153 :         delete[] data[i].type;
     150          153 :         delete[] data[i].unit;
     151              :     }
     152            2 :     delete[] data;
     153            2 : }
     154              : 
     155            0 : char *listAllAPIDataCSV(EnergyPlusState state)
     156              : {
     157            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     158            0 :     std::string output = "**ACTUATORS**\n";
     159            0 :     for (auto const &availActuator : thisState->dataRuntimeLang->EMSActuatorAvailable) {
     160            0 :         if (availActuator.ComponentTypeName.empty() && availActuator.UniqueIDName.empty() && availActuator.ControlTypeName.empty()) {
     161            0 :             break;
     162              :         }
     163            0 :         output.append("Actuator,");
     164            0 :         output.append(availActuator.ComponentTypeName).append(",");
     165            0 :         output.append(availActuator.ControlTypeName).append(",");
     166            0 :         output.append(availActuator.UniqueIDName).append(",");
     167            0 :         output.append(availActuator.Units).append("\n");
     168              :     }
     169            0 :     output.append("**INTERNAL_VARIABLES**\n");
     170            0 :     for (auto const &availVariable : thisState->dataRuntimeLang->EMSInternalVarsAvailable) {
     171            0 :         if (availVariable.DataTypeName.empty() && availVariable.UniqueIDName.empty()) {
     172            0 :             break;
     173              :         }
     174            0 :         output.append("InternalVariable,");
     175            0 :         output.append(availVariable.DataTypeName).append(",");
     176            0 :         output.append(availVariable.UniqueIDName).append(",");
     177            0 :         output.append(availVariable.Units).append("\n");
     178              :     }
     179            0 :     output.append("**PLUGIN_GLOBAL_VARIABLES**\n");
     180            0 :     for (auto const &gVarName : thisState->dataPluginManager->globalVariableNames) {
     181            0 :         output.append("PluginGlobalVariable,");
     182            0 :         output.append(gVarName).append("\n");
     183              :     }
     184            0 :     output.append("**TRENDS**\n");
     185            0 :     for (auto const &trend : thisState->dataPluginManager->trends) {
     186            0 :         output.append("PluginTrendVariable,");
     187            0 :         output.append(trend.name).append("\n");
     188              :     }
     189            0 :     output.append("**METERS**\n");
     190            0 :     for (auto const *meter : thisState->dataOutputProcessor->meters) {
     191            0 :         if (meter->Name.empty()) {
     192            0 :             break;
     193              :         }
     194            0 :         output.append("OutputMeter").append(","); // This multiple append thing is not good
     195            0 :         output.append(meter->Name).append(",");
     196            0 :         output.append(format("{}\n", EnergyPlus::Constant::unitNames[(int)meter->units]));
     197              :     }
     198            0 :     output.append("**VARIABLES**\n");
     199            0 :     for (auto const *variable : thisState->dataOutputProcessor->outVars) {
     200            0 :         if (variable->varType != EnergyPlus::OutputProcessor::VariableType::Real) continue;
     201            0 :         if (variable->name.empty() && variable->keyUC.empty()) {
     202            0 :             break;
     203              :         }
     204            0 :         output.append("OutputVariable,");
     205            0 :         output.append(variable->name).append(",");
     206            0 :         output.append(variable->keyUC).append(",");
     207            0 :         output.append(format("{}\n",
     208            0 :                              variable->units == EnergyPlus::Constant::Units::customEMS ? variable->unitNameCustomEMS
     209            0 :                                                                                        : EnergyPlus::Constant::unitNames[(int)variable->units]));
     210              :     }
     211              :     // note that we cannot just return a c_str to the local string, as the string will be destructed upon leaving
     212              :     // this function, and undefined behavior will occur.
     213              :     // instead make a deep copy, and the user must manage the new char * pointer
     214              :     // strcpy copies including the null-terminator, strlen doesn't include it
     215            0 :     char *p = new char[std::strlen(output.c_str()) + 1];
     216            0 :     std::strcpy(p, output.c_str());
     217            0 :     return p;
     218            0 : }
     219              : 
     220         2883 : int apiDataFullyReady(EnergyPlusState state)
     221              : {
     222         2883 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     223         2883 :     if (thisState->dataPluginManager->fullyReady) {
     224         2883 :         return 1;
     225              :     }
     226            0 :     return 0;
     227              : }
     228              : 
     229            0 : int apiErrorFlag(EnergyPlusState state)
     230              : {
     231            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     232            0 :     if (thisState->dataPluginManager->apiErrorFlag) {
     233            0 :         return 1;
     234              :     }
     235            0 :     return 0;
     236              : }
     237              : 
     238            0 : void resetErrorFlag(EnergyPlusState state)
     239              : {
     240            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     241            0 :     thisState->dataPluginManager->apiErrorFlag = false;
     242            0 : }
     243              : 
     244            2 : char *inputFilePath(EnergyPlusState state)
     245              : {
     246            2 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     247            2 :     std::string const path_utf8 = EnergyPlus::FileSystem::toGenericString(thisState->dataStrGlobals->inputFilePath);
     248            2 :     char *p = new char[std::strlen(path_utf8.c_str()) + 1];
     249            2 :     std::strcpy(p, path_utf8.c_str());
     250            2 :     return p;
     251            2 : }
     252              : 
     253            2 : char *epwFilePath(EnergyPlusState state)
     254              : {
     255            2 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     256            2 :     std::string const path_utf8 = EnergyPlus::FileSystem::toGenericString(thisState->files.inputWeatherFilePath.filePath);
     257            2 :     char *p = new char[std::strlen(path_utf8.c_str()) + 1];
     258            2 :     std::strcpy(p, path_utf8.c_str());
     259            2 :     return p;
     260            2 : }
     261              : 
     262            2 : char **getObjectNames(EnergyPlusState state, const char *objectType, unsigned int *resultingSize)
     263              : {
     264            2 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     265            2 :     auto &epjson = thisState->dataInputProcessing->inputProcessor->epJSON;
     266            2 :     const auto instances = epjson.find(objectType);
     267            2 :     if (instances == epjson.end()) {
     268            0 :         *resultingSize = 0;
     269            0 :         return nullptr;
     270              :     }
     271            2 :     auto &instancesValue = instances.value();
     272            2 :     *resultingSize = instancesValue.size();
     273            2 :     char **data = new char *[*resultingSize];
     274            2 :     unsigned int i = -1;
     275           14 :     for (auto instance = instancesValue.begin(); instance != instancesValue.end(); ++instance) {
     276           12 :         i++;
     277           12 :         std::string s = std::string(instance.key());
     278           12 :         data[i] = new char[std::strlen(instance.key().data()) + 1];
     279           12 :         std::strcpy(data[i], instance.key().data());
     280           12 :     }
     281            2 :     return data;
     282              : }
     283              : 
     284            2 : void freeObjectNames(char **objectNames, unsigned int arraySize)
     285              : {
     286              :     // as of right now we don't actually need to free the underlying strings, they exist in the epJSON instance, so just delete our array of pointers
     287              :     (void)arraySize;
     288              :     // no op to avoid compiler warning that this variable is unused, in the future, this may be needed so keeping it in the API now
     289            2 :     delete[] objectNames;
     290            2 : }
     291              : 
     292           26 : int getNumNodesInCondFDSurfaceLayer(EnergyPlusState state, const char *surfName, const char *matName)
     293              : {
     294           26 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     295           26 :     std::string UCsurfName = EnergyPlus::Util::makeUPPER(surfName);
     296           26 :     std::string UCmatName = EnergyPlus::Util::makeUPPER(matName);
     297           52 :     return EnergyPlus::HeatBalFiniteDiffManager::numNodesInMaterialLayer(*thisState, UCsurfName, UCmatName);
     298           26 : }
     299              : 
     300            4 : void requestVariable(EnergyPlusState state, const char *type, const char *key)
     301              : {
     302              :     // allow specifying a request for an output variable, so that E+ does not have to keep all of them in memory
     303              :     // should be called before energyplus is run!
     304              :     // note that the variable request array is cleared during clear_state, so if you run multiple E+ runs, these must be requested again each time.
     305            4 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     306            4 :     EnergyPlus::OutputProcessor::APIOutputVariableRequest request;
     307            4 :     request.varName = type;
     308            4 :     request.varKey = key;
     309            4 :     thisState->dataOutputProcessor->apiVarRequests.push_back(request);
     310            4 : }
     311              : 
     312           11 : int getVariableHandle(EnergyPlusState state, const char *type, const char *key)
     313              : {
     314              :     // Variables are accessed through a single integer ID, but there are multiple internal types: real and integer.
     315              :     // I am going to make the integer handle span all both types, by carefully defining the handle.
     316              :     // basically, the handles are contiguous, with:
     317              :     //  - index 1 being the first real variable handle
     318              :     //  - index N being the highest real variable handle
     319              :     //  - index N+1 being the first integer variable handle
     320              :     //  - index N+M being the highest integer variable handle
     321              :     // In this function, it is as simple as looping over both types and continuing to increment
     322              :     // the handle carefully.  In the getValue function it is just a matter of checking array sizes.
     323           11 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     324           11 :     std::string const typeUC = EnergyPlus::Util::makeUPPER(type);
     325           11 :     std::string const keyUC = EnergyPlus::Util::makeUPPER(key);
     326          329 :     for (int i = 0; i < thisState->dataOutputProcessor->outVars.size(); i++) {
     327          329 :         auto const *var = thisState->dataOutputProcessor->outVars[i];
     328          329 :         if (typeUC == var->nameUC && keyUC == var->keyUC) {
     329           11 :             return i;
     330              :         }
     331              :     }
     332            0 :     return -1; // return -1 if it wasn't found
     333           11 : }
     334              : 
     335       119635 : Real64 getVariableValue(EnergyPlusState state, const int handle)
     336              : {
     337              :     // this function works in conjunction with the plan set up in getVariableHandle
     338              :     // basically, the handles are contiguous, with:
     339              :     //  - index 1 being the first real variable handle
     340              :     //  - index N being the highest real variable handle
     341              :     //  - index N+1 being the first integer variable handle
     342              :     //  - index N+M being the highest integer variable handle
     343              :     // note that this function will return -1 if it cannot
     344       119635 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     345       119635 :     if (handle >= 0 && handle < thisState->dataOutputProcessor->outVars.size()) {
     346       119634 :         auto const *thisOutputVar = thisState->dataOutputProcessor->outVars[handle];
     347       119634 :         if (thisOutputVar->varType == EnergyPlus::OutputProcessor::VariableType::Real) {
     348       119634 :             return *(dynamic_cast<EnergyPlus::OutputProcessor::OutVarReal const *>(thisOutputVar))->Which;
     349              :         }
     350            0 :         if (thisOutputVar->varType == EnergyPlus::OutputProcessor::VariableType::Integer) {
     351            0 :             return (Real64) * (dynamic_cast<EnergyPlus::OutputProcessor::OutVarInt const *>(thisOutputVar))->Which;
     352              :         }
     353            0 :         if (thisState->dataGlobal->errorCallback) {
     354            0 :             std::cout << "ERROR: Variable at handle has type other than Real or Integer, returning zero but caller should take note and likely abort."
     355            0 :                       << std::endl;
     356              :         } else {
     357              :             // must be running from python plugin, need to fatal out once the plugin is done
     358              :             // throw an error, set the fatal flag, and then return zero
     359            0 :             ShowSevereError(*thisState, fmt::format("Data Exchange API: Error in getVariableValue; received handle: {}", handle));
     360            0 :             ShowContinueError(*thisState,
     361              :                               "The getVariableValue function will return 0 for now to allow the plugin to finish, then EnergyPlus will abort");
     362              :         }
     363            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     364            0 :         return 0;
     365              :     }
     366            1 :     if (thisState->dataGlobal->errorCallback) {
     367            0 :         std::cout << "ERROR: Variable handle out of range in getVariableValue, returning zero but caller should take note and likely abort."
     368            0 :                   << std::endl;
     369              :     } else {
     370              :         // must be running from python plugin, need to fatal out once the plugin is done
     371              :         // throw an error, set the fatal flag, and then return zero
     372            2 :         ShowSevereError(*thisState, fmt::format("Data Exchange API: Index error in getVariableValue; received handle: {}", handle));
     373            3 :         ShowContinueError(*thisState,
     374              :                           "The getVariableValue function will return 0 for now to allow the plugin to finish, then EnergyPlus will abort");
     375              :     }
     376            1 :     thisState->dataPluginManager->apiErrorFlag = true;
     377            1 :     return 0;
     378              : }
     379              : 
     380            0 : int getMeterHandle(EnergyPlusState state, const char *meterName)
     381              : {
     382            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     383            0 :     std::string const meterNameUC = EnergyPlus::Util::makeUPPER(meterName);
     384            0 :     const int i = EnergyPlus::GetMeterIndex(*thisState, meterNameUC);
     385            0 :     if (i == 0) {
     386              :         // inside E+, zero is meaningful, but through the API, I want to use negative one as a signal of a bad lookup
     387            0 :         return -1;
     388              :     }
     389            0 :     return i;
     390            0 : }
     391              : 
     392            0 : Real64 getMeterValue(EnergyPlusState state, int handle)
     393              : {
     394            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     395            0 :     if (handle >= 0 && handle < thisState->dataOutputProcessor->meters.size()) {
     396            0 :         return EnergyPlus::GetCurrentMeterValue(*thisState, handle);
     397              :     }
     398            0 :     if (thisState->dataGlobal->errorCallback) {
     399            0 :         std::cout << "ERROR: Meter handle out of range in getMeterValue, returning zero but caller should take note and likely abort." << std::endl;
     400              :     } else {
     401              :         // must be running from python plugin, need to fatal out once the plugin is done
     402              :         // throw an error, set the fatal flag, and then return zero
     403            0 :         ShowSevereError(*thisState, fmt::format("Data Exchange API: Index error in getMeterValue; received handle: {}", handle));
     404            0 :         ShowContinueError(*thisState, "The getMeterValue function will return 0 for now to allow the plugin to finish, then EnergyPlus will abort");
     405              :     }
     406            0 :     thisState->dataPluginManager->apiErrorFlag = true;
     407            0 :     return 0;
     408              : }
     409              : 
     410           88 : int getActuatorHandle(EnergyPlusState state, const char *componentType, const char *controlType, const char *uniqueKey)
     411              : {
     412           88 :     int handle = 0;
     413           88 :     std::string const typeUC = EnergyPlus::Util::makeUPPER(componentType);
     414           88 :     std::string const keyUC = EnergyPlus::Util::makeUPPER(uniqueKey);
     415           88 :     std::string const controlUC = EnergyPlus::Util::makeUPPER(controlType);
     416           88 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     417         9382 :     for (int ActuatorLoop = 1; ActuatorLoop <= thisState->dataRuntimeLang->numEMSActuatorsAvailable; ++ActuatorLoop) {
     418         9375 :         auto &availActuator = thisState->dataRuntimeLang->EMSActuatorAvailable(ActuatorLoop);
     419         9375 :         handle++;
     420         9375 :         std::string const actuatorTypeUC = EnergyPlus::Util::makeUPPER(availActuator.ComponentTypeName);
     421         9375 :         std::string const actuatorIDUC = EnergyPlus::Util::makeUPPER(availActuator.UniqueIDName);
     422         9375 :         std::string const actuatorControlUC = EnergyPlus::Util::makeUPPER(availActuator.ControlTypeName);
     423         9375 :         if (typeUC == actuatorTypeUC && keyUC == actuatorIDUC && controlUC == actuatorControlUC) {
     424           81 :             if (availActuator.handleCount > 0) {
     425              :                 // If the handle is already used by an IDF EnergyManagementSystem:Actuator, we should warn the user
     426            0 :                 bool foundActuator = false;
     427            0 :                 for (auto const &usedActuator : thisState->dataRuntimeLang->EMSActuatorUsed) {
     428            0 :                     if (usedActuator.ActuatorVariableNum == handle) {
     429            0 :                         ShowWarningError(
     430              :                             *thisState,
     431            0 :                             "Data Exchange API: An EnergyManagementSystem:Actuator seems to be already defined in the EnergyPlus File and named '" +
     432            0 :                                 usedActuator.Name + "'.");
     433            0 :                         ShowContinueError(
     434            0 :                             *thisState, fmt::format("Occurred for componentType='{}', controlType='{}', uniqueKey='{}'.", typeUC, controlUC, keyUC));
     435            0 :                         ShowContinueError(*thisState,
     436            0 :                                           fmt::format("The getActuatorHandle function will still return the handle (= {}) but caller "
     437              :                                                       "should take note that there is a risk of overwritting.",
     438              :                                                       handle));
     439            0 :                         foundActuator = true;
     440            0 :                         break;
     441              :                     }
     442              :                 }
     443            0 :                 if (!foundActuator) {
     444            0 :                     ShowWarningError(*thisState, "Data Exchange API: You seem to already have tried to get an Actuator Handle on this one.");
     445            0 :                     ShowContinueError(*thisState,
     446            0 :                                       fmt::format("Occurred for componentType='{}', controlType='{}', uniqueKey='{}'.", typeUC, controlUC, keyUC));
     447            0 :                     ShowContinueError(*thisState,
     448            0 :                                       fmt::format("The getActuatorHandle function will still return the handle (= {}) but caller should "
     449              :                                                   "take note that there is a risk of overwritting.",
     450              :                                                   handle));
     451              :                 }
     452              :             }
     453           81 :             ++availActuator.handleCount;
     454              : 
     455           81 :             return handle;
     456              :         }
     457         9537 :     }
     458            7 :     return -1;
     459           88 : }
     460              : 
     461            0 : void resetActuator(EnergyPlusState state, int handle)
     462              : {
     463              :     // resets the actuator so that E+ will use the internally calculated value again
     464            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     465            0 :     if (handle >= 1 && handle <= thisState->dataRuntimeLang->numEMSActuatorsAvailable) {
     466            0 :         const auto &theActuator(thisState->dataRuntimeLang->EMSActuatorAvailable(handle));
     467            0 :         *theActuator.Actuated = false;
     468              :     } else {
     469            0 :         if (thisState->dataGlobal->errorCallback) {
     470            0 :             std::cout << "ERROR: Actuator handle out of range in resetActuator, returning but caller should take note and likely abort." << std::endl;
     471              :         } else {
     472              :             // must be running from python plugin, need to fatal out once the plugin is done
     473              :             // throw an error, set the fatal flag, and then return
     474            0 :             ShowSevereError(*thisState, fmt::format("Data Exchange API: index error in resetActuator; received handle: {}", handle));
     475            0 :             ShowContinueError(*thisState, "The resetActuator function will return to allow the plugin to finish, then EnergyPlus will abort");
     476              :         }
     477            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     478              :     }
     479            0 : }
     480              : 
     481       374655 : void setActuatorValue(EnergyPlusState state, const int handle, const Real64 value)
     482              : {
     483       374655 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     484       374655 :     if (handle >= 1 && handle <= thisState->dataRuntimeLang->numEMSActuatorsAvailable) {
     485       374655 :         auto &theActuator(thisState->dataRuntimeLang->EMSActuatorAvailable(handle));
     486       374655 :         if (theActuator.RealValue) {
     487       368895 :             *theActuator.RealValue = value;
     488         5760 :         } else if (theActuator.IntValue) {
     489         5760 :             *theActuator.IntValue = static_cast<int>(std::lround(value));
     490              :         } else {
     491              :             // follow protocol from EMS manager, where 1.0 is true, 0.0 is false, and anything else is also false
     492            0 :             *theActuator.LogValue = value > 0.99999 && value < 1.00001;
     493              :             // allow small tolerance while passing between languages and types
     494              :         }
     495       374655 :         *theActuator.Actuated = true;
     496              :     } else {
     497            0 :         if (thisState->dataGlobal->errorCallback) {
     498            0 :             std::cout << "ERROR: Actuator handle out of range in setActuatorValue, returning but caller should take note and likely abort."
     499            0 :                       << std::endl;
     500              :         } else {
     501              :             // must be running from python plugin, need to fatal out once the plugin is done
     502              :             // throw an error, set the fatal flag, and then return
     503            0 :             ShowSevereError(*thisState, fmt::format("Data Exchange API: index error in setActuatorValue; received handle: {}", handle));
     504            0 :             ShowContinueError(*thisState, "The setActuatorValue function will return to allow the plugin to finish, then EnergyPlus will abort");
     505              :         }
     506            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     507              :     }
     508       374655 : }
     509              : 
     510            0 : Real64 getActuatorValue(EnergyPlusState state, const int handle)
     511              : {
     512            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     513            0 :     if (handle >= 1 && handle <= thisState->dataRuntimeLang->numEMSActuatorsAvailable) {
     514            0 :         const auto &theActuator(thisState->dataRuntimeLang->EMSActuatorAvailable(handle));
     515            0 :         if (theActuator.RealValue) {
     516            0 :             return *theActuator.RealValue;
     517              :         }
     518            0 :         if (theActuator.IntValue) {
     519            0 :             return static_cast<float>(*theActuator.IntValue);
     520              :         }
     521              :         // follow protocol from EMS manager, where 1.0 is true, 0.0 is false, and anything else is also false
     522            0 :         if (*theActuator.LogValue) {
     523            0 :             return 1;
     524              :         }
     525            0 :         return 0;
     526              :     }
     527            0 :     if (thisState->dataGlobal->errorCallback) {
     528            0 :         std::cout << "ERROR: Actuator handle out of range in getActuatorValue, returning zero but caller should take note and likely abort."
     529            0 :                   << std::endl;
     530              :     } else {
     531              :         // must be running from python plugin, need to fatal out once the plugin is done
     532              :         // throw an error, set the fatal flag, and then return 0
     533            0 :         ShowSevereError(*thisState, fmt::format("Data Exchange API: index error in getActuatorValue; received handle: {}", handle));
     534            0 :         ShowContinueError(*thisState,
     535              :                           "The getActuatorValue function will return 0 for now to allow the plugin to finish, then EnergyPlus will abort");
     536              :     }
     537            0 :     thisState->dataPluginManager->apiErrorFlag = true;
     538            0 :     return 0;
     539              : }
     540              : 
     541            9 : int getInternalVariableHandle(EnergyPlusState state, const char *type, const char *key)
     542              : {
     543            9 :     int handle = 0;
     544            9 :     std::string const typeUC = EnergyPlus::Util::makeUPPER(type);
     545            9 :     std::string const keyUC = EnergyPlus::Util::makeUPPER(key);
     546            9 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     547          561 :     for (auto const &availVariable : thisState->dataRuntimeLang->EMSInternalVarsAvailable) {
     548              :         // TODO: this should stop at numEMSInternalVarsAvailable
     549          561 :         handle++;
     550          561 :         std::string const variableTypeUC = EnergyPlus::Util::makeUPPER(availVariable.DataTypeName);
     551          561 :         std::string const variableIDUC = EnergyPlus::Util::makeUPPER(availVariable.UniqueIDName);
     552          561 :         if (typeUC == variableTypeUC && keyUC == variableIDUC) {
     553            9 :             return handle;
     554              :         }
     555          570 :     }
     556            0 :     return -1;
     557            9 : }
     558              : 
     559        36747 : Real64 getInternalVariableValue(EnergyPlusState state, int handle)
     560              : {
     561        36747 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     562        36747 :     if (handle >= 1 && handle <= (int)thisState->dataRuntimeLang->numEMSInternalVarsAvailable) {
     563        36747 :         auto const &thisVar = thisState->dataRuntimeLang->EMSInternalVarsAvailable(handle);
     564        36747 :         if (thisVar.PntrVarTypeUsed == EnergyPlus::DataRuntimeLanguage::PtrDataType::Real) {
     565        36747 :             return *thisVar.RealValue;
     566              :         }
     567            0 :         if (thisVar.PntrVarTypeUsed == EnergyPlus::DataRuntimeLanguage::PtrDataType::Integer) {
     568            0 :             return (Real64)(*thisVar.IntValue);
     569              :         }
     570              :         // Doesn't look like this struct actually has a logical member type, so uh, throw here?
     571            0 :         std::cout << "ERROR: Invalid internal variable type here, developer issue., returning zero but caller should take note and likely abort."
     572            0 :                   << std::endl;
     573            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     574            0 :         return 0;
     575              :     }
     576            0 :     if (thisState->dataGlobal->errorCallback) {
     577              :         std::cout << "ERROR: Internal variable handle out of range in getInternalVariableValue, returning zero but caller should take note and "
     578            0 :                      "likely abort."
     579            0 :                   << std::endl;
     580              :     } else {
     581              :         // must be running from python plugin, need to fatal out once the plugin is done
     582              :         // throw an error, set the fatal flag, and then return 0
     583            0 :         ShowSevereError(*thisState, fmt::format("Data Exchange API: index error in getInternalVariableValue; received handle: {}", handle));
     584            0 :         ShowContinueError(*thisState,
     585              :                           "The getInternalVariableValue function will return 0 for now to allow the plugin to finish, then EnergyPlus will abort");
     586              :     }
     587            0 :     thisState->dataPluginManager->apiErrorFlag = true;
     588            0 :     return 0;
     589              : }
     590              : 
     591            6 : int getEMSGlobalVariableHandle(EnergyPlusState state, const char *name)
     592              : {
     593            6 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     594            6 :     int index = 0;
     595          172 :     for (auto const &erlVar : thisState->dataRuntimeLang->ErlVariable) {
     596          168 :         index++;
     597              :         // only respond if we are outside of the built-in EMS var range
     598          168 :         if (index < thisState->dataRuntimeLang->emsVarBuiltInStart || index > thisState->dataRuntimeLang->emsVarBuiltInEnd) {
     599            6 :             if (EnergyPlus::Util::SameString(name, erlVar.Name)) {
     600            2 :                 return index;
     601              :             }
     602              :         }
     603              :     }
     604            4 :     return 0;
     605              : }
     606              : 
     607            2 : Real64 getEMSGlobalVariableValue(EnergyPlusState state, int handle)
     608              : {
     609            2 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     610            2 :     auto const &erl = thisState->dataRuntimeLang;
     611            2 :     bool const insideBuiltInRange = handle >= erl->emsVarBuiltInStart && handle <= erl->emsVarBuiltInEnd;
     612            2 :     if (insideBuiltInRange || handle > thisState->dataRuntimeLang->NumErlVariables) {
     613              :         // need to fatal out once the process is done
     614              :         // throw an error, set the fatal flag, and then return 0
     615            0 :         EnergyPlus::ShowSevereError(
     616            0 :             *thisState, fmt::format("Data Exchange API: Problem -- index error in getEMSGlobalVariableValue; received handle: {}", handle));
     617            0 :         EnergyPlus::ShowContinueError(
     618              :             *thisState, "The getEMSGlobalVariableValue function will return 0 for now to allow the process to finish, then EnergyPlus will abort");
     619            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     620            0 :         return 0;
     621              :     }
     622            2 :     return erl->ErlVariable(handle).Value.Number;
     623              : }
     624              : 
     625            2 : void setEMSGlobalVariableValue(EnergyPlusState state, int handle, Real64 value)
     626              : {
     627            2 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     628            2 :     auto const &erl = thisState->dataRuntimeLang;
     629            2 :     bool const insideBuiltInRange = handle >= erl->emsVarBuiltInStart && handle <= erl->emsVarBuiltInEnd;
     630            2 :     if (insideBuiltInRange || handle > erl->NumErlVariables) {
     631              :         // need to fatal out once the plugin is done
     632              :         // throw an error, set the fatal flag, and then return
     633            0 :         EnergyPlus::ShowSevereError(
     634            0 :             *thisState, fmt::format("Data Exchange API: Problem -- index error in setEMSGlobalVariableValue; received handle: {}", handle));
     635            0 :         EnergyPlus::ShowContinueError(*thisState,
     636              :                                       "The setEMSGlobalVariableValue function will return to allow the plugin to finish, then EnergyPlus will abort");
     637            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     638              :     }
     639            2 :     erl->ErlVariable(handle).Value.Number = value;
     640            2 : }
     641              : 
     642            0 : int getPluginGlobalVariableHandle(EnergyPlusState state, const char *name)
     643              : {
     644            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     645            0 :     return thisState->dataPluginManager->pluginManager->getGlobalVariableHandle(*thisState, name);
     646              : }
     647              : 
     648            0 : Real64 getPluginGlobalVariableValue(EnergyPlusState state, int handle)
     649              : {
     650            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     651            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxGlobalVariableIndex) {
     652              :         // need to fatal out once the plugin is done
     653              :         // throw an error, set the fatal flag, and then return 0
     654            0 :         ShowSevereError(*thisState,
     655            0 :                         fmt::format("Data Exchange API: Problem -- index error in getPluginGlobalVariableValue; received handle: {}", handle));
     656            0 :         ShowContinueError(
     657              :             *thisState, "The getPluginGlobalVariableValue function will return 0 for now to allow the plugin to finish, then EnergyPlus will abort");
     658            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     659            0 :         return 0;
     660              :     }
     661            0 :     return thisState->dataPluginManager->pluginManager->getGlobalVariableValue(*thisState, handle);
     662              : }
     663              : 
     664            0 : void setPluginGlobalVariableValue(EnergyPlusState state, int handle, Real64 value)
     665              : {
     666            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     667            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxGlobalVariableIndex) {
     668              :         // need to fatal out once the plugin is done
     669              :         // throw an error, set the fatal flag, and then return
     670            0 :         ShowSevereError(*thisState,
     671            0 :                         fmt::format("Data Exchange API: Problem -- index error in setPluginGlobalVariableValue; received handle: {}", handle));
     672            0 :         ShowContinueError(*thisState,
     673              :                           "The getPluginGlobalVariableValue function will return to allow the plugin to finish, then EnergyPlus will abort");
     674            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     675              :     }
     676            0 :     thisState->dataPluginManager->pluginManager->setGlobalVariableValue(*thisState, handle, value);
     677            0 : }
     678              : 
     679            0 : int getPluginTrendVariableHandle(EnergyPlusState state, const char *name)
     680              : {
     681            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     682            0 :     return EnergyPlus::PluginManagement::PluginManager::getTrendVariableHandle(*thisState, name);
     683              : }
     684              : 
     685            0 : Real64 getPluginTrendVariableValue(EnergyPlusState state, int handle, int timeIndex)
     686              : {
     687            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     688            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxTrendVariableIndex) {
     689              :         // need to fatal out once the plugin is done
     690              :         // throw an error, set the fatal flag, and then return
     691            0 :         ShowSevereError(*thisState,
     692            0 :                         fmt::format("Data Exchange API: Problem -- index error in getPluginTrendVariableValue; received handle: {}", handle));
     693            0 :         ShowContinueError(*thisState,
     694              :                           "The getPluginTrendVariableValue function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     695            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     696            0 :         return 0;
     697              :     }
     698            0 :     if (timeIndex < 1 || timeIndex > EnergyPlus::PluginManagement::PluginManager::getTrendVariableHistorySize(*thisState, handle)) {
     699              :         // need to fatal out once the plugin is done
     700              :         // throw an error, set the fatal flag, and then return
     701            0 :         ShowSevereError(
     702              :             *thisState,
     703            0 :             fmt::format("Data Exchange API: Problem -- trend history count argument out of range in getPluginTrendVariableValue; received value: {}",
     704              :                         timeIndex));
     705            0 :         ShowContinueError(*thisState,
     706              :                           "The getPluginTrendVariableValue function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     707            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     708            0 :         return 0;
     709              :     }
     710            0 :     return EnergyPlus::PluginManagement::PluginManager::getTrendVariableValue(*thisState, handle, timeIndex);
     711              : }
     712              : 
     713            0 : Real64 getPluginTrendVariableAverage(EnergyPlusState state, int handle, int count)
     714              : {
     715            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     716            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxTrendVariableIndex) {
     717              :         // need to fatal out once the plugin is done
     718              :         // throw an error, set the fatal flag, and then return
     719            0 :         ShowSevereError(*thisState,
     720            0 :                         fmt::format("Data Exchange API: Problem -- index error in getPluginTrendVariableAverage; received handle: {}", handle));
     721            0 :         ShowContinueError(*thisState,
     722              :                           "The getPluginTrendVariableAverage function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     723            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     724            0 :         return 0;
     725              :     }
     726            0 :     if (count < 2 || count > EnergyPlus::PluginManagement::PluginManager::getTrendVariableHistorySize(*thisState, handle)) {
     727              :         // need to fatal out once the plugin is done
     728              :         // throw an error, set the fatal flag, and then return
     729            0 :         ShowSevereError(
     730              :             *thisState,
     731            0 :             fmt::format(
     732              :                 "Data Exchange API: Problem -- trend history count argument out of range in getPluginTrendVariableAverage; received value: {}",
     733              :                 count));
     734            0 :         ShowContinueError(*thisState,
     735              :                           "The getPluginTrendVariableAverage function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     736            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     737            0 :         return 0;
     738              :     }
     739            0 :     return EnergyPlus::PluginManagement::PluginManager::getTrendVariableAverage(*thisState, handle, count);
     740              : }
     741              : 
     742            0 : Real64 getPluginTrendVariableMin(EnergyPlusState state, int handle, int count)
     743              : {
     744            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     745            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxTrendVariableIndex) {
     746              :         // need to fatal out once the plugin is done
     747              :         // throw an error, set the fatal flag, and then return
     748            0 :         ShowSevereError(*thisState,
     749            0 :                         fmt::format("Data Exchange API: Problem -- index error in getPluginTrendVariableMin; received handle: {}", handle));
     750            0 :         ShowContinueError(*thisState,
     751              :                           "The getPluginTrendVariableMin function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     752            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     753            0 :         return 0;
     754              :     }
     755            0 :     if (count < 2 || count > EnergyPlus::PluginManagement::PluginManager::getTrendVariableHistorySize(*thisState, handle)) {
     756              :         // need to fatal out once the plugin is done
     757              :         // throw an error, set the fatal flag, and then return
     758            0 :         ShowSevereError(
     759              :             *thisState,
     760            0 :             fmt::format("Data Exchange API: Problem -- trend history count argument out of range in getPluginTrendVariableMin; received value: {}",
     761              :                         count));
     762            0 :         ShowContinueError(*thisState,
     763              :                           "The getPluginTrendVariableMin function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     764            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     765            0 :         return 0;
     766              :     }
     767            0 :     return EnergyPlus::PluginManagement::PluginManager::getTrendVariableMin(*thisState, handle, count);
     768              : }
     769              : 
     770            0 : Real64 getPluginTrendVariableMax(EnergyPlusState state, int handle, int count)
     771              : {
     772            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     773            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxTrendVariableIndex) {
     774              :         // need to fatal out once the plugin is done
     775              :         // throw an error, set the fatal flag, and then return
     776            0 :         ShowSevereError(*thisState,
     777            0 :                         fmt::format("Data Exchange API: Problem -- index error in getPluginTrendVariableMax; received handle: {}", handle));
     778            0 :         ShowContinueError(*thisState,
     779              :                           "The getPluginTrendVariableMax function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     780            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     781            0 :         return 0;
     782              :     }
     783            0 :     if (count < 2 || count > EnergyPlus::PluginManagement::PluginManager::getTrendVariableHistorySize(*thisState, handle)) {
     784              :         // need to fatal out once the plugin is done
     785              :         // throw an error, set the fatal flag, and then return
     786            0 :         ShowSevereError(
     787              :             *thisState,
     788            0 :             fmt::format("Data Exchange API: Problem -- trend history count argument out of range in getPluginTrendVariableMax; received value: {}",
     789              :                         count));
     790            0 :         ShowContinueError(*thisState,
     791              :                           "The getPluginTrendVariableMax function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     792            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     793            0 :         return 0;
     794              :     }
     795            0 :     return EnergyPlus::PluginManagement::PluginManager::getTrendVariableMax(*thisState, handle, count);
     796              : }
     797              : 
     798            0 : Real64 getPluginTrendVariableSum(EnergyPlusState state, int handle, int count)
     799              : {
     800            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     801            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxTrendVariableIndex) {
     802              :         // need to fatal out once the plugin is done
     803              :         // throw an error, set the fatal flag, and then return
     804            0 :         ShowSevereError(*thisState,
     805            0 :                         fmt::format("Data Exchange API: Problem -- index error in getPluginTrendVariableSum; received handle: {}", handle));
     806            0 :         ShowContinueError(*thisState,
     807              :                           "The getPluginTrendVariableSum function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     808            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     809            0 :         return 0;
     810              :     }
     811            0 :     if (count < 2 || count > EnergyPlus::PluginManagement::PluginManager::getTrendVariableHistorySize(*thisState, handle)) {
     812              :         // need to fatal out once the plugin is done
     813              :         // throw an error, set the fatal flag, and then return
     814            0 :         ShowSevereError(
     815              :             *thisState,
     816            0 :             fmt::format("Data Exchange API: Problem -- trend history count argument out of range in getPluginTrendVariableSum; received value: {}",
     817              :                         count));
     818            0 :         ShowContinueError(*thisState,
     819              :                           "The getPluginTrendVariableSum function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     820            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     821            0 :         return 0;
     822              :     }
     823            0 :     return EnergyPlus::PluginManagement::PluginManager::getTrendVariableSum(*thisState, handle, count);
     824              : }
     825              : 
     826            0 : Real64 getPluginTrendVariableDirection(EnergyPlusState state, int handle, int count)
     827              : {
     828            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     829            0 :     if (handle < 0 || handle > thisState->dataPluginManager->pluginManager->maxTrendVariableIndex) {
     830              :         // need to fatal out once the plugin is done
     831              :         // throw an error, set the fatal flag, and then return
     832            0 :         ShowSevereError(*thisState,
     833            0 :                         fmt::format("Data Exchange API: Problem -- index error in getPluginTrendVariableDirection; received handle: {}", handle));
     834            0 :         ShowContinueError(*thisState,
     835              :                           "The getPluginTrendVariableDirection function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     836            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     837            0 :         return 0;
     838              :     }
     839            0 :     if (count < 2 || count > EnergyPlus::PluginManagement::PluginManager::getTrendVariableHistorySize(*thisState, handle)) {
     840              :         // need to fatal out once the plugin is done
     841              :         // throw an error, set the fatal flag, and then return
     842            0 :         ShowSevereError(
     843              :             *thisState,
     844            0 :             fmt::format(
     845              :                 "Data Exchange API: Problem -- trend history count argument out of range in getPluginTrendVariableDirection; received value: {}",
     846              :                 count));
     847            0 :         ShowContinueError(*thisState,
     848              :                           "The getPluginTrendVariableDirection function will return 0 to allow the plugin to finish, then EnergyPlus will abort");
     849            0 :         thisState->dataPluginManager->apiErrorFlag = true;
     850            0 :         return 0;
     851              :     }
     852            0 :     return EnergyPlus::PluginManagement::PluginManager::getTrendVariableDirection(*thisState, handle, count);
     853              : }
     854              : 
     855         5760 : int year(EnergyPlusState state)
     856              : {
     857         5760 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     858         5760 :     return thisState->dataEnvrn->Year;
     859              : }
     860              : 
     861         5760 : int calendarYear(EnergyPlusState state)
     862              : {
     863         5760 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     864         5760 :     return thisState->dataGlobal->CalendarYear;
     865              : }
     866              : 
     867            0 : int month(EnergyPlusState state)
     868              : {
     869            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     870            0 :     return thisState->dataEnvrn->Month;
     871              : }
     872              : 
     873            0 : int dayOfMonth(EnergyPlusState state)
     874              : {
     875            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     876            0 :     return thisState->dataEnvrn->DayOfMonth;
     877              : }
     878              : 
     879            0 : int dayOfWeek(EnergyPlusState state)
     880              : {
     881            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     882            0 :     return thisState->dataEnvrn->DayOfWeek;
     883              : }
     884              : 
     885            0 : int dayOfYear(EnergyPlusState state)
     886              : {
     887            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     888            0 :     return thisState->dataEnvrn->DayOfYear;
     889              : }
     890              : 
     891            0 : int daylightSavingsTimeIndicator(EnergyPlusState state)
     892              : {
     893            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     894            0 :     return thisState->dataEnvrn->DSTIndicator;
     895              : }
     896              : 
     897            0 : int hour(EnergyPlusState state)
     898              : {
     899            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     900            0 :     return thisState->dataGlobal->HourOfDay - 1;
     901              :     // no, just stay on 0..23+ DSTadjust ! offset by 1 and daylight savings time
     902              : }
     903              : 
     904         5760 : Real64 currentTime(EnergyPlusState state)
     905              : {
     906         5760 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     907         5760 :     if (thisState->dataHVACGlobal->TimeStepSys < thisState->dataGlobal->TimeStepZone) {
     908              :         // CurrentTime is for end of zone timestep, need to move back to beginning of current zone timestep, then add on system time elapsed already
     909              :         // plus current system timestep
     910         1042 :         return thisState->dataGlobal->CurrentTime - thisState->dataGlobal->TimeStepZone + thisState->dataHVACGlobal->SysTimeElapsed +
     911         1042 :                thisState->dataHVACGlobal->TimeStepSys;
     912              :     }
     913         4718 :     return thisState->dataGlobal->CurrentTime;
     914              : }
     915              : 
     916            0 : int minutes(EnergyPlusState state)
     917              : {
     918              :     // the -1 is to push us to the right minute, but this should be handled cautiously because if we are inside the HVAC iteration loop,
     919              :     // currentTime() returns a floating point fractional hour, so truncation could put this a few seconds from the expected minute.
     920            0 :     const Real64 currentTimeVal = currentTime(state);
     921            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     922            0 :     const Real64 fractionalHoursIntoTheDay = currentTimeVal - static_cast<double>(thisState->dataGlobal->HourOfDay - 1);
     923            0 :     const Real64 fractionalMinutesIntoTheDay = std::round(fractionalHoursIntoTheDay * 60.0);
     924            0 :     return static_cast<int>(fractionalMinutesIntoTheDay);
     925              : }
     926              : 
     927          720 : int numTimeStepsInHour([[maybe_unused]] EnergyPlusState state)
     928              : {
     929          720 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     930          720 :     return thisState->dataGlobal->TimeStepsInHour;
     931              : }
     932              : 
     933         2880 : int zoneTimeStepNum([[maybe_unused]] EnergyPlusState state)
     934              : {
     935         2880 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     936         2880 :     return thisState->dataGlobal->TimeStep;
     937              : }
     938              : 
     939            0 : int holidayIndex(EnergyPlusState state)
     940              : {
     941            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     942            0 :     return thisState->dataEnvrn->HolidayIndex;
     943              : }
     944              : 
     945            0 : int sunIsUp(EnergyPlusState state)
     946              : {
     947              :     // maintain response convention from previous (EMS) implementation
     948            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     949            0 :     return (int)thisState->dataEnvrn->SunIsUp;
     950              : }
     951              : 
     952            0 : int isRaining(EnergyPlusState state)
     953              : {
     954            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     955            0 :     return (int)thisState->dataEnvrn->IsRain;
     956              : }
     957              : 
     958            0 : int warmupFlag(EnergyPlusState state)
     959              : {
     960            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     961            0 :     return (int)thisState->dataGlobal->WarmupFlag;
     962              : }
     963              : 
     964            0 : Real64 zoneTimeStep(EnergyPlusState state)
     965              : {
     966            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     967            0 :     return thisState->dataGlobal->TimeStepZone;
     968              : }
     969              : 
     970         2028 : Real64 systemTimeStep(EnergyPlusState state)
     971              : {
     972         2028 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     973         2028 :     return thisState->dataHVACGlobal->TimeStepSys;
     974              : }
     975              : 
     976            0 : int currentEnvironmentNum(EnergyPlusState state)
     977              : {
     978            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     979            0 :     return thisState->dataEnvrn->CurEnvirNum;
     980              : }
     981              : 
     982            0 : int kindOfSim(EnergyPlusState state)
     983              : {
     984            0 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     985            0 :     return static_cast<int>(thisState->dataGlobal->KindOfSim);
     986              : }
     987              : 
     988            4 : int getConstructionHandle(EnergyPlusState state, const char *constructionName)
     989              : {
     990            4 :     int handle = 0;
     991            4 :     std::string const nameUC = EnergyPlus::Util::makeUPPER(constructionName);
     992            4 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
     993            6 :     for (auto const &construct : thisState->dataConstruction->Construct) {
     994            6 :         handle++;
     995            6 :         if (nameUC == EnergyPlus::Util::makeUPPER(construct.Name)) {
     996            4 :             return handle;
     997              :         }
     998              :     }
     999            0 :     return -1; // return -1 if it wasn't found
    1000            4 : }
    1001              : 
    1002            0 : int actualTime(EnergyPlusState)
    1003              : {
    1004            0 :     const std::string datestring;
    1005            0 :     Array1D_int datevalues(8);
    1006            0 :     ObjexxFCL::date_and_time(datestring, _, _, datevalues);
    1007            0 :     return sum(datevalues({5, 8}));
    1008            0 : }
    1009              : 
    1010            0 : int actualDateTime(EnergyPlusState)
    1011              : {
    1012            0 :     const std::string datestring;
    1013            0 :     const Array1D_int datevalues(8);
    1014            0 :     ObjexxFCL::date_and_time(datestring, _, _, datevalues);
    1015            0 :     return sum(datevalues);
    1016            0 : }
    1017              : 
    1018            0 : int todayWeatherIsRainAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1019              : {
    1020            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1021              : 
    1022            0 :     const int iHour = hour + 1;
    1023            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1024            0 :         return (int)thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).IsRain;
    1025              :     }
    1026            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1027            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1028            0 :     return 0;
    1029              : }
    1030              : 
    1031            0 : int todayWeatherIsSnowAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1032              : {
    1033            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1034              : 
    1035            0 :     const int iHour = hour + 1;
    1036            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1037            0 :         return (int)thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).IsSnow;
    1038              :     }
    1039            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1040            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1041            0 :     return 0;
    1042              : }
    1043              : 
    1044            0 : Real64 todayWeatherOutDryBulbAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1045              : {
    1046            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1047              : 
    1048            0 :     const int iHour = hour + 1;
    1049            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1050            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).OutDryBulbTemp;
    1051              :     }
    1052            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1053            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1054            0 :     return 0.0;
    1055              : }
    1056              : 
    1057            0 : Real64 todayWeatherOutDewPointAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1058              : {
    1059            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1060            0 :     int iHour = hour + 1;
    1061            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1062            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).OutDewPointTemp;
    1063              :     }
    1064            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1065            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1066            0 :     return 0.0;
    1067              : }
    1068              : 
    1069            0 : Real64 todayWeatherOutBarometricPressureAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1070              : {
    1071            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1072            0 :     int iHour = hour + 1;
    1073            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1074            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).OutBaroPress;
    1075              :     }
    1076            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1077            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1078            0 :     return 0.0;
    1079              : }
    1080              : 
    1081            0 : Real64 todayWeatherOutRelativeHumidityAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1082              : {
    1083            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1084            0 :     const int iHour = hour + 1;
    1085            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1086            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).OutRelHum;
    1087              :     }
    1088            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1089            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1090            0 :     return 0.0;
    1091              : }
    1092              : 
    1093            0 : Real64 todayWeatherWindSpeedAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1094              : {
    1095            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1096            0 :     const int iHour = hour + 1;
    1097            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1098            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).WindSpeed;
    1099              :     }
    1100            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1101            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1102            0 :     return 0.0;
    1103              : }
    1104              : 
    1105            0 : Real64 todayWeatherWindDirectionAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1106              : {
    1107            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1108            0 :     const int iHour = hour + 1;
    1109            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1110            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).WindDir;
    1111              :     }
    1112            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1113            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1114            0 :     return 0.0;
    1115              : }
    1116              : 
    1117            0 : Real64 todayWeatherSkyTemperatureAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1118              : {
    1119            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1120            0 :     const int iHour = hour + 1;
    1121            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1122            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).SkyTemp;
    1123              :     }
    1124            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1125            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1126            0 :     return 0.0;
    1127              : }
    1128              : 
    1129            0 : Real64 todayWeatherHorizontalIRSkyAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1130              : {
    1131            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1132            0 :     const int iHour = hour + 1;
    1133            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1134            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).HorizIRSky;
    1135              :     }
    1136            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1137            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1138            0 :     return 0.0;
    1139              : }
    1140              : 
    1141            0 : Real64 todayWeatherBeamSolarRadiationAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1142              : {
    1143            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1144            0 :     const int iHour = hour + 1;
    1145            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1146            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).BeamSolarRad;
    1147              :     }
    1148            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1149            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1150            0 :     return 0.0;
    1151              : }
    1152              : 
    1153            0 : Real64 todayWeatherDiffuseSolarRadiationAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1154              : {
    1155            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1156            0 :     const int iHour = hour + 1;
    1157            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1158            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).DifSolarRad;
    1159              :     }
    1160            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1161            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1162            0 :     return 0.0;
    1163              : }
    1164              : 
    1165            0 : Real64 todayWeatherAlbedoAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1166              : {
    1167            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1168            0 :     const int iHour = hour + 1;
    1169            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1170            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).Albedo;
    1171              :     }
    1172            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1173            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1174            0 :     return 0.0;
    1175              : }
    1176              : 
    1177            0 : Real64 todayWeatherLiquidPrecipitationAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1178              : {
    1179            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1180            0 :     const int iHour = hour + 1;
    1181            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1182            0 :         return thisState->dataWeather->wvarsHrTsToday(timeStepNum, iHour).LiquidPrecip;
    1183              :     }
    1184            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1185            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1186            0 :     return 0.0;
    1187              : }
    1188              : 
    1189            0 : int tomorrowWeatherIsRainAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1190              : {
    1191            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1192            0 :     const int iHour = hour + 1;
    1193            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1194            0 :         return (int)thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).IsRain;
    1195              :     }
    1196            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1197            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1198            0 :     return 0;
    1199              : }
    1200              : 
    1201            0 : int tomorrowWeatherIsSnowAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1202              : {
    1203            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1204            0 :     const int iHour = hour + 1;
    1205            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1206            0 :         return (int)thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).IsSnow;
    1207              :     }
    1208            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1209            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1210            0 :     return 0;
    1211              : }
    1212              : 
    1213          720 : Real64 tomorrowWeatherOutDryBulbAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1214              : {
    1215          720 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1216          720 :     const int iHour = hour + 1;
    1217          720 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1218          720 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).OutDryBulbTemp;
    1219              :     }
    1220            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1221            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1222            0 :     return 0.0;
    1223              : }
    1224              : 
    1225            0 : Real64 tomorrowWeatherOutDewPointAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1226              : {
    1227            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1228            0 :     const int iHour = hour + 1;
    1229            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1230            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).OutDewPointTemp;
    1231              :     }
    1232            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1233            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1234            0 :     return 0.0;
    1235              : }
    1236              : 
    1237            0 : Real64 tomorrowWeatherOutBarometricPressureAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1238              : {
    1239            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1240            0 :     const int iHour = hour + 1;
    1241            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1242            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).OutBaroPress;
    1243              :     }
    1244            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1245            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1246            0 :     return 0.0;
    1247              : }
    1248              : 
    1249            0 : Real64 tomorrowWeatherOutRelativeHumidityAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1250              : {
    1251            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1252            0 :     const int iHour = hour + 1;
    1253            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1254            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).OutRelHum;
    1255              :     }
    1256            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1257            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1258            0 :     return 0.0;
    1259              : }
    1260              : 
    1261            0 : Real64 tomorrowWeatherWindSpeedAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1262              : {
    1263            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1264            0 :     const int iHour = hour + 1;
    1265            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1266            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).WindSpeed;
    1267              :     }
    1268            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1269            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1270            0 :     return 0.0;
    1271              : }
    1272              : 
    1273            0 : Real64 tomorrowWeatherWindDirectionAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1274              : {
    1275            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1276            0 :     const int iHour = hour + 1;
    1277            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1278            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).WindDir;
    1279              :     }
    1280            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1281            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1282            0 :     return 0.0;
    1283              : }
    1284              : 
    1285            0 : Real64 tomorrowWeatherSkyTemperatureAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1286              : {
    1287            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1288            0 :     const int iHour = hour + 1;
    1289            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1290            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).SkyTemp;
    1291              :     }
    1292            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1293            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1294            0 :     return 0.0;
    1295              : }
    1296              : 
    1297            0 : Real64 tomorrowWeatherHorizontalIRSkyAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1298              : {
    1299            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1300            0 :     const int iHour = hour + 1;
    1301            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1302            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).HorizIRSky;
    1303              :     }
    1304            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1305            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1306            0 :     return 0.0;
    1307              : }
    1308              : 
    1309            0 : Real64 tomorrowWeatherBeamSolarRadiationAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1310              : {
    1311            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1312            0 :     const int iHour = hour + 1;
    1313            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1314            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).BeamSolarRad;
    1315              :     }
    1316            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1317            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1318            0 :     return 0.0;
    1319              : }
    1320              : 
    1321            0 : Real64 tomorrowWeatherDiffuseSolarRadiationAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1322              : {
    1323            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1324            0 :     const int iHour = hour + 1;
    1325            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1326            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).DifSolarRad;
    1327              :     }
    1328            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1329            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1330            0 :     return 0.0;
    1331              : }
    1332              : 
    1333            0 : Real64 tomorrowWeatherAlbedoAtTime(EnergyPlusState state, int hour, int timeStepNum)
    1334              : {
    1335            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1336            0 :     const int iHour = hour + 1;
    1337            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1338            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).Albedo;
    1339              :     }
    1340            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1341            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1342            0 :     return 0.0;
    1343              : }
    1344              : 
    1345            0 : Real64 tomorrowWeatherLiquidPrecipitationAtTime(EnergyPlusState state, const int hour, const int timeStepNum)
    1346              : {
    1347            0 :     auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1348            0 :     const int iHour = hour + 1;
    1349            0 :     if ((iHour > 0) && (iHour <= EnergyPlus::Constant::iHoursInDay) && (timeStepNum > 0) && (timeStepNum <= thisState->dataGlobal->TimeStepsInHour)) {
    1350            0 :         return thisState->dataWeather->wvarsHrTsTomorrow(timeStepNum, iHour).LiquidPrecip;
    1351              :     }
    1352            0 :     ShowSevereError(*thisState, "Invalid return from weather lookup, check hour and time step argument values are in range.");
    1353            0 :     thisState->dataPluginManager->apiErrorFlag = true;
    1354            0 :     return 0.0;
    1355              : }
    1356              : 
    1357         5760 : Real64 currentSimTime(EnergyPlusState state)
    1358              : {
    1359         5760 :     const auto *thisState = static_cast<EnergyPlus::EnergyPlusData *>(state);
    1360         5760 :     return (thisState->dataGlobal->DayOfSim - 1) * EnergyPlus::Constant::iHoursInDay + currentTime(state);
    1361              : }
        

Generated by: LCOV version 2.0-1