TRNSYS 18 Programmer's Guide
TRNSYS 18 Programmer's Guide
Volume 7
Programmer's Guide
Revision history
2004-09 For TRNSYS 16.00.0000 2010-04 For TRNSYS 17.00.0013
2005-02 For TRNSYS 16.00.0037 2012-03 For TRNSYS 17.01.0000
2006-01 For TRNSYS 16.01.0000 2014-05 For TRNSYS 17.01.0002
2007-02 For TRNSYS 16.01.0003 2017-04 For TRNSYS 18.00.0010
Notice
This report was prepared as an account of work partially sponsored by the United States Government.
Neither the United States or the United States Department of Energy, nor any of their employees, nor any
of their contractors, subcontractors, or employees, including but not limited to the University of Wisconsin
Solar Energy Laboratory, makes any warranty, expressed or implied, or assumes any liability or
responsibility for the accuracy, completeness or usefulness of any information, apparatus, product or
process disclosed, or represents that its use would not infringe privately owned rights.
© 2017 by the Solar Energy Laboratory, University of Wisconsin-Madison and Thermal Energy
System Specialists, LLC
The software described in this document is furnished under a license agreement. This manual and the
software may be used or copied only under the terms of the license agreement. Except as permitted by
any such license, no part of this manual may be copied or reproduced in any form or by any means
without prior written consent from the Solar Energy Laboratory, University of Wisconsin-Madison or
Thermal Energy System Specialists, LLC of Madison, WI.
7–2
TRNSYS 18 – Programmer's Guide
TRNSYS Contributors
Additional contributors who developed components that have been included in the Standard Library are
listed in the Volume 04 – Mathematical Reference manual.
Contributors to the building model (Type 56) and its interface (TRNBuild) are listed in the Volume 05 –
Multizone Building manual.
Contributors to the TRNSYS Simulation Studio are listed in the Volume 02 – Simulation Studio manual.
7–3
TRNSYS 18 – Programmer's Guide
Table of Contents
7. PROGRAMMER'S GUIDE 7–11
7.1. Introduction and Overview 7–11
7.2. TypeStudio 7–12
7.2.1. Getting Started 7–12
7.2.2. Compiling an Existing Type 7–12
7.2.3. Writing a New Type in TypeStudio 7–13
7.2.4. TypeStudio Menu Reference 7–13
[Link]. The “File” Menu 7–13
[Link]. The “Edit” Menu 7–14
[Link]. The “View” Menu 7–14
[Link]. The “Workspace” Menu 7–14
[Link]. The “Build” Menu 7–15
[Link]. The “Help” Menu 7–15
7.2.5. Acknowledgements 7–15
7.3. Type Structure 7–16
7.3.1. Fundamentals 7–16
7.3.2. The First Line 7–18
7.3.3. DLL Export 7–18
7.3.4. USE Statements 7–19
7.3.5. Variable Declarations 7–20
7.3.6. Data Statements 7–20
7.3.7. Global Constants and Variables 7–21
7.3.8. Version Signing 7–21
7.3.9. “Last Call” Manipulations 7–22
7.3.10. “End of Time Step” Manipulations 7–23
[Link]. Resetting Counters 7–23
[Link]. Updating Storage Variables 7–23
[Link]. Updating Automatic Reporting (SSR) Variables 7–23
7.3.11. “Initialization Call” Manipulations 7–24
[Link]. Reserving Space in the Simulation Summary Report 7–26
7.3.12. “Start Time” Manipulations 7–26
[Link]. Initializing the Simulation Summary Report Data 7–28
7.3.13. “Multiple Unit” Manipulations 7–28
7.3.14. “Every Time Step” Manipulations 7–28
[Link]. Retrieve Stored Values 7–29
[Link]. Retrieve Input Values 7–29
7–4
TRNSYS 18 – Programmer's Guide
7–5
TRNSYS 18 – Programmer's Guide
7–6
TRNSYS 18 – Programmer's Guide
7–7
TRNSYS 18 – Programmer's Guide
7–8
TRNSYS 18 – Programmer's Guide
7–9
TRNSYS 18 – Programmer's Guide
7–10
TRNSYS 18 – Programmer's Guide
7. PROGRAMMER'S GUIDE
7.1. Introduction and Overview
This manual is intended for users who are familiar with constructing and running TRNSYS simulations
and who wish to write and make use of their own TRNSYS components. In order to accomplish this task,
the user must have access to a FORTRAN compiler capable of generating a 64-bit dynamic link library
(also called a DLL). NOTE that technically, it is not entirely necessary to write and compile components in
FORTRAN; because of the structure of DLLs, components can be written in other languages such as C++
as well. In these cases, the user must have a compiler capable of turning code in the programming
language of their choice into a 64-bit DLL. This manual focuses almost entirely on guiding users through
the process of writing components in FORTRAN.
As a note of caution, DLLs can pass information back and forth if they have been compiled using nearly
identical compiler settings. If the settings used in the compilers used to create the DLLs differ too much
then the DLLs will not be able to communicate with each other. Debugging this sort of problem is very
hard as the communication breakdown usually occurs between two DLLs where there are no tools that
can be used for debugging.
TRNSYS’s source code is split into two parts: the kernel contains all of the brains while the Types
calculate the performance of the various components that may be used in a given simulation. The Types
and kernel are not physically distinct from one another but are compiled and linked together in a file called
the [Link]. The distributed [Link] is compiled using the Intel Visual Fortran compiler while the
TypeStudio (discussed in section 7.2) uses the gFortran compiler. It is highly recommended that users
choose one of these two compilers in which to develop new Types if at all possible.
TRNSYS users will be familiar with the idea that TRNSYS components are all structured in a very similar
way as viewed from the outside; they take input information in the form of INPUTS and PARAMETERS
and they calculate OUTPUTS. This generic structuring extends into the code of the components
themselves; all components deal with the information that they obtain from the TRNSYS kernel in the
same way and moreover, in the same order. This generic structure means that users can build on existing
components and can copy existing components to suit their own needs. Section 7.3 explains in detail how
to structure components.
7–11
TRNSYS 18 – Programmer's Guide
7.2. TypeStudio
The TypeStudio is a graphical interface and a Fortran compiler that have been set up to facilitate creating
new Types for use with TRNSYS. The TypeStudio creates and manages workspaces that can contain
one or more TRNSYS Types. It allows the user to compile the Type(s) into a dynamic link library (dll) that
will be placed in the proper location for the TRNSYS engine to load them during a simulation.
Upon launching the TypeStudio the user should see a screen that looks like the following:
When TypeStudio launches it opens a blank workspace. Choose “Add Source Files” to add one or more
Types to the workspace. A sample Type (Type201) is provided in the
..\%TRNSYS18%\Examples\CompilingTypes\ directory.
Having added Types to the workspace, the user should next save the workspace by selecting “Save
Workspace” from the “File” menu. By default workspaces are saved in the ..\%TRNSYS18%\MyTypes
directory and have the extension *.tsw.
7–12
TRNSYS 18 – Programmer's Guide
Once Types are added and the workspace is created, it suffices to select “Compile Type” from the “Build”
menu. If successful, the TypeStudio should write a message to the screen saying that it generated a DLL.
In fact it generated two, one in release mode and one in debug mode. By default the DLLs containing the
compiled Type(s) will be placed in the ..\%TRNSYS18%\UserLib\ReleaseDLLs\ and
..\%TRNSYS18%\UserLib\DebugDLLs\ directories.
It is recommended that users new to writing Types start by generating a proforma in the Trnsys
Simulation Studio. Once the proforma is created it can be exported as FORTRAN using commands within
the Simulation Studio. The exported FORTRAN is a skeleton of the Type being written. It contains much
of the input/output and structure required of all Types. The user then edits the skeleton in the TypeStudio
environment, adding FORTRAN code to compute the values of outputs from the values of inputs and
parameters.
Selecting “Export as FORTRAN” in the Simulation Studio results in the creation of a text file having the
extension *.f90. Once the file is created by the Simulation Studio, launch the TypeStudio. When
TypeStudio launches it opens a blank workspace. Choose “Add Source Files” from the “Workspace”
menu and browse to locate the *.f90 file that was created by the Simulation Studio.
Having added the Type to the workspace, the user should next save the workspace by selecting “Save
Workspace” from the “File” menu. By default workspaces are saved in the ..\%TRNSYS18%\MyTypes
directory and have the extension *.tsw.
Once the Type is added to the workspace and appropriate equations have been added to compute the
values of the outputs, it suffices to select “Compile Type” from the “Build” menu. If successful, the
TypeStudio should write a message to the screen saying that it generated a DLL. In fact it generated two,
one in release mode and one in debug mode. By default the DLLs containing the compiled Type(s) will be
placed in the ..\%TRNSYS18%\UserLib\ReleaseDLLs\ and ..\%TRNSYS18%\UserLib\DebugDLLs\
directories.
This command creates a new blank TypeStudio workspace to which source code files may be added
using commands in the “Workspace” menu.
Open Workspace
This command opens an existing TypeStudio workspace. TypeStudio workspaces have the extension
*.tsw.
7–13
TRNSYS 18 – Programmer's Guide
Save Workspace
This commands saves all changes that have been made to the TypeStudio workspace since it was last
saved. The command also saves changes to all the files contained within the workspace.
Exit
Undo / Redo
Change Theme
This command allows the user to select between a number of screen background, and text color
schemes.
These commands increases or decreases the font size displayed in the TypeStudio editor.
Word Wrap
This command toggles whether or not lines of text are wrapped to the size of the active window.
This command is used to add new source code files to a TypeStudio workspace.
Rename File
This command allows the user to rename the active TypeStudio file.
7–14
TRNSYS 18 – Programmer's Guide
Remove File
This command is used to remove a source code file from a TypeStudio workspace.
These commands are used to change the order of the tabs (each of which represents a file that is
included in a workspace).
These commands are used to switch between the tabs (each of which represents a file that is included in
the workspace). Alternatively the user may click on tabs to change which file is visible.
Compile Workspace
This command attempts to compile all source code contained in the workspace and link it into a DLL.
Debug Workspace
This command allows the user to control the name of the DLL that is created upon compilation / linking.
The DLL name can either be set to the name of the active workspace or it can be generated as a list of
the Type numbers included in the workspace. A third option “custom” has not yet been implemented.
Open Documentation
This command is not yet active. If you are reading this though, you have already done what this
command is intended to do.
About TypeStudio
7.2.5. Acknowledgements
The TypeStudio is written and supported by Northland Numerics ([Link]
7–15
TRNSYS 18 – Programmer's Guide
The following sections of this manual will step the new TRNSYS Type programmer through the process of
filling in a Type template in order to create a new model for use in TRNSYS simulations.
7.3.1. Fundamentals
At the most fundamental level, a component (referred to as a Type) in TRNSYS is merely a black box.
The TRNSYS kernel feeds inputs to the black box and in turn, the black box produces outputs. The kernel
takes care of solving the system of black boxes. To delve a little deeper, however, TRNSYS makes a
distinction between inputs that change with time and inputs that do not change with time. Examples of
inputs that might change with time are temperature, flow rate, or voltage. Examples of inputs that do not
change with time are area or rated capacity. In the early days of TRNSYS, this distinction was critical
because computing time was very costly and inputs that do not change with time can be set once at the
beginning of a simulation thereby saving a good bit of calculation time. With modern computing power,
this distinction is less critical but TRNSYS retains the designation of time dependent inputs and time
independent inputs. Time dependent inputs are referred to as INPUTS while time independent inputs are
referred to as PARAMETERS.
At each iteration and at each time step, a component turns the current values of the INPUTS and
PARAMETERS into OUTPUTS. No distinction is made among OUTPUTS; all OUTPUTS are assumed to
be time dependent and are recomputed by a component whenever appropriate.
7–16
TRNSYS 18 – Programmer's Guide
TRNSYS has one more input / output distinction; that is DERIVATIVES. Components that solve
differential equations numerically will often have DERIVATIVES as well as INPUTS, OUTPUTS and
PARAMETERS. From the simulation user’s point of view, the DERIVATIVES for a given Type specify
initial values, such as the initial temperatures of various nodes in a thermal storage tank or the initial zone
temperatures in a multi zone building. At any given point in time, the DERIVATIVES of a Type hold the
results of the solved differential equation. If these DERIVATIVES are set in a component as OUTPUTS,
the simulation user can see, plot and output these values.
With TRNSYS v. 14.2 and lower, the TRNSYS kernel and Types were all written in FORTRAN and were
compiled together into a run-time executable that offered nothing in terms of a graphical interface, online
plotting or even a progress bar. As the Microsoft Windows operating system gained popularity and
functionality, the TRNSYS structure shifted to that of an exe/dll. In this scenario, a comparatively small
executable was written and provided by the TRNSYS developers to handle all of the Windows operating
system requirements. The kernel and Types were still written in FORTRAN but were now compiled into a
construct called a “dynamic link library” (or DLL for short). The exe and dll spoke back and forth, made
use of Windows functionality such as graphical online plotting, yet did not confuse the Type programmer
with any of the Windows trivialities. With TRNSYS versions between 14.2 and 16.0, one complexity was
that a user wishing to include a non-standard Type in their project had to recompile the DLL to include
both the standard code and the non-standard Type (and, incidentally needed a Fortran compiler to do so).
With the release of TRNSYS v.16.0, a major effort was made to allow for a multiple dll structure. That is to
say that the main exe/dll structure remained but the standard dll could also call out to other dlls and load
Types and routines found therein.
With TRNSYS v. 16.x and lower, the kernel passed certain pieces of information to each Type and
recuperated information set by the Types by means a list of arguments in the Type calling statement. Not
all of the information required by Types was available by means of the argument list, however. Types got
that other information by a hodgepodge of methods such as subroutines, COMMON blocks, access
functions, USE statements, and data modules. With the release of TRNSYS 17, the argument list was
removed and new access functions were added; Types were expected to use access functions to get all
of the data that they need from the kernel.
The remainder of this section of the Programmer’s Guide will use the example of a simple liquid heating
device to illustrate the process of writing a new component for TRNSYS.
Consider a simple heater that raises the variable inlet temperature of a flowing liquid to a user defined
:
temperature Tset. Writing an energy balance on the fluid of inlet temperature, Tin, at a mass flow rate m
The first decision that must be made by the Type programmer is: what are going to be the
PARAMETERS, INPUTS and OUTPUTS of the model. Two possibilities become apparent. If the goal of
the component is for the end user to be able to specify an inlet temperature and a desired outlet
temperature, and in return, find out how much energy was required to bring the liquid from its inlet
should obviously be an output, while m , Tset, and Tin should be
condition to its outlet condition, then Q
INPUTS. Cp could be designated as either a PARAMETER or as an INPUT depending upon whether or
not the liquid specific heat can be assumed to be constant or whether it varies significantly with liquid
temperature. If, on the other hand, the goal of the component is for the end user to provide inlet
conditions, a control signal and a heater output that is full ON whenever the control signal is set to ON,
then perhaps the output of the model would be Tout, and the inputs would be m , Tin, and Q .
For the purposes of this example, the INPUTS will be T in, Tset, and m, the OUTPUTS of interest will be
Q , the instantaneous heating rate and the outlet temperature, T out. The PARAMETERS characterizing
7–17
TRNSYS 18 – Programmer's Guide
the heater will be Tset, Cpf, and Cap, allowing the heater to be capacity limited in the amount of energy that
it can deliver to the liquid stream. Note that m will also be an OUTPUT so that this information is
available to other components. We begin at the top of the new component subroutine.
For this example, Type number 201 will arbitrarily be chosen. Thus the first line of the subroutine should
be:
SUBROUTINE TYPE201
7–18
TRNSYS 18 – Programmer's Guide
simulation where all external DLLs must be located if they are to be used. It then loads all files with the
extension *.dll, and examines them to find out if there are any exported Type subroutines contained
therein. If it finds exported Type routines it loads them into memory for the duration of the simulation. The
main advantage to end users is that they no longer have to recompile the [Link] file when they
receive a new component that they wish to use in their simulation. Instead, they merely need to drop a
DLL containing that Type into the appropriate directory. As a Type programmer, there are certain steps
that you must follow in order to compile your Type and link it as an external DLL. For more information on
linking your component into a DLL, please refer to sections 7.2 (if you are using the built-in TypeStudio)
or section 7.6 (if you are using the Intel Visual Fortran compiler) of this manual. From a code point of
view, however, you need only add one line to your component, right at the top of the file after the
SUBROUTINE declaration and before any USE statements. The syntax of the line is:
!DEC$ATTRIBUTES DLLEXPORT :: TYPEn
Where n is the Type number. For our example (Type201) we would have the following line added:
...
!DEC$ATTRIBUTES DLLEXPORT :: TYPE201
...
It is important that the syntax begin in the leftmost column. In other words, do not put any tabs or
spaces to the left of the first exclamation point. The exclamation mark is recognized as a comment by the
FORTRAN code. It is, however, noticed by the FORTRAN compiler as an indication that this subroutine
should be exported for access by other DLLs. This kind of syntax is called a “compiler directive.” It
indicates something to the compiler about how to compile the code without affecting the executable
FORTRAN itself.
7–19
TRNSYS 18 – Programmer's Guide
For the purposes of our example, the liquid heater will only need some of the TRNSYS’s Access
Functions. Thus, in the USE statement section of the code, we need only add the following line:
...
! USE STATEMENTS
Use TrnsysFunctions
...
As previously mentioned, it is permissible to list the names of those functions that we wish to access from
the TrnsysFunctions module. However, since there is little chance that we will be writing Functions of our
own in this component, the chances that the name of a local function and the name of a global function
will conflict, is minimal.
7–20
TRNSYS 18 – Programmer's Guide
setting the value of pi and the conversion factor between degrees and radians would look like the
following:
Data rdconv/0.017453/,pi/3.1415927/
!----------------------------------------------------------------------
!Get the Global Trnsys Simulation Variables
Time = getSimulationTime()
Timestep = getSimulationTimeStep()
For the purposes of the liquid heater example, we are writing a TRNSYS 17 (and later) style component
so we must add lines of code that “version sign” our Type as complying with the TRNSYS 17 coding
requirements. Note that the coding requirements did not change between v17 and v18 so the following
pertains to both TRNSYS version. The code lines that must be added are:
7–21
TRNSYS 18 – Programmer's Guide
...
!----------------------------------------------------------------------
!Set the Version Number for This Type
If (getIsVersionSigningTime()) Then
Call SetTypeVersion(17)
Return
Endif
...
If a Type fails to register the coding standard for which it was written, the TRNSYS kernel will not allow
the simulation to proceed and will generate an error, writing it to the simulation list and log files.
The Access Function “getIsLastCallOfSimulation()” also returns a “true” result if the simulation terminates
with a fatal error. In that case, the component that generates the error returns control to the TRNSYS
kernel, which calls all components one last time in order to perform their "end of simulation" operations.
You can check if the very last call occurs because of an error or as part of the normal simulation process
by calling getNumberOfErrors(). Some end of simulation operations are unnecessary or might crash
TRNSYS if the simulation ends with a fatal error. E.g. Type 22 handles the “last call” as follows:
If (getIsLastCallOfSimulation() ) Then
! Exit immediately if this call is the result of a fatal error
If (getNumberOfErrors() > 0) Then
Return
! Otherwise, print the nb of "stuck" timesteps
Else
... printing manipulations
...
EndIf
Return ! Exit
EndIf
Notes:
If the simulation ends without errors, the “last call” manipulations call happens after the user has
allowed the simulation to terminate by clicking on the "yes" or "continue" button at the end of the
simulation
7–22
TRNSYS 18 – Programmer's Guide
The lines of code here above should be placed before the normal instructions so the return occurs
before those instructions are executed.
7–23
TRNSYS 18 – Programmer's Guide
Tell the kernel how many PARAMETERS are expected to be found in the input file by calling the
setNumberOfParameters() AccessFunction as follows:
Call setNumberOfParameters(4)
Tell the kernel how many INPUTS are expected to be found in the input file by calling the
setNumberOfInputs() AccessFunction as follows:
Call setNumberOfInputs(5)
Tell the kernel how many DERIVATIVES are expected to be found in the input file by calling the
setNumberOfDerivatives() AccessFunction as follows:
Call setNumberOfDerivatives(0)
Reserve the required amount of space in the global output array by calling the setNumberOfOutputs()
AccessFunction as follows:
Call setNumberOfOutputs(5)
Set how the Type should be called using a call to setIterationMode(). Most Types will call this
AccessFunction with a value of 1, indicating that the Type should be called every iteration whether or not
its input values have changed. Types that are integrators or printers call the function with different values.
Users programming this kind of Type should refer to section [Link] for more information. The call to
setIterationMode() is as follows:
Call setIterationMode(1)
Set the number of static and dynamic storage spots required using a call to the
setNumberStoredVariables() AccessFunction. Refer to section [Link] for fundamental information about
static and dynamic data storage between time steps. It is again important to bear in mind that we are not
setting initial values of the storage variables at this time, we are merely reserving space for later usage.
For the water heater component, the following statement reserves the required space:
Call setNumberStoredVariables(0,0)
Call the routines that set three-character codes for the units of the INPUT and OUTPUT variables and
make sure that the units of the OUTPUTS that are connected to the INPUTS of this Type are correct.
Refer to section [Link] for additional information on these three letter codes. Our list of inputs, their
units, and our list of outputs and their units is as follows:
7–24
TRNSYS 18 – Programmer's Guide
Referring to Table [Link]-1 and to Table [Link]-1 through Table [Link]-22, the following
AccessFunction calls can be added to the Type, thus setting the units of the first input as a temperature in
degrees C, the units of the second input as mass flow rate in kilograms per hour, the third input as a
control signal having a value between 0 and 1, etc.
! Set the Correct Input and Output Variable Types
Call setInputUnits(1,'TE1')
Call setInputUnits(2,'MF1')
Call setInputUnits(3,'CF1')
Call setInputUnits(4,'TE1')
Call setInputUnits(5,'TE1')
Call setOutputUnits(1,'TE1')
Call setOutputUnits(2,'MF1')
Call setOutputUnits(3,'PW1')
Call setOutputUnits(4,'PW1')
Call setOutputUnits(5,'PW1')
By calling the setInputUnits() and setOutputUnits() Access Functions, we are allowing TRNSYS to check
the users connections between other Types and this one to make sure that they did not inadvertently
connect an output with units of power (‘PW1’ for example) to an input with units of temperature (‘TE1’
perhaps)
Return control to the TRNSYS kernel. Again, there are NO iterations performed during this time step.
Therefore there should be NO calculations performed. To return control, add the following line:
Return
The code required for the above steps in the context of Type201 is as follows. Please note that the
following code is fairly generic and can be copied for any Type that does not have a variable number of
parameters, inputs, or derivatives allowed in the input file. The user will, of course, have to correctly
adjust the arguments to the various AccessFunctions so that they correspond to the requirements of their
Type.
...
!----------------------------------------------------------------------
!Do All of the " First Call of the Simulation” Manipulations Here
If (getIsFirstCallofSimulation()) Then
Return
7–25
TRNSYS 18 – Programmer's Guide
EndIf
...
First, read the local parameter list and set each parameter to a local variable. Parameter values can (and
should) be read only at two places in a Type. The first is during this “Start Time” call before time has
progressed. The other is during the “multiple unit manipulations” section (discussed below in section 0).
Only reading parameters at these two stages of the simulation saves a great deal of computational time
because in this manner, parameters (which do not change with time) are read only when they must be. In
each of these two sections, each parameter value is set equal to a local variable name that has been
declared as a double precision variable among the Type’s local variables as discussed in section 7.3.5.
The generalized code for setting a parameter value to a local variable name is
LocalVariable = getParameterValue(n)
Type201 has four parameters, one each for the maximum heating rate, the specific heat of the working
liquid, the overall loss coefficient of the heater, and the heater efficiency. Referring to the code at the end
of this section, each of these four parameters is set to a local variable name: QMAX, CP, UA, and
HTREFF respectively as follows:
! Read in the Values of the Parameters from the Input File
qmax = getParameterValue(1)
cp = getParameterValue(2)
ua = getParameterValue(3)
htreff = getParameterValue(4)
The second step performed during the “start time” manipulations section is to check each of the
parameter values for validity. Parameters whose values cannot be negative, or whose values must be
between 0 and 1, can be flagged as an error using a call to the foundBadParameter() AccessFunction.
Take, for example, the specific heat of the working liquid for the heater. It does not make any physical
sense to allow the user to enter a negative value of specific heat. We could use the following code to
detect and report the problem, assuming that the second parameter is the specific heat and has been set
to a local variable called SpecHeat.
...
SpecHeat = getParameterValue(2)
If (SpecHeat < 0.0) Call foundBadParameter (2,'Fatal', &
'The fluid specific heat must be positive.')
...
7–26
TRNSYS 18 – Programmer's Guide
Once foundBadParameter() AccessFunction has reported the flagged parameter and printed its error
message to the simulation log and list files, it returns control to the calling Type but unfortunately does not
return an argument that tells the Type that an error message was written. It is good practice for a Type
that has called foundBadParameter() with a bad parameter to immediately return control to the TRNSYS
kernel without completing its “start time” manipulations in case the bad parameter could cause other
problems before the end of the call. It is therefore recommended that once all the parameters have been
checked, programmers use the ErrorFound() AccessFunction to determine whether foundBadParameter
wrote any error messages to the simulation list and log files. For more information on the ErrorFound()
AccessFunction, please refer to section [Link]. The code for returning control in this manner is:
...
If (ErrorFound()) Return
...
Next, it is necessary to set the initial values of any static or dynamic storage variables that are used by
the Type. This is accomplished simply by assigning local variable values to each of the spots in the array
that is used to transfer information to and from the storage structure, then calling the
setStaticArrayValue() and setDynamicArrayValueThisIteration() subroutines. The code used to set four
initial storage values might look like the following:
...
Call setStaticArrayValue(1,localVar1)
Call setStaticArrayValue(2,localVar2)
Call setDynamicArrayValueThisIteration(1,localVar3)
Call setDynamicArrayValueThisIteration(2,localVar4)
...
Since our Type201 does not require any storage variable spots, there is no need to include the above
step in this section of the Type201 code.
The final step performed during the “Start Time” manipulations section is to set the initial values of the
outputs. It is essential that you set initial values here. Your Type should not perform any of its calculations
at this point in time. If it does, then it will likely get one time step ahead of where it is supposed to be at
this point in the simulation. Because of this restriction on performing calculations, it is often difficult to
know what value to choose for an output initial value. A good default value is zero since that usually
indicates to the user that the output has not yet been calculated. In the case of devices that have fluid
flow through them, the outlet temperature and outlet flow rate of the fluid can often be set to the inlet
temperature and inlet flow rate respectively. In the case of Type201, the first two outputs can be set to the
input initial values in this manner. The other outputs cannot be calculated easily and so are simply set to
zero.
Below is the entire code for the “Start Time” Manipulations section of Type201.
...
!------------------------------------------------------------------------------!Do All
of the First Timestep Manipulations Here - There Are No Iterations at
! the Intial Time
If (getIsStartTime()) Then
! Read in the Values of the Parameters from the Input File
qmax = getParameterValue(1)
cp = getParameterValue(2)
ua = getParameterValue(3)
htreff = getParameterValue(4)
! Check the Parameters for Problems
If (qmax < 0.) Call foundBadParameter(1,'Fatal', &
'The heater capacity must be positive.')
If (cp < 0.) Call foundBadParameter(2,'Fatal', &
'The fluid specific heat must be positive.')
If (ua < 0.) Call foundBadParameter(3,'Fatal', &
'The heater UA must be positive.')
If ((htreff < 0.).or.(htreff > 1.)) Call foundBadParameter(4,'Fatal', &
7–27
TRNSYS 18 – Programmer's Guide
If the function returns “true” then we know that we need to reread that parameter list so that we are sure
that all local variables are set to the current instance of the Type’s parameter lists. The code is as follows:
...
!------------------------------------------------------------------------------
!ReRead the Parameters if Another Unit of This Type Has Been Called Last
If (getIsReReadParameters()) Then
qmax = getParameterValue(1)
cp = getParameterValue(2)
ua = getParameterValue(3)
htreff = getParameterValue(4)
EndIf
...
There is no need to recheck the parameters for validity since this was done already during the “Start
Time” manipulations section.
7–28
TRNSYS 18 – Programmer's Guide
Our Type201 has five inputs. However, only two of them have restrictions on their values. Namely, the
flow rate should not be negative, and the heater control signal cannot be less than zero or greater than
one. The section that sets the inputs to local variables and checks them might look like the following.
...
!----------------------------------------------------------------------
!Get the Current Inputs to the Model
tin = getInputValue(1)
flow = getInputValue(2)
igam = JFIX(getInputValue(3)+0.1)
tset = getInputValue(4)
tamb = getInputValue(5)
!------------------------------------------------------------------------------
!Perform All of the Calculations
If (flow <= 0.0) Then !if the flow rate is zero...
! There is no flow through the heater
Call setOutputValue(1,tin) !set the outlet temperature to the inlet
!temperature
Call setOutputValue(2,0.d0) !set the outlet flow rate to zero.
Call setOutputValue(3,0.d0) !set the auxiliary energy use to zero.
Call setOutputValue(4,0.d0) !set the thermal losses to zero.
Call setOutputValue(5,0.d0) !set the energy imparted to the liquid to zero.
7–29
TRNSYS 18 – Programmer's Guide
Else
! Check inlet temperature and control function
If ((tin < tset).and.(igam == 1)) Then !if the inlet temperature is below
!the set point temperature AND the
!input control signal is set to ON
! Heater on
!calculate the outlet temperature assuming that the heater is on and
! running at capacity
ton = (qmax*htreff+flow*cp*tin+ua*tamb-ua*tin/2.d0)/(flow*cp+ua/2.d0)
!the outlet temperature is the lesser of TON and TSET – the heater is able
! to modulate its energy output to reach the setpoint temperature.
tout = MIN(tset,ton)
!calculate the average heater temperature – losses are based on the
! average
tbar = (tin+tout)/2.d0
!calculate the auxiliary energy required, accounting for heater
! efficiency.
qaux = (flow*cp*(tout-tin)+ua*(tbar-tamb))/htreff
!calcualte the energy lost from the heater, including heater inefficiency
qloss = ua*(tbar-tamb) + (1.d0-htreff)*qaux
!calculate the energy imparted to the liquid.
qfluid = flow*cp*(tout-tin)
Else
! Heater off
tout = tin !set the outlet temperature equal to the inlet temperature
qaux = 0. !set the auxiliary energy required to zero.
qloss = 0. !set the thermal losses to zero.
qfluid = 0. !set the energy imparted to the liquid to zero.
EndIf
7–30
TRNSYS 18 – Programmer's Guide
7–31
TRNSYS 18 – Programmer's Guide
!------------------------------------------------------------------------------
Use TrnsysConstants
Use TrnsysFunctions
!------------------------------------------------------------------------------
!Variable Declarations
Implicit None !force explicit declaration of local variables
Double Precision Timestep,Time
Integer igam
Double Precision tin !temperature of fluid at heater inlet [C]
Double Precision tout !temperature of fluid at heater outlet [C]
Double Precision tbar !average temperature of fluid in heater [C]
Double Precision tamb !ambient temperature of heater surroundings [C]
Double Precision tset !heater setpoint temperature [C]
Double Precision ton !set temporarily to outlet temperature before check on
! TOUT>TSET [C]
Double Precision qmax !heater capacity [kJ/hr]
Double Precision qaux !required heating rate [kJ/hr]
Double Precision qloss !rate of thermal losses to surroundings [kJ/hr]
Double Precision flow !fluid flow rate through heater [kg/hr]
Double Precision cp !fluid specific heat [kJ/kg.K]
Double Precision htreff !heater efficiency [-]
Double Precision ua !overall loss coefficienct for heater during operation
! [kJ/hr.K]
Double Precision qfluid !rate of energy delivered to fluid [kJ/hr]
!------------------------------------------------------------------------------
!Get the Global Trnsys Simulation Variables
Time = getSimulationTime()
Timestep = getSimulationTimeStep()
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Set the Version Number for This Type
If (getIsVersionSigningTime()) Then
Call setTypeVersion(17)
Return
EndIf
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Do All of the “Last Call” Manipulations That May Be Required
If (getIsLastCallofSimulation()) Then
Return
EndIf
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Perform Any "End of Timestep" Manipulations That May Be Required
If (getIsEndOfTimestep()) Then
Return
7–32
TRNSYS 18 – Programmer's Guide
EndIf
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Do All of the "Very First Call of the Simulation” Manipulations Here
If (getIsFirstCallofSimulation() ) Then
! Tell the TRNSYS Engine How This Type Works
Call setNumberofParameters(4)
Call setNumberofInputs(5)
Call setNumberofDerivatives(0)
Call setNumberofOutputs(5)
Call setIterationMode(1)
Call setNumberStoredVariables(0,0)
! Set the Correct Input and Output Variable Types
Call setInputUnits(1,'TE1')
Call setInputUnits(2,'MF1')
Call setInputUnits(3,'CF1')
Call setInputUnits(4,'TE1')
Call setInputUnits(5,'TE1')
Call setOutputUnits(1,'TE1')
Call setOutputUnits(2,'MF1')
Call setOutputUnits(3,'PW1')
Call setOutputUnits(4,'PW1')
Call setOutputUnits(5,'PW1')
! Return control to the kernel
Return
EndIf
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Do All of the First Timestep Manipulations Here - There Are No Iterations at
! the Intial Time
If (getIsFirstTimestep() ) Then
! Read in the Values of the Parameters from the Input File
qmax = getParameterValue(1)
cp = getParameterValue(2)
ua = getParameterValue(3)
htreff = getParameterValue(4)
! Check the Parameters for Problems
If (qmax < 0.) Call FoundBadParameter(1,'Fatal', &
'The heater capacity must be positive.')
If (cp < 0.) Call FoundBadParameter(2,'Fatal', &
'The fluid specific heat must be positive.')
If (ua < 0.) Call FoundBadParameter(3,'Fatal', &
'The heater UA must be positive.')
If ((htreff < 0.).or.(htreff>1.)) Call FoundBadParameter(4,'Fatal', &
'The heater efficiency must be between 0 and 1.')
If (ErrorFound()) Return
! Set the Initial Values of the Outputs
Call setOutputValue(1,getInputValue(1))
Call setOutputValue(2,getInputValue(2))
Call setOutputValue(3,0.d0)
Call setOutputValue(4,0.d0)
Call setOutputValue(5,0.d0)
! Return control to the kernel
Return
EndIf
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!ReRead the Parameters if Another Unit of This Type Has Been Called Last
If (getIsReReadParameters()) Then
qmax = getParameterValue(1)
7–33
TRNSYS 18 – Programmer's Guide
cp = getParameterValue(2)
ua = getParameterValue(3)
htreff = getParameterValue(4)
EndIf
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Get the Current Inputs to the Model
tin = getInputValue(1)
flow = getInputValue(2)
igam = JFIX(getInputValue(3)+0.1)
tset = getInputValue(4)
tamb = getInputValue(5)
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Check the Inputs for Validity
If (flow < 0.) Call foundBadInput(2,’Fatal’, &
’The input mass flow rate cannot be negative’)
If ((igam > 1.).or.(igam < 0.)) Call foundBadInput(3,’Fatal’, &
’The heater control signal must be between 0 and 1.’)
If (ErrorFound() ) Return
!------------------------------------------------------------------------------
!------------------------------------------------------------------------------
!Perform All of the Calculations Here
If (flow <= 0.0) Then
! No flow
Call setOutputValue(1,tin)
Call setOutputValue(2,0.d0)
Call setOutputValue(3,0.d0)
Call setOutputValue(4,0.d0)
Call setOutputValue(5,0.d0)
Else
! Check inlet temperature and control function
If ((tin < tset).and.(igam == 1) ) Then
! Heater on
ton = (qmax*htreff+flow*cp*tin+ua*tamb-ua*tin/2.d0)/(flow*cp+ua/2.d0)
tout = MIN(tset,ton)
tbar = (tin+tout)/2.d0
qaux = (flow*cp*(tout-tin)+ua*(tbar-tamb))/htreff
qloss = ua*(tbar-tamb) + (1.d0-htreff)*qaux
qfluid = flow*cp*(tout-tin)
Else
! Heater off
tout = tin
qaux = 0.
qloss = 0.
qfluid = 0.
EndIf
! Set outputs
Call setOutputValue(1,tout)
Call setOutputValue(2,flow)
Call setOutputValue(3,qaux)
Call setOutputValue(4,qloss)
Call setOutputValue(5,qfluid)
EndIf
Return
7–34
TRNSYS 18 – Programmer's Guide
In another scenario, Types often need to compute a final value based on an initial value but they need
that initial value to be the final value at the previous time step, not the final value at the previous iteration.
Then at the end of the time step, the Type needs to take the final value calculated at the last iteration and
put it into the “final value at the last time step” spot. This can be accomplished manually using two “static”
storage spots or it can be accomplished more automatically using “dynamic” storage. In this scenario, the
Type programmer again uses the setNumberStoredVariables() AccessFunction to reserve space in the
global storage structure, at the end of each iteration, (s)he then uses the result of a call to the
getDynamicArrayValueLastTimestep() function as the basis of calculations and then uses the function
setDynamicArrayValueThisIteration() to record the calculated result. At the end of the time step, the
TRNSYS kernel takes care of moving the stored variables around so that the Type always gets the
appropriate one. Refer to section [Link].1.2 for additional information.
The idea of the SSR is not to replace traditional, detailed output reporting such as is available using
Type24, 25, and 46. The idea instead is to provide the user with a quick reference by which they can
check to make sure that a particular component in their system is performing as expected, is sized
correctly, or is operating in the intended mode.
Generally a Type can provide four kinds of information to the SSR. These are: numerical values,
integrated values, minimum / maximum values, and text strings. An example of a numerical value might
be the capacity of a heater or the area of a photovoltaic array. These are single values that the
programmer thinks might be a useful way to summarize the characteristics of a particular component.
They may, but certainly do not have to be, the values of one or more of a Type’s parameters. An example
of an integrated value might be the power consumed by a pump or the energy delivered to a flow stream
by a heat pump. Integration is automatically performed over the entire length of the simulation. An
example of a minimum/maximum value might be the efficiency of a fan motor or the COP of a chiller.
Minimums and maximums are reported over the entire length of a simulation. A text string may be used to
provide a reference for which control mode or which algorithm has been selected in a Type that offers
more than one.
7–35
TRNSYS 18 – Programmer's Guide
There are three sections of code that must be added to a Type in order to allow a user to include a
particular instance (Unit) of a Type in the SSR file produced at the end of a simulation. These are the
reservation section, the initialization section and the update section.
It should be noted that unlike many of the other steps in Type initialization, reserving space for report
variables is optional and is best done only if the user implementing the Type in a simulation has actually
asked for a particular Unit number to be reported. Therefore, the call to setNumberOfReportVariables( )
should only be executed if the current unit number has been indicated for reporting. The Type
programmer can made a call to the getIsIncludedInSSR( ) function and call the
setNumberOfReportVariables( ) subroutine only on a .true. result. The complete code for reserving space
in the SSR might look like the following:
! Set up this Type's entry in the SSR
If (getIsIncludedInSSR()) Then
Call setNumberOfReportVariables(1,2,3,4) !(nInt,nMinMax,nVals,nText)
EndIf
Returning to the example of Type201, let us say that we wish to include the heater’s energy consumption
and energy delivered over the course of the simulation (i.e. two integrated values), the minimum and
maximum heater temperature set point (one min/max value), the heater’s capacity, overall loss
coefficient, and efficiency (three numerical values). The code to reserve space would look like the
following:
! Set up this Type's entry in the SSR
If (getIsIncludedInSSR()) Then
Call setNumberOfReportVariables(2,1,3,0) !(nInt,nMinMax,nVals,nText)
EndIf
The two functions referenced in this section are further detailed in sections [Link] and [Link].
Numerical Value
Integrated Value
7–36
TRNSYS 18 – Programmer's Guide
Min/Max Value
Text Field
The general code for initializing a numerical value might look something like the following:
Call initReportValue(index,'Text Description',variableContainingValue,'units text')
The general code for initializing an integrated value might look something like the following:
Call initReportIntegral(index,'Text Description','units text','integrated units text')
The general code for initializing a min/max value might look something like the following:
Call initReportMinMax(index,'Text Description','units text')
The general code for initializing a text field might look something like the following:
Call initReportText(index,'Text Description',variableContainingValue)
As when reserving space in the SSR data structures, initialization should only be carried out if a particular
Unit has been tagged by the user as being included in the SSR. It should also be noted that text and
numberical value fields do not have to be initialized during the simulation start time step. It may be that
the values the programmer wishes to report are not known until later in the simulation.
Note that if one of the SSR variables is initialized twice, TRNSYS will generate a fatal error.
The four functions referenced in this section are further detailed in sections [Link] through [Link].
The general code for updating an integrated value might look something like the following:
Call updateReportIntegral(index,localVariable)
The general code for initializing a min/max value might look something like the following:
Call updateReportMinMax(index,localVariable)
7–37
TRNSYS 18 – Programmer's Guide
In which index is an integer and in which ‘localVariable’ is a double precision variable containing the
present value of the variable being updated.
The two functions referenced in this section are further detailed in sections [Link] and [Link].
Note that if one of the SSR variables is updated twice in the same time step, TRNSYS will generate a
fatal error.
The first method by which a Type may be compiled and linked into an external DLL is to use the
TypeStudio. The Type Studio provides a compiler that is integrated into the TRNSYS package and which
is set up to create a DLL compatible with TRNSYS. Please refer to sections 7.2.2, 7.2.3, and 7.2.4 for
information about the Type Studio and its use.
The second possibility is to use an external FORTRAN compiler to compile Types and link them into a
DLL. The advantage of this method is that many Fortran compilers offer extensive debugging features
that (among other things) will allow the user to step one line at a time through their Type code viewing the
values of internal variables while the simulation is running. The disadvantage of this method is that third
party FORTRAN compilers can be expensive and it is unfortunately quite difficult to get the compiler
settings correct such that the compiled DLL can communicate with the TRNSYS DLLs. Section 7.6 covers
the information needed in order to compile Types and create DLLs using the Intel Visual Fortran compiler.
7–38
TRNSYS 18 – Programmer's Guide
7–39
TRNSYS 18 – Programmer's Guide
maxFileWidth 1000 Maximum file width, i.e. maximum length of any line in a text file that
must be read from / written to by TRNSYS
maxFileWidth should be >= maxPathLength. This constant is also
used for strings, e.g. error messages
maxLabelLength 300 Maximum length of labels. Some labels are file- and pathnames so a
suggested value is maxLabelLength = maxPathLength
7–40
TRNSYS 18 – Programmer's Guide
Please note that the first group of access functions (getMaxDescripLength(), etc.) provide access to
global constants. Those constants are declared in the TrnsysConstants module, so Fortran-written Types
can access them more easily through an "use" statement: use TrnsysConstants. Those access functions
are provided for non-Fortran Types.
This function is only used with Solver 1 (Powell's method). You can find more information
on TRNSYS Solvers in Volume 06, TRNEdit (check the section on the Solver Statement).
An integer function that returns a 1 if the last time step converged and a 0 if the last time step did not
converge. The CheckStability function is used in SOLVER 1, which tries more than one control strategy
and then backs up a time step in order to try something else if it did not find a stable solution. TRNSYS
data reading components need to know that they should not continue reading the data file but should
back up as well.
Example Usage
if (CheckStability() < 1) then
backspace(LU_DATA)
endif
Example usage(s)
Integer :: dummyReturn,logicalUnit
...
dummyReturn = closeFileIVF(logicalUnit)
7–41
TRNSYS 18 – Programmer's Guide
the TRNSYS utility subroutine MESSAGES, which would print out the error, would log that an error
occurred and would return control to TYPECK. TYPECK would in turn return control to the Type, which
can then avoid the remainder of its calculations by accessing the ErrorFound function. An example
follows in which calculations cease if an illegal value of the input variables FLOW_CHW, FLOW_CW, or
FLOW_HW is found.
Example Usage
If(FLOW_CHW < 0.) Call TYPECK(-3,INFO,2,0,0)
If (FLOW_CW < 0.) CALL TYPECK(-3,INFO,4,0,0)
If (FLOW_HW < 0.) CALL TYPECK(-3,INFO,6,0,0)
If ( ErrorFound() ) Return
Example usage
Integer:: getConnectedOutputNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedOutputNumber (i,j)
Example usage
Integer:: getConnectedOutputNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedOutputNumberS1(i,j)
Example usage
Integer:: getConnectedTypeNumber
Integer:: i,j
...
getConnectedTypeNumber = getConnectedTypeNumber(i,j)
7–42
TRNSYS 18 – Programmer's Guide
Example usage
Integer:: getConnectedTypeNumber
Integer:: i,j
...
getConnectedTypeNumber = getConnectedTypeNumberS1(i,j)
Example usage
Integer:: getConnectedUnitNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedUnitNumber(i,j)
Example usage
Integer:: getConnectedUnitNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedUnitNumberS1(i,j)
Example usage
7–43
TRNSYS 18 – Programmer's Guide
Character*3:: getConnectedVariableType
Integer:: i,j
...
getConnectedVariableType = getConnectedVariableType (i,j)
Example usage
Character*3:: getConnectedVariableType
Integer:: i,j
...
getConnectedVariableType = getConnectedVariableTypeS1(i,j)
Example usage
Character (len=maxVarUnitLength):: getConnectedVariableUnit
Integer:: i,j
...
getConnectedVariableUnit = getConnectedVariableUnit(i,j)
Example usage
Character (len=maxVarUnitLength):: getConnectedVariableUnit
Integer:: i,j
...
getConnectedVariableUnit = getConnectedVariableUnitS1(i,j)
7–44
TRNSYS 18 – Programmer's Guide
Example Usage
DOUBLE PRECISION ErrTol
...
ErrTol = getConvergenceTolerance()
Example usage
Integer:: currentType
...
currentType = getCurrentType()
Example usage
Integer:: currentUnit
...
currentUnit = getCurrentUnit()
Example Usage
USE TrnsysConstants, ONLY: maxPathLength
Example usage(s)
7–45
TRNSYS 18 – Programmer's Guide
Example usage(s)
Use TrnsysConstants, Only :: maxPathLength
Integer :: currentUnit,length,i
Character (len=maxPathLength) :: fileLocation
...
length = getExtFilePath(currentUnit,i,extFilePath)
Example Usage
Use TrnsysConstants, Only: maxFileWidth
...
Character (len=maxFileWidth) :: myFormat
...
myFormat = getFormat(INFO(1),1)
...
! Print or read using myFormat
write(luPrint,myFormat) ... variables to be printed
Example usage(s)
Double Precision :: inputValue1, inputValue2
...
inputValue1 = getInputValue(1)
inputValue2 = getInputValue(2)
7–46
TRNSYS 18 – Programmer's Guide
Example usage(s)
Integer :: endOfTimestep
...
endOfTimestep = getIsEndOfTimestep()
~or~
If ( getIsEndOfTimestep() ) Then
...
EndIf
NOTE: in the second usage example, it is not necessary to declare a variable; FORTRAN understands
the use of an integer function that returns a 1 or 0 in place of a logical test.
Example usage(s)
Integer :: firstCall
...
firstCall = getIsFirstCallofSimulation()
~or~
If (getIsFirstCallofSimulation()) Then
...
EndIf
NOTE: in the second usage example, it is not necessary to declare a variable; FORTRAN understands
the use of an integer function that returns a 1 or 0 in place of a logical test.
7–47
TRNSYS 18 – Programmer's Guide
Example usage
If (getIsDemo() ) Then
...
EndIf
Example usage
If (getIsFirstTimestep() ) Then
...
EndIf
Example usage
If (getIsIncludedInSSR()) Then
...
EndIf
Related Functions:
Example usage
Integer :: lastCall
Logical :: drinkUp,orderAnother
...
lastCall = getIsLastCallofSimulation()
If (lastCall == 1) Then
drinkUp = .true.
orderAnother = .false.
Else
drinkUp = .false.
orderAnother = .true.
EndIf
7–48
TRNSYS 18 – Programmer's Guide
Example usage(s)
Integer :: rereadPars
...
rereadPars = getIsReReadParameters()
~or~
If (getIsReReadParameters()) Then
...
EndIf
NOTE: in the second usage example, it is not necessary to declare a variable; FORTRAN understands
the use of an integer function that returns a 1 or 0 in place of a logical test.
Example usage(s)
Integer :: readPars
...
readPars = getIsStartTime()
~or~
If (getIsStartTime()) Then
...
EndIf
NOTE: in the second usage example, it is not necessary to declare a variable; Fortran understands the
use of an integer function that returns a 1 or 0 in place of a logical test.
Example usage
If (getIsTRNSED() ) Then
...
EndIf
7–49
TRNSYS 18 – Programmer's Guide
Example usage(s)
Integer :: versSign
...
versSign = getIsVersionSigningTime()
~or~
If (getIsVersionSigningTime()) Then
...
EndIf
NOTE: in the second usage example, it is not necessary to declare a variable; FORTRAN understands
the use of an integer function that returns a 1 or 0 in place of a logical test.
Example Usage:
Use TrnsysConstants, Only: maxLabelLength
Integer ThisInstance,currentUnit
Character (len=maxLabelLength) EESLocation,EESFile(10)
...
currentUnit = getCurrentUnit()
EESLocation = getLabel(currentUnit,1)
EESFile(ThisInstance) = getLabel(currentUnit,2)
Example Usage
Integer LUW
...
LUW = getListingFileLogicalUnit()
7–50
TRNSYS 18 – Programmer's Guide
External files such as output reports or performance data can be referenced in the input in two ways. If
the external file is associated with a logical unit number by means of an ASSIGN statement, the TRNSYS
kernel will automatically open the external file. External components then do not have to open their
external files and do not even need to know the external file’s name; all they need know is the logical unit
of the file (usually passed as a parameter). If the external file is associated with a logical unit number by
means of a DESIGNATE statement, the TRNSYS kernel will not open the external file and it is left to the
component to do so. The getLUFileName() function is then needed to retrieve the name and location of
the external file associated with the logical unit (usually passed to the component as a parameter).
Example Usage
Integer LU
Character (len=maxLabelLength) fileName
...
fileName = getLUfileName(LU)
Related Functions: getLUFileName_Cpp
Example Usage
Integer strLength,LU
Character (len=maxLabelLength) fileName
...
strLength = getLUfileName_Cpp(LU, fileName)
Related Functions: getLUFileName
An integer function that returns the maximum allowable length of a variable description, e.g. input
descriptions for printers and plotters. The value of the maximum allowable length of a variable description
can be set in the TrnsysConstants file. If the value is modified, the [Link] must then be recompiled in
order for the change to take effect.
Example Usage
INTEGER DescripLen
...
DescripLen = getMaxDescripLength ()
An integer function that returns the maximum allowable width (in characters or columns) of line in any text
file that must be read by TRNSYS. This includes both the input file and external data files read by the
DynamicData utility routine. The value of the maximum allowable line length can be set in the
7–51
TRNSYS 18 – Programmer's Guide
TrnsysConstants file. If the value is modified, the [Link] must then be recompiled in order for the
change to take effect.
Example Usage
INTEGER FileWidth
...
FileWidth = getmaxFileWidth()
An integer function that returns the maximum allowable length (in characters) of variables that contain
pathnames and filenames. The value of the maximum allowable label length can be set in the
TrnsysConstants file. If the value is modified, the [Link] must then be recompiled in order for the
change to take effect.
Example Usage
INTEGER LabLen
...
LabLen = getMaxLabelLength()
An integer function that returns the maximum allowable length (in characters) of pathnames. The value of
the maximum allowable path length can be set in the TrnsysConstants file. If the value is modified, the
[Link] must then be recompiled in order for the change to take effect.
Example Usage
INTEGER PathLen
...
PathLen = getMaxPathLength()
Example Usage
Double Precision minStep
...
minStep = getMinimumTimestep()
7–52
TRNSYS 18 – Programmer's Guide
input file written for TRNSYS version 17.1. The Type programmer could access the
getMinorVersionNumber function and know whether the input file being run was written for TRNSYS
version 17.0 or 17.1, and could read the corresponding parameter list.
Example Usage
Integer minorVersNum
...
minorVersNum = getMinorVersionNumber()
Example Usage
LU = getNextAvailableLogicalUnit()
! Write some data to a temporary file
open(UNIT=LU,FILE='[Link]',status='new')
write(LU,*) ... Data to be written ...
close(LU,status='keep')
Example usage(s)
Integer :: nFiles,currentUnit
...
nFiles = getNFiles(currentUnit)
Example Usage
Integer maxIter
...
maxIter = getnMaxIterations()
An integer function that returns the maximum total number of storage spots that may be requested in a
given simulation. Note that this function is used by the setStorageSize subroutine and that therefore it is
not necessary for the Type programmer to check whether the required number of storage spots for
7–53
TRNSYS 18 – Programmer's Guide
his/her Type will exceed the maximum allowable number of storage spots. The value of the maximum
allowable number of storage spots can be set in the TrnsysConstants file. If the value is modified, the
[Link] must then be recompiled in order for the change to take effect.
Example Usage
INTEGER StorSpots
...
StorSpots = getnMaxStorageSpots()
Example Usage
Integer maxWarns
...
maxWarns = getnMaxWarnings()
Example Usage
Integer nSteps
...
nSteps = getnTimeSteps()
Example usage(s)
Integer :: nDerivs
...
nDerivs = getNumberOfDerivatives()
Example Usage
Integer NumErrs
...
NumErrs = getNumberOfErrors()
7–54
TRNSYS 18 – Programmer's Guide
Example usage(s)
Integer :: nInputs
...
nInputs = getNumberOfInputs()
Example Usage
Integer NumLabels,unitNum
...
NumLabels = getNumberOfLabels(unitNum)
Example usage(s)
Integer :: nOutputs
...
nOutputs = getNumberOfOutputs()
Example usage(s)
Integer :: nPars
...
nPars = getNumberOfParameters()
7–55
TRNSYS 18 – Programmer's Guide
Example Usage
Integer numWarns
...
numWarns = getNumberofWarnings()
Example usage(s)
Double Precision :: localDTDT(:)
Integer :: i,j
...
DTDT(i) = getNumericalDerivative(j)
Example usage(s)
Double Precision :: T(:)
Integer :: i,j
...
T(j) = getNumericalSolution(i)
Related Functions: setNumberofDerivatives(), setNumericalDerivative(), getNumericalDerivative()
Example Usage
Integer TRNSolver
7–56
TRNSYS 18 – Programmer's Guide
...
If (TRNSolver == 0) Then
... Do things required for successive substitution
Else
... Do things required for Powell's solver
EndIf
Example usage(s)
Double Precision :: outputValue1, outputValue2
...
outputValue1 = getOutputValue(1)
outputValue2 = getOutputValue(2)
Example usage(s)
Integer :: overallIteration,i
...
overallIteration = getOverallIteration(i)
Example usage(s)
Integer :: parValue1
Double Precision :: parValue2, parValue3
...
parValue1 = jfix(getParameterValue(1)+0.1)
parValue2 = getParameterValue(2)
parValue3 = getParameterValue(3)
Example usage(s)
Integer :: lastState,i
...
lastState = getPreviousControlState(i)
7–57
TRNSYS 18 – Programmer's Guide
Example Usage
Double Precision TIME0
...
TIME0 = getSimulationStartTime()
Example Usage
Double Precision TIME0V15
...
TIME0V15 = getSimulationStartTimeV15()
Example Usage
Double Precison TFINAL
...
TFINAL = getSimulationStopTime()
Example Usage
Double Precision TIME
...
TIME = getSimulationTime()
Example Usage
Double Precision DELT
...
DELT = getSimulationTimeStep()
7–58
TRNSYS 18 – Programmer's Guide
Example usage(s)
Double Precision :: value
Integer :: j
...
value = getStaticArrayValue(j)
Example usage
Logical :: timereport
...
timereport = getTimeReport()
Example usage(s)
Integer :: iteration,i
...
iteration = getTimestepIteration(i)
Example Usage
Integer StepNumber
...
StepNumber = getTimeStepNumber()
7–59
TRNSYS 18 – Programmer's Guide
Example Usage
Use TrnsysConstants, Only: maxPathLength
Example Usage
Use TrnsysConstants, Only: maxPathLength
Example Usage
Use TrnsysConstants, Only: maxPathLength
Example Usage
Use TrnsysConstants, Only: maxPathLength
7–60
TRNSYS 18 – Programmer's Guide
Example Usage
Use TrnsysConstants, Only: maxPathLength
Example Usage
Use TrnsysConstants, Only: maxPathLength
Example Usage
Integer varNum
...
varNum = getTypeVariant()
Example usage(s)
Integer :: typeVersion
...
typeVersion = getTypeVersion()
7–61
TRNSYS 18 – Programmer's Guide
Example usage
Character (len=maxDescripLength) :: columnHeader
...
Do j = 1, nVariables
columnHeader = getVariableDescription(INFO(1),j)
... write column header to a file, etc...
EndDo
Example usage
Character (len=maxVarUnitLength) :: varUnitString
...
Do j = 1, nVariables
varUnitString = getVariableDescription(INFO(1),j)
... write units to a file, etc...
EndDo
Example Usage
Integer VERSNUM
...
VERSNUM = getVersionNumber()
Example usage
Logical :: luOk
Integer :: lu
...
lu = nint(par(1))
luOk = LogicalUnitIsOpen(lu)
7–62
TRNSYS 18 – Programmer's Guide
If (luOk) Then
... !it's OK to print to / read from the file
Else
... !Probably an error in parameters
EndIf
Example usage(s)
Integer :: lun
...
Call readNextChar(lun)
Example usage(s)
Use TrnsysConstants, Only :: maxPathLength
...
Integer :: lu
Character (len=maxPathLength) :: pathAndFileName
...
Call addExternalFile(lu,pathAndFileName)
7–63
TRNSYS 18 – Programmer's Guide
be called at every iteration since Input values change with time. In the following example, the first Input is
read to a local variable called “inpValue,” the value of which must be positive.
Example usage(s)
Integer :: i
Double Precision :: inpValue
...
inpValue = getInputValue(i)
...
If (inpValue < 0.d0) Call foundBadInput(i,’fatal’, &
’the value of this input cannot be negative’)
...
If (ErrorFound() ) Return
Example usage(s)
Integer :: i
Double Precision :: parValue
...
parValue = getParameterValue(i)
...
If (parValue < 0.d0) Call foundBadParameter(i,’fatal’, &
’the value of this parameter cannot be negative’)
...
If (ErrorFound() ) Return
If this function is called more than once with the same index number, TRNSYS will generate a fatal error.
Example usage(s)
7–64
TRNSYS 18 – Programmer's Guide
Integer :: i
...
Call initReportIntegral(i,'Description of Variable','Units')
...
If this function is called more than once with the same index number, TRNSYS will generate a fatal error.
Example usage(s)
Integer :: i
...
Call initReportMinMax(i,'Description of Variable','Units')
...
Related Functions: updateReportMinMax( )
If this function is called more than once with the same index number, TRNSYS will generate a fatal error.
Example usage(s)
Integer :: i
...
Call initReportMinMax(i,'Description of Variable','Text Field')
...
If this function is called more than once with the same index number, TRNSYS will generate a fatal error.
Example usage(s)
7–65
TRNSYS 18 – Programmer's Guide
Integer :: i
Double Precision :: localVariable
...
Call initReportMinMax(i,'Description of Variable',localVariable,'Units')
...
Example usage(s)
Integer :: i ,nControllers
...
! turn OFF all of the controllers
Do i=1,nControlers
Call setDesiredControlState(i,0)
EndDo
Example usage(s)
If (getIsFirstCallOfSimulation) Then
...
Call setInputUnits(1,’TE1’)
Call setInputUnits(2,’MF1’)
...
EndIf
7–66
TRNSYS 18 – Programmer's Guide
Example usage(s)
Integer :: i
...
Call setIterationMode(i)
Example usage(s)
Integer :: i
...
If (getIsFirstCallofSimulation() ) Then
...
Call setNumberofDerivatives(i)
...
EndIf
Example usage(s)
Integer :: i
...
Call setNumberofDiscreteControls(i)
7–67
TRNSYS 18 – Programmer's Guide
Example usage(s)
Integer :: i
...
If (getIsFirstCallofSimulation() ) Then
...
Call setNumberofInputs(i)
...
EndIf
Example usage(s)
Integer :: i
...
Call setNumberofOutputs(i)
Example usage(s)
Integer :: i
...
If (getIsFirstCallofSimulation() ) Then
...
Call setNumberofParameters(i)
...
EndIf
Example usage(s)
Integer :: i,j,k,l
...
7–68
TRNSYS 18 – Programmer's Guide
Call setNumberOfReportVariables(i,j,k,l)
Example usage(s)
Integer :: i
Double Precision :: derVal
...
Call setNumericalDerivative(i,derVal)
Example usage(s)
If (getIsFirstCallOfSimulation) Then
...
Call setOutputUnits(1,’TE1’)
Call setOutputUnits(2,’TE3’)
Call setOutputUnits(3,’MF1’)
...
EndIf
Example usage(s)
Integer :: i
Double Precision :: value
7–69
TRNSYS 18 – Programmer's Guide
...
Call setOutputValue(i,value)
Example usage(s)
Integer :: typeVersion
...
If (getIsVersionSigningTime() ) Then
Call setTypeVersion(typeVersion)
Return
EndIf
Calling the function more than once with the same index during the same time step will result in an error.
Example usage(s)
Integer :: i
Double Precision :: localVariable
...
Call updateReportIntegral(i,localVariable)
...
Calling the function more than once with the same index during the same time step will result in an error.
Example usage(s)
Integer :: i
Double Precision :: localVariable
...
Call updateReportMinMax(i,localVariable)
7–70
TRNSYS 18 – Programmer's Guide
...
Example usage(s)
Use TrnsysConstants, Only :: maxMessageLength
...
Character (len=maxMessageLength) :: messageText
...
Call writeToList(messageText)
getLABEL2(i,j, outLabel)
This function is similar to the getLabel() function discussed in section [Link]. It is used by external
programs that call TRNSYS Types. getLabel2() is a character function that returns the j th label of unit i.
The length of the returned string is maxLabelLength. For example, Type66 takes two LABELs; the first is
the location of the EES executable, the second is the name and location of the EES file that is to be
solved. To access these labels, Type66 contains the following code:
Example Usage:
Use TrnsysConstants, Only: maxLabelLength
Integer ThisInstance,currentUnit
Character (len=maxLabelLength) EESLocation,EESFile(10)
...
currentUnit = getCurrentUnit()
EESLocation = getLabel(currentUnit,1)
EESFile(ThisInstance) = getLabel(currentUnit,2)
initTrnsys(deckVersionNumber)
A function that sets a number of kernel variables that need to exist before a Type can be called directly
from an external program (ie not from the TRNSYS kernel).
Example usage(s)
Integer :: i
...
Call initTrnsys(i)
7–71
TRNSYS 18 – Programmer's Guide
resetErrors()
A function that resets the value of the TRNSYS kernel’s IERROR variable. IERROR is global variable
containing the number of errors encountered in the simulation
Example usage(s)
...
Call resetErrors()
...
setCurrentType(TypeNum)
A function that resets the current Type. Many other access functions (particularly the “get” functions)
access information about the current Type. Normally, the kernel decides what the current Type is (based
on where it is in the calling order and its iterations at the current time step). This function supersedes the
kernel-set Tnit number, changing it to the one set as the integer argument to the function.
Example usage(s)
Integer :: currentType
...
Call setCurrentType(currentType)
setCurrentUnit(UnitNum)
A function that resets the current Unit. Many other access functions (particularly the “get” functions)
access information about the current Unit. Normally, the kernel decides what the current Unit is (based on
where it is in the calling order and its iterations at the current time step). This function supersedes the
kernel-set Unit number, changing it to the one set as the integer argument to the function.
Example usage(s)
Integer :: currentUnit
...
Call setCurrentUnit(currentUnit)
setInputValue(i,InValue)
A function that sets the ith input value of the current Unit to InValue. Under normal circumstances, Types
use the getInputValue() function to obtain the current values of their inputs from the TRNSYS kernel. The
setInputValue() function would be used if some engine other than the TRNSYS kernel were directing the
simulation.
Example usage(s)
7–72
TRNSYS 18 – Programmer's Guide
Integer :: i
Double Precision :: newInputValue
...
Call setInputValue(i,newInputValue)
setNumericalSolution(i,tValue)
A function that sets the ith value of the current Unit’s T() array to tValue. Under normal circumstances,
Types use the getNumericalSolution() function to obtain the current values of their T() array from the
TRNSYS kernel. The setNumericalValue() function would be used if some engine other than the TRNSYS
kernel were solving numerical differential equations in place of the TRNSYS kernel.
Example usage(s)
Integer :: i
Double Precision :: tValue
...
Call setNumericalSolution(i,tValue)
setParameterValue(i,Value)
A rarely used function that sets the ith parameter of the current Unit to a particular value. This function is
rarely used because under normal circumstances, the parameter values for all Units are set in the input
file, are read by the kernel and are made available to be read by the Types. Hardly ever would a Type set
a parameter value as this would supersede information in the input file.
Example usage(s)
Integer :: i
Double Precision :: value
...
Call setParameterValue(i,value)
setPreviousControlState(i,controlState)
A function that sets the ith value of the current Unit’s ICNTRL() array to controlState. Under normal
circumstances, Types use the getPreviousControlState() function to obtain the current values of their
ICNTRL() array from the TRNSYS kernel. The setPreviousControlState() function would be used if some
engine other than the TRNSYS kernel were determining the Powell’s Method control states.
Example usage(s)
Integer :: i,controlState
...
Call setInputValue(i,controlState)
7–73
TRNSYS 18 – Programmer's Guide
setSimulationStartTime(newStart)
A function that resets the simulation start time, superseding the value that was read from the TRNSYS
input file.
Example usage(s)
Double Precision :: newStart
...
Call setSimulationStartTime(newStart)
setSimulationStopTime(newStop)
A function that resets the simulation stop time, superseding the value that was read from the TRNSYS
input file.
Example usage(s)
Double Precision :: newStop
...
Call setSimulationStopTime(newStop)
setSimulationTime(SimTime)
A function that resets the simulation time, superseding the value that was set by the kernel.
Example usage(s)
Double Precision :: simTime
...
Call setSimulationTimeStep(simTime)
setSimulationTimeStep(newStep)
A function that resets the simulation time step, superseding the value that was read from the TRNSYS
input file.
Example usage(s)
Double Precision :: newStep
...
Call setSimulationTimeStep(newStep)
7–74
TRNSYS 18 – Programmer's Guide
setTimestepIteration(i)
A function that resets the current iteration number for the current time step. Under normal circumstances,
the TRNSYS kernel continues calling all of the components in the system until it decides that
convergence has been reached. Each time the kernel recalls the component set, it increments a counter
that keeps track of the number of iterations that have gone by in the current time step. This function
supersedes the kernel-set iteration number for the current Unit (ie not for all Units). At the next iteration,
the kernel will reset the value for the current Unit so that it matches that of all the rest.
Example usage(s)
Integer :: i
...
Call setTimestepIteration(i)
7–75
TRNSYS 18 – Programmer's Guide
INFO(n) Role
1 Unit number
2 Type number
3 Number of Inputs in the input file (.dck) for this Unit
4 Number of Parameters in the input file (.dck) for this Unit
5 Number of Derivatives in the input file (.dck) for this Unit
6 Number of outputs (set by the Type)
7 Number of iterative calls to this Unit in the current time step. Special values: -1, -2
8 Total number of calls to this unit. Special values: -1
9 Indicate whether or not the Type depends on the passage of time and tells TRNSYS where
the Type should go in the calling sequence
10 Used in storage management for TRNSYS 15 Types (not used by TRNSYS 16 Types)
11 Indicates number of discrete control variables
12 TRNSYS version for which the Type was written (15 or 16)
13 Indicates when all Units have converged in the current time step
14 Reserved for future use
15 Reserved for future use
[Link]. INFO(1:5)
The fist 5 spots in INFO are set by TRNSYS from information in the input file (.dck). They are used to
distinguish the current Unit / Type from the other ones and to detect possible configuration errors with the
TYPECK routine. It is possible to check that the number of parameters in the input file is acceptable, etc.
[Link]. INFO(6)
INFO(6) indicates the number of outputs used by the Type. A minimum of 20 outputs is reserved for each
unit in the simulation, but INFO(6) should always be set to provide an accurate Trace and insure efficient
error checking.
7–76
TRNSYS 18 – Programmer's Guide
[Link]. INFO(7)
INFO(7) indicates how many times the Unit has been called in the current time step. This information is
very useful for building stability into user written controller routines and for eliminating unneeded
calculations at each time step. INFO(7) also carries out information through special values (-1 and -2).
Possible values of INFO(7) are listed in Table [Link]-1.
INFO(7) Role
-2 Special call at the very beginning of the simulation to allow for Type version signing. Types
should only set the value of INFO(13) during this call
-1 Initial call in simulation for this Unit. The Type should only perform initialization operations
here: array sizing, memory allocation, file opening, parameter checking, etc. The Type
should also set the value of INFO(6), INFO(9) and INFO(10) (if used)
0 First call in the current time step for this Unit.
1 First iterative call (second call) in the current time step for this Unit
2 Second iterative call (third call) in the current time step for this Unit
+n nth iterative call ((n+1)th call) in the current time step for this Unit
[Link]. INFO(8)
INFO(8) indicates how many times the Unit has been called in the simulation. INFO(8) also carries out
information through special values (-1). Possible values of INFO(8) are listed in Table [Link]-1.
INFO(8) Role
1 Very first call in the simulation (version signing call)
2 Initialization call (INFO(7) = -1)
3 Initial conditions at Time = Start time (no iteration for this time step)
4 First call of the first time step (Time = Start time + Time step)
5 Second call of the first time step (Time = Start time + Time step)
6 Third call of the first time step, or first call of next time step
… Etc
-1 Very last call of the simulation. This call occurs after the "OK" or "Continue? Yes" button
has been pressed in TRNExe. Types should close files and perform other post-simulation
tasks during this call.
7–77
TRNSYS 18 – Programmer's Guide
INFO(9) is initialized to 1 for all Types by the TRNSYS Kernel. Each Type can change that value during
the initialization call (when INFO(7) = -1).
Possible values of INFO(9) are listed in Table [Link]-1. Please note that the introduction of a post-
convergence call (flagged with INFO(13) = 1) makes some of the options offered by INFO(9) redundant.
They have been kept for backwards compatibility.
INFO(9) Role
0 The Type's outputs only depend upon its input values and not explicitly upon time.
Note that failure to properly identify such a component (keeping the default value of
INFO(9) = 1) will only results in some unnecessary calls to the component
1 The Type's outputs depend upon the passage of time and the Type must therefore
(default) be called at least once every time step even if the values of inputs do not change
3 The Type should be called after all other components have converged and before
the integrators and printers. User-written statistic subroutines that send their output
to integrators is a situation where this may be appropriate.
4 Standard integrators
5 Standard printers
2 The Type should be called after all other components have converged and after the
integrators and printers. User-written output subroutines and non-iterative
controllers are situations for which this would be appropriate.
Note that the order in which components are called does not match the logical progression in
INFO(9) values for backwards compatibility reasons. The calling sequence is as follows:
Iterations during a time step: Units with INFO(9) = 1 (and Units with INFO(9) = 0 if their inputs have
changed) are called iteratively.
Convergence has been reached. All INFO(9) = 1 and 0 are called again with INFO(13) = 1 so they
can perform post-convergence manipulations (e.g. store values)
INFO(9) = 3 components (user-written routines to be called after convergence but before integrators)
are called once
INFO(9) = 4 components (standard integrators) are called once
INFO(9) = 5 components (standard printers) are called once
INFO(9) = 2 components (user-written components to be called after integrators and printers) are
called once
This calling sequence only applies to normal time steps. All components are called once, in an order
according to their Unit numbers, during the following calls:
Version signing call (INFO(7) = -2)
Initialization call (INFO(7) = -1)
Initial time step (INFO(7) = 0, TIME = Start time). No iterations are performed, Types should just
output initial conditions. and the very
Very last call (INFO(8) = -1)
7–78
TRNSYS 18 – Programmer's Guide
[Link]. INFO(10)
INFO(10) was used for storage management in TRNSYS 15. It was used to send the number of required
storage spots to TYPECK and then receive the index of the first reserved spot in the global storage array.
That way of handling storage is obsolete in TRNSYS 16 and should not be used anymore. It is still
present to allow TRNSYS 15 Types to run in legacy mode. Please note that the storage array accessed
by those Types is single-precision, unlike the storage array manipulated through the new access
functions (SetStorageSize, SetStorageVars, GetStorageVars). The standard way of handling variable
storage in TRNSYS 16 is described in section [Link].
[Link]. INFO(11)
INFO(11) sets the number of discrete control variables in the Type. It should only be set to a non-zero
value if Solver 1 must be used with the Type. It is very important to make sure that the Solver used in a
simulation is handled properly by all Types. For more details about Solver 1, please refer to the Solver
Statement description in Volume 06, TRNEdit manual.
[Link]. INFO(12)
INFO(12) indicates the TRNSYS version for which the Type was written (15 or 16). It must be set at the
very first call during the simulation (INFO(7) = -2).
[Link]. INFO(13)
INFO(13) is a flag that indicates that all the Units have converged during the current time step. It is 0
during iterative calls and 1 during the post-convergence call. Special units for which the Type has set
INFO(9) to any value greater than or equal to 2 will only be called once per time step, with INFO(13) = 1.
7–79
TRNSYS 18 – Programmer's Guide
6 7 8 9 10 11 12 13
Version signing call Start 0 -2 1 1 -10 0 0 0
Initialization call Start 0 -1 2 1 -10 0 16 0
Start (initial conditions) Start nO 0 3 S 0 0 16 0
1st step, 1st call Start+Step nO 0 4 S 0 0 16 0
1st step, 2nd call (1st iter.) Start+Step nO 1 5 S 0 0 16 0
1st step, 3rd call (2nd iter.) Start+Step nO 2 6 S 0 0 16 0
1st step, post-convergence Start+Step nO 3 7 S 0 0 16 1
2nd step, 1st call Start+2*Step nO 0 8 S 0 0 16 0
2nd step, 2nd call (1st iter.) Start+2*Step nO 1 9 S 0 0 16 0
2nd step, 3rd call (2nd iter.) Start+2*Step nO 2 10 S 0 0 16 0
2nd step, post-convergence Start+2*Step nO 3 11 S 0 0 16 1
etc. … … … … S 0 0 16 …
Last step, 1st call Stop nO 0 nCalls-3 S 0 0 16 0
Last step, 2nd call (1st iter.) Stop nO 1 nCalls-2 S 0 0 16 0
Last step, 3rd call (2nd iter.) Stop nO 2 nCalls-1 S 0 0 16 0
Last step, post-converg. Stop nO 3 nCalls S 0 0 16 1
Very last call (after "OK") Stop nO 0 -1 S 0 0 16 1
7–80
TRNSYS 18 – Programmer's Guide
GENERAL DESCRIPTION
In order to allow calls to external programs, a utility subroutine named “CallProgram” was been added to
TRNSYS with the release of version 15. CallProgram uses several Win32 Application Programming
Interface (API) commands to start the external program. API commands directly control the Windows
operating system. Depending on the mode specified in the call statement, CallProgram will either wait for
the second program to finish its task before proceeding or will merely start the second program and then
proceed with other TRNSYS calculations. The call statement for CallProgram is:
...
Call CallProgram(CMDLINE,bwait,prochand,thrdhand)
...
Where:
CMDLINE is the command line text string containing the path and name for the
executable program
BWAIT is a logical variable that determines whether TRNSYS will wait for the
second program to finish running or not.
-If BWAIT = .TRUE., then TRNSYS does not proceed until the second
program is finished and closed.
-If BWAIT = .FALSE., then TRNSYS proceeds once the second program
is done initializing but still running.
PROCHAND is the Windows process handle for the new program. This is a value
returned by the CALLPROGRAM routine.
THRDHAND is the Windows thread handle for the new program. This is a value
returned by the CALLPROGRAM routine.
When CallProgram is used to start another program and leave it running (BWAIT = .FALSE.), then the
program needs to be terminated at the end of the simulation before leaving TRNSYS. This can be done
by using the following commands:
...
res = TerminateProcess(PROCHAND,1)
If (res == 0) THEN
Write(CHCKWHY,*) GETLASTERROR()
EndIf
...
See the source code of Type 66 (CALL EES MODELS) for an example of the use of CallProgram.
7–81
TRNSYS 18 – Programmer's Guide
[Link]. CoolProp_Fluid_Properties( )
The double precision routine called CoolProp_Fluid_Properties returns the thermodynamic properties of
various refrigerants using the CoolProp program ([Link]).
Call CoolProp_Fluid_Properties(prop,nref,itype,iflagr)
Where
prop double precision array holding the two known thermodynamic properties of the
refrigerant in question upon entry and the complete state of the refrigerant upon
return from the routine. This array must be dimensioned to 9 in the routine that calls
the routine. Each location in this array is described below:
nref an integer variable denoting the refrigerant to be analyzed (table of possible nref
values is below)
itype integer variable denoting which two properties are supplied as known properties. The
possible combinations:
7–82
TRNSYS 18 – Programmer's Guide
iflagr an integer variable returning the error messages from the routine (0 – no error found,
1 – error found)
Table: nref numbers and refrigerant names included in the CoolProp program
nref name nref name nref name nref name
913 Diethyl Ether 936 Methyl Stearate 142 R142B 957 n-Decane
7–83
TRNSYS 18 – Programmer's Guide
918 Ethylene Oxide 941 Ortho Hydrogen 227 R227EA 290 n-Propane
920 Heavy Water 943 Para Hydrogen 949 R236FA 965 p-Xylene
An example illustrating the use of the CoolProp_Fluid_Properties routine is shown below. In the example,
two inputs (temperature and quality) are read and are placed in the PROP() array. The
CoolProp_Fluid_Properties routine is called. When CoolProp_Fluid_Properties returns, the example
checks to make sure that no errors were reported by CoolProp_Fluid_Properties by calling an Access
Function called ErrorFound( ) (refer to section [Link] for more information). If errors were detected,
execution of the Type that called CoolProp_Fluid_Properties stops immediately by returning control to the
calling program. If errors were not found then the PROP() array has been filled. The second and third
array spots are set to local variables and Type execution continues normally.
Use TrnsysFunctions
...
Double Precision prop(9),temp, quality, pressure, enthalpy
Integer nRef, iFlag
...
nRef = 12 !Refrigerant R12
...
temp = getInputValue(1)
quality = getInputValue(2)
...
prop(1) = temp
prop(5) = quality
Call CoolProp_Fluid_Properties(prop,nRef,15,iFlag)
If (ErrorFound()) Return
...
pressure = prop(2)
enthalpy = prop(3)
MATHEMATICAL DESCRIPTION
For details on the CoolProp routines and algorithm sources please see the webpage [Link].
7–84
TRNSYS 18 – Programmer's Guide
It is possible to use the CooProp routines directly rather than using the CoolProp_Fluid_Properties
routine. The CPINTERFACE must be used inside code that calls the CoolProp routines and the
CoolProp DLL must be found. The CoolProp website has instructions for calling the CoolProp routines.
GENERAL DESCRIPTION
The utility routine Enclosure_17 calculates view factors between all surfaces of a rectangular
parallelpiped. Up to 9 windows or doors may be located on any of the 6 wall surfaces. Enclosure_17 is a
double precision routine, meaning that its arguments must be declared in the calling Type as double
precision variables (as opposed to REAL variables). The values returned by Enclosure_17 are also
double precision. In TRNSYS versions 15.x and below, Enclosure_17 was known simply as “ENCL,”
which was a single precision routine. In TRNSYS version 16.x, a double precision version called
“ENCLOSURE” was written. ENCLOSURE and ENCL were retained for backwards compatibility and
every effort should be made to use the double precision Enclosure_17 routine.
This routine is used by the TYPE 19 zone model. A call to Enclosure is of the form
Double Precision :: SPAR(10),WPAR(10),FV
Integer :: currentUnit, currentType
...
Call Enclosure_17(SPAR,WPAR,FV,currentUnit,currentType)
where
MATHEMATICAL DESCRIPTION
Subroutine Enclosure_17 utilizes function subroutine View_Factors to obtain view factors between
continuous rectangular surfaces. Reciprocity is also used to reduce the number of computations. In
order to determine view factors between surfaces that contain windows or doors, it is necessary to
perform some view factor algebra.
7–85
TRNSYS 18 – Programmer's Guide
Consider the general case of m windows located on a surface i and n windows on a surface j as shown in
Figure [Link]-1.
j
Wj1 Wj2 Wj3
W i3
W i2
W i1 W jn
W im
Figure [Link]-1
Fi j Fi j W ji ... W jn Fi (W jk )
n
Eq. 7.4.4-1
k 1
where
Fi j W j1 ... W jn
A j
AW j1 ... AW jn F( j W j1 ... W jn ) i
Eq. 7.4.4-2
Ai
m
F( j W j1 ... W jn ) i F( j W j1 ... W jn ) (i Wi1 ... Wim ) F( j W j1 ... W jn ) Wik Eq. 7.4.4-3
k 1
AW jk FW jk i
Fi W jk Eq. 7.4.4-4
Ai
m
FW jk i FW jk (i Wi1 ... Wim ) FW jk Wil Eq. 7.4.4-5
l 1
The variables W i1 through W im are the surface numbers associated with windows on wall i. Likewise, W j1
through W in refer to windows on wall j. Thus, (i+W i1+...W in) and (j+W j1+... W jm), each denote surfaces
that are collections of individual surfaces. The variable A refers to the area of a surface whose number is
used as a subscript.
7–86
TRNSYS 18 – Programmer's Guide
7–87
TRNSYS 18 – Programmer's Guide
AMMONIA (717)
ITYPE integer variable denoting which two properties are supplied as known
properties. ITYPE = 10* PROP indicator 1 + PROP indicator 2 (12 to
98)
IFLAGR an integer variable returning the error messages from the
Fluid_Properties call:
0 - no error found, calculations completed
1 - error found, calculations could not be completed
The subroutines FLUID_PROPS and FLUIDS also required the following:
*N the corresponding line number to jump to if the subprogram is present.
An example illustrating the use of the Fluid_Properties routine is shown below. In the example, two inputs
(temperature and quality) are read and are placed in the PROP() array. The Fluid_Properties routine is
called. When Fluid_Properties returns, the example checks to make sure that no errors were reported by
Fluid_Properties by calling an Access Function called ErrorFound( ) (refer to section Error! Reference
source not found. for more information). If errors were detected, execution of the Type that called
Fluid_Properties stops immediately by returning control to the calling program. If errors were not found
then the PROP() array has been filled. The second and third array spots are set to local variables and
Type execution continues normally.
Use TrnsysFunctions
...
Character (len=2) :: units
Double Precision :: prop(9),temp,quality,pressure,enthalpy
Integer :: nRef,iFlag
...
units = ‘SI’ !SI units are desired.
nRef = 12 !Refrigerant R12
...
temp = getInputValue(1)
quality = getInputValue(2)
...
prop(1) = temp
prop (5) = quality
Call Fluid_Properties(units,prop,nRef,15,iFlag)
If (ErrorFound()) Return
...
pressure = prop(2)
enthalpy = prop (3)
MATHEMATICAL DESCRIPTION
The correlations required to solve for the refrigerant properties are from the Engineering Equation Solver
program (F-chart software, 1994), a numerical solver employing thermodynamic correlations from many
different sources. Interested users should contact the reference for more details on the correlations.
Enthalpies for ammonia and R134a are based on the reference state: enthalpy equal to zero at -40C.
Enthalpies for all other refrigerants are based on the reference state: enthalpy equal to zero at 0C
This subroutine checks for many improper inputs, such as qualities less than 0. or greater than 1., and the
input of two properties that cannot be correct for one state. For these and other improper inputs, the
subroutine prints a warning, corrects one of the inputs, and continues; or prints an error and halts the
simulation.
7–88
TRNSYS 18 – Programmer's Guide
Subcooled properties are not available for refrigerants. If a subcooled state is specified, the saturated
liquid results will instead be provided.
7–89
TRNSYS 18 – Programmer's Guide
7–90
TRNSYS 18 – Programmer's Guide
elevation (double precision) the elevation of the location for which the solar
radiation calculations are being performed. [m]
shift (double precision) the shift between local and solar time. The shift is
calculated by the equation shift = Lst - Lloc where Lst is the standard
meridian for the local time zone, and Lloc is the longitude of the location in
question. Longitude angles are positive towards West, negative towards
East. [deg]
iSolarTime (integer) flag indicating whether the input data being passed is in solar
time or local time. (-1: data is in solar time, 1: data is in local time) [-1/1]
solConst (double precision) the solar constant [kJ/h.m 2]
td1 (double precision) the time of the last solar radiation data point [hr]
td2 (double precision) the time of the next solar radiation data point [hr]
solar (double precision array) contains the sixteen values that are returned by
getIncidentRadiation.
solar(1) extraterrestrial solar [kJ/h.m 2]
solar(2) solar zenith angle [deg]
solar(3) solar azimuth angle [deg]
solar(4) slope of the tilted surface [deg]
solar(5) azimuth of the tilted surface [deg]
solar(6) incidence angle of beam radiation on the tilted surface [deg]
solar(7) total solar radiation on the horizontal [kJ/h.m 2]
solar(8) beam solar radiation on the horizontal [kJ/h.m 2]
solar(9) diffuse solar radiation on the horizontal [kJ/h.m 2]
solar(10) total solar radiation on the tilted surface [kJ/h.m 2]
solar(11) beam solar radiation on the tilted surface [kJ/h.m 2]
solar(12) diffuse solar radiation on the tilted surface [kJ/h.m 2]
solar(13) ground reflected solar radiation on the tilted surface [kJ/h.m 2]
solar(14) isotropic sky diffuse radiation on the tilted surface (part of solar(12) sky
diffuse) [kJ/h.m2]
solar(15) circumsolar diffuse radiation on the tilted surface (part of solar(12) sky
diffuse) [kJ/h.m2]
solar(16) horizon brightening diffuse radiation on the tilted surface (part of
solar(12) sky diffuse) [kJ/h.m 2]
iErrRad (integer) error condition returned by getHorizontalRadiation (1: illegal
tracking mode specified, 2: sunup/sundown time issue, 3: horizontal
beam calculation greater than extraterrestrial radiation on the horizontal
surface, 4: time step/data time step inconsistency, 5: horizontal diffuse
calculation greater than extraterrestrial radiation on the horizontal
surface, 6: total horizontal calculation greater than extraterrestrial
radiation on the horizontal surface, 7: total horizontal calculation greater
than extraterrestrial radiation on the horizontal surface due to sum of
beam and diffuse, ratios used to set beam and diffuse, 8: direct normal
radiation greater than solar constant (hdn=SC), 9: calculated value of
beam radiation on the horizontal is greater than provided total horizontal
7–91
TRNSYS 18 – Programmer's Guide
7–92
TRNSYS 18 – Programmer's Guide
GENERAL DESCRIPTION
Solar insolation data is generally recorded at one hour intervals and on a horizontal surface. In some
TRNSYS simulations, estimates of radiation at time intervals other than one hour are required. This
routine interpolates solar radiation data, calculates several quantities related to the position of the sun,
and estimates insolation on a surface of either fixed or variable orientation.
There are several possible methods of interpolating radiation data. One fairly simple method is to linearly
interpolate hourly data to obtain estimates of radiation over shorter time intervals. This approach, which
was used in TRNSYS prior to Version 10.1, has several drawbacks. The most readily apparent problem is
that positive radiation values are produced before sunrise and after sunset. If sunrise is at 6:30 a.m., then
an hourly radiation data file may have a value of zero at 6:00 and 40 watts/m 2 at 7:00. Linear interpolation
will give 10 watts/m2 at 6:15, fifteen minutes before sunrise. This problem is compounded by the fact that
the ratio of beam radiation on a tilted surface to that on a horizontal, R b, may become very large near
sunrise and sunset. If the estimate of radiation on the horizontal is too large near sunrise, the calculated
radiation on a tilted surface will be immense. Another method uses the curve for extraterrestrial radiation
to interpolate radiation data. While this seems to relieve the problems encountered with linear
interpolation, it does introduce a characteristic saw-tooth pattern in the radiation. With TRNSYS 18 a new
method that uses future values of radiation to produce a smoother curve to the sub-data intervals while
still preserving the values from the data file was introduced in Type15 and a new mode was added to
GetHorizontalRadiation where no interpolation of the horizontal data will be performed.
Total radiation on a tilted surface is usually required for solar energy system simulations. The models
used in this subroutine to estimate the total tilted surface radiation require knowing the division of total
horizontal radiation into its beam and diffuse components. If only total horizontal radiation is measured,
correlations are provided to estimate the beam or diffuse radiation on a horizontal surface. The horizontal
components are then projected onto the tilted surface. The getHorizontalRadiation routine has several
options for calculating the horizontal radiation components as does the getTiltedRadiation routine for
estimating the radiation on a tilted surface.
7–93
TRNSYS 18 – Programmer's Guide
NOMENCLATURE
AI - Anisotropy index
a/c weighted circumsolar solid angle
E Factor accounting for the eccentricity of the earth's orbit
f Modulating factor for Reindl titlted surface model
F1' Reduced brightness coefficient (circumsolar)
F2' Reduced brightness coefficient (horizon brightening)
Io Extraterrestrial radiation
Ion Extraterrestrial radiation at normal incidence
Ib Beam radiation on horizontal surface
Ibn Beam radiation at normal incidence
IbT Beam radiation on tilted surface
Id Diffuse radiation on horizontal surface
Idn Direct normal beam radiation
IdT Diffuse radiation on tilted surface
I Total radiation on a horizontal surface
IT Total radiation on a tilted surface
IgT Ground reflected radiation on a tilted surface
kT Ratio of total radiation on a horizontal surface to extraterrestrial radiation
Lloc Longitude of a given location
Lst Standard meridian for time zone
n Day of year of the start of the simulation
Rb Ratio of beam radiation on tilted surface to beam on horizontal
Rd Ratio of diffuse radiation on tilted surface to diffuse on horizontal
Rr Ratio of reflected radiation on tilted surface to total radiation on horizontal
rh relative humidity [%]
Sc Solar constant
SHFT Shift in solar time relative to the nominal time of data reading
Ta Ambient temperature
t1 Time of start of time step
t2 Time of end of time step
td1 Time of last data reading
td2 Time of next data reading
Solar altitude angle (90 - qz)
Slope of surface, positive when tilted in the direction of the azimuth specification
Slope of tracking axis
Solar declination angle
Sky brightness parameter
Sky clearness parameter
Azimuth angle of surface; angle between the projection of the normal to the surface
into the horizontal plane and the local meridian. (facing equator = 0, west positive,
east negative)
' Azimuth angle of axis; angle between the projection of the axis line onto the
horizontal plane and local meridian. (Same sign convention as for )
s Solar azimuth angle
Angle of incidence of beam radiation on surface
Z Solar zenith angle
g Ground reflectance
Latitude
Mean hour angle of time step (0 at noon, mornings negative)
1 Hour angle at start of time step, or sunrise hour angle if sunrise occurs during time
step
7–94
TRNSYS 18 – Programmer's Guide
2 Hour angle at end of time step, or sunset hour angle if sunset occurs during time step.
MATHEMATICAL DESCRIPTION
In practice, most solar radiation data are actually integrated totals of instantaneous measurements.
GetHorizontalRadiation has two methods for determining the sub-timestep values. The first simplay
assumes that the determination of the sub-timestep values has been performed by the calling routine
(such as Type15) and that the inputs should be used as is. The other method uses the total radiation
between times td1 and td2 that is passed to it. Then, by summing integrals if necessary, the total radiation
between hour anglesd1 and d2 is found. The hour angles d1and d2are chosen so that d1 ≤ 1 and
d2 ≥ . Here is the angle of the start of the time step and 2 is the angle of the end of the time step. If
sunrise or sunset occurs during the time step, then the portion of the time step when the sun is below the
horizon is ignored.
The total extraterrestrial radiation between hour angles ’ and ’’ is found from:
Io | = Sc E (cos cos cos + sin sin) d Eq. 7.4-6
I|
d2
Given d1, a reasonable estimate of the actual insolation over the time step is
Io |
2
I|2 d2
1 = I|d1 *
1
Eq. 7.4-7
Io |
d2
d1
This calculation scales integrated radiation data using the ratio of extraterrestrial radiation over the time
step to extraterrestrial radiation over the period which corresponds to the data. Since other TRNSYS
routines require the rate of solar radiation, the integrated radiation is converted to the average rate over
the time step.
The getHorizontalRadiation routine has five methods for obtaining beam and diffuse radiation on a
horizontal surface from total radiation on a horizontal surface data. Horizontal Radiation Modes 1 and 2
are based on the relationships developed by Reindl (9a). Both modes provide estimates of the diffuse
fraction of the total horizontal radiation (Id/I). Mode 1 is a reduced form of the full correlation given in Mode
2. Mode 1 uses the clearness index and the solar altitude angle to estimate the diffuse fraction. The
correlation is given by the following equations:
7–95
TRNSYS 18 – Programmer's Guide
Horizontal Radiation Mode 2 estimates the diffuse fraction as a function of the clearness index, solar
altitude angle, ambient temperature, and relative humidity. The correlation is given by the following
equations:
Id/I = 1.000 - 0.232 kT + 0.0239 sin ( ) - 0.000682 Ta + 0.0195 (rh/100) Eq. 7.4-11
Rather than constrain each variable in the above correlations, a subsequent constraint is placed on the
overall estimate of the diffuse fraction. The constraints limit the diffuse fraction estimates to values that
are physically possible.
For the above Horizontal Radiation Modes, beam radiation on a horizontal surface is calculated by the
difference between the total radiation and the diffuse component,
Ib = I - Id Eq. 7.4-14
In Horizontal Radiation Mode (hMode) 3, beam and diffuse radiation on a horizontal surface are Input
directly. For Horizontal Radiation Mode (hMode) 4, total horizontal and direct normal radiation are Inputs
and Horizontal Radiation Mode (hMode) 5 has Inputs of total and diffuse radiation on a horizontal surface.
If measurements of global horizontal and beam or diffuse radiation are available, then Horizontal
Radiation Mode (hMode) 3, 4 or 5 should be used. Horizontal Radiation Mode 4 can be used with
SOLMET (4) data, since direct normal radiation values have been estimated for this data using the
algorithm developed by Randall and Whitson (5). When beam and diffuse radiation measurements are
not available, Horizontal Radiation Modes 1 or 2 must be used. If total radiation on a horizontal surface,
ambient temperature and relative humidity data are available, Horizontal Radiation Mode 2 is
recommended. (Note that the temperature and relative humidity data sent to the getHorizontalRadiation
routine may be interpolated values. They will not be interpolated by getHorizontalRadiation.) If only total
radiation is available, then it is recommended that Horizontal Radiation Mode 1 be used.
The above recommendations are based on evaluation of the existing correlations with several sets of
measurements (9a).
The position of the sun in the sky can be specified by giving the solar zenith and solar azimuth angles.
The zenith angle is the angle between the vertical and the line of sight of the sun. This is 90 minus the
angle between the sun and the horizontal (solar altitude angle). The solar azimuth angle is the angle
7–96
TRNSYS 18 – Programmer's Guide
between the local meridian and the projection of the line of sight of the sun onto the horizontal plane. A
solar azimuth value of zero is facing the equator, west is positive, while east is negative. Facing away
from the equator is ±180. Both zenith and solar angles can be determined from trigonometric relationship
given in Chapter 2 of Duffie and Beckman (6) or ASHRAE (7), or by Braun and Mitchell (8).
Four Surface Tracking Modes (trackMode) are incorporated into TRNSYS for handling various surfaces
for which determination of incident radiation is often needed. Tracking Mode 1 is for surfaces that do not
track to maximize incoming radiation. The slope and azimuth Inputs denote the position of the surface.
These may vary with time as with any TRNSYS Inputs or may be constant. Tracking Modes 2-4 handle
various kinds of optimally tracked surfaces. An optimally tracked collector will be maneuvered to
maximize radiation at all times. In general, this amounts to maximizing beam radiation, or cos .
Tracking Mode 2 handles a tracking surface with a fixed surface slope and variable surface azimuth
rotating about a vertical axis as denoted in Figure 7.4.4–2. For this case, beam radiation is maximized
when = s. The azimuth Input in this situation is ignored.
Ve rtical
East
S outh
Tracking Mode 3 handles the general case of a surface rotating about a single axis that is always parallel
to the surface. An illustration of this scheme is presented in Figure 7.4.4–3. For a horizontal axis, the
surface slope at any instant is given by
7–97
TRNSYS 18 – Programmer's Guide
If a surface tracks about a single axis that is always parallel to the surface, but is not vertical or horizontal,
both azimuth and slope of the surface vary with time. In this case,
tan
= tan-1 Eq. 7.4-21
cos(-)
where ' is the incidence angle for a surface with slope and azimuth equal to those of the axis.
The slope and azimuth Inputs for Mode 3 refer to the position of the axis.
Ve rtical
East
'
S urface Normal
'
'
S outh
In Tracking Mode 4, two-axis tracking surfaces are considered. Beam radiation is maximized for a surface
adjusted such that the sun's rays are always at normal incidence (i.e. cos = 1). This is accomplished
when = s and = z. Both slope and azimuth Inputs are ignored. The derivations of the trigonometric
relationships for the class of tracking collectors presented here are given in Reference 8.
For most surfaces, an estimate of the total radiation incident on the surface is of interest. The
getTiltedRadiation routine provides five models for estimating the total radiation on a tilted surface. Each
model requires knowledge of total and diffuse (or beam) radiation on a horizontal surface as well as the
sun's position. In general the total tilted surface radiation is calculated by estimating and adding beam,
diffuse and reflected radiation components on the tilted surface.
7–98
TRNSYS 18 – Programmer's Guide
All tilted surface radiation models use the same techniques for projecting the beam and ground reflected
radiation onto a tilted surface; they differ only in the estimate of diffuse radiation on a tilted surface. The
contribution of beam radiation on a tilted surface (in short time intervals) can be calculated by using the
geometric factor Rb (6):
In the above equation, is the slope of the surface defined as the angle between the surface and the
horizontal, while is the surface azimuth or the angle between the projection of the normal to the surface
into the horizontal plane and the local meridian. The sign convention for surface azimuth is identical to
that for solar azimuth (zero if facing the equator, positive if west, negative if east). Slope is measured as a
positive value when tilted in the direction of the azimuth specification.
Once Rb is found,
The contribution of reflected radiation on a titled surface is calculated by assuming the ground acts as an
isotropic reflector and defining Rr as the ratio of reflected radiation on a tilted surface to the total radiation
on a horizontal surface is:
The contribution of diffuse radiation on a tilted surface is determined by using one of the five models
provided in the getTiltedRadiation routine’s Tilted Surface Radiation Mode. Tilted Surface Radiation Mode
1 uses the isotropic sky model. This is the model that has been used by default in previous versions of
TRNSYS. The isotropic sky model assumes that the diffuse radiation is uniformly distributed over the
complete sky dome. A factor Rd, the ratio of diffuse radiation on a tilted surface to that on a horizontal, is
given by:
Thus the diffuse radiation on a tilted surface assuming isotropic sky is:
Tilted Surface Radiation Mode 2 uses a model developed by Hay and Davies (10). The Hay and Davies
model accounts for both circumsolar and isotropic diffuse radiation. Under clear sky conditions, there is
an increased intensity of diffuse radiation in the area around the sun (circumsolar diffuse). Hay and
Davies weight the amount of circumsolar diffuse by using an anisotropy index; AI The anisotropy index
defines a portion of the diffuse radiation to be treated as circumsolar with the remaining portion of diffuse
radiation considered isotropic. The Hay and Davies tilted surface diffuse radiation model is given by:
7–99
TRNSYS 18 – Programmer's Guide
The first term in bracket represents the contribution of isotropic diffuse radiation while the second term
represents the contribution of circumsolar diffuse radiation.
Tilted Surface Radiation Mode 3 uses a model developed by Reindl (9b) based on the work of several
previous authors. This model adds a horizon brightening diffuse term to the Hay and Davies model. The
horizon brightening is lumped with the isotropic diffuse term and its magnitude is controlled by a
modulating factor, f.
Ib
f= Eq. 7.4-31
I
The first term in brackets represents the contribution of isotropic and horizon diffuse and the second term
represents the contribution of circumsolar diffuse.
Tilted Surface Radiation Mode 4 uses a version of the tilted surface model developed Perez, et al in 1988
(11). This model accounts for circumsolar, horizon brightening, and isotropic diffuse radiation by
empirically derived "reduced brightness coefficients". The reduced brightness coefficients, F’ 1, F’2, are
functions of sky clearness, e, and sky brightness, , parameters.
Id + Idn 3
+ 1.041 Z
Id Eq. 7.4-33
3
1 + 1.041 Z
Where z is in radians:
Id m = Id Eq. 7.4-34
Ion Io
The sky clearness and sky brightness parameters are used to calculate the reduced brightness
coefficients from the relationships and table given below.
The Perez coefficients (F11, etc.) are given in the following table (11):
Bin Upper Cases F11 F12 F13 F21 F22 F21
Limit for (%)
1 1.065 13.60 -0.196 1.084 -0.006 -0.114 0.180 -0.019
2 1.230 5.60 0.236 0.519 -0.180 -0.011 0.020 -0.038
3 1.500 7.52 0.454 0.321 -0.255 0.072 -0.098 -0.046
7–100
TRNSYS 18 – Programmer's Guide
max 0, cos
a/c = Eq. 7.4-37
max cos 85, cos Z
The tilted surface diffuse radiation can be estimated by the following
With the release of TRNSYS v17 Tilted Radiation Mode 5 was added. This model was developed by
Perez, et al in 1999 (12). The Perez 1999 model is identical in formulation to the Perez 1988 model. It
differs only in the curve fit coefficients. The coefficients for the Perez 1999 model are:
Bin F11 F12 F13 F21 F22 F21
1 -0.0083117 0.5877285 -0.0620636 -0.0596012 0.0721249 -0.0220216
2 0.1299457 0.6825954 -0.1513752 -0.0189325 0.0659650 -0.0288748
3 0.3296958 0.4868735 -0.2210958 0.0554140 -0.0639588 -0.0260542
4 0.5682053 0.1874525 -0.2951290 0.1088631 -0.1519229 -0.0139754
5 0.8730280 -0.3920403 -0.3616149 0.2255647 -0.4620442 -0.0012448
6 1.1326077 -1.2367284 -0.4118494 0.2877813 -0.8230357 0.0558651
7 1.0601591 -1.5999137 -0.3589221 0.2642124 -1.1272340 0.1310694
8 0.6777470 -0.3272588 -0.2504286 0.2642124 -1.3765031 0.2506212
In general, the anisotropic sky models (Hay and Davies, Reindl, and Perez, et al) provide comparable
estimates of the total radiation on a tilted surface and are recommended for general use. The Hay and
Davies and the Reindl models are computationally simple when compared to the Perez model. The
isotropic sky model (mode 1) under predicts the total radiation on a tilted surface and is not
recommended for general use; it is included to permit consistency with simulations performed with earlier
versions of TRNSYS.
Since many of the calculations made in transforming insolation on a horizontal surface depend on the
time of day, it is important that the correct solar time be used. Several correction factors are used in
computing solar time. Following the development in Chapter 2 of Duffie and Beckman,
Here E accounts for the eccentricity of the earth's orbit and varies between about -.24 hours and +.26
hours each year. Lst is the standard meridian for the local time zone and Lloc is the longitude of the
location in question. Both standard and local meridians are measured in degrees 0 to 180. West of
longitude 0 (Greenwich, England) is positive, east is negative. Standard meridians for continental U.S.
7–101
TRNSYS 18 – Programmer's Guide
time zones are Eastern 75° W, Central 90° W, Mountain l05° W, and Pacific l20°. Standard meridians
for Europe are Western (Greenwich time) 0° and Central (MEZ time) -15°.
For processing the total radiation over a time step, the mean hour angle
is used. This is to ensure that the calculated position of the sun will be the average position for the time
step.
where t is the time in hours corresponding to . Comparing the two equations for solar time, one can see
that SHFT should be set to Lst - Lloc. Also, simulation time should be set so that the first data line read in
corresponds to the period (typically hour) ending at the simulation starting time. If data is supplied at
even solar time intervals, then the factors E and SHFT should be omitted. This is accomplished by
including a negative last parameter.
References
1. Liu, B. Y. H. and Jordan, R. C. “The Interrelationships and Characteristic Distribution of Direct,
Diffuse and Total Solar Radiation,” Solar Energy, Vol. IV, July, (1960), pp. 1-19.
2. Boes, E. C. et al., “Distribution of Direct and Total Solar Radiation Availabilities for the U.S.A.,”
Sandia Report SAND76-0411, August, (1976).
3. Erbs, D. G., “Methods for Estimating the Diffuse Fraction of Hourly, Daily and Monthly Average
Global Solar Radiation,” Masters Thesis in Mechanical Engineering, University of Wisconsin-
Madison, (1980).
4. SOLMET, Volume 2 – Final Report, “Hourly Solar Radiation Surface Metereological
Observations,” TD-9724, (1979).
5. Randall, C.M. and Whitson, M. E., Final Report, “Hourly Insolation and Metereological Data
Bases Including Improved Direct Insolation Estimates,” Aerospace Report No. ATR-78(7592)-1,
(1977).
6. Duffie, J. A. and Beckman, W. A., Solar Energy Thermal Processes, Wiley, New York, (1974).
7. ASHRAE Handbook of Fundamentals, American Society of Heating, Refrigeration and Air-
Conditioning Engineers, (1972).
8. Braun, J. E. and Mitchell, J.C., “Solar Geometry for Fixed and Tracking Surfaces,” Solar Energy,
Vol. 31, No. 5, October, (1983).
9. (a) Reindl, D.T., Beckman, W.A. and Duffie, J.A., “Diffuse Fraction Correlations”, Solar Energy,
Vol. 45, No. 1, (1990), pp.1-7.
(b) Reindl, D.T., Beckman, W.A. and Duffie, J.A., “Evaluation of Hourly Tilted Surface Radiation
Models”, Solar Energy, Vol. 45, No. 1, (1990), pp. 9-17.
10. Hay, J.E., Davies, J.A., “Calculation of the Solar Radiation Incident on an Inclined Surface”,
Proceedings First Canadian Solar Radiation Workshop, (1980), pp. 59-72.
11. Perez, R., Stewart, R., Seals, R., and Guertin, T., “The Development and Verification of the Perez
Diffuse Radiation Model”, Sandia Report SAND88-7030, (1988).
7–102
TRNSYS 18 – Programmer's Guide
12. Perez, R, et al. “Modeling Daylight Availability and Irradiance Components from Direct and Global
Irradiance.” Solar Energy, 1990, vol. 44, no. 5, p. 271-289
13. Perez, R. private communication, 5/21/99. Perez coefficients (Fij values) have higher precision
than those listed in Table # 6 of Perez et al., 1990.
7–103
TRNSYS 18 – Programmer's Guide
GENERAL DESCRIPTION
The InterpolateData utility routine is available to read user supplied data from external text based files
that have been assigned a FORTRAN logical unit number in the TRNSYS input file. The InterpolateData
routine is able to interpolate the data found in the file in up to six dimensions during the course of the
simulation. For each data set, up to ten dependent (Y) functions may be specified in terms of up to six
independent (X) variables. At each call to the InterpolateData routine, the calling Type sends the values
of each independent variable. InterpolateData performs the multi-dimensional interpolation and returns
the interpolated values of as many dependent variables as have been provided in the data file and
requested by the calling Type. InterpolateData is NOT able to extrapolate beyond the range of data given
in the external file. If the calling Type sends a value of an independent variable that falls above or below
the range given in the data file, InterpolateData will return the values of the dependent variables that
correspond to the maximum or minimum of the range. With the release of TRNSYS 17, InterpolateData
keeps track of what percentage of the simulation time a given data file and a given independent variable
were called with values above or below the range given in the data file. A notice is printed to the *.lst and
*.log files at the end of the simulation.
InterpolateData is a double precision routine, meaning that the independent and dependent variables
found in the external file will be treated as FORTRAN double precision variables. Similarly, the X and Y
arrays in the calling Type must be declared as double precision. In TRNSYS versions 15.x and below,
InterpolateData was known as either “DynamicData” (which was a double precision routine) or as “DATA”
or “DYNDATA,” both of which were single precision routines. DynamicData, DATA and DYNDATA were
retained for backwards compatibility but every effort should be made to use the double precision
InterpolateData routine.
Examples of standard components that use InterpolateData are the Type1 Solar Collector and the
Type44 Conditioning Equipment model. The form of a call to InterpolateData is:
Integer :: LU,nIND,nX(:),nY(:),INFO(15)
Double Precision :: X(:),Y(:)
...
Call InterpolateData (LU, nIND, nX, nY, X, Y)
where
7–104
TRNSYS 18 – Programmer's Guide
DynamicData, DYNDATA, and DATA all required two additional arguments as follows:
The data is read from logical unit LU at the start of the simulation. Thereafter, InterpolateData linearly
interpolates for Y values given X values. If InterpolateData is called with an X out of range of the supplied
data, then the closest specified value is used. InterpolateData does not extrapolate beyond the user
supplied data.
Data is supplied in an external text file that is read by the InterpolateData routine. The values of all the
independent variables are specified at the top of the file, followed by the values of the dependent
variables. The independent variables may be thought of as the inputs; the dependent variables are read
from the file and may be thought of as the outputs. There may be up to six independent variables. Each
independent variable’s value range is specified in a single row starting with the 6 th dimension and
proceeding to the 1st dimension. If the data being read and interpolated is influenced by less than 6
dimensions, the data file begins with the greatest dimension. Thus the row of independent variable values
corresponding to X1 is always adjacent to the section of the file containing the dependent values. An
exclamation point following the variable values indicates the beginning of a comment and can be used to
clarify the contents of each row in the file.
If NIND (the number of independent variables expected in the file) equals 6 then nX(6) values of the sixth
independent variable (X6) are expected to appear on the first line of the data file. In this case, the second
row of the data file would contain nX(5) values of the fifth independent variable (X 5), the third row of the
data file would contain nX(4) values of the fourth independent variable, the fourth row of the data file
would contain nX(3) values of the third independent variable, the fifth row would contain nX(2) values of
the second independent variable and the sixth row would contain nX(1) values of the first independent
variable.
If nIND is equal to 2, then nX(2) values of the second independent variable appear on the first row of the
file and nX(1) values of the first independent variable appear on the second row of the file. In each line,
the values of independent variables must be in ascending order but need not be at regular intervals.
The remainder of the data file contains rows of dependent variable values. Each row contains nY (the
number of dependent variable) values. And each row corresponds to a specific combination of
independent variable values. The total number of rows of dependent variable values will be equal to the
product of the number of values in each of the rows of independent variable values. For example, if the
file has two independent variables (nIND = 2) and there are 3 values of X 2 (on the first line) and 4 values
of X1 on the second line of the file then the file will contain 12 rows of dependent variable values.
The first set of dependent variable value rows correspond to the values of the X1 independent variable. In
the previous example, there were 4 values of X1; the first set of dependent variable values would be made
up of four rows corresponding to X 1(1), X1(2), X1(3), and X1(4). Each subsequent set of dependent
variable value rows correspond to the values of the next highest dimension of independent variable.
Again taking the example from above, the same first four rows would correspond to X 1(1), X1(2), X1(3),
and X1(4) for the first value of X2. A second set of four rows would follow corresponding to X 1(1), X1(2),
X1(3), and X1(4) for the second value of X2. A third set of four rows would correspond to X1(1), X1(2),
X1(3), and X1(4) for the third value of X2.
7–105
TRNSYS 18 – Programmer's Guide
Example: A user wishes to write a model for a water-to-water heat pump whose performance depends
upon the inlet flow stream temperatures to both the evaporator (T evap) and condenser (Tcond).
InterpolateData is to be used to evaluate both the capacity and COP. The experimental data is shown in
Table [Link]-1.
Table [Link]-1
Tevap [°C] Capacity [kJ/hr] COP Tevap [°C] Capacity [kJ/hr] COP
10 35000 2.47 10 21000 1.73
20 41000 2.80 20 25000 1.96
30 49500 2.99 30 29000 2.09
The data is to be read from logical unit 10. Three values of T evap and two values of Tcond will be supplied.
The call to InterpolateData within the calling Type routine might appear as
USE TrnsysFunctions
...
Integer :: nX(2)
Double Precision :: X(2),Y(2),CAP,COP,T_Evap,T_Cond
...
nX(1) = 3 !There are 3 values of the second variable in the file.
nX(2) = 2 !There are 2 values of the first variable in the file.
X(1) = T_Evap !sets x(1) to the local variable t_evap
X(2) = T_Cond !sets x(2) to the local variable t_cond
Call InterpolateData (10,2,nX,2,X,Y)
CAP = Y(1) !sets the call result y(1) to local variable CAP.
COP = Y(2) ! sets the call result y(1) to local variable COP.
...
The syntax of the data file accessed through logical unit 10 would be as follows:
20.0 50.0 !Tcond values
21000. 1.73 !Capacity and COP for Tcond =50°C, and Tevap=10°C
25000. 1.96 !Capacity and COP for Tcond =50°C, and Tevap=20°C
29000. 2.09 !Capacity and COP for Tcond =50°C, and Tevap=30°C
7–106
TRNSYS 18 – Programmer's Guide
General Description
MATHEMATICAL DESCRIPTION
Y Ymod el , j
N data
J j
Eq. 7.4.4-43
j 1
N coef
Ymod el , j X
i 1
i i, j
Eq. 7.4.4-44
where,
7–107
TRNSYS 18 – Programmer's Guide
Example Consider the equation used in the Type53 Chiller component. The dimensionless power
consumption is correlated with performance data using the following bi-quadratic equation:
X1,j = 1.0
X2,j = E
X3,j = E2
X4,j = F
X5,j = F2
X6,j = EF
E F G
3.0 0.2 10.0
5.0 0.4 12.5
7.0 0.6 13.1
7–108
TRNSYS 18 – Programmer's Guide
The LinearRegression subroutine would be called with the above input data and return values for PHI and
IFLAG. PHI would be a vector containing the values for a0-a5.
7–109
TRNSYS 18 – Programmer's Guide
[Link]. LINKCK
The LINKCK subroutine is a utility subroutine used for the detection and subsequent error message
printing of unlinked subroutines. With earlier version of TRNSYS (up to version 15.0) the LINKCK routine
was of vital importance because as a memory saving step TRNSYS was often compiled to include only
those kernel routines that were critical to a given simulation. With advances in computing power and
speed, this step became less and less important. In TRNSYS 16, LINKCK remained as a safeguard
against inadvertently unlinked routines but almost always, unlinked routines will be caught during the
compiling and linking processes. With the release of TRNSYS 17, many of the direct calls that a user-
written Type made to LINKCK were made obsolete by the introduction of access functions. Essentially the
call to LINKCK was handled by the access function and the user no longer had to worry about it. A call to
LINKCK is of the form:
Character (len=12) :: ENAME1,ENAME2
Integer :: ILINK,LNKTYP
...
Call LINKCK(ENAME1,ENAME2,ILINK,LNKTYP)
where
ENAME1 a 12-character variable identifying the subroutine from which the call
originated.
ENAME2 a 12-character variable identifying the subroutine that was called
ILINK an integer indicating the steps to be taken by the LINKCK program
=1 an unlinked subroutine has been found, generate an error
message and stop the program
=2 an unlinked subroutine has been found, generate a warning but
keep running
=3 an unlinked TYPE subroutine has been found, generate an error
message and stop the program
=4 warn the user that a subroutine requires use of an external
function which cannot be link checked
LNKTYP integer variable corresponding to the TYPE subroutine which was not
found in the TRNSYS executable
With TRNSYS versions prior to 17the routines required an additional integer argument “N” following the
LNKTYP argument.
N (integer) the corresponding line number to jump to if the subprogram is
present.
The LINKCK subroutine is provided to the users as a means to standardize the TRNSYS error and
warning messages associated with unlinked subroutines. The user should only call LINKCK when an
unlinked subroutine is detected or an external function is required.
The following example should clarify the use of the LINKCK subroutine. Refer to section 3.3.5 for more
details.
Subroutine Type75
...
Character (len=12) ENAME1,ENAME2
Double Precision :: SPAR(10),WPAR(10),FV
Integer :: ILINK,LNKTYP,INFO(15)
7–110
TRNSYS 18 – Programmer's Guide
...
! Attempt to call the TRNSYS 16 subroutine called “ENCLOSURE.” NOTE: a !
TRNSYS 16 subroutine is used in this example because it makes use of ! the
“alternate return” technique.
Call ENCLOSURE(SPAR,WPAR,FV,INFO,*101)
! Stop TRNSYS if the ENCLOSURE subroutine is not present.
ILINK = 1
IDUM = 75
ENAME1 = ‘TYPE75 ’
ENAME2 = ‘ENCLOSURE ’
Call LINKCK(ENAME1,ENAME2,ILINK,IDUM)
7–111
TRNSYS 18 – Programmer's Guide
NRC (integer) is the column and row dimensions of the two-dimensional A()
array as defined in the program that calls InvertMatrix.
N (integer) the number of equations and unknowns associated with the
problem.
A a double precision two-dimensional array (A(NRC, NRC)). Upon calling
InvertMatrix A should contain the matrix to be inverted. InvertMatrix also
returns the inverted matrix in the A array.
iFLAG an integer flag that is set to 0 if the inversion proceeds correctly, 1 if the
number equations and unknowns, N, exceeds 50, and 2 if the matrix is
singular.
The MATRIX_INVERT, INVERT, and DINVRT routines required the additional argument *N following the
iFlag argument.
*N the corresponding line number to jump to if the subprogram is present.
The inverted matrix is returned in the A array. The method used to invert the matrix is the Gauss-Jordan
reduction with maximum pivoting.
7–112
TRNSYS 18 – Programmer's Guide
[Link]. Messages
The Messages utility routine provides the Type programmer with a convenient method of reporting error
messages to the end user. When a Type catches a particular condition, it can send a text string and
information as to the severity of the condition to the Messages utility subroutine. Messages will take care
of logging the event, reporting it to both the simulation list and log files, and stopping the simulation if
appropriate.
INTERFACE
Subroutine Messages(errorCode,message,severity,unitNo,typeNo)
Integer :: errorCode
Character (len=*) :: message, severity
Integer :: unitNo, typeNo
(Note: Although the length of message is not explicitly declared, it should never exceed the
maxMessageLength global constant).
USAGE
ERRORCODE
errorCode is a standard TRNSYS error message number. Please refer to the initializeErrorMessages()
subroutine in Messages.f90 for existing messages.
If you wish to generate a custom error message (as will most often be the case for user-written Types),
simply set ErrorCode to a value of –1, indicating the messages that the second argument (message)
contains the information to be printed.
MESSAGE
If you are generating a custom error message, this string variable will be printed in a standard format by
the Messages subroutine. It should consist of one line of text, shorter than maxMessageLength. The
example here below illustrates the use of Write to add run-time information to the message.
If you are using a standard error message, the string text will be printed in addition to the standard error
message under the heading “Reported Information.” It is a method for providing additional information
about the error.
SEVERITY
severity is a string that indicates the severity of the message. Messages understands 4 levels of severity:
"Notice": A notice is simply information that you would like the user to know
"Warning": The messages subroutine keeps track of how many "Warning" messages have been
generated. If the maximum allowable number of warnings (set by the LIMITS statement in the input
file) are exceeded, then the messages subroutine automatically generates a "Fatal" error.
"Fatal": Designates a fatal error, i.e. an error that should stop the simulation. A call to Messages with
such an error should be followed by a "return 1" statement in the calling Type. Note that TRNSYS
will stop after going up the chain of "return" statements and giving the chance to all subroutines to
perform end-of-simulation operations. Further errors might be generated during that process.
7–113
TRNSYS 18 – Programmer's Guide
"Stop": The error will abort TRNSYS immediately without going up the chain of "return" statements,
by generating an exception in the DLL and returning control to [Link]. This error type should
only be used as a last resort, e.g. when returning from that error would result in memory access
violations or other exceptions. Exiting from a DLL by generating an exception is generally considered
as bad programming and users should only use this technique if the cost of modifying the Type to
handle the error properly is too high.
Note: severity is a FORTRAN literal string and can be enclosed in single or double
quotes. Messages will understand some case variants of the codes here above. e.g.
notice, Notice and NOTICE are accepted (other variants are not)
EXAMPLE
The following example illustrates calls to Messages with different severity levels by a Type for which the
first parameter > 10 is not acceptable (values < 10.1 are just rounded to 10 and the simulation goes on).
Subroutine Type200
...
Use TrnsysConstants
Use TrnsysFunctions
...
Character (len=maxMessageLength) :: myMessage
Integer crntUnit,crntType
Double Precision :: param1
...
crntUnit = getCurrentUnit()
crntType = getCurrentType()
param1 = getParameterValue(1)
If (param1 < 10.0 ) Then
Write(myMessage,'("parameter 1 = ",g," , which is OK")') param1
Call Messages(-1,trim(myMessage),'Notice', crntUnit,crntType)
ElseIf (getParameterValue(1) <= 10.1) Then
Call Messages(-1,'parameter 1 has been rounded to 10', &
'Warning',crntUnit,crntType)
Else
Call Messages(-1,''parameter 1 is outside the acceptable range.', &
'Fatal', crntUnit,crntType)
Return
EndIf
…
Please note the use of RETURN following the call to Messages with a severity of ‘Fatal.’ When the
severity of the message is low (notice, message, or warning), the simulation should proceed; thus no
RETURN statement is required. In the case of a ‘fatal’ message, however, the simulation should be
immediately stopped and the Type should return control to the TRNSYS kernel through use of the
RETURN statement.
7–114
TRNSYS 18 – Programmer's Guide
[Link]. ParRead
This is an undocumented subroutine used internally by some standard Types. See the source code in
ParRead.f90 for additional information.
7–115
TRNSYS 18 – Programmer's Guide
CrntUnit the UNIT number of the TYPE calling the MoistAirProperties routine. If a
non-Type is calling the routine, this argument should be set to -1
CrntTyp the TYPE number of the TYPE calling the MoistAirProperties routine. If a
non-Type is calling the routine, this argument should be set to -1
iUnits an integer variable equal to 1 or 2 identifying the units desired for the
properties. IUNITS = 1 results in properties in SI units. IUNITS = 2
results in properties in English units.
mode an integer variable from 1 through 6. Three properties are needed to
specify the moist air state. The MODE identifies which two properties
besides pressure are need to be input, leaving the other properties to be
calculated. The modes are as follows:
1: input dry bulb and wet bulb temperatures (PSYDAT(2) and
PSYDAT(3))
2: input dry bulb temperature and relative humidity (PSYDAT(2)
and PSYDAT(4))
3: input dry bulb and dew point temperatures (PSYDAT(2) and
PSYDAT(5))
4: input dry bulb temperature and humidity ratio (PSYDAT(2) and
PYSDAT(6))
5: input dry bulb temperature and enthalpy (PSYDAT(2) and
PSYDAT(7))
6: input humidity ratio and enthalpy (PSYDAT(6) and PSYDAT(7)) .
If saturation conditions occur, enthalpy is reset to saturation
enthalpy at the given value of humidity ratio.
7: input humidity ratio and enthalpy (PSYDAT(6) and PSYDAT(7)) .
If saturation conditions occur, humidity ratio is reset to saturation
humidity ratio at the given value of enthalpy. 8: input relative
humidity and enthalpy (PSYDAT(6) and PSYDAT(4)).
wbMode an integer variable equal to 0 or 1. If WBMODE = 0, the wet bulb
temperature will not be calculated in MODEs 2 through 6. If WBMODE =
1, the wet bulb temperature is calculated. At PATM = 1.0 and
7–116
TRNSYS 18 – Programmer's Guide
MATHEMATICAL DESCRIPTION
7–117
TRNSYS 18 – Programmer's Guide
In determining a number of moist air properties the water vapor saturation pressure (PWS) is required.
The correlations (ASHRAE, 2001) used for PWS are accurate over the temperature range of 100C to
200C. A warning is printed if moist air states occur outside this temperature range.
The correlations for the dew point temperature (ASHRAE, 2001) are accurate over the temperature range
of -60C to 70C. A warning is printed if moist air states occur outside this dew point range.
This subroutine checks for many improper inputs, such as relative humidities less than 0. or greater than
1., dew point temperatures greater than the dry bulb temperature, and the input of two properties that
cannot be correct for one state (such as a humidity ratio greater than saturation humidity ratio for dry air
at a given dry bulb temperature). For these and other improper inputs, the subroutine prints a warning,
corrects one of the inputs and continues, or prints an error and halts the simulation.
7–118
TRNSYS 18 – Programmer's Guide
[Link]. Rcheck
The RCHECK subroutine was added to TRNSYS 14 to provide input-output mismatch checking for all
components, especially those that do not have the benefit of INPUT/OUTPUT unit connection checking
as part of an interface program such as the Simulation Studio. With the release of TRNSYS v17, direct
calls by a Type to the RCHECK routine became somewhat obsolete as two access functions were written
to replace them. A call to RCHECK is of the form:
Integer :: INFO(15)
Character (len=3) :: YCHECK(:),OCHECK(:)
...
Call RCHECK(INFO,YCHECK,OCHECK)
where
INFO This is the standard INFO array used in TRNSYS (see Section
[Link]). It is used in the RCHECK subroutine to identify the Unit and
Type number of the component which calls the subroutine, which will be
printed during a simulation if warnings or errors occur.
YCHECK A 3-character array containing the expected input types for the
component.
OCHECK A 3-character array containing the output types for the component
The RCHECK array is passed the input and output types for each component in the simulation and stores
these variables in arrays with the same structure as the kernel’s XIN and OUT arrays. When the TRNSYS
processor checks for input-output mismatches, the arrays are inspected to ensure that the variable types
for an input-output connection are consistent.
With the release of TRNSYS v17, it was recommended that calls to RCHECK be replaced by use of the
“setInputUnits” and “setOutputUnits” access functions. See section Error! Reference source not found.
for information about converting Types to the TRNSYS 17 coding standard. Refer to sections [Link]
and [Link] for additional information about these specific access functions.
In TRNSYS v16 and earlier, it was recommended that a user formulating a new component utilize the
RCHECK input/output checking feature of TRNSYS for two reasons: input/output checking ensures that
TRNSYS connections are correctly defined, and output information such as output type and output units
are carried with the output and are able to be processed by the TYPE 25 printer and the TYPE 57 unit
conversion routine.
The first step in input/output checking with RCHECK is to characterize the inputs and outputs using the
codes from Table [Link]. Users wishing to create additional input-output types or add a unit conversion
to an existing input-output type should modify the file “[Link]”, keeping the same format and style as
the original. Refer to the TYPE 57 unit conversion routine for more details on modifying this file. The
input-output types should be stored in the YCHECK and OCHECK arrays respectively.
The final step in using the input/output checking is to call the RCHECK array at the proper time, with the
proper arrays. The RCHECK routine should be called during the first iteration in most cases (during the
“first call manipulations) (formerly INFO(7)=-1) see Section [Link]) and after the call to the TYPECK
subroutine (see Section 3.4.1).
7–119
TRNSYS 18 – Programmer's Guide
The following example should help clarify the use RCHECK by a TRNSYS 16 coding standard
component:
Subroutine TYPE75(TIME,XIN,OUT,T,DTDT,PAR,INFO,ICNTRL,*)
! There are 3 Inputs and 4 Outputs for this Type
! Inputs: Temperature in (F)
! Mass flow rate in (lb-m/hr)
! Control signal in (0 or 1)
! OUTPUTS: Temperature out (C)
! Mas flow rate out (kg/hr)
! Heat transfer rate (kJ/hr)
! Power (W)
...
Character (len=3) :: YCHECK(3),OCHECK(4)
Integer :: INFO(15)
...
Data YCHECK/’TE2’,’MF3’,’CF1’/
Data OCHECK/’TE1’,’MF1’,’PW1’,’PW2’/
...
If (INFO(7).EQ.-1) Then
...
Call RCHECK(INFO,YCHECK,OCHECK)
...
Return 1
EndIf
As a point of reference, the same results are achieved in TRNSYS 17 coding standard as follows:
Subroutine Type75
! There are 3 Inputs and 4 Outputs for this Type
! Inputs: Temperature in (F)
! Mass flow rate in (lb-m/hr)
! Control signal in (0 or 1)
! OUTPUTS: Temperature out (C)
! Mas flow rate out (kg/hr)
! Heat transfer rate (kJ/hr)
! Power (W)
...
If (getIsFirstCallofSimulation()) Then
...
Call setInputUnits(1,’TE2’)
Call setInputUnits(1,’MF3’)
Call setInputUnits(1,’CF1’)
Call setOutputUnits(1,’TE1’)
Call setOutputUnits(1,’MF1’)
Call setOutputUnits(1,’PW1’)
Call setOutputUnits(1,’PW2’)
...
Return
EndIf
Table [Link]-1: TEMPERATURE
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
7–120
TRNSYS 18 – Programmer's Guide
1 m LE1 1 0
2 cm LE2 100 0
3 km LE3 1000 0
4 in LE4 39.3701 0
5 ft LE5 3.28084 0
6 miles LE6 6.21371 E-04 0
Table [Link]-3: AREA
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 m2 AR1 1 0
2 cm2 AR2 1 E+04 0
3 km2 AR3 1 E-06 0
4 in2 AR4 1550 0
5 ft2 AR5 10.7639 0
6 mi2 AR6 3.86102 E-07 0
Table [Link]-4: VOLUME
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 m3 VL1 1 0
2 l VL2 1000 0
3 ml VL3 1 E+06 0
4 in3 VL4 6.10237 E+04 0
5 ft3 VL5 35.3147 0
6 gal VL6 264.172 0
Table [Link]-5: SPECIFIC VOLUME
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 m3/kg SV1 1 0
2 l/kg SV2 1000 0
3 ft3/lbm SV3 16.0185 0
4 in3/lbm SV4 2.76799 E+04 0
Table [Link]-6: VELOCITY
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 m/s VE1 1.0 0
2 km/hr VE2 3.6 0
3 ft/s VE3 3.28084 0
4 ft/min VE4 196.85 0
5 mph VE5 2.23694 0
Table [Link]-7: MASS
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kg MA1 1 0
2 g MA2 1000 0
3 lbm MA3 2.20462 0
4 ounces MA4 35.274 0
5 ton MA5 1.10231 E-03 0
Table [Link]-8: DENSITY
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kg/m3 DN1 1.0 0
2 kg/l DN2 0.001 0
3 lbm/ft3 DN3 6.2428 E-02 0
4 lbm/gal DN4 8.3454 E-03 0
7–121
TRNSYS 18 – Programmer's Guide
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 N FR1 1.0 0
2 lbf FR2 0.224809 0
3 ounce FR3 3.59694 0
Table [Link]-10: PRESSURE
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 BAR PR1 1 0
2 kPa PR2 100 0
3 Pa PR3 1 E+05 0
4 ATM PR4 0.986923 0
5 psi PR5 14.5038 0
6 lbf/ft2 PR6 2.08854 E+03 0
7 in. H2O PR7 401.463 0
8 in. Hg PR8 29.53 0
Table [Link]-11: ENERGY
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kJ EN1 1 0
2 kWh EN2 2.77778 E-04 0
3 Cal EN3 238.846 0
4 ft-lbf EN4 737.562 0
5 hp-hr EN5 3.72506 E-04 0
6 BTU EN6 0.947817 0
Table [Link]-12: POWER
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kJ/hr PW1 1 0
2 W PW2 0.277778 0
3 kW PW3 2.77778 E-04 0
4 hp PW4 3.72505 E-04 0
5 BTU/hr PW5 0.947817 0
6 BTU/min PW6 1.57969 E-02 0
7 Tons PW7 7.89847 E-05 0
Table [Link]-13: SPECIFIC ENERGY
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kJ/kg SE1 1 0
2 BTU/lbm SE2 0.429923 0
3 ft-lbf/lbm SE3 334.553 0
Table [Link]-14: SPECIFIC HEAT
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kJ/kg-K CP1 1 0
2 W-hr/kg-K CP2 0.277778 0
3 BTU/lbm-R CP3 0.238846 0
Table [Link]-15: FLOW RATE
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kg/hr MF1 1 0
2 kg/s MF2 2.77778 E-04 0
3 lbm/hr MF3 2.20462 0
7–122
TRNSYS 18 – Programmer's Guide
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 m3/hr VF1 1 0
2 m3/s VF2 2.77778 E-04 0
3 l/hr VF3 1000 0
4 l/s VF4 0.277778 0
5 ft3/s VF5 9.80958 E-03 0
6 ft3/hr VF6 35.3144 0
7 gpm VF7 4.40286 0
Table [Link]-17: FLUX
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kJ/hr-m2 IR1 1 0
2 W/m2 IR2 0.277778 0
3 BTU/hr-ft2 IR3 8.8055 E-02 0
Table [Link]-18: THERMAL CONDUCTIVITY
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kJ/hr-m-K KT1 1 0
2 W/m-K KT2 0.277778 0
3 BTU/hr-ft-R KT3 0.160497 0
Table [Link]-19: HEAT TRANSFER COEFFICIENTS
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 kJ/hr-m2-K HT1 1 0
2 W/m2-K HT2 0.277778 0
3 BTU/hr-ft2-R HT3 4.89194 E-02 0
Table [Link]-20: DYNAMIC VISCOSITY
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 N-s/m2 VS1 1 0
2 kg/m-s VS2 1 0
3 poise VS3 10 0
4 lbf-s/ft2 VS4 2.08854 E-02 0
5 lbf-hr/ft2 VS5 5.80151 E-06 0
6 lbm/ft-hr VS6 2419.08 0
Table [Link]-21: KINEMATIC VISCOSITY
VAR. TYPE # VAR. UNITS VAR. TYPE MULT. FACTOR ADD. FACTOR
1 m2/s KV1 1 0
2 m2/hr KV2 3600 0
3 ft2/s KV3 10.7639 0
4 ft2/hr KV4 3.87501 E+04 0
Table [Link]-22: MISCELLANEOUS
VAR. TYPE
Dimensionless DM1
Degrees DG1
Percentage PC1
7–123
TRNSYS 18 – Programmer's Guide
Month MN1
Day DY1
Hour TD1
Control function CF1
Volts VO1
Ampere CU1
Ohm RE1
Ampere-hour AH1
In user-written routines that have output variable types dependent on input variable types, such as a
statistics or integrator routine, the call to RCHECK must come on the second iteration of the first time
step, after a call to the EQUATER subroutine. The EQUATER subroutine will determine the output
connected to the unknown input and provide the appropriate input type. A call to the EQUATER
subroutine has the following form:
Character (len=3) :: TRUTYP,INDES,ODES
Double Precision :: X1,A1,X2,A2
Integer :: IU,INNO, OUTU,OUTNO,ICK1,ICK2
Call EQUATER(IU,INNO,INDES,TRUTYP,OUTU,OUTNO,ODES,X1,A1,X2,A2,ICK1,ICK2)
where
7–124
TRNSYS 18 – Programmer's Guide
Users attempting to use the input/output checking algorithm in this capacity should refer to the TYPE 55
Periodic Integrator subroutine and the EQUATER subroutine source code for more details.
7–125
TRNSYS 18 – Programmer's Guide
[Link]. Rewind
The Rewind utility is designed to rewind a data file whose end has been reached through multiple read
statements. It is able to then skip a specified number of steps from the beginning of the file and leave a
pointer ready to read the first non skipped line. A call to Rewind should have the following form:
Integer :: LU,SKIP,IU,IT,IE
...
Call Rewind(LU,SKIP,IU,IT,IE)
where
LU (integer) the Fortran logical unit number ASSIGNed to the data file that is
to be rewound.
SKIP (integer) the number of lines that should be skipped in the data file once
it is rewound.
IU (integer) the unit number of the Type calling the Rewind routine.
IT (integer) the type number of the Type calling the Rewind routine.
IE (integer) an error code that is returned by the Rewind routine and is set
to zero if no errors were encountered while rewinding the data file or
skipping lines and which is set to a vale of 1 if errors were encountered.
EXAMPLE
The following example shows the usage of the Rewind routine and a possible method for checking
whether errors occurred during the rewind process.
Use TrnsysFunctions
...
Integer :: LU,SKIP,iUnit,iType,iError
...
LU = jfix(getParameterValue(1)) ! the jfix() function turns a double precision
! value into an integer.
SKIP = 10
iUnit = getCurrentUnit
iType = getCurrentType
Call Rewind(LU,SKIP,iUnit,iType,iError)
If (iError == 1) Then
Return
EndIf
...
7–126
TRNSYS 18 – Programmer's Guide
The SolarCellPerformance subroutine is called by Types 49 and 50 and uses a set of empirical values to
model the cells. Data for Spectrolab type cells, provided by Professor Evans, is "built-in" and is used by
default if no other data are supplied by the user. Users may supply their own data by adding an extra
parameter to the list of TYPE 49 or TYPE 50 in modes 5-8. This extra parameter is interpreted as the
logical unit number of the file containing the cell characteristics. The data are read using 6F10.0 format
and should be ordered as follows; (default values are listed after the definition of the parameter):
FIRST RECORD:
ICELL Cell type indicator, 0 for Spectrolab and Solarix Types, 1 for RCA types (peak power
tracking only for RCA); (0).
CELLPF Ratio of cell area to absorber area; if ICELL = 1, the numerical value is ignored, but a
number must be present; (0.8).
SECOND RECORD:
TL A low temperature reference (˚ C); (43)
TH A high temperature reference (˚ C); (175)
CL A low reference concentration; (6)
CH A high reference concentration; (20)
VOCLL Open circuit voltage of a cell at temperature TL and concentration CL (volts); (0.625)
ISCLL Short circuit current of the cell at temperature TL and concentration CL (amps); (0.649)
THIRD RECORD:
ISCLH Short circuit current of the cell at temperature TL and concentration CH (amps); (0.625)
ISCHL Short circuit current of the cell at temperature TH and concentration CL(amps); (2.16)
ISCHH Short circuit current of the cell at temperature TH and concentration CH(amps); (2.16)
ACELL Gross cell area (m2); (0.0004)
EG Cell band gap at 0 Kelvin; (14000)
AOMIN Value of Ao. at concentration of 0; (1)
FOURTH RECORD:
DAODC Slope of the Ao. vs concentration curve; (0.018)
7–127
TRNSYS 18 – Programmer's Guide
CONTR Minimum concentration for which the series resistance can be considered to be equal to
RSMIN; (10)
DRSDC Slope of the series resistance vs concentration curve below a concentration CONTR; (-
0.005)
NSER Number of cells to be wired in series in the array (10)
7–128
TRNSYS 18 – Programmer's Guide
dT
aT b Eq. 7.4.4-48
dt
The designation “double precision” means that the arguments and results of the utility routine SolveDiffEq
must be declared in the calling Type as DOUBLE PRECISION variables as opposed to REAL or
INTEGER variables.
Users intending to utilize the Powell’s method TRNSYS solver (SOLVER 1) should use the SolveDiffEq
subroutine discussed here instead of the numerical derivative solver (the DTDT array) discussed in
section 7.4.5. The form of the call to SolveDiffEq is:
Double Precision :: time,AA,BB,TI,TF,TBAR
...
Call SolveDiffEq(AA, BB, TI, TF, TBAR)
where
SolveDiffEq solves differential equations at each call based on parameters and the current set of inputs. If
the inputs have not converged, the iteration proceeds by direct substitution provided that the Successive
Substitution solver (SOLVER 0) is being used. Additional notes on the analytical solution of differential
equations are as follows:
1) SolveDiffEq requires the arguments AA, BB, and TI, while returning TF and TBAR. For calls to
SolveDiffEq at the start time of the simulation (TIME= TIME0), the initial condition TI is returned
for both TF and TBAR.
2) It is necessary to save the final values of dependent variables each time step as initial conditions
for the following interval. This can be done using calls to the getStorageVars and setStorageVars
routine discussed in sections [Link].
3) Inputs will often be a function of the dependent variable of the differential equation. For instance,
collector outlet temperature, which might be an input to a storage component, might also be a
function of the storage temperature. In order to get a good estimate of the average inputs over
each interval, TBAR should be set as an output if required as an input of other components. To
7–129
TRNSYS 18 – Programmer's Guide
be consistent with this formulation and the rectangular integration provided by Type24, etc., any
outputs that are rates and are expressed as a function of the dependent variable T should be
evaluated at TBAR.
As an example of a model formulation, suppose that one wishes to study the temperature response of a
one-node house to ambient conditions. The instantaneous energy balance for this situation is given as
dTR
C (UA) L (TR Ta ) Eq. 7.4.4-49
dt
(UA) L (UA) L Ta
a and b Eq. 7.4.4-50
C C
The following code would establish initial conditions, solve the differential equation for the final and
average temperatures, and determine the average energy loss rate from the house for each time interval.
Double Precision :: ti,aa,bb,ual,ta,c,qLoss,tf,tBar
...
C PERFORM FIRST CALL MANIPULATIONS
If (getIsFirstCallOfSimulation() ) Then
...
!reserve space in the dynamic storage structure
Call setNumberStoredVariables(0,1) !0 static spots, 1 dynamic spot.
...
!set initial values of the variables in the dynamic storage structure
Call setDynamicArrayInitialValue(1,10.d0)
!return to the calling program
Return
EndIf
...
!The following section is executed at every iteration.
ti = getDynamicArrayValueLastTimestep(1)
aa = -ual/c
bb = ual*ta/c
Call SolveDiffEq(aa,bb,ti,tf,tbar)
Call setDynamicArrayValueThisIteration(1,tf)
qLoss = ual*(tbar - ta)
...
One subtlety in the above example is well worth noting. Note that the call to SolveDiffEq is made with the
temperature at the start of the time step (ti) and that SolveDiffEq returns both the temperature at the end
of the time step (tf) and the average temperature over the time step (tbar). TRNSYS outputs are (almost)
always the average value over a time step so the calculation of qLoss is made using tbar. However, the
differential equation solver will need to know the temperature at the end of the time step in order to have
a correct initial value at the next time step. Thus it is the final temperature (tf) that is stored using the call
to setDynamicArrayValueThisIteration().
It is worth noting that the code above makes use of the Dynamic Data Storage feature introduced in
Trnsys17 (i.e. the functions setNumberStoredVariables(), setDynamicArrayInitialValue(),
setDynamicArrayValueThisIteration(), and getDynamicArrayValueLastTimestep()). Components written
using the Trnsys16 coding standard would instead make use of calls to the setStorageVars() and
getStorageVars() subroutines. The same example is repeated using the older coding standard. NOTE:
7–130
TRNSYS 18 – Programmer's Guide
components using the Trnsys17 coding standard cannot directly use the following code because the
contents of the info() array is not passed to them.
Double Precision :: stored(2),ti,aa,bb,ual,ta,c,qLoss,tf,tBar
Integer :: nS,info(15)
...
!this section is executed at the end of each timestep. In this case it is
!used to update the storage structures for the following time step.
If (isEndOfTimestep()) Then
Call getStorageVars(stored,nS,info)
stored(1) = stored(2)
Call setStorageVars(stored,nS,info)
EndIf
...
!The following section is executed at every iteration.
Call getStorageVars(stored,nS,info)
ti = stored(1)
aa = -ual/c
bb = ual*ta/c
Call SolveDiffEq(aa,bb,ti,tf,tbar)
stored(2) = tf
qLoss = ual*(tbar - ta)
Call setStorageVars(stored,nS,info)
...
For this particular example (and regardless of coding standard), the component would not be called by
the kernel during any time step after its inputs have converged within the algebraic error tolerance. There
is no need for a differential equation convergence check, since the solution will always be consistent with
the current set of inputs. A DERIVATIVES control statement should not be used for the component in the
simulation input file; the initial value of the dependent variable at the beginning of the simulation should
be supplied to the subroutines as a PARAMETER. In this respect the example is similar to Types 12, 21
and 23.
In TRNSYS version 16.x, this subroutine was called Differential_Eqn but had all the same arguments and
return values. A single precision version of the routine (called DIFFEQ) is also available.
7–131
TRNSYS 18 – Programmer's Guide
UNITS two character variable denoting unit system to be employed by the fluids
routine; ‘SI’ for metric units and ‘EN’ for english units
PROP double precision array holding the two known thermodynamic properties
of steam upon entry and the complete state upon return from the
Steam_Properties routine. This array must be dimensioned to 7 in the
routine that calls Steam_Properties. Each location in this array is
described below:
PROP(1) (double precision) temperature of the steam (F, C)
PROP(2) (double precision) pressure of the steam (PSI, MPa)
PROP(3) (double precision) enthalpy of the steam (BTU/lbm, kJ/kg)
PROP(4) (double precision) entropy of the steam (BTU/lbm R, kJ/kg K)
PROP(5) (double precision) quality (0 < x < 1)
PROP(6) (double precision) specific volume (ft3/lbm, m3/kg)
PROP(7) (double precision) internal energy (BTU/lbm, kJ/kg)
ITYPE integer variable denoting which two properties are supplied as known
properties. ITYPE = 10* PROP indicator 1 + PROP indicator 2 (12 to
76)
IERR an integer variable returning the error messages from the
Steam_Properties call:
= 0 - no error found, calculations completed
> 0 - error found, calculations could not be completed
The legacy subroutines STEAM_PROPS and STEAM required a 5 th argument *N following the iErr
argument.
*N the corresponding line number to jump to if the subprogram is present
An example illustrating the use of the Steam_Properties routine is shown with the following
considerations: SI units are desired, and Temperature (PROP(1)) and Quality (PROP(5)) are known.
Use TrnsysFunctions
...
Character (len=2) :: units
Double Precision :: prop(7),temperature,quality,pressure,enthalpy
...
7–132
TRNSYS 18 – Programmer's Guide
MATHEMATICAL DESCRIPTION
The correlations required to solve for the steam properties are from the EES program (8), a numerical
solver employing thermodynamic correlations from many different sources. Interested users should
contact the reference for more details on the correlations.
Enthalpies for steam are based on the following reference state: enthalpy equal to zero at 0C
This subroutine checks for much improper input, such as qualities less than 0. or greater than 1., and the
input of two properties that cannot be correct for one state. For these and other improper inputs, the
subroutine prints a warning, corrects one of the inputs, and continues; or prints an error and halts the
simulation.
Subcooled properties are not available for steam. If a subcooled state is specified, the saturated liquid
results will instead be provided.
7–133
TRNSYS 18 – Programmer's Guide
One solution to this problem is to use an output; Types can reserve a few additional outputs and store the
values that they need in those spots. However, for large storage requirements, it is recommended that a
series of calls to AccessFunctions be used instead. Prior to the release of TRNSYS v.16, structures called
the “S array” and the STORE common block were the recommended solution. With the release of
TRNSYS v.16, three AccessFunctions (setStorageSize(), getStorageVars() and setStorageVars) were
added and recommended. With the release of TRNSYS v.17, the concept of data storage between time
steps was further simplified into two main usages: “static” and “dynamic.” If the user has a component that
was written using an earlier coding standard, both the “s array” and the set/getStorageVars() functions
are retained in the kernel so that the component does not need to be modified. However, if the user is
writing a component using the TRNSYS v.17 coding standard, the user should not make use of these
earlier features as they are incompatible with the more recent standard. The TRNSYS v.16
AccessFunctions are discussed in section [Link].1.3 for reference.
In the “static storage” situation, the Type calculates a value that is not going to change throughout the
simulation or that is going to change only sporadically. A good example is the solar radiation view factor
of a particular façade element in the Type34 overhang and wingwall shading component. The user enters
the dimensions of the façade, overhang, and wingwalls as parameters of the model. The model takes
those values and calculates a sky view factor for the façade. Since the view factor is based only on
parameters it need never be calculated again unless there is more than one instance of Type34 in the
simulation. The view factor calculation is time consuming so the user might decide to calculate the view
factor once during the “first call” manipulations and then store the value, retrieving it only if the “reread
parameters” manipulation section is required. The above is an example of a static storage variable. In this
situation, three AccessFunctions would be used: setNumberStoredVariables(), setStaticArrayValue() and
getStaticArrayValue()
SETNUMBERSTOREDVARIABLES(NSTATIC,NDYNAMIC)
INTERFACE
subroutine setNumberStoredVariables(nStatic,nDynamic)
integer :: nStatic,nDynamic
DESCRIPTION
The setNumberStoredVariables AccessFunction should be called during the “First Call” manipulations.
This will tell the storage data structure how many spots it needs to reserve for your component. The
subroutine has two arguments:
nStatic: The integer number of “static” storage spots required by this component.
7–134
TRNSYS 18 – Programmer's Guide
nDynamic: The integer number of “dynamic” storage spots required by this component. NOTE: we
will not be concerning ourselves with dynamic storage in this example. Please refer to the example
immediately following for information about dynamic storage.
GETSTATICARRAYVALUE(N)
INTERFACE
subroutine getStaticArrayValue(n)
integer :: n
DESCRIPTION
When the user wants to obtain a previously stored static value a call is made to the getStaticArrayValue
AccessFunction. The AccessFunction takes the following arguments:
m: The integer index of the variable to be retrieved. If more than one variable value is to be stored, it
is up to the Type programmer to keep track of which variable is at which index.
SETSTATICARRAYVALUE(M,VAL)
INTERFACE
subroutine setStaticArrayValue(m,val)
integer :: m
double precision :: val
DESCRIPTION
When the user wants to set storage, a call is made to the setStaticArrayValue() AccessFunction. The
setStaticArrayValue() function takes the following arguments:
m: The integer index of the variable to be retrieved. If more than one variable value is to be stored, it
is up to the Type programmer to keep track of which variable is at which index.
val: A double precision variable containing the value that is to be stored.
A tank model which uses global static storage to store the initial tank temperature might contain the
following lines:
...
C PERFORM FIRST CALL MANIPULATIONS
If (getIsFirstCallOfSimulation() ) Then
...
!reserve space in the double precision storage structure
Call setNumberStoredVariables(1,0) !1 static spot, 0 dynamic spots.
...
!return to the calling program
Return
EndIf
7–135
TRNSYS 18 – Programmer's Guide
...
!return to the calling program
Return
EndIf
...
Call getStaticArrayValue(1,T)
TZERO = Stored(1)
...
The above example is exceedingly simplistic. The result of it is that no matter what is done to the local
variable TZERO later in the Type, it will always be reset to the initial value of T each time the Type is
called anew. It is well worth noting that while we refer to this kind of storage as “static” it is not actually
static. The user can call the setStaticArrayValue() AccessFunction whenever they like, thereby changing
the stored value.
In the “dynamic storage” situation arises when not only do we wish to use an initial value in calculations
but at the end of the time step, we wish to set the final calculated value as the new initial value for the
next time step. Any component that solves a differential equation is almost invariably going to use
dynamic storage because it needs to predict a final value not based on the final value from the previous
iteration but the final value from the previous time step. The Type therefore needs to store the final value
from the previous time step somewhere safe. In TRNSYS v.16, this would have been accomplished by
reserving two spots in the global storage structure. One spot would be updated at the end of each
iteration with the “proposed” final value. Then, during the “end of time step” manipulations section, the last
calculated “proposed” final value would have been saved into the other global storage spot as the “real”
final value. At the next time step, the Type would read and base its calculations on the “real” final value,
repeatedly calculating a new “proposed” final value. With the development of TRNSYS v17, it was felt that
the “end of timestep” manipulations were too cumbersome and the concept of “dynamic” global storage
was proposed. In this case, only one storage spot is required. The Type calls the setDynamicArrayValue()
AccessFunction at the end of each iteration and bases its calculations on what it retrieves from a call to
the getDynamicArrayValue() function. The TRNSYS kernel takes care of swapping the two values
automatically at the end of a time step.
SETNUMBERSTOREDVARIABLES(NSTATIC,NDYNAMIC)
INTERFACE
subroutine setNumberStoredVariables(nStatic,nDynamic)
integer :: nStatic,nDynamic
DESCRIPTION
The setNumberStoredVariables AccessFunction should be called during the “First Call” manipulations.
This will tell the storage data structure how many spots it needs to reserve for your component. The
subroutine has two arguments:
nStatic: The integer number of “static” storage spots required by this component. NOTE: we will not
be concerning ourselves with static storage in this example. Please refer to the example immediately
above for information about static storage.
nDynamic: The integer number of “dynamic” storage spots required by this component.
7–136
TRNSYS 18 – Programmer's Guide
GETDYNAMICARRAYVALUELASTTIMESTEP(N)
INTERFACE
subroutine getDynamicArrayValueLastTimestep(n)
integer :: n
DESCRIPTION
When the user wants to obtain a previously stored dynamic value a call is made to the
getDynamicArrayValueLastTimestep() AccessFunction. The AccessFunction takes the following
arguments:
m: The integer index of the variable to be retrieved. If more than one variable value is to be stored, it
is up to the Type programmer to keep track of which variable is at which index.
SETDYNAMICARRAYINITIALVALUE (M,VAL)
INTERFACE
subroutine setDynamicArrayInitialValue(m,val)
integer :: m
double precision :: val
DESCRIPTION
When the user wants to set an initial storage value, a call is made to the setStaticArrayInitialValue()
AccessFunction. The setStaticArrayInitialValue() function takes the following arguments:
m: The integer index of the variable to be retrieved. If more than one variable value is to be stored, it
is up to the Type programmer to keep track of which variable is at which index.
val: A double precision variable containing the value that is to be stored.
SETDYNAMICARRAYVALUETHISITERATION(M,VAL)
INTERFACE
subroutine setDynamicArrayValueThisIteration(m,val)
integer :: m
double precision :: val
DESCRIPTION
When the user wants to set storage, a call is made to the setDynamicArrayValueThisIteration()
AccessFunction. The setDynamicArrayValueThisIteration() function takes the following arguments:
m: The integer index of the variable to be retrieved. If more than one variable value is to be stored, it
is up to the Type programmer to keep track of which variable is at which index.
val: A double precision variable containing the value that is to be stored.
A tank model which uses global dynamic storage to keep the tank temperature at the end of the previous
time step might contain the following lines:
...
C PERFORM FIRST CALL MANIPULATIONS
7–137
TRNSYS 18 – Programmer's Guide
If (getIsFirstCallOfSimulation() ) Then
...
!reserve space in the dynamic storage structure
Call setNumberStoredVariables(0,1) !0 static spots, 1 dynamic spot.
...
!return to the calling program
Return
EndIf
The first of the three utility routines reserves a requested number of spots in the global data structure.
The second routine retrieves the values from the global storage structure that correspond to the current
Type. The third sets new values in the global structure for the current Type. The following section
provides general information about the manner in which the three storage related utility routines are
called. An example of using storage in a Type follows.
SETSTORAGESIZE
INTERFACE
subroutine setStorageSize(n,INFO)
integer :: n, INFO(15)
DESCRIPTION
The setStorageSize subroutine should be called during the “First Call” manipulations. This will tell the
storage data structure how many spots it needs to reserve for your component. The subroutine has two
arguments:
n: The integer number of storage spots required by this component.
INFO: The standard INFO array is sent so that the storage data structures know what unit and type
number are requesting storage.
GETSTORAGEVARS
INTERFACE
7–138
TRNSYS 18 – Programmer's Guide
subroutine getStorageVars(storageArray,m,INFO)
integer :: m, INFO(15)
double precision :: storageArray(*)
DESCRIPTION
When the user wants to obtain a previously stored value (usually at the first call of a new time step), a call
is made to the getStorageVars subroutine. The subroutine takes the following arguments:
StorageArray: a locally defined double precision array dimensioned to n (see setStorageSize above)
that will contain the stored variables that are being retrieved from storage.
m: The integer number of variables that are to be retrieved. This argument allows the user to retrieve
only a subset of the stored variables. For example, if only the 5th stored variable is desired, setting m
to 5 will retrieve stored variables 1 through 5 and place them into spots 1 through 5 of storageArray
INFO: the standard INFO array is sent so that the storage data structures know what unit and type
number are requesting storage
SETSTORAGEVARS
INTERFACE
subroutine setStorageVars(storageArray,m,INFO)
integer :: m, INFO(15)
double precision :: storageArray(*)
DESCRIPTION
When the user wants to set storage at the end of a time step, a call is made to the setStorageVars
subroutine during the “End of Time Step” manipulations section. Much like the getStorageVars
subroutine, the setStorageVars subroutine takes the following arguments:
storageArray: a locally defined double precision array dimensioned to n (see setStorageSize above)
that will contain the stored variables that are being retrieved from storage.
m: the integer number of variables that are to be stored. This argument allows the user to store only
a subset of an array that is used in the Type.
INFO: the standard INFO array is sent so that the storage data structures know what unit and type
number are requesting storage.
STORAGE EXAMPLE
A tank model which uses global storage to store the initial tank temperature might contain the following
lines:
...
C PERFORM FIRST CALL MANIPULATIONS
If (getIsFirstCallOfSimulation() ) Then
...
!reserve space in the double precision storage structure
StorageSize = 1
Call setStorageSize(StorageSize,INFO)
...
!return to the calling program
Return
EndIf
7–139
TRNSYS 18 – Programmer's Guide
If (getIsStartTime() ) Then
...
!set initial values of variables in the double precision storage structure
Stored(1) = T
Call setStorageVars(Stored,StorageSize,INFO)
...
!return to the calling program
Return
EndIf
...
Call getStorageVars(Stored,StorageSize,INFO)
TZERO = Stored(1)
...
The above example is exceedingly simplistic. The result of it is that no matter what is done to the local
variable TZERO later in the Type, it will always be reset to the initial value of T each time the Type is
called anew. A much more common situation arises when not only do we wish to use an initial value in
calculations but at the end of the time step, we wish to set the final calculated value as the initial value for
the next time step. In TRNSYS version 15.x and before, there was no way for a Type to know when it was
being called for the last time in a given time step. With the release of TRNSYS version 16, the “end of
timestep” call to all Types was added, simplifying this process. In the following modification to the above
example, TZERO is set to an initial value. TFINAL is calculated based on TZERO. At the end of each time
step, the converged value of TFINAL is set as the value of TZERO for the next time step.
...
C PERFORM END OF TIMESTEP MANIPULATIONS
If (getIsEndOfTimestep() ) Then
Call getStorageVars(Stored,StorageSize,INFO) !recall the storage values
Stored(1)=Stored(2) !update the TZERO spot with the value stored !in the
TFINAL spot.
Call setStorageVars(Stored,StorageSize,INFO) !set the new storage values
EndIf
7–140
TRNSYS 18 – Programmer's Guide
...
!update the second storage spot with the calculated value of TFINAL
Stored(2) = TFINAL
Call setStorageVars(Stored,StorageSize,INFO)
...
7–141
TRNSYS 18 – Programmer's Guide
7–142
TRNSYS 18 – Programmer's Guide
Note: Transfer function coefficients in the file [Link] are different from those
actually found in the ASHRAE handbooks. Because the TYPE 19 single-zone model
handles the inside radiative heat transfer separately, the inside radiative resistance is not
included in the [Link] transfer coefficients. Thus while the file [Link] is
well-suited for use with TYPE 19 and other models which calculate radiative heat transfer
separately, it must not be assumed that this file matches the ASHRAE handbook values.
7–143
TRNSYS 18 – Programmer's Guide
GENERAL DESCRIPTION
The double precision function Tau_Alpha and its obsolete single precision counterpart TALF calculate the
transmittance-absorptance product () of a solar collector as a function of angle of incidence of radiation
and collector construction. The transmittance of one or more sheets of glass or plastic can be obtained
by specifying an absorptance of 1. Tau_Alpha is a double precision routine, meaning that all but its first
argument must be declared in the calling Type as double precision variables (as opposed to REAL
variables). The value returned by Tau_Alpha is also double precision. In TRNSYS versions 15.x and
below, Tau_Alpha was known simply as “TALF,” which was a single precision routine. TALF was retained
for backwards compatibility and every effort should be made to use the double precision Tau_Alpha
routine.
Due to FORTRAN considerations, functions cannot be checked for unlinked subroutines. Use the
LINKCK subroutine to warn the user that this function must be linked to the TRNSYS executable.
MATHEMATICAL DESCRIPTION
The function subprogram Tau_Alpha calculates the transmittance-absorptance product () of a solar
collector for a given angle of incident radiation. The collector is described by the number of glazings, N,
each with refractive index ng and extinction length kL, and the absorptance of the collector plate . The
model uses Fresnel's equation for the specular reflectance at a planar interface (assuming unpolarized
incident radiation) and accounts for multiple reflections. The transmittance for diffuse radiation is
approximated as the transmittance for specular radiation at an incident angle of 60 °. Fresnel's equations
for reflectance at a planar interface for perpendicular and parallel polarized radiation are the following:
perpendicular parallel
7–144
TRNSYS 18 – Programmer's Guide
The angles 1 and 2 are related by Snell's Law with the index of refraction for air of unity.
sin 1
sin 2 Eq. 7.4.4-53
ng
The transmittance and reflectance of a single glazing for each component of polarization, including
absorption and multiple reflections within the glazings, can be derived to give the following [1,2]:
a (1 i ) 2
Ti ,1 Eq. 7.4.4-54
1 a i
2 2
2 (1 i ) 2
Ri ,1 i 1 a 2
Eq. 7.4.4-55
1 a i
2
The internal transmittance, a, is a function of the extinction length and the transmission angle.
kL
a exp Eq. 7.4.4-56
cos 2
The transmittance and reflectance of N parallel plates, of the same material and thickness, can be
determined by the following recursive formulae.
Ti ,1Ti , N 1
Ti , N Eq. 7.4.4-57
1 Ri ,1Ri , N 1
Ri ,1Ti , N
Ri , N Ri , N 1 Eq. 7.4.4-58
1 Ri ,1Ri , N 1
The transmittance-absorptance product of the collector plate and glazing assembly can then be
calculated as
( )
T1, N T2, N
Eq. 7.4.4-59
21 (1 ) RD
where RD is the reflectance of the N covers to diffuse radiation. R D is calculated as the reflectance for
specular radiation at 60° incident angle.
7–145
TRNSYS 18 – Programmer's Guide
[Link]. TYPECK
The purpose of TYPECK is to perform some simple checks on the TRNSYS input file to ensure the proper
number of INPUTS, PARAMETERS, and DERIVATIVES have been specified for the given component,
and to terminate the simulation after compilation of the component input file with appropriate error
messages if errors are found. With TRNSYS versions 16.x and below, almost all Types (whether standard
or user-written) made various direct calls to the TYPECK routine, setting the IOPT argument
appropriately. With the release of TRNSYS 17, it was recommended that users wishing to write their own
components make use of various access functions (see section 7.4.2) in place of direct calls to TYPECK.
The form of a TYPECK call is:
Integer :: IOPT,INFO(15),NI,NP,ND
...
Call TYPECK(IOPT,INFO,NI,NP,ND)
where
[Link]. View_Factors
Prior to Trnsys v17 this function was known as “VIEW”
7–146
TRNSYS 18 – Programmer's Guide
GENERAL DESCRIPTION
The double precision function View_Factors (and its obsolete single precision companion VIEW) calculate
the view factor between two planer rectangles of any orientation. For common orientations, analytical
expressions are used. A call to View_Factors is of the form:
Integer :: iType,nA1,nA2
Double Precision :: A,B,C,D,E,F,G,H,X3,Y3,Z3
...
F21 = View_Factors(iType,A,B,C,D,E,F,G,H,X3,Y3,Z3,nA1,nA2)
The integer variable iType defines the type of orientation between the two surfaces. There are five
possibilities as described by the following Figures. The arguments A, B, C, D, E, F, G, H, X3, Y3, and Z3
(all double precision) are dimensions or coordinates that depend upon the orientation chosen. Not all of
these variables are used for each orientation. The possible orientations and required dimensions are
shown in Figure [Link]-1 to Figure [Link]-5. The view factor from surface 2 to 1 is determined by the
routine. The integer arguments nA1 and nA2 are the number of differential areas for each surface, when
numerical integration is used to determine view factors. nA1 is only used for ITYPE equal to 3, 4, or 5.
nA2 is only for ITYPE equal to 5.
2
1
B
A
C
Figure [Link]-1: ITYPE=1; parallel identical rectangles.
1
B
C
Figure [Link]-2: ITYPE=2; perpendicular rectangles with a common edge.
E G
B D 1
F
2
A
C
Figure [Link]-3: ITYPE=3; nonidentical parallel rectangles.
7–147
TRNSYS 18 – Programmer's Guide
B F
1
D E
C
Figure [Link]-4: ITYPE=4; perpendicular rectangles without a common edge.
2 B
X
(0, 0, 0) A
Figure [Link]-5: ITYPE=5; two rectangular surfaces of any orientation (X1=C, Y1=D, Z1=E, X2=F, Y2=G, Z2=H
from subroutine call statement).
MATHEMATICAL DESCRIPTION:
ITYPE = 1
The view factor from surface two to one of Figure [Link]-1 is determined with the following expression
taken from Reference 1.
1/ 2
2 1 X 2 1 Y 2 X
F21 ln 1 Y 2 tan 1
XY 1 X 2 Y 2 1 Y 2
Eq. 7.4.4-60
Y
Y 1 X 2 tan 1 X tan 1 X Y tan 1 Y
1 X 2
where,
X = A/C
and
Y = B/C
ITYPE = 2
7–148
TRNSYS 18 – Programmer's Guide
From Reference 1, the view factor from surface two to one of Figure [Link]-2 is
F21
1
1 1
Y tan 1 X tan 1 X 2 Y 2 tan 1
1
Y Y X X2 Y2
ln
1 1 Y 2 1 X 2 Y 1 X
2 2
Y 2 X 1 X
Y2 2 2
Y 2 X2
Eq. 7.4.4-61
1 Y X
4 1 X 2 Y 2
2 2
Y 2 1 X X 2 2
Y 2
where,
X = B/A
and
Y = C/A
ITYPE = 3
The VIEW factor from surface two to one of Figure [Link]-3 is found by numerical integration using the
following expression:
F d 1 2 dA1
Eq. 7.4.4-62
F21
A1
A2
where Fd1-2 is the view factor from an elemental area dA1 on surface 1 to surface 2 and A1 and A2 are the
areas of surfaces 1 and 2, respectively. The number of differential areas used in the integration, NA1, is
specified as an argument in the call to View_Factors( ).
The view factor Fd1-2 is determined by breaking surface 2 into 4 sections such that the normal to the
center of the element passes through a common corner of each section of surface 2.
From Reference 1,
4
1 Xi Yi Yi Xi
Fd 1 2 tan 1 tan 1 Eq. 7.4.4-63
2 1 X
1 Xi 1 Yi 1 Yi
2 2 2 2
i 1
i
where
Ai B
Xi and Yi i
C C
and Ai and Bi are dimensions of each section on surface 2, measured in the same directions as A and B.
ITYPE = 4
7–149
TRNSYS 18 – Programmer's Guide
The view factor from surface 2 to 1 of Figure [Link]-4 is also determined using Eq. 7.4.4-62. The view
factor Fd1-2 is found by breaking surface 4 into 2 sections such that the normal to a common corner of
the sections splits the element in half. From Reference 1,
2
1 1 1 Yi 1
Fd 1 2 tan tan 1 Eq. 7.4.4-64
i 1 2 Yi X i Yi
2 2 2 2
X i Yi
where
A C'
Xi and Yi
Bi Bi
Bi is the dimension of each section measured in the direction of B. C' is the distance from the edge of
surface 2 to the center of the element on surface one.
ITYPE = 5
For two rectangular surfaces of arbitrary orientation as shown in Figure [Link]-5, the view factor from 2
to 1 is:
1 cos1 cos 2
F21
A2
A1 A2 S 2
dA2 dA1 Eq. 7.4.4-65
where S is the distance between the centers of elemental areas on each surface, 1 and 2 are angles
between the normals to each element and the line connecting their centers, and A 1 and A2 are the areas
of surfaces 1 and 2. Eq. 7.4.4-65 is solved by numerical integration. The number of elemental areas used
in the integration procedure (NA1 and NA2) are specified in the argument list in the call to
View_Factors().
The distance S is
where (Xd1,Yd1,Zd1) and (Xd2,Yd2,Zd2) are the coordinates of the elemental areas on surfaces 1 and 2,
respectively. For Surface 2,
Z d1 Z d 2
cos 2 Eq. 7.4.4-67
S
For Surface 1,
7–150
TRNSYS 18 – Programmer's Guide
SN
cos 1 Eq. 7.4.4-68
N S
where S is the vector originating at the center of the elemental area on surface 1 and ending at the
center of the second element on surface 2 and N is a normal vector to the elemental area on surface 1.
In general,
S sxi s y j sz k Eq. 7.4.4-69
N nx i n y j nz k Eq. 7.4.4-70
where i , j , and k are unit vectors in the x, y, and z directions, respectively. Substitution of Eq.
7.4.4-69 and Eq. 7.4.4-70 into Eq. 7.4.4-68 gives
S x nx S y n y S z nz
cos Eq. 7.4.4-71
Sx S y Sz nx n y nz
2 2 2 2 2 2
where,
Sx = Xd2 - Xd1 Eq. 7.4.4-72
Sy = Yd2 - Yd1 Eq. 7.4.4-73
Sz = Zd2 - Zd1 Eq. 7.4.4-74
K n yY 1 Z 1
nx Eq. 7.4.4-75
X1
X2 X2
K 1 Z1 Z 2
ny X1 X1 Eq. 7.4.4-76
X2
Y2 Y1
X1
where,
X3 X2 X2 X3
Z1 Z 3 Y 2 Y 1 Z1 Z 2 Y 3 Y 1
K
X1 X1 X1 X1
Eq. 7.4.4-77
X 2 X 3 X 3 X2
1 Y 3 Y 1 1 Y 2 Y 1
X 1 X1 X 1 X1
The coordinates X1, X2, X3, Y1, Y2, Y3, Z1, Z2, Z3 are as defined in Figure [Link]-5.
7–151
TRNSYS 18 – Programmer's Guide
dT
aT b Eq. 7.4.5-1
dt
The numerical method generally requires shorter time steps and more computation for comparable
accuracy and numerical stability. Users intending to utilize the Powell’s method TRNSYS solver (SOLVER
1) should use the SolveDiffEq subroutine whenever possible.
Numerical solutions to differential equations, when required can be obtained through use of the
getNumericalDerivative(). Prior to the release of TRNSYS 17, these values were accessed through the
DTDT and T arrays in the subroutine argument list). To use a very simple example, if the equation
dT
Q i C 1 Eq. 7.4.5-2
dt
were part of the mathematical model and the DERIVATIVE of the temperature T1 with respect to time t
were to be integrated for a known heat flow rate Q and a constant value C, it would appear in the Type
subroutine in a manner similar to that shown below.
DTDT(1) is the differential dT1/dt and is registered in the kernel by the Type calling the
setNumericalDerivative function. T(1) is the result of numerically integrating DTDT(1); it is retrieved by the
Type through the call to getNumericalSolution. In this example T1 is also desired to be the second
OUTPUT. The Type stores this value through a call to the setOutputValue() routine. T(n) will always be
the result of integrating DTDT(n). The numerical differential equation solution returns the average value
over the time step, not the final value at the end of the time step.
7–152
TRNSYS 18 – Programmer's Guide
A DERIVATIVES control statement followed by an initial values line must be included among the
component control statements for any model which uses the numerical integration feature. The presence
of a DERIVATIVES command signals TRNSYS to integrate derivatives placed in the kernel’s global
DTDT array by means of a call to setNumericalDerivative() and to make results available in the global T
array (which is accessed by a Type calling getNumericalSolution()), repeating the procedure at each time
step until either the appropriate error TOLERANCE or the iteration LIMIT is reached. The initial values of
the dependent variables (i.e., T(n)) are available to the component subroutine, if needed, through the T
array at the first call of the simulation (i.e., when getIsFirstCallOfSimulation() returns a “true” result (when
INF0(7) = - 1) see Section [Link] for additional information.
7–153
TRNSYS 18 – Programmer's Guide
All user written routines written with coding standards between 14.1 and 16.x (inclusive) should contain
an asterisk (*) at the end of the subroutine designation and ‘RETURN 1’s every place a RETURN is
desired. Failure to do so will cause the unlinked subroutine error message to be displayed and the
program to terminate.
All user-written routines written with coding standards between 14.1 and 16.x (inclusive) that call other
subprograms should also include the alternate return feature to check for unlinked subprograms. To
activate the alternate return:
1) Call the subprogram with an asterisk-line number combination at the end of the
subprogram designation.
2) Specify the line number given in the step above as a CONTINUE line.
3) Between the subprogram call and the CONTINUE statement, place an error message
and a:
CALL MESSAGES(-1,’Error Message Text’,’fatal’,INFO(1),INFO(2))
command - a call may instead be placed to the LINKCK subroutine (see Section [Link]).
4) Make sure all RETURN’s in the subprogram are replaced with a RETURN 1 statement.
Refer to the example given or a FORTRAN manual for more details.
7–154
TRNSYS 18 – Programmer's Guide
With the release of TRNSYS 14, the Powell’s Method control strategy was designed to eliminate the
problems caused by the Successive Substitution TRNSYS controllers “sticking” in order to solve the
system of equations (see Manual 06-TRNEdit). With TRNSYS 14, the TRNSYS kernel, rather than the
component models, directly controlled discrete variables. When the Powell’s Method solver is selected by
the user, at the start of each time step, the values of all discrete variables are known. TRNSYS 14 (and
subsequent versions) force these values to remain at their current state until a converged solution to the
equations is obtained or an iteration limit is encountered. During these calculations, the component
models calculate the ‘desired’ value of the discrete variables but they do not actually change the settings.
After a converged solution is obtained, or the maximum number of iterations is exceeded, TRNSYS
compares the current discrete variable values with the ‘desired’ values. If they do not differ and a
converged solution has been obtained, the calculations are completed for the time step. Otherwise,
TRNSYS changes the values of the discrete variables to the ‘desired’ setting and repeats this process,
taking care to not repeat the calculations with the same set of discrete variables used previously.
To incorporate the Powell’s Method control strategy into user-written component routines, the ICNTRL
and INFO arrays must be set up correctly. The setNumberofDiscreteControls() access function should be
called to set INFO(11) to the number of discrete control variables in the component routine. The
setDesiredControlState() access function should be called so that ICNTRL(2*i) contains the desired at the
current iteration. The TRNSYS kernel takes care of setting ICNTRL(2*(i-1)+1), which contains the
previously converged solution for controller i in the component model (controlled by the TRNSYS
processor).
The ICNTRL array is an integer array and must therefore pass and receive only integer values. The
assumption in TRNSYS is that an ICNTRL value of 1 implies the control signal was enabled while an
ICNTRL value of 0 denotes a disabled control signal.
For example, a user wishes to describe an on/off controller with hysteresis effects (control signal depends
on previous control signal). The component formulation would be of the following format:
UDB = getParameterValue(1) ! UPPER DEAD BAND TEMP. DIFFERENCE
LDB = getParameterValue(2) ! LOWER DEAD BAND TEMP. DIFFERENCE
.
If (getIsFirstCallofSimulation) Then
.
setNumberofDiscreteControls(1) ! 1 CONTROL VARIABLE
.
EndIf
.
.
TH = getInputValue(1) ! UPPER INPUT TEMPERATURE
TL = getInputValue(2) ! LOWER INPUT TEMPERATURE
.
.
oldState = ICNTRL(1) ! CONTROL STATE AT PREVIOUS SOLUTION
newState = oldState
7–155
TRNSYS 18 – Programmer's Guide
If (oldState == 1) Then
If((TH-TL) < LDB) newState = 0
Else
If(TH-TL) > UDB)) newState = 1
EndIf
ICNTRL(2) = newState
.
At every iteration, the value of ICNTRL(1) holds the controller state at the previous solution while
ICNTRL(2) holds the desired controller state at this iteration. The TRNSYS processor will check to see if
ICNTRL(1) is equal to ICNTRL(2) at convergence. If the values are not equal at convergence, ICNTRL(1)
will be set to the desired controller state at convergence (ICNTRL(2)) and the process will be repeated.
IMPORTANT!! If a new component makes use of the ICNTRL array, then SOLVER 1 must be used in any
TRNSYS input file that contains that component.
7–156
TRNSYS 18 – Programmer's Guide
3) Change control algorithms to accommodate the Powell’s Method control strategy (Optional)
(see Section 7.4.7)
4) Change the XIN and OUT arrays to DOUBLE PRECISION variables. (see Section 7.3.2)
5) Change the INFO array dimension from 10 places to 15. (see Section [Link])
6) Define the input and output variable types in the YCHECK and OCHECK arrays and call the
RCHECK subroutine to perform input/output checking. (see Section [Link])
7) All calls to the following routines should be modified to include the link checking option:
DATA,ENCL,TABLE,INVERT,DINVRT,FIT,DFIT and PSYCH. (see Section [Link])
7–157
TRNSYS 18 – Programmer's Guide
2) Windows does not allow any write-to-screen statements. Any WRITE or PRINT statements that
print to the screen such as:
WRITE (*,*) ‘ There is an error in this type.’
need to be replaced with a statement that writes the text to the listing file.
WRITE(LUW,*) ‘There is an error in this type’
Note: In most cases, writing to the list file requires the inclusion of the common block that contains the
value for the logical unit. Include the following line:
COMMON /LUNITS/ LUR, LUW, IFORM, LUK
7–158
TRNSYS 18 – Programmer's Guide
conversion will depend on the way the existing Type is coded: heavy access to Kernel variables
through common blocks, use of Fortran functions specific to single precision variables, etc.
In order for your component to be found by the TRNSYS Kernel, it needs to broadcast its name. This is
done by adding the following syntax to the component just underneath the subroutine line at the top of the
file.
!DEC$ATTRIBUTES DLLEXPORT :: TYPEnnn
Where nnn is the Type number. Thus Type205 would have the following line added:
!DEC$ATTRIBUTES DLLEXPORT :: TYPE205
It is important that the syntax begin in the leftmost column. In other words, do not put any tabs or
spaces to the left of the first exclamation point. As far as the Fortran compiler itself is concerned, the line
that has just been added is a comment. However, the pre-processor recognizes the syntax and includes
the Type in a file called an export library. Essentially this means that the subroutine will be accessible by
other subroutines not contained within the same DLL.
Note: The line here above is required due to the new calling mechanism in TRNSYS 16, even though
TRNSYS 15 Types have to be linked to the main DLL. The "DLLEXPORT" directive is required but it does
not mean your Type will be usable in an external DLL.
A number of structural changes have been made to TRNSYS components. Types in TRNSYS 16 are
called in a different manner and with new INFO array codes, allowing them much more flexibility in when
and how they perform their calculations. Many of these changes are not compatible with Types written for
TRNSYS 15 or earlier so to avoid forcing users to completely rewrite all their components, TRNSYS 16
contains two parallel calling structures, one for new TRNSYS 16 components, and one for legacy
components. In order for TRNSYS to determine the manner in which it should call a component, each
component must be "signed" with a version number for which it was written. To sign your component, you
need to add the following syntax to it, at the top of the executable section (just below the variable
declarations)
! Set the version information for TRNSYS
if (INFO(7) == -2) then
INFO(12) = 15
return 1
endif
By adding the above, you have signaled to TRNSYS that your component was written using the TRNSYS
15 calling structure. TRNSYS will treat it accordingly. There should be no further changes that you need
to make to your Type in order for it to run under version 16.
7–159
TRNSYS 18 – Programmer's Guide
Additional considerations
If your Type refers to "[Link]", the include file that declares global TRNSYS 15 constants, you need to
update the path to that file. [Link] is now located in %TRNSYS17%\SourceCode\Include
(%TRNSYS17% is your installation directory). Note that [Link] is obsolete and that TRNSYS 16 (and
more recent) Types should use the global constants declared in the TrnsysConstants module (see
section 0 for details).
See section 0 here above for details. You need to add the following syntax to the component just
underneath the subroutine line at the top of the file.
!DEC$ATTRIBUTES DLLEXPORT :: TYPEnnn
Where nnn is the Type number. Thus Type205 would have the following line added:
!DEC$ATTRIBUTES DLLEXPORT :: TYPE205
It is important that the syntax begin in the leftmost column. In other words, do not put any tabs or
spaces to the left of the first exclamation point.
Note that detailed explanations of the INFO array and a full example of a typical calling sequence for an
iterative call are provided in section [Link]. The following sections just outline the changes to existing
TRNSYS 15 Types.
See section 0, here above, for details. To sign your component, you need to add the following syntax to it,
at the top of the executable section (just below the variable declarations):
! Set the version information for TRNSYS
if (INFO(7) == -2) then
INFO(12) = 16
return 1
endif
By adding the above, you have signaled to TRNSYS that your component was written using the TRNSYS
16 standard.
7–160
TRNSYS 18 – Programmer's Guide
The INFO(7) = -1 call is still intended to allow components to perform initializations, as in TRNSYS 15.
However, due to the new specification of TIME in TRNSYS, the manipulations required at INFO(7) = -1
have changed. The manipulations that your component should do at INFO(7) = -1 are the following:
Set INFO(6) to the number of output spots needed by the component.
Set INFO(9) so that your Type will be called in the proper manner (see section [Link] for details).
Handle data storage initialization:
Set INFO(10) to the number of storage spots required in the single precision storage structure (in
other words, use the S array).
Call SetStorageSize to reserve space in the double precision storage structure. See section 0
for more information.
Call TYPECK to have TRNSYS check whether the correct number of Inputs, Outputs and
Parameters were specified in the deck.
Call RCHECK to have TRNSYS check the units of the Input Output connections in the deck.
RETURN 1: no other manipulations should be made during this call.
Note that reading parameters and process them can be realized either during this call or during the initial
time step (see "TIME = TIME0 call" here below). You should be careful to handle all operations that
must be done only once (e.g. file opening) in only one of those initial calls.
In TRNSYS 16, the time specified in the simulation cards ("Simulation Start Time" in the Simulation
Studio) became the exact moment at which the simulation starts. This is different from TRNSYS 15,
where the so-called simulation start was the time at the end of the first time step. In TRNSYS 16,
components are called at TIME = TIME0 and they should just output their initial values at that call. There
are no iterations for that time step.
All components that are signed as having been written for version 16 are called once more at the end of
every time step after convergence has been reached. This modification was made in order to simplify the
use of storage (the TRNSYS 15 S array) and other operations that must be done after convergence has
been reached, such as printing or integration. If your component does not use storage and is not a printer
or an integrator, then you may simply add the lines:
! Perform post-convergence operations
if(INFO(13) > 0) then
return 1
endif
7–161
TRNSYS 18 – Programmer's Guide
If your component does use storage, then you should add lines that set up your local storage array, and
then send the values to global storage using a call to the setStorageVars subroutine as explained in
section 0.
This call has not changed between TRNSYS 15 and 16. At the very end of a TRNSYS simulation, each
Type is called one last time with INFO(8) = -1. If your Type does not contain any handling of INFO(8) = -1,
it will simply run through its calculations one last time and probably no harm will come of it. However, it is
a good idea to specifically handle INFO(8). You can add the following lines if your component does not
have to do anything:
! Perform last call manipulations
if(INFO(8) == -1) then
return 1
endif
You may want your components to actually do something at the end of the simulation. They could, for
instances print a message to the list file or close logical units that were used during the simulation.
Standard component Type 22 (Iterative Feedback controller) performs end of the simulation
manipulations that you might use as an example.
The INFO(8)=-1 call also occurs if the simulation terminates with a fatal error. In that case, the component
that generates the error returns control to TRNSYS, which calls all components one last time in order to
perform their "end of simulation" operations. You can check if the very last call occurs because of an error
or as part of the normal simulation process by calling getNumberOfErrors(). Some end of simulation
operations are unnecessary or might crash TRNSYS if the simulation ends with a fatal error. E.g. Type 22
handles INFO(8)=1 as follows:
if (info(8) == -1) then
! Exit immediately if this call is the result of a fatal error
if (getNumberOfErrors() > 0) then
return 1
! Otherwise, print the nb of "stuck" timesteps
else
...
printing manipulations
...
endif
return 1 ! Exit
endif
Notes:
If the simulation ends without errors, the INFO(8) = -1 call happens after the user has allowed the
simulation to terminate by clicking on the "yes" or "continue" button at the end of the simulation
The lines of code here above should be placed before the normal instructions so the return occurs
before those instructions are executed.
One of the other focuses of version 16 developments was to move away from single precision variables
toward double precision variables. Four of the arguments sent to each Type are now double precision
(TIME, PAR, T, and DTDT). Previously only XIN and OUT were double precision. You will need to go
through and declare TIME, PAR, T and DTDT as double precision instead of real. It is also recommended
that you do this for all your variables. If you prefer to keep your variables single precision, it is important
that you help Fortran make the conversion correctly. The following incorrect code will not be caught by
the Fortran compiler and may result in incorrect answers:
7–162
TRNSYS 18 – Programmer's Guide
RealVariable = DoublePrecisionVariable
The correct way of performing the above is the following:
RealVariable = sngl(DoublePrecisionVariable)
To go the other way, you need the following:
DoublePrecisionVariable = dble(RealVariable)
TRNSYS 16 Types should access global constants through the "TrnsysConstants" data module. The
available constants are described in section 7.4.1. Many new constants have been added in order to
promote consistency in TRNSYS (e.g. by making sure strings are sized in a consistent way), and the
existing constants previously found in the "[Link]" file have been transferred into the new data
module. Note that "[Link]" is still included in the TRNSYS distribution for backwards compatibility, but
it should not be used by TRNSYS 16 Types. To use the "TrnsysConstants" module in a Type, add the
following line at the top of the declaration section (i.e. just below the !DEC$ATTRIBUTES instruction):
use TrnsysConstants
This will declare all the constants in the module in your Type. Alternatively, if you only want to use the
constant defining the maximum length of a Label string (maxLabelLength), you can use the following
syntax:
use TrnsysConstants, only: maxLabelLength
This will only declare the constant(s) listed after the "only" keyword. You can list several constants in one
"only:" instruction by using a comma-separated list.
A note on strings
Fortran 77/90/95 do not provide variable-length strings, so each individual string variable must be sized
according to its expected maximum length. This can cause problems when different parts of the code
expect different maximum lengths for the same string. If your Type manipulates strings, we strongly
recommend that you check section 7.4.1 to see if a suitable constant is already available for the size of
your string, rather than using a new constant or a hard-coded value.
It is also recommended to use the generic "a" format when printing strings, rather than "ann" where nn is
the length of the string. Where an old print instructions for a variable descriptor (column title in a printer)
might say:
character*10 myString
myString = 'Hello world'
write(*,1000) myString
1000 format(a20)
The recommended way is now:
use TrnsysConstants ! defines integer, parameter ::maxDescripLength
character (len=maxDescripLength) :: myString
myString = 'Hello world'
write(*,'(a)') trim(myString)
Note that the generic "a" format does not work for character arrays (which are not exactly the same as
strings). In that case it is necessary to adjust the format instruction with a variable, e.g.:
use TrnsysConstants ! defines integer, parameter ::maxDescripLength
character (len=100) :: myFormatString
character :: myString(maxDescripLength) ! myString is a character array,
not a string
write(myFormatString,'(i)') maxDescripLength
7–163
TRNSYS 18 – Programmer's Guide
TRNSYS 16 Types should access global (Kernel) variables through access functions only. Access
functions allow Types to use Kernel variables in a much safer way than the Common Blocks that were
used in TRNSYS 15. Common Blocks are inherently dangerous because they do not ensure name nor
even type consistency for Kernel variables among the Types. There is also no way of preventing a Type
from changing the simulation stop time, or even the current simulation time, with Common Blocks.
The principle of Access Functions is to provide functions that allow access to Kernel variables in the way
they are intended to be used. For example, a function is provided to "Get" the simulation time step, but no
function is provided to change it.
First, the module with all the function declarations must be Used in the Type:
use TrnsysFunctions
That line should be inserted with the other "Use" instructions at the top of the declaration section. Here
again, it is possible to add "only:" instructions if only some of the functions are needed and if name
conflicts may occur (it is strongly discouraged to re-use TRNSYS function names in Types)
Then, when a Kernel variable is needed, it can be accessed with the corresponding function. For
example, the simulation time step (DELT variable in the Kernel) is accessed through the
"getSimulationTimeStep()" function. Let's say a Type is integrating a value x over time, the result being
put in "integral".
subroutine Type205(TIME,XIN,OUT,T,DTDT,PAR,INFO,ICNTRL,*)
common/SIM/TIME0,TFINAL,DELT,IWARN
real TIME0,TFINAL,DELT
integer IWARN
TRNSYS 15 …
real x,s
…
s = s+x*DELT
subroutine Type205(TIME,XIN,OUT,T,DTDT,PAR,INFO,ICNTRL,*)
use TrnsysFunctions
7–164
TRNSYS 18 – Programmer's Guide
The TRNSYS 15 Common Blocks are still present in TRNSYS 16 in order to allow existing Types to run in
"legacy mode". However, they are not exported from the main DLL ([Link]). If you do not replace
Common Blocks with the use of Access Functions, you will not be able to use your Type in an external
DLL.
One of the most unintuitive utilities in TRNSYS 15 was storage using the S array. The underlying idea of
storage is that sometimes you want your calculations not to be based upon the value of a variable at the
last iteration but the value of that variable at the end of the last time step. To use the S array, one would
bring it in as part of a COMMON block and declare how many places were needed by setting INFO(10) to
that number. Then every time a stored variable was needed, the user would get a pointer into the S array
by setting INFO(10) to a local integer variable (such as ISTORE), then would start pulling out the stored
values by referencing them as S(ISTORE), S(ISTORE+1) etc. At the end of a time step, the user would
do the reverse, again getting a pointer into the S array, then setting its values to the correct local
variables.
The problem was that Types did not know when it was the end of a time step, only that a new time step
had begun. Consequently, users had to notice that a new time step had started, then update their S array
with the most recent values (from the end of the last time step).In addition, there was no check that a
given Unit was not writing values in parts of the S array that had been allocated to a different Unit.
In TRNSYS 16, the S array still exists in the COMMON block /STORE/ for legacy components. However,
three new utility subroutines were created, allowing for a hopefully more intuitive approach to variable
storage. The functions are described in details in section [Link].
At the initialization call (INFO(7) = -1), the Type should call SetStorageSize to allocate storage for
the current Unit.
When the user wants to set storage at the end of a time step, a call is made to the setStorageVars
subroutine when INFO(13) = 1
When the user wants to obtain a previously stored value, a call is made to the getStorageVars
subroutine. This usually occurs during the first call of a new time step, identified by INFO(7) = 0.
One of the enhancements in TRNSYS 16 is the introduction of a Messages subroutine that handles all
notices and error messages that component print to the listing and log files. This makes it easier to parse
a listing or log file for errors and it ensures a consistent handling of messages by the Simulation Studio's
"Error Manager".
Where Type previously wrote error messages to the listing file (accessed throught the logical unit LUW in
the LUNITS Common Block), they should now call the Messages subroutine:
call Messages(errorCode,message,severity,unitNo,typeNo)
7–165
TRNSYS 18 – Programmer's Guide
errorCode is a standard TRNSYS error number (if available), message is the string that has to be printed,
severity indicates the severity of the message (e.g. warning or error) and UnitNo and TypeNo indicate the
calling unit and Type numbers.
Please refer to section [Link] for more information on the Messages subroutine.
One of the focuses of version 16 development was to move away from single precision variables toward
double precision variables. As a consequence, it is important to correctly handle the arguments to utility
subroutines (such as PSYCH) that your components may be calling. In TRNSYS 15, the call to PSYCH
was:
call PSYCH(TIME,INFO,IUNITS,MODE,WBMODE,PSYDAT,0,STATUS,N)
The arguments TIME and PSYDAT were both declared as real (single precision). In TRNSYS 16, both
TIME and PSYDAT should be declared in components as double precision and the call should be made
to the double precision version of PSYCH, which is called Psychrometrics. Thus the syntax would be:
call Psychrometrics(TIME,INFO,IUNITS,MODE,WBMODE,PSYDAT,0,STATUS,N)
The single precision PSYCH subroutine still exists in TRNSYS 16 but it is merely a shell that correctly
converts single precision arguments to double precision, calls Psychrometrics, and reconverts the results
from double precision back to single precision. Table [Link]-1 shows the TRNSYS 15 utility subroutine
names in column 1, the corresponding TRNSYS 16 utility subroutine name in column 2 and the
arguments that must be converted from single to double precision in column 3.
Table [Link]-1: TRNSYS 15 (single precision) and TRNSYS 16 (double precision) utility routines
7–166
TRNSYS 18 – Programmer's Guide
Since fewer and fewer users have experience in writing programs in FORTRAN, one of the main focuses
of TRNSYS 17 development was the simplification of the interaction between the TRNSYS kernel and the
TRNSYS types. For example, where a user was previously required to identify a bad PARAMETER value
by using the following call to the TYPECK subroutine:
IF (NODES_F.LT.1) CALL TYPECK(-4,INFO,0,19,0)
The code “-4” that told TYPECK what action to take is replaced by a more intuitive subroutine name, the
TYPECK routine goes and gets the information that it needs from the “INFO” array by itself, two of the
three index arguments are gone; only the index number of the bad PARAMETER remains (in this case, it
is PARAMETER 19 that has been identified as having a bad value). TYPECK’s generic and somewhat
cryptic message saying simply that PARAMETER 19 has a bad value is replaced by a more specific
message and the user is able to decide whether this bad parameter value should be a ‘warning’ to the
user or whether it should result in a ‘fatal’ error and stop the simulation.
The following sections go over the recommended modifications to update a TRNSYS 16 component to
the TRNSYS 17 coding standard.
to
Subroutine TYPEnnn
7–167
TRNSYS 18 – Programmer's Guide
currentUnit = getCurrentUnit()
currentType = getCurrentType()
to
!Set the Version Number for This Type
If (getIsVersionSigningTime()) Then
Call setTypeVersion(17)
Return
EndIf
Note that the “RETURN 1” statement is replaced by a simple “RETURN.” Use of the “alternate return” was
abandoned with TRNSYS 17. Refer to section 7.4.6 for additional information concerning alternate return
statements in FORTRAN.
to
! Do All of the “Last Call” Manipulations Here
If (getIsLastCallofSimulation()) Then
...
Return
EndIf
The ellipsis (…) is used to indicate that any actual manipulations performed by the component should
stay the same between the TRNSYS 16 and 17 coding standards.
NOTE that the “Return 1” statement in the TRNSYS 16 coding standard is replaced by a simple “Return”
in the TRNSYS 17 coding standard.
7–168
TRNSYS 18 – Programmer's Guide
...
RETURN 1
ENDIF
to
! Perform Any "End of Timestep" Manipulations That May Be Required
If (getIsEndOfTimestep()) Then
...
Return
EndIf
Again, the ellipsis (…) is used to indicate that any actual manipulations performed by the component
should stay the same between the two coding standards.
As with the other TRNSYS coding standard updates discussed in this section, the manipulations that are
made in the TRNSYS 17 coding standard are unchanged. The modifications are all in how the
manipulations are made.
The first step, of course, is to check whether or not the current call is the “first call.” In the TRNSYS
16 coding standard, this was accomplished by checking whether the value of the 7 th INFO() array
spot was equal to -1. In the TRNSYS 17 standard, an access function is provided:
IF (INFO(7).EQ.-1) THEN
TRNSYS 16 coding standard: ...
ENDIF
If (getIsFirstCallofSimulation()) Then
TRNSYS 17 coding standard: ...
EndIf
The IUNIT and ITYPE variables are no longer needed. They were replaced by a global simulation
variable call (see section [Link]).
IUNIT=INFO(1)
TRNSYS 16 coding standard: ITYPE=INFO(2)
7–169
TRNSYS 18 – Programmer's Guide
Reserving space in the OUT() array using the 6th spot in the INFO array becomes a call to an
access function. Note the “5” in the following example should be replaced by the actual number of
outputs for the Type in question.
TRNSYS 16 INFO(6)= 5
coding standard:
Setting the Type’s place in the global Type-calling structure changes from setting the 9th spot of the
INFO() array to a call to an access function. Note that “1” in the following example denotes that the
Type should be called along with others until convergence is reached. Refer to section [Link] for
information on other possible argument values to the setIterationMode() subroutine.
TRNSYS 16 INFO(9)= 1
coding standard:
Setting up data storage is the one spot where there is not a one-to-one correspondence between
calling a subroutine in the TRNSYS 16 standard and calling an access function in the TRNSYS 17
standard. The TRNSYS 16 standard offered a “one size fits all” solution to data storage between
time steps; components reserved space, placed, and removed whatever variables they wanted in
storage at whatever time was appropriate to their purposes. TRNSYS 17 offers two data storage
options (called “static” and “dynamic”). Refer to section [Link] for additional information. In
converting a TRNSYS 16 type to TRNSYS 17, set the number of items that you were storing (nItems
in the example below) as the second argument in the setNumberStoredVariables() subroutine call.
A call to the TYPECK() subroutine in the TRNSYS 16 coding standard was used for various
purposes; the action that TYPECK() took was determined by the first argument (the “IOPT mode” –
see section [Link] for additional details). In the TRNSYS 17 coding standard, each mode is
replaced by one or more specific task subroutine calls. Typically the first call to TYPECK() was used
to check that the user specified the correct number of inputs, parameters, and derivatives in the input
file. This was accomplished by calling TYPECK() with an IOPT mode of 1. In the TRNSYS 17 coding
standard, the call to TYPECK is replaced by calls to three subroutines as shown below. Note that in
the example below, nI denotes the number of INPUTS specified/expected, nP denotes the number of
PARAMETERS and nD denotes the number of DERIVATIVES.
7–170
TRNSYS 18 – Programmer's Guide
The RCHECK() subroutine was used in the TRNSYS 16 coding standard to check and make sure
whether the user had connected only INPUTS and OUTPUTS whose units match. For example to
make sure that temperature outputs in °C are connected to inputs in °C. The recommended
methodology was to set up two arrays (YCHECK and OCHECK) each containing a three letter code
designating the units of each input and output employed by the Type. For example, if a Type has
three inputs: temperature in [°C], mass flow rate in [kg/h], and pressure in [atm] then the
corresponding three-letter codes placed in the YCHECK() array would be ‘TE1’ (for °C), ‘MF1’ (for
kg/h) and ‘PR1’ (for atm). Once the YCHECK() and OCHECK() arrays had been set up, the user
called the RCHECK subroutine.
The recommended methodology in the TRNSYS 17 coding standard is to call the setInputUnits() and
setOutputUnits() subroutines, sending the three letter code for a particular input or output each time.
In the following example, the Type has 5 inputs and 4 outputs.
DATA YCHECK/'TE1','MF1','CF1','TE1','TE1'/
TRNSYS 16 DATA OCHECK/'TE1','MF1','PW1','PW1'/
coding standard: CALL RCHECK(INFO,YCHECK,OCHECK)
Call SetInputUnits(1,'TE1')
Call SetInputUnits(2,'MF1')
Call SetInputUnits(3,'CF1')
Call SetInputUnits(4,'TE1')
TRNSYS 17 Call SetInputUnits(5,'TE1')
coding standard:
Call SetOutputUnits(1,'TE1')
Call SetOutputUnits(2,'MF1')
Call SetOutputUnits(3,'PW1')
Call SetOutputUnits(4,'PW1')
Certain Types require calls to additional access functions and utility routines during the “first call.”
For example, Types employing the numerical differential equation solver should also set the
expected number of derivatives. The present discussion is limited to the manipulations that all
components must make. Refer to the relevant sections of this manual for additional information on
“first call” manipulations required by specific kernel features.
The “RETURN 1” statement is replaced by a simple “RETURN”
TRNSYS 16 RETURN 1
coding standard:
TRNSYS 17 Return
coding standard:
7–171
TRNSYS 18 – Programmer's Guide
If (getIsStartTime()) Then
TRNSYS 17 coding standard: ...
Return
EndIf
The IUNIT and ITYPE variables are no longer needed. They were replaced by a global simulation
variable call (see section [Link]).
TRNSYS 16 IUNIT=INFO(1)
coding standard: ITYPE=INFO(2)
Next, the Type reads its parameters and stores them as local variables. In the following example, the
Type has 4 parameters:
QMAX = PAR(1)
TRNSYS 16 CP = PAR(2)
coding standard: UA = PAR(3)
HTREFF = PAR(4)
qmax = getParameterValue(1)
TRNSYS 17 cp = getParameterValue(2)
coding standard: ua = getParameterValue(3)
htreff = getParameterValue(4)
After reading the parameters, the TRNSYS 16 Type checks their values using another call to
TYPECK(), this time with an IOPT mode of -4. By contrast, the TRNSYS 17 Type calls an access
function with a more specific message:
!Check the parameters for problems
IF([Link].0.) CALL TYPECK(-4,INFO,0,1,0)
TRNSYS 16 IF([Link].0.) CALL TYPECK(-4,INFO,0,2,0)
coding standard: IF([Link].0.) CALL TYPECK(-4,INFO,0,3,0)
IF(([Link].1.).OR.([Link].0.)) CALL TYPECK(-4,INFO,0,4,0)
IF(ErrorFound() ) RETURN 1
!Check the parameters for problems
If (qmax < 0.) Call foundBadParameter(1,'Fatal', &
'The heater capacity must be positive.')
If (cp < 0.) Call foundBadParameter(2,'Fatal', &
TRNSYS 17 'The fluid specific heat must be positive.')
coding standard: If (ua < 0.) Call foundBadParameter(3,'Fatal', &
'The heater UA must be positive.')
If ((htreff < 0.).or.(htreff > 1.)) Call foundBadParameter(4, &
'Fatal','The heater efficiency must be between 0 and 1.')
If (ErrorFound() ) Return
The final task for the “initial time” call is for the Type to set output initial values. In the TRNSYS 16
coding standard, a Type did so by setting values of the OUT() array. The TRNSYS 17 coding
standard Type calls an access function instead:
! Set the Initial Values of the Outputs
OUT(1) = XIN(1) !outlet temperature = inlet temperature [C]
OUT(2) = XIN(2) !mass flowrate out = mass flowrate in [kg/hr]
TRNSYS 16 OUT(3) = 0. !required heating rate [kJ/hr]
coding standard: OUT(4) = 0. !rate of losses to environment [kJ/hr]
OUT(5) = 0. !rate of energy delivered to stream [kJ/hr]
!the first timestep is for initialization - exit
RETURN 1
7–172
TRNSYS 18 – Programmer's Guide
7–173
TRNSYS 18 – Programmer's Guide
7–174
TRNSYS 18 – Programmer's Guide
If you have the Intel compiler and its interface (MS Visual Studio), go to the directory
%TRNSYS18%\Compilers\TRNSYS\. This directory contains a solution file for the Intel Visual FORTRAN
(IVF) compiler and its interface with the appropriate settings. You do not have to modify any setting to
recompile and debug TRNSYS if you use the project included in the distribution.
You can use the IVF solution file to make modifications to the standard components and kernel
subroutines, or to add you own components to the main library [Link].
You may also use the IVF solution file to build your own components into an individual dll. In this case,
use the project ‘MyType’ and add the source code for your own components.
You may also use the IVF solution file to build your own components into an individual dll. In this case,
use the project ‘MyType’ and add the source code for your own components.
7–175
TRNSYS 18 – Programmer's Guide
7–176
TRNSYS 18 – Programmer's Guide
In the window ‘TRNDll64 Property Pages’, go to the pull down menu ‘Configuration’; select "All
Configurations". We will now choose the settings that are common to the Debug and Release
configurations.
There are numerous settings here controlled by a tree structure on the left. Below are the important
settings for each of these tabs. Each tree branch can have several "Categories", so there are many
settings involved. Only the settings that must be changed from their default values are mentioned.
7–177
TRNSYS 18 – Programmer's Guide
7–178
TRNSYS 18 – Programmer's Guide
Notes:
The post-build step makes sure that the required files are copied to the Exe folder without adding
unnecessary compiler files to that folder and making sure a copy of those files stays in the Debug or
Release directory
Note: You need to do a Rebuild before compiling any file that uses TRNSYS data modules. If you try to
compile a routine using the data modules before performing a "Rebuild" you will get a message saying
"error in opening module file" and the compilation will fail. The "Rebuild" operation compiles the modules
and creates the module files (.mod) before compiling the files that require them.
7–179
TRNSYS 18 – Programmer's Guide
Note: The instructions here below are given for reference only and for users who want to
control more advanced options. Please refer to the "Getting Started" TRNSYS Manual
and to the TRNSYS Studio manual for more information on the "Export as Fortran"
command.
In Intel Visual Fortran, a project is set of files and settings that are used to build an application (.exe or
.dll). A Solution is a container for multiple projects. The solution itself can be built, which builds all of the
contained projects in a specified order (which can be adjusted by the user).
7–180
TRNSYS 18 – Programmer's Guide
In the "configuration" drop-down list box showing "Active (Debug)", select "All configurations". We will now
choose the settings that are common to the Debug and Release configurations. There are numerous
settings here controlled by a tree structure on the left. Below are the important settings for each of these
tabs. Each tree branch can have several "Categories", so there are many settings involved. Only the
settings that must be changed from their default values are mentioned.
Table [Link]-1: New Dll Settings – IVF Composer XE, All Configurations
Table [Link]-2: New Dll Settings – IVF Composer XE, Win64 Debug
7–181
TRNSYS 18 – Programmer's Guide
The post-build step makes sure the required files are copied to the UserLib folder without adding
unnecessary compiler files to that folder and making sure a copy of those files stays in the Debug or
Release directory
These instructions will create a DLL of your files, and will place a copy of the ‘[Link]’ into the directory
%TRNSYS18%\UserLib\ReleaseDLLs or %TRNSYS18%\UserLib\DebugDLLs. You may want to rename
the file ‘[Link]’ for another meaningful name, such as ‘[Link]’ but bear in mind that there is no
reason why you cannot add many Types into the same DLL.
7–182
TRNSYS 18 – Programmer's Guide
Where nn refers to the Type number. Please refer to section 7.3.2 for guidance in
selecting the number for the Type.
if (getIsFirstCallofSimulation()) {}
7–183
TRNSYS 18 – Programmer's Guide
7–184
TRNSYS 18 – Programmer's Guide
7.8. References
Engineering Equation Solver, F-Chart Software, 4406 Fox Bluff Road, Middleton WI, 1994.
[Link]
ASHRAE. 2001. Handbook of Fundamentals. American Society of Heating Refrigeration, and Air
Conditioning Engineers, Atlanta, Ga.
7–185