EnergyPlus Module Development Guide
EnergyPlus Module Development Guide
COPYRIGHT © 1998-2013 The Board of Trustees of the University of Illinois and the Regents of the University of California through
the Ernest Orlando Lawrence Berkeley National Laboratory.
All Rights Reserved. No part of this material may be reproduced or transmitted in any form or by any means without the prior written
permission of the University of Illinois or the Ernest Orlando Lawrence Berkeley National Laboratory.
EnergyPlus is a Trademark of the US Department of Energy.
TABLE OF CONTENTS
Introduction ......................................................................................................................................1
Modules in EnergyPlus....................................................................................................................2
Input Concepts.................................................................................................................................4
Choice Names........................................................................................................... 7
DataSets ....................................................................................................................... 12
Module Structure............................................................................................................................13
9/27/13 i
TABLE OF CONTENTS
EnergyPlus Calling Structure.........................................................................................................42
High Level HVAC Calling Tree (schematic – not all routines are shown) ....................... 42
Air System Calling Tree (schematic – not all routines are shown) ................................. 43
Plant Calling Tree (schematic – not all routines are shown) .......................................... 43
Zone Equipment Calling Tree (schematic – not all routines are shown) ........................ 44
HVAC Network...............................................................................................................................48
Initialization ............................................................................................................. 57
Sizing ...................................................................................................................... 58
Controls................................................................................................................... 60
Updating.................................................................................................................. 60
Reporting................................................................................................................. 61
EnergyPlus Services......................................................................................................................63
9/27/13 ii
TABLE OF CONTENTS
Input Services ............................................................................................................... 64
InputProcessor ........................................................................................................ 65
GetNumObjectsFound............................................................................................. 65
GetObjectItem ......................................................................................................... 65
GetObjectDefMaxArgs............................................................................................. 66
GetObjectItemNum.................................................................................................. 67
FindItemInList.......................................................................................................... 67
FindItem .................................................................................................................. 67
FindItemInSortedList ............................................................................................... 67
SameString ............................................................................................................. 67
VerifyName ............................................................................................................. 68
RangeCheck............................................................................................................ 68
MakeUPPERCase ................................................................................................... 69
BranchInputManager ............................................................................................... 73
NumBranchesInBranchList ...................................................................................... 74
GetBranchList.......................................................................................................... 74
GetBranchData........................................................................................................ 74
NodeInputManager.................................................................................................. 75
NodeFluidType ................................................................................................... 76
NodeObjectType................................................................................................. 76
NodeObjectName ............................................................................................... 76
NodeConnectionType ......................................................................................... 76
9/27/13 iii
TABLE OF CONTENTS
NodeFluidStream................................................................................................ 78
ObjectIsParent .................................................................................................... 78
GetOnlySingleNode................................................................................................. 79
GetNodeNums......................................................................................................... 79
InitUniqueNodeCheck.............................................................................................. 80
CheckUniqueNodes................................................................................................. 81
EndUniqueNodeCheck ............................................................................................ 81
SetUpCompSets ................................................................................................. 82
TestCompSet...................................................................................................... 85
CheckOutAirNodeNumber ....................................................................................... 86
CheckAndAddAirNodeNumber ................................................................................ 86
GetScheduleIndex................................................................................................... 88
GetDayScheduleIndex............................................................................................. 88
CheckScheduleValueMinMax.................................................................................. 88
CheckScheduleValue .............................................................................................. 89
GetScheduleMinValue............................................................................................. 89
GetScheduleMaxValue............................................................................................ 89
GetCurrentScheduleValue....................................................................................... 90
GetScheduleValuesForDay ..................................................................................... 90
GetSingleDayScheduleValues................................................................................. 90
LookUpScheduleValue ............................................................................................ 90
Data Services................................................................................................................ 91
9/27/13 iv
TABLE OF CONTENTS
GetMeterIndex......................................................................................................... 91
GetVariableKeyCountAndType................................................................................ 91
GetVariableKeys ..................................................................................................... 92
GetCurrentMeterValue ............................................................................................ 92
GetInstantMeterValue.............................................................................................. 92
GetInternalVariableValue......................................................................................... 92
GetNewUnitNumber ................................................................................................ 93
FindUnitNumber ...................................................................................................... 93
FindNumberinList .................................................................................................... 93
ValidateComponent ................................................................................................. 93
CheckComponent.................................................................................................... 94
CreateSysTimeIntervalString................................................................................... 94
TrimSigDigits ........................................................................................................... 95
RoundSigDigits........................................................................................................ 95
SafeDivide............................................................................................................... 96
SetupAndSort .......................................................................................................... 96
Error Messages............................................................................................................. 96
ShowWarningError, ShowWarningMessage............................................................ 98
ShowSevereError, ShowSevereMessage................................................................ 99
ShowFatalError ....................................................................................................... 99
ShowMessage......................................................................................................... 99
9/27/13 v
TABLE OF CONTENTS
Performance Curve Services....................................................................................... 101
GetCurveCheck..................................................................................................... 102
Reference Data Set (RDS) Values for Refrigerant Class Fluids............................. 104
Fluid Property Data and Expanding the Glycols Available to EnergyPlus .............. 109
Parameters............................................................................................................ 111
9/27/13 vi
TABLE OF CONTENTS
PsyHFnTdbRhPb (Tdb,Rh,Pb,calledfrom) ............................................................. 114
WriteTable(body,rowLabels,columnLabels,widthColumn)...................................... 116
Output ..........................................................................................................................................118
9/27/13 vii
TABLE OF CONTENTS
Table 4. SetupOutputVariable Arguments........................................................ 119
9/27/13 viii
TABLE OF CONTENTS
DisplayAdvancedReportVariables: turn on access to advance report
variables ........................................................................................................... 131
DeveloperFlag: turn on (or off) some different outputs for the developer........... 131
SutherlandHodgman: turn on (or off) the polygon clipping algorithm ................. 131
MinimalShadowing: turn on (or off) the use of Minimal Shadowing ................... 131
Appendix G. .................................................................................................................................152
9/27/13 ix
EnergyPlus Module Developer's Guide Introduction
Introduction
9/27/13 1
EnergyPlus Module Developer's Guide Modules in EnergyPlus
Modules in EnergyPlus
Program Modules
A module is a Fortran 90/95 programming construct that can be used in various
ways. In EnergyPlus, its primary use is to segment a rather large program into
smaller, more manageable pieces. Each module is a separate package of source
code stored on a separate file. The entire collection of modules, when compiled and
linked, forms the executable code of EnergyPlus.
Each module contains source code for closely related data structures and
procedures. For instance, the WeatherManager module contains all the weather
handling routines in EnergyPlus. The module is contained in the file
WeatherManager.f90. Another example is PlantPumps. This module contains all the
code to simulate pumps in EnergyPlus. It is contained in file PlantPumps.f90.
Of course dividing a program into modules can be done in various ways. We have
attempted to create modules that are as self-contained as possible. The philosophy
that has been used in creating EnergyPlus is contained in the Programming
Standard reference document. Logically, the modules in EnergyPlus form an
inverted tree structure. At the top is EnergyPlus. Just below that are ProcessInput
and ManageSimulation. At the bottom are the modules such as
HVACDamperComponent that model the actual HVAC components.
Data Only Modules
EnergyPlus also uses modules that primary contain data and data structures that
may be used by several modules. These modules form one of the primary ways data
is structured and shared in EnergyPlus. An example is the DataEnvironment module.
Many parts of the program need access to the outdoor conditions. All of that data is
encapsulated in DataEnvironment. Modules that need this data obtain access
through a Fortran USE statement. Without such access, modules cannot use or
change this data.
Sometimes data modules are extended to perform certain utilities or even getting
input for the data structures that are the primary focus of the module but this is not a
standard approach.
9/27/13 2
EnergyPlus Module Developer's Guide Modules in EnergyPlus
The process for adding new features or significantly changing some features goes
through a development team discussion period where the new feature is outlined,
discussed and (hopefully) approved for inclusion.
The team has a New Feature Proposal template document that is available to
anyone wishing to add a new feature to EnergyPlus (or to auxiliary programs around
EnergyPlus). The full New Feature Proposal format is shown in Appendix F.
The sections of the New Feature Proposal are summarized in the following table:
Table 1. Sections of a New Feature Proposal
Section Description
Justification Why is the feature important. Impact on
energy use. What energy aspects the feature
is using.
Conference Call Conclusions Conclusions from the discussions (email or
conference call)
Other Conference Call topics Items outside the scope of the feature might
be brought up but not able to be
accomplished.
Overview Description of the feature and references
Approach What approach will be used.
Testing/Validation data Sources Required
IORef/Draft IDD Objects (new or revised) as well as full
IOReference text
Proposed Report Variables What outputs will come out of this feature.
Proposed additions to meters How the outputs will affect the meter output
Engineering Reference Draft Draft text for the Engineering Reference
document
Example File What/how many example files will be included
or used to support this feature
Transition changes What will be the required changes for current
input files for this feature
Other documents Other references.
Then, of course, the document in Appendix G must be filled out and given to the
proper people as well – to show that rights to the intellectual property of the new
feature are owned by the developer.
9/27/13 3
EnergyPlus Module Developer's Guide Input Concepts
Input Concepts
In EnergyPlus, input and output are accomplished by means of ASCII (text) files. On
the input side, there are two files:
1) the Input Data Dictionary (IDD) that describes the types (classes) of input objects
and the data associated with each object;
2) the Input Data File (IDF) that contains all the data for a particular simulation.
Each EnergyPlus module is responsible for getting its own input. Of course,
EnergyPlus provides services to the module that make this quite easy. The first task
of a module developer is to design and insert a new entry into the Input Data
Dictionary.
9/27/13 4
EnergyPlus Module Developer's Guide Input Concepts
\type real
\default 82.2
N5, \field Design Inlet Air Temperature
\units C
\type real
\default 16.6
N6, \field Design Outlet Water Temperature
\units C
\type real
\default 71.1
N7; \field Design Outlet Air Temperature
\units C
\type real
\default 32.2
This entry defines a simple water-heating coil and specifies all of the input data
needed to model it. The following rules apply.
The first element Coil:Heating:Water is the class name (also called a keyword or
key). This class name must be unique in the IDD. The maximum length for the
class name is 100 characters. Embedded spaces are allowed and are
significant.
In most cases, one should have fields following the object name. An object
name by itself (terminated with a semicolon) is a “section” – there may be uses
for sections in input but the “Getting” of input is not hierarchical – one typically
gets all objects of one type and then all objects of the next type.
In most cases, the second field of an object should be an “alpha” and the field
name should contain the word “name”. (This will allow for certain validations
later on.)
Commas separate fields. They always act as separators – thus there is no way
to include a comma in a class name or as part of a data field.
Similarly, semicolons are terminators – a semicolon is always interpreted as the
end of an EnergyPlus “sentence”. So, avoid embedded semicolons in class
names or data fields.
Blank lines are allowed.
Each line can be up to 500 characters in length.
The comment character is an exclamation or a backslash. Anything on a line
after an “!” or a “\” is ignored during EnergyPlus input.
The only significant syntax elements are the commas, the semicolon, the N’s
(denoting numeric data), and the A’s (denoting alphanumeric data) and the
exclamation and backslash. Everything else including blanks, end of lines, or even
text that is not a comma, semicolon, N, or A is ignored. There are several style
conventions in use however.
Sequence numbers are appended to the letters A or N denoting each data
element. Thus, A2 is the second alphanumeric data item and N3 is the third
numeric data item.
The class name contains a naming convention: type:subtype:subsubtype. For
further naming conventions, please see the next section of this document.
Backslashes denote specially formatted comments. These comments provide
information about the input, such as a description of the item, units, limits, mins &
maxes, etc., in a form that can be processed by an input editor or interface. A
9/27/13 5
EnergyPlus Module Developer's Guide Input Concepts
complete description of the backslash comment format is given at the start of the
IDD file and in the Guide for Interface Developers. While these are “comments”,
they are quite important and allow the InputProcessor module to do some error
checking for you. They are also used by the IDFEditor that many users continue
to use and by interface developers in understanding EnergyPlus.
\default – the number (N fields) or phrase (A fields) after this special field will be filled
for any input file that has a blank in that field.
\minimum or \minimum> -- the number following this special field will be
automatically checked during input
\maximum or \maximum< -- the number following this special field will be
automatically checked during input
\extensible:# – allows you to structure your GetInput routine so that the object
arguments can be expanded (you include the number of fields in the “extension” and
the Input Processor can automatically extend IDD definitions) – you will still need to
determine how many maximum arguments are in the object. The IDF Editor does not
use this field and cannot auto-extend such objects if an IDF is encountered that has a
greater number of fields than IDD allows.
\type integer – (or real or alpha) – this field has gained increased importance after a
user kept hitting an internal maximum detected by the program and kept increasing
their input number until it overflowed the system’s integer size. Until all types are
shown on numeric fields it will be hard for the InputProcessor to provide proper error
detection.
There are many more \ fields – these are described at the top of the IDD.
Overall, the IDD file has very little structure. Generally, a new entry should be placed
next to entries describing similar components. Coil:Heating:Water, for instance, is
grouped with entries describing other water coils.
Summary
One of the early tasks for a module developer is to create a new entry in the Input
Data Dictionary. This entry defines the data needed to model the new component.
Field Names
Field names shall be written in title case where every major word is capitalized
(exceptions: "a", "the", "for", etc.) with spaces separating words. Field names shall
be written using natural language terminology but should be relatively concise (no
unnecessary abbreviations or acronyms). If the field is for the name of this object,
the field name shall simply be "Name" to eliminate redundancy. The nature of an
alpha field shall be explicit, for instance, "Availability Schedule Name" instead of
merely "Availability Schedule". Generally, the object is not also included as the field
name.
Example: Availability Schedule Name
9/27/13 6
EnergyPlus Module Developer's Guide Input Concepts
When object names/types are included as part of the input, then the field name
should contain “Object Type”:
Example: Zone Equipment 1 Object Type
Choice Names
When field choices list object references, the field choices shall list the class/object
type name the same as its class definition in the IDD. When field choices list other
key words, the field choice names shall be written in camel case where words are
joined together without spaces and each word is capitalized. Field choice names
shall be written using natural language terminology but should be relatively concise
(no unnecessary abbreviations or acronyms) and avoid overly lengthy key words.
Field choice names shall only use alphanumeric characters with the addition of the
forward slash ("/") character as a concise alternative to the word "per"; colons shall
be allowed if the field choices are class names.
A2 , \field Period Selection
\retaincase
\note Following is a list of all possible types of Extreme and Typical periods that
\note might be identified in the Weather File. Not all possible types are available
\note for all weather files.
\type choice
\key SummerExtreme
\key SummerTypical
\key WinterExtreme
\key WinterTypical
\key AutumnTypical
\key SpringTypical
\key WetSeason
\key DrySeason
\key NoDrySeason
\key NoWetSeason
\key TropicalHot
\key TropicalCold
The Input Data File (IDF) is the file containing the data for an actual simulation. This
file is also a text (ASCII) file with a syntax “filling in the blanks” of the definitions in
the IDD. A portion of an IDF with input data for the hot water coil defined in the IDD
example looks like:
9/27/13 7
EnergyPlus Module Developer's Guide Input Concepts
Coil:Heating:Water,
SPACE1-1 Zone Coil, !- Name
ReheatCoilAvailSched, !- Availability Schedule Name
autosize, !- U-Factor Times Area Value {W/K}
autosize, !- Maximum Water Flow Rate {m3/s}
SPACE1-1 Zone Coil Water In Node, !- Water Inlet Node Name
SPACE1-1 Zone Coil Water Out Node, !- Water Outlet Node Name
SPACE1-1 Zone Coil Air In Node, !- Air Inlet Node Name
SPACE1-1 In Node, !- Air Outlet Node Name
UFactorTimesAreaAndDesignWaterFlowRate, !- Performance Input Method
autosize, !- Nominal Capacity {W}
82.2, !- Design Inlet Water Temperature {C}
16.6, !- Design Inlet Air Temperature {C}
71.1, !- Design Outlet Water Temperature {C}
32.2; !- Design Outlet Air Temperature {C}
Coil:Heating:Water,
SPACE2-1 Zone Coil, !- Name
ReheatCoilAvailSched, !- Availability Schedule Name
autosize, !- U-Factor Times Area Value {W/K}
autosize, !- Maximum Water Flow Rate {m3/s}
SPACE2-1 Zone Coil Water In Node, !- Water Inlet Node Name
SPACE2-1 Zone Coil Water Out Node, !- Water Outlet Node Name
SPACE2-1 Zone Coil Air In Node, !- Air Inlet Node Name
SPACE2-1 In Node, !- Air Outlet Node Name
UFactorTimesAreaAndDesignWaterFlowRate, !- Performance Input Method
autosize, !- Nominal Capacity {W}
82.2, !- Design Inlet Water Temperature {C}
16.6, !- Design Inlet Air Temperature {C}
71.1, !- Design Outlet Water Temperature {C}
32.2; !- Design Outlet Air Temperature {C}
Coil:Heating:Water,
SPACE3-1 Zone Coil, !- Name
ReheatCoilAvailSched, !- Availability Schedule Name
autosize, !- U-Factor Times Area Value {W/K}
autosize, !- Maximum Water Flow Rate {m3/s}
SPACE3-1 Zone Coil Water In Node, !- Water Inlet Node Name
SPACE3-1 Zone Coil Water Out Node, !- Water Outlet Node Name
SPACE3-1 Zone Coil Air In Node, !- Air Inlet Node Name
SPACE3-1 In Node, !- Air Outlet Node Name
UFactorTimesAreaAndDesignWaterFlowRate, !- Performance Input Method
autosize, !- Nominal Capacity {W}
82.2, !- Design Inlet Water Temperature {C}
16.6, !- Design Inlet Air Temperature {C}
71.1, !- Design Outlet Water Temperature {C}
32.2; !- Design Outlet Air Temperature {C}
Each coil entry begins with the class name (keyword) specifying the type of coil.
Next is the coil name – a user (or interface) created name that is unique within the
given class. Generally in EnergyPlus, objects within a class are distinguished by
unique names. The object name is usually the first data element following the class
name. Any alphanumeric data item in the IDF can be up to 100 characters long.
Any characters past 100 are truncated (lost). After the object name comes the real
data. If we look at the IDD we see that the first data item after the object name is
expected to be an alphanumeric – a schedule name. In the IDF, we see the
corresponding field is “ReheatCoilAvailSched”, the object name of a schedule
elsewhere in the IDF file. In EnergyPlus, all references to other data entries (objects)
are via object names. The next two data items are numeric: the coil UA and the
9/27/13 8
EnergyPlus Module Developer's Guide Input Concepts
maximum water mass flow rate. The final four items are again alphanumeric – the
names of the coil inlet and outlet nodes. Nodes are used in EnergyPlus to connect
HVAC components together into HVAC systems.
The example illustrates the use of comments to create clear input. The IDF is
intended to be human readable, largely for development and debugging purposes.
Of course, most users will never see an IDF – they will interact with EnergyPlus
through a Graphical User Interface (GUI), which will write the IDF for them.
However, a module developer is a special kind of user. The module developer will
need to create a portion of an IDF by hand very early in the development process in
order to begin testing the module under development. Thus, it is important to
understand the IDF syntax and to use comments to create readable test IDF files.
Summary
One of the early tasks of a module developer is to create input (most likely by hand)
for the new component and to insert it into an existing IDF file in order to test the new
component model. The IDF syntax resembles the syntax for the IDD. The data
follows the IDD class description. Comments should be used to make the IDF
readable.
Input Considerations
The IDD/IDF concept allows the module developer much flexibility. Along with this
flexibility comes a responsibility to the overall development of EnergyPlus.
Developers must take care not to obstruct other developers with their additions or
changes. Major changes in the IDD require collaboration among the developers
(both module and interface).
In many cases, the developer may be creating a new model – a new HVAC
component, for instance. Then the most straightforward approach is to create a new
object class in the IDD with its own unique, self-contained input. This will seldom
impact other developers.
In some cases, the developer may be adding a calculation within an existing module
or for an existing class of objects. This calculation may require new or different input
fields. Then the developer has a number of choices. This section will present some
ideas for adding to the IDD that will minimize impact to other developers.
For example, consider the implementation of Other Side Coefficients (OSC) in the
IDD. Other side coefficients are a simplification for the surface heat balance and
were used mostly in BLAST 2.0 before we had interzone surfaces. We have carried
this forward into EnergyPlus for those users that understand and can use it. We’ll
use it as an example of approaches to adding data items to the IDD. Moreover, we’ll
try to give some hints on which approaches might be used for future additions.
So, you're adding something to EnergyPlus and it is part of an existing module or
object class. What do you do with your required inputs to your model? There are at
least four options:
Embed your values in a current object class definition.
Put something in the current definition that will trigger a "GetInput" for your values.
Put something in the current definition that will signal a "special" case and embed a name
(of your item) in the definition (this adds 1 or 2 properties to the object).
Just get your input and have each of those inputs reference a named object.
9/27/13 9
EnergyPlus Module Developer's Guide Input Concepts
For example, using the OSC option in surfaces, in the beta 2 version of EnergyPlus
we had
A8 , \field Exterior environment
\type alpha
\note <for Interzone Surface:Adjacent surface name>
\note For non-interzone surfaces enter:
\note ExteriorEnvironment, Ground, or OtherSideCoeff
\note OSC won't use CTFs
1) We have done option 1: embed the values in the input. (We have also
embedded these values in each and every surface derived type (internal data
structure) but that can be discussed elsewhere).
When to use: It makes sense to embed these values when each and every object
(SURFACE) needs these values (e.g. we need to specify Vertices for Every Surface
-- so these clearly should be embedded).
After beta 2, the definition of Surfaces was changed. Obviously option 1 was not a
good choice for the OSC data: the data would be rarely used. Our other options
were:
2) Obviously the ExteriorEnvironment field will remain (but its name was changed to
Outside Face Environment).
However, we do not want to embed the values for OtherSideCoef in the Surface
items. So, if the ExteriorEnvironment continues to reference OtherSideCoef, we can
easily trigger a "GetInput" for them. An additional object class would be necessary
for this case.
OtherSideCoef, A1, \field name of OtherSideCoef,
A2, \field SurfaceName (reference to surface using OSC)
....
When to use: This option can be used for many cases. The same object definition
will work for option 4 below. Obviously, if there is not a convenient trigger in
SURFACE but you want to add a feature, this would let you do it without embedding
it in the Surface Definition. If there is a trigger, such as exists with the
ExteriorEnvironment, the A2 field might not be needed. This approach would
become a bit cumbersome if you expected there to be a lot of these or if there were a
one-to-many relationship (i.e. a single set of OSCs could be used for many
surfaces). Nevertheless, the approach provides a convenient "data check"/cross
reference that can be validated inside the code.
3) We could also have the SURFACE definition reference an OSC name (in this
instance).
9/27/13 10
EnergyPlus Module Developer's Guide Input Concepts
So, we'd add a field to the Surface that would be the name in the OtherSideCoef
object above. Then, the OtherSideCoef objects wouldn’t need a Surface Name. This
is the most straightforward approach: including data in one object by referencing
another and it was the approach chosen for the redefined Surface class.
When to use: when there is a set of parameters that would be used extensively,
then this would provide a name for those. If hand editing, then you only would need
to change one set of these parameters rather than having to go through many. Of
course, the OtherSideCoef object wouldn’t also have to have the true numbers but
could reference yet a third named object...... (starting to get messy).
4) We could have the OtherSideCoef object as above and just "get" it as a matter of
course. (e.g., in the case where we don’t have a convenient trigger such as
ExteriorEnvironment).
When to use: Note that the same structure for 2 works here too. It's just not
triggered (to get the input) by a value in the other object (SURFACE).
Summary
There are several approaches to adding items to the IDD. Developers need to
consider impacts to other developers and users early in the implementation planning.
9/27/13 11
EnergyPlus Module Developer's Guide Input Concepts
ZoneHVAC:FourPipeFanCoil,
\min-fields 21
A1 , \field Name
\required-field
A2 , \field Availability Schedule Name
\required-field
\type object-list
\object-list ScheduleNames
N1 , \field Maximum Supply Air Flow Rate
\required-field
\autosizable
\units m3/s
N2 , \field Maximum Outdoor Air Flow Rate
\required-field
\autosizable
\units m3/s
<snip>
A11, \field Cooling Coil Name
\required-field
\type object-list
\object-list CoolingCoilsWater
N3 , \field Maximum Cold Water Flow Rate
\required-field
\autosizable
\units m3/s
\ip-units gal/min
<snip>
A13; \field Cooling Coil Object Type
\required-field
\type choice
\key Coil:Cooling:Water
\key Coil:Cooling:Water:DetailedGeometry
\key CoilSystem:Cooling:Water:HeatExchangerAssisted
DataSets
Akin to the libraries of other programs, EnergyPlus uses data sets. Data sets are
similar to libraries but many items are contained in a single file (usually input file
format or sometimes macro format). Developers are encouraged, as appropriate, to
submit data sets along with new features. Some of the existing data sets include:
Materials properties
Construction elements (layers of materials)
Composite construction definitions (equivalent constructions for complex elements)
Solar Collector parameters
Economic Tariffs
Design Day definitions
Location definitions
Standard report definitions
9/27/13 12
EnergyPlus Module Developer's Guide Module Structure
Module Structure
Let us assume that the novice EnergyPlus developer wishes to model a new HVAC
component called NewHVACComponent. Right at the start there is a choice to
make: whether to insert the new model into an existing module or to create an
entirely new EnergyPlus component simulation model. Creating a new module is the
easier option to explain, implement and test. We will discuss this option in this
document. The discussion should also impart enough information to allow a new
developer to insert a model into an existing EnergyPlus module if that option is
chosen.
If you intend that the module will become part of the distributed EnergyPlus, follow
the guidance in the Programming Standard document. Even if you don’t intend that
your module will become part of EnergyPlus – but you might want some advice from
one of the core development team, follow the guidance in the Programming
Standard.
Module Outline
The developer will create a new file NewHVACComponent.f90. The file shall contain
the following elements:
Note – even if your component does not need some of the suggested modules, you should include “stub”
routines for these.
MODULE NewHVACComponent
Documentation: Fortran comments describing and documenting the module. Included are
sections showing module author, module creation date, date modified and modification
author. Each routine and/or function should also follow the documentation guidelines as
shown in the templates.
USE Statements: Fortran statements naming other modules that this module can access,
either for data or for routines.
Module Parameters: If you will be implementing more than one “type” of component in
the module, it is a good idea to assign numeric parameters to each type so as to retain
readability yet reduce alpha comparisons which are notoriously slow for most systems.
Assign numeric parameters to alphanumeric fields within a class type (.e.g. object
UnitarySystem:HeatPump, field Fan Placement: “blow through” or “draw through”) when
this information is required in init, calc, update or report subroutines to further reduce
alpha comparisons. Use string comparison only in GetInput subroutines.
Module Data structure Definitions: Using the Fortran TYPE statement define the data
structures needed in the module that will not be available from other modules. Define all
module level variables that will be needed.
Typically, you define your module’s data structure within the module. If this data must be
used by multiple modules, you should define a separate Data module for the data.
Character strings in structures are not allowed (except for name of object) – any
exceptions must be approved. Schedule names, curve object names, and child object
types MUST all be referenced by an integer.
For existing code, convert all character string structure variables to integer parameters
and delete the character variable from the structure. Also delete unused strings rather
than converting to integer. Do not use structure variable to store information used only
9/27/13 13
EnergyPlus Module Developer's Guide Module Structure
during GetInput even if you think it could be used in the future, use local variables
instead. Usually won't hurt anything until some user puts a large number of objects in
their input (memory use impact).
Currently, the furnace structure includes many that should not be there.
SuppHeatCoilType is an example of a character string structure variable that is only used
in GetInput and is not needed in the structure. Should have been a local instead. And
CoolingPLFFPLR and HeatingPLFFPLR structure variables are not even used.
CONTAINS
SUBROUTINE SimNewHVACComponent
This routine selects the individual component being simulated and calls the other
module subroutines that do the real work. This routine is the only routine in the
module that is accessible outside the module (PUBLIC). All other routines in the
module are PRIVATE and are only callable within the module. This routine is
sometimes called the “driver” routine for the module.
END SUBROUTINE SimNewHVACComponent
SUBROUTINE GetNewHVACComponentInput
This routine uses the “get” routines from the InputProcessor module to obtain
input for NewHVACComponent. The module data arrays are allocated and the
data is moved into the arrays.
END SUBROUTINE GetNewHVACComponentInput
SUBROUTINE InitNewHVACComponent
This routine performs whatever initialization calculations that may be needed at
various points in the simulation. For instance, some calculations may only need
to be done once; some may need to be done at the start of each simulation
weather period; some at the start of each HVAC simulation time step; and some
at the start of each loop solution. This routine also transfers data from the
component inlet nodes to the component data arrays every time the component
is simulated, in preparation for the actual component simulation.
END SUBROUTINE InitNewHVACComponent
SUBROUTINE SizeNewHVACComponent
This routine can create the sizing options (if applicable) for the component or be
left as a placeholder for later manipulation for sizing purposes.
END SUBROUTINE SizeNewHVACComponent
SUBROUTINE CalcNewHVACComponent
This routine does the actual calculations to simulate the performance of the
component. Only calculation is done – there is no moving of data from or to input
or output areas. There may be more than one “CALC” subroutine if more than
one component is being modeled within this module.
END SUBROUTINE CalcNewHVACComponent
SUBROUTINE UpdateNewHVACComponent
This routine moves the results of the “Calc” routine(s) to the component outlet
nodes.
END SUBROUTINE UpdateNewHVACComponent
SUBROUTINE ReportNewHVACComponent
This routine performs any special calculations that are needed purely for
reporting purposes.
END SUBROUTINE ReportNewHVACComponent
Utility Routines (as appropriate) – in the Fan module we allow outside modules to
access internal fan inlets, outlets, and design volume flow rate.
9/27/13 14
EnergyPlus Module Developer's Guide Module Structure
Module Example
This example can be used as a template for new HVAC component modules. In
particular, the commenting structure in the module and within the subroutines should
be followed closely. Of course, there is no perfect example module – this one is
particularly simple. Some others that might be examined are in files Humidifiers.f90,
HVACHeatingCoils.f90 and PlantChillers.f90. Templates are also available as
separate files.
In particular, the module template with routines contains structure and information
pertinent to module development.
Note that in the following module, the “Data IPShortcuts” is not used – rather those
variables are allocated within this module – likely because another module calls this
one during input.
Module Fans
! Module containing the fan simulation routines
! MODULE INFORMATION:
! AUTHOR Richard J. Liesen
! DATE WRITTEN April 1998
! MODIFIED Shirey, May 2001
! RE-ENGINEERED na
! REFERENCES: none
! USE STATEMENTS:
! Use statements for data only modules
USE DataPrecisionGlobals
USE DataLoopNode
USE DataHVACGlobals, ONLY: TurnFansOn, TurnFansOff, Main, Cooling, Heating, Other, &
OnOffFanPartLoadFraction, SmallAirVolFlow, UnbalExhMassFlow, NightVentOn, cFanTypes, &
FanType_SimpleConstVolume, FanType_SimpleVAV, FanType_SimpleOnOff, FanType_ZoneExhaust
USE DataGlobals, ONLY: SetupOutputVariable, BeginEnvrnFlag, BeginDayFlag, MaxNameLength, &
ShowWarningError, ShowFatalError, ShowSevereError, HourofDay, SysSizingCalc, CurrentTime, &
OutputFileDebug, ShowContinueError, ShowRecurringWarningErrorAtEnd, WarmupFlag, &
ShowContinueErrorTimeStamp
Use DataEnvironment, ONLY: StdBaroPress, DayofMonth, Month, StdRhoAir
USE Psychrometrics, ONLY:PsyRhoAirFnPbTdbW, PsyTdbFnHW, PsyCpAirFnWTdb
9/27/13 15
EnergyPlus Module Developer's Guide Module Structure
TYPE NightVentPerfData
CHARACTER(len=MaxNameLength) :: FanName =' ' ! Name of the fan that will use this data
REAL(r64) :: FanEff =0.0 !Fan total efficiency; motor and mechanical
REAL(r64) :: DeltaPress =0.0 !Delta Pressure Across the Fan [N/m2]
REAL(r64) :: MaxAirFlowRate =0.0 !Max Specified Volume Flow Rate of Fan [m3/s]
REAL(r64) :: MaxAirMassFlowRate =0.0 ! Max flow rate of fan in kg/sec
REAL(r64) :: MotEff =0.0 !Fan motor efficiency
REAL(r64) :: MotInAirFrac =0.0 !Fraction of motor heat entering air stream
END TYPE NightVentPerfData
9/27/13 16
EnergyPlus Module Developer's Guide Module Structure
CONTAINS
! MODULE SUBROUTINES:
!*************************************************************************
SUBROUTINE SimulateFanComponents(CompName,FirstHVACIteration)
! SUBROUTINE INFORMATION:
! AUTHOR Richard Liesen
! DATE WRITTEN February 1998
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! na
! REFERENCES:
! na
! USE STATEMENTS:
USE InputProcessor, ONLY: FindItemInList
! FLOW:
! Find the correct FanNumber with the AirLoop & CompNum from AirLoop Derived Type
!FanNum = AirLoopEquip(AirLoopNum)%ComponentOfTypeNum(CompNum)
! Determine which Fan given the Fan Name
9/27/13 17
EnergyPlus Module Developer's Guide Module Structure
FanNum = FindItemInList(CompName,Fan%FanName,NumFans)
IF (FanNum == 0) THEN
CALL ShowFatalError('Fan not found='//TRIM(CompName))
ENDIF
RETURN
! SUBROUTINE INFORMATION:
! AUTHOR Richard Liesen
! DATE WRITTEN April 1998
! MODIFIED Shirey, May 2001
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Uses "Get" routines to read in data.
! REFERENCES:
! na
! USE STATEMENTS:
USE InputProcessor
USE NodeInputManager, ONLY: GetOnlySingleNode
USE CurveManager, ONLY: GetCurveIndex
USE BranchNodeConnections, ONLY: TestCompSet
! USE DataIPShortCuts
9/27/13 18
EnergyPlus Module Developer's Guide Module Structure
! Flow
MaxAlphas=0
MaxNumbers=0
NumSimpFan = GetNumObjectsFound('Fan:ConstantVolume')
IF (NumSimpFan > 0) THEN
CALL GetObjectDefMaxArgs('Fan:ConstantVolume',NumParams,NumAlphas,NumNums)
MaxAlphas=MAX(MaxAlphas,NumAlphas)
MaxNumbers=MAX(MaxNumbers,NumNums)
ENDIF
NumVarVolFan = GetNumObjectsFound('Fan:VariableVolume')
IF (NumVarVolFan > 0) THEN
CALL GetObjectDefMaxArgs('Fan:VariableVolume',NumParams,NumAlphas,NumNums)
MaxAlphas=MAX(MaxAlphas,NumAlphas)
MaxNumbers=MAX(MaxNumbers,NumNums)
ENDIF
NumOnOff = GetNumObjectsFound('Fan:OnOff')
IF (NumOnOff > 0) THEN
CALL GetObjectDefMaxArgs('Fan:OnOff',NumParams,NumAlphas,NumNums)
MaxAlphas=MAX(MaxAlphas,NumAlphas)
MaxNumbers=MAX(MaxNumbers,NumNums)
ENDIF
NumZoneExhFan = GetNumObjectsFound('Fan:ZoneExhaust')
IF (NumZoneExhFan > 0) THEN
CALL GetObjectDefMaxArgs('Fan:ZoneExhaust',NumParams,NumAlphas,NumNums)
MaxAlphas=MAX(MaxAlphas,NumAlphas)
MaxNumbers=MAX(MaxNumbers,NumNums)
ENDIF
NumNightVentPerf = GetNumObjectsFound('FanPerformance:NightVentilation')
IF (NumNightVentPerf > 0) THEN
CALL GetObjectDefMaxArgs('FanPerformance:NightVentilation',NumParams,NumAlphas,NumNums)
MaxAlphas=MAX(MaxAlphas,NumAlphas)
MaxNumbers=MAX(MaxNumbers,NumNums)
ENDIF
ALLOCATE(cAlphaArgs(MaxAlphas))
cAlphaArgs=' '
ALLOCATE(cAlphaFieldNames(MaxAlphas))
cAlphaFieldNames=' '
ALLOCATE(lAlphaFieldBlanks(MaxAlphas))
lAlphaFieldBlanks=.false.
ALLOCATE(cNumericFieldNames(MaxNumbers))
cNumericFieldNames=' '
ALLOCATE(lNumericFieldBlanks(MaxNumbers))
lNumericFieldBlanks=.false.
9/27/13 19
EnergyPlus Module Developer's Guide Module Structure
ALLOCATE(rNumericArgs(MaxNumbers))
rNumericArgs=0.0
DO SimpFanNum = 1, NumSimpFan
FanNum = SimpFanNum
cCurrentModuleObject= 'Fan:ConstantVolume'
CALL GetObjectItem(TRIM(cCurrentModuleObject),SimpFanNum,cAlphaArgs,NumAlphas, &
rNumericArgs,NumNums,IOSTAT, &
NumBlank=lNumericFieldBlanks,AlphaBlank=lAlphaFieldBlanks, &
AlphaFieldNames=cAlphaFieldNames,NumericFieldNames=cNumericFieldNames)
IsNotOK=.false.
IsBlank=.false.
CALL VerifyName(cAlphaArgs(1),Fan%FanName,FanNum-1,IsNotOK,IsBlank,TRIM(cCurrentModuleObject)//'
Name')
IF (IsNotOK) THEN
ErrorsFound=.true.
IF (IsBlank) cAlphaArgs(1)='xxxxx'
ENDIF
Fan(FanNum)%FanName = cAlphaArgs(1)
Fan(FanNum)%FanType = cCurrentModuleObject
Fan(FanNum)%Schedule = cAlphaArgs(2)
Fan(FanNum)%SchedPtr = GetScheduleIndex(cAlphaArgs(2))
IF (Fan(FanNum)%SchedPtr == 0) THEN
IF (lAlphaFieldBlanks(2)) THEN
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//':
'//TRIM(cAlphaFieldNames(2))// &
' is required, missing for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
ELSE
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//': invalid
'//TRIM(cAlphaFieldNames(2))// &
' entered ='//TRIM(cAlphaArgs(2))// &
' for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
END IF
ErrorsFound=.true.
END IF
! Fan(FanNum)%Control = 'CONSTVOLUME'
Fan(FanNum)%FanType_Num=FanType_SimpleConstVolume
Fan(FanNum)%FanEff = rNumericArgs(1)
Fan(FanNum)%DeltaPress = rNumericArgs(2)
Fan(FanNum)%MaxAirFlowRate= rNumericArgs(3)
IF (Fan(FanNum)%MaxAirFlowRate == 0.0) THEN
CALL ShowWarningError(TRIM(cCurrentModuleObject)//'="'//TRIM(Fan(FanNum)%FanName)// &
'" has specified 0.0 max air flow rate. It will not be used in the simulation.')
ENDIF
Fan(FanNum)%MotEff = rNumericArgs(4)
Fan(FanNum)%MotInAirFrac = rNumericArgs(5)
Fan(FanNum)%MinAirFlowRate= 0.0
Fan(FanNum)%InletNodeNum = &
GetOnlySingleNode(cAlphaArgs(3),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Inlet,1,ObjectIsNotParent)
Fan(FanNum)%OutletNodeNum = &
GetOnlySingleNode(cAlphaArgs(4),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Outlet,1,ObjectIsNotParent)
9/27/13 20
EnergyPlus Module Developer's Guide Module Structure
DO VarVolFanNum = 1, NumVarVolFan
FanNum = NumSimpFan + VarVolFanNum
cCurrentModuleObject= 'Fan:VariableVolume'
CALL GetObjectItem(TRIM(cCurrentModuleObject),VarVolFanNum,cAlphaArgs,NumAlphas, &
rNumericArgs,NumNums,IOSTAT, &
NumBlank=lNumericFieldBlanks,AlphaBlank=lAlphaFieldBlanks, &
AlphaFieldNames=cAlphaFieldNames,NumericFieldNames=cNumericFieldNames)
IsNotOK=.false.
IsBlank=.false.
CALL VerifyName(cAlphaArgs(1),Fan%FanName,FanNum-1,IsNotOK,IsBlank,TRIM(cCurrentModuleObject)//'
Name')
IF (IsNotOK) THEN
ErrorsFound=.true.
IF (IsBlank) cAlphaArgs(1)='xxxxx'
ENDIF
Fan(FanNum)%FanName = cAlphaArgs(1)
Fan(FanNum)%FanType = cCurrentModuleObject
Fan(FanNum)%Schedule = cAlphaArgs(2)
Fan(FanNum)%SchedPtr =GetScheduleIndex(cAlphaArgs(2))
IF (Fan(FanNum)%SchedPtr == 0) THEN
IF (lAlphaFieldBlanks(2)) THEN
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//':
'//TRIM(cAlphaFieldNames(2))// &
' is required, missing for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
ELSE
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//': invalid
'//TRIM(cAlphaFieldNames(2))// &
' entered ='//TRIM(cAlphaArgs(2))// &
' for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
END IF
ErrorsFound=.true.
ENDIF
! Fan(FanNum)%Control = 'VARIABLEVOLUME'
Fan(FanNum)%FanType_Num=FanType_SimpleVAV
Fan(FanNum)%FanEff = rNumericArgs(1)
Fan(FanNum)%DeltaPress = rNumericArgs(2)
Fan(FanNum)%MaxAirFlowRate= rNumericArgs(3)
IF (Fan(FanNum)%MaxAirFlowRate == 0.0) THEN
CALL ShowWarningError(TRIM(cCurrentModuleObject)//'="'//TRIM(Fan(FanNum)%FanName)// &
'" has specified 0.0 max air flow rate. It will not be used in the simulation.')
ENDIF
Fan(FanNum)%MinAirFlowRate= rNumericArgs(4)
Fan(FanNum)%MotEff = rNumericArgs(5)
Fan(FanNum)%MotInAirFrac = rNumericArgs(6)
Fan(FanNum)%FanCoeff(1) = rNumericArgs(7)
Fan(FanNum)%FanCoeff(2) = rNumericArgs(8)
Fan(FanNum)%FanCoeff(3) = rNumericArgs(9)
Fan(FanNum)%FanCoeff(4) = rNumericArgs(10)
Fan(FanNum)%FanCoeff(5) = rNumericArgs(11)
IF (Fan(FanNum)%FanCoeff(1) == 0.0 .and. Fan(FanNum)%FanCoeff(2) == 0.0 .and. &
Fan(FanNum)%FanCoeff(3) == 0.0 .and. Fan(FanNum)%FanCoeff(4) == 0.0 .and. &
Fan(FanNum)%FanCoeff(5) == 0.0) THEN
CALL ShowWarningError('Fan Coefficients are all zero. No Fan power will be reported.')
CALL ShowContinueError('For '//TRIM(cCurrentModuleObject)//', Fan='//TRIM(cAlphaArgs(1)))
ENDIF
Fan(FanNum)%InletNodeNum = &
GetOnlySingleNode(cAlphaArgs(3),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Inlet,1,ObjectIsNotParent)
Fan(FanNum)%OutletNodeNum = &
GetOnlySingleNode(cAlphaArgs(4),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Outlet,1,ObjectIsNotParent)
9/27/13 21
EnergyPlus Module Developer's Guide Module Structure
DO ExhFanNum = 1, NumZoneExhFan
FanNum = NumSimpFan + NumVarVolFan + ExhFanNum
cCurrentModuleObject= 'Fan:ZoneExhaust'
CALL GetObjectItem(TRIM(cCurrentModuleObject),ExhFanNum,cAlphaArgs,NumAlphas, &
rNumericArgs,NumNums,IOSTAT, &
NumBlank=lNumericFieldBlanks,AlphaBlank=lAlphaFieldBlanks, &
AlphaFieldNames=cAlphaFieldNames,NumericFieldNames=cNumericFieldNames)
IsNotOK=.false.
IsBlank=.false.
CALL VerifyName(cAlphaArgs(1),Fan%FanName,FanNum-1,IsNotOK,IsBlank,TRIM(cCurrentModuleObject)//'
Name')
IF (IsNotOK) THEN
ErrorsFound=.true.
IF (IsBlank) cAlphaArgs(1)='xxxxx'
ENDIF
Fan(FanNum)%FanName = cAlphaArgs(1)
Fan(FanNum)%FanType = cCurrentModuleObject
Fan(FanNum)%Schedule = cAlphaArgs(2)
Fan(FanNum)%SchedPtr =GetScheduleIndex(cAlphaArgs(2))
IF (Fan(FanNum)%SchedPtr == 0) THEN
IF (lAlphaFieldBlanks(2)) THEN
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//':
'//TRIM(cAlphaFieldNames(2))// &
' is required, missing for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
ELSE
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//': invalid
'//TRIM(cAlphaFieldNames(2))// &
' entered ='//TRIM(cAlphaArgs(2))// &
' for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
END IF
ErrorsFound=.true.
ELSE
IF (HasFractionalScheduleValue(Fan(FanNum)%SchedPtr)) THEN
CALL ShowWarningError(TRIM(cCurrentModuleObject)//'="'//TRIM(Fan(FanNum)%FanName)// &
'" has fractional values in Schedule='//TRIM(cAlphaArgs(2))//'. Only 0.0 in the schedule
value turns the fan off.')
ENDIF
ENDIF
! Fan(FanNum)%Control = 'CONSTVOLUME'
Fan(FanNum)%FanType_Num=FanType_ZoneExhaust
Fan(FanNum)%FanEff = rNumericArgs(1)
Fan(FanNum)%DeltaPress = rNumericArgs(2)
Fan(FanNum)%MaxAirFlowRate= rNumericArgs(3)
Fan(FanNum)%MotEff = 1.0
Fan(FanNum)%MotInAirFrac = 1.0
Fan(FanNum)%MinAirFlowRate= 0.0
Fan(FanNum)%RhoAirStdInit = StdRhoAir
Fan(FanNum)%MaxAirMassFlowRate = Fan(FanNum)%MaxAirFlowRate * Fan(FanNum)%RhoAirStdInit
Fan(FanNum)%InletNodeNum = &
GetOnlySingleNode(cAlphaArgs(3),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Inlet,1,ObjectIsNotParent)
Fan(FanNum)%OutletNodeNum = &
GetOnlySingleNode(cAlphaArgs(4),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Outlet,1,ObjectIsNotParent)
9/27/13 22
EnergyPlus Module Developer's Guide Module Structure
DO OnOffFanNum = 1, NumOnOff
FanNum = NumSimpFan + NumVarVolFan + NumZoneExhFan + OnOffFanNum
cCurrentModuleObject= 'Fan:OnOff'
CALL GetObjectItem(TRIM(cCurrentModuleObject),OnOffFanNum,cAlphaArgs,NumAlphas, &
rNumericArgs,NumNums,IOSTAT, &
NumBlank=lNumericFieldBlanks,AlphaBlank=lAlphaFieldBlanks, &
AlphaFieldNames=cAlphaFieldNames,NumericFieldNames=cNumericFieldNames)
IsNotOK=.false.
IsBlank=.false.
CALL VerifyName(cAlphaArgs(1),Fan%FanName,FanNum-1,IsNotOK,IsBlank,TRIM(cCurrentModuleObject)//'
Name')
IF (IsNotOK) THEN
ErrorsFound=.true.
IF (IsBlank) cAlphaArgs(1)='xxxxx'
ENDIF
Fan(FanNum)%FanName = cAlphaArgs(1)
Fan(FanNum)%FanType = cCurrentModuleObject
Fan(FanNum)%Schedule = cAlphaArgs(2)
Fan(FanNum)%SchedPtr = GetScheduleIndex(cAlphaArgs(2))
IF (Fan(FanNum)%SchedPtr == 0) THEN
IF (lAlphaFieldBlanks(2)) THEN
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//':
'//TRIM(cAlphaFieldNames(2))// &
' is required, missing for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
ELSE
CALL ShowSevereError(RoutineName//TRIM(cCurrentModuleObject)//': invalid
'//TRIM(cAlphaFieldNames(2))// &
' entered ='//TRIM(cAlphaArgs(2))// &
' for '//TRIM(cAlphaFieldNames(1))//'='//TRIM(cAlphaArgs(1)))
END IF
ErrorsFound=.true.
ENDIF
! Fan(FanNum)%Control = 'ONOFF'
Fan(FanNum)%FanType_Num=FanType_SimpleOnOff
Fan(FanNum)%FanEff = rNumericArgs(1)
Fan(FanNum)%DeltaPress = rNumericArgs(2)
Fan(FanNum)%MaxAirFlowRate= rNumericArgs(3)
IF (Fan(FanNum)%MaxAirFlowRate == 0.0) THEN
CALL ShowWarningError(TRIM(cCurrentModuleObject)//'="'//TRIM(Fan(FanNum)%FanName)// &
'" has specified 0.0 max air flow rate. It will not be used in the simulation.')
ENDIF
! the following two structure variables are set here, as well as in InitFan, for the Heat Pump:Water
Heater object
! (Standard Rating procedure may be called before BeginEnvirFlag is set to TRUE, if so
MaxAirMassFlowRate = 0)
Fan(FanNum)%RhoAirStdInit = StdRhoAir
Fan(FanNum)%MaxAirMassFlowRate = Fan(FanNum)%MaxAirFlowRate * Fan(FanNum)%RhoAirStdInit
Fan(FanNum)%MotEff = rNumericArgs(4)
Fan(FanNum)%MotInAirFrac = rNumericArgs(5)
Fan(FanNum)%MinAirFlowRate= 0.0
Fan(FanNum)%InletNodeNum = &
GetOnlySingleNode(cAlphaArgs(3),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Inlet,1,ObjectIsNotParent)
Fan(FanNum)%OutletNodeNum = &
GetOnlySingleNode(cAlphaArgs(4),ErrorsFound,TRIM(cCurrentModuleObject),cAlphaArgs(1), &
NodeType_Air,NodeConnectionType_Outlet,1,ObjectIsNotParent)
9/27/13 23
EnergyPlus Module Developer's Guide Module Structure
cCurrentModuleObject= 'FanPerformance:NightVentilation'
NumNightVentPerf = GetNumObjectsFound(TRIM(cCurrentModuleObject))
END DO
DEALLOCATE(cAlphaArgs)
DEALLOCATE(cAlphaFieldNames)
DEALLOCATE(lAlphaFieldBlanks)
DEALLOCATE(cNumericFieldNames)
DEALLOCATE(lNumericFieldBlanks)
9/27/13 24
EnergyPlus Module Developer's Guide Module Structure
DEALLOCATE(rNumericArgs)
IF (ErrorsFound) THEN
CALL ShowFatalError(RoutineName//'Errors found in input. Program terminates.')
ENDIF
Do FanNum=1,NumFans
! Setup Report variables for the Fans
CALL SetupOutputVariable('Fan Electric Power[W]', Fan(FanNum)%FanPower,
'System','Average',Fan(FanNum)%FanName)
CALL SetupOutputVariable('Fan Delta Temp[C]', Fan(FanNum)%DeltaTemp,
'System','Average',Fan(FanNum)%FanName)
CALL SetupOutputVariable('Fan Electric Consumption[J]', Fan(FanNum)%FanEnergy,
'System','Sum',Fan(FanNum)%FanName, &
ResourceTypeKey='Electric',GroupKey='System', &
EndUseKey='Fans',EndUseSubKey=Fan(FanNum)%EndUseSubcategoryName)
END DO
DO OnOffFanNum = 1, NumOnOff
FanNum = NumSimpFan + NumVarVolFan + NumZoneExhFan + OnOffFanNum
CALL SetupOutputVariable('On/Off Fan Runtime Fraction', Fan(FanNum)%FanRuntimeFraction,
'System','Average', &
Fan(FanNum)%FanName)
END DO
RETURN
SUBROUTINE InitFan(FanNum,FirstHVACIteration)
! SUBROUTINE INFORMATION:
! AUTHOR Richard J. Liesen
! DATE WRITTEN February 1998
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Uses the status flags to trigger initializations.
! REFERENCES:
! na
! USE STATEMENTS:
USE DataSizing, ONLY: CurSysNum
USE DataAirLoop, ONLY: AirLoopControlInfo
9/27/13 25
EnergyPlus Module Developer's Guide Module Structure
! FLOW:
IF (MyOneTimeFlag) THEN
ALLOCATE(MyEnvrnFlag(NumFans))
ALLOCATE(MySizeFlag(NumFans))
MyEnvrnFlag = .TRUE.
MySizeFlag = .TRUE.
MyOneTimeFlag = .false.
END IF
CALL SizeFan(FanNum)
! Set the loop cycling flag
IF (Fan(FanNum)%Control == 'ONOFF') THEN
IF (CurSysNum > 0) THEN
AirLoopControlInfo(CurSysNum)%CyclingFan = .TRUE.
END IF
END IF
MySizeFlag(FanNum) = .FALSE.
END IF
!For all Fan inlet nodes convert the Volume flow to a mass flow
InNode = Fan(FanNum)%InletNodeNum
OutNode = Fan(FanNum)%OutletNodeNum
Fan(FanNum)%RhoAirStdInit = PsyRhoAirFnPbTdbW(StdBaroPress,20.0,0.0)
MyEnvrnFlag(FanNum) = .FALSE.
END IF
9/27/13 26
EnergyPlus Module Developer's Guide Module Structure
! Do the following initializations (every time step): This should be the info from
! the previous components outlets or the node data in this section.
! Do a check and make sure that the max and min available(control) flow is
! between the physical max and min for the Fan while operating.
InletNode = Fan(FanNum)%InletNodeNum
OutletNode = Fan(FanNum)%OutletNodeNum
! Load the node data in this section for the component simulation
!
!First need to make sure that the massflowrate is between the max and min avail.
IF (Fan(FanNum)%FanType .NE. 'ZONE EXHAUST FAN') THEN
Fan(FanNum)%InletAirMassFlowRate = Min(Node(InletNode)%MassFlowRate, &
Fan(FanNum)%MassFlowRateMaxAvail)
Fan(FanNum)%InletAirMassFlowRate = Max(Fan(FanNum)%InletAirMassFlowRate, &
Fan(FanNum)%MassFlowRateMinAvail)
ELSE ! zone exhaust fans - always run at the max
Fan(FanNum)%MassFlowRateMaxAvail = Fan(FanNum)%MaxAirMassFlowRate
Fan(FanNum)%MassFlowRateMinAvail = 0.0
Fan(FanNum)%InletAirMassFlowRate = Fan(FanNum)%MassFlowRateMaxAvail
END IF
RETURN
SUBROUTINE SizeFan(FanNum)
! SUBROUTINE INFORMATION:
! AUTHOR Fred Buhl
! DATE WRITTEN September 2001
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Obtains flow rates from the zone or system sizing arrays.
! REFERENCES:
! na
! USE STATEMENTS:
USE DataSizing
9/27/13 27
EnergyPlus Module Developer's Guide Module Structure
! na
FanMinAirFlowRate = 0.0
IF (Fan(FanNum)%MaxAirFlowRate == AutoSize) THEN
SELECT CASE(CurDuctType)
CASE(Main)
Fan(FanNum)%MaxAirFlowRate = FinalSysSizing(CurSysNum)%DesMainVolFlow
FanMinAirFlowRate = CalcSysSizing(CurSysNum)%SysAirMinFlowRat *
CalcSysSizing(CurSysNum)%DesMainVolFlow
CASE(Cooling)
Fan(FanNum)%MaxAirFlowRate = FinalSysSizing(CurSysNum)%DesCoolVolFlow
FanMinAirFlowRate = CalcSysSizing(CurSysNum)%SysAirMinFlowRat *
CalcSysSizing(CurSysNum)%DesCoolVolFlow
CASE(Heating)
Fan(FanNum)%MaxAirFlowRate = FinalSysSizing(CurSysNum)%DesHeatVolFlow
FanMinAirFlowRate = CalcSysSizing(CurSysNum)%SysAirMinFlowRat *
CalcSysSizing(CurSysNum)%DesHeatVolFlow
CASE(Other)
Fan(FanNum)%MaxAirFlowRate = FinalSysSizing(CurSysNum)%DesMainVolFlow
FanMinAirFlowRate = CalcSysSizing(CurSysNum)%SysAirMinFlowRat *
CalcSysSizing(CurSysNum)%DesMainVolFlow
CASE DEFAULT
Fan(FanNum)%MaxAirFlowRate = FinalSysSizing(CurSysNum)%DesMainVolFlow
FanMinAirFlowRate = CalcSysSizing(CurSysNum)%SysAirMinFlowRat *
CalcSysSizing(CurSysNum)%DesMainVolFlow
END SELECT
END IF
END IF
RETURN
9/27/13 28
EnergyPlus Module Developer's Guide Module Structure
! SUBROUTINE INFORMATION:
! AUTHOR Unknown
! DATE WRITTEN Unknown
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Converts design pressure rise and efficiency into fan power and temperature rise
! Constant fan pressure rise is assumed.
! REFERENCES:
! ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
! USE STATEMENTS:
! na
DeltaPress = Fan(FanNum)%DeltaPress
FanEff = Fan(FanNum)%FanEff
! For a Constant Volume Simple Fan the Max Flow Rate is the Flow Rate for the fan
Tin = Fan(FanNum)%InletAirTemp
Win = Fan(FanNum)%InletAirHumRat
RhoAir = Fan(FanNum)%RhoAirStdInit
MassFlow = MIN(Fan(FanNum)%InletAirMassFlowRate,Fan(FanNum)%MaxAirMassFlowRate)
MassFlow = MAX(MassFlow,Fan(FanNum)%MinAirMassFlowRate)
!
!Determine the Fan Schedule for the Time step
If( ( GetCurrentScheduleValue(Fan(FanNum)%SchedPtr)>0.0 .and. Massflow>0.0 .or. TurnFansOn .and.
Massflow>0.0) &
.and. .[Link] ) Then
!Fan is operating
Fan(FanNum)%FanPower = MassFlow*DeltaPress/(FanEff*RhoAir) ! total fan power
FanShaftPower = Fan(FanNum)%MotEff * Fan(FanNum)%FanPower ! power delivered to shaft
9/27/13 29
EnergyPlus Module Developer's Guide Module Structure
Else
!Fan is off and not operating no power consumed and mass flow rate.
Fan(FanNum)%FanPower = 0.0
FanShaftPower = 0.0
PowerLossToAir = 0.0
Fan(FanNum)%OutletAirMassFlowRate = 0.0
Fan(FanNum)%OutletAirHumRat = Fan(FanNum)%InletAirHumRat
Fan(FanNum)%OutletAirEnthalpy = Fan(FanNum)%InletAirEnthalpy
Fan(FanNum)%OutletAirTemp = Fan(FanNum)%InletAirTemp
! Set the Control Flow variables to 0.0 flow when OFF.
Fan(FanNum)%MassFlowRateMaxAvail = 0.0
Fan(FanNum)%MassFlowRateMinAvail = 0.0
End If
RETURN
END SUBROUTINE SimSimpleFan
SUBROUTINE SimVariableVolumeFan(FanNum)
! SUBROUTINE INFORMATION:
! AUTHOR Unknown
! DATE WRITTEN Unknown
! MODIFIED Phil Haves
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Converts design pressure rise and efficiency into fan power and temperature rise
! Constant fan pressure rise is assumed.
! Uses curves of fan power fraction vs. fan part load to determine fan power at
! off design conditions.
! REFERENCES:
! ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
! USE STATEMENTS:
! na
9/27/13 30
EnergyPlus Module Developer's Guide Module Structure
Real PartLoadFrac
REAL MaxFlowFrac !Variable Volume Fan Max Flow Fraction [-]
REAL MinFlowFrac !Variable Volume Fan Min Flow Fraction [-]
REAL FlowFrac !Variable Volume Fan Flow Fraction [-]
Real FanShaftPower ! power delivered to fan shaft
Real PowerLossToAir ! fan and motor loss to air stream (watts)
DeltaPress = Fan(FanNum)%DeltaPress
FanEff = Fan(FanNum)%FanEff
Tin = Fan(FanNum)%InletAirTemp
Win = Fan(FanNum)%InletAirHumRat
RhoAir = Fan(FanNum)%RhoAirStdInit
MassFlow = MIN(Fan(FanNum)%InletAirMassFlowRate,Fan(FanNum)%MaxAirMassFlowRate)
! MassFlow = MAX(MassFlow,Fan(FanNum)%MinAirMassFlowRate)
RETURN
END SUBROUTINE SimVariableVolumeFan
SUBROUTINE SimOnOffFan(FanNum)
9/27/13 31
EnergyPlus Module Developer's Guide Module Structure
! SUBROUTINE INFORMATION:
! AUTHOR Unknown
! DATE WRITTEN Unknown
! MODIFIED Shirey, May 2001
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Converts design pressure rise and efficiency into fan power and temperature rise
! Constant fan pressure rise is assumed.
! Uses curves of fan power fraction vs. fan part load to determine fan power at
! off design conditions.
! Same as simple (constant volume) fan, except added part-load curve input
! REFERENCES:
! ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
! USE STATEMENTS:
USE CurveManager, ONLY: CurveValue
DeltaPress = Fan(FanNum)%DeltaPress
FanEff = Fan(FanNum)%FanEff
Tin = Fan(FanNum)%InletAirTemp
Win = Fan(FanNum)%InletAirHumRat
RhoAir = Fan(FanNum)%RhoAirStdInit
MassFlow = MIN(Fan(FanNum)%InletAirMassFlowRate,Fan(FanNum)%MaxAirMassFlowRate)
MassFlow = MAX(MassFlow,Fan(FanNum)%MinAirMassFlowRate)
Fan(FanNum)%FanRuntimeFraction = 0.0
! The actual flow fraction is calculated from MassFlow and the MaxVolumeFlow * AirDensity
FlowFrac = MassFlow/(Fan(FanNum)%MaxAirMassFlowRate)
9/27/13 32
EnergyPlus Module Developer's Guide Module Structure
RETURN
END SUBROUTINE SimOnOffFan
SUBROUTINE SimZoneExhaustFan(FanNum)
! SUBROUTINE INFORMATION:
! AUTHOR Fred Buhl
! DATE WRITTEN Jan 2000
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Converts design pressure rise and efficiency into fan power and temperature rise
! Constant fan pressure rise is assumed.
! REFERENCES:
! ASHRAE HVAC 2 Toolkit, page 2-3 (FANSIM)
! USE STATEMENTS:
! na
9/27/13 33
EnergyPlus Module Developer's Guide Module Structure
DeltaPress = Fan(FanNum)%DeltaPress
FanEff = Fan(FanNum)%FanEff
! For a Constant Volume Simple Fan the Max Flow Rate is the Flow Rate for the fan
Tin = Fan(FanNum)%InletAirTemp
Win = Fan(FanNum)%InletAirHumRat
RhoAir = Fan(FanNum)%RhoAirStdInit
MassFlow = Fan(FanNum)%InletAirMassFlowRate
!
!Determine the Fan Schedule for the Time step
If( ( GetCurrentScheduleValue(Fan(FanNum)%SchedPtr)>0.0 .or. TurnFansOn ) &
.and. .[Link] ) Then
!Fan is operating
Fan(FanNum)%FanPower = MassFlow*DeltaPress/(FanEff*RhoAir) ! total fan power
PowerLossToAir = Fan(FanNum)%FanPower
Fan(FanNum)%OutletAirEnthalpy = Fan(FanNum)%InletAirEnthalpy + PowerLossToAir/MassFlow
! This fan does not change the moisture or Mass Flow across the component
Fan(FanNum)%OutletAirHumRat = Fan(FanNum)%InletAirHumRat
Fan(FanNum)%OutletAirMassFlowRate = MassFlow
Fan(FanNum)%OutletAirTemp = PsyTdbFnHW(Fan(FanNum)%OutletAirEnthalpy,Fan(FanNum)%OutletAirHumRat)
Else
!Fan is off and not operating no power consumed and mass flow rate.
Fan(FanNum)%FanPower = 0.0
PowerLossToAir = 0.0
Fan(FanNum)%OutletAirMassFlowRate = 0.0
Fan(FanNum)%OutletAirHumRat = Fan(FanNum)%InletAirHumRat
Fan(FanNum)%OutletAirEnthalpy = Fan(FanNum)%InletAirEnthalpy
Fan(FanNum)%OutletAirTemp = Fan(FanNum)%InletAirTemp
! Set the Control Flow variables to 0.0 flow when OFF.
Fan(FanNum)%MassFlowRateMaxAvail = 0.0
Fan(FanNum)%MassFlowRateMinAvail = 0.0
Fan(FanNum)%InletAirMassFlowRate = 0.0
End If
RETURN
END SUBROUTINE SimZoneExhaustFan
SUBROUTINE UpdateFan(FanNum)
! SUBROUTINE INFORMATION:
! AUTHOR Richard Liesen
! DATE WRITTEN April 1998
! MODIFIED na
! RE-ENGINEERED na
9/27/13 34
EnergyPlus Module Developer's Guide Module Structure
! METHODOLOGY EMPLOYED:
! Data is moved from the fan data structure to the fan outlet nodes.
! REFERENCES:
! na
! USE STATEMENTS:
! na
OutletNode = Fan(FanNum)%OutletNodeNum
InletNode = Fan(FanNum)%InletNodeNum
! Set the Node Flow Control Variables from the Fan Control Variables
Node(OutletNode)%MassFlowRateMaxAvail = Fan(FanNum)%MassFlowRateMaxAvail
Node(OutletNode)%MassFlowRateMinAvail = Fan(FanNum)%MassFlowRateMinAvail
RETURN
END Subroutine UpdateFan
SUBROUTINE ReportFan(FanNum)
! SUBROUTINE INFORMATION:
! AUTHOR Richard Liesen
! DATE WRITTEN April 1998
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! na
9/27/13 35
EnergyPlus Module Developer's Guide Module Structure
! REFERENCES:
! na
! USE STATEMENTS:
Use DataHVACGlobals, ONLY: TimeStepSys, FanElecPower
Fan(FanNum)%FanEnergy=Fan(FanNum)%FanPower*TimeStepSys*3600
Fan(FanNum)%DeltaTemp=Fan(FanNum)%OutletAirTemp - Fan(FanNum)%InletAirTemp
FanElecPower = Fan(FanNum)%FanPower
RETURN
END Subroutine ReportFan
! FUNCTION INFORMATION:
! AUTHOR Linda Lawrie
! DATE WRITTEN February 2006
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! na
! REFERENCES:
! na
! USE STATEMENTS:
USE InputProcessor, ONLY: FindItemInList
9/27/13 36
EnergyPlus Module Developer's Guide Module Structure
WhichFan=FindItemInList(FanName,Fan%FanName,NumFans)
IF (WhichFan /= 0) THEN
DesignVolumeFlowRate=Fan(WhichFan)%MaxAirFlowRate
ENDIF
IF (WhichFan == 0) THEN
CALL ShowSevereError('Could not find FanType="'//TRIM(FanType)//'" with Name="'//TRIM(FanName)//'"')
ErrorsFound=.true.
DesignVolumeFlowRate=-1000.
ENDIF
RETURN
! FUNCTION INFORMATION:
! AUTHOR Linda Lawrie
! DATE WRITTEN February 2006
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! na
! REFERENCES:
! na
! USE STATEMENTS:
USE InputProcessor, ONLY: FindItemInList
9/27/13 37
EnergyPlus Module Developer's Guide Module Structure
CALL GetFanInput
GetFanInputFlag=.false.
End If
WhichFan=FindItemInList(FanName,Fan%FanName,NumFans)
IF (WhichFan /= 0) THEN
NodeNumber=Fan(WhichFan)%InletNodeNum
ENDIF
IF (WhichFan == 0) THEN
CALL ShowSevereError('Could not find FanType="'//TRIM(FanType)//'" with Name="'//TRIM(FanName)//'"')
ErrorsFound=.true.
NodeNumber=0
ENDIF
RETURN
! FUNCTION INFORMATION:
! AUTHOR Linda Lawrie
! DATE WRITTEN February 2006
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! na
! REFERENCES:
! na
! USE STATEMENTS:
USE InputProcessor, ONLY: FindItemInList
WhichFan=FindItemInList(FanName,Fan%FanName,NumFans)
IF (WhichFan /= 0) THEN
NodeNumber=Fan(WhichFan)%OutletNodeNum
ENDIF
9/27/13 38
EnergyPlus Module Developer's Guide Module Structure
IF (WhichFan == 0) THEN
CALL ShowSevereError('Could not find FanType="'//TRIM(FanType)//'" with Name="'//TRIM(FanName)//'"')
ErrorsFound=.true.
NodeNumber=0
ENDIF
RETURN
! NOTICE
!
! Copyright © 1996-xxxx The Board of Trustees of the University of Illinois
! and The Regents of the University of California through Ernest Orlando Lawrence
! Berkeley National Laboratory. All rights reserved.
!
! Portions of the EnergyPlus software package have been developed and copyrighted
! by other individuals, companies and institutions. These portions have been
! incorporated into the EnergyPlus software package under license. For a complete
! list of contributors, see "Notice" located in EnergyPlus.f90.
!
! NOTICE: The U.S. Government is granted for itself and others acting on its
! behalf a paid-up, nonexclusive, irrevocable, worldwide license in this data to
! reproduce, prepare derivative works, and perform publicly and display publicly.
! Beginning five (5) years after permission to assert copyright is granted,
! subject to two possible five year renewals, the U.S. Government is granted for
! itself and others acting on its behalf a paid-up, non-exclusive, irrevocable
! worldwide license in this data to reproduce, prepare derivative works,
! distribute copies to the public, perform publicly and display publicly, and to
! permit others to do so.
!
! TRADEMARKS: EnergyPlus is a trademark of the US Department of Energy.
!
It may be that your new module or your new feature impacts existing code. Should that
happen, follow the guidance in the Programming Standard about positioning of “global data”.
Likewise, any code written should follow the guidance outlined in the Programming Standard.
9/27/13 39
EnergyPlus Module Developer's Guide Module Structure
doing a parallel effort of writing a simple input file for the legacy code while testing
results with your developing EnergyPlus transition code.
Programmers throughout time have had to deal with speed of code execution and it’s
an ongoing concern. However, compilers are pretty smart these days and, often,
can produce speedier code for the hardware platform than the programmer can
when he or she uses “speed up” tips. The EnergyPlus development team would
rather the code be more “readable” to all than to try to outwit the compilers for every
platform. First and foremost, the code is the true document of what EnergyPlus does
– other documents will try to explain algorithms and such but must really take a back
seat to the code itself.
However, many people may read the code – as developers, we should try to make it
as readable at first glance as possible. For a true example from the code and a
general indication of preferred style, take the case of the zone temperature update
equation. In the Engineering Reference document, the form is recognizable and
usual:
N surfaces
C z 3T t t 3 T t 2 t 1 T t 3 t
N sl N zones
Q i h AT m C T
i i si i p zi
m inf C pT m sys C pTsupply z
t 2
z
3
z
Tzt i 1 i 1 i 1
N surfaces
11 Cz
N zones
6 t
i 1
hi A m C
i 1
i p
m inf C p m sys C
Somewhat abbreviated here due to lack of page width but still recognizable from the
original. A better version would actually be:
ZT(ZoneNum)= (CoefSumhat - CoefAirrat*(-3.0*ZTM1(ZoneNum) + (3.0/2.0)*ZTM2(ZoneNum) &
- (1./3.)* ZTM3(ZoneNum))) &
/ ((11.0/6.0)*CoefAirrat+CoefSumha)
Whereas the natural tendency of programming would lead to the less readable:
ZT(ZoneNum)= (CoefSumhat + CoefAirrat*(3.0*ZTM1(ZoneNum) – 1.5*ZTM2(ZoneNum) + .333333* ZTM3(ZoneNum))) &
/ (1.83333*CoefAirrat+CoefSumha)
The final version is a correct translation (more or less) from the Engineering/usual
representation but much harder to look at in code and realize what is being
represented.
Speed of Execution
A critical consideration in speed of execution is character string comparisons.
These are typically quite slow and should not be used in the core routines (i.e. those
that are executed every zone or hvac time step). An alternative to string comparisons
is to define module-level integer parameters, equate a string to a parameter during
the initial subroutine call (e.g. GetInput), and then do integer comparisons through
the remainder of the calls to the module. Doing this does not deter readability, yet
assists in reducing execution time.
For example, in the module shown previously (Module Fans), the parameters for fan
types are set as Integers:
9/27/13 40
EnergyPlus Module Developer's Guide Module Structure
9/27/13 41
EnergyPlus Module Developer's Guide EnergyPlus Calling Structure
EnergyPlus
The HVAC part of EnergyPlus is divided into a number of simulation blocks. At this
point, there are blocks for the air system, the zone equipment, the plant equipment,
and the on-site electrical equipment. There will be simulation blocks for waste heat
supply and usage as well as electricity and gas. Within each HVAC time step, the
blocks are simulated repeatedly until the conditions on each side of each block
interface match up. The following calling tree represents the high level HVAC
simulation structure. It is schematic – not all routines are shown.
High Level HVAC Calling Tree (schematic – not all routines are shown)
Each of the “Manage” routines has a different structure, since the simulation to be
performed is different in each case. We will show schematic calling trees for several
of the “Manage” routines.
9/27/13 42
EnergyPlus Module Developer's Guide EnergyPlus Calling Structure
Air System Calling Tree (schematic – not all routines are shown)
9/27/13 43
EnergyPlus Module Developer's Guide EnergyPlus Calling Structure
Zone Equipment Calling Tree (schematic – not all routines are shown)
9/27/13 44
EnergyPlus Module Developer's Guide EnergyPlus Calling Structure
Let us return to our example new module NewHVACComponent. Since the module
gets its own input and output, adding the NewHVACComponent model to the
program simply means adding a call to the driver routine SimNewHVACComponent
from the correct place in EnergyPlus. In the simplest case, there is only one location
from which the driver routine should be called. In some cases, though, more than
one HVAC simulation block will need to use the new component model.
SimulateWaterCoilComponents, for instance, can be used in both zone equipment
and air systems for heating, reheating and cooling coils. In the air system simulation
it is called from two places: the main air system simulation, and the mixed air
simulation – the outside air duct might contain a separate cooling coil.
Let us assume that the NewHVACComponent will be part of the air system –
perhaps it is a solid desiccant wheel. Examining the air system calling tree we see
that SimAirLoopComponent is one routine that will invoke the new component, and -
if we want the component to possibly be in the outside air stream – then
SimOAComponent is the other routine that will need to call the new component
simulation. Generally, all that is involved is adding a new CASE statement to a
Fortran SELECT construct. For instance in SimAirLoopComponent this would look
like:
SELECT CASE(CompType_Num)
CASE(Fan_Simple_VAV) ! 'FAN:SIMPLE:VARIABLEVOLUME'
9/27/13 45
EnergyPlus Module Developer's Guide EnergyPlus Calling Structure
CALL SimulateFanComponents(…)
CASE(DXSystem) ! 'DXSYSTEM:AIRLOOP'
CALL SimDXCoolingSystem(…)
CASE(Furnace_UnitarySys) ! 'FURNACE:BLOWTHRU:HEATONLY',
! 'FURNACE:BLOWTHRU:HEATCOOL',
! 'UNITARYSYSTEM:BLOWTHRU:HEATONLY',
! 'UNITARYSYSTEM:BLOWTHRU:HEATCOOL'
! 'UNITARYSYSTEM:HEATPUMP:AIRTOAIR',
! 'UNITARYSYSTEM:HEATPUMP:WATERTOAIR'
CALL SimFurnace(…)
! Heat recovery
CASE(HeatXchngr) ! 'HEAT EXCHANGER:AIR TO AIR:FLAT PLATE'
CALL SimHeatRecovery(…)
! Ducts
CASE(Duct) ! 'DUCT'
CALL SimDuct(…)
9/27/13 46
EnergyPlus Module Developer's Guide EnergyPlus Calling Structure
DEFAULT
END SELECT
The new code is italicized. Do the same thing in SimOAComponent and you are
done! Note that “NEW HVAC COMPONENT” is the class name (keyword) for the
new component in the IDD file. The class names are converted to upper case in
EnergyPlus, so the CASE statement must have the class name in upper case. The
actual class name on the IDD file would probably be “New HVAC Component”.
If the new HVAC component is a piece of zone equipment – a cooled beam system,
for instance – then the zone equipment calling tree indicates that the call to
SimNewHVACComponent would be in SimZoneEquipment. If the new component is
a gas fired absorption chiller, the call would be in SimPlantEquip.
In every case, since NewHVACComponent is a new module, a USE statement must
be added to the calling subroutine. For instance in SimAirLoopComponent this would
look like:
SUBROUTINE SimAirLoopComponent(CompType, CompName, FirstHVACIteration,
LastSim)
! SUBROUTINE INFORMATION
! AUTHOR: Russ Taylor, Dan Fisher, Fred Buhl
! DATE WRITTEN: Oct 1997
! MODIFIED: Dec 1997 Fred Buhl
! RE-ENGINEERED: This is new code, not reengineered
! REFERENCES: None
! USE Statements
USE Fans, Only:SimulateFanComponents
USE WaterCoils, Only:SimulateWaterCoilComponents
USE MixedAir, Only:ManageOutsideAirSystem
USE NewHVACComponent, Only:SimNewHVACComponent
9/27/13 47
EnergyPlus Module Developer's Guide HVAC Network
HVAC Network
In EnergyPlus, the HVAC system and plant form a network (technically, a graph).
The individual pieces of equipment – the fans, coils, chillers, etc. – are connected
together by air ducts and fluid pipes. In EnergyPlus nomenclature, the air and fluid
circuits are called loops. Specifying how an individual system and plant are
connected is done in the EnergyPlus input (IDF) file. The overall structure of the
network is defined with Branch and Connector objects. The detail is filled with
components and their inlet and outlet nodes. A Branch consists of one or more
components arranged sequentially along a pipe or duct. A Connector specifies how
three or more branches are connected through a Splitter or Mixer. Nodes connect
components along a branch: the outlet node of one component is the inlet node of
the next downstream component. The nodes represent conditions at a point on a
loop. Each component has one or more inlet and outlet nodes, depending on how
many loops it interacts with. A fan, for instance, has one inlet node and one outlet
node, since it interacts with a single air loop. A water coil will have 2 inlet and 2 outlet
nodes, since it interacts with an air and a fluid loop. Figure 1 shows a diagram of an
EnergyPlus HVAC input.
3 Zone Dual Duct System
Plant Supply Side
Supply Fan Supply Air Splitter CW Pump Cooling Loop
("Look Ahead") 34
5 3 Splitter
2 CC Plant Demand Side
Cooling Loop 36 37 35
3 33 50 51 Chiller #1 Chiller # 2
Bypass
Purchased
Bypass Cooling
HC 32 31 40 38 39 49
1 4 6 3 Mixer
Plant Demand Side
24
Heating Loop
7 11
26
Zone 1 8 27 41 2 Split- 42 43 2 Mix-44
Cond Cond
Bypass
Damper 28 29 40 45
Purchased
Heating 48 46
Return Air Mixer
20 19 18 Mixing 13
Damper Plant Supply Side 47
Heating Loop
23 22 21 Mixing 14
Damper
Cond Supply Side Loop
As an illustration of how such a network is built up on the IDF, here is the section of
the IDF that describes the supply fan, splitter, and heating and cooling coil section of
the dual duct air system.
BranchList,
9/27/13 48
EnergyPlus Module Developer's Guide HVAC Network
ConnectorList,
Dual Duct Connectors, !- Name
Connector:Splitter, !- Connector 1 Object Type
DualDuctAirSplitter; !- Connector 1 Name
NodeList,
Zone Equipment Inlet Node List, !- Name
Main Hot Air Inlet, !- Node 1 Name
Main Cold Air Inlet; !- Node 2 Name
NodeList,
Air Loop Outlet Node List, !- Name
Heating Coil Outlet Node,!- Node 1 Name
Cooling Coil Outlet Node;!- Node 2 Name
Branch,
Air Loop Main Branch, !- Name
autosize, !- Maximum Flow Rate {m3/s}
Fan:ConstantVolume, !- Component 1 Object Type
Supply Fan 1, !- Component 1 Name
Supply Fan Inlet Node, !- Component 1 Inlet Node Name
Supply Fan Outlet Node, !- Component 1 Outlet Node Name
PASSIVE; !- Component 1 Branch Control Type
Branch,
Heating Coil Air Sys Branch, !- Name
autosize, !- Maximum Flow Rate {m3/s}
Coil:Heating:Water, !- Component 1 Object Type
Main Heating Coil, !- Component 1 Name
Heating Coil Inlet Node, !- Component 1 Inlet Node Name
Heating Coil Outlet Node,!- Component 1 Outlet Node Name
ACTIVE; !- Component 1 Branch Control Type
Branch,
Cooling Coil Air Sys Branch, !- Name
autosize, !- Maximum Flow Rate {m3/s}
Coil:Cooling:Water, !- Component 1 Object Type
Simple Cooling Coil, !- Component 1 Name
Cooling Coil Inlet Node, !- Component 1 Inlet Node Name
Cooling Coil Outlet Node,!- Component 1 Outlet Node Name
ACTIVE; !- Component 1 Branch Control Type
Connector:Splitter,
DualDuctAirSplitter, !- Name
Air Loop Main Branch, !- Inlet Branch Name
Heating Coil Air Sys Branch, !- Outlet Branch 1 Name
Cooling Coil Air Sys Branch; !- Outlet Branch 2 Name
Fan:ConstantVolume,
Supply Fan 1, !- Name
FanAndCoilAvailSched, !- Availability Schedule Name
0.7, !- Fan Efficiency
600.0, !- Pressure Rise {Pa}
autosize, !- Maximum Flow Rate {m3/s}
0.9, !- Motor Efficiency
1.0, !- Motor In Airstream Fraction
Supply Fan Inlet Node, !- Fan Inlet Node Name
Supply Fan Outlet Node; !- Fan Outlet Node Name
9/27/13 49
EnergyPlus Module Developer's Guide HVAC Network
Coil:Cooling:Water,
Simple Cooling Coil, !- Name
CoolingCoilAvailSched, !- Availability Schedule Name
autosize, !- Design Water Flow Rate {m3/s}
autosize, !- Design Air Flow Rate {m3/s}
autosize, !- Design Inlet Water Temperature {C}
autosize, !- Design Inlet Air Temperature {C}
autosize, !- Design Outlet Air Temperature {C}
autosize, !- Design Inlet Air Humidity Ratio {kg-H2O/kg-air}
autosize, !- Design Outlet Air Humidity Ratio {kg-H2O/kg-air}
Cooling Coil Water Inlet Node, !- Water Inlet Node Name
Cooling Coil Water Outlet Node, !- Water Outlet Node Name
Cooling Coil Inlet Node, !- Air Inlet Node Name
Cooling Coil Outlet Node,!- Air Outlet Node Name
SimpleAnalysis, !- Type of Analysis
CrossFlow; !- Heat Exchanger Configuration
AirLoopHVAC:ZoneSplitter,
ZoneColdAirSupplySplitter, !- Name
Main Cold Air Inlet, !- Inlet Node Name
Zone 1 Dual Duct Cold Inlet, !- Outlet 1 Node Name
Zone 2 Dual Duct Cold Inlet, !- Outlet 2 Node Name
Zone 3 Dual Duct Cold Inlet; !- Outlet 3 Node Name
AirLoopHVAC:ZoneSplitter,
ZoneHotAirSupplySplitter,!- Name
Main Hot Air Inlet, !- Inlet Node Name
Zone 1 Dual Duct Hot Inlet, !- Outlet 1 Node Name
Zone 2 Dual Duct Hot Inlet, !- Outlet 2 Node Name
Zone 3 Dual Duct Hot Inlet; !- Outlet 3 Node Name
AirLoopHVAC:ZoneMixer,
ZoneReturnAirMixer, !- Name
Return Air Mixer Outlet, !- Outlet Node Name
Zone 1 Outlet Node, !- Inlet 1 Node Name
Zone 2 Outlet Node, !- Inlet 2 Node Name
Zone 3 Outlet Node; !- Inlet 3 Node Name
Coil:Heating:Water,
Main Heating Coil, !- Name
FanAndCoilAvailSched, !- Availability Schedule Name
autosize, !- U-Factor Times Area Value {W/K}
autosize, !- Maximum Water Flow Rate {m3/s}
Heating Coil Water Inlet,!- Water Inlet Node Name
Heating Coil Water Outlet, !- Water Outlet Node Name
Heating Coil Inlet Node, !- Air Inlet Node Name
Heating Coil Outlet Node,!- Air Outlet Node Name
UFactorTimesAreaAndDesignWaterFlowRate, !- Performance Input Method
autosize, !- Nominal Capacity {W}
82.2, !- Design Inlet Water Temperature {C}
16.6, !- Design Inlet Air Temperature {C}
71.1, !- Design Outlet Water Temperature {C}
32.2; !- Design Outlet Air Temperature {C}
Controller:WaterCoil,
Main Cooling Coil Controller, !- Name
Temperature, !- Control Variable
Reverse, !- Action
FLOW, !- Actuator Variable
Cooling Coil Outlet Node,!- Sensor Node Name
Cooling Coil Water Inlet Node, !- Actuator Node Name
0.001, !- Controller Convergence Tolerance {deltaC}
9/27/13 50
EnergyPlus Module Developer's Guide HVAC Network
Controller:WaterCoil,
Main Heating Coil Controller, !- Name
Temperature, !- Control Variable
Normal, !- Action
FLOW, !- Actuator Variable
Heating Coil Outlet Node,!- Sensor Node Name
Heating Coil Water Inlet,!- Actuator Node Name
0.01, !- Controller Convergence Tolerance {deltaC}
autosize, !- Maximum Actuated Flow {m3/s}
0.0; !- Minimum Actuated Flow {m3/s}
Obviously, the creation of such a system/plant network description is best handled by
a graphical user interface (GUI). However, for testing purposes a developer may
have to create the input for a component by hand and insert it into an existing IDF.
Then the developer must be careful to choose unique names for the branches and
nodes and make sure the entire network makes physical sense.
In the EnergyPlus data structure, the nodes are where each component model gets
its input and where it places its output. The module DataLoopNode contains all the
node related data. In particular, the array Node contains the state variables and
mass flows for all the nodes in the problem being simulated.
! Valid Fluid Types for Nodes
INTEGER, PARAMETER :: NodeType_Unknown = 0 ! 'blank'
INTEGER, PARAMETER :: NodeType_Air = 1 ! 'Air'
INTEGER, PARAMETER :: NodeType_Water = 2 ! 'Water'
INTEGER, PARAMETER :: NodeType_Steam = 3 ! 'Steam'
INTEGER, PARAMETER :: NodeType_Electric= 4 ! 'Electric'
9/27/13 51
EnergyPlus Module Developer's Guide HVAC Network
TYPE NodeData
INTEGER :: FluidType = 0 ! must be one of the valid parameters
INTEGER :: FluidIndex = 0 ! For Fluid Properties
REAL(r64) :: Temp = 0.d0 ! {C}
REAL(r64) :: TempMin = 0.d0 ! {C}
REAL(r64) :: TempMax = 0.d0 ! {C}
REAL(r64) :: TempSetPoint = SensedNodeFlagValue ! {C}
REAL(r64) :: TempLastTimestep = 0.d0 ! [C} DSU
REAL(r64) :: MassFlowRateRequest = 0.d0 ! {kg/s} DSU
REAL(r64) :: MassFlowRate = 0.d0 ! {kg/s}
REAL(r64) :: MassFlowRateMin = 0.d0 ! {kg/s}
REAL(r64) :: MassFlowRateMax = SensedNodeFlagValue ! {kg/s}
REAL(r64) :: MassFlowRateMinAvail = 0.d0 ! {kg/s}
REAL(r64) :: MassFlowRateMaxAvail = 0.d0 ! {kg/s}
REAL(r64) :: MassFlowRateSetPoint = 0.d0 ! {kg/s}
REAL(r64) :: Quality = 0.d0 ! {0.0-1.0 vapor fraction/percent}
REAL(r64) :: Press = 0.d0 ! {Pa}
REAL(r64) :: Enthalpy = 0.d0 ! {J/kg}
REAL(r64) :: EnthalpyLastTimestep = 0.d0 ! {J/kg} DSU for steam?
REAL(r64) :: HumRat = 0.d0 ! {}
REAL(r64) :: HumRatMin = SensedNodeFlagValue ! {}
REAL(r64) :: HumRatMax = SensedNodeFlagValue ! {}
REAL(r64) :: HumRatSetPoint = SensedNodeFlagValue ! {}
REAL(r64) :: TempSetPointHi = SensedNodeFlagValue ! {C}
REAL(r64) :: TempSetPointLo = SensedNodeFlagValue ! {C}
REAL(r64) :: Height = -1.d0 ! {m}
! Following are for Outdoor Air Nodes "read only"
REAL(r64) :: OutAirDryBulb = 0.d0 ! {C}
LOGICAL :: EMSOverrideOutAirDryBulb = .FALSE. ! if true, the EMS is calling to override outdoor
air node drybulb setting
REAL(r64) :: EMSValueForOutAirDryBulb = 0.d0 ! value EMS is directing to use for outdoor air
node's drybulb {C}
REAL(r64) :: OutAirWetBulb = 0.d0 ! {C}
LOGICAL :: EMSOverrideOutAirWetBulb = .FALSE. ! if true, the EMS is calling to override outdoor
air node wetbulb setting
REAL(r64) :: EMSValueForOutAirWetBulb = 0.d0 ! value EMS is directing to use for outdoor air
node's wetbulb {C}
! Contaminant
REAL(r64) :: CO2 = 0.d0 ! {ppm}
REAL(r64) :: CO2SetPoint = 0.d0 ! {ppm}
END TYPE NodeData
9/27/13 52
EnergyPlus Module Developer's Guide HVAC Network
TYPE MoreNodeData
REAL(r64) :: RelHumidity = 0.d0 ! {%}
REAL(r64) :: ReportEnthalpy = 0.d0 ! specific enthalpy calculated at the HVAC timestep
[J/kg]
REAL(r64) :: VolFlowRateStdRho = 0.d0 ! volume flow rate at standard density [m3/s]
REAL(r64) :: VolFlowRateCrntRho = 0.d0 ! volume flow rate at current density, only used for
air nodes [m3/s]
REAL(r64) :: WetbulbTemp = 0.d0 ! wetbulb temperature [C]
REAL(r64) :: AirDensity = 0.d0 ! reported air density at standard density [kg/m3]
END TYPE MoreNodeData
TYPE (NodeData), ALLOCATABLE, DIMENSION(:) :: Node !dim to num nodes in SimHVAC
TYPE (NodeData) :: DefaultNodeValues= &
NodeData(0, & ! FluidType
0, & ! FluidIndex
0.0D0, & ! Temp {C}
0.0D0, & ! TempMin {C}
0.0D0, & ! TempMax {C}
SensedNodeFlagValue, & ! TempSetPoint {C}
0.0D0, & ! TempLastTimeStep {C}
0.0D0, & ! MassFlowRateRequest {kg/s}
0.0D0, & ! MassFlowRate {kg/s}
0.0D0, & ! MassFlowRateMin {kg/s}
0.0D0, & ! MassFlowRateMax {kg/s}
0.0D0, & ! MassFlowRateMinAvail {kg/s}
0.0D0, & ! MassFlowRateMaxAvail {kg/s}
0.0D0, & ! MassFlowRateSetPoint {kg/s}
0.0D0, & ! Quality {0.0-1.0 vapor fraction/percent}
0.0D0, & ! Press {Pa} REAL(r64) ::
0.0D0, & ! Enthalpy {J/kg}
0.0D0, & ! EnthalpyLastTimeStep {J/kg}
0.0D0, & ! HumRat {}
SensedNodeFlagValue, & ! HumRatMin {}
SensedNodeFlagValue, & ! HumRatMax {}
SensedNodeFlagValue, & ! HumRatSetPoint {}
SensedNodeFlagValue, & ! TempSetPointHi {C}
SensedNodeFlagValue, & ! TempSetPointLo {C}
-1.0D0, & ! Height {m}
0.0D0, & ! OutAirDryBulb {C}
.FALSE., & ! EMSOverrideOutAirDryBulb
0.0D0, & ! EMSValueForOutAirDryBulb {C}
0.0D0, & ! OutAirWetBulb {C}
.FALSE., & ! EMSOverrideOutAirWetBulb
0.0D0, & ! EMSValueForOutAirWetBulb {C}
0.0D0, & ! CO2 {ppm}
0.0D0) ! CO2 setpoint {ppm}
TYPE (MoreNodeData), ALLOCATABLE, DIMENSION(:) :: MoreNodeInfo
Getting Nodes
9/27/13 53
EnergyPlus Module Developer's Guide HVAC Network
file, data from the inlet nodes, and any schedule values. In addition, these data structure(s)
store the results of the calculation.
3. The component outlet nodes – data is moved from the internal data structure(s) to the outlet
nodes at the completion of each component simulation.
The data flows from the inlet nodes into the component internal data structure(s) and
then into the outlet nodes. Let us see how this works in our example module Fans.
At the start of the module, the component internal data structure is defined.
TYPE FanEquipConditions
CHARACTER(len=MaxNameLength) :: FanName ! Name of the fan
CHARACTER(len=MaxNameLength) :: FanType ! Type of Fan ie. Simple, Vane axial, Centrifugal, etc.
CHARACTER(len=MaxNameLength) :: Schedule ! Fan Operation Schedule
CHARACTER(len=MaxNameLength) :: Control ! ie. Const Vol, Variable Vol
Integer :: SchedPtr ! Pointer to the correct schedule
REAL(r64) :: InletAirMassFlowRate !MassFlow through the Fan being Simulated [kg/Sec]
REAL(r64) :: OutletAirMassFlowRate
REAL(r64) :: MaxAirFlowRate !Max Specified Volume Flow Rate of Fan [m^3/sec]
REAL(r64) :: MinAirFlowRate !Min Specified Volume Flow Rate of Fan [m^3/sec]
REAL(r64) :: MaxAirMassFlowRate ! Max flow rate of fan in kg/sec
REAL(r64) :: MinAirMassFlowRate ! Min flow rate of fan in kg/sec
REAL(r64) :: InletAirTemp
REAL(r64) :: OutletAirTemp
REAL(r64) :: InletAirHumRat
REAL(r64) :: OutletAirHumRat
REAL(r64) :: InletAirEnthalpy
REAL(r64) :: OutletAirEnthalpy
REAL(r64) :: FanPower !Power of the Fan being Simulated [kW]
REAL(r64) :: FanEnergy !Fan energy in [kJ]
REAL(r64) :: DeltaTemp !Temp Rise across the Fan [C]
REAL(r64) :: DeltaPress !Delta Pressure Across the Fan [N/M^2]
REAL(r64) :: FanEff !Fan total efficiency; motor and mechanical
REAL(r64) :: MotEff !Fan motor efficiency
REAL(r64) :: MotInAirFrac !Fraction of motor heat entering air stream
REAL(r64), Dimension(5):: FanCoeff !Fan Part Load Coefficients to match fan type
! Mass Flow Rate Control Variables
REAL(r64) :: MassFlowRateMaxAvail
REAL(r64) :: MassFlowRateMinAvail
INTEGER :: InletNodeNum
INTEGER :: OutletNodeNum
END TYPE FanEquipConditions
In this case, there is only one structure that stores all of the fan data. We could have
chosen to divide this rather large structure up into separate structures – one for input
file data, one for inlet data, and one for outlet data, for instance. Note that in Fortran
90 structures are called defined type. The TYPE – END TYPE construct defines a
new data structure. Then an allocatable array Fan of the defined type is created. This
one-dimensional array will contain an entry for each fan in the problem.
The internal data array is allocated (sized) in the “GetInput” routine GetFanInput.
NumSimpFan = GetNumObjectsFound('FAN:SIMPLE:CONSTVOLUME')
NumVarVolFan = GetNumObjectsFound('FAN:SIMPLE:VARIABLEVOLUME')
NumOnOff = GetNumObjectsFound('FAN:SIMPLE:ONOFF')
NumZoneExhFan = GetNumObjectsFound('ZONE EXHAUST FAN')
NumFans = NumSimpFan + NumVarVolFan + NumZoneExhFan+NumOnOff
IF ([Link].0) ALLOCATE(Fan(NumFans))
9/27/13 54
EnergyPlus Module Developer's Guide HVAC Network
The remainder of the “GetInput” routine moves input file data into the Fan array. The
“Init” routine transfers data from the inlet nodes into the same array in preparation for
performing the calculation.
! Load the node data in this section for the component simulation
!
!First need to make sure that the massflowrate is between the max and min avail.
IF (Fan(FanNum)%FanType_Num /= FanType_ZoneExhaust ) THEN
Fan(FanNum)%InletAirMassFlowRate = Min(Node(InletNode)%MassFlowRate, &
Fan(FanNum)%MassFlowRateMaxAvail)
Fan(FanNum)%InletAirMassFlowRate = Max(Fan(FanNum)%InletAirMassFlowRate, &
Fan(FanNum)%MassFlowRateMinAvail)
ELSE ! zone exhaust fans - always run at the max
Fan(FanNum)%MassFlowRateMaxAvail = Fan(FanNum)%MaxAirMassFlowRate
Fan(FanNum)%MassFlowRateMinAvail = 0.0
Fan(FanNum)%InletAirMassFlowRate = Fan(FanNum)%MassFlowRateMaxAvail
IF (Fan(FanNum)%EMSMaxMassFlowOverrideOn) Fan(FanNum)%InletAirMassFlowRate = &
MIN(Fan(FanNum)%EMSAirMassFlowValue,Fan(FanNum)%MassFlowRateMaxAvail)
END IF
The “Calc” routines do the actual component simulation. All the data they need has
been stored in the internal data array ready to be used. The results of the calculation
are, in this case, stored in the same array. The “Calc” routine always does pure
calculation/simulation – it never retrieves or stores data.
9/27/13 55
EnergyPlus Module Developer's Guide HVAC Network
DeltaPress = Fan(FanNum)%DeltaPress
FanEff = Fan(FanNum)%FanEff
! For a Constant Volume Simple Fan the Max Flow Rate is the Flow Rate for the fan
Tin = Fan(FanNum)%InletAirTemp
Win = Fan(FanNum)%InletAirHumRat
RhoAir = Fan(FanNum)%RhoAirStdInit
MassFlow = MIN(Fan(FanNum)%InletAirMassFlowRate,Fan(FanNum)%MaxAirMassFlowRate)
MassFlow = MAX(MassFlow,Fan(FanNum)%MinAirMassFlowRate)
!
!Determine the Fan Schedule for the Time step
If( ( GetCurrentScheduleValue(Fan(FanNum)%SchedPtr)>0.0 .and. Massflow>0.0 .or. TurnFansOn .and.
Massflow>0.0) &
.and. .[Link] ) Then
!Fan is operating
Fan(FanNum)%FanPower = MassFlow*DeltaPress/(FanEff*RhoAir) ! total fan power
FanShaftPower = Fan(FanNum)%MotEff * Fan(FanNum)%FanPower ! power delivered to shaft
PowerLossToAir = FanShaftPower + (Fan(FanNum)%FanPower - FanShaftPower) * &
Fan(FanNum)%MotInAirFrac
Fan(FanNum)%OutletAirEnthalpy = Fan(FanNum)%InletAirEnthalpy + PowerLossToAir/MassFlow
! This fan does not change the moisture or Mass Flow across the component
Fan(FanNum)%OutletAirHumRat = Fan(FanNum)%InletAirHumRat
Fan(FanNum)%OutletAirMassFlowRate = MassFlow
Fan(FanNum)%OutletAirTemp = PsyTdbFnHW (Fan(FanNum)%OutletAirEnthalpy,Fan(FanNum)%OutletAirHumRat)
Else
!Fan is off and not operating no power consumed and mass flow rate.
Fan(FanNum)%FanPower = 0.0
FanShaftPower = 0.0
PowerLossToAir = 0.0
Fan(FanNum)%OutletAirMassFlowRate = 0.0
Fan(FanNum)%OutletAirHumRat = Fan(FanNum)%InletAirHumRat
Fan(FanNum)%OutletAirEnthalpy = Fan(FanNum)%InletAirEnthalpy
Fan(FanNum)%OutletAirTemp = Fan(FanNum)%InletAirTemp
! Set the Control Flow variables to 0.0 flow when OFF.
Fan(FanNum)%MassFlowRateMaxAvail = 0.0
Fan(FanNum)%MassFlowRateMinAvail = 0.0
End If
Finally, the “Update” routine (UpdateFan) moves the results from the internal data
array into the outlet node(s).
OutletNode = Fan(FanNum)%OutletNodeNum
InletNode = Fan(FanNum)%InletNodeNum
! Set the Node Flow Control Variables from the Fan Control Variables
Node(OutletNode)%MassFlowRateMaxAvail = Fan(FanNum)%MassFlowRateMaxAvail
Node(OutletNode)%MassFlowRateMinAvail = Fan(FanNum)%MassFlowRateMinAvail
Certain data items must always be transferred from inlet nodes to outlet nodes even
if the data item is unaltered by the component model. The data items that must be
transferred are:
1. Temp
2. HumRat
3. Enthalpy
9/27/13 56
EnergyPlus Module Developer's Guide HVAC Network
4. Press
5. MassFlowRate
6. MassFlowRateMaxAvail
7. MassFlowRateMinAvail
Beginning with Version 7.0, EnergyPlus’s plant routines were reengineered and this section
discusses protocols for how component models should interact with plant loop modeling.
Component models that reject or obtain heat from a liquid fluid stream, such as hot or chilled
water, condenser water, and steam (but not refrigeration), are “plant components” that will
need to interface with the central plant solver routines. This section describes a number of
utility routines and concepts for developers of plant component models.
The node structure discussed above is reused for plant. Each component model related to
plant has inlet and outlet nodes that describe how it is connected to the loop. Many of the
routines pass in node indexes as arguments as well as other indexes into the main plant data
structure.
Plant Loop Data Structure
For plant components, in addition to inlet nodes, outlet nodes, and the component’s internal
data structure, there is a fourth aspect to data flow that includes central data structures
defined in DataPlant.f90. The main data structure is called PlantLoop. Both condenser
loops and plant loops are treated the same and share the PlantLoop structure. The
PlantLoop structure stores information on the loop topology as well as various control and
dispatch input and operational data. The data structure is nested and component
information is stored at this level:
PlantLoop()%LoopSide()%Branch()%Comp()%xxx
Where,
PlantLoop is the top level and will be sized to the total number of plant and condenser
loops.
LoopSide is the second level and will be sized to two, one loop side is for the demand side
and one loop side is for the supply side.
Branch is the third level and will be sized to the total number of branches on that loop side
Comp is the fourth level and will be sized to the total number of components on the branch.
There are four indices that indentify each component’s location for each of the plant loops it is
connected with: : loop number, loop side number, branch number, and component number.
A water cooled chiller will be connected to two loops and so the component itself will appear
twice in the data structure and one set of indices will identify its location on the chilled water
loop while a second set of indices will locate it on the condenser loop.
Initialization
Component models should store indexes that describe their location in the plant data
structure. To obtain these indices, call the routine ScanPlantLoopsForObject once for
each instance of the component. The component model’s data structure should store a set of
indices for: loop number, loop side number, branch number, and component number. If the
component is connected to more than one plant loop, then there should be set of indices and
a call to ScanPlantLoopsForObject for each plant loop it is connected to. If a component
model only has a single node name, the required indices can be similarly obtained using the
a call to ScanPlantLoopsForNodeNum.
Component models generally need to do a thorough re-initialization at the start of each new
environment. Component models can call InitComponentNodes to coordinate initializing
9/27/13 57
EnergyPlus Module Developer's Guide HVAC Network
inlet and outlet nodes. This routine has arguments for the minimum and maximum flow and
these should be mass flow rates, in kg/s, that correspond to the “hardware” limits of the
device.
Some components are connected to more than one plant loop creating dependencies
between loops. For example a water-cooled chiller is connected to both a chilled water loop
and a condenser water loop. The chilled water loop places demands on the condenser water
loop so it is beneficial to model the chilled water loop’s supply side before the condenser
water loop’s demand side is modeled. An initialization routine called
InterConnectTwoPlantLoopSides is used by the component models to inform the
central plant routines of these situations. One call to this routine describes a connection
between two half-loops. The component model developer needs to decide which of the half
loops places demands on the other and set the logical argument Loop1DemandsOnLoop2
appropriately. The central plant routines use this information to determine an appropriate
calling order for simulating individual half-loops.
Sizing
Component models need to interact with centralized routines that relate to sizes. This
section provides an overview of how EnergyPlus performs automatic sizing of plant systems
and components so that the broader context can be understood when implementing plant
components. As of EnergyPlus version 7, the plant sizing methods were changed
significantly. We first describe some of the variables involved, then describe the overall
process steps, and finally discuss implications for component models.
The following variables are used to help control plant sizing:
PlantSizeNotComplete This public logical flag is declared in DataPlant. It starts
out FALSE TRUE and is set to TRUE FALSE only after all plant sizing actions have
been completed and finalized.
PlantSizesOkayToFinalize This public logical flag is declared in DataPlant. It
starts out false FALSE and is set to TRUE after the main iterative phase of sizing is
completed but before the final finishing passes are made. Component models
should delay final reporting and filling of autosized values until this is set to TRUE.
The -9999 values that indicate an autosized variable are not filled until this is TRUE.
Calls to report the outcome of sizing are not made until this is TRUE.
InitLoopEquip This logical flag is passed as an argument with SimPlantEquip
and carries through to the main simulation calls for component models. This
argument is set to TRUE when the plant sizing is being conducted. The component
model needs to handle this argument such that when TRUE the get input,
initialization and sizing routines are run, but the calculation routine does not. When
TRUE most supply side component models need to return values for the minimum,
maximum, and optimal capacities (in terms of loop loads that the device can meet).
GetSizingFactor This logical flag is passed as an argument with
SimPlantEquip and carries through to the main simulation calls for component
models. This is arguementargument set TRUE during some portions of the plant
sizing calls and signals the intent to obtain the value of a component-level sizing
factor. When this argument is TRUE, InitLoopEquip will also be TRUE. It can
be ignored if the component model has no component-level sizing factor as part of its
input. If the component does offer a sizing factor, then the implementation needs to
handle this argument such that when TRUE the model returns the value of the
SizingFactor as an argument to the simulation routine that is called from
SimPlantEquip.
CurLoopNum This public integer variable is declared in DataSizing. It is used to
communicate to the component models which of the plant loops is actively being
sized at the moment.
9/27/13 58
EnergyPlus Module Developer's Guide HVAC Network
LoopNum and LoopSide These arguments are optional to the main simulation
routine
Plant sizing routines use the approach outlined in the following steps. These steps occur at a
point during the program’s procedural flow when: zone and system sizing is completed,
much of the plant loop input has been read in and processed but the main plant manager is
being called for the first time, none of the pure plant component’s simulation routines have
yet been called (but components on the air side may have been), and an initial attempt at
determining loop calling order has been made in SetupInitialPlantCallingOrder.
1. Initialize the indices that map between the central plant sizing data structures and the
PlantLoop data structure. This uses the subroutine called
InitOneTimePlantSizingInfo. This ensures that the
PlantLoop%PlantSizNum variable is filled before any component models are
called.
(steps 2 thru 4 are sequentially repeated for four iterations)
2. Call each component model in calling order. InitLoopEquip is TRUE. The
components on each half loop are called in flow order. Each half loop in the model is
called in the order set up for simulation. These calls are typically the first time certain
component models have been called and should trigger input processing and plant
loop topology processing including loop interconnections.
3. Revise the calling order for the sequence with which the various plant loop sides are
called for sizing and normal simulation. Components that connect two loops will have
been processed in Step 2 and that information is now available to refine loop side
calling order
4. Call loop sizing routines in calling order. Component will have registered their design
flow rates in step 2 and now the overall loop sizes are determined from the sum of
the components on the loop.
5. A final pass thru each loop side is made in calling order with the flag
PlantSizesOkayToFinalize set to true. At this point the findings are not
expected to change. Component models now finalize their findings and store the
results for use during the simulation. Overall plant loops are finalized. Sizing
reporting occurs.
6. Sizing finished and PlantSizeNotComplete set FALSE
Previous to version 7, component sizing routines were only called once and one had to take
care not call them repeatedly (or else their flow request would get doubled each time).
However, now plant component models should be designed for multiple executions of their
component-level sizing routine. This allows for an iterative approach to plant sizing that is
used to solve complex problems raised by inter-connected loops and the interdependence of
sizing information.
After the component model has determined a design value for the flow rate, this flow rate
needs to be registered with the larger plant routines by calling
3
RegisterPlantCompDesignFlow. This is a volume flow rate in m /s. The flow rate is
associated with the inlet node. This call can be repeated and the design flow will be updated
with the latest request.
Calls to InitComponentNodes should be done after sizing is complete so that valid sizes
are passed for initialing nodes.
Component Flow Rates
Plant components models need knowledge of the rate of plant fluid flows through the device
for each of loops involved. Some components will need to request the flow they desire while
others just need to know the mass flow rate. However, components do not necessarily have
complete control over the resulting flow rates because they depend on the state of the entire
plant and not just on the individual component model. Component models need to be
9/27/13 59
EnergyPlus Module Developer's Guide HVAC Network
implemented to handle situations where they do not get the exact flow rate they requested or
expected to get. For example there could be a shortage of flow and components are starved
and get less than they desire. Or a component could be in series with another that is making
a larger flow request and therefore a component receives more flow than expected. Even if a
component is usually passive and takes what flow it gets, the user might have placed a
component on a branch that is in parallel with other branches making it necessary for even a
passive component to make a flow “request” in order for its parallel branch to receive flow
when a splitter distributes flow across a set of branches.
SetComponentFlowRate collects code for how to properly deal with plant flow rates. The
idea is to use a central routine that actually changes the various mass flow rate variables on
the node and checks against all the constraints. As of Version 7, component models should
no longer assign flows to the Node data structure. (Component models can get data from
Node data structure but should not set flow rate data on the Node directly.) The
SetComponentFlowRate subroutine’s argument for fluid mass flow is INOUT; the
component model makes a request and if it cannot be satisfied, the mass flow rate variable
will be returned with the corrected flow that the plant can actually provide at the moment.
Some models, such as a water coil controller, may only have information about one control
node. If a model does not really represent a single device with inlet and outlet nodes, then
there is another useful routine called SetActuatedBranchFlowRate which serves a role
similar to SetComponentFlowRate. This routine handles mass flow issues for all the
components on the branch that contains the actuated node but is otherwise similar in
concept.
Controls
Plant component models have different types of control interactions depending on the type of
component. Plant components that are led by the air side of HVAC models will generally be
controlled by circumstances on the air side. A water-based cooling coil will be targeting the
achievement of certain air conditions and while the state of the chilled water plant serving the
coil will matter in the model calculations, the component itself is not controlled by plant but
things outside of plant.
Components that need to be operated to meet the loads placed on plant loops will often be
controlled based on some combination of node setpoints and dispatched loads. The main
entry routine (called from PlantLoopEquipment.f90) for most such primary components
should include and use arguments for “MyLoad” and “RunFlag.” Central routines for
operation schemes and availability managers will determine if a component is available (e.g.
RunFlag) and what power level the device is being asked to provide (e.g. MyLoad). MyLoad
is now signed as of version 7; a negative value of MyLoad is a cooling load; a positive value
of MyLoad is a heating load.
Updating
Plant component update routines should no longer be setting mass flow rates in the update
routine. The flow setting routines should be called during initialization or calculation routines
and should not need to be called again during update. The state of the outlet node should be
updated, such as outlet temperature, but mass flow rate should not be. Prior to version 7 it
was common in EnergyPlus to write
Node(OutletNode) = Node(InletNode)
However this is no longer acceptable practice and is not allowed for plant nodes. Instead this
can be replaced with a call to SafeCopyPlantNode. This avoids problems when two
components are in series and the outlet of one is the inlet of another. We cannot allow unsafe
node copying because it will wipe out information stored on the inlet node of the second
component.
9/27/13 60
EnergyPlus Module Developer's Guide HVAC Network
Reporting
A component model connected to plant via nodes will inherit a great deal of reporting that
already occurs for each node. The output variables that start out “System Node” will already
be available to the user. In general, the focus of reporting should be on data that are internal
to the component model.
Central Routine Modifications
When adding a new plant component, there are several places where the central routines’
code needs to be modified so that the new model can properly interact with them. The
following sections of the code should be expanded when adding a new plant component:
1. DataPlant.f90. A new component will need to modify DataPlant.f90 in these places:
a. Parameter NumSimPlantEquipTypes. Increment up to include new
component.
b. Array SimPlantEquipTypes. Add array element with new object’s class
name in upper case.
c. Array ccSimPlantEquipTypes. Add array element with new object’s
class name in camel case.
d. Array ValidLoopEquipTypes. Add array element with classification for
what type of loop this component is intended for, primarily with respect to the
type of loop it is intended to meet loads.
e. Parameter TypeOf_xxxx . Add an integer parameter to identify “TypeOf”
number for subsequent use to identify component type without having to do
string comparisions.
2. PlantManager.f90
a. GetPlantInput. There is a large IF-ELSEIF block in this routine that will
need to be extended to process the new component. This is where the
“TypeOf” number gets set for subsequent use. Choose a general equipment
type for the component. Initialize the value for Comp%CurOpSchemeType
depending on which loop side is involved and/or the nature of the
component
b. SetupBranchControlTypes. There is a large Case block in this routine
that will need to be extended to process the new component. Prior to
Version 7, the user had to input a branch control type in the IDF. Now this
information is set in code in this routine. There are three different control
classifications that need to be set in this routine:
i. Comp%FlowCtrl. This is the branch control type input for versions
prior to version 7. Plant components that have some influence over
the mass flows should be set to ControlType_Active. There are
also ControlType_Passive and ControlType_ByPass options
that may apply. The branches are further processed by routines
that automatically detect series active situations.
ii. Comp%FlowPriority. New for version 7 is a plant modeling
concept that treats flow requests differently depending on the nature
of the component’s priority. The idea is that when determining the
overall flow rate in a loop, some mass flow requests need to be
handled differently than others. The three flow priority options for
components are LoopFlowStatus_NeedyAndTurnsLoopOn,
LoopFlowStatus_NeedyIfLoopOn, and
LoopFlowStatus_TakesWhatGets. The first is typically a
demand side component that when it requests flow will dictate that
the loop operate and try to meet its request. The second is typically
9/27/13 61
EnergyPlus Module Developer's Guide HVAC Network
The node mass flow variables merit a little more discussion. Six mass flow variables
are defined at each node. They are: MassFlowRate, MassFlowRateMin,
MassFlowRateMax, MassFlowRateMinAvail, MassFlowRateMaxAvail and
MassFlowRateRequest. These variables hold loop mass flow rate information
according to the following definitions.
MassFlowRate – this node variable holds the simulation mass flow rate for the current
timestep. The remaining four variables serve as limits to MassFlowRate.
MassFlowRateMax, MassFlowRateMin – These node variables hold the maximum
possible and the minimum allowable flow rates for a particular component. As such, they
represent the “hardware limit” on the flow rate for the component.
MassFlowRateMaxAvail, MassFlowRateMinAvail – these node variables represent the
loop maximum and minimum flow rate for the current configuration of the loop on which
the component resides.
MassFlowRateRequest – this node variable applies only to plant and holds the desired
mass flow rate for the current timestep. This stores a record of what flow was desired.
9/27/13 62
EnergyPlus Module Developer's Guide EnergyPlus Services
EnergyPlus Services
EnergyPlus provides some standard services that make the developer’s task much
easier. The developer can concentrate on the new simulation algorithm rather than
have to deal with details of input file structure, writing output, obtaining scheduled
data, and accessing weather variables.
Utility Routines/Functions
9/27/13 63
EnergyPlus Module Developer's Guide EnergyPlus Services
Input Services
The module InputProcessor processes the input data files (IDFs). It also reads and
parses the IDD file. The InputProcessor uses the definition lines in the IDD as
directives on how to process each input object in the IDF. The InputProcessor also
turns all alpha strings into all UPPER CASE. Currently, it does nothing else to those
strings – so the number of blanks in a string must match what the calculational
modules expect. The InputProcessor processes all numeric strings into single
precision real numbers. Special characters, such as tabs, should not be included in
the IDF.
The EnergyPlus module InputProcessor provides several routines - generically called
the “get” routines – that enable the developer to readily access the data for a new
module. These routines are made available by including a “USE InputProcessor”
statement in the module or in the routine that will use the “get” routines. The
GetFanInput subroutine in the example illustrates some of the uses of the “get”
routines.
9/27/13 64
EnergyPlus Module Developer's Guide EnergyPlus Services
InputProcessor
The following objects use public routines from the InputProcessor. To access these,
the code has:
Use InputProcessor, ONLY: <routine1>, <routine2>
Where the <routine> is one or more of the following:
GetNumObjectsFound
This function returns the number of objects in the input belonging to a particular
class. In other terms, it returns the number of instances in the input of a particular
component.
Example:
USE InputProcessor, ONLY: GetNumObjectsFound
---
NumVAVSys = GetNumObjectsFound('SINGLE DUCT:VAV:REHEAT')
Here NumVAVSys will contain the number of single duct VAV terminal units in the
input data file (IDF). SINGLE DUCT:VAV:REHEAT is the class name or keyword
defining VAV terminal unit input on the IDD file.
GetObjectItem
This subroutine is used to obtain the actual alphanumeric and numeric data for a
particular object.
Example:
USE InputProcessor
---
INTEGER :: SysNum = 0 ! The Sys that you are currently loading input
into
---
CHARACTER(Len=MaxNameLength) :: CurrentModuleObject
CHARACTER(Len=MaxNameLength), ALLOCATABLE, DIMENSION(:) :: Alphas
CHARACTER(Len=MaxNameLength), ALLOCATABLE, DIMENSION(:) :: cAlphaFields
CHARACTER(Len=MaxNameLength), ALLOCATABLE, DIMENSION(:) :: cNumericFields
REAL(r64), ALLOCATABLE, DIMENSION(:) :: Numbers
LOGICAL, ALLOCATABLE, DIMENSION(:) :: lAlphaBlanks
LOGICAL, ALLOCATABLE, DIMENSION(:) :: lNumericBlanks
INTEGER :: MaxNums=0
INTEGER :: MaxAlphas=0
INTEGER :: TotalArgs=0
---
CALL GetObjectDefMaxArgs &
('AirTerminal:SingleDuct:VAV:Reheat', TotalArgs, NumAlphas, NumNums)
MaxNums=MAX(MaxNums,NumNums)
MaxAlphas=MAX(MaxAlphas,NumAlphas)
---
!Start Loading the System Input
CurrentModuleObject='AirTerminal:SingleDuct:VAV:Reheat'
DO SysIndex = 1, NumVAVSys
SysNum = SysIndex
9/27/13 65
EnergyPlus Module Developer's Guide EnergyPlus Services
! You supply the object word, routine returns numargs, numalpha, numnumeric
CALL GetObjectDefMaxArgs(‘DAYSCHEDULE:INTERVAL’,NumArgs,NumAlpha,NumNumeric)
ALLOCATE(Alphas(NumAlpha))
ALLOCATE(Numbers(NumNumeric))
9/27/13 66
EnergyPlus Module Developer's Guide EnergyPlus Services
In the example, ListNum will contain the input file index of the ‘CONTROLLER LIST’
whose name is contained in the string variable ControllerListName.
FindItemInList
This function looks up a string in a similar list of items and returns the index of the
item in the list, if found. It is case sensitive.
Example:
USE InputProcessor, ONLY: FindItemInList
---
SysNum = FindItemInList(CompName,Sys%SysName,NumSys)
9/27/13 67
EnergyPlus Module Developer's Guide EnergyPlus Services
Example:
USE InputProcessor, ONLY: SameString
---
IF (SameString(InputRoughness,'VeryRough')) THEN
Material(MaterNum)%Roughness=VeryRough
ENDIF
VerifyName
This subroutine checks that an object name is unique; that is, it hasn’t already been
used for the same class of object and the name is not blank.
Example:
USE InputProcessor, ONLY: VerifyName
---
CALL VerifyName(AlphArray(1),Fan%FanName, &
FanNum-1,IsNotOK,IsBlank,'FAN:SIMPLE:CONSTVOLUME Name')
The first argument is the name to be checked, the second is the list of names to
search, the third argument is the number of entries in the list, the 4th argument is set
to TRUE if verification fails, the 5th argument is set to true if the name is blank, and
the last argument is part of the error message written to the error file when
verification fails.
RangeCheck
The routine RangeCheck can be used to produce a reasonable error message to
describe the situation in addition to setting the ErrorsFound variable to true. Errors
found can then be checked in the calling routine and the program terminated if
desired.
SUBROUTINE RangeCheck(ErrorsFound,WhatFieldString,WhatObjectString,ErrorLevel, &
LowerBoundString,LowerBoundCondition,UpperBoundString,UpperBoundCondition)
It can be used in a variety of places when the \minimum and \maximum fields will not
work (e.g. different min/max dependent on some other field).
USE InputProcessor, ONLY: RangeCheck
---
ErrorsFound=.false.
CALL RangeCheck(ErrorsFound,'DryBulb Temperature','WeatherFile', &
'SEVERE','> -70',(Drybulb>-70.),'< 70',(DryBulb <70.))
CALL RangeCheck(ErrorsFound,'DewPoint Temperature','WeatherFile', &
'SEVERE','> -70',(Dewpoint>-70.),'< 70',(Dewpoint <70.))
CALL RangeCheck(ErrorsFound,'Relative Humidity','WeatherFile', &
'SEVERE','> 0',(RelHum>=0.),'<= 110',(RelHum<=110.))
To examine one call:
The variable DryBulb is set to its value. In this case, it is coming from the Weather
File. The LowerBoundString is ‘> - 70’ and the LowerBoundCondition is
(DryBulb>-70.) [this expression will yield true or false depending…]
The LowerBounds (LowerBoundString, LowerBoundCondition) are optional as
are the UpperBounds (UpperBoundString, UpperBoundCondition). If we were
only testing one set of ranges, the call would look like:
Call RangeCheck(ErrorsFound,’DryBulb Temperature’,’WeatherFile’,’SEVERE’, &
UpperBoundString=’< 70’, UpperBoundCondition=(DryBulb<70.))
ErrorLevel can be one of the usual Error levels:
WARNING – would be a simple warning message – the calling routine might reset
the value to be within bounds
9/27/13 68
EnergyPlus Module Developer's Guide EnergyPlus Services
MakeUPPERCase
This function can be used to make sure an upper case string is being used. (Note
this is not needed when using “SameString”). Parameter 1 to the function is the
string to be upper cased:
USE InputProcessor, ONLY: MakeUPPERCase
---
UCString=MakeUPPERCase(‘lower string’)
Object Services
It is standard practice in EnergyPlus that only objects associated with a given module
be accessed from the input data file using a GetObjectItem function call and that this
type of function call only be executed during GetInput. For example, the module
HVACDXSystem would only access the object DXSystem:AirLoop in the GetInput
subroutine or the module HVACFanComponent would only access the different fan
objects as shown in the example below. This programming standard requires that all
modules be “responsible” for specific objects and no other module accesses the
input data file for this specific object. Using this technique, maintenance of the
EnergyPlus modules is limited to specific areas of software as input data for objects
evolve for any reason.
Module HVACDXSystem - SUBROUTINE GetDXCoolingSystemInput:
CALL GetObjectItem('DXSYSTEM:AIRLOOP',DXCoolSysNum,AlphArray, &
NumAlphas,NumArray,NumNums,IOSTAT)
Module HVACFanComponent – SUBROUTINE GetFanInput:
CALL GetObjectItem('FAN:SIMPLE:CONSTVOLUME',SimpFanNum,AlphArray, &
NumAlphas,NumArray,NumNums,IOSTAT)
CALL GetObjectItem('FAN:SIMPLE:VARIABLEVOLUME',VarVolFanNum, &
AlphArray,NumAlphas,NumArray,NumNums,IOSTAT)
CALL GetObjectItem('ZONE EXHAUST FAN',ExhFanNum,AlphArray, &
NumAlphas,NumArray,NumNums,IOSTAT)
CALL GetObjectItem('FAN:SIMPLE:ONOFF',OnOffFanNum,AlphArray, &
NumAlphas,NumArray,NumNums,IOSTAT)
9/27/13 69
EnergyPlus Module Developer's Guide EnergyPlus Services
If module developers were allowed to access the input data file for other objects not
related to a particular module, both the original module and the alternate module
would have to be corrected each time the object changed. This poses a severe
hazard for future development of EnergyPlus.
Module developers may at times require information for specific objects from other
modules. When this occurs, the Information is “mined” through function or subroutine
calls located in the other module. Existing function calls may be used or added to
EnergyPlus as needed. In this way, a module developer could confirm that node
information provided in a parent object matched the node information specified for its
children object. Other error checking may also be performed in this manner. For
example, if the module HVACDXSystem needed to know the capacity of the DX
cooling coil, a function call to GetCoilCapacity in the DXCoil module would provide
this information. The function GetCoilCapacity would the “Get” the input from the
input data file if it has not already been accessed and provide the information back to
the calling module.
A variety of examples exist to aid the module developer in this area of programming.
DXCoil.f90:
FUNCTION GetCoilCapacity(CoilType,CoilName,ErrorsFound) RESULT(CoilCapacity)
FUNCTION GetMinOATCompressor(CoilType,CoilName,ErrorsFound) RESULT(MinOAT)
FUNCTION GetCoilInletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetCoilOutletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetSupplyAirFanOperatingMode(CoilType,CoilName,ErrorsFound) RESULT(OpMode)
FUNCTION GetCoilCondenserNode(CoilType,CoilName,ErrorsFound) RESULT(CondNode)
FUNCTION GetHPCoolingCoilIndex(HeatingCoilType, HeatingCoilName, HeatingCoilIndex)
RESULT(DXCoolingCoilIndex)
FanCoilUnits.f90:
INTEGER FUNCTION GetFanCoilZoneInletAirNode(FanCoilNum)
INTEGER FUNCTION GetFanCoilOutAirNode(FanCoilNum)
INTEGER FUNCTION GetFanCoilReturnAirNode(FanCoilNum)
INTEGER FUNCTION GetFanCoilMixedAirNode(FanCoilNum)
HeatRecovery.f90:
FUNCTION GetSupplyInletNode(HXName,ErrorsFound)
FUNCTION GetSupplyOutletNode(HXName,ErrorsFound)
FUNCTION GetSecondaryInletNode(HXName,ErrorsFound)
FUNCTION GetSecondaryOutletNode(HXName,ErrorsFound)
HVACFanComponent.f90:
FUNCTION GetFanDesignVolumeFlowRate(FanType,FanName,ErrorsFound) RESULT(DesignVolumeFlowRate
FUNCTION GetFanInletNode(FanType,FanName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetFanOutletNode(FanType,FanName,ErrorsFound) RESULT(NodeNumber)
SUBROUTINE GetFanVolFlow(FanIndex, FanVolFlow)
SUBROUTINE GetFanType(FanName,FanType,ErrorsFound,ThisObjectType)
HVACHeatingCoils.f90:
FUNCTION GetCoilCapacity(CoilType,CoilName,ErrorsFound) RESULT(CoilCapacity)
FUNCTION GetCoilInletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetCoilOutletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
SUBROUTINE GetHeatingCoilIndex(HeatingCoilName,HeatingCoilIndex,ErrorsFound)
9/27/13 70
EnergyPlus Module Developer's Guide EnergyPlus Services
HVACHXAssistedCoolingCoil.f90:
FUNCTION GetCoilCapacity(CoilType,CoilName,ErrorsFound) RESULT(CoilCapacity)
FUNCTION GetCoilInletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetCoilOutletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetHXDXCoilName(CoilType,CoilName,ErrorsFound) RESULT(DXCoilName)
FUNCTION GetCoilMaxWaterFlowRate(CoilType,CoilName,ErrorsFound) RESULT(MaxWaterFlowRate)
HVACStandAloneERV.f90
FUNCTION GetSupplyAirFlowRate(ERVType,ERVCtrlName,ErrorsFound) RESULT(AirFlowRate)
FUNCTION GetSupplyAirInletNode(ERVType,ERVCtrlName,ErrorsFound) RESULT(AirInletNode)
FUNCTION GetExhaustAirInletNode(ERVType,ERVCtrlName,ErrorsFound) RESULT(AirInletNode)
INTEGER FUNCTION GetStandAloneERVOutAirNode(StandAloneERVNum)
INTEGER FUNCTION GetStandAloneERVZoneInletAirNode(StandAloneERVNum)
INTEGER FUNCTION GetStandAloneERVReturnAirNode(StandAloneERVNum)
HVACSteamCoilComponent.f90:
FUNCTION GetCoilMaxWaterFlowRate(CoilType,CoilName,ErrorsFound) RESULT(MaxWaterFlowRate)
HVACWaterCoilComponent.f90:
FUNCTION GetCoilMaxWaterFlowRate(CoilType,CoilName,ErrorsFound) RESULT(MaxWaterFlowRate)
FUNCTION GetCoilInletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetCoilOutletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
HVACWaterToAir.f90:
FUNCTION GetCoilCapacity(CoilType,CoilName,ErrorsFound) RESULT(CoilCapacity)
FUNCTION GetCoilInletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
FUNCTION GetCoilCapacity(CoilType,CoilName,ErrorsFound) RESULT(CoilCapacity)
FUNCTION GetCoilInletNode(CoilType,CoilName,ErrorsFound) RESULT(NodeNumber)
MixedAir.f90:
FUNCTION GetOAMixerNodeNumbers(OAMixerName,ErrorsFound) RESULT(OANodeNumbers)
FUNCTION GetNumOAMixers() RESULT(NumberOfOAMixers)
FUNCTION GetNumOAControllers() RESULT(NumberOfOAControllers)
FUNCTION GetOAMixerReliefNodeNumber(OAMixerNum) RESULT(ReliefNodeNumber)
FUNCTION GetOASystemNumber(OASysName) RESULT(OASysNumber)
FUNCTION GetOAMixerInletNodeNumber(OAMixerNumber) RESULT(OAMixerInletNodeNumber)
FUNCTION GetOAMixerReturnNodeNumber(OAMixerNumber) RESULT(OAMixerReturnNodeNumber)
FUNCTION GetOAMixerMixedNodeNumber(OAMixerNumber) RESULT(OAMixerMixedNodeNumber)
PackagedTerminalHeatPump.f90:
INTEGER FUNCTION GetPTHPZoneInletAirNode(PTHPNum)
INTEGER FUNCTION GetPTHPOutAirNode(PTHPNum)
INTEGER FUNCTION GetPTHPReturnAirNode(PTHPNum)
INTEGER FUNCTION GetPTHPMixedAirNode(PTHPNum)
PurchasedAirManager.f90:
FUNCTION GetPurchasedAirOutAirMassFlow(PurchAirNum) RESULT(OutAirMassFlow)
SetpointManager.f90:
LOGICAL FUNCTION IsNodeOnSetPtManager(NodeNum,SetPtType)
UnitVentilator.f90:
9/27/13 71
EnergyPlus Module Developer's Guide EnergyPlus Services
WindowAC.f90:
INTEGER FUNCTION GetWindowACZoneInletAirNode(WindACNum)
INTEGER FUNCTION GetWindowACOutAirNode(WindACNum)
INTEGER FUNCTION GetWindowACReturnAirNode(WindACNum)
INTEGER FUNCTION GetWindowACMixedAirNode(WindACNum)
These kinds of calls are highly encouraged so that data is mined from the other
modules rather than being declared public.
The function call for GetCoilCapacity in module DXCoil.f90 is shown below. Note that
the format for these function calls have the same format as other subroutines
throughout the EnergyPlus software. The example function shown below is declared
as a public routine in module DXCoils for use by other modules through a USE
statement.
Module DXCoils.f90:
PUBLIC GetCoilCapacity
FUNCTION GetCoilCapacity(CoilType,CoilName,ErrorsFound) RESULT(CoilCapacity)
! FUNCTION INFORMATION:
! AUTHOR Linda Lawrie
! DATE WRITTEN February 2006
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! na
! REFERENCES:
! na
! USE STATEMENTS:
USE InputProcessor, ONLY: FindItemInList
9/27/13 72
EnergyPlus Module Developer's Guide EnergyPlus Services
IF (WhichCoil == 0) THEN
CALL ShowSevereError('Could not find CoilType="' &
//TRIM(CoilType)//'" with Name="'//TRIM(CoilName)//'"')
ErrorsFound=.true.
CoilCapacity=-1000.
ENDIF
RETURN
Note that the function name in one module can be the same as a function name in a
different module. In fact, for EnergyPlus this should be the case – the module should
use a generic name that is typical of its function. The calling module should use a
“local name” that better specifies the type of item it is accessing. For example, if
module HVACFurnace required node or capacity information from identical functions
contained in modules HVACHeatingCoils and DXCoils, these function names could
easily be assigned more descriptive names in the HVACFurnace module as follows.
Module HVACFurnace.f90:
USE HeatingCoils, ONLY: GetHeatingCoilCapacity=>GetCoilCapacity,
GetHeatingCoilInletNode=>GetCoilInletNode
USE DXCoils, ONLY: GetDXCoilCapacity=>GetCoilCapacity,
GetDXCoilInletNode=>GetCoilInletNode
BranchInputManager
For the most part, new modules do not use the BranchInputManager directly.
Branches are “gotten” at a high management level. The main routines that might be
used from the BranchInputManager are: NumBranchesInBranchList, GetBranchList
9/27/13 73
EnergyPlus Module Developer's Guide EnergyPlus Services
and GetBranchData. The BranchInputManager also houses the Splitter and Mixer
data: GetLoopSplitter and GetLoopMixer.
NumBranchesInBranchList
This routine is used to get the number of branches in a branch list name (so that an
appropriate array can be allocated).
INTEGER FUNCTION NumBranchesInBranchList(BranchListName)
An example of use:
=== Example ===
USE BranchInputManager, ONLY: NumBranchesInBranchList,. . .
. . .
PrimeAirSys(ASysNum)%NumBranches= &
NumBranchesInBranchList(BranchListName)
IF (PrimeAirSys(ASysNum)%[Link].0) THEN
CALL ShowSevereError('There must be at least 1 branch in system ' &
//TRIM(PrimeAirSys(ASysNum)%Name))
ErrorsFound=.true.
END IF
ALLOCATE(BranchNames(PrimeAirSys(ASysNum)%NumBranches))
BranchNames=' '
GetBranchList
This routine is used to get the names of the branches on a Loop.
SUBROUTINE GetBranchList(LoopName, BranchListName, NumBranchNames, BranchNames,
LoopType)
=== Example ===
USE BranchInputManager, ONLY: GetBranchList, . . .
. . .
ALLOCATE(CompTypes(NumBComps))
CompTypes=' '
ALLOCATE(CompNames(NumBComps))
CompNames=' '
ALLOCATE(CompCtrls(NumBComps))
CompCtrls=' '
ALLOCATE(InletNodeNames(NumBComps))
9/27/13 74
EnergyPlus Module Developer's Guide EnergyPlus Services
InletNodeNames=' '
ALLOCATE(InletNodeNumbers(NumBComps))
InletNodeNumbers=0
ALLOCATE(OutletNodeNames(NumBComps))
OutletNodeNames=' '
ALLOCATE(OutletNodeNumbers(NumBComps))
OutletNodeNumbers=0
PrimeAirSys(ASysNum)%Branch(BNum)%TotalNodes = &
NumBComps+1
ALLOCATE (PrimeAirSys(ASysNum)%Branch(BNum)%NodeNum(NumBComps+1))
PrimeAirSys(ASysNum)%Branch(BNum)%NodeNum(1) = &
InletNodeNumbers(1)
PrimeAirSys(ASysNum)%Branch(BNum)%DuctType = Main
DO CNum = 1,PrimeAirSys(ASysNum)%Branch(BNum)%TotalComponents
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%TypeOf = &
CompTypes(CNum)
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%Name = &
= CompNames(CNum)
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%Index = 0
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%FlowCtrl= &
CompCtrls(CNum)
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%NodeNameIn=&
InletNodeNames(CNum)
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%NodeNumIn=&
InletNodeNumbers(CNum)
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%NodeNameOut=&
OutletNodeNames(CNum)
PrimeAirSys(ASysNum)%Branch(BNum)%Comp(CNum)%NodeNumOut= &
OutletNodeNumbers(CNum)
PrimeAirSys(ASysNum)%Branch(BNum)%NodeNum(CNum+1) = &
OutletNodeNumbers(CNum)
NodeInputManager
The NodeInputManager is responsible for getting all the node names and assigning
each a number. Node names are learned in random order – which can make
validation difficult. Internally nodes are referenced as number and should be
integers in any data structure or reference. Two key routines are used for obtaining
node numbers: GetOnlySingleNode and GetNodeNums.
Node Information Arguments
Both routines need some extra information about the node as the number is
[Link] information is used to support fluid property calculations, the HVAC
Diagram utility, and various diagnostic checks.
9/27/13 75
EnergyPlus Module Developer's Guide EnergyPlus Services
NodeFluidType
This argument defines the type of fluid at this node such as air or water. The node
fluid type is used for fluid property calculations and is reported in the list of nodes in
the bnd output file. Parameter definitions for this argument can be found in
DataLoopNode. As of version 1.3, the list of valid choices is:
! Valid Fluid Types for Nodes
INTEGER, PARAMETER :: NodeType_Unknown = 0 ! 'blank'
INTEGER, PARAMETER :: NodeType_Air = 1 ! 'Air'
INTEGER, PARAMETER :: NodeType_Water = 2 ! 'Water'
INTEGER, PARAMETER :: NodeType_Steam = 3 ! 'Steam'
INTEGER, PARAMETER :: NodeType_Electric= 4 ! 'Electric'
Note that the argument passed in is an integer value – you can “USE
DataLoopNode” and use the above definitions (preferred over either defining your
own or passing in a number). In many cases, a component may not know the fluid
type. For example, most SET POINT MANAGERS are applicable to both air and
water nodes. In this case, NodeType_Unknown should be used. It is assumed that
for any given node, at least one object referencing it will know the fluid type. Once a
known fluid type is passed for a given node, it cannot be changed. All references to
the same node must specify the same fluid type or unknown. When all input has
been gotten, all node fluid types should be known, but this is not being validated
currently.
NodeObjectType
This is the type of object which is referencing the node (e.g. Chiller:Electric). This
information is used to generate the list of Parent and Non-Parent Node Connections
in the bnd output file. This list is used by the HVAC Diagram utility.
NodeObjectName
This is the name of the object which is referencing the node (e.g. My Chiller). This
information is used to generate the list of Parent and Non-Parent Node Connections
in the bnd output file. This list is used by the HVAC Diagram utility.
NodeConnectionType
Parameter definitions for this argument can be found in DataLoopNode. .As of
version 1.2.0, the current list of choices is:
9/27/13 76
EnergyPlus Module Developer's Guide EnergyPlus Services
This information is used to generate the list of Parent and Non-Parent Node
Connections in the bnd output file. This list is used by the HVAC Diagram utility.
After all input has been gotten, node connection types are also validated in
CheckNodeConnections in NodeInputManager according to the following rules. The
rules are intended to catch user input errors without placing unnecessary constraints
on system configurations. The validation checks are not exhaustive, so it is possible
to pass all of the checks yet have a misconnected simulation. The main goal here is
to prevent dangling nodes which do not behave as the user expects and can often
go undetected without scrutinizing detailed outputs.
For any node which is used as an actuator, the same node must also be used at least
once as a node type which is not sensor or actuator or outsideair.
For any node which is used as a setpoint, the same node must also be used at least
once as a node type which is not a setpoint or outsideair.
Every ZoneInlet must appear as an outlet from something, otherwise it will do nothing.
Every ZoneExhaust must appear as an inlet to something, otherwise it will do nothing.
Every inlet node should match either an Outlet, ZoneReturn, ZoneExhaust, ReliefAir, or
OutsideAir node, with the following exceptions:
If an InletNode's object is AIR PRIMARY LOOP, CONDENSER LOOP, or PLANT
LOOP, then skip the test.
If an InletNode's object is not one of the above types, it is valid if the same node
name appears as an INLET to an AIR PRIMARY LOOP, CONDENSER LOOP, or
PLANT LOOP.
If a node fails any of the above tests, a severe error message is generated. If a new
module generates unexpected errors, check the node connection types used by a
similar module. If a given node is used in more than one way by an object, it may be
necessary to register the node more than once by successive calls to
GetOnlySingleNode or GetNodeNums with different arguments in each call.
9/27/13 77
EnergyPlus Module Developer's Guide EnergyPlus Services
What is a parent object? A parent object is one which encloses and references other
objects. For example, FAN COIL UNIT:4 PIPE is a parent to a fan, a heating coil, a
cooling coil, and an outside air mixer. In most cases, all nodes referenced by a
parent object are duplicated in the non-parent objects which are the components
which ultimately act on the fluid stream. From the perspective of the HVAC Diagram
utility, every fluid loop must be a continuous connection of non-parent objects and
zones. In this example, the nodes of the mixer, fan, coils, and zone form a complete
loop. Some components, such as UNIT VENTILATOR are part parent and part non-
parent. It is a parent to a fan, a heating coil, and a cooling coil, but it does not
reference an explicit outside air mixer. The mixer is an implied component within the
unit ventilator. In these cases, to facilitate drawing a loop in HVAC Diagram, it is
necessary to create a non-parent component to carry the fluid. So, the unit ventilator
uses the following approach as illustrated by the comments and source code. Note
that Alphas(3), the air inlet node, is registered twice, once as an inlet to parent object
UNIT VENTILATOR, and once as an inlet to the implicit non-parent object UNIT
VENTILATOR-OA MIXER.
9/27/13 78
EnergyPlus Module Developer's Guide EnergyPlus Services
UnitVent(UnitVentNum)%AirOutNode = &
GetOnlySingleNode(Alphas(4),ErrorsFound,'UNIT VENTILATOR',Alphas(1), &
NodeType_Air,NodeConnectionType_Outlet,1,ObjectIsParent)
UnitVent(UnitVentNum)%FanOutletNode = &
GetOnlySingleNode(Alphas(5),ErrorsFound,'UNIT VENTILATOR',Alphas(1), &
NodeType_Air,NodeConnectionType_Internal,1,ObjectIsParent)
GetOnlySingleNode
This is used when only one node is expected as the input point. If this name points
to a NodeList, an appropriate error message will be issued and errFlag (the second
argument) will be set .true.
GetOnlySingleNode(NodeName,errFlag,NodeObjectType,NodeObjectName,NodeFluidType,NodeConnectionType,NodeFlui
dStream,ObjectIsParent)
It is used:
Example:
USE NodeInputManager, ONLY: GetOnlySingleNode
. . .
! get inlet node number
Baseboard(BaseboardNum)%WaterInletNode = &
GetOnlySingleNode(AlphArray(3),ErrorsFound, &
'Baseboard Heater:Water:Convective',AlphArray(1), &
NodeType_Water,NodeConnectionType_Inlet, &
1,ObjectIsNotParent)
! get outlet node number
Baseboard(BaseboardNum)%WaterOutletNode = &
GetOnlySingleNode(AlphArray(4),ErrorsFound, &
'Baseboard Heater:Water:Convective',AlphArray(1), &
NodeType_Water,NodeConnectionType_Outlet, &
1,ObjectIsNotParent)
The first argument is the node name, the 2nd argument is the error flag variable, the
3rd argument is the object type, the 4th argument is the object name – the remainder
arguments are as listed above.
GetNodeNums
This is used when more than one node is valid for an input. Like the
GetOnlySingleNode invocation, GetNodeNums needs the extra information for a
node:
SUBROUTINE GetNodeNums(Name,NumNodes,NodeNumbers,ErrorsFound, &
NodeFluidType,NodeObjectType,NodeObjectName, &
NodeConnectionType,NodeFluidStream,ObjectIsParent)
9/27/13 79
EnergyPlus Module Developer's Guide EnergyPlus Services
Example:
USE NodeInputManager, ONLY: GetNodeNums
. . .
CHARACTER(len=MaxNameLength), DIMENSION(4) :: AlphArray
INTEGER :: NumNodes
INTEGER, DIMENSION(25) :: NodeNums
. . . . . . . .
! Get the supply nodes
ErrInList=.false.
CALL GetNodeNums(Names(8),NumNodes,NodeNums,ErrInList,NodeType_Air, &
'AIR PRIMARY LOOP',PrimaryAirSystem(AirSysNum)%Name, &
NodeConnectionType_Inlet,1,ObjectIsParent)
IF (ErrInList) THEN
CALL ShowContinueError('Invalid Node Name or Node List in Air System=' &
//TRIM(PrimaryAirSystem(AirSysNum)%Name))
ErrorsFound=.true.
ENDIF
! Allow at most 3 supply nodes (for a 3 deck system)
IF (NumNodes > 3) THEN
CALL ShowSevereError('Air System:Only 1st 3 Nodes will be used from:' &
//TRIM(Names(8)))
CALL ShowContinueError('Occurs in Air System='// &
TRIM(PrimaryAirSystem(AirSysNum)%Name))
ErrorsFound=.true.
ENDIF
IF ([Link].0) THEN
CALL ShowSevereError('Air System:there must be at least 1 ‘// &
‘supply node in system '//TRIM(Names(1)))
CALL ShowContinueError('Occurs in Air System='// &
TRIM(PrimaryAirSystem(AirSysNum)%Name))
ErrorsFound=.true.
END IF
. . . . . . . .
The first argument is a node name or the name of a Node List, the 2nd argument is
the number of nodes in the Node List (1 for a single node), the 3rd argument is the
output: a list of node numbers – these are followed by the arguments shown above.
Unique Node Checking
A set of routines will allow you to use the NodeInputManager to check for unique
node names across a set of inputs. This is used currently in the CONTROLLED
ZONE EQUIP CONFIGURATION object where each zone node mentioned must be
unique. Three routines comprise the unique node check: InitUniqueNodeCheck,
CheckUniqueNodes, EndUniqueNodeCheck
InitUniqueNodeCheck
A call to this routine starts the collection and detection of unique/non-unique nodes
by the NodeInputManager:
USE NodeInputManager, ONLY: InitUniqueNodeCheck, CheckUniqueNodes, &
EndUniqueNodeCheck
. . .
CALL InitUniqueNodeCheck(‘CONTROLLED ZONE EQUIP CONFIGURATION’)
The only argument is a simple string that will help with error messages that may
come from the NodeInputManager. Unique node checking can only be done for one
context (‘CONTROLLED ZONE EQUIP CONFIGURATION’) at a time.
9/27/13 80
EnergyPlus Module Developer's Guide EnergyPlus Services
CheckUniqueNodes
SUBROUTINE CheckUniqueNodes(NodeTypes,CheckType,ErrorsFound, &
CheckName,CheckNumber)
This is the routine called during the getting of the nodes. The CheckType argument
can be ‘Nodename’ or ‘NodeNumber’ and then pass in the appropriate argument to
CheckName or CheckNumber. CheckName and CheckNumber are optional
arguments – only the necessary one need be supplied.
Argument 1, NodeTypes, is the type of node being looked for – this argument is used
for error messages within the NodeInput processing. Argument 2, ErrorsFound, will
be set to true of this node is not unique in the current context.
Example:
UniqueNodeError=.false.
CALL CheckUniqueNodes('Zone Air Node','NodeName',UniqueNodeError, &
CheckName=AlphArray(5))
IF (UniqueNodeError) THEN
CALL ShowContinueError('Occurs for Zone='//TRIM(AlphArray(1)))
ErrorsFound=.true.
ENDIF
EndUniqueNodeCheck
This routine terminates the unique node check – allows arrays to be deallocated, etc.
CALL EndUniqueNodeCheck(‘CONTROLLED ZONE EQUIP CONFIGURATION’)
The only argument is the Context String – which must match the string given in the
InitUniqueNodeCheck routine.
SetUpCompSets and TestCompSet
SetUpCompSets and TestCompSet are used to develop a list of hierarchical
relationships between HVAC objects. The CompSet routines are housed in the
BranchInputManager. A list of component sets is built which contains the following
information:
Parent Object Type (Currently cannot be SPLITTER or MIXER)
Parent Object Name
Child Component Type (Currently cannot be SPLITTER or MIXER)
Child Component Name
Child Component InletNodeName
Child Component OutletNodeName
Node Description
Parent and child refer to a hierarchical relationship of two HVAC objects. For
example, a branch is the parent to a pump, and a fan coil is the parent to a fan. The
component sets do not include peer-to-peer connections such as a splitter connected
to a branch, or a zone supply air path connected to an air loop.
The following rules apply to component sets:
Each parent/child component set is unique. The same pair of components
should never appear in the component sets list more than once.
Each set of child component plus inlet and outlet nodes is unique.
Each child component must have a parent component.
9/27/13 81
EnergyPlus Module Developer's Guide EnergyPlus Services
SetUpCompSets
SetUpCompSets should be called any time a parent object such as a branch or a
compound object (e.g. furnace) references a child component which is connected to
it. If an object has more than one child component, then SetUpCompSets is called
once for each child.
SetUpCompSets first looks for the child component in the existing list of component
sets by looking for a matching component type and name. If it is found, then the
parent name and type are filled in. If the child component is not found is the exisiting
list, then a new component set is created.
SUBROUTINE
SetUpCompSets(ParentType,ParentName,CompType,CompName,InletNode,OutletNode,De
scription)
9/27/13 82
EnergyPlus Module Developer's Guide EnergyPlus Services
9/27/13 83
EnergyPlus Module Developer's Guide EnergyPlus Services
In this case, the furnace is the parent object to the fan and the heating coil. To set
up the component set for the furnace and its fan, the furnace type and name, the fan
type and name (A7 and A8), and the furnace/fan inlet and fan outlet nodes (A3 and
A9) are passed to SetUpCompSets:
Example:
In some cases, the inlet or outlet node names may not be known by the parent
object. In this case, "UNDEFINED" is passed to SetUpCompSets.
Examples:
CALL SetUpCompSets(
Furnace(FurnaceNum)%FurnaceType,Furnace(FurnaceNum)%Name,
AlphArray(12),AlphArray(13),'UNDEFINED',AlphArray(4))
9/27/13 84
EnergyPlus Module Developer's Guide EnergyPlus Services
TestCompSet
TestCompSet should be called by every HVAC object which has a parent object. A
given object may be both a parent and a child. For example,
AirLoopHVAC:Unitary:Furnace:HeatOnly is a child to a branch and a parent to a
fan and coils.
TestCompSet first looks for the calling component in the existing list of component
sets by looking for a matching component type and name. If the found compset has
inlet and outlet nodes defined, then these must also match. If a match is found, then
any undefined node names are filled in and the description string for the nodes is
added. If the component is not found, then a new component set is created with
undefined parent object type and name.
SUBROUTINE TestCompSet(CompType,CompName,InletNode,OutletNode,Description)
To register the component set for the furnace (as a child component), the furnace
type and name, and the furnace inlet and outlet nodes (A3 and A4) along with a
node descriptor are passed to TestCompSets:
Example:
9/27/13 85
EnergyPlus Module Developer's Guide EnergyPlus Services
CheckOutAirNodeNumber
Outside Air Nodes are special nodes connected to the outside environment. With
the introduction of the Site Atmospheric Variation parameters, it becomes important
to know whether the node name (e.g. Condenser Inlet Node on Air Cooled Chillers)
is a legitimate outside air node or not. CheckOutAirNodeNumber allows you to
determine if an entered node is, in fact, a proper outside air node.
Declaration:
FUNCTION CheckOutAirNodeNumber(NodeNumber) RESULT(Okay)
Example:
USE OutAirNodeManager, ONLY: CheckOutAirNodeNumber
! outdoor condenser node
IF (lAlphaBlanks(10)) THEN
DXCoil(DXCoilNum)%CondenserInletNodeNum(1) = 0
ELSE
DXCoil(DXCoilNum)%CondenserInletNodeNum(1) = &
GetOnlySingleNode(Alphas(10),ErrorsFound,TRIM(CurrentModuleObject),DXCoil(DXCoi
lNum)%Name, &
NodeType_Air,NodeConnectionType_OutsideAirReference,1,ObjectIsNotParent)
IF (.not.
CheckOutAirNodeNumber(DXCoil(DXCoilNum)%CondenserInletNodeNum(1))) THEN
CALL
ShowWarningError(RoutineName//trim(CurrentModuleObject)//'="'//trim(DXCoil(DXCo
ilNum)%Name)//'", may be invalid')
CALL ShowContinueError(TRIM(cAlphaFields(10))//'="'//TRIM(Alphas(10))// &
'", node does not appear in an
OutdoorAir:NodeList or as an OutdoorAir:Node.')
CALL ShowContinueError('This node needs to be included in an air system
or the coil model will not be valid' &
//', and the simulation continues')
END IF
ENDIF
Note that GetOnlySingleNode is used to get the proper node number, then the node
number is used in the outside air node verification.
CheckAndAddAirNodeNumber
Should you feel really nice about your users (or more likely be updating older code
that may have allowed blanks in places that are properly outside air nodes), you can
use the CheckAndAddAirNodeNumber routine to not only check to see if it is an
outside air node but also add it at the same time.
Declaration:
SUBROUTINE CheckAndAddAirNodeNumber(NodeNumber,Okay)
USE OutAirNodeManager, ONLY: CheckAndAddAirNodeNumber
Example:
ElectricChiller(ChillerNum)%CondInletNodeNum = &
GetOnlySingleNode(AlphArray(5),ErrorsFound, &
'Chiller:Electric',AlphArray(1), NodeType_Air, &
NodeConnectionType_OutsideAirReference, 2, ObjectIsNotParent)
CALL CheckAndAddAirNodeNumber( &
ElectricChiller(ChillerNum)%CondInletNodeNum, &
Okay)
IF (.not. Okay) THEN
CALL ShowWarningError('Chiller:Electric, Adding Outside Air Node='// &
AlphArray(5)))
ENDIF
9/27/13 86
EnergyPlus Module Developer's Guide EnergyPlus Services
Note that here “not Okay” is not an error condition but rather the opportunity to notify
the user that you are adding an air node.
Schedule Services
Schedules are widely used in specifying input for building simulation programs. For
instance heat gains from lighting, equipment and occupancy are usually specified
using schedules. Schedules are used to indicate when equipment is on or off.
Schedules are also used to specify zone and system set points. EnergyPlus uses
schedules in all these ways and provides services that make using schedules very
easy for the developer.
Schedules are specified in a three level hierarchy in EnergyPlus input.
Day Schedules (IDD Objects: Schedule:Day:Hourly, Schedule:Day:Interval,
Schedule:Day:List)
Week Schedules (IDD Objects: Schedule:Week:Daily, Schedule:Week:Compact)
Annual Schedules (IDD Objects: Schedule:Year, Schedule:Compact,
Schedule:File)
In addition, a ScheduleTypeLimits object can specify certain limits on the
schedules. This is a mostly optional input but can be used effectively. (That is, if
your examples include it, users will probably use it too.)
An example from an input (IDF) file:
ScheduleTypeLimits,
Fraction, !- ScheduleType Name
0.0 : 1.0, !- range
CONTINUOUS; !- Numeric Type
ScheduleTypeLimits,
On/Off, !- ScheduleType Name
0:1, !- range
DISCRETE; !- Numeric Type
! Schedule Constant
SCHEDULE:COMPACT,
Constant,
on/off,
Through: 12/31,
For: AllDays,
Until: 24:00, 1.0;
! Schedule Intermittent
9/27/13 87
EnergyPlus Module Developer's Guide EnergyPlus Services
SCHEDULE:COMPACT,
Intermittent,
Fraction,
Through: 12/31,
For: AllDays,
Until: 08:00, 0.0,
Until: 18:00, 1.0,
Until: 24:00, 0.0;
The day schedule elements assign numbers that span a full day (24 hours). The
week schedule elements indicate which day schedules are applicable to each day of
the week plus holiday and some special days. Schedule elements indicate which
week schedules are applicable to various periods of the year. Both day schedules
and schedules reference a schedule type. A schedule type is characterized by a
range (e.g. 0 to 1) and whether it is continuous (can assume any value) or discrete
(can assume integer values only). The following routines from the ScheduleManager
module enable the developer to use schedules in a simulation.
GetScheduleIndex
This function takes a schedule name as input and returns an internal pointer to the
schedule. Schedule values will always be accessed via the pointer not the name
during the simulation for reasons of efficiency. This function should be called once
for each schedule during the input phase and the returned value stored in the
appropriate data structure.
Example:
USE ScheduleManager, ONLY: GetScheduleIndex
. . .
Baseboard(BaseboardNum)%SchedPtr = GetScheduleIndex(AlphArray(2))
Here the schedule pointer for the schedule name contained in AlphArray(2) is stored
in the baseboard data structure for later use. If a 0 is returned, this is not a valid
schedule. Objects should also typically check for “blank” schedules.
GetDayScheduleIndex
This function takes a “day schedule” name as input and returns an internal pointer to
the schedule. Day schedule values will always be accessed via the pointer not the
name during the simulation for reasons of efficiency. This function should be called
once for each schedule during the input phase and the returned value stored in the
appropriate data structure.
Example:
USE ScheduleManager, ONLY: GetDayScheduleIndex
. . . DesDayInput(EnvrnNum)%RelHumSchPtr=GetDayScheduleIndex(DDNames(4))
Here the day schedule pointer for the day schedule name contained in DDNames(4)
is stored in the design day data structure for later use. If a 0 is returned, this is not a
valid day schedule. Objects should also typically check for “blank” schedules.
CheckScheduleValueMinMax
Since you can’t always rely on a user to input the ScheduleType, the
ScheduleManager can be used to check the minimum and/or maximum values for a
schedule.
LOGICAL FUNCTION CheckScheduleValueMinMax(ScheduleIndex, &
MinString,Minimum,MaxString,Maximum)
9/27/13 88
EnergyPlus Module Developer's Guide EnergyPlus Services
CheckScheduleValue
There are times when the “CheckScheduleValueMinMax” will not be sufficient to
verify proper values. A good example is the “control type” schedules – valid values
might be 0 through 4, but just checking the min/max will not tell you if it contains a
specific value (say, 3). This function allows you to check the entire schedule for a
specific value – this will be more useful for discrete schedules than for schedule
types of a continuous nature but can be used for both.
LOGICAL FUNCTION CheckScheduleValue(ScheduleIndex,Value)
Example of use:
IF (CheckScheduleValue(CTIndex,REAL(SingleHeatingSetPoint))) THEN
Here, the CTIndex is a schedule index for the Control Type schedules.
SingleHeatingSetPoint is an integer value for that control type.
“CheckScheduleValue” is used to determine if the schedule does, in fact, contain that
value.
GetScheduleMinValue
There are times when you don’t necessarily want to issue an error message but
might like to find out what the minimum value of a given schedule is. For example, if
the schedule allowed for >1 multipliers on a given input.
FUNCTION GetScheduleMinValue(ScheduleIndex) RESULT(MinimumValue)
Example of use:
USE ScheduleManager, ONLY: GetScheduleMinValue
. . .
Value=GetScheduleMinValue(ScheduleIndex)
The only argument needed is the ScheduleIndex for the schedule. Note that all
schedule values are stored as real numbers – if you have a discrete/integer valued
schedule, you may wish to do some special checking of the min value.
GetScheduleMaxValue
There are times when you don’t necessarily want to issue an error message but
might like to find out what the maximum value of a given schedule is. For example, if
the schedule allowed for >1 multipliers on a given input.
FUNCTION GetScheduleMaxValue(ScheduleIndex) RESULT(MaximumValue)
Example of use:
USE ScheduleManager, ONLY: GetScheduleMaxValue
. . .
Value=GetScheduleMaxValue(ScheduleIndex)
9/27/13 89
EnergyPlus Module Developer's Guide EnergyPlus Services
The only argument needed is the ScheduleIndex for the schedule. Note that all
schedule values are stored as real numbers – if you have a discrete/integer valued
schedule, you may wish to do some special checking of the min value.
GetCurrentScheduleValue
This function returns the current schedule value for the current day and time, given
the schedule pointer as input.
REAL FUNCTION GetCurrentScheduleValue(ScheduleIndex)
Example of use:
USE ScheduleManager, ONLY: GetCurrentScheduleValue
. . .
CloUnit = GetCurrentScheduleValue(People(PeopleNum)%ClothingPtr)
Notice that the developer doesn’t have to keep track of hour of the day, day of the
month, or month. The program does all of that. The only input needed is the pointer
to the schedule.
GetScheduleValuesForDay
This function returns the schedule values for a specific day, given the schedule index
as input.
SUBROUTINE GetScheduleValuesForDay(ScheduleIndex,DayValues,JDay)
Example of use:
ALLOCATE(SVals1(24,NumOfTimeStepInHour))
SVals1=0.0
...
DO JDay=1,366
CALL GetScheduleValuesForDay(CrossMixing(Loop)%SchedPtr, &
SVals1,JDay)
IF (.not. ANY(SVals1>0.0)) CYCLE
...
END DO
GetSingleDayScheduleValues
This function returns the schedule values for a specific day schedule (used in Design
Day input, for example).
SUBROUTINE GetSingleDayScheduleValues(DayScheduleIndex,DayValues)
Example of use:
ALLOCATE (DDRelHumValues(TotDesDays,24,NumOfTimeStepInHour))
DDRelHumValues=0.0
...
CALL GetSingleDayScheduleValues(DesDayInput(EnvrnNum)%RelHumSchPtr, &
DDRelHumValues(EnvrnNum,:,:))
LookUpScheduleValue
This function can be used to look up a schedule value for the current time or
optionally for any specific hour, timestep, day of year.
REAL FUNCTION LookUpScheduleValue(ScheduleIndex, ThisHour, ThisTimeStep,
ThisDayOfYear)
...
! FUNCTION ARGUMENT DEFINITIONS:
INTEGER ScheduleIndex
INTEGER, OPTIONAL :: ThisHour
9/27/13 90
EnergyPlus Module Developer's Guide EnergyPlus Services
Data Services
For the most part, modules are independent and only need the data they have within
or USE from other modules. Occasionally, this may take on more complicated needs
such as accessing “real-time” values for meters and/or custom meters or current
report variable names/values.. Meter names are standard; you may have to use
user input to get custom meter names.
Global variable: MetersHaveBeenInitialized
Meters are a bit peculiar and aren’t fully set until the first run through the first time
step of the HVAC simulation. Therefore, there is a global variable
“MetersHaveBeenInitialized” which is set to true after meters have been set up. If
you have a call to your routine that must use meter values as part of the simulation,
you must use this variable before your items can be set.
Example:
…
If (MetersHaveBeenInitialized) CALL ManageDemand
Only the first time step will be missed in your routine and that time step will be part of
“warming up” the simulation, so there is minimal impact due to this limitation.
GetMeterIndex
You use the GetMeterIndex to check if a meter is valid for a particular simulation or if
the user has entered a custom meter of that name. You use the index returned in
later calls to get the value of the meter. Returns 0 if there is no meter of that name.
Example:
INTEGER, EXTERNAL :: GetMeterIndex
…
thismeter=GetMeterIndex(‘Electricity:Facility’)
GetVariableKeyCountAndType
This subroutine returns the variable type (real, integer, meter, etc.) (varType)
whether it is an averaged or summed variable (varAvgSum), whether it is a zone or
HVAC time step (varStepType), and the number of keynames for a given report
variable or report meter name (varName). The variable type (varType) and number
of keys (numKeys) are used when calling subroutine GetVariableKeys to obtain a list
of the keynames for a particular variable and a corresponding list of indexes. An
INTERFACE statement exists in the module OPInterfaces.
Declaration:
SUBROUTINE GetVariableKeyCountandType(varName, numKeys, varType, &
varAvgSum, varStepType, varUnits)
Example:
USE OPInterfaces, ONLY: GetVariableKeyCountAndType
! call the key count function but only need count during this pass
CALL GetVariableKeyCountandType(AlphArray(fldIndex), &
KeyCount,TypeVar,AvgSumVar,StepTypeVar,UnitsVar)
ALLOCATE(NamesOfKeys(KeyCount))
ALLOCATE(IndexesForKeyVar(KeyCount))
9/27/13 91
EnergyPlus Module Developer's Guide EnergyPlus Services
GetVariableKeys
This subroutine returns a list of keynames and indexes associated with a particular
report variable or report meter name (varName). This routine assumes that the
variable type (real, integer, meter, etc.) may be determined by calling
GetVariableKeyCountandType. The variable type and index can then be used with
function GetInternalVariableValue to to retrieve the current value of a particular
variable/keyname combination. An INTERFACE statement exists in the module
OPInterfaces.
Declaration:
SUBROUTINE GetVariableKeys(varName,varType,keyNames,keyVarIndexes)
Example:
USE OPInterfaces, ONLY: GetVariableKeys
CALL GetVariableKeys(AlphArray(fldIndex), TypeVar, NamesOfKeys, &
IndexesForKeyVar)
! See earlier GetVariableKeyCountandType as well.
GetCurrentMeterValue
You use the GetCurrentMeterValue to obtain the value of a meter at its last “reported
value” (timestep). Note that all meters are reported on the zone time step. Returns
0.0 if the MeterNumber passed is <=0.
Example:
INTEGER, EXTERNAL :: GetCurrentMeterValue
…
thismetervalue=GetCurrentMeterValue(ElecFacilityMtrIndex)
GetInstantMeterValue
You use the GetInstantMeterValue to get a component of a meter’s value by index
type. The values returned are “raw” (that is, not weighted by time step values). In
these calls, 1 is a zone time step index, 2 is a system time step index.
Example:
INTEGER, EXTERNAL :: GetInstantMeterValue
…
FuelType%ElecFacility = &
GetInstantMeterValue(FuelType%ElecFacilityIndex,1)*FracTimeStepZone + &
GetInstantMeterValue(FuelType%ElecFacilityIndex,2)
GetInternalVariableValue
This function returns the current value of the Internal Variable assigned to the
varType and keyVarIndex. Values may be accessed for real and integer report
variables and meter variables. The variable type (varType) may be determined by
calling subroutine and GetVariableKeyCountandType. The index (keyVarIndex) may
be determined by calling subroutine GetVariableKeys. To use, there is an
INTERFACE statement in DataGlobals.f90
Example:
USE DataGlobals, ONLY: GetInternalVariableValue
curValue = GetInternalVariableValue(curTypeOfVar,curVarNum)
9/27/13 92
EnergyPlus Module Developer's Guide EnergyPlus Services
GetNewUnitNumber
Rather than attempt to keep track of all open files and distribute this list to everyone,
we have chosen to use a routine that does this operation. If you need to have a
scratch file (perhaps when porting legacy code into EnergyPlus modules), you can
use the GetNewUnitNumber function to determine a logical file number for the OPEN
and READ/WRITE commands. The function works by looking at all open assigned
files and returning a number that isn't being used. This implies that you will OPEN
the unit immediately after calling the function (and you should!).
Example:
INTEGER, EXTERNAL :: GetNewUnitNumber
…
myunit=GetNewUnitNumber()
OPEN(Unit=myunit,File=’myscratch’)
FindUnitNumber
If you want to find out a unit number for a file you think is already open, you can use
the FindUnitNumber function. For example, rather than creating a new unit for
debug output, you could latch onto the same unit as currently used for the
“[Link]” file.
Example:
INTEGER, EXTERNAL :: FindUnitNumber
…
myunit=FindUnitNumber(‘[Link]’)
If that file is already opened, it will get back the unit number it is currently assigned
to. If it is not opened or does not exist, it will go ahead, get a unit number, and
OPEN the file. (Should not be used for Direct Access or Binary files!)
FindNumberinList
Sometimes you would like to find a number in a list. This is applicable to integers
only (e.g. Index numbers of some item).
Example:
INTEGER, EXTERNAL :: FindNumberInList
…
MatchingCooledZoneNum = &
FindNumberinList(CtrlZoneNum, &
AirToZoneNodeInfo(AirLoopNum)%CoolCtrlZoneNums,NumZonesCooled)
The location/index in the array AirToZoneNodeInfo%CoolCtrlZoneNums will be
returned if it finds the number in the array. If 0 is returned, it did not find that number
in the list.
ValidateComponent
Many objects specify a component type as well as a component name. Or, an object
might have only a component name. The ValidateComponent routine will allow for
objects outside the scope of a current “GetInput” routine to verify that the specific
component does exist in the input file.
SUBROUTINE ValidateComponent(CompType,CompName,IsNotOK,CallString)
CompType, CompName are the typical nomenclature for “Component Type” (e.g.
Fan:Simple:OnOff) and “Component Name” (e.g. “my fan” – user specified). IsNotOk
9/27/13 93
EnergyPlus Module Developer's Guide EnergyPlus Services
is a logical from the calling program that is set to true when the component is not on
the input file. CallString should specify the calling object – so that an appropriate
error message can be issued.
Example:
! No USE needed – straightforward routine in GeneralRoutines
CALL ValidateComponent(Furnace(FurnaceNum)%FanType, &
Furnace(FurnaceNum)%FanName,IsNotOK, &
'Furnace:BlowThru:HeatOnly')
IF (IsNotOK) THEN
CALL ShowContinueError('In Furnace='// &
TRIM(Furnace(FurnaceNum)%Name))
ErrorsFound=.true.
ENDIF
Note that in the example, the FanType is entered by the user. This allows for
ultimate flexibility though the example could also include appropriate fan types that
are inherent to the code (an acceptable, if somewhat inflexible, practice).
CheckComponent
This routine is exactly like ValidateComponent but doesn’t generate an error
message. It could be used instead of ValidateComponent and you could use the
“IsNoOK” to generate your own error message. However, the intended use is for
checking out different components when you don’t have the component type as a
field for the object. Thus, you can easily check if there is an object (component type)
with the name entered in your field.
SUBROUTINE CheckComponent(CompType,CompName,IsNotOK)
CompType, CompName are the typical nomenclature for “Component Type” (e.g.
Fan:OnOff) and “Component Name” (e.g. “my fan” – user specified). IsNotOk is a
logical from the calling program that is set to true when the component is not on the
input file.
Example:
! No USE needed – straightforward routine in GeneralRoutines
CALL CheckComponent('Furnace:BlowThru:HeatOnly', &
FurnaceRefName,IsNotOK)
IF (IsNotOK) THEN
CALL CheckComponent('Furnace:BlowThru:HeatCool', &
FurnaceRefName,IsNotOK)
. . . more checks on IsNotOK
ELSE
FurnaceType='Furnace:BlowThru:HeatOnly'
ENDIF
. . .
Note that in the example, the FurnaceRefName is entered by the user. And this
module knows what kind of components it might be.
CreateSysTimeIntervalString
A very important part of EnergyPlus simulation is to be able to alert the user to
problems during the simulation. The CreateSysTimeIntervalString will help do that
though a better use is the ShowContinueErrorTimeStamp routine. The routine has
no argument – a string is returned. The example below also illustrates the preferred
method of counting how many times an error is produced and not printing each
occurrence.
Example:
USE General, ONLY: CreateSysTimeInterval
---
9/27/13 94
EnergyPlus Module Developer's Guide EnergyPlus Services
TrimSigDigits
Along with error messages to alert the user, oftentimes you’d like to include values
that are in error. You can use what some of the examples have shown –
Write(string,*) value but that will produce many digits in real numbers. The
TrimSigDigits routine will allow for easy modification to a set of digits. Note that
there are two flavors (INTERFACE statement in module General) so that you can
easily get the string value of an integer.
FUNCTION TrimSigDigits(RealValue,SigDigits) RESULT(OutputString)
And
FUNCTION TrimSigDigits(IntegerValue) RESULT(OutputString)
As seen in the following example of use in code, a real value is passed in as
argument 1 and the number of digits desired is passed in as argument 2. Note that
the routine will preserve any “E+xx” outputs when a value like .000000004 might be
passed in.
USE General, ONLY: TrimSigDigits
. . .
CALL ShowWarningError('COIL:Water:DetailedFlatCooling in Coil ='// &
TRIM(WaterCoil(coilNum)%Name))
CALL ShowContinueError('Air Flow Rate Velocity has greatly exceeded ‘// &
‘upper design guildelines of ~2.5 m/s')
CALL ShowContinueError('Air MassFlowRate[kg/s]='// &
TRIM(TrimSigDigits(AirMassFlow,6)))
AirVelocity=AirMassFlow*AirDensity/WaterCoil(CoilNum)%MinAirFlowArea
CALL ShowContinueError('Air Face Velocity[m/s]='// &
TRIM(TrimSigDigits(AirVelocity,6)))
CALL ShowContinueError('Approximate MassFlowRate limit for Face ‘// &
Area[kg/s]='// &
TRIM(TrimSigDigits(2.5*WaterCoil(CoilNum)%MinAirFlowArea/AirDensity,6)))
CALL ShowContinueError('COIL:Water:DetailedFlatCooling could be ‘// &
‘resized/autosized to handle capacity')
CoilWarningOnceFlag(CoilNum) = .False.
RoundSigDigits
Similar to TrimSigDigits, the RoundSigDigits function may be used when you want to
“round” the output string – perhaps for reporting and/or error messages. Note that
there are two flavors (INTERFACE statement in module General) so that you can
easily get the string value of an integer.
FUNCTION RoundSigDigits(RealValue,SigDigits) RESULT(OutputString)
9/27/13 95
EnergyPlus Module Developer's Guide EnergyPlus Services
And
FUNCTION RoundSigDigits(IntgerValue) RESULT(OutputString)
As seen in the following example of use in code, a real value is passed in as
argument 1 and the number of digits desired is passed in as argument 2. Note that
the routine will preserve any “E+xx” outputs when a value like .000000004 might be
passed in.
USE General, ONLY: RoundSigDigits
. . .
LatOut=RoundSigDigits(Latitude,2)
LongOut=RoundSigDigits(Longitude,2)
TZOut=RoundSigDigits(TimeZoneNumber,2)
NumOut=RoundSigDigits(Elevation,2)
PressOut=RoundSigDigits(StdBaroPress,0)
Write(OutputFileInits,LocFormat) Trim(LocationTitle),TRIM(LatOut), &
TRIM(LongOut), &
TRIM(TZOut), &
TRIM(NumOut), &
TRIM(PressOut)
SafeDivide
SafeDivide can be used when you might not be sure that the denominator in a divide
will not be zero.
FUNCTION SafeDivide(a, b) RESULT (c)
USE General, ONLY: SafeDivide
. . .
Result=SafeDivide(A,B)
SetupAndSort
SetupAndSort can be called to order/sort a character array. A companion index
array goes along with it so that one does not have to supply an entire derived type to
be sorted. This companion array is then used to point to the proper element of such
structures.
SUBROUTINE SetupAndSort(CharacterList, iCharacterList)
USE SortAndStringUtilities, ONLY: SetupAndSort
. . .
A use:
ALLOCATE(iCharacterList(number of entries))
Do item=1,number of entries
iCharacterList(item)=item
end do
Do item=1,number of entries
! iCharacterList now points to actual structure
Write(output,*) Structure(iCharacterList(item))%Name
Enddo
Error Messages
Several error message routines are provided for the developer, indicating three
different levels of error severity: ShowFatalError, ShowSevereError,
ShowSevereMessage, ShowWarningError and ShowWarningMessage. Each takes
9/27/13 96
EnergyPlus Module Developer's Guide EnergyPlus Services
a string as an argument. The string is printed out as the message body on the file
“[Link]”. There are two additional optional arguments, which are file unit
numbers on which the message will also be printed. In practice, most modules will
not use either file unit number argument – but the Input Processor may use these to
make sure some files contain a notice. ShowFatalError causes the program to
immediately abort.
Two other error messages can be used to help make the error file more readable:
ShowContinueError and ShowContinueErrorTimeStamp. Finally, another similar
ShowMessage call can be used to display an informative string to the error file
([Link]).
As indicated, all of the “show” error calls look the same:
SUBROUTINE <ErrorMessageCall>(ErrorMessage,OutUnit1,OutUnit2)
Or
SUBROUTINE ShowWarningError(ErrorMessage,OutUnit1,OutUnit2)
SUBROUTINE ShowWarningMessage(ErrorMessage,OutUnit1,OutUnit2)
SUBROUTINE ShowSevereError(ErrorMessage,OutUnit1,OutUnit2)
SUBROUTINE ShowSevereMessage(ErrorMessage,OutUnit1,OutUnit2)
SUBROUTINE ShowFatalError(ErrorMessage,OutUnit1,OutUnit2)
SUBROUTINE ShowContinueError(ErrorMessage,OutUnit1,OutUnit2)
SUBROUTINE ShowContinueErrorTimeStamp(ErrorMessage,OutUnit1,OutUnit2)
SUBROUTINE ShowMessage(Message,OutUnit1,OutUnit2)
As stated previously, you would likely never use either of the optional “OutUnit”
arguments. One use might be if you were, in addition to the normal EnergyPlus
output files, writing your own output file that would be processed separately.
Format of the error messages should be such that it makes it easy for the developer
or user to realize the context of the error. Obviously, it is usually easier for the
developer as he/she can search the code for the error string, but hard for many
users. Current suggested format is to include the Module Name and/or the Routine
name. (see section Standard Message Format for more details). This is particularly
useful when two or more places in the code have the same main error string but may
mean different things: where one might be in a Plant Loop context and the other in a
Condenser Loop context, for example.
Due to the optional parameters, Interface statements are set in DataGlobals and you
must enter USE statements defining which of the error calls you wish to use.
Example:
USE DataGlobals, ONLY: ShowSevereError
. . .
IF (Construct(ConstrNum)%LayerPoint(Layer) == 0) THEN
CALL ShowSevereError(‘Did not find matching material for construct ‘ &
//TRIM(Construct(ConstrNum)%Name)// &
‘, missing material = ‘ &
//TRIM(ConstructAlphas(Layer)))
ErrorsFound=.true.
ENDIF
This code segment will produce (with proper conditions) the message onto the error
file:
** Warning ** Did not find matching material for construct XYZ, missing material =
ABC
The ShowContinueError is used in conjunction with either ShowSevereError or
ShowWarningError. The “~~~” characters represent the continuation:
9/27/13 97
EnergyPlus Module Developer's Guide EnergyPlus Services
** Warning ** The total number of floors, walls, roofs and internal mass surfaces
in Zone ZONE ONE
** ~~~ ** is < 6. This may cause an inaccurate zone heat balance calculation.
** Warning ** No floor exists in Zone=ZONE ONE
** Warning ** Surfaces in Zone="ZONE ONE" do not define an enclosure.
** ~~~ ** Number of surfaces is <= 4 in this zone. View factor reciprocity
forced
The ShowContinueError is particularly useful with some of the previous routines that,
in addition to signaling an error, produce their own error message. For example, see
the example code in the ValidateComponent excerpt above. Note that no
ShowContinueError should be used with the ShowFatalError as it immediately
terminates the program. Instead, a Severe-Continue-Fatal sequence should be
used.
Each GetInput routine is responsible for verifying its input. Rather than terminating
with the first illegal value, however, it is better to have an “ErrorsFound” logical that
gets set to true for error conditions during the main routine processing and
terminates at the end of the GetInput routine. Of course during simulation,
conditions should also be checked and terminated if necessary. Try to give the user
as much information as possible with the set of error routine calls.
Quite a complex message can be constructed using concatenation. These routines
can also be used to output numeric fields by writing the numeric variables to a string
variable, although this isn’t very convenient.
A good use of the ContinueErrorTimeStamp as well as “counting” errors is shown
below:
IF(OutDryBulbTemp .LT. 0.0) THEN
CINErrCount1=CINErrCount1+1
IF (CINErrCount1 < 15) THEN
CALL ShowWarningError('ElectricChillerModel:Air Cooled ‘// &
‘Condenser Inlet Temperature below 0C')
CALL ShowContinueErrorTimeStamp('OutDoor Dry Bulb='// &
TRIM(RoundSigDigits(OutDryBulbTemp,2)//','))
ELSE
IF (MOD(CINErrCount1,50) == 0) THEN
WRITE(CINCharErrOut,*) CINErrCount1
CINCharErrOut=ADJUSTL(CINCharErrOut)
CALL ShowWarningError('ElectricChillerModel:Air Cooled‘// &
‘ Condenser Inlet Temperature below 0C continues...' &
//CINCharErrOut)
ENDIF
ENDIF
ENDIF
ShowWarningError, ShowWarningMessage
Both of these calls produce messages onto the .err file that signal a warning:
** Warning ** Processing Monthly Tabular Reports: PEAK SPACE GAINS
The important difference between the two calls is that the “Error” call will incrase the “number
of warnings” counter whereas the “Message” call does not incrase the counter. The
“Message” call can, therefore, be used ro “start” off a recurring sequence without disturbing
the total warning count. To do this, one would place the calls:
CALL ShowWarningMessage(xxx)
<more messages that describe the basic problem>
CALL ShowRecurringWarningErrorAtEnd(xxx,msgindex)
As indicated, this first call can also show significantly more information about the situation
than will be captured by using the Recurring error sequence.
9/27/13 98
EnergyPlus Module Developer's Guide EnergyPlus Services
ShowSevereError, ShowSevereMessage
Both of these calls produce messages onto the .err file that signal a warning:
** Severe ** Node Connection Error, Node="SOFC AIR INLET NODE",
ZoneExhaust node did not find a matching inlet node.
The important difference between the two calls is that the “Error” call will incrase the “number
of severe errors” counter whereas the “Message” call does not incrase the counter. The
“Message” call can, therefore, be used ro “start” off a recurring sequence without disturbing
the total warning count. To do this, one would place the calls:
CALL ShowSevereMessage(xxx)
<more messages that describe the basic problem>
CALL ShowRecurringSevereErrorAtEnd(xxx,msgindex)
As indicated, this first call can also show significantly more information about the situation
than will be captured by using the Recurring error sequence.
ShowFatalError
This error terminates the program.
** Fatal ** EMS user program halted simulation with error code = 9001.30
For clarity, the sequence ending in the fatal error, should start with a Severe error and give
the user a good indication of the problem. During execution, this Severe error may
immediately preceed the Fata call. During get input, errors may be found previously in the
input, interspersed with Warning errors. The last Severe error is stored and displayed as the
program terminates.
ShowContinueError, ShowContinueErrorTimeStamp
Continue errors are shown after the initial condition and formatted in a fashion that a post
processor could detect and string all the errors about a single condition together.
The basic format is simple:
** ~~~ ** ..Location object=DENVER STAPLETON INTL ARPT CO USA
WMO=724690
The continue error with time stemp adds the time stamp information to the initial message. (It
also might show if the error occurred during “warmup”).
** ~~~ ** CalcMultiSpeedDXCoil:lowspeedoutlet Occurrence info=Chicago
Ohare Intl Ap IL USA TMY3 WMO#=725300, 04/24 15:45 - 16:00
ShowMessage
This call is strictly for informative messages that are displayed to the .err file. For example:
************* Beginning Zone Sizing Calculations
************* Beginning System Sizing Calculations
************* Testing Individual Branch Integrity
************* All Branches passed integrity testing
The indicated messages help establish context for other errors that may be shown.
9/27/13 99
EnergyPlus Module Developer's Guide EnergyPlus Services
(min/max/sum) (and units thereof). And an error message index (pointer to the
message in the recurring error structure) that is stored in your data structure is used.
The first two parameters (Message, MsgIndex) are required. The remaining six
arguments (ReportMaxOf, ReportMinOf, ReportSumOf, ReportMaxUnits,
ReportMinUnits, ReportSumUnits) are optional. To illustrate, we re-write the above
call using the recurring error routines. (Note that we still do the first few counted
because we are using the TimeStamp routine – however a message buffer is set up
in this instance.).
! Print warning messages only when valid and only for the first ocurrance. Let summary provide
statistics.
! Wait for next time step to print warnings. If simulation iterates, print out
! the warning for the last iteration only. Must wait for next time step to accomplish this.
! If a warning occurs and the simulation down shifts, the warning is not valid.
IF(CurrentEndTime .GT. CurrentEndTimeLast .AND. TimeStepSys .GE. TimeStepSysLast)THEN
IF(ElectricChiller(ChillNum)%PrintMessage)THEN
ElectricChiller(ChillNum)%MsgErrorCount = &
ElectricChiller(ChillNum)%MsgErrorCount + 1
! Show single warning and pass additional info to ShowRecurringWarningErrorAtEnd
IF (ElectricChiller(ChillNum)%MsgErrorCount < 2) THEN
CALL ShowWarningError(TRIM(ElectricChiller(ChillNum)%MsgBuffer1)//'.')
CALL ShowContinueError(TRIM(ElectricChiller(ChillNum)%MsgBuffer2))
ELSE
CALL ShowRecurringWarningErrorAtEnd(TRIM(ElectricChiller(ChillNum)%MsgBuffer1)//' error
continues.', &
ElectricChiller(ChillNum)%ErrCount1,ReportMaxOf=ElectricChiller(ChillNum)%MsgDataLast, &
ReportMinOf=ElectricChiller(ChillNum)%MsgDataLast,ReportMaxUnits='[C]',ReportMinUnits='[C]')
END IF
END IF
END IF
9/27/13 100
EnergyPlus Module Developer's Guide EnergyPlus Services
DesicDehum(DesicDehumNum)%RegenFanErrorIndex4, &
ReportMaxOf=((RegenAirMassFlowRate -
Node(DesicDehum(DesicDehumNum)%RegenAirInNode)%MassFlowRate)/ RhoAirStdInit), &
ReportMinOf=((RegenAirMassFlowRate -
Node(DesicDehum(DesicDehumNum)%RegenAirInNode)%MassFlowRate)/ RhoAirStdInit))
ENDIF
Similarly, note that this is a summary message after surfaces have been gotten:
** Warning ** GetSurfaceData:The total number of floors, walls, roofs and internal mass surfaces in Zone
GARAGE ZONE
** ~~~ ** is < 6. This may cause an inaccurate zone heat balance calculation.
Display Strings
Two display routines are useful for displaying to the “run” log the progress of the
simulation. Since EnergyPlus usually runs as a “console” mode application, users
may monitor progress of the simulation. Thus, at times it is useful to have messages
displayed there. These should be minimal in number though can be used effectively
during debugging of new modules.
subroutine DisplayString(String)
subroutine DisplayNumberandString(Number,String)
The “String” parameters are normal strings. The “Number” parameter must be an
integer.
Some HVAC equipment models in EnergyPlus use performance curves. These are
polynomials in one or two independent variables that are used to modify rated
equipment performance for performance at the current, off-rated conditions. Most
often the curves are functions of temperature – entering wetbulb and outside drybulb,
for instance – or of the part load fraction. EnergyPlus provides services to input,
store, and retrieve curve data and to evaluate curves given values of the
independent variables. There are 3 curve objects: CURVE:QUADRATIC,
CURVE:CUBIC, and CURVE:BIQUADRATIC.
GetCurveIndex
This function takes a curve name as input and returns an internal pointer to the
curve. Curve values will always be accessed via the pointer not the name during the
simulation for reasons of efficiency. This function is usually called once for each
curve during the input phase.
9/27/13 101
EnergyPlus Module Developer's Guide EnergyPlus Services
GetCurveCheck
This function uses a curve name as well as an error indicator and object name to
“get” a curve index and perform error checking in one call. The calling routine will
need to check the value of the error flag and perform appropriate action.
FUNCTION GetCurveCheck(alph, errFlag, ObjName) &
RESULT (GetCurveCheckOut)
The curve index (as in GetCurveIndex) is the result. Curve values will always be
accessed via the pointer not the name during the simulation for reasons of efficiency.
This function would be called during an input phase for an object.
USE CurveManager, ONLY: GetCurveCheck
...
GasAbsorber(AbsorberNum)%CoolCapFTCurve = &
GetCurveCheck(AlphArray(8), ErrorsFound, ChillerName)
GasAbsorber(AbsorberNum)%FuelCoolFTCurve = &
GetCurveCheck(AlphArray(9), ErrorsFound, ChillerName)
GetCurveType
This function will tell the calling routine what the “curve type” that was input. This
function may be useful if your module does different calculations depending on a
curve type (i.e. cubic vs quadratic) or if it should not use a specific curve type. This
function would be called during input phase for an object.
CHARACTER(len=20) FUNCTION GetCurveType (CurveIndex)
Example of use:
USE CurveManager, ONLY: GetCurveIndex, GetCurveType
…
SELECT CASE(GetCurveType(DXCoil(DXCoilNum)%CCapFTemp))
CurveValue
This function takes the curves index and one or two independent variables as input
and returns the curve value.
USE CurveManage, ONLY: CurveValue
. . .
! Get total capacity modifying factor (function of temperature)
! for off-rated conditions
50 TotCapTempModFac = CurveValue(DXCoil(DXCoilNum)%CCapFTemp,
InletAirWetbulbC, &
OutDryBulbTemp)
Fluid property routines have been implemented within EnergyPlus with the goal of
making the specification of new fluids relatively easy for the user and not require the
9/27/13 102
EnergyPlus Module Developer's Guide EnergyPlus Services
user to specify data for the most common loop fluids. Common refrigerants are
listed within an extensive Reference Data Set (RDS) that is provided with the
EnergyPlus program.
Fluids in EnergyPlus are broken into two categories: refrigerants and glycols. This
relates back to the amount of information needed to determine the properties of the
various fluid types inside the program. The decision to define or use one class of
fluids or another relates back to whether or not one expects the fluid to change
phase (liquid and/or vapor) or remain a liquid. When a developer feels that a fluid
may change phase, all code should access the Refrigerant class of fluid property
routines. When the developer is certain that the fluid will remain a liquid and wishes
to abide by that assumption (generally, this is the case for most larger loops), all
code from such modules should access the Glycol class of fluid property routines.
Each of these classes will be described in separate sections below since each class
has different subroutine access to the main module.
Internally, both the refrigerant and glycol classes of fluids use “table lookup” and
interpolation to find the appropriate value of a fluid property. No curve fits are done
internally and the interpolation search routines are currently not optimized (no
interval halving or special fast searching techniques are used to find the values).
HOWEVER, if values out of range (too low or too high) are passed to the routines,
the value returned is a valid value at the lowest or highest (respectively) input
parameter (that was passed in out of range).
You will also note in the succeeding descriptions that IP units can be entered by
some editors (IDF Editor) using predefined unit conversions.
Using Fluid Property Routines in EnergyPlus Modules
The routines are contained within a single module: FluidProperties.f90
Developers can use the routines anywhere inside EnergyPlus through the following
USE statement:
USE FluidProperties
Access to this module may be limited by expanding this line of code with the ONLY
designator.
Fluid Properties Functions for Refrigerant Class Fluids
In EnergyPlus, a refrigerant fluid is capable of being either in the liquid or vapor
phase. Due to this definition, data must be available for both of these regions in
order for the program to accurately calculate the various fluid properties. There are
eight possible functions that may be used to obtain refrigerant data using the Fluid
Properties module. They include:
GetSatPressureRefrig(Refrigerant,Temperature,RefrigIndex,calledfrom)
GetSatTemperatureRefrig (Refrigerant,Pressure,RefrigIndex,calledfrom)
GetSatEnthalpyRefrig (Refrigerant,Temperature,Quality,RefrigIndex,calledfrom)
GetSatDensityRefrig (Refrigerant,Temperature,Quality,RefrigIndex,calledfrom)
GetSatSpecificHeatRefrig (Refrigerant,Temperature,Quality,RefrigIndex,calledfrom)
GetSupHeatEnthalpyRefrig (Refrigerant,Temperature,Pressure,RefrigIndex,calledfrom)
GetSupHeatPressureRefrig (Refrigerant,Temperature,Enthalpy,RefrigIndex,calledfrom)
GetSupHeatDensityRefrig (Refrigerant,Temperature,Pressure,RefrigIndex,calledfrom)
While most of the variables passed into the routine are self-explanatory, the three
variables that are common to each of these functions are Refrigerant, RefrigIndex
and calledfrom. Refrigerant in this case is the character string name of the
refrigerant in question as listed in the input file using the FluidNames object. This
9/27/13 103
EnergyPlus Module Developer's Guide EnergyPlus Services
must be passed into the function to identify the fluid being referenced. RefrigIndex
is an internal variable. On the first call to the fluid property routine, it is zero. All of
the fluid property routines are set-up to find a non-zero index in the local fluid
property data structure that corresponds to this refrigerant name. Since finding the
proper fluid from the fluid name each and every time is computationally slow, the
index allows the code to quickly find the right data without doing an inordinate
number of string comparisons. Thus, module developers should store the
RefrigIndex in their own local data structure in addition to the refrigerant name.
calledfrom is a string variable passed to the routine so that error messages coming
from the above functions can give a better context for errors when they happen.
Units for these other variables in these function calls are: Joules per kilogram for
enthalpy, degrees Celsius for temperature, Pascals for pressure, kilograms per cubic
meter for density, and Joules per kilogram-degree Celsius for specific heat. Quality
and concentration are dimensionless fractions. All variables are considered input
variables.
Module developers should use the functions listed above to first determine whether
they are in the saturated region or the superheated region. The
GetSatPressureRefrig and GetSatTemperatureRefrig functions should assist the
users in determining whether they are in or beyond the saturated region. Once this
is determined, the developer can call the appropriate function to obtain the quantity
of interest: in the saturated region this includes the enthalpy, density, or specific
heat; in the superheated region this includes the enthalpy, pressure, or density.
Reference Data Set (RDS) Values for Refrigerant Class Fluids
The data for refrigerants that are included in the reference data set that comes with
EnergyPlus are as follows (temperatures in Celsius, pressure in MegaPascals):
Table 3. Regions for Fluid Properties
9/27/13 104
EnergyPlus Module Developer's Guide EnergyPlus Services
*Obviously data for all temperatures at all pressures isn't loaded. The entire range of
pressures given above will work, but the temperature range for a given pressure will
be some subset of the Super Temp range shown above.
Subcooled region actually only returns h(f) or the saturated liquid value at the
temperature you input.
Fluid Property Data and Expanding the Refrigerants Available to
EnergyPlus
The Fluid Property routines have been reengineered to allow other users to add
refrigerants to the input file without having to make any changes to the program
code. The only requirement on input is that in order to add a new refrigerant, a user
must enter a full set of data. The exact definition of a full set of data is given below.
As with all EnergyPlus input, the fluid properties data has both an input data
description and a reference data set that must show up in the input file. All of the
“standard” refrigerants listed above must show up in the [Link] file for it to be available
to the rest of the simulation. Below is the description of the input data description
syntax for the fluid properties entries.
The first syntax item lists all of the fluids present in an input file and categorizes them
as either a refrigerant (such as R11, R12, etc.) or a glycol (such as ethylene glycol,
propylene glycol, etc.). A refrigerant or glycol must be in this list in order to be used
as a valid fluid in other loops in the input file.
FluidProperties:Names,
\unique-object
\extensible:2 repeat last two fields
\memo list of potential fluid names/types in the input file, maximum of ten
A1, \field Fluid 1 Name
\type alpha
A2, \field Fluid 1 Type
\type choice
\key Refrigerant
\key Glycol
A3, \field Fluid 2 Name
\type alpha
A4, \field Fluid 2 Type
\type choice
\key Refrigerant
\key Glycol
A5, \field Fluid 3 Name
\type alpha
A6, \field Fluid 3 Type
\type choice
\key Refrigerant
\key Glycol
All fluid properties vary with temperature. As a result, the following syntax allows the
user to list the temperatures at which the data points are valid. Since in many cases,
the temperatures will be similar, this provides a more compact input structure and
avoids listing the temperatures multiple times. The name associated with the
temperature list is the piece of information that will allow the actual fluid property data
9/27/13 105
EnergyPlus Module Developer's Guide EnergyPlus Services
Property data for the saturated region is entered with the following syntax. Before
the actual data is entered, this line of input must identify the refrigerant the data is to
be associated with, what the data represents (choice of one of three keywords), the
phase of the data (either fluid or gas), and the temperature list reference that links
each data point with a temperature.
9/27/13 106
EnergyPlus Module Developer's Guide EnergyPlus Services
FluidProperties:Saturated,
\memo fluid properties for the saturated region
\format FluidProperty
A1, \field Name
\type object-list
\object-list FluidNames
A2, \field Fluid Property Type
\note Enthalpy Units are J/kg
\note Density Units are kg/m3
\note SpecificHeat Units are J/kg-K
\note Pressure Units are Pa
\type choice
\key Enthalpy ! Units are J/kg
\key Density ! Units are kg/m3
\key SpecificHeat ! Units are J/kg-K
\key Pressure ! Units are Pa
A3, \field Fluid Phase
\note Fluid=saturated fluid
\note FluidGas=saturated vapor
\type choice
\key Fluid ! saturated fluid
\key FluidGas ! saturated vapor
A4, \field Temperature Values Name
\note Enter the name of a FluidProperties:Temperatures object.
\type object-list
\object-list FluidPropertyTemperatures
N1, \field Property Value 1
\type real
\unitsBasedOnField A2
N2, \field Property Value 2
\type real
\unitsBasedOnField A2
< same thing repeated over and over again>
N250; \field Property Value 250
\type real
\unitsBasedOnField A2
The format of the data for the superheated region is almost identical to that of the
saturated region with one addition—a pressure. The pressure is listed before the
rest of the data and has units of Pa.
9/27/13 107
EnergyPlus Module Developer's Guide EnergyPlus Services
FluidProperties:Superheated,
\memo fluid properties for the superheated region
\format FluidProperty
A1, \field Fluid Name
\type object-list
\object-list FluidNames
A2, \field Fluid Property Type
\note Enthalpy Units are J/kg
\note Density Units are kg/m3
\type choice
\key Enthalpy ! Units are J/kg
\key Density ! Units are kg/m3
A3, \field Temperature Values Name
\note Enter the name of a FluidProperties:Temperatures object.
\type object-list
\object-list FluidPropertyTemperatures
N1, \field Pressure
\note pressure for this list of properties
\type real
\units Pa
\minimum> 0.0
N2, \field Property Value 1
\type real
\unitsBasedOnField A2
N3, \field Property Value 2
\type real
\unitsBasedOnField A2
< same thing repeated over and over again>
N250; \field Property Value 250
\type real
\unitsBasedOnField A2
9/27/13 108
EnergyPlus Module Developer's Guide EnergyPlus Services
9/27/13 109
EnergyPlus Module Developer's Guide EnergyPlus Services
FluidProperties:Concentration,
MyPropyleneGlycol,SPECIFICHEAT ,GlycolTemperatures, ! Specific heat in J/kg-K
0.8, ! Concentration
2572,2600,2627,2655,2683,2710,2738,2766,2793,2821,2849,2876,2904,2931,2959,
2987,3014,3042,3070,3097,3125,3153,3180,3208,3236,3263,3291,3319,3346,3374,
3402,3429,3457;
The above input syntax is used to define data for a particular new fluid beyond the
default glycol fluids. It would be repeated at other appropriate concentration values,
if necessary, to define the fluid. It should be noted that in order to enter a fluid, the
user must specify all four of the properties: conductivity, specific heat, viscosity, and
density.
In addition to specifying the raw data for a new glycol, the user must list the fluid in
the FluidNames object and then specify the concentration in the
GlycolConcentrations object as shown below:
FluidProperties:Names,
MyPropyleneGlycol, GLYCOL;
GlycolConcentrations,
MyPropyleneGlycol, GLYCOL;
9/27/13 110
EnergyPlus Module Developer's Guide EnergyPlus Services
glycol, it is not enough to define raw data since this does not necessarily define the
actual concentration of glycol being used. Thus, the GlycolConcentrations object is
needed. It defines a name for the actual glycol and then refers back to the
FluidNames (first fluid listed in the above example) or to one of the default glycol
fluids (second fluid listed in the above example). It is critical that module developers
refer to the “fluid name” listed in the GlycolConcentrations object. This is the name
used inside the fluid property module to access the proper data. Note that when the
GlycolConcentrations object is read in during execution that the module will
interpolate down from a two-dimensional array of data (variation on temperature and
concentration) to a one-dimensional array of data (with temperature as the only
independent variable, concentration of a glycol fluid on any loop is assumed to be
constant). This means that only the temperature (along with the glycol fluid name
and index) must be passed into the fluid property module and also saves execution
time since only a one-dimensional interpolation is needed.
Weather Services
Global data is used sparsely in EnergyPlus, according to our goals and programming
standards. Data-only modules should be used to share data, usually across a limited
number of other modules. Two critical data-only modules have been used:
DataGlobals – contains truly global data (such as number of zones, current hour,
simulation status flags, interface statements to error and output routines)
DataEnvironment – contains weather data that is global (such as current outdoor
dry-bulb temperature, barometric pressure, etc.)
As an example of a limited data-only module, DataSurfaces contains data that is
used in the modules that reference surfaces e.g., shadowing calculations, heat
balance calculations.
Module excerpts in this document show uses of these data-only modules.
Parameters
Constants that might be useful throughout the program are defined as Fortran
parameters in the DataGlobals data module. Examples include PI, PiOvr2,
DegToRadians, and MaxNameLength. DataHVACGlobals contains parameters that
might be useful anywhere in the HVAC simulation. Some examples are
SmallTempDiff and SmallMassFlow that can be used for preventing divide by zero
errors. The full set of global parameters can be obtained by examining the modules
DataGlobals and DataHVACGlobals.
9/27/13 111
EnergyPlus Module Developer's Guide EnergyPlus Services
Simulation Flags
A number of logical flags (variables that are either true or false) are used throughout
EnergyPlus. These flags are normally used to indicate the start or end of a time or
simulation period. The following shows a complete list.
In DataGlobals:
BeginSimFlag
Set to true until the actual simulation has begun, set to false after first heat
balance time step.
BeginFullSimFlag
Set to true until a full simulation begins (as opposed to a sizing simulation); set to
false after the first heat balance time step of the full simulation.
EndSimFlag
Normally false, but set to true at the end of the simulation (last heat balance time
step of last hour of last day of last environment).
WarmupFlag
Set to true during the warmup portion of a simulation; otherwise false.
BeginEnvrnFlag
Set to true at the start of each environment (design day or run period), set to
false after first heat balance time step in environment. This flag should be used
for beginning of environment initializations in most HVAC components. See the
example module for correct usage.
EndEnvrnFlag
Normally false, but set to true at the end of each environment (last heat balance
time step of last hour of last day of environment).
BeginDayFlag
Set to true at the start of each day, set to false after first heat balance time step
in day.
EndDayFlag
Normally false, but set to true at the end of each day (last heat balance time step
of last hour of day).
BeginHourFlag
Set to true at the start of each hour, set to false after first heat balance time step
in hour.
EndHourFlag
Normally false, but set to true at the end of each hour (last heat balance time
step of hour)
BeginTimeStepFlag
Set to true at the start of each heat balance time step, set to false after first
HVAC step in the heat balance time step.
In DataHVACGlobals:
9/27/13 112
EnergyPlus Module Developer's Guide EnergyPlus Services
FirstTimeStepSysFlag
Set to true at the start of the first HVAC time step within each heat balance time
step, false at the end of the HVAC time step. In other words, this flag is true
during the first HVAC time step in a heat balance time step, and is false
otherwise.
In Subroutine SimHVAC:
FirstHVACIteration
True when HVAC solution technique on first iteration, false otherwise. Passed as
a subroutine argument into the HVAC equipment simulation driver routines.
The most commonly used logical flag in the HVAC simulation is FirstHVACIteration
that is passed around as an argument among the HVAC simulation subroutines. The
HVAC simulation is solved iteratively each HVAC time step. FirstHVACIteration is
true for the first iteration in each time step and false for the remaining iterations.
Finally, each developer must define and set a “GetInput” flag to make sure input data
is read in only once. In the example module Fans the GetInput flag is GetInputFlag;
the new developer can follow this example in using such a flag.
Psychrometric services
EnergyPlus has a full complement of psychrometric functions. All the routines are
Fortran functions returning a single precision real value. All arguments and results
are in SI units.
Note that each of the psychrometric routines has a “calledfrom” optional parameter – this has been
implemented in some of the calling routines and is useful when errors are detected during simulation for
support personnel to figure out where the psych routine is called from.
The Names for the different Psychrometric Routines are based on the following self-
explanatory format; the different variables used in the Psych Routine taxonomy are
as follows.
H = Enthalpy
W= Humidity Ratio
Rh= Relative Humidity
V= Specific Volume
Rhov= Vapor Density of Air
Hfg = Latent energy (heat of vaporization for moist air)
Hg= Enthalpy of gaseous moisture
Pb= Barometric Pressure
Twb=Temperature Wet Bulb
Twd= Temperature Dry Bulb
Tdp= Temperature Dew Point
Tsat and Psat= Saturation Temperature and Saturation Pressure
Psy## Fn ## = Psy {## is a Function of ##}
Note: Each of the two capital alphabets together have different meaning
Eg: {Psy ## Fn HW}= {Psy ## Function of Enthalpy and Humidity Ratio}
9/27/13 113
EnergyPlus Module Developer's Guide EnergyPlus Services
PsyRhoAirFnPbTdbW (Pb,Tdb,W,calledfrom)
Returns the density of air in kilograms per cubic meter as a function of barometric
pressure [Pb] (in Pascals), dry bulb temperature [Tdb] (in Celsius), and humidity ratio
[W] (kilograms of water per kilogram of dry air).
PsyCpAirFnWTdb (W,Tdb,calledfrom)
Returns the specific heat of air in Joules per kilogram degree Celsius as a function of
humidity ratio [W] (kilograms of water per kilogram of dry air) and dry bulb
temperature [Tdb] (Celsius).
PsyHfgAirFnWTdb (W,Tdb,calledfrom)
Returns the Latent energy of air [Hfg](Joules per kilogram) as a function of humidity
ratio [W] (kilograms of water per kilogram of dry air) and dry bulb temperature [Tdb]
(Celsius). It calculates hg and then hf and the difference is Hfg.
PsyHgAirFnWTdb (W,Tdb,calledfrom)
Returns the specific enthalpy of the moisture as a gas in the air in Joules per
kilogram as a function of humidity ratio [W] (kilograms of water per kilogram of dry
air) and dry bulb temperature [Tdb] (Celsius).
PsyTdpFnTdbTwbPb (Tdb,Twb,Pb,calledfrom)
Returns the dew point temperature in Celsius as a function of dry bulb temperature
[Tdb] (Celsius), wet bulb temperature [Twb] (Celsius), and barometric pressure [Pb]
(Pascals).
PsyTdpFnWPb (W,Pb,calledfrom)
Returns the dew point temperature in Celsius as a function of humidity ratio [W]
(kilograms of water per kilogram of dry air) and barometric pressure [Pb] (Pascals).
PsyHFnTdbW (Tdb,W,calledfrom)
Returns the specific enthalpy of air in Joules per kilogram as a function of dry bulb
temperature [Tdb] (Celsius) and humidity ratio [W] (kilograms of water per kilogram
of dry air).
PsyHFnTdbRhPb (Tdb,Rh,Pb,calledfrom)
Returns the specific enthalpy of air in Joules per kilogram as a function of dry bulb
temperature [Tdb] (Celsius), relative humidity [Rh] (fraction), and barometric
pressure [Pb] (Pascals).
PsyTdbFnHW (H,W,calledfrom)
Returns the air temperature in Celsius as a function of air specific enthalpy [H]
(Joules per kilogram) and humidity ratio [W] (kilograms of water per kilogram of dry
air).
PsyRhovFnTdbRh (Tdb,Rh,calledfrom)
Returns the Vapor Density in air [RhoVapor](kilograms of water per cubic meter of
air) as a function of dry bulb temperature [Tdb](Celcius), Relative Humidity [Rh]
(fraction).
9/27/13 114
EnergyPlus Module Developer's Guide EnergyPlus Services
PsyRhovFnTdbWP (Tdb,W,Pb,calledfrom)
Returns the Vapor Density in air [RhoVapor](kilograms of water per cubic meter of
air) as a function of dry bulb temperature [Tdb](Celcius), humidity ratio [W]
(kilograms of water per kilogram of dry air) and barometric pressure [Pb] (Pascals).
PsyRhFnTdbRhov (Tdb,Rhov,calledfrom)
Returns the Relative Humidity [Rh] (fraction) in air as a function of dry bulb
temperature [Tdb] (Celcius) and Vapor Density in air [RhoVapor](kilograms of water
per cubic meter of air).
PsyRhFnTdbWPb (Tdb,W,Pb,calledfrom)
Returns the relative humifity (fraction) as a function of of dry bulb temperature [Tdb]
(Celsius), humidity ratio [W] (kilograms of water per kilogram of dry air) and
barometric pressure [Pb] (Pascals).
PsyTwbFnTdbWPb (Tdb,W,Pb,calledfrom)
Returns the air wet bulb temperatute in Celsius as a function of dry bulb temperature
[Tdb] (Celsius), humidity ratio [W] (kilograms of water per kilogram of dry air) and
barometric pressure [Pb] (Pascals).
PsyVFnTdbWPb (Tdb,W,Pb,calledfrom)
Returns the specific volume in cubic meters per kilogram as a function of dry bulb
temperature [Tdb] (Celsius), humidity ratio [W] (kilograms of water per kilogram of
dry air) and barometric pressure [Pb] (Pascals).
PsyWFnTdpPb (Tdp,Pb,calledfrom)
Returns the humidity ratio in kilograms of water per kilogram of dry air as a function
of the dew point temperature [Tdp] (Celsius) and barometric pressure [Pb] (Pascals).
PsyWFnTdbH (Tdb,H,calledfrom)
Returns the humidity ratio in kilograms of water per kilogram of dry air as a function
of dry bulb temperature [Tdb] (Celsius) and air specific enthalpy [H] (Joules per
kilogram).
PsyWFnTdbTwbPb (Tdb,Twb,Pb,calledfrom)
Returns the humidity ratio in kilograms of water per kilogram of dry air as a function
of dry bulb temperature [Tdb] (Celsius), wet bulb temperature [Twb] (Celsius), and
barometric pressure [Pb] (Pascals).
PsyWFnTdbRhPb (Tdb,Rh,Pb,calledfrom)
Returns the humidity ratio in kilograms of water per kilogram of dry air as a function
of dry bulb temperature [Tdb] (Celsius), relative humidity [RH] (fraction), and
barometric pressure [Pb] (Pascals).
PsyPsatFnTemp (T,calledfrom)
Returns the saturation pressure in Pascals as a function of the air saturation
temperature [T] (Celsius).
9/27/13 115
EnergyPlus Module Developer's Guide EnergyPlus Services
PsyTsatFnHPb (H,Pb,calledfrom)
Returns the air saturation temperature in Celsius as a function of air specific enthalpy
[H] (Joules per kilogram) and barometric pressure [Pb] (Pascals).
PsyTsatFnPb (P,calledfrom)
Returns the air saturation temperature in Celsius as a function of saturation pressure
[P] (Pascals).
CPCW (Temp,calledfrom)
Returns Specific heat capacity (Joule/kilogram/kelvin) for chilled water as function
of temperature [T] (Celsius).
CPHW (Temp,calledfrom)
Returns Specific heat capacity (Joule/kilogram/kelvin) for hot water as function of
temperature [T] (Celsius).
CVHW (Temp,calledfrom)
Returns Specific heat capacity (Joule/kilogram/kelvin) for hot water at constant
volume as function of temperature [T] (Celsius).
RhoH2O (Temp,calledfrom)
Returns density of water (kg/m3) as function of Temperature [T] (Celsius).
Several utility routines are available to help generate tabular reports. To create
tabular reports, the developer needs to create a routine called something like
WriteTabularX. The WriteTabularX routine should appear in SimulationManger
between the OpenOutputTabularFile and CloseOutputTabularFile calls. The
WriteTabularX routine should make use of several utilities described below. The
“USE” statement reference OutputReportTabular module. Good example of how to
use this facility are in the OutputReportTabular file and the EconomicTariff file.
WriteReportHeaders(reportName,objectName,averageOrSum)
Where reportName is the name that you want the report to be called and the
objectName is the name of the object that appears after the “For: “ for each instance
of the report. The averageOrSum flag when set to SUM adds the phrase “per
second” after the reportName.
WriteSubtitle(subtitle)
Where the subtitle is a string that usually appears before a specific table. This is
useful if the report includes multiple tables.
WriteTable(body,rowLabels,columnLabels,widthColumn)
The WriteTable routine actually generates the tables that appear in the tabular output
file (CSV, HTML, or TXT). The rowLabels and columnLables are both one
dimensional string arrays that contain the appropriate labels. If the column labels
strings include the vertical bar symbol “|” then when creating a text report, the labels
9/27/13 116
EnergyPlus Module Developer's Guide EnergyPlus Services
will be split between lines at the vertical bar. For HTML and CSV output, the vertical
bar symbols are removed prior to display.
The body array is a two dimensional array (row,column order) containing the cells in
the body of the table. It must be strings so conversion utilities such as RealToStr
should be used to convert from numeric values.
WidthColumn is a one dimensional integer array containing the column widths for
use only with the fixed width text output option.
Services are available to help with modeling internal gains. Internal gains include the usual
sources such as people, lights, plug loads, etc., but in EnergyPlus there can also be zone
gains from the skin losses from certain equipment such as thermal tanks, electric load center
equipment and refrigeration case credits. Developers adding new device models, or adding
skin loss modeling to exisiting device models, need to use a call to SetupZoneInternalGains.
This call is defined in DataInterfaces.f90 and contains a number of optional arguments
depending on the type of internal gains involved. The types of gains that can be added with
this call include convection, radiation, and latent gains to the zone, convection and latent
gains to the return air, carbon dioxide gains to the zone and generic air contaminant gains to
the zone. For example, the call to register gains for the People object includes
convection(sensible), thermal radiation, latent, and CO2 and is:
CALL SetupZoneInternalGain(People(Loop)%ZonePtr, &
'People', &
People(Loop)%Name, &
IntGainTypeOf_People, &
ConvectionGainRate = People(Loop)%ConGainRate,&
ThermalRadiationGainRate = People(Loop)%RadGainRate, &
LatentGainRate = People(Loop)%LatGainRate, &
CarbonDioxideGainRate = People(Loop)%CO2GainRate)
The refrigerated case model includes terms for sensible and latent gains to both the zone and
the return air. These are really negative gains, or sinks, and the call to register them is:
CALL SetupZoneInternalGain(RefrigCase(CaseNum)%ActualZoneNum, &
'Refrigeration:Case', &
RefrigCase(CaseNum)%Name , &
IntGainTypeOf_RefrigerationCase, &
ConvectionGainRate = RefrigCase(CaseNum)%SensZoneCreditRate , &
ReturnAirConvectionGainRate = RefrigCase(CaseNum)%SensHVACCreditRate , &
LatentGainRate = RefrigCase(CaseNum)%LatZoneCreditRate , &
ReturnAirLatentGainRate = RefrigCase(CaseNum)%LatHVACCreditRate )
The module developer needs to program the model to update the variable in their module,
the one being registered by the call, and central routines use pointers to include the term in
the appropriate energy balances elsewhere in the model. When adding a new type of
internal gain, the new device needs to be added to arrays in DataHeatBalance.f90 called
ZoneIntGainDeviceTypes and ccZoneIntGainDeviceTypes and a new unique
“IntGainTypeOf_” parameter.
9/27/13 117
EnergyPlus Module Developer's Guide Output
Output
There are several output files available in EnergyPlus. As you can see in Appendix
A, DataGlobals contains OutputFileStandard, OutputFileInits, and OutputFileDebug.
OutputFileDebug is initialized very early in the EnergyPlus execution and is available
for any debugging output the developer might need.
OutputFileInits is intended for “one-time” outputs. If the value is calculated or
entered and should be echoed to output, this file is the place for it. The structure is
similar to the IDD/IDF structure in that there is a “definition” line followed by the data
being reported. Since the data may be produced in several places during the
simulation, the actual file looks a bit hodge-podge but can be easily imported into a
spreadsheet program and grouped.
OutputFileStandard is the reporting variable output file from EnergyPlus. You can
read more details from the Guide for Interface Developers document and in the Input
Output Reference document. OutputFileMeters is a similar file to contain meter
(only) output. Meter values also may appear in the OutputFileStandard file. Only
values that change during the simulation should be output to these files. They are
automaticallly included by the SetupOutputVariable calls.
Module developers are responsible for “setting” up the variables that will appear in
the OutputFileStandard.
To do this is very simple. All you need to do is place a simple call to
SetupOutputVariable into your module for each variable to be available for reporting.
This call should be done only once for each Variable/KeyedValue pair (see below).
For HVAC and Plant components, this call is usually at the end of the “GetInput”
subroutine. See the example module for an illustration of this. Other calls in the
simulation routines will invoke the EnergyPlus OutputProcessor automatically at the
proper time to have the data appear in the OutputFileStandard.
For you the call is:
Call SetupOutputVariable(VariableName,ActualVariable, &
IndexTypeKey, VariableTypeKey,KeyedValue,ReportFreq &
ResourceTypeKey,EndUseKey,GroupKey)
Interface statements allow for the same call to be used for either real or integer
“ActualVariable” variables. A few examples from EnergyPlus and then we will define
the arguments:
CALL SetupOutputVariable('Site Outdoor Drybulb Temperature [C]', &
OutDryBulbTemp,'Zone','Average','Environment')
9/27/13 118
EnergyPlus Module Developer's Guide Output
SetupOutput Description
Variable
Arguments
VariableName String name of variable, units should be included in []. If no
units, use []
ActualVariable This should be the actual variable that will store the value.
The OutputProcessor sets up a pointer to this variable, so it
will need to be a SAVEd variable if in a local routine. As noted
in examples, can be a simple variable or part of an
array/derived type.
IndexTypeKey When this variable has its proper value. ‘Zone’ is used for
variables that will have value on the global timestep (alias
“HeatBalance”). ‘HVAC’ is used for variables that will have
values calculated on the variable system timesteps (alias
“System”, “Plant”)
VariableTypeKey Two kinds of variables are produced. ‘State’ or ‘Average’ are
values that are instantaneous at the timestep (zone air
temperature, outdoor weather conditions). ‘NonState’ or ‘Sum’
are values which need to be summed for a period (energy).
KeyedValue Every variable to be reported needs to have an associated
keyed value. Zone Air Temperature is available for each
Zone, thus the keyed value is the Zone Name.
ReportFreq This optional argument should only be used during debugging
of your module but it is provided for the developers so that
these variables would always show up in the OutputFile. (All
other variables must be requested by the user).
ResourceTypeKey Meter Resource Type; an optional argument used for including
the variable in a meter. The meter resource type can be
'Electricity', ‘Gas’, ‘Coal’, ‘FuelOil#1’, ‘FuelOil#2’, ‘Propane’,
‘Water’, or ‘EnergyTransfer’.
EndUseKey Meter End Use Key; an optional argument used when the
variable is included in a meter. The end use keys can be:
'InteriorLights’, 'ExteriorLights', 'Heating', ‘Cooling’, 'DHW',
'Cogeneration', 'ExteriorEquipment', 'ZoneSource',
'PurchasedHotWater', 'PurchasedChilledWater', 'Fans',
'HeatingCoils', 'CoolingCoils', 'Pumps', 'Chillers', 'Boilers',
'Baseboard', 'HeatRejection', 'Humidifier', 'HeatRecovery' or
‘Refrigeration’.
EndUseSubKey Meter End Use Subcategory Key; an optional argument to
further divide a particular End Use. This key is user-defined in
the input object and can be any string, e.g., 'Task Lights', 'Exit
Lights', 'Landscape Lights', 'Computers', or 'Fax Machines'.
GroupKey Meter Super Group Key; an optional argument used when the
variable is included in a meter. The group key denotes
whether the variable belongs to the building, system, or
[Link] choices are: 'Building', 'HVAC' or 'Plant'.
9/27/13 119
EnergyPlus Module Developer's Guide Output
As described in the Input Output Reference, not all variables may be available in any
particular simulation. Only those variables that will have values generated will be
available for reporting. In the IDF, you can include a
“Output:VariableDictionary,regular;” command that will produce the [Link] file
containing all the variables with their IndexTypeKeys. This list can be used to tailor
the requests for values in the OutputFileStandard.
This variable dictionary is separated into two pieces: regular reporting variables and
meter variables. It can also be sorted by name (ascending).
For general output variables there aren’t many rules. For meter output variables
there are quite a few. Here are some tips to keep you out of trouble.
What Variables Should I Output?
The choice of variables to output is really up to the developer. Since variables don’t
appear on the output file unless requested by the user in the IDF input file, it is better
to “SetUp” too many rather than too few. For an HVAC component one should
generally output the heating and cooling outputs of the component both in terms of
energy and power. Energy is always output in Joules, power in Watts. If there is
humidification or dehumidification both total and sensible cooling should be reported.
Any electricity or fuel consumed by a component should be reported out, again both
in terms of energy (Joules) and power (Watts). For HVAC components in most cases
reporting inlet and outlet temperatures and humidities is unnecessary since these
quantities can be obtained from the system node outputs.
Output Variable Naming Conventions
The names for output variables need to be selected carefully to maintain a high level
of consistency and clarity. Well-chosen names help users quickly understand the
meaning of a specific output.
The following general guidelines are to be followed when choosing names for new
output variables:
Output variable names shall be written in title case where every major word is
capitalized (exceptions: "a", "the", "for", etc.) with spaces separating words.
Output variable names shall be written using natural language terminology
but should be relatively concise. The language is American English.
Although they should be avoided where practical, acronyms (and symbols)
are acceptable where their use is commonplace and contributes to
conciseness in identifying a complex engineering concept. Examples of
acceptable acronyms for output variable names are listed in the table below.
Abbreviations should not be used and the words spelled out completely
(except for Units).
Where practical, reuse existing names for output variables across different
models for similar components. For example, a new model for a zone
baseboard heater should reuse the existing names for output variables
already in use for other baseboard models rather than use new names that
distinguish the kind of baseboard model that the output is associated with.
The user-defined name of the component should allow the user to know the
association without the basic name of the output variable reflecting that
9/27/13 120
EnergyPlus Module Developer's Guide Output
association. This has the advantage of reducing the total number of output
variable names and making it simpler for users.
Engineering terminology should generally be consistent with that used in
ASHRAE handbooks and literature (American Society of Heating,
Refrigeration and Air-Conditioning Engineers, Inc., Atlanta, CA, USA)
Output variable names shall have no punctuation or special characters. The
names are expected to contain many adjectives adjacent to each other and
no hyphens or commas are needed to clarify.
Output variable names shall always be less than 100 characters long.
An output variable name should be constructed from up to six separate name
elements. The following diagram shows the elements and the order that they are to
be used in the name. The first three are each somewhat optional and are used as
needed to identify the type of engineering model, object, or device being reported on.
The last three are nearly always needed. Units are always needed (as described
below.
Model Classification. This name element is used to identify the specific type of
modeling being conducted. When used, it will form the first part of the name. This
name element is often not needed, such as when the output is for a more or less
usual aspect of buildings and HVAC system models. This is typically used to identify
outputs that are associated with an alternative, usually more advanced, model, such
as AirflowNetwork (AFN) or Conduction Finite Difference (CondFD). Although
modeling domains such as Building, HVAC, or Internal Loads are usually obvious
and not needed here, this classification can be useful for non-obvious sub-domains
such as Environmental Impact, Refrigeration, or Daylighting.
Spatial Classification. This name element is used to identify spatial or topological
location of the thing being reported on. It is generally used to identify which part of
the building or system is being referred to by the output. For parts of the building,
classifications such as “Zone” and “Surface” are the most common. For a model
such as Refrigeration this classification may identify specific parts of the system,
such as “Secondary Loop.” There is often no spatial or topological aspect needed
and in that case this name element can be omitted.
Type of Component. This name element is used to identify the type of device or
phenomena being modeled and reported on. For most component models this
should be a simple generic term for the type of device and attempt to reuse
established names for similar devices or models. In cases where the Model and
Spatial Classifications are sufficient, this element can be omitted.
Specific Nature. This name element is used to identify the nature of what is being
reported for the device or phenomena being modeled. This is where the most low-
level and specific detail is applied to describe the output variable. This name
element is nearly always needed.
Dimensional Nature. This name element is used to identify the nature of the
physical dimensions of the quantity being reported in words. This name element is
nearly always needed. This name element is the final part of the name so that names
end with terms that reflect the nature of the value being reported. However, the name
9/27/13 121
EnergyPlus Module Developer's Guide Output
element should not be the actual units. For example, an output that has units of
degrees Celsius, the final word in the name should be “Temperature.” Or an output
for air flow that has units of kg/s, the final words in the name should be “Mass Flow
Rate.” When reporting on electricity use in Watts, the term “Power” is used; however
most other uses of Watts use the term “Rate.”
Units. This name element is used to identify the units of the value being reported.
Units of output variables are strictly SI, as used in EnergyPlus. Units are
concatenated on the end of the name with square brackets and separated by a
space and. Dimensionless quantities shall use empty brackets “[ ].” The preferred
set of units is listed at the top of the Energy+.idd file. Units are always abbreviated.
In some situations, a model may lend itself to generating a series of related output
variables that depend on input. For example a surface heat transfer model may
have results for numerous individual nodes or cells across the thickness of the
surfaces. The number of nodes in the model will vary at runtime depending on the
Construction. When this is the case, the standard approach used in EnergyPlus is to
produce a series of output variables by enumerating the output variable name (rather
than the key value) to generate a specific name for each instance. The generated
name element for each instance in the series is appended to the end of the name
(but before the Units element) and should end in a number. For example, the third
node in a stratified tank model is called “Chilled Water Thermal Storage Temperature
Node 3 [C].” This is done to facilitate wildcarding when postprocessing output.
For Version 8.0, a comprehensive effort was made to rename output variables to
follow the guidelines and scheme described above. As of Version 8.0 the existing
output variables demonstrate the pattern and should serve as good examples to
follow for future output variables. The following table lists a few examples of terms,
but these are not meant to be comprehensive or restrictive. It is expected that new
models may have valid reasons to introduce new terms and units. Developers should
examine RDD output files for comprehensive lists of example output variable names.
Table 5. Output Variable Classifications
9/27/13 122
EnergyPlus Module Developer's Guide Output
The following table lists acronyms and symbols used in output variable names.
Table 6. Output Variable Example Abbreviations
Acronym Definition
AC Alternating Current
AFN AirflowNetwork
Ar Argon
ASHRAE American Society of Heating, Refrigeration, and Air-
Conditioning Engineers, Inc.
BSDF Bidirectional Scattering Distribution Function
CEN European Committee for Standardization (Comite Europeen
de Normalisation)
CH4 Methane
CO Carbon Monoxide
CO2 Carbon Dioxide
CondFD Conduction Finite Difference
COP Coefficient of Performance
DC Direct Current
DX Direct Expansion
EIR Energy Input Ratio
EMPD Effective Moisture Penetration Depth
H20 Water
HAMT Heat and Moisture Transfer
Hg Mercury
HHV Higher Heating Value
HVAC Heating Ventilation and Air Conditioning
KSU Kansas State University
LHV Lower Heating Value
N2 Nitrogen
N2O Nitrous Oxide
NH3 Ammonia
NMVOC Non-Methane Volatile Organic Compounds
NOx Nitrogen Oxides
O2 Oxygen
Pb Lead
9/27/13 123
EnergyPlus Module Developer's Guide Output
Acronym Definition
PM Particulate Matter
PM10 Particulate Matter of 10 microns or less in size
PM2.5 Particulate Matter of 2.5 microns or less in size
PMV Predicted Mean Vote
PPD Percent People Dissatisfied
PV Photovoltaic
PVT Photovoltaic-Thermal
SO2 Sulfur Dioxide
VAV Variable Air Volume
VRF Variable Refrigerant Flow
WAHP Water to Air Heat Pump
9/27/13 124
EnergyPlus Module Developer's Guide Output
9/27/13 125
EnergyPlus Module Developer's Guide Energy Management System
The Energy Management System (EMS) feature in EnergyPlus is an advanced user feature
that many users will not need (but may try anyway). Custom programming features are
written in the EMS runtime language (Erl). Most of the features have been added to the
modules as appropriate. Further “actuators” may need to be added (or desired to be added)
and new component developers should review the following information and determine if
actuators are useful for the component.
New component models may need to register certain control variables with the Energy
Management System. In many cases, a component model will be controlled by setpoints
placed on a system node, such as the component outlet, and the setpoints placed on the
nodes can already be actuated by the EMS. But a given new component may have internal
controls that should be made to work with EMS. When this is the case, the developer needs
to register the control point as an actuator that EMS users can reference. The content of
registered actuators is reported to the EDD file when EMS is used in a model and the
Output:EnergyManagementSystem object is configured to do so.
The EMS actuator interface is similar to SetupOutputVariable. Here is the syntax:
CALL SetupEMSActuator(<component type>, <component unique name>,
<control type name>, <units>, <logical variable on flag>,
< variable to be controlled> )
<component type> is a string representing the type of component or entity being registered.
This is usually the class name of the IDF object. Or it could be another identifying string, if not
directly associated with an object. For example the call to setup actuator for nodes uses
“System Node Setpoint.’
<component unique name> is the local user-specified object name that identifies a unique
instance among a set of the same or similar components.
<control type name> is the string identifying the type of actuator. A model may have more
than one type of control and this argument clarifys which one is being registered. A
thermostat object could, for instance, have several actuators for that object type: "On/Off",
"Heating Set Point Temperature", and "Cooling Set Point Temperature".
<units> is the string for the units of the control variable, used for reporting.
<logical variable ON flag> is a local variable attached to the object data structure that says
whether or not the actuator value should be used (see below). This becomes a pointer in the
EMS data structure so that the EMS can set the value of this variable remotely. The variable
type needs to be LOGICAL.
<variable to be controlled> is another variable attached to the object data structure that
specifies the value or state of the actuator, used in conjunction with the flag above. Similar to
above, this also becomes a pointer in the EMS data structure so that the EMS can set the
value of this variable remotely. A Fortran INTERFACE is used to overload the call the
SetupEMSActuator so that this can be either a real, integer, or logical value.
However, it is not desirable to register EMS actuators in every simulation because if there is
no use of the EMS then this just adds to memory and computation. Therefore, we wrap calls
to SetupEMSActuator inside logical checks using a global variable called
“AnyEnergyManagementSystemInModel.”
Here is an example to create an actuator that can set the power on EXTERIORLIGHTS:
if (AnyEnergyManagementSystemInModel) Then
CALL SetupEMSActuator('ExteriorLights', ExteriorLights(Item)%Name, &
'Electric Power', 'W', ExteriorLights(Item)%PowerActuatorOn, &
9/27/13 126
EnergyPlus Module Developer's Guide Energy Management System
ExteriorLights(Item)%PowerActuatorValue)
ENDIF
9/27/13 127
EnergyPlus Module Developer's Guide Running/Testing EnergyPlus – for Developers
9/27/13 128
EnergyPlus Module Developer's Guide Running/Testing EnergyPlus – for Developers
Some environment variables can be used with single or several idf file(s) to keep IDF
files pristine while allowing developers or others trying to determine a problem or run
a group of files. Many of these have counterparts in Output:Diagnostics objects
(some may not be documented). Likewise there may be some “sections” that will
produce certain outputs not generally documented.
DDOnly: Design Days Only
Setting to “yes” will cause EnergyPlus to set Run Control option (regardless of
whether there is a Run Control object in the input file) for Do the Design Day
Simulation to “yes” and Do the Weather File Simulation to “no”. (Uses logical
variable DDOnly in module DataSystemVariables). There is no Output:Diagnostics
equivalent.
Set DDOnly=yes
9/27/13 129
EnergyPlus Module Developer's Guide Running/Testing EnergyPlus – for Developers
full test suite for checking changes. The MinReportFrequency environment variable
allows EnergyPlus to report at a higher/less frequent level that still allows for
changes to be checked (though differences may require more frequent reporting to
track down). EnergyPlus reads this environment variable and sets reporting
frequency appropriately. There is no Output:Diagnostics equivalent.
Set MinReportFrequency=daily
The standard frequencies accepted by EnergyPlus must be used: detail, timestep,
hourly, daily, monthly, runperiod, environment, annual. In addition, if this environment
variable is used, the following will show in the .eio file:
! <Minimum Reporting Frequency (overriding input value)>, Value, Input Value
Minimum Reporting Frequency, !Daily [Value,Min,Hour,Minute,Max,Hour,Minute],DAILY
9/27/13 130
EnergyPlus Module Developer's Guide Running/Testing EnergyPlus – for Developers
DeveloperFlag: turn on (or off) some different outputs for the developer
Setting to “yes” (internal default is “no”) causes the program to display some different
information that could be useful to developers. In particular, this will cause the
Warmup Convergence output to show the last day for each zone, each timestep.
There is no Output:Diagnostics equivalent.
Set DeveloperFlag=yes
9/27/13 131
EnergyPlus Module Developer's Guide Running/Testing EnergyPlus – for Developers
9/27/13 132
EnergyPlus Module Developer's Guide Quick Procedure Outline For Making Code Changes to EnergyPlus
Some of the steps in this section are primarily applicable to developers who are part
of the “EnergyPlus Team”. However, these steps should also be followed as you
develop a module or other piece to submit to the EnergyPlus Team for inclusion in
an EnergyPlus release.
1. Write a New Feature Proposal (often called NFP) for discussion at a bi-weekly
conference call. Based on that discussion, update the NFP. Out of team
developers: use the NFP format to help formulate your submission
documentation to the EnergyPlus Team. The NFP format is shown in
Appendix F. The sections of the NFP format are shown in Table 1. Sections
of a New Feature Proposal.
2. Get the relevant files for your development. Team developers can check out files
from StarTeam.
a. Energy+.idd and [Link] are in the ‘Release’ Folder. This
folder also contains the “Rules” spreadsheet and “Report Variables” files.
b. [Link], [Link], and baseline or relevant IDF files
from ‘Test Files - Utilities\InternalTests\InputFiles‘
c. F90 files from the ‘SourceCode’ folder.
d. Documents ([Link], [Link],
[Link], etc.) from the ‘External
Documentation\Documentation Sources’ folder.
3. Following proper procedures (e.g., Object naming conventions are specified
earlier in this document) make your object changes to the Energy+.idd and
relevant IDF files. If your IDD modifications make changes for existing objects,
you must determine if you need to add to the “Rules” spreadsheet so that the
transition program can be made for existing IDF files. Likewise, if you change
existing report variable names, you must update the “Report Variables” file. Note
that the [Link] has some guidance on the contents of new test suite
files. Create or change existing IDF files for your feature.
4. Make code changes to F90 files for subroutines, GetInput, Sim, Report or create
your own module following the Programming Standards and Programming
Templates. Programming Templates are available in Appendix D. Programming
Standards is a separate document.
5. Compile and run in debug mode to track errors.
6. Test making sample runs; review summary and time step reports to identify
issues. Test many features of your module even if you are not including all in the
Test Suite IDF file. Go back to Step 4 as necessary. Note some of the issues in
the “Important Rules for Developers”.
7. When complete, run full test suite to make sure there are no crashes or
unexpected changes in other files.
8. Run Reverse DD for your featured files – making sure the results exactly match.
9. Update relevant portions of documents: [Link],
[Link], [Link], etc. Only excerpted
portions of the document should be sent forward for review and final inclusion in
the whole document. Depending on the changes, it may be better to “track
9/27/13 133
EnergyPlus Module Developer's Guide Quick Procedure Outline For Making Code Changes to EnergyPlus
9/27/13 134
EnergyPlus Module Developer's Guide Important Rules for Module Developers
9/27/13 135
EnergyPlus Module Developer's Guide Appendix A. DataGlobals and DataEnvironments Modules
Rather than include the code of the DataGlobals and DataEnvironments modules,
they will be described here.
DataGlobals
can be used safely from any routine. Constants such as Pi (), Degrees To Radians,
and Number of Seconds in Hour are also stored there. Remember that we suggest
compiling EnergyPlus in double precision and these constants (as should all
constants) are representative of double precision (even if someone were to compile
in single precision).
Finally, the interface specifications for the Setup Report Variables is contained in this
module. The interface allows for a single call for accomplishing that while actually
forking to call several different routines based on the type of data being used.
DataEnvironment
9/27/13 136
EnergyPlus Module Developer's Guide Appendix B. Submissions and Check-ins
There are two methods by which new modules are entered into the EnergyPlus
(publicly available) program.
Checkin: Part of the core development team may create or modify an existing
module. As we use a configuration management system – this is called a check
in.
Note --- to save people grief and rework effort and to work toward consistency
in approach, new features or changes to existing features must be proposed
in a documented way for discussion during one of the bi-weekly conference
calls.
Submission: When someone outside the core development team submits a
module or modification of an existing module for inclusion, this is termed a
submission.
Submissions are subjected to the same kind of scrutiny as team checkins and
usually will require rework by the submitter. We welcome outside developers
to send their ideas as early documents for comment with the understanding
that revising does not guarantee automatic inclusion. See the proposed
feature outline document in Appendix F and/or the “doc” file in the Documents
for Developers Zip file.
Both kinds of inclusions need to follow the checklist procedure for new inclusions:
Source Code Rules
Shall follow programming standard
Shall follow F90/95 or later standards (use “allocatable” for allocatable structures
within Derived Types)
Shall follow the Template standards (documentation, naming conventions)
Shall follow the guidelines shown in this document
All items shall be directly initialized (exception: derived type elements may be staticly
initialized)
There shall be no “unused” variables. If you put in a variable that you “might use
later” – comment it out and comment it to be used later.
No Tabs in source code!!!
Lines shall be less than 133 characters in length. (Some compilers allow longer lines
without warning).
Suggest using F95 standards checking during compiles -- you may use the compiler
option to generate warnings for non-standard code.
Permission to use the code shall be supplied -- written, even email, is required.
LBNL is monitoring this aspect – so a grant-back letter can also be
obtained from them.
Energy+.IDD rules
Standard Units shall be used (SI only on Input)
Show units with the \units field. Supply \ip-units only if your input would require it
(see comments at top of the Energy+.idd).
Use \minimum and \maximum
9/27/13 137
EnergyPlus Module Developer's Guide Appendix B. Submissions and Check-ins
The first field following the object name should contain “name” as part of the field
name
Use \default, \min-fields and \required-field appropriately
Object changes during minor releases ([Link]) should not change fields in the
middle – only at the end
Surface objects may not add further fields to the end (the end is reserved for vertices
and extension to the current limits)
Note that changes in the Energy+.idd will require a “transition” rule change in the
Rules Spreadsheet file (Rules…xls). Likewise, changes in report variable names
must be documented in the “report variables” change file that is a companion to
the Rules spreadsheet.
Testing
Shall run the full test suite for all new features and unless you are absolutely,
positively sure that your change will not impact other parts of the code. We have
a python script that can compare between two run versions (using the .csv files
output from ReadVarsESO).
If you need a script, look under StarTeam…Test Files>ScriptMaker. Other scripts
are mentioned in the section on “Running EnergyPlus for Developers” (Module
Developer’s Guide).
If you modify objects, you must change all test suite files that are impacted by your
object modifications.
New Features need a new example file
You must create a new input file for your changes—input files shall include
appropriate internal documentation! (Test files have a document template as
well see Appendix E. Test File Documentation). Some features may be
appropriately added to an existing file but documentation must be updated.
You must fill out a line in the “[Link]” spreadsheet for your new input file.
You must run a full annual run with your test file even if that is not the configuration
that ends up in the internal test suite. Annual runs have been known to fail –
obviously, your input file should not.
You must try to minimize the number of errors shown in the [Link] file for your
files.
Reverse DD Compliance Test: You must run a test that reverses a run of two
environments (design days) and make sure that the results (when you also
reverse the results files) are identical. (Identical means exactly the same.)
Several scripts and automated programs to accomplish this feat are available.
Documentation (must be included at the same time as code!!!)
A document template is available for use – only the styles in that document should
be used. (Microsoft™ Word is our standard word processing software).
Equations – limited in IORef, necessary in Engineering Doc – limit the number of
“references” though. You can use standard Equation formatting from Microsoft™
Word or Mathtype™ is an acceptable alternate.
Figures – Though AutoShapes may draw nice pictures, they are not often
“captionable” without undue editing. Please make figures into Jpegs or GIFs.
Use “insert caption” (below the figure) so that auto-numbering of figures is used
(these will transfer automatically to EnergyPlus documents).
9/27/13 138
EnergyPlus Module Developer's Guide Appendix B. Submissions and Check-ins
Tables – use “insert caption” (above the table) so that auto-numbering of figures is
used (these will transfer automatically to EnergyPlus documents).
Cross-References – limit your “insert cross references”. You should highlight these
so that “editing” from your inclusion is more obvious – use a different color to
help them stand out.
IORef – See the InputOutputReference document for indications of what is included.
Eng Ref – New modules shall include an engineering document reference. See the
Engineering Reference for indications of typical writeups.
Output Details and Examples – this can help illustrate your changes. Any new files
must be detailed in here. Likewise, changes to the .eio file must be described.
[Link]
Every change to source code, example files, datsets, utilities (any change other than
documentation) must include a line in the “[Link]” file.
Checked in?
A courtesy message to the EnergyPlus team should be done for each check in, with
details of files checked in, etc. Save one of the emails you have received if you
don’t know how many to send it to.
Defect fixing?
If you fix a defect or “fix” a suggested change (CR), you should mark it “fixed” in
StarTeam and the responsibility should automatically change back to the author
of the CR. If you fix your own CR, assign it to someone else for verification.
If you fix a defect or “fix” a suggested change, you should provide a “synopsis for
users” (on the “Custom” tab in the CR edit dialog) so that when we release the
version with your fix, we can provide something descriptive for the users.
If a defect has a workaround, you should enter this in the “Workaround” field (on the
“Solution” tab) to inform users until the fix is released in a public version.
Rules…xls
If a transition rule will be needed (or a deleted / obsolete / renamed object is needed)
– a line (or more) in this spreadsheet must be used. See example rules files
from previous releases. If in doubt, put something in.
ReportVariables…csv
If you change the name of a report variable, the transition program for release can
automatically transition older input files IF you put the old and new names into
this file.
If you delete a report variable, that detail should go in this file. Note that you must
consult others on the core development team before deleting a reported variable.
9/27/13 139
EnergyPlus Module Developer's Guide Appendix C. Documentation Specifics
Documents that module developers will typically be updating or changing are the:
Input Output Reference, Engineering Documentation, and Output Details and
Examples. You may, of course, note revisions to other documents.
All of the EnergyPlus documentation follows a Word™ template – [Link].
This template takes care of many of the nuances of formatting so that the documents
all retain the same “look and feel”. The template itself will contain examples for the
IORef and Engineering Documentation.
General guidelines:
Don’t get fancy with formatting. No extra “enters” are needed to space the
paragraphs.
Submit your pictures as pictures (jpeg, tif, gif). This will allow you to “insert
captions” below them and have them automatically numbered. (This also allows
them to be re-numbered once inside the EnergyPlus documents). Don’t use Text
boxes.
Likewise, use an “insert caption” on tables.
Table captions go above the table. Figure captions go below.
If you want to reference a table or figure in your text, use “insert cross reference”
and select table or figure as appropriate. Usually, just use the “label and
number” option.
Body Text is the expected style for most text. DO NOT put object names in a
different font (such as Courier) or as a different size though you may bold them
for emphasis.
Headings are used judiciously to help separate text.
Object names (IOReference) are Heading 3.
Each field must be described and shown as Heading 4 followed by the
description. Form should be “Field: <field Name>”. (Exception: if your object has
a repeating set of fields – you may describe the initial field set in detail such as is
done for the branch specifications fields in the Branch object).
Each object’s IDD must be shown and use the format “IDD Definition”.
An excerpt IDF using the object must be shown.
Output variables for the object must be shown (heading 4) with a heading 3
<object name> Output variables preceding.
Equations may be inserted using the Microsoft™ Equation Editor. Internally we
use software called “MathType” – that also may be used for Equations. It is not
desirable to number every equation. If you want to reference the equations, of
course, you will need to number them – it is best to number them in plain text and
then we can edit them into the rest of the documents.
Each Engineering Reference section should contain a “References” section and
should be formatted in author style (not numbered).
Example References:
ASHRAE. 1993. 1993 ASHRAE Handbook – Fundamentals. Atlanta: American Society of
Heating, Refrigerating, and Air-Conditioning Engineers, Inc.
th
Chapman, A. J. 1984. Heat Transfer, 4 Edition, New York: Macmillan Publishing Company.
9/27/13 140
EnergyPlus Module Developer's Guide Appendix C. Documentation Specifics
Lienhard, J. H. 1981. A Heat Transfer Textbook, Englewood Cliffs, N.J.: Prentice-Hall, Inc.
McClellan, T. M., and C. O. Pedersen. 1997. Investigation of Outside Heat Balance Models
for Use in a Heat Balance Cooling Load Calculation. ASHRAE Transactions, Vol. 103, Part 2,
pp. 469-484.
Walton, G. N. 1983. Thermal Analysis Research Program Reference Manual. NBSSIR 83-
2655. National Bureau of Standards.
9/27/13 141
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
The following module template can and should be used to create new modules.
Following the module template are subroutine and function templates. You should
be able to copy the template for your own use (or you can get a plain text version).
MODULE <module_name>
! MODULE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
! OTHER NOTES:
! na
! USE STATEMENTS:
! <use statements for data only modules>
USE DataGlobals, ONLY: ShowWarningError, ShowSevereError, ShowFatalError, &
MaxNameLength, ...
9/27/13 142
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
CONTAINS
SUBROUTINE Sim<module_name>
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
! USE STATEMENTS:
! na
IF (GetInputFlag) THEN
CALL Get<module_name>Input
GetInputFlag=.false.
ENDIF
9/27/13 143
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
CALL Init<module_name>(Args)
CALL Calc<module_name>(Args)
CALL Update<module_name>(Args)
CALL Report<module_name>(Args)
RETURN
SUBROUTINE Get<module_name>Input
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
! USE STATEMENTS:
USE InputProcessor, ONLY: GetNumObjectsFound, GetObjectItem ! might also use FindItemInList
USE DataIPShortCuts
<NumItems>=GetNumObjectsFound(CurrentModuleObject)
DO Item=1,<NumItems>
CALL GetObjectItem(CurrentModuleObject,Item,cAlphaArgs,NumAlphas, &
rNumericArgs,NumNumbers,IOStatus, &
AlphaBlank=lAlphaFieldBlanks,NumBlank=lNumericFieldBlanks, &
AlphaFieldnames=cAlphaFieldNames,NumericFieldNames=cNumericFieldNames)
<process, noting errors>
! Errors should be formatted as (alpha 1 should hold the name of the object)
CALL ShowSevereError(RoutineName//':'//CurrentModuleObject//'="'//trim(cAlphaArgs(1)))// &
'", invalid '//trim(cAlphaFieldNames(x))//'="'//trim(cAlphaArgs(x))//'" <condition>.')
! likewise for numeric fields
9/27/13 144
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
ENDDO
<SetupOutputVariables here...>
IF (ErrorsFound) THEN
CALL ShowFatalError(RoutineName//':'//CurrentModuleObject//': Errors found in input.')
ENDIF
RETURN
SUBROUTINE Init<module_name>
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
! USE STATEMENTS:
! na
RETURN
SUBROUTINE Size<module_name>
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
9/27/13 145
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
! USE STATEMENTS:
! na
RETURN
SUBROUTINE Calc<module_name>
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
! USE STATEMENTS:
! na
RETURN
SUBROUTINE Update<module_name>
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
9/27/13 146
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
! USE STATEMENTS:
! na
RETURN
SUBROUTINE Report<module_name>
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! <description>
! REFERENCES:
! na
! USE STATEMENTS:
! na
9/27/13 147
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
! <this routine is typically needed only for those cases where you must transform the internal data to a
reportable form>
RETURN
! SUBROUTINE INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Needs description, as appropriate.
! REFERENCES:
! na
! USE STATEMENTS:
! na
RETURN
9/27/13 148
EnergyPlus Module Developer's Guide Appendix D. Module, Subroutine, Function Templates
! FUNCTION INFORMATION:
! AUTHOR <author>
! DATE WRITTEN <date_written>
! MODIFIED na
! RE-ENGINEERED na
! METHODOLOGY EMPLOYED:
! Needs description, as appropriate.
! REFERENCES:
! na
! USE STATEMENTS:
! na
RETURN
9/27/13 149
EnergyPlus Module Developer's Guide Appendix E. Test File Documentation
Each test file, whether released to the public or not, should be a best practice model
and documented (comments at the top of the file) following the guidelines below.
The document template file is also included with each installation in the
“ExampleFiles” folder – [Link]
! <name of file>
! Basic file description: <specify number of zones, stories in building, etc>
! Highlights: <Purpose of this example file>
! Simulation Location/Run: <location information, design days, run periods>
! Location:
! Design Days (should have SummerDesignDay,WinterDesignDay designations):
! Run Period (Weather File):
! Run Control (should include this):
!
! Building: <more details about building. metric units, if also english enclose in []{} or ()>
! Floor Area:
! Number of Stories:
!
! Zone Description Details:
! Internal gains description: <lighting level, equipment, number of occupants, infiltration, daylighting,
etc>
! Interzone Surfaces:
! Internal Mass:
! People:
! Lights:
! Windows:
! Detached Shading:
! Daylight:
! Natural Ventilation :
! Compact Schedules (preferred):
! Solar Distribution:
!
! HVAC: <HVAC description and plant supply, as appropriate>
! Purchased Air:
! Zonal Equipment:
! Central Air Handling Equipment:
! System Equipment Autosize:
! Purchased Cooling:
! Purchased Heating:
! Coils:
! Pumps:
! Boilers:
! Chillers:
! Towers:
!
! Results: <how are results reported>
! Standard Reports:
! Timestep or Hourly Variables:
! Time bins Report:
! HTML Report:
! Environmental Emissions:
! Utility Tariffs:
Most of the example files have completed their documentation requirements and
include plan views of the building. Our naming convention uses an underscore (_)
as the first character of an input file “not for publication”.
9/27/13 150
EnergyPlus Module Developer's Guide Appendix F. New or Changed Proposal Feature Template
<TITLE>
<organization>
<Date(s), Original, Revision, etc>
Justification for Feature Update:
<Required>
Conference Call Conclusions:
<Optional – note date of conference call where talked about>
Other Conference Call Topics (not in scope of current proposal):
<Optional>
Overview:
<Include Description of Feature and references>
Approach:
Testing/Validation/Data Source(s):
<required>
IO Ref (draft):
<required>
IDD Object (New):
<include as appropriate>
IDD Object(s) (Revised):
<include as appropriate>
Proposed Report Variables:
Proposed additions to Meters:
EngRef (draft):
<required>
Example File and Transition changes:
As needed.
Other documents:
As needed.
9/27/13 151
Appendix G. Questionnaire for Code Contributions
ENERGYPLUS™
QUESTIONNAIRE FOR CODE CONTRIBUTIONS
The EnergyPlus™ building energy simulation computer program has been developed jointly by the University of Illinois at Urbana-
Champaign and Lawrence Berkeley National Laboratory (Berkeley Lab) under funding from the U.S. Department of Energy.
Berkeley Lab has the sole authority to administer the licensing of EnergyPlus™ software.
To ensure the long-term viability of EnergyPlus, any proposed contributions must be made with “no strings attached” – that is, at a
minimum, with royalty-free, non-exclusive, unlimited rights for Berkeley Lab to use, copy, modify, prepare derivative works, and
distribute any contributions (both source code and executables), and to permit others to do so. Exceptions to this policy are made
only in extraordinary circumstances, on a case-by-case basis, and only by Berkeley Lab’s Technology Transfer Dept.
This Questionnaire is intended to aid in our management of contributions to the EnergyPlus code base and to flag any intellectual
property or licensing issues that may need to be resolved. EnergyPlus is a team effort! We appreciate your cooperation!
THIS FORM MUST BE FILLED OUT COMPLETELY FOR US TO CONSIDER YOUR CONTRIBUTION – THANKS!
Company/Institution (“Contributor”):
Title or position:
Address:
Tel: Fax:
I have attached a brief description of my contribution (subroutine(s), module(s), library/ies, etc.). (THIS IS REQUIRED)
Yes No Don’t Know Do you have an active E+ Collaborative Developer License Agreement in place?
If ‘yes’, is your contribution a user interface? Yes No
A. AUTHORSHIP
1. For the code you are submitting, did you or your fellow employees write every line of code? Before answering “yes,” you should
actually contact your fellow employees to confirm that they did not use any code written by others,(e.g., “public domain code,” “open
source code,” etc.).
Yes No (If you don’t know, then find out.)
2. For the code you are submitting, was any written by a contractor or consultant?
Yes No (If you don’t know, then find out.) Not applicable (i.e., I answered ‘yes’ to question #1)
2(a) Have you confirmed that the funding/contract document with such contractor/consultant grants you or your institution the
necessary rights to provide a royalty-free unlimited license to your contributions to Lawrence Berkeley National Laboratory?
(Note: if you are in an academic/research institution, you should confirm this with your contracts & grants office or your
technology transfer office). If the answer is “No,” then such rights must be secured in writing before we can consider such
code for incorporation into EnergyPlus.
Yes No (If you don’t know, then find out.)
Rev130927
2(b) Did the contractors/consultants include any code that they did not actually write themselves? Before answering “yes,” you
should confirm with them that they did not use any code written by others (e.g., “public domain code,” “open source code,”
etc.).
Yes No (If you don’t know, then find out.)
3. For ANY code that was not actually written by you, your fellow employees or a contractor/consultant, do you know the portions of
the code written by others (i.e., the name of the subroutine, module, library, etc.)?
Yes No Don’t know Not applicable (no third party code included)
If “yes,” please list all third party code here (if more than two pieces of third party code, attach separate sheets for each):
B. FUNDING
1. For the code you are submitting, was your contribution funded under a Berkeley Lab R&D Subcontract?
Yes No Don’t know
2. For other funding sources, have you confirmed that the funding document (if any) grants you or your institution the necessary rights
to provide a royalty-free unlimited license to your contributions to Lawrence Berkeley National Laboratory? (Note: for employees of
academic or research institutions, you should confirm this with your contracts & grants office or your technology transfer office). If the
answer is “No,” then you do not have the necessary rights to such code and we cannot accept such code for consideration of
incorporation into EnergyPlus.
Yes No I funded this myself I don’t know the funding source
To the best of my knowledge, all of the above is complete and correct. If there are any extenuating or
exceptional circumstances regarding any of the above, I have attached a sheet to this form explaining same.
Signed: ___________________________________
Date: ___________________________________
Please submit the completed and signed form via FAX or, if scanned, via e-mail to:
Rev111012