LCOV - code coverage report
Current view: top level - EnergyPlus - PluginManager.hh (source / functions) Hit Total Coverage
Test: lcov.output.filtered Lines: 12 25 48.0 %
Date: 2023-01-17 19:17:23 Functions: 9 10 90.0 %

          Line data    Source code
       1             : // EnergyPlus, Copyright (c) 1996-2023, 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(EnergyPlusData &state, EMSManager::EMSCallFrom iCalledFrom, const std::function<void(void *)> &f);
      86             :     void runAnyRegisteredCallbacks(EnergyPlusData &state, EMSManager::EMSCallFrom iCalledFrom, bool &anyRan);
      87             :     void onBeginEnvironment(EnergyPlusData &state);
      88             :     std::string pythonStringForUsage(EnergyPlusData &state);
      89             : 
      90             :     void clear_state();
      91             : 
      92         146 :     struct PluginInstance
      93             :     {
      94          44 :         PluginInstance(const fs::path &_modulePath, const std::string &_className, std::string emsName, bool runPluginDuringWarmup)
      95          88 :             : modulePath(_modulePath), className(_className), emsAlias(std::move(emsName)), runDuringWarmup(runPluginDuringWarmup),
      96          88 :               stringIdentifier(_modulePath.string() + "." + _className)
      97             :         {
      98          44 :         }
      99             : 
     100             :         // members
     101             :         fs::path modulePath;
     102             :         std::string className;
     103             :         std::string emsAlias;
     104             :         bool runDuringWarmup;
     105             :         std::string stringIdentifier; // for diagnostic reporting
     106             : 
     107             :         // setup/shutdown should only be called once construction is completely done, i.e., setup() should only be called once the vector holding all
     108             :         // 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
     109             :         // happen inside setup() and shutdown() are related to un-managed memory, and it's tricky to manage inside existing constructor/move
     110             :         // operations, so they are split out into these explicitly called methods.
     111             :         void setup(EnergyPlusData &state);
     112             :         void shutdown() const;
     113             : 
     114             :         // methods
     115             :         static void reportPythonError(EnergyPlusData &state);
     116             :         bool run(EnergyPlusData &state, EMSManager::EMSCallFrom iCallingPoint) const; // calls main() on this plugin instance
     117             : 
     118             :         // plugin calling point hooks
     119             :         const char *sHookBeginNewEnvironment = "on_begin_new_environment";
     120             :         const char *sHookBeginZoneTimestepBeforeSetCurrentWeather = "on_begin_zone_timestep_before_set_current_weather";
     121             :         const char *sHookAfterNewEnvironmentWarmUpIsComplete = "on_after_new_environment_warmup_is_complete";
     122             :         const char *sHookBeginZoneTimestepBeforeInitHeatBalance = "on_begin_zone_timestep_before_init_heat_balance";
     123             :         const char *sHookBeginZoneTimestepAfterInitHeatBalance = "on_begin_zone_timestep_after_init_heat_balance";
     124             :         const char *sHookBeginTimestepBeforePredictor = "on_begin_timestep_before_predictor";
     125             :         const char *sHookAfterPredictorBeforeHVACManagers = "on_after_predictor_before_hvac_managers";
     126             :         const char *sHookAfterPredictorAfterHVACManagers = "on_after_predictor_after_hvac_managers";
     127             :         const char *sHookInsideHVACSystemIterationLoop = "on_inside_hvac_system_iteration_loop";
     128             :         const char *sHookEndOfZoneTimestepBeforeZoneReporting = "on_end_of_zone_timestep_before_zone_reporting";
     129             :         const char *sHookEndOfZoneTimestepAfterZoneReporting = "on_end_of_zone_timestep_after_zone_reporting";
     130             :         const char *sHookEndOfSystemTimestepBeforeHVACReporting = "on_end_of_system_timestep_before_hvac_reporting";
     131             :         const char *sHookEndOfSystemTimestepAfterHVACReporting = "on_end_of_system_timestep_after_hvac_reporting";
     132             :         const char *sHookEndOfZoneSizing = "on_end_of_zone_sizing";
     133             :         const char *sHookEndOfSystemSizing = "on_end_of_system_sizing";
     134             :         const char *sHookAfterComponentInputReadIn = "on_end_of_component_input_read_in";
     135             :         const char *sHookUserDefinedComponentModel = "on_user_defined_component_model";
     136             :         const char *sHookUnitarySystemSizing = "on_unitary_system_sizing";
     137             :         bool bHasBeginNewEnvironment = false;
     138             :         bool bHasBeginZoneTimestepBeforeSetCurrentWeather = false;
     139             :         bool bHasAfterNewEnvironmentWarmUpIsComplete = false;
     140             :         bool bHasBeginZoneTimestepBeforeInitHeatBalance = false;
     141             :         bool bHasBeginZoneTimestepAfterInitHeatBalance = false;
     142             :         bool bHasBeginTimestepBeforePredictor = false;
     143             :         bool bHasAfterPredictorBeforeHVACManagers = false;
     144             :         bool bHasAfterPredictorAfterHVACManagers = false;
     145             :         bool bHasInsideHVACSystemIterationLoop = false;
     146             :         bool bHasEndOfZoneTimestepBeforeZoneReporting = false;
     147             :         bool bHasEndOfZoneTimestepAfterZoneReporting = false;
     148             :         bool bHasEndOfSystemTimestepBeforeHVACReporting = false;
     149             :         bool bHasEndOfSystemTimestepAfterHVACReporting = false;
     150             :         bool bHasEndOfZoneSizing = false;
     151             :         bool bHasEndOfSystemSizing = false;
     152             :         bool bHasAfterComponentInputReadIn = false;
     153             :         bool bHasUserDefinedComponentModel = false;
     154             :         bool bHasUnitarySystemSizing = false;
     155             : #if LINK_WITH_PYTHON
     156             :         PyObject *pModule = nullptr;        // reference to module
     157             :         PyObject *pClassInstance = nullptr; // reference to instantiated class -- *don't decref until the end of the simulation*
     158             :         // precalculated function names as PyObjects
     159             :         PyObject *pBeginNewEnvironment = nullptr;
     160             :         PyObject *pBeginZoneTimestepBeforeSetCurrentWeather = nullptr;
     161             :         PyObject *pAfterNewEnvironmentWarmUpIsComplete = nullptr;
     162             :         PyObject *pBeginZoneTimestepBeforeInitHeatBalance = nullptr;
     163             :         PyObject *pBeginZoneTimestepAfterInitHeatBalance = nullptr;
     164             :         PyObject *pBeginTimestepBeforePredictor = nullptr;
     165             :         PyObject *pAfterPredictorBeforeHVACManagers = nullptr;
     166             :         PyObject *pAfterPredictorAfterHVACManagers = nullptr;
     167             :         PyObject *pInsideHVACSystemIterationLoop = nullptr;
     168             :         PyObject *pEndOfZoneTimestepBeforeZoneReporting = nullptr;
     169             :         PyObject *pEndOfZoneTimestepAfterZoneReporting = nullptr;
     170             :         PyObject *pEndOfSystemTimestepBeforeHVACReporting = nullptr;
     171             :         PyObject *pEndOfSystemTimestepAfterHVACReporting = nullptr;
     172             :         PyObject *pEndOfZoneSizing = nullptr;
     173             :         PyObject *pEndOfSystemSizing = nullptr;
     174             :         PyObject *pAfterComponentInputReadIn = nullptr;
     175             :         PyObject *pUserDefinedComponentModel = nullptr;
     176             :         PyObject *pUnitarySystemSizing = nullptr;
     177             : #endif
     178             :     };
     179             : 
     180             :     class PluginManager
     181             :     {
     182             :     public:
     183             :         explicit PluginManager(EnergyPlusData &state);
     184             :         ~PluginManager();
     185             : 
     186             :         static int numActiveCallbacks(EnergyPlusData &state);
     187             :         static void addToPythonPath(EnergyPlusData &state, const fs::path &path, bool userDefinedPath);
     188             :         static fs::path sanitizedPath(fs::path const &path);
     189             :         static void setupOutputVariables(EnergyPlusData &state);
     190             : 
     191             :         int maxGlobalVariableIndex = -1;
     192             :         void addGlobalVariable(EnergyPlusData &state, const std::string &name);
     193             :         static int getGlobalVariableHandle(EnergyPlusData &state, const std::string &name, bool suppress_warning = false);
     194             :         static Real64 getGlobalVariableValue(EnergyPlusData &state, int handle);
     195             :         static void setGlobalVariableValue(EnergyPlusData &state, int handle, Real64 value);
     196             : 
     197             :         int maxTrendVariableIndex = -1;
     198             :         static int getTrendVariableHandle(EnergyPlusData &state, const std::string &name);
     199             :         static Real64 getTrendVariableValue(EnergyPlusData &state, int handle, int timeIndex);
     200             :         static size_t getTrendVariableHistorySize(EnergyPlusData &state, int handle);
     201             :         static Real64 getTrendVariableAverage(EnergyPlusData &state, int handle, int count);
     202             :         static Real64 getTrendVariableMin(EnergyPlusData &state, int handle, int count);
     203             :         static Real64 getTrendVariableMax(EnergyPlusData &state, int handle, int count);
     204             :         static Real64 getTrendVariableSum(EnergyPlusData &state, int handle, int count);
     205             :         static Real64 getTrendVariableDirection(EnergyPlusData &state, int handle, int count);
     206             : 
     207             :         static void updatePluginValues(EnergyPlusData &state);
     208             : 
     209             :         static int getLocationOfUserDefinedPlugin(EnergyPlusData &state, std::string const &_programName);
     210             :         static void runSingleUserDefinedPlugin(EnergyPlusData &state, int index);
     211             :         static bool anyUnexpectedPluginObjects(EnergyPlusData &state);
     212             : 
     213             :         bool eplusRunningViaPythonAPI = false;
     214             :     };
     215             : 
     216           6 :     struct PluginTrendVariable
     217             :     {
     218             :         std::string name;
     219             :         int numValues;
     220             :         std::deque<Real64> values;
     221             :         std::deque<Real64> times;
     222             :         int indexOfPluginVariable;
     223             :         PluginTrendVariable(EnergyPlusData &state, std::string _name, int _numValues, int _indexOfPluginVariable);
     224           6 :         void reset()
     225             :         {
     226           6 :             this->values.clear();
     227        2406 :             for (int i = 1; i <= this->numValues; i++) {
     228        2400 :                 this->values.push_back(0);
     229             :             }
     230           6 :         }
     231             :     };
     232             : 
     233             : } // namespace PluginManagement
     234             : 
     235        1542 : struct PluginManagerData : BaseGlobalStruct
     236             : {
     237             :     std::map<EMSManager::EMSCallFrom, std::vector<std::function<void(void *)>>> callbacks;
     238             :     std::unique_ptr<PluginManagement::PluginManager> pluginManager;
     239             :     std::vector<PluginManagement::PluginTrendVariable> trends;
     240             :     std::vector<PluginManagement::PluginInstance> plugins;
     241             : 
     242             :     std::vector<std::string> globalVariableNames;
     243             :     std::vector<Real64> globalVariableValues;
     244             :     bool fullyReady = false;
     245             :     bool apiErrorFlag = false;
     246             :     std::vector<std::string> const objectsToFind = {
     247             :         "PythonPlugin:OutputVariable", "PythonPlugin:SearchPaths", "PythonPlugin:Instance", "PythonPlugin:Variables", "PythonPlugin:TrendVariable"};
     248             : 
     249             :     bool eplusRunningViaPythonAPI = false;
     250             : 
     251           0 :     void clear_state() override
     252             :     {
     253           0 :         callbacks.clear();
     254             : #if LINK_WITH_PYTHON
     255           0 :         for (auto &plugin : plugins) {
     256           0 :             plugin.shutdown(); // clear unmanaged memory first
     257             :         }
     258           0 :         trends.clear();
     259           0 :         globalVariableNames.clear();
     260           0 :         globalVariableValues.clear();
     261           0 :         plugins.clear();
     262           0 :         fullyReady = false;
     263           0 :         apiErrorFlag = false;
     264           0 :         auto *p = pluginManager.release();
     265           0 :         delete p;
     266             : #endif
     267           0 :     }
     268             : };
     269             : 
     270             : } // namespace EnergyPlus
     271             : 
     272             : #endif // EPLUS_PLUGIN_MANAGER_HH

Generated by: LCOV version 1.13