LCOV - code coverage report
Current view: top level - EnergyPlus - PluginManager.hh (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 7 23 30.4 %
Date: 2024-08-24 18:31:18 Functions: 2 3 66.7 %

          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             : #ifndef EPLUS_PLUGIN_MANAGER_HH
      49             : #define EPLUS_PLUGIN_MANAGER_HH
      50             : 
      51             : // C++ Headers
      52             : #include <iomanip>
      53             : #include <queue>
      54             : #include <utility>
      55             : #include <vector>
      56             : 
      57             : // EnergyPlus Headers
      58             : #include <EnergyPlus/DataGlobals.hh>
      59             : #include <EnergyPlus/EMSManager.hh>
      60             : #include <EnergyPlus/EnergyPlus.hh>
      61             : 
      62             : #if LINK_WITH_PYTHON
      63             : #ifdef _DEBUG
      64             : // We don't want to try to import a debug build of Python here
      65             : // so if we are building a Debug build of the C++ code, we need
      66             : // to undefine _DEBUG during the #include command for Python.h.
      67             : // Otherwise it will fail
      68             : #undef _DEBUG
      69             : #include <Python.h>
      70             : #define _DEBUG
      71             : #else
      72             : #include <Python.h>
      73             : #endif
      74             : #endif
      75             : 
      76             : namespace EnergyPlus {
      77             : 
      78             : // Forward declarations
      79             : struct EnergyPlusData;
      80             : 
      81             : namespace PluginManagement {
      82             : 
      83             :     constexpr const char *programName = "python";
      84             : 
      85             :     void registerNewCallback(const EnergyPlusData &state, EMSManager::EMSCallFrom iCalledFrom, const std::function<void(void *)> &f);
      86             :     void registerUserDefinedCallback(const EnergyPlusData &state, const std::function<void(void *)> &f, const std::string &programNameInInputFile);
      87             : 
      88             :     void runAnyRegisteredCallbacks(EnergyPlusData &state, EMSManager::EMSCallFrom iCalledFrom, bool &anyRan);
      89             :     void onBeginEnvironment(const EnergyPlusData &state);
      90             :     std::string pythonStringForUsage(const EnergyPlusData &state);
      91             : 
      92             :     void clear_state();
      93             : 
      94             :     struct PluginInstance
      95             :     {
      96             :         PluginInstance(const fs::path &_modulePath, const std::string &_className, std::string emsName, bool runPluginDuringWarmup);
      97             : 
      98             :         // members
      99             :         fs::path modulePath;
     100             :         std::string className;
     101             :         std::string emsAlias;
     102             :         bool runDuringWarmup;
     103             :         std::string stringIdentifier; // for diagnostic reporting
     104             : 
     105             :         // setup/shutdown should only be called once construction is completely done, i.e., setup() should only be called once the vector holding all
     106             :         // the instances is done for the day, and shutdown should only be called when you are ready to destruct all the instances.  The things that
     107             :         // happen inside setup() and shutdown() are related to un-managed memory, and it's tricky to manage inside existing constructor/move
     108             :         // operations, so they are split out into these explicitly called methods.
     109             :         void setup(EnergyPlusData &state);
     110             :         void shutdown() const;
     111             : 
     112             :         // methods
     113             :         static void reportPythonError(EnergyPlusData &state);
     114             :         bool run(EnergyPlusData &state, EMSManager::EMSCallFrom iCallingPoint) const; // calls main() on this plugin instance
     115             : 
     116             :         // plugin calling point hooks
     117             :         const char *sHookBeginNewEnvironment = "on_begin_new_environment";
     118             :         const char *sHookBeginZoneTimestepBeforeSetCurrentWeather = "on_begin_zone_timestep_before_set_current_weather";
     119             :         const char *sHookAfterNewEnvironmentWarmUpIsComplete = "on_after_new_environment_warmup_is_complete";
     120             :         const char *sHookBeginZoneTimestepBeforeInitHeatBalance = "on_begin_zone_timestep_before_init_heat_balance";
     121             :         const char *sHookBeginZoneTimestepAfterInitHeatBalance = "on_begin_zone_timestep_after_init_heat_balance";
     122             :         const char *sHookBeginTimestepBeforePredictor = "on_begin_timestep_before_predictor";
     123             :         const char *sHookAfterPredictorBeforeHVACManagers = "on_after_predictor_before_hvac_managers";
     124             :         const char *sHookAfterPredictorAfterHVACManagers = "on_after_predictor_after_hvac_managers";
     125             :         const char *sHookInsideHVACSystemIterationLoop = "on_inside_hvac_system_iteration_loop";
     126             :         const char *sHookEndOfZoneTimestepBeforeZoneReporting = "on_end_of_zone_timestep_before_zone_reporting";
     127             :         const char *sHookEndOfZoneTimestepAfterZoneReporting = "on_end_of_zone_timestep_after_zone_reporting";
     128             :         const char *sHookEndOfSystemTimestepBeforeHVACReporting = "on_end_of_system_timestep_before_hvac_reporting";
     129             :         const char *sHookEndOfSystemTimestepAfterHVACReporting = "on_end_of_system_timestep_after_hvac_reporting";
     130             :         const char *sHookEndOfZoneSizing = "on_end_of_zone_sizing";
     131             :         const char *sHookEndOfSystemSizing = "on_end_of_system_sizing";
     132             :         const char *sHookAfterComponentInputReadIn = "on_end_of_component_input_read_in";
     133             :         const char *sHookUserDefinedComponentModel = "on_user_defined_component_model";
     134             :         const char *sHookUnitarySystemSizing = "on_unitary_system_sizing";
     135             :         bool bHasBeginNewEnvironment = false;
     136             :         bool bHasBeginZoneTimestepBeforeSetCurrentWeather = false;
     137             :         bool bHasAfterNewEnvironmentWarmUpIsComplete = false;
     138             :         bool bHasBeginZoneTimestepBeforeInitHeatBalance = false;
     139             :         bool bHasBeginZoneTimestepAfterInitHeatBalance = false;
     140             :         bool bHasBeginTimestepBeforePredictor = false;
     141             :         bool bHasAfterPredictorBeforeHVACManagers = false;
     142             :         bool bHasAfterPredictorAfterHVACManagers = false;
     143             :         bool bHasInsideHVACSystemIterationLoop = false;
     144             :         bool bHasEndOfZoneTimestepBeforeZoneReporting = false;
     145             :         bool bHasEndOfZoneTimestepAfterZoneReporting = false;
     146             :         bool bHasEndOfSystemTimestepBeforeHVACReporting = false;
     147             :         bool bHasEndOfSystemTimestepAfterHVACReporting = false;
     148             :         bool bHasEndOfZoneSizing = false;
     149             :         bool bHasEndOfSystemSizing = false;
     150             :         bool bHasAfterComponentInputReadIn = false;
     151             :         bool bHasUserDefinedComponentModel = false;
     152             :         bool bHasUnitarySystemSizing = false;
     153             : #if LINK_WITH_PYTHON
     154             :         PyObject *pModule = nullptr;        // reference to module
     155             :         PyObject *pClassInstance = nullptr; // reference to instantiated class -- *don't decref until the end of the simulation*
     156             :         // precalculated function names as PyObjects
     157             :         PyObject *pBeginNewEnvironment = nullptr;
     158             :         PyObject *pBeginZoneTimestepBeforeSetCurrentWeather = nullptr;
     159             :         PyObject *pAfterNewEnvironmentWarmUpIsComplete = nullptr;
     160             :         PyObject *pBeginZoneTimestepBeforeInitHeatBalance = nullptr;
     161             :         PyObject *pBeginZoneTimestepAfterInitHeatBalance = nullptr;
     162             :         PyObject *pBeginTimestepBeforePredictor = nullptr;
     163             :         PyObject *pAfterPredictorBeforeHVACManagers = nullptr;
     164             :         PyObject *pAfterPredictorAfterHVACManagers = nullptr;
     165             :         PyObject *pInsideHVACSystemIterationLoop = nullptr;
     166             :         PyObject *pEndOfZoneTimestepBeforeZoneReporting = nullptr;
     167             :         PyObject *pEndOfZoneTimestepAfterZoneReporting = nullptr;
     168             :         PyObject *pEndOfSystemTimestepBeforeHVACReporting = nullptr;
     169             :         PyObject *pEndOfSystemTimestepAfterHVACReporting = nullptr;
     170             :         PyObject *pEndOfZoneSizing = nullptr;
     171             :         PyObject *pEndOfSystemSizing = nullptr;
     172             :         PyObject *pAfterComponentInputReadIn = nullptr;
     173             :         PyObject *pUserDefinedComponentModel = nullptr;
     174             :         PyObject *pUnitarySystemSizing = nullptr;
     175             : #endif
     176             :     };
     177             : 
     178             :     class PluginManager
     179             :     {
     180             :     public:
     181             :         explicit PluginManager(EnergyPlusData &state);
     182             :         ~PluginManager();
     183             : 
     184             :         static int numActiveCallbacks(const EnergyPlusData &state);
     185             :         static void addToPythonPath(EnergyPlusData &state, const fs::path &includePath, bool userDefinedPath);
     186             :         static void setupOutputVariables(EnergyPlusData &state);
     187             : 
     188             :         int maxGlobalVariableIndex = -1;
     189             :         void addGlobalVariable(const EnergyPlusData &state, const std::string &name);
     190             :         static int getGlobalVariableHandle(EnergyPlusData &state, const std::string &name, bool suppress_warning = false);
     191             :         static Real64 getGlobalVariableValue(EnergyPlusData &state, int handle);
     192             :         static void setGlobalVariableValue(EnergyPlusData &state, int handle, Real64 value);
     193             : 
     194             :         int maxTrendVariableIndex = -1;
     195             :         static int getTrendVariableHandle(const EnergyPlusData &state, const std::string &name);
     196             :         static Real64 getTrendVariableValue(const EnergyPlusData &state, int handle, int timeIndex);
     197             :         static size_t getTrendVariableHistorySize(const EnergyPlusData &state, int handle);
     198             :         static Real64 getTrendVariableAverage(const EnergyPlusData &state, int handle, int count);
     199             :         static Real64 getTrendVariableMin(const EnergyPlusData &state, int handle, int count);
     200             :         static Real64 getTrendVariableMax(const EnergyPlusData &state, int handle, int count);
     201             :         static Real64 getTrendVariableSum(const EnergyPlusData &state, int handle, int count);
     202             :         static Real64 getTrendVariableDirection(const EnergyPlusData &state, int handle, int count);
     203             : 
     204             :         static void updatePluginValues(EnergyPlusData &state);
     205             : 
     206             :         static int getLocationOfUserDefinedPlugin(const EnergyPlusData &state, std::string const &_programName);
     207             :         static int getUserDefinedCallbackIndex(const EnergyPlusData &state, const std::string &callbackProgramName);
     208             :         static void runSingleUserDefinedPlugin(EnergyPlusData &state, int index);
     209             :         static void runSingleUserDefinedCallback(EnergyPlusData &state, int index);
     210             :         static bool anyUnexpectedPluginObjects(EnergyPlusData &state);
     211             : 
     212             :         bool eplusRunningViaPythonAPI = false;
     213             : 
     214             :         // For debugging purposes / issuing better error messages
     215             :         static std::vector<std::string> currentPythonPath();
     216             :     };
     217             : 
     218             :     struct PluginTrendVariable
     219             :     {
     220             :         std::string name;
     221             :         int numValues;
     222             :         std::deque<Real64> values;
     223             :         std::deque<Real64> times;
     224             :         int indexOfPluginVariable;
     225             :         PluginTrendVariable(const EnergyPlusData &state, std::string _name, int _numValues, int _indexOfPluginVariable);
     226           6 :         void reset()
     227             :         {
     228           6 :             this->values.clear();
     229        2406 :             for (int i = 1; i <= this->numValues; i++) {
     230        2400 :                 this->values.push_back(0);
     231             :             }
     232           6 :         }
     233             :     };
     234             : 
     235             : } // namespace PluginManagement
     236             : 
     237             : struct PluginManagerData : BaseGlobalStruct
     238             : {
     239             :     std::map<EMSManager::EMSCallFrom, std::vector<std::function<void(void *)>>> callbacks;
     240             :     std::vector<std::string> userDefinedCallbackNames;
     241             :     std::vector<std::function<void(void *)>> userDefinedCallbacks;
     242             :     std::unique_ptr<PluginManagement::PluginManager> pluginManager;
     243             :     std::vector<PluginManagement::PluginTrendVariable> trends;
     244             :     std::vector<PluginManagement::PluginInstance> plugins;
     245             : 
     246             :     std::vector<std::string> globalVariableNames;
     247             :     std::vector<Real64> globalVariableValues;
     248             :     bool fullyReady = false;
     249             :     bool apiErrorFlag = false;
     250             :     std::vector<std::string> const objectsToFind = {
     251             :         "PythonPlugin:OutputVariable", "PythonPlugin:SearchPaths", "PythonPlugin:Instance", "PythonPlugin:Variables", "PythonPlugin:TrendVariable"};
     252             : 
     253             :     bool eplusRunningViaPythonAPI = false;
     254             : 
     255         796 :     void init_state([[maybe_unused]] EnergyPlusData &state) override
     256             :     {
     257         796 :     }
     258             : 
     259           0 :     void clear_state() override
     260             :     {
     261           0 :         callbacks.clear();
     262           0 :         userDefinedCallbackNames.clear();
     263           0 :         userDefinedCallbacks.clear();
     264             : #if LINK_WITH_PYTHON
     265           0 :         for (auto &plugin : plugins) {
     266           0 :             plugin.shutdown(); // clear unmanaged memory first
     267           0 :         }
     268           0 :         trends.clear();
     269           0 :         globalVariableNames.clear();
     270           0 :         globalVariableValues.clear();
     271           0 :         plugins.clear();
     272           0 :         fullyReady = false;
     273           0 :         apiErrorFlag = false;
     274           0 :         auto *p = pluginManager.release();
     275           0 :         delete p;
     276             : #endif
     277           0 :     }
     278             : };
     279             : 
     280             : } // namespace EnergyPlus
     281             : 
     282             : #endif // EPLUS_PLUGIN_MANAGER_HH

Generated by: LCOV version 1.14