#pyidf
This Python library allows to read, modify and create EnergyPlus idf files.
The Pyidf library is generated from the current (EnergyPlus V8.4.0) Energy+.idd IDF specification. For each EnergyPlus Object a Python class is generated. This class is aware of the specified properties. Thus input values can be checked to be valid against the EnergyPlus specification.
Due to ambiguities in the EnergyPlus IDF specification file some EnergyPlus objects are (possibly) not correctly transferred to Python objects:
Site:SpectrumData
ZoneProperty:UserViewFactors:bySurfaceName
GroundHeatTransfer:Slab:XFACE
GroundHeatTransfer:Slab:YFACE
GroundHeatTransfer:Slab:ZFACE
GroundHeatTransfer:Basement:XFACE
GroundHeatTransfer:Basement:YFACE
GroundHeatTransfer:Basement:ZFACE
Pyidf represents EnergyPlus Objects as Python Classes. This allows auto completion. Pyidf EnergyPlus Objects are aware of their schema. Thus input values can be tested against the specification when the IDF is generated. The Python classes are documented based on the EnergyPlus specification.
pip install pyidf
git clone https://github.com/rbuffat/pyidf.git
cd pyidf
python setup.py install
Link to pyidf documentation page
Pyidf supports four different levels of validation. ValidationLevel.no
does not perform any validation. ValidationLevel.warn
issues warnings for all values not following the specification. ValidationLevel.transition
tries to transition values to follow the specification. This includes casting float values to integers, matching values of choice types to values from the specification and setting default values for required fields when no value is set. For values not possible to match or cast, a warning is issued. ValidationLevel.error
issues exceptions when a value is not valid according the specification. The default validation level is ValidationLevel.transition
. The validation level can be changed with:
from pyidf import ValidationLevel
import pyidf
pyidf.validation_level = ValidationLevel.no
import logging
from pyidf.idf import IDF
logging.info("start")
idf = IDF(r"/usr/local/EnergyPlus-8-2-0/ExampleFiles/BasicsFiles/Exercise1A.idf")
idf.save(r"~/Exercise1A_out.idf")
Accessing data objects is possible either by the name of the object:
for building in idf['Building']:
print building
# Output:
# Building,Exercise 1A,0.0,Country,0.04,0.4,FullInteriorAndExterior,,6
or by the corresponding property:
for building in idf.buildings:
print building
# Output:
# Building,Exercise 1A,0.0,Country,0.04,0.4,FullInteriorAndExterior,,6
Both variants return a list of the corresponding data objects present in the idf object. The name of the EnergyPlus data dictionaries were pythonified, for example BuildingSurface:Detailed
is represented by the Python class BuildingSurfaceDetailed
. Each data dictionary is located in the module of its group.
It is possible to iterate over all data objects of an idf object:
for obj in idf:
print obj
# Output:
# Version,8.2
# Building,Exercise 1A,0.0,Country,0.04,0.4,FullInteriorAndExterior,,6
# Timestep,4
# SurfaceConvectionAlgorithm:Inside,TARP
# ...
There are two types of fields. Normal fields and extensible fields. Normal fields exists only once while extensible fields can exist multiple times. Normal fields of a data object can similarly be accessed as data objects by their name, corresponding property or additionally by their index:
print idf['Building'][0]['Name']
# Output:
# Exercise 1A
print idf.buildings[0].name
# Output:
# Exercise 1A
print idf.buildings[0][0]
# Output:
# Exercise 1A
The schema of normal fields can be accessed with:
print idf['Building'][0].schema['fields']
# Output
# OrderedDict([(u'name', {'name': u'Name', 'pyname': u'name', 'default': u'NONE', 'required-field': True, 'autosizable': False, 'autocalculatable': False, 'type': 'alpha'}), ....
and of extensible fields with:
print idf['Building'][0].schema['extensible-fields']
# Output:
# OrderedDict() ( object has no extensible-fields)
The schema of a field can be accessed with:
print idf['Building'][0].field("Name")
# Output:
# {'name': u'Name', 'pyname': u'name', 'default': u'NONE', 'required-field': True, 'autosizable': False, 'autocalculatable': False, 'type': 'alpha'}
Extensible fields can be accessed with:
print idf.buildingsurfacedetaileds[0].extensibles
# Output:
# [[8.0, 6.0, 2.7], [8.0, 6.0, 0.0], [0.0, 6.0, 0.0], [0.0, 6.0, 2.7]]
For example for BuildingSurface:Detailed
the extensible fields are vertexes consisting of x,y,z values. The following code adds one to all coordinates:
print idf["BuildingSurface:Detailed"][0].schema['extensible-fields'].keys()
a = idf.buildingsurfacedetaileds[0].extensibles
b = [map(lambda x: x + 1, ext) for ext in a]
idf.buildingsurfacedetaileds[0].extensibles = b
The following code creates a new BuildingSurfaceDetailed
object and fills the values from an existing object:
from pyidf.idf import IDF
from pyidf.thermal_zones_and_surfaces import BuildingSurfaceDetailed
idf = IDF(r"/usr/local/EnergyPlus-8-2-0/ExampleFiles/BasicsFiles/Exercise1A.idf")
bsd = BuildingSurfaceDetailed()
for key in bsd.schema['fields']:
bsd[key] = idf.buildingsurfacedetaileds[0][key]
bsd.extensibles = idf.buildingsurfacedetaileds[0].extensibles
bsd.name = "test"
idf2 = IDF()
idf2.add(bsd)
Extensible fields can be added with add_extensibles. The number of parameters required by this method depends on the number of extensible fields of a data object.
bsd.add_extensible(1.0, 2.0, 3.0)
Single values of extensible fields can be altered by referencing the field to alter with a tuple (field name, index):
print bsd[(u'Vertex 1 Y-coordinate', 4)]
bsd[(u'Vertex 1 Y-coordinate', 4)] = 11.0
print bsd[(u'Vertex 1 Y-coordinate', 4)]
All values with corresponding keys of a data object can be accessed with the method items():
print bsd.items()
# Output:
# [(u'Name', 'test'), (u'Surface Type', 'Wall'), (u'Construction Name', 'LTWALL'), (u'Zone Name', 'ZONE ONE'), (u'Outside Boundary Condition', 'Outdoors'), (u'Outside Boundary Condition Object', None), (u'Sun Exposure', 'SunExposed'), (u'Wind Exposure', 'WindExposed'), (u'View Factor to Ground', 0.5), (u'Number of Vertices', 4.0), ((u'Vertex 1 X-coordinate', 0), 8.0), ((u'Vertex 1 Y-coordinate', 0), 6.0), ((u'Vertex 1 Z-coordinate', 0), 2.7), ((u'Vertex 1 X-coordinate', 1), 8.0), ((u'Vertex 1 Y-coordinate', 1), 6.0), ((u'Vertex 1 Z-coordinate', 1), 0.0), ((u'Vertex 1 X-coordinate', 2), 0.0), ((u'Vertex 1 Y-coordinate', 2), 6.0), ((u'Vertex 1 Z-coordinate', 2), 0.0), ((u'Vertex 1 X-coordinate', 3), 0.0), ((u'Vertex 1 Y-coordinate', 3), 6.0), ((u'Vertex 1 Z-coordinate', 3), 2.7)]
Keep in mind that pyidf is automatically generated from the specification. For some fields, especially extensible-fields, the field name contains a number where it shouldn't. For example for "BuildingSurface:Detailed", the specification looks as follows:
...
N3, \field Vertex 1 X-coordinate
\begin-extensible
\required-field
\units m
\type real
N4 , \field Vertex 1 Y-coordinate
\required-field
\units m
\type real
N5 , \field Vertex 1 Z-coordinate
\required-field
\units m
\type real
N6, \field Vertex 2 X-coordinate
\required-field
\units m
\type real
N7, \field Vertex 2 Y-coordinate
\required-field
\units m
\type real
N8, \field Vertex 2 Z-coordinate
\required-field
\units m
\type real
...
In pyidf only the 3 fields "Vertex 1 [X|Y|Z]-coordinate" are included in the schema. Extensible fields are implemented as a list of lists containing the values of the extensible fields. Thus field names can contain a number, for example "Vertex 1 X-coordinate", but should be named "Vertex X-coordinate" or "Vertex n X-coordinate"
Large parts of this library are generated automatically. In case the library should be rebuilt, for example to fix bugs or generate the library for a different EnergyPlus version, main.py in the generator package need to be executed. Currently generator/V8-2-0-Energy+.idd is used as basis to generate the library. generator/V8-2-0-Energy+Alt.idd contains modified data objects. Every data object in V8-2-0-Energy+Alt.idd overwrites data objects with the same name in the original idd. Generating the library requires the libraries jinja2, autopep8 and docformatter.
An alternative Python library to manipulate EnergyPlus idf files is eppy.