LCOV - code coverage report
Current view: top level - EnergyPlus/api - datatransfer.cc (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 168 831 20.2 %
Date: 2024-08-23 23:50:59 Functions: 28 88 31.8 %

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

Generated by: LCOV version 1.14