EnergyPlus is the Department of Energy’s (DOE’s) open-source, state-of-the-art building energy modeling (BEM) engine, supporting energy-efficiency code development, commercial products, and research. EnergyPlus has a broad suite of modeling capabilities. However, one of its most interesting features is EMS (Energy Management System), an integrated scripting facility that allows power users to implement custom functionality directly in EnergyPlus.

EMS exposes a significant set of EnergyPlus internal variables (e.g., date and time, sensor values, HVAC component and system settings, etc.) and allows users to write programs that manipulate these values. EnergyPlus then invokes these programs at pre-determined times (e.g., at the beginning of the zone time step, at the end of the HVAC time step, at the start of each HVAC iteration, etc.). Although initially intended to implement custom control strategies that complement EnergyPlus’ library of built-in strategies, EMS has found a range of uses—from simple tasks, such as overriding convection coefficients and altering component availability—to complete physics-based HVAC component and system models and, more recently, to demand response (DR) and equipment fault modeling.

To date, EMS users have had to write these programs using a minimalist language called ERL (EnergyPlus Runtime Language). On the spectrum of programming languages, ERL is analogous to circa 1980 BASIC or AWK. It has scalar variables, but no data structures like arrays or objects. It has loops, but they cannot be nested. It provides access to some internal EnergyPlus functions, but it does not support user-defined functions. It does not have general-purpose input/output facilities or libraries. These shortcomings exist because EnergyPlus is a BEM engine, not a programming language interpreter.

In March 2020, EnergyPlus 9.3.0 fast-forwarded the EMS feature about 40 years. Specifically, EnergyPlus added an embedded Python interpreter and wrapped its EMS endpoints (e.g., sensors, actuators, meters) in a Python API, allowing users to write EMS programs in one of the world’s most popular scripting languages. Python has all the features of modern programming language and a trove of libraries for all kinds of domains from scientific calculations to machine learning (ML) to interact with web application programming interfaces (APIs) and even sense and control hardware. It will allow Python users to not only simplify the implementation of EMS’ existing use cases but enable new ones as well. Python will also allow users to organize EMS scripts into portable “packages” that can be published and used by others. “It is exciting to think about how users will take advantage of this new feature,” says Dr. Edwin Lee, NREL’s EnergyPlus project lead and primary developer of this feature.

An example

One traditional application of EMS is to take component heating and cooling capacity values calculated by EnergyPlus and bumping them to the next highest nominal value that corresponds to real equipment. For example, rounding up an evaporator capacity to the next highest tonnage in order to provide more realistic part load performance.  This application is demonstrated in example files that are packaged with EnergyPlus. The figure below shows the python implementation (in file PythonPluginDiscreteAirSystemSizes.py) and the EnergyPlus object that links to it (in file PythonPluginDiscreteAirSystemSizes.idf).  

This python script upsizes equipment airflow capacities to match actually available equipment. EnergyPlus calls this script after calculating airflow capacities based on maximum heating, cooling, and ventilation loads.
This python script upsizes equipment airflow capacities to match actually available equipment. EnergyPlus calls this script after calculating airflow capacities based on maximum heating, cooling, and ventilation loads.
BTO

The python implementation consists of a helper function select_discrete_nominal_airflow which takes a calculated airflow value and maps it to the next highest value from a list. A second function on_end_of_system_sizing (which is unsurprisingly called at the end of the sizing calculations) loops over all zones, reads the calculated airflow rates, uses the helper function to map those to discrete higher values, and overrides them.  

Contrast the python implementation to just a portion of the traditional EMS implementation in the figure below (found in the file EMSDiscreteAirSystemSizes.idf). This figure shows only the helper function implementation, as the implementation of on_end_of_system_sizing is much longer. One obvious difference is that EMS has no looping constructs (i.e., the “for” statements in the python implementation) and so the loop has to be manually “unrolled” into an “if-then-elsif ladder”. For on_end_of_system_sizing, the EMS implementation would similarly have to unroll the loop over all of the zones. This unrolling would be necessary even if EMS supported explicit looping constructs, because it doesn’t support arrays or string manipulations that are required to write more generalized code. The EMS implementation also has to declare, allocate space for, and explicitly manage all variables, whereas the python interpreter takes care of all of that.

This is part of the implementation of the same equipment airflow upsizing routine, using the original EMS feature. This implementation is far more verbose and clunky.
This is part of the implementation of the same equipment airflow upsizing routine, using the original EMS feature. This implementation is far more verbose and clunky.
BTO

Relationship of Python EMS to Spawn

Those who have been monitoring the development of Spawn, DOE’s next-generation BEM-controls engine, may be wondering about the relationship of Python EMS to Spawn. Isn’t Spawn intended to allow users to develop control sequences in real-world programming languages? Yes, it is! But Spawn is also a dynamic simulation engine that allows control sequences to be written in a physically realistic way and model them in, similarly, a physically realistic way. Python EMS control sequences will still have to be written to EnergyPlus’ load-based simulation approach, although once they are, they produce “correct” behavior.

Python EMS and Spawn shared significant underlying development. Much of the EnergyPlus re-engineering that enables Spawn to reuse its envelope and load modules also supports Python EMS. A key effort has been developing and exposing a rich API that allows external programs to “call into” EnergyPlus and invoke functions to read sensors, write actuators, query and calculate properties, etc. Spawn is using this API to exchange data between EnergyPlus and Modelica components. Third-party applications and services will also be able to apply this API to use EnergyPlus in a more granular “a la carte” form to implement new and enhanced functionality. Adds Lee, “Python EMS is just one use of this new API; there will be many other exciting uses.”