0% found this document useful (0 votes)
58 views185 pages

TRNSYS 18 Programmer's Guide

The TRNSYS 18 Programmer's Guide serves as a reference for users interested in creating their own components or understanding the TRNSYS 18 simulation engine. It includes detailed information on programming, type structure, and access functions, along with a revision history and contributor acknowledgments. Additional resources and support can be found on the TRNSYS website and through the TRNSYS coordinator.

Uploaded by

Gordon Sumner
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
58 views185 pages

TRNSYS 18 Programmer's Guide

The TRNSYS 18 Programmer's Guide serves as a reference for users interested in creating their own components or understanding the TRNSYS 18 simulation engine. It includes detailed information on programming, type structure, and access functions, along with a revision history and contributor acknowledgments. Additional resources and support can be found on the TRNSYS website and through the TRNSYS coordinator.

Uploaded by

Gordon Sumner
Copyright
© All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd

TRNSYS 18

a TRaNsient SYstem Simulation program

Volume 7

Programmer's Guide

Solar Energy Laboratory, Univ. of Wisconsin-Madison


[Link]

TRANSSOLAR Energietechnik GmbH


[Link]

CSTB – Centre Scientifique et Technique du Bâtiment


[Link]

TESS – Thermal Energy Systems Specialists


[Link]
TRNSYS 18 – Programmer's Guide

About This Manual


The information presented in this manual is intended to provide a reference to users who want to create
their own TRNSYS 18 components or want to understand the TRNSYS 18 simulation engine. This
manual is not intended to provide information about other utility programs in TRNSYS 18. More
information concerning these programs can be found in other parts of the TRNSYS documentation set.
The latest version of this manual is always available for registered users on the TRNSYS website (see
here below).

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

Where to find more information


Further information about the program and its availability can be obtained from the TRNSYS website or
from the TRNSYS coordinator at the Solar Energy Lab:

TRNSYS Coordinator Email: TechSupport@[Link]


Thermal Energy System Specialists, LLC
22 North Carroll Street – suite 370
Madison, WI 53703 – U.S.A.

TRNSYS website: [Link]

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

S.A. Klein W.A. Beckman J.W. Mitchell

J.A. Duffie N.A. Duffie T.L. Freeman

J.C. Mitchell J.E. Braun B.L. Evans

J.P. Kummer R.E. Urban A. Fiksel

J.W. Thornton N.J. Blair P.M. Williams

D.E. Bradley T.P. McDowell M. Kummert

D.A. Arias M.J. Duffy J. Dyerby

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

[Link]. Perform Calculations 7–29


[Link]. Set Storage Values 7–30
[Link]. Set Outputs 7–30
[Link]. Return Control 7–30
7.3.15. Complete Code 7–32
7.3.16. Implementing Data Storage between Time Steps 7–35
7.3.17. Implementing Automatic Simulation Summary Reporting 7–35
[Link]. Reserving Space in the SSR 7–36
[Link]. Initializing SSR Variables 7–36
[Link]. Updating SSR Variables 7–37
7.3.18. Including your new component in an external DLL 7–38
7.4. Programming Reference 7–39
7.4.1. Global constants 7–39
[Link]. Constants settings limits on TRNSYS simulations 7–39
[Link]. Constants used for string length 7–40
7.4.2. Access functions 7–41
[Link]. function CheckStability( ) 7–41
[Link]. function closeFileIVF(lu) 7–41
[Link]. function ErrorFound( ) 7–41
[Link]. function getConnectedOutputNumber(i,j) 7–42
[Link]. function getConnectedOutputNumberS1(i,j) 7–42
[Link]. function getConnectedTypeNumber(i,j) 7–42
[Link]. function getConnectedTypeNumberS1(i,j) 7–43
[Link]. function getConnectedUnitNumber(i,j) 7–43
[Link]. function getConnectedUnitNumberS1(i,j) 7–43
[Link]. function getConnectedVariableType(i,j) 7–43
[Link]. function getConnectedVariableTypeS1(i,j) 7–44
[Link]. function getConnectedVariableUnit(i,j) 7–44
[Link]. function getConnectedVariableUnitS1(i,j) 7–44
[Link]. function getConvergenceTolerance( ) 7–45
[Link]. function getCurrentType() 7–45
[Link]. function getCurrentUnit() 7–45
[Link]. function getDeckFileName( ) 7–45
[Link]. function getDynamicArrayValueLastTimestep(j) 7–45
[Link]. function getExtFilePath(unitNum,fileNum,extFilePath) 7–46
[Link]. function getFormat(i,j ) 7–46
[Link]. function getInputValue(i) 7–46
[Link]. function getIsConvergenceReached( ) 7–46

7–5
TRNSYS 18 – Programmer's Guide

[Link]. function getCosimConvergenceCheckingTime( ) 7–47


[Link]. function getIsEndOfTimestep() 7–47
[Link]. function getIsFirstCallofSimulation( ) 7–47
[Link]. function getIsDemo( ) 7–48
[Link]. function getIsFirstTimestep( ) 7–48
[Link]. function getIsIncludedInSSR( ) 7–48
[Link]. function getIsLastCallofSimulation() 7–48
[Link]. function getIsReReadParameters() 7–49
[Link]. function getIsStartTime () 7–49
[Link]. function getIsTRNSED( ) 7–49
[Link]. function getIsVersionSigningTime() 7–50
[Link]. function getLabel(i,j) 7–50
[Link]. function getListingFileLogicalUnit( ) 7–50
[Link]. function getLUFileName (i) 7–50
[Link]. function getLUFileName_Cpp(i, LUfilePath ) 7–51
[Link]. function getMaxDescripLength( ) 7–51
[Link]. function getmaxFileWidth( ) 7–51
[Link]. function getMaxLabelLength( ) 7–52
[Link]. function getMaxPathLength( ) 7–52
[Link]. function getMinimumTimestep( ) 7–52
[Link]. function getMinorVersionNumber( ) 7–52
[Link]. function getNextAvailableLogicalUnit( ) 7–53
[Link]. function getNFiles(unitNum) 7–53
[Link]. function getnMaxIterations( ) 7–53
[Link]. function getnMaxStorageSpots( ) 7–53
[Link]. function getnMaxWarnings( ) 7–54
[Link]. function getnTimeSteps( ) 7–54
[Link]. function getNumberOfDerivatives( ) 7–54
[Link]. function getNumberOfErrors( ) 7–54
[Link]. function getNumberOfInputs() 7–55
[Link]. function getNumberOfLabels( ) 7–55
[Link]. function getNumberOfOutputs() 7–55
[Link]. function getNumberOfParameters() 7–55
[Link]. function getNumberOfWarnings( ) 7–56
[Link]. function getNumericalDerivative(i) 7–56
[Link]. function getNumericalSolution(i) 7–56
[Link]. function getNumericalSolver( ) 7–56

7–6
TRNSYS 18 – Programmer's Guide

[Link]. function getOutputValue(i) 7–57


[Link]. function getOverallIteration( ) 7–57
[Link]. function getParameterValue(i) 7–57
[Link]. function getPreviousControlState(i) 7–57
[Link]. function getSimulationStartTime( ) 7–58
[Link]. function getSimulationStartTimeV15( ) 7–58
[Link]. function getSimulationStopTime( ) 7–58
[Link]. function getSimulationTime( ) 7–58
[Link]. function getSimulationTimeStep( ) 7–58
[Link]. function getStaticArrayValue(j) 7–59
[Link]. function getTimeReport() 7–59
[Link]. function getTimestepIteration() 7–59
[Link]. function getTimeStepNumber( ) 7–59
[Link]. function getTrnsysDebugLibDir( ) 7–60
[Link]. function getTrnsysExeDir( ) 7–60
[Link]. function getTrnsysInputFileDir( ) 7–60
[Link]. function getTrnsysReleaseLibDir( ) 7–60
[Link]. function getTrnsysRootDir( ) 7–61
[Link]. function getTrnsysUserLibDir( ) 7–61
[Link]. function getTypeVariant( ) 7–61
[Link]. function getTypeVersion() 7–61
[Link]. function getVariableDescription(i,j) 7–62
[Link]. function getVariableUnit(i,j) 7–62
[Link]. function getVersionNumber( ) 7–62
[Link]. function LogicalUnitIsOpen( ) 7–62
[Link]. function readNextChar( ) 7–63
[Link]. subroutine addExternalFile(LUN, FileName) 7–63
[Link]. subroutine foundBadInput(i,severity,message) 7–63
[Link]. subroutine foundBadParameter(i,severity,message ) 7–64
[Link]. subroutine initReportIntegral(indx,descrip,units) 7–64
[Link]. subroutine initReportMinMax(indx,descrip,units) 7–65
[Link]. subroutine initReportText(indx,descrip,value) 7–65
[Link]. subroutine initReportValue(indx,descrip,value,units) 7–65
[Link]. subroutine setDesiredDiscreteControlState(I,j) 7–66
[Link]. subroutine setInputUnits(i,string) 7–66
[Link]. subroutine setIterationMode(i) 7–67
[Link]. subroutine setNumberofDerivatives(i) 7–67

7–7
TRNSYS 18 – Programmer's Guide

[Link]. subroutine setNumberofDiscreteControls(i) 7–67


[Link]. subroutine setNumberofInputs(i) 7–67
[Link]. subroutine setNumberofOutputs(i) 7–68
[Link]. subroutine setNumberofParameters(i) 7–68
[Link]. subroutine setNumberOfReportVariables(:,:,:,:) 7–68
[Link]. subroutine setNumericalDerivative(i,derVal) 7–69
[Link]. subroutine setOutputUnits(i,String) 7–69
[Link]. subroutine setOutputValue(i,Value) 7–69
[Link]. subroutine setTypeVersion(i) 7–70
[Link]. subroutine updateReportIntegral(index,intValue) 7–70
[Link]. subroutine updateReportMinmax(index,newValue) 7–70
[Link]. subroutine writeToList(message) 7–71
[Link]. Access Functions for (really, really) Expert Users 7–71
7.4.3. The INFO array – Typical Calling Sequence 7–76
[Link]. INFO(1:5) 7–76
[Link]. INFO(6) 7–76
[Link]. INFO(7) 7–77
[Link]. INFO(8) 7–77
[Link]. INFO(9) and Types calling sequence 7–77
[Link]. INFO(10) 7–79
[Link]. INFO(11) 7–79
[Link]. INFO(12) 7–79
[Link]. INFO(13) 7–79
[Link]. Typical calling sequence for an iterative Type 7–79
7.4.4. Utility Subroutines 7–81
[Link]. CallProgram (Calling External Programs) 7–81
[Link]. CoolProp_Fluid_Properties( ) 7–82
[Link]. Enclosure_17 (formerly ENCLOSURE and ENCL) 7–85
[Link]. Fluid_Properties (formerly FLUID_PROPS and FLUIDS) 7–87
[Link]. GetHorizontalRadiation and GetTiltedRadiation 7–90
[Link]. InterpolateData (formerly DynamicData, DYNDATA and DATA) 7–104
[Link]. LinearRegression (formerly DFIT and FIT) 7–107
[Link]. LINKCK 7–110
[Link]. InvertMatrix (formerly MATRIX_INVERT, INVERT and DINVRT) 7–112
[Link]. Messages 7–113
[Link]. ParRead 7–115
[Link]. MoistAirProperties (formerly PSYCHROMETRICS and PSYCH) 7–116

7–8
TRNSYS 18 – Programmer's Guide

[Link]. Rcheck 7–119


[Link]. Rewind 7–126
[Link]. SolarCellPerformance (formerly SOLCEL) 7–127
[Link]. SolveDiffEq (formerly DIFFERENTIAL_EQN, and DIFFEQ) 7–129
[Link]. Steam_Properties (formerly STEAM_PROPS and STEAM) 7–132
[Link]. Storage of Data between Time Steps 7–134
[Link]. ASHRAE_Coefs (formerly TABLE_COEFS and TABLE) 7–142
[Link]. Tau_Alpha (formerly TALF) 7–144
[Link]. TYPECK 7–146
[Link]. View_Factors 7–146
7.4.5. Solving Differential Equations 7–152
7.4.6. Use of the Alternate Return (RETURN 1) 7–154
7.4.7. Use of the ICNTRL Array 7–155
7.5. Converting Types from earlier TRNSYS Versions 7–157
7.5.1. Converting components from version 13.x to the version 14.1 coding standard 7–157
7.5.2. Converting components from version 14.1 to the version 14.2 coding standard 7–157
7.5.3. Converting components from version 14.2 to the version 15.x coding standard 7–158
7.5.4. Converting components from version 15.x to the version 16.x coding standard 7–158
[Link]. Steps to use TRNSYS 15 components in "legacy mode" 7–159
[Link]. Instructions on converting TRNSYS 15 Types to the TRNSYS 16 standard 7–160
7.5.5. Converting components from version 16.x to the version 17.x coding standard 7–167
[Link]. The Subroutine Call 7–167
[Link]. Set Global Simulation Variables 7–167
[Link]. Identify the Type’s Coding Standard (version signing) 7–168
[Link]. Perform “Last Call” Manipulations 7–168
[Link]. Perform “End of Time Step” Manipulations 7–168
[Link]. Perform “First Call” Manipulations 7–169
[Link]. Perform “Start Time” Manipulations 7–171
[Link]. Rereading Parameters 7–173
[Link]. Retrieving Input Values 7–173
[Link]. Other Considerations 7–174
7.5.6. Converting components from version 17.x to the version 18.x coding standard 7–174
7.6. Working with the Intel Visual FORTRAN Compiler 7–175
7.6.1. Rebuilding the [Link] with Intel Visual FORTRAN Composer 7–176
[Link]. Creating a TRNSYS Solution 7–176
[Link]. TRNDll project 7–176
[Link]. Project settings 7–176
[Link]. Project files 7–179

7–9
TRNSYS 18 – Programmer's Guide

[Link]. Building [Link] 7–179


7.6.2. Instructions to add a new project to the IvfCXE2011 Solution 7–180
[Link]. TRNSYS Solution 7–180
[Link]. New Project 7–180
[Link]. Project settings 7–181
[Link]. Project files 7–182
[Link]. Building MyDLL 7–182
7.7. Programming a Type in C++ 7–183
7.7.1. Header File (TRNSYS.h) 7–183
7.7.2. Type Declaration 7–183
7.7.3. Calling TRNSYS functions 7–183
[Link]. Calling a TRNSYS Boolean Function 7–183
[Link]. Calling a Function that Passes a Number to TRNSYS 7–184
[Link]. Calling a Function that Receives a Number from TRNSYS 7–184
[Link]. Calling a Function that Passes a String to TRNSYS 7–184
[Link]. Calling a Function that Receives a String from TRNSYS 7–184
7.7.4. Example TRNSYS C++ Type 7–185
7.8. References 7–185

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.

There are 3 main sections in this guide:


 Section 7.2 explains how to use the TypeStudio, an interface and FORTRAN compiler included with
the TRNSYS package as of the TRNSYS 18 release.
 Section 7.3 describes the structure of TRNSYS components in detail.
 Section 7.4 provides a detailed reference on the TRNSYS kernel:
 Calling sequence of Types and structure of the INFO array ([Link])
 Available global constants (7.4.1). Some constants are especially interesting for programmers
since they set standard string lengths in TRNSYS (Fortran 90 does not handle variable-length
strings). See section [Link].
 Access functions that allow Types to access kernel variables (7.4.2)
 Utility subroutines (7.4.4)
 Instructions on recompiling the TRNSYS DLL and on compiling add-on DLL's to the UserLib
using the Intel Visual Fortran compiler (Section 7.6)

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.

7.2.1. Getting Started


The TypeStudio is launched in one of three ways. First, the user may select “Fortran environment…” from
the “Tools” menu in the TRNSYS Simulation Studio. Second, the user may double click on the
TypeStudio executable found in ..\%TRNSYS18%\TypeStudio directory. Third, the user may select the
TypeStudio shortcut from among the TRNSYS shortcuts in the start menu.

Upon launching the TypeStudio the user should see a screen that looks like the following:

7.2.2. Compiling an Existing Type


If a user has existing components already written and wishes to recompile and link them into a DLL using
the TypeStudio then they need to create a TypeStudio workspace.

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.

7.2.3. Writing a New Type in TypeStudio


The TypeStudio is intended to compile one or more pieces of FORTRAN code into a DLL that can be
loaded by the TRNSYS kernel. The FORTRAN code must be written to comply with the coding standards
outlined in section 7.3.

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.

7.2.4. TypeStudio Menu Reference

[Link]. The “File” Menu

New Empty Workspace

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

This command exits the TypeStudio

[Link]. The “Edit” Menu

Undo / Redo

Undoes or redoes a series of edits to the active file.

Cut / Copy / Paste

Standard Windows® commands for manipulating text.

[Link]. The “View” Menu

Change Theme

This command allows the user to select between a number of screen background, and text color
schemes.

Make Text Bigger / Smaller

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.

[Link]. The “Workspace” Menu

Add Source Files

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.

Move Left/Move Right

These commands are used to change the order of the tabs (each of which represents a file that is
included in a workspace).

Show Previous / Next File

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.

[Link]. The “Build” Menu

Compile Workspace

This command attempts to compile all source code contained in the workspace and link it into a DLL.

Debug Workspace

This command is not yet implemented.

Set DLL Name

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.

[Link]. The “Help” Menu

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

This command is not yet implemented.

7.2.5. Acknowledgements
The TypeStudio is written and supported by Northland Numerics ([Link]

7–15
TRNSYS 18 – Programmer's Guide

7.3. Type Structure


One of TRNSYS’s major strengths is the ease with which users may write new components to expand
upon the capabilities of the program. Three features provide the foundation of this expandability. First is
TRNSYS’s open architecture. With one exception, all standard components are provided along with their
source code to act as a reference and to act as the basis for adding new components. Second, all
components whether standard components or user written components are formulated in the same
manner and follow the same steps and progression throughout the code; writing new components
becomes a matter of using a template and adding the appropriate functions, utility calls and equations to
write a model of your own. Thirdly, and perhaps most importantly, the TRNSYS kernel does not impose
any hierarchy whatsoever on the components that are used in a simulation. Nor does it make any
assumptions regarding the order in which components should be solved to simulate the system. Many
other simulation packages do impose such a hierarchy. To take the example of simulating a building, they
often solve the building loads using one part of their kernel, then proceed to solve the system with
another part of their kernel and finally solve the plant aspect of the system last. Many do not revise a
previous step based on calculations in a subsequent step. Thus the system could well not meet the load
at a given time step. However, the building, at the next time step, has no idea that the load was not met.
TRNSYS, by contrast, continues to iterate through all components (whether by successive substitution or
Powell’s method) until convergence is reached. While this can make controls in a TRNSYS simulation
somewhat more cumbersome, it has a major advantage from the point of view of someone writing a new
component; that is that there is no need for the component writer to modify the TRNSYS kernel in any
way in order to accommodate and include their new component. There is no need, for example to decide
where in the management hierarchy the new component that you are writing fits best. Components in
TRNSYS are automatically called by the kernel as soon as they are found in a given simulation. By
assigning a number to each component, the TRNSYS kernel anticipates and automatically calls all
component numbers that it finds in a simulation input file. If a particular Type number is found in the input
file but is not found in the compiled code by the TRNSYS kernel, a dummy place holding component is
called in its stead and the simulation ends with an error.

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

Q  m C p (Tset  Tin ) Eq. 7.3.1-1

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.

7.3.2. The First Line


Every Type begins with the same line:
SUBROUTINE TYPEn
Where “n” in TYPEn is a number between 1 and 9999. To avoid problems with more than one component
being assigned the same number, the following conventions have been adopted:
 Type1 – Type200: reserved for library of Standard TRNSYS Components
 Type201 – Type300 : reserved for user written components
 Type301 – Type500: reserved for add-on components commercially available from Transsolar
Energietechnik, GmbH
 Type501 – Type1700: reserved for add-on components commercially available from Thermal Energy
System Specialists, LLC (TESS)
 Type1701 – Type1800: reserved for add-on components commercially available from Auiguasol
 Type1801 – Type2000: reserved for add-on components commercially available from CSTB.
 Type2001 – Type2200: reserved for components from TRNLib, the freely available online resource
of user-written components.
 Type2201 – Type2300: reserved for additional add-on components commercially available from
TESS.
 Type2301 – Type2400: reserved for components in the Solar Thermal Electric Components (STEC)
library
 Type2401 – Type2500: reserved for components in the TRNAUS library
 Type2501 – Type2600: reserved for components in the System Advisor Module (SAM) library.
 Type2601 – Type2800: reserved for add-on components commercially available from Quattro
 Type2801 – Type3000: unreserved.
 Type3001 – Type3500: reserved for add-on components commercially available from CSTB.
 Type3501 – Type7000: unreserved.
 Type7001 – Type8000: reserved for components in the Solar Ratings and Certification Corporation
(SRCC) library.
 Type8001 – Type9999: unreserved

For this example, Type number 201 will arbitrarily be chosen. Thus the first line of the subroutine should
be:
SUBROUTINE TYPE201

7.3.3. DLL Export


With the release of TRNSYS v. 16.0, a great deal of effort was put into allowing Types to exist either in
the standard [Link] along with the other standard Types or to exist in an External DLL. The TRNSYS
16 (and later) kernel examines the contents of a particular user library directory at the beginning of each

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.3.4. USE Statements


Whereas previous versions of TRNSYS relied heavily on Fortran COMMON blocks, TRNSYS 16 (and
later version) Types should access global constants through various Data Modules that are included with
the source code. A Data Module is really nothing more than a file that contains a series of variable
declarations. They are a convenient way of declaring the variables that are accessible by various
subroutines (Types, and kernel routines) within a program all in one location. If a variable contained within
a data module is needed by a given component, it is accessed by adding a “USE” statement directly after
the DLL Export instruction (see section 7.3.3 above). The syntax of a USE statement is as follows:
Use NameOfDataModule
The above has the effect of declaring ALL of the variables or functions contained within the module in
your Type. Alternatively, if you only want to use a particular variable or function that is contained within
the module but do not want access to all of the variables therein, you can use the syntax:
Use NameOfDataModule, Only: nameOfVariable1,nameOfVariable2
This will only declare the variable(s) listed after the "ONLY" keyword. The advantage of listing only those
variables to which we want access is that we can reuse the names of global variables locally as long as
we do not request access to them through a USE statement. A complete list of Data Modules accessible
from a given Type or subroutine of a Type are listed in sections 7.4.1, 7.4.2. The most common Data
Modules that you will need to access from your Type are: TrnsysFunctions, TrnsysConstants, and
TrnsysData. TrnsysFunctions contains a series of functions that return commonly useful data such as the
simulation start time or time step, or which perform common functions such as reserving a new logical
unit number in a global list for use by an external file accessed by your Type. The TrnsysConstants
module contains values that do not change throughout a simulation but which are again, of common
interest. The TrnsysData module carries a series of data structure sizing constants such as the number of
allowable UNITS in a given simulation or the number of allowable EQUATIONS in a given simulation.

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.3.5. Variable Declarations


Having defined the subroutine, exported the component, and given the component access to global
TRNSYS variables, we next need to declare all of the local variables that we intend to use in the Type.
From a practical point of view, there is no way to anticipate and simply enter all of the variables that will
be needed during the course of developing a new component. The following list is almost always created
as the Type is being written and as local variables are needed.
...
! LOCAL VARIABLE DECLARATIONS
Integer iGam
Double Precision time, & !the current simulation time [hr]
Timestep, & !the simulation time step [hrs]
tin, & !temperature of fluid at heater inlet [C]
tout, & !temperature of fluid at heater outlet [C]
tbar, & !average temperature of fluid in heater [C]
tamb, & !ambient temperature of heater surroundings [C]
tset, & !heater setpoint temperature [C]
ton, & !set temporarily to TOUT before check on TOUT>TSET [C]
qMax, & !heater capacity [kJ/hr]
qAux, & !required heating rate [kJ/hr]
qLoss, & !rate of thermal losses to surroundings [kJ/hr]
flow, & !fluid flow rate through heater [kg/hr]
Cp, & !fluid specific heat [kJ/kg.K]
HtrEff, & !heater efficiency [-]
ua, & !overall loss coeff. for heater during operation [kJ/hr.K]
qFluid !rate of energy delivered to fluid [kJ/hr]
...
For those less familiar with FORTRAN syntax, blue text indicates a keyword that is recognized as a
declaration or a function by the compiler. Green text indicates a comment (comment lines in FORTRAN
begin with an exclamation mark). The “&” simply indicates a line continuation.

7.3.6. Data Statements


It is advantageous in some Types to set some constants that will be used throughout the Type outside of
the executable portion of the code using a DATA statement. The advantage of doing so is that by defining
a constant in a DATA statement, that definition is loaded at the simulation start and never is there a time
when simulation time has to be spent setting or resetting those values. Often times Type programmers
will set a variable called PI to the value 3.1415926 in a DATA statement, or they will set a variable for the
conversion factor between degrees and radians in a DATA statement. Any variable whose value is set in
a DATA statement must be declared among the Local Variable declarations discussed in section 7.3.5
above. While no DATA statements are necessary for our Type201 water heater, a DATA statement

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/

7.3.7. Global Constants and Variables


We have now arrived at the executable section of the Type; from here on, each line of the code will be
executed sequentially, starting at the top. It is therefore necessary to put those lines that should be
executed every single time step and every single iteration right at the beginning of the executable section.
In the case of almost all Types, the only thing that needs to be done this regularly is to retrieve the values
of some global variables that are used in controlling what the Type does at what point in the simulation.
Users familiar with coding standard prior to TRNSYS 17 will recall that a good bit of information was
passed to the component through the argument list. In the TRNSYS 17 (and later) coding standard, some
of this information must now be obtained using Access Functions. Variables such as the simulation time,
the time step, the simulation start time, and the simulation stop time, the current Unit number, the current
Type number must be retrieved on an “as needed” basis. Almost all Types, this one not included, need to
know the simulation time and the simulation time step. These two variables are often used to control Type
functionality. Again, the local variable names for these two variables have already been declared in the
block of local variables that are required by every Type. The local variable name for the simulation time
step is “Timestep” and the local variable name for the simulation time is simply “Time” The code that
should be added to Type201 is as follows:

!----------------------------------------------------------------------
!Get the Global Trnsys Simulation Variables
Time = getSimulationTime()
Timestep = getSimulationTimeStep()

7.3.8. Version Signing


Version signing is one of a series of special calls that is made to a Type when the Type is not intended to
perform any manipulations of inputs or outputs. Once, at the very beginning of a simulation, a Type needs
to log itself as having been written using a given TRNSYS coding standard. Throughout TRNSYS’s
history, new requirements have periodically been added to the recommended practices in coding
components. These requirements reflect new enhancements that have been added or reflect changes is
recommended coding practices that come from the developers of Fortran compilers. Prior to the release
of TRNSYS version 16, it was left to the Type programmer to simply make the required modifications
before being able to use an existing Type with the new version of TRNSYS. With the release of TRNSYS
16.0, an effort was made to allow for backwards compatibility in Types. That is that the TRNSYS 16
kernel was designed in such a way that it was able to deal with Types that were written to conform with
the TRNSYS 16 coding requirements, and to deal with Types that had been written for TRNSYS 15
(which have different coding requirements). The same was true of the TRNSYS 17 release; TRNSYS 16
and TRNSYS 15 components (and their specific needs) can be handled by the TRNSYS 17 kernel
provided that the Types log themselves properly during the “version signing” step. In order for the kernel
to know how to treat a Type, however, each Type must log itself as having been written with TRNSYS 17
(or later), TRNSYS 16, or the TRNSYS 15 (and earlier) conventions. For additional information about the
differences in conventions, please refer to section 7.5 of this manual.

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.

7.3.9. “Last Call” Manipulations


The second special case call to Types occurs at the very END of each simulation. Whether the simulation
ends correctly or ends in error, each Type is recalled by the TRNSYS kernel before the simulation shuts
down. This call allows Types to perform any “last call” manipulations that may be necessary. These may
include closing external data files that were opened by the Type during the course of a simulation, or
calculating summary information that may have been collected during a simulation. The Type that we are
writing does not require any such last call manipulations, so it is advisable to simply return control directly
to the TRNSYS kernel. The code that is added to Type201 is as follows:
...
!----------------------------------------------------------------------
!Do All of the Last Call Manipulations Here
If (getIsLastCallofSimulation()) Then
Return
Endif
You may want your component to actually do something at the end of the simulation. It could, for instance
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 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.3.10. “End of Time Step” Manipulations


At the end of each time step, each Type in a simulation is recalled. The Type should call the Access
Function “getIsEndOfTimestep().” Note that the function will return “true” whether or not a converged
solution was found at the current time step. We are keeping the example Type as simple as possible so
there will be no manipulations at the end of the time step. Therefore, we can enter the following code at
this point in the component:
...
!----------------------------------------------------------------------
!Perform Any "End of Time Step" Manipulations That May Be Required
If (getIsEndOfTimestep()) Then
Return
Endif
...
In more complex components than the one detailed by this example, the “end of time step” call allows a
number of different manipulations to be performed such as resetting counters. For users familiar with the
concept of manually updating storage variables, the concept of “dynamic” and “static” storage variables
were introduced with TRNSYS 17. Refer to section [Link]. The “end of time step” call is also used by
Types that automatically report information to the simulation summary report (SSR). For additional
information, refer to section [Link].

[Link]. Resetting Counters


It is sometimes advantageous to count the number of times that a particular event has occurred during a
given time step. One example might be a controller that counts the number of times that it has calculated
a different value of its control signal during a given time step. After a certain number of different decisions,
the controller “sticks” and the calculated output state no longer changes. At the end of the time step after
all components have converged, it is necessary to reset the iteration counter to zero. This could be done
as one of the end of time step manipulations when the call to the getIsEndOfTimestep() Access Function
returns “true.”

[Link]. Updating Storage Variables


In TRNSYS versions prior to 17.1, another common “end of timestep” manipulation was to update
variables that had been stored in the global storage structure during the Type’s iterations. With the
addition of the concept of “dynamic” storage, this step is no longer needed. Refer to section [Link].1.2
for information on implementing dynamic storage.

[Link]. Updating Automatic Reporting (SSR) Variables


With the release of TRNSYS 18.0 the concept of automatic reports was introduced. If a component is to
automatically report either integrated or min/max values, those values need to be updated at the end of
each time step. Refer to section [Link] for more information about updating automatic report variables.

7–23
TRNSYS 18 – Programmer's Guide

7.3.11. “Initialization Call” Manipulations


At the very start of each simulation, after all Types have version signed themselves (see section 7.3.8 or
section [Link] for more information), each Type should initialize itself. Types should call the
“getIsFirstCallOfSimulation()” Access Function to determine when these initializations should take place.
There is a very specific set of steps that each Type should take at this point in the simulation. With the
release of TRNSYS version 16, the steps taken by a Type during the initialization step changed from what
had been done previously. The most important thing to keep in mind concerning the initialization call is
that a Type should NOT read its parameter list, nor should it perform ANY calculation of output values. It
should perform the following operations

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:

Table [Link]-1: Inputs, Outputs, and their Units

Input Input Description Units Output Output Description Units


Number Number
1 Liquid inlet temperature C 1 Liquid outlet temperature C
2 Liquid inlet mass flow rate kg/hr 2 Liquid outlet flow rate kg/hr
3 Control signal 0..1 3 Required heating rate kJ/hr

7–24
TRNSYS 18 – Programmer's Guide

4 Temperature set point C 4 Energy lost to ambient kJ/hr


5 Ambient temperature C 5 Energy to liquid stream kJ/hr

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

! 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

7–25
TRNSYS 18 – Programmer's Guide

EndIf
...

[Link]. Reserving Space in the Simulation Summary Report


During the initialization step any Types that are to be reported in the Simulation Summary Report (*.SSR)
must reserve the number of spots that they wish to later use. For additional information about the required
programming, please refer to sections [Link] and [Link].

7.3.12. “Start Time” Manipulations


Once the initialization steps (discussed in section 7.3.11 above) were completed, control was returned to
the TRNSYS kernel. The next time that each Type is called is when the simulation time is equal to the
simulation start time. Throughout much of TRNSYS’s history (through version 15) there was no call to
components at the simulation start time. After being called when getIsFirstCallOfSimulation() returned
“true” for initialization (as described in section 7.3.11) Types were next called at the end of the first time
step (TIME = InitialTime + TimeStep). With the release of TRNSYS 16.0, an important distinction was
made by calling all Types once after they have been initialized but before time has advanced in the
simulation. The point of this initial time call is to perform the following actions:

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

'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
EndIf
...

[Link]. Initializing the Simulation Summary Report Data


During the initialization step any Types that are to be reported in the Simulation Summary Report (*.SSR)
should initialize (set up) the specifics of the values that they wish to report. For specific convections and
requirements, refer to section [Link]

7.3.13. “Multiple Unit” Manipulations


Only one more special manipulation section is required before we begin actually simulating the
performance of the liquid heater. In this “Multiple Unit” manipulations section, we must reread our
components parameter list if and only if there is more than one instance of the component in the user’s
simulation.

As usual, we begin by querying an AccessFunction:


If (getIsReReadParameters()) Then
...
EndIf

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.3.14. “Every Time Step” Manipulations


At last we have come to the meat of writing new components. It is in this final section that the
performance of the component is simulated. Because every component is different, the rules for what
steps go in this section become much more flexible. That said the “Every Time Step” manipulations
section can be broken up into four basic categories which proceed in order as follows.

7–28
TRNSYS 18 – Programmer's Guide

[Link]. Retrieve Stored Values


At each iteration, a call should be made to the getDynamicArrayValueLastTimestep() and
getStaticArrayValue() functions to retrieve stored values that are needed in calculations. The call might
look like the following:
...
localVar1 = getStaticArrayValue(1)
localVar2 = getStaticArrayValue(2)
localVar3 = getDynamicArrayValueLastTimestep(1)
localVar4 = getDynamicArrayValueLastTimestep(2)
...

[Link]. Retrieve Input Values


Retrieving input values follows much the same pattern as that of retrieving parameter values. The inputs
are available to each Type by means of the getInputValue() AccessFunction. The values are typically
read to local variable names for convenience and then can be checked for validity in much the same way
as parameters.

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)

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
...
Here the 2 and the 3 in the foundBadInput() call indicate the input number that is the problem in each
case.

[Link]. Perform Calculations


Once all of the input values have been retrieved, the heater performance calculations and control logic
can be performed. Each line in the following code is commented to show its purpose.

!------------------------------------------------------------------------------
!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

[Link]. Set Storage Values


Before exiting the Type at each iteration, it is good practice to update all appropriate storage variables.
Obviously, if one or more of the storage variables is an initial value to be used for all iterative calculations
at a given time step until convergence has been reached then it is not appropriate to update this value
until the “End of Timestep” call (see sections 7.3.10 and [Link] for additional information.)

[Link]. Set Outputs


In much the same way that we took the TRNSYS kernel provided parameter and input values and set
them to local variable names, we now have to set the calculated local variables to the appropriate
TRNSYS global output array. The code to do so for Type201 is as follows:
...
! Set outputs
Call setOutputValue(1,tout)
Call setOutputValue(2,flow)
Call setOutputValue(3,qaux)
Call setOutputValue(4,qloss)
Call setOutputValue(5,qfluid)
...

[Link]. Return Control


The very last requirement is that a Type return control to the TRNSYS kernel after its computations are
complete.
...
Return

7–30
TRNSYS 18 – Programmer's Guide

End Subroutine Type201


...

7–31
TRNSYS 18 – Programmer's Guide

7.3.15. Complete Code


The entire code of Type201 is reproduced here below as a complete reference.
Subroutine Type201

!------------------------------------------------------------------------------
Use TrnsysConstants
Use TrnsysFunctions
!------------------------------------------------------------------------------

!export this subroutine for its use in external DLLs.


!DEC$ATTRIBUTES DLLEXPORT :: TYPE201

!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

End Subroutine Type201

7–34
TRNSYS 18 – Programmer's Guide

7.3.16. Implementing Data Storage between Time Steps


Whenever two or more instances of a Type are used in a single simulation, some care must be taken to
make sure that the local variables in a Type have the values that are associated with the current Unit. For
parameters and inputs, this is not a problem; inputs are read at every iteration and parameters are reread
when a new Unit is encountered (see section 0). Values that are calculated from parameters are also no
problem; the calculations can be redone at each iteration. What if those calculations are time consuming?
It would be nice to be able to do them once and store the result for each Unit (for each instance of the
Type in the simulation) and then to retrieve the value instead of redoing the calculation. The concept of
“static” storage is used. The Type programmer uses the setNumberStoredVariables() AccessFunction to
reserve space in the global storage structure, and then uses the AccessFunctions setStaticArrayValue()
and getStaticArrayValue() as appropriate. Refer to section [Link].1.1 for additional information.

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.

7.3.17. Implementing Automatic Simulation Summary


Reporting
With the release of TRNSYS 18 a user can elect to generate a simulation summary report when a
simulation project is run. The simulation summary report (SSR) is an automatically created text file that
contains a summary of certain pieces of information about the instances (Units) of Types contained in the
simulation. Specifically what information is written to the SSR by a given Type is determined by the
Type’s author. The user has the ability to include all of a given Unit’s information in the SSR or to exclude
it all. This section will focus primarily on the source code that must be added to a Type in order for a Unit
of that Type to be reported in the SSR.

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.

[Link]. Reserving Space in the SSR


If its information is to be included in an SSR report, a Type must first reserve the number of numerical
value spots, min max value spots, integrated value spots, and text strings it wishes to use. This is
accomplished by calling the subroutine setNumberOfReportVariables( ) during Type initialization (covered
in section 7.3.11). The subroutine requires four integer arguments each of which corresponding to the
number of values of each information type being reserved. The code required to reserve one integrated
value spot, two min/max value spots, three numerical value spots and four text string spots is:
Call setNumberOfReportVariables(1,2,3,4)

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].

[Link]. Initializing SSR Variables


Once space has been reserved in the SSR data structures each spot must be initialized. During
initialization, the Type programmer provides a heading for (title/description of) each data value, provides
the units of each data value and can provide the values for numerical value fields and text value fields if
desired. The following table indicates what information should be provided during initialization for each of
the four data types:

Index number Heading Units Integrated Value


Units

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.

The code for Type201’s SSR value initialization is:


! Initialize variables
If (getIsIncludedInSSR()) Then
Call initReportIntegral(1,'Energy Consumed','kW','kWh')
Call initReportIntegral(2,'Energy Delivered','kW','kWh')
Call initReportMinMax(1,'Heater Set Point','C')
Call initReportValue(1,'Heater Capacity',qmax/3600.d0,'kW')
Call initReportValue(2,'Heater Loss Coefficient',ua,'kJ/h.K')
Call initReportValue(3,'Heater Efficiency',htreff,'0..1')
EndIf

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].

[Link]. Updating SSR Variables


Two of the four SSR variable types must be updated throughout the simulation: integrated variables and
min/max variables. Typically the update will be performed at the end of a time step. The update is not
automatic and must be initiated by the Type programmer. During the update, the values of the local
variables that are being reported must be retrieved and then sent as an argument to the appropriate
update function. If the variables being updated and reported are inputs or outputs of the Type, the
retrieval consists of using the getInputValue( ) and / or getOutputValue( ) functions. If, however, the
variable being reported is not an input or an output then either the value must be recalculated at the end
of time step or the programmer must place the value into the between time step storage structures
discussed in section 7.3.16.

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].

The code for Type201’s SSR value update is:


!Perform Any "End of Timestep" Manipulations That May Be Required
If (getIsEndOfTimestep()) Then
! Update variables
If (getIsIncludedInSSR()) Then
Call updateReportIntegral(1,getOutputValue(3)/3600.d0)
Call updateReportIntegral(2,getOutputValue(5)/3600.d0)
Call updateReportMinMax(1,getInputValue(4))
EndIf
Return
Endif

Note that if one of the SSR variables is updated twice in the same time step, TRNSYS will generate a
fatal error.

7.3.18. Including your new component in an external DLL


There are two methods of including a new Type in an external DLL. For information on why a Type should
be contained in an external DLL, please refer to the introduction to this manual (section 7.1)

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.4. Programming Reference


This section gives usage rules for most of the functions and subroutines in the TRNSYS kernel that Types
may need to access in the course of a simulation.

7.4.1. Global constants


Certain constants in the TRNSYS kernel are defined globally in such a way that they are easy to modify.

[Link]. Constants settings limits on TRNSYS simulations

Constant Default Comment

nMaxUnits 1000 Maximum number of units


nMaxEquations 2000 Maximum number of equations
nMaxDerivatives 100 Maximum number of derivatives
nMaxOutputs 6000 Maximum number of Outputs
nMaxParameters 4000 Maximum number of Parameters
nMaxStorageSpots 10000 Number of Storage places in the S array
nMaxFiles 300 Maximum number of files that can be opened by TRNSYS
nMaxDescriptions 750 Maximum number of descriptions in an input file
nMaxVariableUnits 750 Maximum number of input variable types in an input file
nMaxLabels 100 Maximum number of labels in an input file
nMaxFormats 100 Maximum number of format statements in an input file
nMaxChecks 20 Maximum number of CHECK statements in an input file
nMaxCheckCodes 30 Maximum number of outputs per CHECK statement
nMaxUnitConversions 250 Maximum number of unit conversions allowed in [Link] file
nMaxUnitTypes 250 Maximum number of unit types allowed in [Link] file
nMaxCardValues 500 Maximum number of values allowed in one TRNSYS input file card
E.g. a component with 500 parameters would require
nMaxCardValues to be greater or equal to 500

minTimeStep 0 .1 Minimum Simulation Time Step [in hours] (0.1 second)


3600

nMaxTimeSteps 109 Maximum number of time steps in a simulation (1 billion)


nMaxPlottedTimeSteps 525601 Maximum number of time steps plotted by the online plotter
Note: This constant is set in TRNExe. Do not edit

7–39
TRNSYS 18 – Programmer's Guide

nMaxErrorMessages 1000 Maximum number of standard error messages in TrnsysErrors


Note: If you increase this constant, additional messages
will not be initialized. Add lines in Messages.f90

[Link]. Constants used for string length

Constant Default Comment

maxPathLength 300 Maximum length of variables containing path- and filenames


Note: DFWIN defines MAX_PATH as 260 but the Windows OS (since
XP) can actually use much longer pathnames.
ATTENTION: TRNExe must be adapted if this constant is modified.
Users should not change maxPathLength

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

maxDescripLength 25 Maximum length of a variable description, e.g. descriptions for printers


and plotters

maxVarUnitLength 20 Maximum length of units associated with variables

maxEqnNameLength 40 Maximum length of variable names in equations

maxLabelLength 300 Maximum length of labels. Some labels are file- and pathnames so a
suggested value is maxLabelLength = maxPathLength

maxMessageLength 800 Maximum length of notices, warnings and error messages


Error messages and any text printed on the same line must
fit within the maximum file width (maxFileWidth).
It is recommended to set maxMessageLength to maxFileWidth-200

7–40
TRNSYS 18 – Programmer's Guide

7.4.2. Access functions


This section lists all functions declared in the "TrnsysFunctions" module. Note that the subroutines used
to handle data storage are mentioned here for the record, but detailed explanations on their use can be
found in section [Link].

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.

[Link]. function CheckStability( )

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

[Link]. function closeFileIVF(lu)


An integer function that closes the file associated with a specified logical unit number. The function
always returns a value of 1. This function is typically used by Types that are located in an external DLL
(i.e. not in the TRNDll) but which need to read an external file that has been associated with the Unit by
means of an ASSIGN statement. With certain Fortran compilers, since the file has already been opened
by the TRNDll, the external DLL is prevented from also opening it. This function gives the user the ability
to tell the TRNSYS kernel to close the file. The calling Type would then open the file itself and read the
data. NOTE: files that are intended to be read (and interpolated) by the InterpolateData (formerly
DynamicData) routine do not need to make use of this function since it is a TRNSYS kernel routine that
will be performing the file read.

Example usage(s)
Integer :: dummyReturn,logicalUnit
...
dummyReturn = closeFileIVF(logicalUnit)

[Link]. function ErrorFound( )


Logical function that returns a value of “TRUE” if TRNSYS errors have been found. This function is most
useful in Types that call one or more of the TRNSYS Utility subroutines (such as TYPECK,
PSYCHROMETRICS, or STEAM) which may call find and flag errors. For example, say a user written
Type calls TYPECK to indicate that one of the INPUTS had an inappropriate value. TYPECK would call

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

[Link]. function getConnectedOutputNumber(i,j)


An integer function that returns the output number connected to the j th input of Unit i. When using the
Powell’s Method solver (SOLVER 1), you should call the getConnectedOutputNumberS1() function
instead of this one.

Example usage
Integer:: getConnectedOutputNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedOutputNumber (i,j)

Related Functions: getConnectedOutputNumberS1()

[Link]. function getConnectedOutputNumberS1(i,j)


An integer function that returns the output number connected to the j th input of Unit i. When using the
Successive Substitution solver (SOLVER 0), you should call the getConnectedOutputNumber() function
instead of this one.

Example usage
Integer:: getConnectedOutputNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedOutputNumberS1(i,j)

Related Functions: getConnectedOutputNumber()

[Link]. function getConnectedTypeNumber(i,j)


An integer function that returns the type number of the unit connected to j th input of Unit i. When using the
Powell’s Method solver (SOLVER 1), you should use the similar function getConnectedTypeNumberS1().

Example usage
Integer:: getConnectedTypeNumber
Integer:: i,j
...
getConnectedTypeNumber = getConnectedTypeNumber(i,j)

7–42
TRNSYS 18 – Programmer's Guide

Related Functions: getConnectedTypeNumberS1()

[Link]. function getConnectedTypeNumberS1(i,j)


An integer function that returns the type number of the unit connected to j th input of Unit i. When using the
Successive Substitution solver (SOLVER 0), you should use the similar function
getConnectedTypeNumber().

Example usage
Integer:: getConnectedTypeNumber
Integer:: i,j
...
getConnectedTypeNumber = getConnectedTypeNumberS1(i,j)

Related Functions: getConnectedTypeNumber()

[Link]. function getConnectedUnitNumber(i,j)


An integer function that returns the unit connected to j th input of Unit i. When using the Powell’s Method
solver (SOLVER 1), you should use the similar function getConnectedUnitNumberS1().

Example usage
Integer:: getConnectedUnitNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedUnitNumber(i,j)

Related Functions: getConnectedUnitNumberS1()

[Link]. function getConnectedUnitNumberS1(i,j)


An integer function that returns the unit connected to jth input of Unit i. When using the Successive
Substitution solver (SOLVER 0), you should use the similar function getConnectedUnitNumber().

Example usage
Integer:: getConnectedUnitNumber
Integer:: i,j
...
getConnectedOutputNumber = getConnectedUnitNumberS1(i,j)

Related Functions: getConnectedUnitNumber()

[Link]. function getConnectedVariableType(i,j)


A character function that returns the three-character description of the type of variable that is connected
to jth input of Unit i. This information is stored the array OCHECK. When using the Powell’s Method
solver (SOLVER 1), you should use the similar function getConnectedVariableTypeS1().

Example usage

7–43
TRNSYS 18 – Programmer's Guide

Character*3:: getConnectedVariableType
Integer:: i,j
...
getConnectedVariableType = getConnectedVariableType (i,j)

Related Functions: getConnectedVariableTypeS1()

[Link]. function getConnectedVariableTypeS1(i,j)


A character function that returns the three-character description of the type of variable that is connected
to jth input of Unit i. This information is stored the array OCHECK. When using the Successive
Substitution solver (SOLVER 0), you should use the similar function getConnectedVariableType().

Example usage
Character*3:: getConnectedVariableType
Integer:: i,j
...
getConnectedVariableType = getConnectedVariableTypeS1(i,j)

Related Functions: getConnectedVariableType()

[Link]. function getConnectedVariableUnit(i,j)


A character function that returns the corresponding units (e.g., kJ/kg-h) of the variable that is connected
to jth input of Unit i. When using the Powell’s Method solver (SOLVER 1), you should use the similar
function getConnectedVariableUnitS1().

Example usage
Character (len=maxVarUnitLength):: getConnectedVariableUnit
Integer:: i,j
...
getConnectedVariableUnit = getConnectedVariableUnit(i,j)

Related Functions: getConnectedVariableUnitS1()

[Link]. function getConnectedVariableUnitS1(i,j)


A character function that returns the corresponding units (e.g., kJ/kg-h) of the variable that is connected
to jth input of Unit i. When using the Successive Substitution solver (SOLVER 0), you should use the
similar function getConnectedVariableUnit().

Example usage
Character (len=maxVarUnitLength):: getConnectedVariableUnit
Integer:: i,j
...
getConnectedVariableUnit = getConnectedVariableUnitS1(i,j)

Related Functions: getConnectedVariableUnit()

7–44
TRNSYS 18 – Programmer's Guide

[Link]. function getConvergenceTolerance( )


Double precision function that returns the user specified value of a simulation’s convergence tolerance
(the second argument in the TOLERANCES keyword statement).

Example Usage
DOUBLE PRECISION ErrTol
...
ErrTol = getConvergenceTolerance()

[Link]. function getCurrentType()


Integer function that returns the current (or most recently called) Type number. This return value is the
second spot in the INFO( ) array.

Example usage
Integer:: currentType
...
currentType = getCurrentType()

[Link]. function getCurrentUnit()


Integer function that returns the current (or most recently called) Unit number. This return value is the first
spot in the INFO( ) array.

Example usage
Integer:: currentUnit
...
currentUnit = getCurrentUnit()

[Link]. function getDeckFileName( )


A character function that returns the name (NOT including the path) of the input file being run. This
function is useful in printer and other output devices in which results that pertain to a particular input file
are to be stored. The length of the returned string is maxPathLength.

Example Usage
USE TrnsysConstants, ONLY: maxPathLength

CHARACTER (len=maxPathLength) DeckName


...
DeckName = getDeckFileName()

[Link]. function getDynamicArrayValueLastTimestep(j)


A double precision function that returns the jth value from the dynamic double-precision global storage
structure. Note that this value is the one that was calculated at the end of the previous time step. It will not
change until the end of the current time step, at which point it will be replaced by the most recent value
that was stored using a call to the setDynamicArrayValueThisIteration() function. Refer to section [Link]
for a discussion of the proper use of this function and those related to it.

Example usage(s)

7–45
TRNSYS 18 – Programmer's Guide

Double Precision :: value


Integer :: j
...
value = getDynamicArrayValueLastTimestep(j)

Related Functions: setDynamicArrayValuethisIteration(:), setNumberStoredVariables(:,:)

[Link]. function getExtFilePath(unitNum,fileNum,extFilePath)


An integer function that returns the length of the string variable needed to contain the path and name of
an external file that is associated with a particular Unit through the use of the FILES keyword. Note this
function does not return the path and name of files associated with a particular Unit by use of an ASSIGN
statement. The function also returns a string variable containing the name and location of the requested
file.

Example usage(s)
Use TrnsysConstants, Only :: maxPathLength
Integer :: currentUnit,length,i
Character (len=maxPathLength) :: fileLocation
...
length = getExtFilePath(currentUnit,i,extFilePath)

[Link]. function getFormat(i,j )


A character function that returns the jth format statement associated with unit i. The length of the returned
string is maxFileWidth. For example, in certain modes, Type9 takes a single Format statement.. To
access the format of the data file line that is to be read, Type9 contains the following code:

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

[Link]. function getInputValue(i)


A double precision function that returns the current value of the current Type’s i th input.

Example usage(s)
Double Precision :: inputValue1, inputValue2
...
inputValue1 = getInputValue(1)
inputValue2 = getInputValue(2)

[Link]. function getIsConvergenceReached( )


This function is obsolete and any instances of its use should be replaced by a call to the function
getIsEndOfTimestep( ).

7–46
TRNSYS 18 – Programmer's Guide

[Link]. function getCosimConvergenceCheckingTime( )


REVISIT

[Link]. function getIsEndOfTimestep()


Integer function that returns a 1 if the TRNSYS kernel is calling the Types at the current time step one
final time after convergence has been reached (or after it has determined that convergence cannot be
reached) but before the start of the next time step. The return value corresponds to the condition when
the 13th spot in the INFO( ) array is equal to 1.

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.

[Link]. function getIsFirstCallofSimulation( )


Integer function that returns a 1 if the TRNSYS kernel is calling the Types before time has begun to
advance This is the call at which components perform their initializations: setting where they should be
called in the calling sequence (using the setIterationMode() function), setting how many parameters
(using the setNumberofParameters() function), inputs (using the setNumberofInputs() function), and
derivatives (using the setNumberOfDerivatives() function) they expect, reserving space in the output array
(using the setNumberofOutputs() function) and in the various storage structures (using the
setNumberStoredVariables() function). The return value corresponds to the condition when the 7 th spot in
the INFO( ) array is equal to -1.

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

[Link]. function getIsDemo( )


A logical function that returns “true” if the demonstration version of TRNSYS (as opposed to the fully
featured version of TRNSYS is being run. The demonstration version of TRNSYS has certain built-in
limitations.

Example usage
If (getIsDemo() ) Then
...
EndIf

[Link]. function getIsFirstTimestep( )


A logical function that returns “true” if the current time step coincides with the first time step of the
simulation.

Example usage
If (getIsFirstTimestep() ) Then
...
EndIf

[Link]. function getIsIncludedInSSR( )


A logical function that returns “true” if the unit number of the calling Type has been designated in the input
file (*.dck) as being included in the simulation summary report.

Example usage
If (getIsIncludedInSSR()) Then
...
EndIf
Related Functions:

[Link]. function getIsLastCallofSimulation()


Integer function that returns a 1 if the TRNSYS kernel is calling the Types the very last time before the
end of the simulation. The return value corresponds to the condition when the 8 th spot in the INFO( ) array
is equal to -1.

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

[Link]. function getIsReReadParameters()


Integer function that returns a 1 if the current Type needs to reread its parameters (usually because
multiple instances of the same Type exist in the same TRNSYS project). There is no need to recheck
parameter values for validity since they were already checked previously. Variables that are calculated
based only on parameter values must be recalculated unless they are stored globally using the
setNumberStoredVariables() function.

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.

Related Functions: none

[Link]. function getIsStartTime ()


Integer function that returns a 1 if the TRNSYS kernel is calling the Types before time has begun to
advance. This is the call at which components read their parameter values and check them for validity.

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.

[Link]. function getIsTRNSED( )


A logical function that returns “true” if a TRNSED input file (as opposed to a Simulation Studio input file or
*.dck file) is being run.

Example usage
If (getIsTRNSED() ) Then
...
EndIf

7–49
TRNSYS 18 – Programmer's Guide

[Link]. function getIsVersionSigningTime()


Integer function that returns 1 if the current Type needs to set which coding standard it uses. The coding
standard is set using the setTypeVersion() function. The return value corresponds to the 7 th spot of the
INFO() array being set to -2.

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.

Related Functions: none

[Link]. function getLabel(i,j)


A character function that returns the jth 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)

[Link]. function getListingFileLogicalUnit( )


An integer function that returns the logical unit of the TRNSYS list file.

Example Usage
Integer LUW
...
LUW = getListingFileLogicalUnit()

[Link]. function getLUFileName (i)


A character function that returns the name of the file corresponding to the logical unit i. If the file logical
unit number has not been assigned, it returns an error message.

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

[Link]. function getLUFileName_Cpp(i, LUfilePath )


The getLUFileName_Cpp function returns the name of the file corresponding to the logical unit number i
and the length of the path. It differs from the getLUFileName( ) function in that getLUFileName only
returns the path (not the path length). In this function the argument "LUFilePath" is set to the full path and
name of the file. The function return value is the length of the variable needed to contain the file name.

Example Usage
Integer strLength,LU
Character (len=maxLabelLength) fileName
...
strLength = getLUfileName_Cpp(LU, fileName)
Related Functions: getLUFileName

[Link]. function getMaxDescripLength( )


[ maxDescripLength is also available through "use TrnsysConstants" ]

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 ()

[Link]. function getmaxFileWidth( )


[ maxFileWidth is also available through "use TrnsysConstants" ]

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()

[Link]. function getMaxLabelLength( )


[ maxLabelLength is also available through "use TrnsysConstants" ]

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()

[Link]. function getMaxPathLength( )


[ maxPathLength is also available through "use TrnsysConstants" ]

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()

[Link]. function getMinimumTimestep( )


Double precision function that returns the minimum allowable TRNSYS time step. The minimum allowable
TRNSYS time step 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
Double Precision minStep
...
minStep = getMinimumTimestep()

[Link]. function getMinorVersionNumber( )


Integer function that returns the TRNSYS minor version number (if the version number is XX.Y, it will
return Y). This function is primarily useful in allowing for backward compatibility between versions of a
component, when changes have occurred between minor release versions. For example, a Type
required 14 parameters in an input file written for TRNSYS version 17.0 but requires 15 parameters in an

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()

[Link]. function getNextAvailableLogicalUnit( )


Integer function that returns an available logical unit number and logs the logical unit number in a global
list of assigned logical unit numbers. The getNextAvailableLogicalUnit function can be used to find an
available logical unit number for temporary files, scratch files, or for data files accessed by components
that do not require a logical unit number among their list of parameters.

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')

[Link]. function getNFiles(unitNum)


An integer function that returns the number of external files that are associated with a particular Unit
through the use of the FILES keyword. Note this function does not return the number of files associated
with a particular Unit by use of an ASSIGN statement.

Example usage(s)
Integer :: nFiles,currentUnit
...
nFiles = getNFiles(currentUnit)

[Link]. function getnMaxIterations( )


An integer function that returns the maximum allowable number of iterations in one time step before the
simulation continues with the current values and a warning is issued. The maximum allowable number of
iterations can be set in a Limit statement (or in the Studio's Control Cards).

Example Usage
Integer maxIter
...
maxIter = getnMaxIterations()

[Link]. function getnMaxStorageSpots( )


[nMaxStorageSpots is also available through "use TrnsysConstants" ]

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()

[Link]. function getnMaxWarnings( )


An integer function that returns the maximum allowable number of warnings written to the simulation list
and log files before the simulation stops in error. The maximum allowable number of warnings can be set
in a Limit statement (or in the Studio's Control Cards).

Example Usage
Integer maxWarns
...
maxWarns = getnMaxWarnings()

[Link]. function getnTimeSteps( )


An integer function that returns the total number of time steps in the simulation being run.

Example Usage
Integer nSteps
...
nSteps = getnTimeSteps()

[Link]. function getNumberOfDerivatives( )


An integer function that returns the number of derivatives provided for the current Unit in the input file
being run. Note that if a user provided the incorrect number of derivatives in the input file, then this
function will not return the correct number of derivatives; it will return the number of derivatives that the
user specified. The return value corresponds to the 5th value in the INFO() array.

Example usage(s)
Integer :: nDerivs
...
nDerivs = getNumberOfDerivatives()

Related Functions: setNumberofDerivatives()

[Link]. function getNumberOfErrors( )


An integer function that returns the total number of errors that have occurred thus far in the simulation.

Example Usage
Integer NumErrs
...
NumErrs = getNumberOfErrors()

7–54
TRNSYS 18 – Programmer's Guide

[Link]. function getNumberOfInputs()


An integer function that returns the number of inputs provided for the current Unit in the input file being
run. Note that if a user provided the incorrect number of inputs in the input file, then this function will not
return the correct number of inputs; it will return the number of inputs that the user specified. The return
value corresponds to the 3rd value in the INFO() array.

Example usage(s)
Integer :: nInputs
...
nInputs = getNumberOfInputs()

Related Functions: setNumberofInputs(), getInputValue()

[Link]. function getNumberOfLabels( )


An integer function that returns the number of labels associated with unit i

Example Usage
Integer NumLabels,unitNum
...
NumLabels = getNumberOfLabels(unitNum)

[Link]. function getNumberOfOutputs()


An integer function that returns the number of outputs that have been reserved by the current Unit for the
current Unit. Note that it is the Type’s responsibility to reserve its own output space using a call to the
setNumberOfOutputs() function discussed in section [Link]. The return value corresponds to the 6th
value in the INFO() array.

Example usage(s)
Integer :: nOutputs
...
nOutputs = getNumberOfOutputs()

Related Functions: setNumberofOutputs(), getOutputValue()

[Link]. function getNumberOfParameters()


An integer function that returns the number of parameters provided for the current Unit in the input file
being run. Note that if a user provided the incorrect number of parameters in the input file, then this
function will not return the correct number of parameters; it will return the number of parameters that the
user specified. The return value corresponds to the 4th value in the INFO() array.

Example usage(s)
Integer :: nPars
...
nPars = getNumberOfParameters()

7–55
TRNSYS 18 – Programmer's Guide

Related Functions: setNumberofParameters(), getParameterValue()

[Link]. function getNumberOfWarnings( )


An integer function that returns the total number of warnings that have occurred thus far in the simulation.

Example Usage
Integer numWarns
...
numWarns = getNumberofWarnings()

[Link]. function getNumericalDerivative(i)


A double precision function that returns the ith numerically solved derivative for the current Unit. In
TRNSYS versions 16 and prior, this value would be the ith spot in the DTDT() array. Refer to section 7.4.5
for additional information on solving differential equations numerically in TRNSYS. NOTE that only very
rarely would a Type ever call this function. Normally a Type sets the derivatives and calls the
getNumericalSolution() function to obtain the results. The getNumericalDerivative() function is included for
cases in which it is not the TRNSYS kernel but another engine (such as Matlab or the TRNSYS Studio)
that calls the Type directly.

Example usage(s)
Double Precision :: localDTDT(:)
Integer :: i,j
...
DTDT(i) = getNumericalDerivative(j)

Related Functions: setNumberofDerivatives(), setNumericalDerivative(), getNumericalSolution()

[Link]. function getNumericalSolution(i)


An double precision function that returns the value of the ith spot in the T() array. This return value is the
numerical solution to the ith derivative value set by the Type in the DTDT() array. Refer to section 7.4.5 for
additional information on solving differential equations numerically.

Example usage(s)
Double Precision :: T(:)
Integer :: i,j
...
T(j) = getNumericalSolution(i)
Related Functions: setNumberofDerivatives(), setNumericalDerivative(), getNumericalDerivative()

[Link]. function getNumericalSolver( )


An integer function that returns the Solver used by TRNSYS. More information on TRNSYS solvers can
be found in Volume 06, TRNEdit (check the section on the Solver statement). Handling of discrete control
signals is different with Solver 0 and Solver 1. See Type 2 for a n example.

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

[Link]. function getOutputValue(i)


A double precision function that returns the last calculated value of the current Unit’s i th output.

Example usage(s)
Double Precision :: outputValue1, outputValue2
...
outputValue1 = getOutputValue(1)
outputValue2 = getOutputValue(2)

[Link]. function getOverallIteration( )


An integer function that returns the number of times that the current Unit has been called thus far in the
simulation. The return value corresponds to the value carried in the 8th spot of the INFO() array.

Example usage(s)
Integer :: overallIteration,i
...
overallIteration = getOverallIteration(i)

Related Functions: setTimestepIteration(), getTimestepIteration()

[Link]. function getParameterValue(i)


A double precision function that returns the value of the current Unit’s ith parameter.

Example usage(s)
Integer :: parValue1
Double Precision :: parValue2, parValue3
...
parValue1 = jfix(getParameterValue(1)+0.1)
parValue2 = getParameterValue(2)
parValue3 = getParameterValue(3)

[Link]. function getPreviousControlState(i)


An integer function that returns the last calculated value of the i th spot in the ICNTRL() array. Please refer
to section 7.4.7 for additional information on the use of the ICNTRL() array.

Example usage(s)
Integer :: lastState,i
...
lastState = getPreviousControlState(i)

7–57
TRNSYS 18 – Programmer's Guide

[Link]. function getSimulationStartTime( )


Double precision function that returns the hour of the year at which the simulation began.

Example Usage
Double Precision TIME0
...
TIME0 = getSimulationStartTime()

[Link]. function getSimulationStartTimeV15( )


Double precision function that returns the hour of the year at which the simulation began. The returned
value is the original start time in a Version 15 deck file (Start time is changed by TRNSYS 16 to adapt it to
the new start time definition)

Example Usage
Double Precision TIME0V15
...
TIME0V15 = getSimulationStartTimeV15()

[Link]. function getSimulationStopTime( )


Double precision function that returns the hour of the year at which the simulation is set to end.

Example Usage
Double Precison TFINAL
...
TFINAL = getSimulationStopTime()

[Link]. function getSimulationTime( )


Double precision function that returns the hour of the year at which the current simulation time.

Example Usage
Double Precision TIME
...
TIME = getSimulationTime()

[Link]. function getSimulationTimeStep( )


Double precision function that returns the simulation time step (in hours).

Example Usage
Double Precision DELT
...
DELT = getSimulationTimeStep()

7–58
TRNSYS 18 – Programmer's Guide

[Link]. function getStaticArrayValue(j)


A double precision function that returns the j th value from the static double-precision global storage
structure. Refer to section [Link] for a discussion of the proper use of this function and those related to
it.

Example usage(s)
Double Precision :: value
Integer :: j
...
value = getStaticArrayValue(j)

Related Functions: setStaticArrayValue(:), setNumberStoredVariables(:,:)

[Link]. function getTimeReport()


Logical function that returns the value of the global variable TIME_REPORT. This global variable is set to
false by default, but may be set to true in the input file.

Example usage
Logical :: timereport
...
timereport = getTimeReport()

[Link]. function getTimestepIteration()


An integer function that returns the number of times that the current Unit has been called thus far in the
current time step. The return value corresponds to the value carried in the 7 th spot of the INFO() array.

Example usage(s)
Integer :: iteration,i
...
iteration = getTimestepIteration(i)

Related Functions: setTimestepIteration(), getOverallIteration()

[Link]. function getTimeStepNumber( )


An integer function that returns the time step number in the current simulation being run.

Example Usage
Integer StepNumber
...
StepNumber = getTimeStepNumber()

7–59
TRNSYS 18 – Programmer's Guide

[Link]. function getTrnsysDebugLibDir( )


A character function that returns the path and directory in which all of the debug mode loadable user dlls
are located (default = "C:\Program Files\Trnsys17\UserLib\DebugDLLs"). NOTE: when compiled in debug
mode, the [Link] will search for loadable user dlls in this directory. The length of the returned string is
maxPathLength.

Example Usage
Use TrnsysConstants, Only: maxPathLength

Character (len=maxPathLength) DbgLibDir


...
DbgLibDir = getTrnsysDebugLibDir()

[Link]. function getTrnsysExeDir( )


A character function that returns the path in which the TRNSYS executable ([Link]) is located
(default = "C:\Program Files\Trnsys16\Exe"). The length of the returned string is maxPathLength.

Example Usage
Use TrnsysConstants, Only: maxPathLength

Character (len= maxPathLength) ExeLoc


...
ExeLoc = getTrnsysExeDir()

[Link]. function getTrnsysInputFileDir( )


A character function that returns the path in which the input file being run is contained. This function is
useful in printer and other output devices in which results that pertain to a particular input file are to be
stored. The length of the returned string is maxPathLength.

Example Usage
Use TrnsysConstants, Only: maxPathLength

Character (len=maxPathLength) DeckLoc


...
DeckLoc = getTrnsysInputFileDir()

[Link]. function getTrnsysReleaseLibDir( )


A character function that returns the path and directory in which all of the release mode loadable user dlls
are located (default = "C:\Program Files\Trnsys17\UserLib\ReleaseDLLs"). NOTE: when compiled in
release mode, the [Link] will search for loadable user dlls in this directory. The length of the returned
string is maxPathLength.

Example Usage
Use TrnsysConstants, Only: maxPathLength

Character (len=maxPathLength) RlsLibDir


...
RlsLibDir = getTrnsysReleaseLibDir()

7–60
TRNSYS 18 – Programmer's Guide

[Link]. function getTrnsysRootDir( )


A character function that returns the path to the root TRNSYS directory (default = "C:\Program
Files\Trnsys16 "). The length of the returned string is maxPathLength.

Example Usage
Use TrnsysConstants, Only: maxPathLength

Character (len=maxPathLength) RootDir



RootDir = getTrnsysRootDir()

[Link]. function getTrnsysUserLibDir( )


A character function that returns the path and directory in which the debug mode and release mode
subdirectories, which in turn contain loadable user dlls are located (default = "C:\Program
Files\Trnsys17\UserLib"). The length of the returned string is maxPathLength.

Example Usage
Use TrnsysConstants, Only: maxPathLength

Character (len=maxPathLength) UsrLibDir


...
UsrLibDir = getTrnsysUserLibDir()

[Link]. function getTypeVariant( )


This function returns the VARIANT number that is associated with the current UNIT of the current TYPE.
The function effectively returns 0 if no VARIANT has been set since INFO(14) is set to zero in this case.
VARIANTS can be used to manage multiple options within a single Type. Types may have more than one
variant, all coded within the same Fortran subroutine. The VARIANT number (written in the *.dck file) can
be used to specify which VARIANT of a Type is to be executed during a given simulation.

Example Usage
Integer varNum
...
varNum = getTypeVariant()

[Link]. function getTypeVersion()


An integer function that returns the coding standard set for the current Unit by the current Unit. Note that it
is the Type’s responsibility to set the coding standard for which it was written using a call to the
setTypeVersion() function discussed in section [Link]. The return value is the 12th spot of the INFO()
array.

Example usage(s)
Integer :: typeVersion
...
typeVersion = getTypeVersion()

Related Functions: setTypeVersion()

7–61
TRNSYS 18 – Programmer's Guide

[Link]. function getVariableDescription(i,j)


String function that returns the variable descriptor for the j th variable of Unit i. Variable descriptors are
strings that give the "name" of the variable in printers and other output devices. The length of the returned
string is maxDescripLength.

Example usage
Character (len=maxDescripLength) :: columnHeader
...
Do j = 1, nVariables
columnHeader = getVariableDescription(INFO(1),j)
... write column header to a file, etc...
EndDo

[Link]. function getVariableUnit(i,j)


String function that returns the variable unit string for the j th variable of Unit i. Variable descriptors are
strings that give the "name" of the variable in printers and other output devices. The length of the returned
string is maxVarUnitLength.

Example usage
Character (len=maxVarUnitLength) :: varUnitString
...
Do j = 1, nVariables
varUnitString = getVariableDescription(INFO(1),j)
... write units to a file, etc...
EndDo

[Link]. function getVersionNumber( )


Integer function that returns the TRNSYS major version number (i.e, if the version number is XX.Y, it will
return XX). This function is primarily useful in allowing for backward compatibility between versions of a
component. Say, for example that a Type required 14 parameters in an input file written for TRNSYS
version 16 but requires 15 parameters in an input file written for TRNSYS version 17. The Type
programmer could access the getVersionNumber function and know whether the input file being run was
written for TRNSYS version 16 or 17, and could read the corresponding parameter list.

Example Usage
Integer VERSNUM
...
VERSNUM = getVersionNumber()

[Link]. function LogicalUnitIsOpen( )


Logical function that returns true if the Logical unit has been assigned in the deck file and opened by
TRNSYS.

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

[Link]. function readNextChar( )


A function that reads the next line of the external file associated with logical unit number LUN. The
function returns a 1 if it succeeded, a 2 if it got to the end of the file, and a 3 if it failed. Somewhat
incomprehensibly, it does not return the line that it read. The person writing the access function
comments that this is “necessary in cases where a Type is directly called from an external program such
as the Studio or Matlab.” It seems a bit pointless to the person writing this documentation, however.

Example usage(s)
Integer :: lun
...
Call readNextChar(lun)

Related Functions: none

[Link]. subroutine addExternalFile(LUN, FileName)


A function that adds an additional file to the list of files that the kernel opens and then asks the kernel to
open that file. The kernel automatically opens various files. These include the *.lst, *.log, and those files
that are referenced by a Type through an ASSIGN statement. Note: the files that are referenced by a
Type through a DESIGNATE statement are not opened by the kernel. For additional information about the
ASSIGN and DESIGNATE statements, refer to the 06-TRNEdit manual.

A call to the addExternalFile() function is structured as follows:

Example usage(s)
Use TrnsysConstants, Only :: maxPathLength
...
Integer :: lu
Character (len=maxPathLength) :: pathAndFileName
...
Call addExternalFile(lu,pathAndFileName)

Related Functions: none

[Link]. subroutine foundBadInput(i,severity,message)


This function is used to write a message concerning a bad Input value to the TRNSYS *.log and *.lst files.
It replaces a call to the TYPECK() subroutine with an IOPT value of 3 (refer to section [Link]). The
three arguments to the foundBadInput() function are the index number of the Input whose value has been
found to be bad, the severity of the error (notice, warning, or fatal), and a text string containing the
message that should be printed. Note that the action taken by the kernel (whether the simulation stops or
not) is dictated by the selected severity of the error. Once all Inputs have been checked and any bad
ones have been flagged by a call to the foundBadInput() function, the ErrorFound() function should be
called to exit the Type properly if required. Unlike the foundBadParameter() function, this function should

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

Related Functions: none

[Link]. subroutine foundBadParameter(i,severity,message )


This function is used to write a message concerning a bad Parameter value to the TRNSYS *.log and *.lst
files. It replaces a call to the TYPECK() subroutine with an IOPT value of 4 (refer to section [Link]). The
three arguments to the foundBadParameter() function are the index number of the Parameter whose
value has been found to be bad, the severity of the error (notice, warning, or fatal), and a text string
containing the message that should be printed. Note that the action taken by the kernel (whether the
simulation stops or not) is dictated by the selected severity of the error. Once all Parameters have been
checked and any bad ones have been flagged by a call to the foundBadParameter() function, the
ErrorFound() function should be called to exit the Type properly if required. This function need only be
called once during the “first timestep” manipulations call. In the following example, the first Parameter is
read to a local variable called “parValue,” the value of which must be positive.

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

Related Functions: none

[Link]. subroutine initReportIntegral(indx,descrip,units)


This routine initializes an “integrated value” spot in the Simulation Summary Report (SSR) data
structures. The first argument is an integer index indicating which of the spots that was reserved is
currently being initialized. The second argument is a text string containing a description of the variable
being integrated. This text string will appear in the SSR as the heading for the variable in question. The
third argument is a text string indicating the units of the variable’s value.

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')
...

Related Functions: updateReportIntegral( )

[Link]. subroutine initReportMinMax(indx,descrip,units)


This routine initializes a “min / max value” spot in the Simulation Summary Report (SSR) data structures.
The first argument is an integer index indicating which of the spots that was reserved is currently being
initialized. The second argument is a text string containing a description of the variable whose minimum
and maximum are being recorded. This text string will appear in the SSR as the heading for the variable
in question. The third argument is a text string indicating the units of the variable’s value.

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( )

[Link]. subroutine initReportText(indx,descrip,value)


This routine initializes a “text value” spot in the Simulation Summary Report (SSR) data structures. The
first argument is an integer index indicating which of the spots that was reserved is currently being
initialized. The second argument is a text string containing a description of the text field. This text string
will appear in the SSR as the heading for the variable in question. The third argument is a text string
containing the information that the programmer wishes to provide in the text field.

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')
...

[Link]. subroutine initReportValue(indx,descrip,value,units)


This routine initializes a “numerical value” spot in the Simulation Summary Report (SSR) data structures.
The first argument is an integer index indicating which of the spots that was reserved is currently being
initialized. The second argument is a text string containing a description of the variable whose valueis
being reported. This text string will appear in the SSR as the heading for the variable in question. The
third argument is the value of the variable. The fourth argument is a text string indicating the units of the
variable’s value.

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')
...

[Link]. subroutine setDesiredDiscreteControlState(I,j)


A function used by controller components that make use of the Powell’s Method solver. At each iteration
these components should use this function call to tell the TRNSYS kernel what their control decision
would be given the current inputs to the controller. The Powell’s Method solver will not actually make a
control decision until the end of the time step. In this function call, “i” designates the i th controller for the
current Unit (see section [Link] for information on how to set the number of discrete controllers for a
given Unit) while “j” denotes the desired state for the i th controller. As is standard in TRNSYS, a controller
state of 0 indicates that the controlled device should be off while a controller state of 1 indicates that the
controlled device should be on.

Example usage(s)
Integer :: i ,nControllers
...
! turn OFF all of the controllers
Do i=1,nControlers
Call setDesiredControlState(i,0)
EndDo

Related Functions: setNumberofDiscreteControls()

[Link]. subroutine setInputUnits(i,string)


This function registers a three character code as the units of the i th Input of the current Unit. It replaces a
DATA statement setting the YCHECK array and a direct call to the RCHECK() subroutine. The function
must be called once per Input during the “first call” manipulations; it does not need to be called at each
step of the simulation. The TRNSYS kernel registers all of the three character codes for all connected
Inputs and Outputs in the simulation and warns the user if any Input-Output connections have
mismatched units. Refer to the Type57 section of the 04-Mathematical Reference manual for a complete
list of allowable three-character codes. Refer to section [Link] of this manual for information about the
functionality of the RCHECK() subroutine. In the following example, the component has two Inputs: a
temperature and a mass flow rate. Their units are designated by the three-character codes for
“temperature in degrees C” (TE1) and “mass flow rate in kilograms per hour” (MF1).

Example usage(s)
If (getIsFirstCallOfSimulation) Then
...
Call setInputUnits(1,’TE1’)
Call setInputUnits(2,’MF1’)
...
EndIf

Related Functions: setOutputUnits()

7–66
TRNSYS 18 – Programmer's Guide

[Link]. subroutine setIterationMode(i)


A function that sets where a Type will be placed in the Type calling sequence. Various options are
available: the Type is a normal (iterative) component, the Type is an integrator and should be called after
convergence has been reached, the Type is a printer and should be called after the integrators, etc. Refer
to section [Link] for additional information. This function is typically called once during the “first call”
manipulations section.

Example usage(s)
Integer :: i
...
Call setIterationMode(i)

Related Functions: none

[Link]. subroutine setNumberofDerivatives(i)


This function is called once by each Type during the “first call” manipulations. It is used to tell the
TRNSYS kernel how many Derivative values the Type expects there to be in the input file.

Example usage(s)
Integer :: i
...
If (getIsFirstCallofSimulation() ) Then
...
Call setNumberofDerivatives(i)
...
EndIf

Related Functions: getNumberofDerivatives(), getNumericalDerivative()

[Link]. subroutine setNumberofDiscreteControls(i)


A function used by Types to inform the kernel of the number of discrete control variables required by the
current Unit. This function is called during the “first call” manipulations and sets the 11 th spot of the current
Unit’s INFO() array. Refer to section [Link] for additional information. This function is only called by those
components that make use of the Powell’s Method solver. Refer to the SOLVER keyword description in
the 06-TRNEdit manual for additional information on the Powell’s Method solver.

Example usage(s)
Integer :: i
...
Call setNumberofDiscreteControls(i)

Related Functions: setDesiredDiscreteControlState()

[Link]. subroutine setNumberofInputs(i)


This function is called once by each Type during the “first call” manipulations. It is used to tell the
TRNSYS kernel how many Input values the Type expects there to be in the input file.

7–67
TRNSYS 18 – Programmer's Guide

Example usage(s)
Integer :: i
...
If (getIsFirstCallofSimulation() ) Then
...
Call setNumberofInputs(i)
...
EndIf

Related Functions: getNumberofInputs(), getInputValue()

[Link]. subroutine setNumberofOutputs(i)


A function used by Types to inform the TRNSYS kernel of how many OUTPUTS they will be setting. The
kernel reserves this many spots in the global output array structure. This function is typically called once
during the “first call” manipulations section.

Example usage(s)
Integer :: i
...
Call setNumberofOutputs(i)

Related Functions: getNumberofOutputs()

[Link]. subroutine setNumberofParameters(i)


This function is called once by each Type during the “first call” manipulations. It is used to tell the
TRNSYS kernel how many Parameter values the Type expects there to be in the input file.

Example usage(s)
Integer :: i
...
If (getIsFirstCallofSimulation() ) Then
...
Call setNumberofParameters(i)
...
EndIf

Related Functions: getNumberofParameters(), getParameterValue()

[Link]. subroutine setNumberOfReportVariables(:,:,:,:)


This function reserves space in the data structures that are used to generate the Simulation Summary
Report (*.ssr) at the end of a simulation. The four integer arguments correspond (in order of appearance)
to the number of integrated value spots, the number of min/max value spots, the number of numerical
value sports and the number of text string spots that are desired. Note that often this function is called
after a call to the isIncludedInSSR( ) function has returned ‘true.’

Example usage(s)
Integer :: i,j,k,l
...

7–68
TRNSYS 18 – Programmer's Guide

Call setNumberOfReportVariables(i,j,k,l)

[Link]. subroutine setNumericalDerivative(i,derVal)


This function sets the ith numerical derivative to derVal. Calling this function sets the ith spot in the global
DTDT() array to derVal; the TRNSYS kernel will use its innate ability to solve mathematical problems
iteratively to compute corresponding values of the T() array. The T() array values are then accessed by
means of a call to the getNumericalSolution.

Example usage(s)
Integer :: i
Double Precision :: derVal
...

Call setNumericalDerivative(i,derVal)

Related Functions: setNumberOfDerivatives(), getNumberOfDerivatives(), getNumericalSolution(),


getNumericalDerivative(), setNumericalSolution()

[Link]. subroutine setOutputUnits(i,String)


This function registers a three character code as the units of the i th output of the current Unit. It replaces a
DATA statement setting the OCHECK array and a direct call to the RCHECK() subroutine. The function
must be called once per Output during the “first call” manipulations; it does not need to be called at each
step of the simulation. The TRNSYS kernel registers all of the three character codes for all connected
Inputs and Outputs in the simulation and warns the user if any Input-Output connections have
mismatched units (for example if a power output is connected to a pressure input). Refer to the Type57
section of the 04-Mathematical Reference manual for a complete list of allowable three-character codes.
Refer to section [Link] of this manual for information about the functionality of the RCHECK()
subroutine. In the following example, the component has thee Outputs: two temperatures and a mass
flow rate. Their units are designated by the three-character codes for “temperature in degrees C” (TE1),
“temperature in degrees K” (TE3) and “mass flow rate in kilograms per hour” (MF1).

Example usage(s)
If (getIsFirstCallOfSimulation) Then
...
Call setOutputUnits(1,’TE1’)
Call setOutputUnits(2,’TE3’)
Call setOutputUnits(3,’MF1’)
...
EndIf

Related Functions: setInputUnits()

[Link]. subroutine setOutputValue(i,Value)


Once a Type has computed an output value, this function is called in order to send that value back to the
TRNSYS kernel for global storage.

Example usage(s)
Integer :: i
Double Precision :: value

7–69
TRNSYS 18 – Programmer's Guide

...
Call setOutputValue(i,value)

Related Functions: getOutputValue(), setNumberofOutputs()

[Link]. subroutine setTypeVersion(i)


A function that sets the coding standard set for the current Unit. Note that it is the Type’s responsibility to
set the coding standard for which it was written by calling this function.

Example usage(s)
Integer :: typeVersion
...
If (getIsVersionSigningTime() ) Then
Call setTypeVersion(typeVersion)
Return
EndIf

Related Functions: getTypeVersion()

[Link]. subroutine updateReportIntegral(index,intValue)


This function updates an “integrated value” field in the Simulation Summary Report (*.ssr) at the end of a
time step. The first argument is an integer index indicating which of the integrated value fields is to be
updated. The second argument is a double precision containing the present value of the variable. Note
that this subroutine is usually called only if the isIncludedInSSR( ) function has returned ‘true’.

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)
...

[Link]. subroutine updateReportMinmax(index,newValue)


This function updates a “min/miax value” field in the Simulation Summary Report (*.ssr) at the end of a
time step. The first argument is an integer index indicating which of the min/max value fields is to be
updated. The second argument is a double precision containing the present value of the variable. Note
that this subroutine is usually called only if the isIncludedInSSR( ) function has returned ‘true’.

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

...

[Link]. subroutine writeToList(message)


A function that allows Types to write directly to a simulation’s list file (*.lst) without a call to the
Messages() subroutine (refer to section [Link] for additional information about the Messages() routine).
Note that a message written directly to the *.lst file will NOT be written to the *.log file.

Example usage(s)
Use TrnsysConstants, Only :: maxMessageLength
...
Character (len=maxMessageLength) :: messageText
...
Call writeToList(messageText)

Related Functions: none

[Link]. Access Functions for (really, really) Expert Users


The TRNSYS kernel contains a number of access functions that are only used under very rare
circumstances because using them incorrectly can have significant adverse effects on your simulation.
Situations in which these access functions may be useful include calling Types from some other software
tool (i.e. something other than the TRNSYS kernel). In many cases, the following access functions would
be called not by a user-written Type but by a user-written engine that is intended to call Types.

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

Related Functions: none

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()
...

Related Functions: none

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)

Related Functions: getCurrentType()

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)

Related Functions: getCurrentUnit()

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)

Related Functions: getInputValue()

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)

Related Functions: getNumericalSolution()

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)

Related Functions: getParameterValue()

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)

Related Functions: getPreviousControlState()

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)

Related Functions: getSimulationStartTime()

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)

Related Functions: getSimulationStopTime()

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)

Related Functions: getSimulationTime()

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)

Related Functions: getSimulationTimeStep()

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)

Related Functions: getTimestepIteration(), getOverallIteration()

7–75
TRNSYS 18 – Programmer's Guide

7.4.3. The INFO array – Typical Calling Sequence


The INFO array is an integer array of 15 values. It contains a great deal of information about the UNIT
that is currently being called by the kernel. In TRNSYS version 16 and earlier, the contents of the INFO
array was passed to each Type through the argument list. With the release of TRNSYS 17, however the
information was accessed by Types when needed through the use of Access Functions. The contents of
the INFO array for a given unit are given in Table [Link]-1 (see text for detailed explanations).

Table [Link]-1: INFO array contents

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.

Table [Link]-1: INFO(7) values

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.

Table [Link]-1: INFO(8) values

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.

[Link]. INFO(9) and Types calling sequence


INFO(9) indicates if the Type depends on the passage of time and tells TRNSYS where it should go in the
calling sequence. Different options are available: normal (iterative) component, integrator, printer, etc.

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.

Table [Link]-1: INFO(9) values

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.

[Link]. Typical calling sequence for an iterative Type


Table [Link]-1 shows the time and INFO array values for an iterative Type in a typical simulation.
Please note the following:
 INFO(1:5) are set by TRNSYS before calling the Type from information in the input (.dck) file and
should not be modified by the Type. For that reason they are omitted in the table.
 It is assumed that convergence is reached after 2 iterations (after the 3 rd call in a time steps) for all
time steps.
 Start, Stop and Step are respectively the simulation start time, stop time and time step. nO is the
number of outputs set by the Type.
 S is the value set by the Type for INFO(9).
 Values that change are in bold and especially meaningful values have a dark background.
 It is assumed that the total number of iterative calls to the Type in the simulation (which is reported in
the "Iterative call breakdown" in the listing and log files) is nCalls.
 The Type is assumed to follow TRNSYS 16 Standard (i.e. it is not signed as a "15" Type and it does
not use the old storage array)

Table [Link]-1: Typical INFO calling sequence for an iterative Type

Call description Time INFO element

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

7.4.4. Utility Subroutines

[Link]. CallProgram (Calling External Programs)

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]).

A call to CoolProp_Fluid_Properties( ) is of the form:


Integer nref,itype,iflagr
Double Precision prop(9)

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:

PROP(1) temperature of refrigerant (C)

PROP(2) pressure of refrigerant (MPa)

PROP(3) enthalpy of refrigerant (kJ/kg)

PROP(4) entropy of refrigerant (kJ/kg K)

PROP(5) quality (0 < x < 1)

PROP(6) specific volume (m3/kg)

PROP(7) internal energy (kJ/kg)

PROP(8) dynamic viscosity (N s/m2)

PROP(9) thermal conductivity (kJ/hr m K)

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:

itype = 15 or 51 Temperature and Quality

itype = 12 or 21 Temperature and Pressure

itype = 16 or 61 Temperature and Specific Volume

itype = 26 or 62 Pressure and Specific Volume

itype = 25 or 52 Pressure and Quality

7–82
TRNSYS 18 – Programmer's Guide

itype = 24 or 42 Pressure and Entropy

itype = 23 or 32 Pressure and Enthalpy

itype = 34 or 43 Enthalpy and Entropy

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

900 1-Butene 922 Hydrogen Sulfide 113 R113 365 R365MFC

901 Acetone 967 IsoButane (R600a) 114 R114 40 R40


(MethylChloride)

729 Air 923 IsoButene 115 R115 404 R404a

717 Ammonia 924 Isohexane 116 R116 407 R407c

740 Argon 968 Isopentane (R601a) 12 R12 41 R41

902 Benzene 925 Krypton 123 R123 410 R410a

744 Carbon Dioxide 926 Decamethyltetrasiloxane 1233 R1233zd(E) 507 R507a


(MD2M)

903 Carbon Monoxide 927 Dodecamethylpentasiloxane 1234 R1234yf 318 RC318


(MD3M)

904 Carbonyl Sulfide 928 Tetradecamethylhexasiloxane 945 R1234ze(E) 36 SES36


(MD4M)

905 CycloHexane 929 Octamethyltrisiloxane (MDM) 946 R1234ze(Z) 951 SulfurDioxide

906 CycloPropane 930 Hexamethyldisiloxane (MM) 124 R124 952 SulfurHexafluoride

907 CycloPentane 50 Methane 125 R125 953 Toluene

908 Octamethylcyclotetrasiloxane 931 Methanol 13 R13 718 Water


(D4)

909 Decamethylcyclopentasiloxane 932 Methyl Linoleate 134 R134a 954 Xenon


(D5)

910 Dodecamethylcyclohexasiloxane 933 Methyl Linolenate 947 R13I1 955 cis-2-Butene


(D6)

911 Deuterium 934 Methyl Oleate 14 R14 956 m-Xylene

912 Dichloroethane 935 Methyl Palmitate 141 R141B 600 n-Butane

913 Diethyl Ether 936 Methyl Stearate 142 R142B 957 n-Decane

914 Dimethyl Carbonate 720 Neon 143 R143a 958 n-Dodecane

7–83
TRNSYS 18 – Programmer's Guide

915 Dimethyl Ether 937 Neopentane 152 R152a 959 n-Heptane

170 Ethane 728 Nitrogen 161 R161 960 n-Hexane


(Fluoroethane)

916 Ethanol 938 Nitrous Oxide 21 R21 961 n-Nonane

917 Ethyl Benzene 939 Novec649 218 R218 962 n-Octane

1150 Ethylene 940 Ortho Deuterium 22 R22 601 n-Pentane

918 Ethylene Oxide 941 Ortho Hydrogen 227 R227EA 290 n-Propane

919 Fluorine 732 Oxygen 23 R23 963 n-Undecane

948 HFE143m 942 Para Deuterium 236 R236EA 964 o-Xylene

920 Heavy Water 943 Para Hydrogen 949 R236FA 965 p-Xylene

704 Helium 1270 Propylene 245 R245ca 966 trans-2-Butene

702 Hydrogen 944 Propyne 950 R245fa

921 Hydrogen Chloride 11 R11 32 R32

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.

[Link]. Enclosure_17 (formerly ENCLOSURE and ENCL)

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

SPAR a double precision array of 10 values containing the 10 zone geometry


parameters described in the TYPE 19 documentation (parameters 2-11
of geometry Mode 1).
WPAR a double precision array dimensioned to 54, containing the complete list
of window or door geometry parameters described in the TYPE 19
section for geometry Mode 1.
FV a double precision array containing the view factors for all surfaces as
calculated by the subroutine.
currentUnit (integer) the Unit number of the component calling the Enclosure_17
subroutine.
currentType (integer) the Type number of the component calling the Enclosure_17
subroutine.
The subroutines ENCLOSURE and ENCL did not require the currentUnit or currentType arguments but
DID require the following:
INFO the calling TYPE's INFO array.
N is the corresponding line number to jump to if the subprogram is present.
Subroutine Enclosure_17 outputs a table of the view factors between surfaces. The surface numbers are
as specified in the SPAR array.

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

In general, the view factor between i and j is

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 FW 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

[Link]. Fluid_Properties (formerly FLUID_PROPS and FLUIDS)


The double precision utility routine called Fluid_Properties is used to calculate the thermodynamic
properties of various refrigerants based on correlations. In TRNSYS version 15.x and earlier, the routine
was known as “FLUIDS.” In TRNSYS v16.x, a double precision version was added called
“FLUID_PROPS. Arguments to the Fluid_Properties routine should be declared in the calling Type as
DOUBLE PRECISION variables. Given two state properties, the Fluid_Properties routine will return the
complete state of the refrigerant. A call to Fluid_Properties is of the form
Integer :: nRef,iType,iFlagr
Double Precision :: prop(9)
Character (len=2) :: units
...
Call Fluid_Properties(units,prop,nRef,iType,iFlagr)
where

UNITS (character) 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 the refrigerant in question upon entry and the complete state of the
refrigerant upon return from the Fluid_Properties routine. This array
must be dimensioned to 9 in the routine that calls Fluid_Properties. Each
location in this array is described below:
PROP(1) temperature of refrigerant (F, C)
PROP(2) pressure of refrigerant (psi, MPa)
PROP(3) enthalpy of refrigerant (Btu/lbm, kJ/kg)
PROP(4) entropy of refrigerant (Btu/lbm R, kJ/kg K)
PROP(5) quality (0 < x < 1)
PROP(6) specific volume (ft3/lbm, m3/kg)
PROP(7) internal energy (Btu/lbm, kJ/kg)
PROP(8) dynamic viscosity (lbm/ft hr, N s/m2)
PROP(9) thermal conductivity (Btu/hr ft R, kJ/hr m K)
nREF an integer variable denoting the refrigerant to be analyzed.
Available refrigerants are listed along with the required nREF code
number:
R-11 (11)
R-12 (12)
R-13 (13)
R-14 (14)
R-22 (22)
R-114 (114)
R-134A (134)
R-500 (500)
R-502 (502)

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 -40C.

Enthalpies for all other refrigerants are based on the reference state: enthalpy equal to zero at 0C

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

[Link]. GetHorizontalRadiation and GetTiltedRadiation


With TRNSYS releases prior to version 17.0, numerous Types were available for processing solar
radiation data. Historically data was read by Type9 and Type16 was the radiation processor of choice.
With the release of TRNSYS 15, “standard format” weather data such as TMY2, IWEC, and EnergyPlus
weather became more widely available (read by Type89 but still processed by Type16). Users and
developers alike expressed frustration with constantly remaking the connections between Types 89 and
16. Late in the TRNSYS 16 version cycle, two Types were introduced to combine the data reading and
solar radiation processing tasks (Type109 and Type15). The various radiation processing sections of all
these Types began to diverge; enhancements were made in one version and not another, bugs were
fixed here and not there. With the release of TRNSYS 17, all of the solar radiation processing functionality
was moved to a TRNSYS kernel routine called getIncidentRadiation. In an effort for code efficiency, with
the release of TRNSYS 18 the solar radiation routines were split into two separate routines:
GetHorizontalRadiation and GetTiltedRadiation. GetHorizontalRadiation converts the data from the
weather data file (or measured data) into the incident horizontal components and GetTiltedRadiation
applies the selected algorithms for calculating the incident solar radiation on tilted surfaces from the
horizontal solar radiation.

A call to GetHorizontalRadiation is of the form:


Integer :: hMode,shapeMode,iSolarTime,iErrRad
Double Precision :: time,radInput(6),latitude,elevation,shift,solConst
Double Precision :: td1,td2,solar(16)
...
Call GetHorizontalRadiation(time,hMode,shapeMode,radInput,latitude,elevation,shift,&
iSolartime,solConst,td1,td2,solar,iErrRad)
where

time (double precision) the current simulation time [hrs]


hMode (integer) the horizontal radiation mode indicates what input data is
provided as the basis for tilted surface algorithms (1: total horizontal only.
2: total horizontal, ambient temperature and humidity, 3: horizontal beam
and horizontal diffuse, 4: total horizontal and direct normal, 5: total
horizontal and diffuse horizontal, 6: direct normal and diffuse horizontal)
shapeMode (integer) a flag indicating if the sub-data step radiation data should be
shaped by the shape of the extraterrestrial radiation (>0) or that the
radiation has already been interpolated for sub-data step intervals (=0).
radInput (double precision array) contains the six values that are used as inputs to
the tilted surface radiation calculation algorithms. NOTE: not all 6 values
are used during each call, only those corresponding to the selected
hMode.
radInput(1) total solar radiation on the horizontal [kJ/h.m 2]
radInput(2) beam solar radiation on the horizontal [kJ/h.m 2]
radInput(3) diffuse solar radiation on the horizontal [kJ/h.m2]
radInput(4) direct normal solar radiation [kJ/h.m 2]
radInput(5) ambient temperature [C]
radInput(6) ambient relative humidity [%]
latitude (double precision) the latitude of the location for which the solar radiation
calculations are being performed. [deg]

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

radiation (hb=hhor), 10: calculated value of beam radiation on the


horizontal is less than 0, set horizontal diffuse to total horizontal and
horizontal beam to zero, 11: illegal tilt mode specified, 12: illegal latitude
specified, 13: illegal shift value specified, 14: illegal ground reflectance
mode specified.
A call to GetTiltedRadiation is of the form:
Integer :: trackMode,tiltMode,iErrRad
Double Precision :: time,rhoG,slope,azimuth,elevation,solConst,solar(16)
...
Call GetTiltedRadiation(time,rhoG,slope,azimuth,trackMode,tiltMode,elevation, &
solConst,solar,iErrRad)
where

time (double precision) the current simulation time [hrs]


rhoG (double precision) ground reflectance [0..1]
slope (double precision) slope of the surface for which calculations are being
performed. Slope is measured up from the horizontal. [deg]
azimuth (double precision) azimuth of the surface for which calculations are being
performed. The sign convention is 0: facing the equator, ±180: facing
away from the equator, -90: east, 90: west [deg]
trackMode (integer) surface tracking mode. (1: fixed surface (no tracking), 2: the
surface rotates about a vertical axis, 3: the surface rotates about a fixed
(user-defined) axis, 4: the surface 2-axis tracks such that the beam
radiation is always normal to the surface.)
tiltMode (integer) the desired tilted surface radiation processing algorithm (1:
Isotropic Sky model, 2: Hay and Davies model, 3: Reindl model, 4: Perez
1988 model. 5: Perez 1999 model.)
elevation (double precision) the elevation of the location for which the solar
radiation calculations are being performed. [m]
solConst (double precision) the solar constant [kJ/h.m 2]
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.m2]
solar(12) diffuse solar radiation on the tilted surface [kJ/h.m 2]

7–92
TRNSYS 18 – Programmer's Guide

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 getTiltedRadiation (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
radiation (hb=hhor), 10: calculated value of beam radiation on the
horizontal is less than 0, set horizontal diffuse to total horizontal and
horizontal beam to zero, 11: illegal tilt mode specified, 12: illegal latitude
specified, 13: illegal shift value specified, 14: illegal ground reflectance
mode specified.

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.

d1 Hour angle at start of data


d2 Hour angle at end of data

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 anglesd1 and d2 is found. The hour angles d1and d2are 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.

[Link].1.1. Horizontal Radiation Mode

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:

Interval: 0  kT  0.3 ; Constraint: Id/I  1.0

Id/I = 1.020 - 0.254 kT + 0.0123 sin ( ) Eq. 7.4-8

Interval: 0.3 < kT < 0.78; Constraint: 0.1 Id/I  0.97

Id/I = 1.400 - 1.749 kT + 0.177 sin ( ) Eq. 7.4-9

7–95
TRNSYS 18 – Programmer's Guide

Interval: 0.78 < kT; Constraint: 0.1 Id/I

Id/I = 0.486 kT - 0.182 sin ( ) Eq. 7.4-10

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:

Interval: 0  kT  0.3 ; Constraint: Id/I  1.0

Id/I = 1.000 - 0.232 kT + 0.0239 sin ( ) - 0.000682 Ta + 0.0195 (rh/100) Eq. 7.4-11

Interval: 0.3 < kT < 0.78; Constraint: 0.1 Id/I  0.97


Id/I = 1.329 - 1.716 kT + 0.267 sin ( ) - 0.00357 Ta + 0.106 (rh/100) Eq. 7.4-12

Interval: 0.78 < kT; Constraint: 0.1 Id/I


Id/I = 0.426 kT - 0.256 sin ( ) + 0.00349 Ta + 0.0734 (rh/100) Eq. 7.4-13

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).

[Link].1.2. Position of Sun in Sky

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).

cos Z  sin  sin   cos  cos  cos  Eq. 7.4-15

sins = cos sin Eq. 7.4-16


sin Z

[Link].1.3. Surface Tracking Mode

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

Figure 7.4.4–2: Tracking Mode 2 Surface

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

 = tan-1 (tanZ cos(s - )) Eq. 7.4-17

where the surface azimuth is given in terms of the axis azimuth as

 =  + 90 if s -  > 0 Eq. 7.4-18

7–97
TRNSYS 18 – Programmer's Guide

 =  - 90 if s -  < 0 Eq. 7.4-19

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,

sin Z sin( s - )


 =  + tan-1 Eq. 7.4-20
sin  cos

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

Figure 7.4.4–3: Tracking Mode 3 Surface

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.

[Link].1.4. Tilted Surface Radiation Mode

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):

Rb = cos  Eq. 7.4-22


cos  Z
where

cos = cosZ cos + sinZ cos(s - ) sin Eq. 7.4-23

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,

IbT = Ib Rb Eq. 7.4-24

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:

Rr = 0.5 (1 - cos) g Eq. 7.4-25

IgT = I Rr Eq. 7.4-26

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:

Rd = 0.5 (1 + cos) Eq. 7.4-27

Thus the diffuse radiation on a tilted surface assuming isotropic sky is:

IdT = Id Rd Eq. 7.4-28

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

AI = Ibn Eq. 7.4-29


Ion

IdT = Id 0.5 1 - AI 1 + cos  + AI Rb Eq. 7.4-30

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.

The Reindl tilted surface diffuse radiation model is given by:

Ib
f= Eq. 7.4-31
I

IdT = Id 0.5 1 - AI 1 + cos  1 + f sin 3(/2) + AI Rb Eq. 7.4-32

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.

F1 = F11() + F12()  + F13() Z Eq. 7.4-35

F2 = F21() + F22()  + F23() Z Eq. 7.4-36

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

4 1.950 8.87 0.866 -0.381 -0.375 0.203 -0.403 -0.049


5 2.800 13.17 1.026 -0.711 -0.426 0.273 -0.602 -0.061
6 4.500 21.45 0.978 -0.986 -0.350 0.280 -0.915 -0.024
7 6.200 16.06 0.748 -0.913 -0.236 0.173 -1.045 0.065
8 - 13.73 0.318 -0.757 0.103 0.062 -1.698 0.236
The magnitude of the reduced brightness coefficients weight the respective circumsolar, horizon
brightening, and isotropic diffuse radiation components. The angular location of the circumsolar region is
determined by the ratio a/c.

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

IdT = Id 0.5 1-F1 1+cos  + F1 a + F2 sin  Eq. 7.4-38


c
Thus the total radiation incident on a tilted flat surface for all tilted surface radiation modes is

IT = IbT + IdT + IgT Eq. 7.4-39

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.

[Link].1.5. Solar Time Calculation

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,

solar time (hrs) = standard time + E + (Lst - Lloc)/15 Eq. 7.4-40

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

 = 0.5 (1 + 2) Eq. 7.4-41

is used. This is to ensure that the calculated position of the sun will be the average position for the time
step.

The solar time that is used is

solar time = t + E + SHFT/15 Eq. 7.4-42

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

[Link]. InterpolateData (formerly DynamicData, DYNDATA and


DATA)

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

LU (integer) is the FORTRAN logical unit number through which the


performance data is accessed.
nIND (integer) is the number of independent variables (1  nIND  6)
nX is an integer array dimensioned to nIND containing the number of values
of each independent variable to be read from LU. NX(1), NX(2), NX(3),
NX(4), NX(5), and NX(6) are the number of values of X 1, X2, X3, X4, X5,
and X6, respectively.
nY (integer) is the number of dependent (Y) values associated with each set
of independent (X) values (1  nY  10)
X is a double precision array dimensioned to nIND containing the values of
the independent variables for which interpolated Y values are desired
Y is a double precision array of dimension nY containing interpolated
values of the dependent variables

7–104
TRNSYS 18 – Programmer's Guide

DynamicData, DYNDATA, and DATA all required two additional arguments as follows:

INFO is the calling TYPE's INFO array.


N (integer) is the corresponding line number to jump to if the subprogram is
present.

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

Tcond = 20 [°C] Tcond = 50 [°C]

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

10.0 20.0 30.0 !Tevap values

35000. 2.47 !Capacity and COP for Tcond=20°C, and Tevap=10°C


41000. 2.80 !Capacity and COP for Tcond =20°C, and Tevap=20°C
49500. 2.99 !Capacity and COP for Tcond =20°C, and Tevap=30°C

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

[Link]. LinearRegression (formerly DFIT and FIT)

General Description

Subroutine LinearRegression uses linear least-squares regression to determine coefficients of a user


defined correlation. A call to LinearRegression is of the form:
Integer :: nRow,nCol,nCoef,nData,iFlag
Double Precision :: X,Y,PHI
...
Call LinearRegression(nRow,nCol,nCoef,nData,X,Y,PHI,iFlag)
where,

nROW (integer) Row dimension of X in routine calling LinearRegression.


nCOL (integer) Column dimension of X in routine calling LinearRegression.
nCOEF (integer) Number of coefficients in model.
nDATA (integer) Number of data points for the regression.
X Double precision two dimensional array containing the values of the
independent variables to the model. X(I,J) is the value of the
independent variable associated with the ith coefficient of the model and
the jth data point.
Y (double precision) vector containing values of the dependent variable
corresponding to independent variable data points.
PHI (double precision) vector containing the coefficients determined from the
regression.
iFLAG (integer) flag returned indicating the error condition (0 - no error, 1 -
dimension error, 2 - coefficients cannot be determined).
With TRNSYS versions prior to 17, the LienarRegression subroutine was available in two forms: FIT
required single precision arguments, while DFIT used double precision arguments. The routines required
an additional integer argument “N” following the iFlag argument.
*N (integer) the corresponding line number to jump to if the subprogram is
present.

MATHEMATICAL DESCRIPTION

Least-squares regression is used to minimize a function J, where:

 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,

Yj jth data point for dependent variable


Ymodel,j dependent variable of the user's model for the jth data point

7–107
TRNSYS 18 – Programmer's Guide

i ith coefficient to be determined with LinearRegression


Xi,j user defined functions of the independent variable or variables.

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:

G  a0  a1E  a2 E 2  a3 F  a4 F 2  a5 EF Eq. 7.4.4-45

This is the same form as Eq. 7.4.4-44 with:


1-5 = a0-a5

X1,j = 1.0

X2,j = E

X3,j = E2

X4,j = F

X5,j = F2

X6,j = EF

If the following data existed for E, F, and G:

E F G
3.0 0.2 10.0
5.0 0.4 12.5
7.0 0.6 13.1

Then LinearRegression would be called with

NROW = 6 or more (minimum is the # of coefficients,i's)


NCOL = 3 or more (minimum is the # of data points,j's)
NCOEF = 6 (number of coefficients, i's)
NDATA = 3 (number of data points, j's)

7–108
TRNSYS 18 – Programmer's Guide

1.0 1.0 1.0


E1 E2 E3 1.0 1.0 1.0
3.0 5.0 7.0
E1 2 E2 2 E3 2 9.0 25.0 49.0
X= = Eq. 7.4.4-46
F1 F2 F3 0.2 0.4 0.6
.04 .16 .36
F1 2 F2 2 F3 2 0.6 2.0 4.2
EF1 EF2 EF3
10.0
Y = 12.5 Eq. 7.4.4-47
13.1

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)

!ENCLOSURE is present – Continue on.


101 Continue
...

7–111
TRNSYS 18 – Programmer's Guide

[Link]. InvertMatrix (formerly MATRIX_INVERT, INVERT and


DINVRT)
Subroutine InvertMatrix is a double precision routine available to invert a matrix of up to 50 by 50 entries.
In TRNSYS version 15.x and below, the subroutine had two forms; INVERT was a single precision
version and DINVRT was a double precision. With the release of TRNSYS 16.0, the double precision
routine was renamed and recommended for use by all standard and user written Types. INVERT and
DINVRT were maintained for backwards compatibility. The InvertMatrix routine takes a slightly different
list of arguments than did the Matrix_Invert routine. A call to InvertMatrix is of the form
Integer :: NRC,iFLAG
Double Precision :: A
...
CALL InvertMatrix(NRC,N,A,iFlag)
where

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

[Link]. MoistAirProperties (formerly PSYCHROMETRICS and


PSYCH)
This utility routine is available to calculate various moist air properties based on ASHRAE correlations
and the Ideal Gas Law. A double precision version called MoistAirProperties and legacy double and
single precision versions called PSYCHROMETRICS, and PSYCH respectively are available although
PSYCHROMETRICS and PSYCH are only included for backwards compatibility. It is recommended that
all user written routines employ the double precision version and that all non integer arguments to the
MoistAirProperties routine be declared as DOUBLE PRECISION variables in the calling Type. A call to
MoistAirProperties is of the form
Double Precision :: psydat(7)
Integer :: crntUnit,crntTyp,iUnits,mode,wbmode,psydat,eMode,stat
...
Call MoistAirProperties(crntUnit,crntTyp,iUnits,mode,wbmode,psydat,eMode,stat)
where

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

temperatures common to HVAC applications, a correlation (1) is used to


find the wet bulb temperature given enthalpy. For other pressures and
temperatures, a Newton's iterative method is used with the equations
given by ASHRAE (2) to calculate the wet bulb temperature. If the wet
bulb temperature is not needed, WBMODE should be set to 0 to
decrease the computational effort. If WBMODE = 0, the wet bulb
temperature is set to the dry bulb temperature.
PSYDAT an array containing the properties of the moist air. This array must be
dimensioned to 9 in the routine that calls MoistAirProperties. Each
location in this array is described below:
PSYDAT(1) (double precision) The total system pressure in atmospheres. The
subroutine prints a warning if PATM is over 5 atmospheres, which is
considered here to be an upper limit for using ideal gas relations for air
and water mixtures.
PSYDAT(2) (double precision) dry bulb temperature (C).
PSYDAT(3) (double precision) wet bulb temperature (C).
PSYDAT(4) (double precision) relative humidity (fraction).
PSYDAT(5) (double precision) dew point temperature (C).
PSYDAT(6) (double precision) humidity ratio (kg water/kg dry air).
PSYDAT(7) (double precision) enthalpy (kJ/kg dry air).
PSYDAT(8) (double precision) density of the air water mixture (kg/m3)
PSYDAT(9) (double precision) density of the air portion of the mixture (kg dry air/m3)
eMode an integer variable equal to 0, 1, or 2 specifying how warnings are
handled. If EMODE=0, no warnings will be printed. If EMODE=1, only
one warning for each condition will be printed throughout the simulation.
If EMODE=2, warnings will be printed every time step. (EMODE=2 is
useful for program and simulation development, but it can produce an
excessive amount of output).
stat an integer variable equal to 0 through 13 identifying the warning
condition that occurred within subroutine PSYCH. 0 indicates no
warnings. For a complete listing of warnings 1 through 13 the subroutine
source code should be reviewed.
The previous versions of this routine (PSYCHROMETRICS, and PSYCH) did NOT require the crntUnit
and crntType arguments. They did, however, require that the first two arguments were the variable TIME,
and the INFO() array and that the last argument was *N
TIME (double precision) This is the standard TIME used in TRNSYS. It is used
in the MoistAirProperties subroutine only to identify the time at which
warnings or errors occur.
INFO This is the standard integer INFO array used in TRNSYS (see Section
[Link]). It is used in the PSYCHROMETRICS 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.
*N the corresponding line number to jump to if the subprogram is present.

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 100C to
200C. 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 -60C to 70C. A warning is printed if moist air states occur outside this dew point range.

Enthalpies are based on the following reference states:

air enthalpy is zero at 0C

liquid water enthalpy is zero at 0C

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 [Link] MULT. FACTOR ADD. FACTOR


1 °C TE1 1.0 0
2 °F TE2 1.8 32
3 K TE3 1.0 273.15
4 R TE4 1.8 492
Table [Link]-2: LENGTH

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

Table [Link]-9: FORCE

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

4 lbm/s MF4 6.12395 E-04 0


Table [Link]-16: VOLUMETRIC FLOW RATE

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

IU the unit number of the user-written component routine calling the


EQUATER subroutine (integer variable)
INNO the input number with the undetermined input type (integer variable)
INDES the desired input variable type - not used in this capacity, set to ‘NAV’ for
not available (3-character variable)
TRUTYP a 3 character array returning the output variable type connected to this
input (this is the desired result for this application) (3 character variable)
OUTU the unit number of the output connected to the unknown input (not used
in this capacity) (integer variable)
OUTNO the output number of the OUTU unit connected to the unknown input (not
used in this capacity) (integer variable)
ODES the desired output variable type for this unknown input - not used in this
capacity (3-character variable)
X1 the multiplication factor for the INDES variable - not used in this capacity
(double precision value)
A1 the addition factor for the INDES variable - not used in this capacity
(double precision value)
X2 the multiplication factor for the OUTDES variable - not used in this
capacity (double precision value)
A2 the addition factor for the OUTDES variable - not used in this capacity
(double precision value)
ICK1 error flag for calculation (1 = error found) (integer variable)
ICK2 error flag for calculation (1 = error found) (integer variable)

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

[Link]. SolarCellPerformance (formerly SOLCEL)


SolarCellPerformance models silicon cell I-V characteristics. Its argument list is slightly different than it
was in TRNSYS versions 16.x and earlier (at which time it was known as SOLCEL).

Contributor: Professor Don L. Evans, Arizona State University. Tempe, AZ 85281


(Provided as-is. Check the source code for additional information)

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)

RSH Shunt resistance (ohms); (10000)

RSMIN Value of series resistance when it becomes essentially independent of concentration


(ohms); (0.01)

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

[Link]. SolveDiffEq (formerly DIFFERENTIAL_EQN, and DIFFEQ)


The double precision utility routine SolveDiffEQ provides an analytical solution to first-order linear
differential equations that can be written as

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

AA (double precision) is the a coefficient of the differential equation


BB (double precision) is the b coefficient of the differential equation
TI (double precision) is the value of the dependent variable (T) at the
beginning time step
TF (double precision) is the value of the dependent variable (T) at the end of
the time step
TBAR (double precision) is the average value of the dependent variable over
the time step.
The SolveDiffEq routine does not require link checking since it is considered to be a kernel routine (those
routines which must be present to successfully run TRNSYS.)

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

This can be written in the form of Eq. 7.4.4-48 if

 (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

[Link]. Steam_Properties (formerly STEAM_PROPS and STEAM)


The double precision Steam_Properties routine and its legacy double and single precision counterparts
STEAM_PROPS and STEAM are used to calculate the thermodynamic properties of steam based on
correlations from the National Bureau of Standards. Given two state properties, the Steam_Properties
routine will return the complete state of the fluid. A call to Steam_Properties is of the form
Character (len=2) :: UNITS
Double Precision :: PROP(7)
Integer :: iTYPE,iERR
...
Call Steam_Properties(UNITS,PROP,iTYPE,iERR)
where

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

units = ‘SI’ !SI units are desired.


...
temperature = getInputValue(1)
quality = getInputValue(2)
...
prop(1) = temperature
prop(5) = quality
iType = 15
Call Steam_Properties(units,prop,iType,iErr)
If (iErr > 0) Return
...
pressure = prop (2)
enthalpy = prop (3)

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 0C

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

[Link]. Storage of Data between Time Steps


Since a single Type subroutine may be used for several UNITS in one simulation, care must be taken
when storing values that are to be used from one time step to the next. If a tank model, for instance,
requires the initial tank temperature throughout the simulation, simply setting a variable TZERO to the
tank temperature during the “Initialization” manipulations section will not work. When two tanks are used,
the local variable TZERO will be set twice. Throughout the simulation, it will contain the initial temperature
of the second tank. As a result, the first tank will not be modeled correctly.

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.

Two situations typically arise: “Static” and “Dynamic” storage.

[Link].1.1. Static Storage

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.

STATIC STORAGE EXAMPLE

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

C PERFORM INITIAL TIME STEP MANIPULATIONS


If (getIsStartTime() ) Then
...
!set initial values of variables in the double precision storage structure
Call setStaticArrayValue(1,T)

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.

[Link].1.2. Dynamic Storage

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.

In the case of “dynamic” storage, four AccessFunctions are used: setNumberStoredVariables(),


setDynamicArrayInitialValue(), setDynamicArrayValueThisIteration(), and
getDynamicArrayValueLastTimestep()

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.

DYNAMIC STORAGE EXAMPLE

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

C PERFORM INITIAL TIME STEP MANIPULATIONS


If (getIsStartTime() ) Then
...
!set initial value of variables in the dynamic storage structure
Call setDynamicArrayInitialValue(1,T)
...
!return to the calling program
Return
EndIf
...
!retrieve the stored value of the initial temperature for this time step.
TZERO = getDynamicArrayValueLastTimestep(1)
...
!calculate TFINAL based on the initial temperature.
TFINAL = TZERO + ...
...
!update the storage with the calculated value of TFINAL
Call setDynamicArrayValueThisIteration(1,TFINAL)
...

[Link].1.3. DataStorage using TRNSYS v16’s setStorageSize(), getStorageVars() and


setStorageVars()

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

C PERFORM INITIAL TIME STEP MANIPULATIONS

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

C PERFORM FIRST CALL MANIPULATIONS


If (getIsFirstCallOfSimulation() ) Then
...
!reserve space in the double precision storage structure
StorageSize = 2
Call setStorageSize(StorageSize,INFO)
...
!return to the calling program
Return
EndIf

C PERFORM INITIAL TIME STEP MANIPULATIONS


If (getIsStartTime() ) Then
...
!set initial values of variables in the double precision storage structure
Stored(1) = T
Stored(2) = T
Call setStorageVars(Stored, StorageSize,INFO)
...
!return to the calling program
Return
EndIf
...
!retrieve the stored value of the initial temperature for this time step.
Call getStorageVars(Stored,StorageSize,INFO)
TZERO = Stored(1)
...
!calculate TFINAL based on the initial temperature.
TFINAL = TZERO + ...

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

[Link]. ASHRAE_Coefs (formerly TABLE_COEFS and TABLE)


The double precision subroutine ASHRAE_Coefs (and its legacy counterparts double repcision
TABLE_COEFS single precision companion TABLE) return transfer function coefficients corresponding to
the standard walls, partitions, floors, and ceilings given in the ASHRAE Handbook of Fundamentals.
“Double Precision” indicates that the arguments to the TABLE_COEFS routine must be declared in the
calling Type as “DOUBLE PRECISON” instead of as REAL variables. The single precision version (called
TABLE) was the only version available in TRNSYS version 15.x and below. It was retained for backwards
compatibility but every effort should be made to use the double precision version: ASHRAE_Coefs.
ASHRAE_Coefs differs in its argument list from the legacy routine TABLE_COEFS. The ASHRAE_Coefs
routine is used by the TYPE 19 Zone Model. A call to ASHRAE_Coefs is of the form:
Integer :: ITYPE,NTABLE, IU,NBS,NCS,NDS
Double Precision :: B,C,D
...
Call ASHRAE_Coefs(ITYPE,NTABLE,IU,NBS,NCS,NDS,B,C,D)
where

ITYPE an integer variable equal to 1, 2, or 3 denoting which type of surface is


desired. ITYPE = 1 corresponds to roof coefficients, ITYPE = 2 is for
exterior walls, and ITYPE = 3 denotes interior partitions, floors and
ceilings. The tables containing the surface descriptions can be found in
the documentation for TYPE 19; both in this manual and in the
Component Description manual.
NTABLE (integer) number of wall, roof, etc., from the table specified by ITYPE.
NBS (integer) the number of b coefficients for the desired wall as returned by
the subroutine.
NCS (integer) the number of c coefficients for the desired wall as returned by
the subroutine.
NDS (integer) the number of d coefficients for the desired wall as returned by
the subroutine.
B a double precision array dimensioned to 10 that contains the b
coefficients. These are the coefficients for the current and previous sol-
air temperatures (i.e. bo to bNBS-1).
C a double precision array dimensioned to 10 that contains the c
coefficients. These are the coefficients for the current and previous room
temperatures (i.e. co to cNCS-1).
D a double precision array dimensioned to 10 that contains the d
coefficients. These are the coefficients for the previous heat fluxes (d1 to
dNDS).
The obsolete versions of this routine (TABLE_COEF and TABLE) also took an additional 10 th argument
(*N) following the D() array argument:
*N the corresponding line number to jump to if the subprogram is present.
Subroutine ASHRAE_Coefs reads the transfer function coefficient from the file [Link] accessed
through FORTRAN logical unit 8. This logical unit can be changed by modifying a data statement within
the subroutine. After the coefficients have been read for a particular wall, the coefficients are stored
internally within the subroutine for use on subsequent calls to ASHRAE_Coefs.

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

[Link]. Tau_Alpha (formerly TALF)

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.

A call to function Tau_Alpha is of the form


Double Precision :: TAUALF,TAU_ALPHA,THETA,XKL,REFRIN,ALPHA,RHOD
Integer :: N
...
TAUALF = TALF(N,THETA,XKL,REFRIN,ALPHA,RHOD)
The function arguments are interpreted as follows:

N (integer) number of covers


THETA (double precision) angle of incidence (degrees)
XKL (double precision) product of cover thickness and extinction coefficient
REFRIN (double precision) index of refraction
ALPHA (double precision) absorber surface absorptance
RHOD (double precision) reflectance of the N covers to diffuse radiation
If the value of RHOD is not known, then Tau_Alpha can calculate it: When the sixth argument in the
function reference is less than zero, the reflectance of the N covers to diffuse radiation is determined.
The variable used as the sixth argument in the call to Tau_Alpha is then set to this value so that on
subsequent calls to Tau_Alpha the value of RHOD may be supplied.

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

sin 2 (1   2 ) tan 2 (1   2 )


1  Eq. 7.4.4-51 2  Eq. 7.4.4-52
sin 2 (1   2 ) tan 2 (1   2 )

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
21  (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

IOPT- indicates to TYPECK what kind of check to perform:


<0 the compilation will be terminated immediately after printing
an explanatory error message.
>0 the simulation will be terminate after all UNITS have been
called once or 20 error messages have been issued.
1 or -1 check the number of user furnished INPUTS,
PARAMETERS, and DERIVATIVES from the INFO array
against the values of NI, NP, and ND. An error message will
be printed only if TYPECK finds an error.
2 or -2 TYPE routine has found unspecified error and wants
TYPECK to flag it.
3 or -3 TYPE routine has found a bad INPUT or number of INPUTS
and wants TYPECK to flag it.
4 or -4 TYPE routine has found a bad PARAMETER or number of
PARAMETERS and wants TYPECK to flag it.
5 or -5 TYPE routine has found a bad DERIVATIVE or number of
DERIVATIVES and wants TYPECK to flag it.
6 TYPE routine has determined that the maximum number of
UNITS of that TYPE has been exceeded and wants
TYPECK to flag it and stop the simulation.
INFO- TYPE's INFO array containing pertinent bookkeeping data on the UNIT
(see Section [Link]).
NI- correct number of INPUTS
NP- correct number of PARAMETERS
ND- correct number of DERIVATIVES

[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.

(X2, Y2, Z2)

(X1, Y1, Z1)


1
(X3, Y3, Z3)
Z

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 cos1 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

S  X d 2  X d 1 2  Yd 1  Yd 2 2  Z d 2  Z d 1 2 Eq. 7.4.4-66

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

 
SN
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

If nz is arbitrarily chosen to be 1, then

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

7.4.5. Solving Differential Equations


TRNSYS versions 11.1 and higher provide two methods for solving differential equations which may
occur in component models: an approximate analytical solution using the subroutine SolveDiffEq (see
Section [Link]), and a numerical solution using one of three numerical methods (see Manual 06-
TRNEdit). The analytical method is recommended whenever practical it is possible to write the differential
equation in the following general form:

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.

Double Precision :: qDot,C


...
Call setNumericalDerivative(1,qDot/C)
...
Call setOutputValue(2,getNumericalSolution(1))
...
As a point of reference, this same code would appear in TRNSYS coding standards prior to that of
version 17.x as the following:
Double Precision :: qDot,C
.
.
DTDT(1) = qDot / C
.
.
OUT(2) = T(1)
.
.

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

7.4.6. Use of the Alternate Return (RETURN 1)


In the coding standards between TRNSYS 14.1 and 16.x (inclusive) TRNSYS checked to make sure that
all routines required by the TRNSYS input file were included in the TRNSYS executable file by utilizing
the FORTRAN alternate return. In previous TRNSYS versions (prior to 14.1) run with compilers allowing
unresolved externals, unlinked subroutines were not checked and were often the source of strange
errors. In TRNSYS versions 17 and later, the link check was made in a manner that did not require the
alternate return. Since the alternate return was a difficult concept for users to grasp, its use was
sunsetted. This section is included in the documentation in case users encounter Types that use the
“RETURN 1” The following example should help the user understand the workings of the alternate return.
C* CALLING PROGRAM **
Call TYPE2(TIME,XIN,OUT,T,DTDT,PAR,INFO,ICNTRL,*101)
100 Write(*,*) ‘ERROR - TYPE 2 IS NOT LINKED !’
Return 1
101 Continue
.
.
C* CALLED SUBROUTINE **
Subroutine TYPE2(TIME,XIN,OUT,T,DTDT,PAR,INFO,ICNTRL,*)
.
Return 1
The calling program will call the TYPE 2 subroutine and return to line 101 when the subroutine
calculations are completed due to the RETURN 1 line in the TYPE 2 subroutine. If the RETURN 1 is
missing from the TYPE 2 subroutine or the subroutine is not linked, the program will return to line 100 of
the calling program and the error message will be flagged.

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

7.4.7. Use of the ICNTRL Array


The ICNTRL array, which was new to version 14, conveyed to the component subroutines (TYPE1,
TYPE2, etc.) and to the TRNSYS equation processor, the states of discrete controller variables when the
Powell’s Method solver was employed in a simulation. With the release of the TRNSYS 17 component
coding standard, the ICNTRL() array was no longer passed to Types through an argument list but was
made available through the access functions setNumberofDiscreteControls() and
setDesiredControlState(). Refer to sections [Link] and [Link] respectively for additional information.

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

7.5. Converting Types from earlier TRNSYS


Versions
As programming standards have evolved, so too have the conventions required by TRNSYS Types. The
following sections provide the user with information on the steps required to convert Types written for
earlier versions of TRNSYS to later versions.

7.5.1. Converting components from version 13.x to the


version 14.1 coding standard
TRNSYS routines written for version 13.1 or earlier have to be modified for use with TRNSYS version
14.1 and higher. The steps are summarized below for convenience - refer to the sections listed for full
details.

1) Change the TYPE specification from:


CALL TYPEn(TIME,XIN,OUT,T,DTDT,PAR,INFO)
to:
CALL TYPEn(TIME,XIN,OUT,T,DTDT,PAR,INFO,ICNTRL,*)
2) Replace all RETURN statements in the subroutine with RETURN 1
Failure to replace all returns will result in an unlinked subroutine error. (see Section 7.4.6)

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.5.2. Converting components from version 14.1 to the


version 14.2 coding standard
TRNSYS routines written for version 14.1 have to be modified for use with TRNSYS 14.2 for Windows.
The Windows operating system does not deal well with two common features of TRNSYS version 14.1
subroutines. The steps are summarized below for convenience.

1) Change any statements that contain a STOP statement from:


STOP

7–157
TRNSYS 18 – Programmer's Guide

to the following if the Stop occurred in the primary Type subroutine:


CALL MYSTOP(1001)
RETURN 1
or to the following if the Stop occurred in a secondary subroutine:
CALL MYSTOP(1001)
RETURN
The number 1001 can be changed to another error number if so desired.

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.5.3. Converting components from version 14.2 to the


version 15.x coding standard
There are no modifications necessary to a TRNSYS 14.2 Type in order for it to be used with TRNSYS
version 15.x.

7.5.4. Converting components from version 15.x to the


version 16.x coding standard
TRNSYS 15 components can be updated to TRNSYS 16 in two ways:
 After 2 steps that do not require any programming knowledge, you can run TRNSYS 15 Types
in a "legacy TRNSYS 15" mode, where all the information exchange with the Kernel is identical to
what was happening in TRNSYS 15. This implies that you will not benefit from some of the new
features:
 General use of double precision
 Added security and user-friendliness thanks to access functions, etc.
 Drop-in DLL's: Types running in "legacy TRNSYS 15 mode" must be linked to the main
TRNSYS DLL ([Link]).
You will also have to be careful if you are interested in the system response just after initialization:
Because of the change in the definition of the initial time step, TRNSYS 15 Types might give an
incorrect answer just after the simulation start.
Simple components can be put into external DLLs in legacy mode. However, if the Type needs to
call one of the TRNSYS utility routines, it needs to be fully updated so that it can call the double
precision versions of those routines instead of the outdated single precision versions.
 You can also fully convert an existing component to the TRNSYS 16 standard by following a
systematic procedure. The difficulty of that procedure and the time required to perform the

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.

[Link]. Steps to use TRNSYS 15 components in "legacy mode"


The following 2 steps are required in order to use TRNSYS 15 Types in TRNSYS 16. If you want to use
your Type in a "TRNSYS 15 legacy mode", this is all you need to do. If you want to fully convert your
Types to the TRNSYS 16 standard, you will find additional instructions in section 0. Note that the steps
listed in this section are also required to fully convert existing TRNSYS 15 Types. NOTE: If you choose
to use your component in “legacy mode” the Type cannot be placed in an external DLL; it must be
compiled and linked into [Link] along with TRNSYS’s standard components.

Export the name of the routine (Typennn)

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.

Version sign the Type

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).

[Link]. Instructions on converting TRNSYS 15 Types to the


TRNSYS 16 standard
The steps required in order to convert an existing Type to the TRNSYS 16 standard are given in the
following sections. The first two steps are the same as the steps required to run TRNSYS 15 Types in
"legacy mode" (except that the Type is signed as a "Version 16" Type). Please note that if you have a
Type that was written for a TRNSYS version prior to TRNSYS 15, steps for converting those Types are
listed in sections 7.5.1, 7.5.2, and 7.5.3, of this manual.

Export the name of the routine (TYPEnnn)

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.

Special calls identified by INFO(7:8) and INFO (13)

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.

[Link].1.1. Version sign call (INFO(7) = -2)

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

[Link].1.2. Initialization (pre-simulation) call (INFO(7) = -1)

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.

[Link].1.3. New significance of the first time step (TIME = TIME0)

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.

The manipulations that a component should make at TIME = TIME0 are:


 read parameter values and set them to local variable names
 check parameters for validity. For example, you might want to check to see if the specified specific
heat is negative and generate an error if it is. Note that
 set outputs to initial conditions or 0
 return 1: no other manipulations should be made during this call.

[Link].1.4. "Post convergence" call (INFO(13) = 1)

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.

[Link].1.5. Final call after the simulation is done (INFO(8) = -1)

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.

Double precision variables

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)

Access to global constants: the "TrnsysConstants" module

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

myFormatString = '(' // trim(adjustl(myFormatString)) // 'a1)'


myString = 'Hello world'
write(*,myFormatString) trim(myString)
We recommend that you use string variables rather than character arrays when possible.

Access to Kernel variables: Access Functions and the "TrnsysFunctions" module

[Link].1.6. Why access functions?

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.

All access functions are listed in section 7.4.2.

[Link].1.7. How to use access functions

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

TRNSYS 16 double precision :: delt, x, s



delt = getSimulationTimeStep()

s = s+x*delt

7–164
TRNSYS 18 – Programmer's Guide

[Link].1.8. Note on external DLL's

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.

Data storage (the "S array")

[Link].1.9. Storage in TRNSYS 15

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.

[Link].1.10. Storage in TRNSYS 16

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.

The "Messages" subroutine

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.

Utility subroutine calls

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

Single precision Double precision Arguments that need to be changed from


routine routine single to double precision
PSYCH Psychrometrics TIME, PSYDAT
DATA DynamicData X, Y
TALF TauAlpha THETA,XKL, REFRIN, ALPHA, RHOD
DIFFEQ Differential_Eqn TIME, AA, BB, TI, TF, TBAR
ENCL Enclosure SPAR, WPAR, FV
VIEW ViewFactor A, B, C, D, E, F, G, H, X3, Y3, Z3
TABLE Table_Coefs B, C, D
INVERT Matrix_Invert A
DINVRT Matrix_Invert A
FLUIDS Fluid_Props PROP
STEAM Steam_Props PROP

Additional information on Utility Subroutines can be found in section 7.4.4.

7–166
TRNSYS 18 – Programmer's Guide

7.5.5. Converting components from version 16.x to the


version 17.x coding standard
There are no required changes that a user must make to components that were written in the TRNSYS
16 coding standard in order for them to work the same in TRNSYS 17. However, a major effort was made
in developing TRNSYS 17 to simplify the structure of components so it may be worth the user’s effort to
update to the more recent standard. Furthermore, while every effort is made to maintain backwards
compatibility from one major TRNSYS version release to the next, there may come a time when the
developers decide to sunset backwards compatibility for older and older versions.

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 user now implements the following:


If (NODES_X < 1) Call foundBadParameter(19,’Fatal’,’The number of nodes in the “x”
direction cannot be fewer than 1.’)

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.

[Link]. The Subroutine Call


The TRNSYS kernel no longer automatically passes information to the TRNSYS components;
components are required to get the information that they need from the TRNSYS kernel using Access
Functions (see Section 7.4.2 for a complete list of Access Functions). As a result of this change, the very
first line of the Type should be changed from
SUBROUTINE TYPEnnn(TIME,XIN,OUT,T,DTDT,PAR,INFO,ICNTRL,*)

to
Subroutine TYPEnnn

where nnn is the Type number in both cases.

[Link]. Set Global Simulation Variables


The current value of the simulation time used to be passed to Types by the kernel through the subroutine
argument list. Since the argument list has been removed, Types now need to go and get various values.
Almost all Types will need to go and get the current simulation time. Most types will also need to know
their UNIT and TYPE number. The following lines need to be added
Time = getSimulationTime()

7–167
TRNSYS 18 – Programmer's Guide

currentUnit = getCurrentUnit()
currentType = getCurrentType()

[Link]. Identify the Type’s Coding Standard (version signing)


A new access function was added to simplify the method by which the Type identifies its coding standard
to the kernel. The following section of the Type should be changed from
C SET THE VERSION INFORMATION FOR TRNSYS
IF(INFO(7).EQ.-2) THEN
INFO(12)=16
RETURN 1
ENDIF

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.

[Link]. Perform “Last Call” Manipulations


A new access function was added to simplify the method by which the Type knows that the current call is
the very last call in the simulation. The following section of the Type should be changed from
C PERFORM LAST CALL MANIPULATIONS
IF(INFO(8).EQ.-1) THEN
...
RETURN 1
ENDIF

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.

[Link]. Perform “End of Time Step” Manipulations


A new access function was added to simplify the method by which the Type knows that this is the “end of
timestep” call that the kernel makes to each Type at the end of a time step after convergence has been
reached (or after the kernel has decided that convergence cannot be reached) but before the simulation
time has advanced. The following section of the Type should be changed from
C PERFORM POST CONVERGENCE MANIPULATIONS
IF(INFO(13).GT.0) THEN

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.

[Link]. Perform “First Call” Manipulations


In the TRNSYS 16 coding standard, Types were expected to carry out a series of steps to introduce
themselves to the TRNSYS kernel (before time has begun to advance). These were as follows:
 Set the first and second spots in the INFO() array to local variables IUNIT and ITYPE
 Reserve space in the global OUT() array
 Set the Type’s place in the global Type-calling structure (the ninth spot in the INFO() array).
 Call the TYPECK() subroutine to check and make sure that the user had provided the correct
number of PARAMETERS, INPUTS, and DERIVATIVES.
 Set the 3-digit codes for the Type’s INPUTS and OUTPUTS and call the RCHECK() routine so that
the kernel can check the user’s input/output connections.
 Reserve space in the kernel’s single-precision global storage structure (ONLY for legacy TRNSYS
15 coding standard Types)
 Reserve space in the kernel’s double-precision global storage structure (if necessary)

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)

TRNSYS 17 coding standard:

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:

TRNSYS 17 Call SetNumberofOutputs(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:

TRNSYS 17 Call SetIterationMode(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.

TRNSYS 16 CALL setStorageSize(xFer,nItems,INFO)


coding standard:

TRNSYS 17 Call setNumberStoredVariables(0,nItems)


coding standard:

 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.

TRNSYS 16 CALL TYPECK(1,INFO,nI,nP,nD)


coding standard:
Call SetNumberofParameters(nP)
TRNSYS 17 Call SetNumberofInputs(nI)
coding standard: Call SetNumberofDerivatives(nD)

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:

[Link]. Perform “Start Time” Manipulations


In both the TRNSYS 16 and TRNSYS 17 coding standards, the component reads it parameters at the
initial time step and sets output initial values. It should NOT read its inputs or simulate performance since
simulation time has not yet advanced.
 The first step, again, is to check whether or not the current call is the “initial time step” call. In the
TRNSYS 16 coding standard, this was accomplished by checking whether time had advanced yet.
Note that again the “RETURN 1” is replaced with a simple “RETURN” In the TRNSYS 17 standard,
an access function is provided:
IF([Link].(TIME0+DELT/2.)) THEN
TRNSYS 16 coding standard: ...
RETURN 1
ENDIF

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)

TRNSYS 17 ! there is no code required to replace these lines.


coding standard:

 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

! Set the Initial Values of the Outputs


Call setOutputValue(1,getInputValue(1))
Call setOutputValue(2,getInputValue(2))
TRNSYS 17 Call setOutputValue(3,0.d0)
coding standard: Call setOutputValue(4,0.d0)
Call setOutputValue(5,0.d0)
! Return to the TRNSYS kernel
Return

[Link]. Rereading Parameters


If two or more instances of a given Type are to be used in a simulation, it is necessary to reread the
parameter values so that the local variables within the Type’s code reflect the values associated with the
current instance. In the TRNSYS 16 coding standard, this was accomplished by checking whether the 1st
spot of the INFO() array was equal to the local variable iUnit. Again, this check is replaced by an access
function call.
!ReRead the Parameters if another Unit of this Type was called
last
IF(INFO(1).[Link]) THEN
!reset the unit number
IUNIT = INFO(1)
TRNSYS 16 ITYPE = INFO(2)
coding standard: !read the parameter values
QMAX = PAR(1)
CP = PAR(2)
UA = PAR(3)
HTREFF = PAR(4)
ENDIF
!ReRead the Parameters if another Unit of this Type was called
last
If (getIsReReadParameters()) Then
TRNSYS 17 qmax = getParameterValue(1)
coding standard: cp = getParameterValue(2)
ua = getParameterValue(3)
htreff = getParameterValue(4)
Endif

[Link]. Retrieving Input Values


Each Type retrieves its own inputs. In the TRNSYS 16 coding standard, this involved reading the
contents of the XIN() array to local variables. In TRNSYS 17 coding, an access function is employed:
!Get the Current Inputs to the Model
TIN = XIN(1)
TRNSYS 16 FLOW = XIN(2)
coding standard: IGAM = JFIX(XIN(3)+0.1)
TSET = XIN(4)
TAMB = XIN(5)
!Get the Current Inputs to the Model
tin = getInputValue(1)
TRNSYS 17 flow = getInputValue(2)
coding standard: igam = JFIX(getInputValue(3)+0.1)
tset = getInputValue(4)
tamb = getInputValue(5)

7–173
TRNSYS 18 – Programmer's Guide

[Link]. Other Considerations


User written Types often make use of other utility subroutines (such as steam or psychrometric
properties), solve differential equations (using either analytical or numerical solution techniques), or use
inter-time step data storage. If such features are relevant to the Type you are converting, please refer to
the corresponding section of this manual for information about the access functions that have replaced
many of the direct calls to utility subroutines. The present discussion is limited to those manipulations that
are common to every TRNSYS component.

7.5.6. Converting components from version 17.x to the


version 18.x coding standard
There are no changes required to move a component from the TRNSYS 17.x Type coding standard to the
TRNSYS 18.x Type coding standard. Users may, if they wish, implement the Simulation Summary Report
(SSR) Access Functions as discussed in section 7.3.17.

7–174
TRNSYS 18 – Programmer's Guide

7.6. Working with the Intel Visual FORTRAN


Compiler
The following sections give detailed information on the compiler settings used to rebuild [Link] and to
compile and build external DLLs such as MyType. The TRNSYS developers recompile the main dynamic
link library ([Link]), with the Intel Visual Fortran compiler, which plugs into MS Visual Studio. It may
be possible to recompile and relink both the [Link] and other dynamic link libraries using other
compilers but it is not a trivial process.

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.6.1. Rebuilding the [Link] with Intel Visual FORTRAN


Composer
The following sections give detailed information on the compiler settings used to rebuild [Link]. They
are for reference only. They result in the creation of an Intel Visual Fortran “solution.” However, such a
“solution” is already provided. To use the provided "solution," launch Intel Visual FORTRAN Composer,
go to "File/Open Solution" and select the following file: %TRNSYS18%\Compilers\TRNSYS\[Link].
You do not have to modify any settings to recompile and debug TRNSYS if you use the project included
in the distribution. The instructions hereunder are for reference only. They explain how this solution was
created and give all modifications to default settings.

[Link]. Creating a TRNSYS Solution


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).
 Go to File/New, select the "Blank Solution" option
 In "name", type in "Ivf11CXE" (without the quotes)
 For "Location", browse to %TRNSYS18%\Compilers
 Click OK. This will create the file %TRNSYS18%\Compilers\IvfCXE\[Link]

[Link]. TRNDll project


The TRNSYS kernel and the standard components are compiled and linked into one DLL, [Link]. To
create the project:
 Go to File / New / Project
 Under "Project Types", select "Intel ® Fortran Project"
 Under "Templates", select "Dynamic-link Library"
 Type in "TRNDll64" for the name
 Select the radio button ‘Add to Solution’.
 Click OK.
 This will open the "Fortran Dynamic Link Library Wizard" window.
 Select "DLL Settings" under "Overview", in the left frame, and choose "Empty Project" as the DLL
Type.
 Click "Finish".
 This will create the following Project file with default settings:
%TRNSYS18%\Compilers\IvfCXE\TRNDll64\[Link]

[Link]. Project settings


In the Solution Explorer (right-hand window by default), right-click on the TRNDll project and select
"Properties".

7–176
TRNSYS 18 – Programmer's Guide

Figure [Link]-1: Solution explorer, with TRNDll64 project.

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.

Figure [Link]-2: TRNDll64 properties window. Select ‘All 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

Table [Link]-1: TRNDll Settings – IVF Composer XE, All Configurations

Branch Category Parameter Value


Suppress Startup Banner Yes
General
Additional Include Directories ..\..\..\SourceCode\Include
Optimization Disable
Language Fixed form line length 132 columns
Use Other Powerstation run-
Compatibility Yes
time behavior
Fortran Local Variable Storage All Variables SAVE
Data Initialize Local Saved Scalars to
Yes
Zero
Extend precision of Single-
Floating Point Yes
Precision Constants
Calling convention C,REFERENCE
External
procedures Name Case Interpretation Upper Case
Run-time Runtime Error Checking All
Enable Incremental Linking No
General
Linker Suppress Startup Banner Yes
System SubSystem Windows
In the "configuration" drop-down list box, select "Debug". We will now choose the settings that only apply
to the Debug configuration. Here again, only the settings that must be changed from their default values
are mentioned.

Table [Link]-2: TRNDll Settings – IVF Composer XE, Win64 Debug

Branch Category Parameter Value


Command ..\..\..\Exe\[Link]
You can optionally enter the name of the deck file that you
Debugging
Command arguments wish to debug here, to bypass the file/open dialog in
[Link]
Preprocessor
General Add ‘TRNSYS_DEBUG’
Definitions
Generate traceback
Yes
Fortran information
Run-time
Runtime Error
All
Checking
Libraries Runtime library Debug Multithreaded DLL
copy "x64\Debug\[Link]" "..\..\..\Exe\[Link]"
Command Line
Build Post-build copy "x64\Debug\[Link]" "..\..\..\Exe\[Link]"
events Event Copying Debug [Link] and [Link] to the Exe
Description
folder
In the "configuration" drop-down list box, select "Release". We will now choose the settings that only
apply to the Release configuration. Here again, only the settings that must be changed from their default
values are mentioned.

Table [Link]-3: TRNDll Settings – IVF Composer XE, Win64 Release

Branch Category Parameter Value


Libraries Runtime library Multithreaded
Fortran Use Other Yes (/fpscomp:general)
Compatibility PowerStation Run-
time Behavior
Post-build copy "x64\Release\[Link]" "..\..\..\Exe\[Link]"
Build Command Line
Event copy "x64\Release\[Link]" "..\..\..\Exe\[Link]"

7–178
TRNSYS 18 – Programmer's Guide

events Copying Release [Link] and [Link] to the Exe


Description
folder
Linker Optimization References Keep unreferenced data

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

[Link]. Project files


 In the Solution Explorer, you can optionally remove the "Header Files" and "Resource Files" folders
under "TRNDll64", since they are not used (right-click on the folder and select "Remove").
 Add Kernel routines:
 Right-Click on "Source Files" under the "TRNDll64" project.
 Select "Add", then "New Folder".
 Create a folder and rename it to "Kernel".
 Right-click on that newly-created folder and select "Add", then "Add Existing Item".
 Browse to %TRNSYS18%\SourceCode\Kernel and select all *.for and *.f90 files.
 Click OK to add the files to the project.
 Add Standard Types:
 Go back to the "Source file" folder.
 Right-click on it and choose "New folder".
 Create the "Types" folder.
 Right-click on this folder and choose "Add", then "Add Existing Item".
 Browse to %TRNSYS18%\SourceCode\Types and select all *.f90 (and *.for files if any).
 Click OK to add the files to the project.

[Link]. Building [Link]


 Make sure the right project (TRNDll64) is active (its name should be in bold characters in the
Solution Explorer). If not, make it active (Select, right-click, choose "Set as StartUp Project").
 Select the appropriate configuration (Debug or Release) in Build/Configuration Manager
 Go to Build/Rebuild Solution

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

7.6.2. Instructions to add a new project to the IvfCXE2011


Solution
This section explains how to add a new project to the TRNSYS Solution provided with TRNSYS 18 in
order to create a library of user components.

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.

[Link]. TRNSYS Solution


The solution is %TRNSYS18%\Compilers\TRNSYS\[Link]

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).

[Link]. New Project


 Go to File / New / Project
 Under "Project Types", select "Intel ® Fortran Project"
 Under "Templates", select “Library” and then "Dynamic-link Library"
 Type in "MyDLL" for the name. You may select a different name for your application, or rename it
at the end of these instructions.
 Check the "Add to solution" radio button. The Location will be adapted automatically and should
say: %TRNSYS18%\Compilers\TRNSYS
 Click OK.
 This will create the following Project file with default settings:
%TRNSYS18%\Compilers\TRNSYS\MyDll\[Link]. You should now see a new project called
“MyDLL” appear in the Solution Explorer window.

Figure [Link]-1: Solution explorer, with projects ‘TRNDll64’ and ‘MyDll’.

7–180
TRNSYS 18 – Programmer's Guide

[Link]. Project settings


In the Solution Explorer (right-hand window by default), right-click on the project ‘MyDll’ and select
"Properties".

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

Branch Category Parameter Value


Local Variable Storage All variables SAVE
Data Initialize Local Saved Scalars to
Yes
Zero
Fortran Floating Extend precision of Single
Yes
Point precision constants
External Calling convention C, REFERENCE
procedures Name case interpretation Upper Case
In the "configuration" drop-down list box, select "Debug". We will now choose the settings that only apply
to the Debug configuration. Here again, only the settings that must be changed from their default values
are mentioned.

Table [Link]-2: New Dll Settings – IVF Composer XE, Win64 Debug

Branch Category Parameter Value


Command ..\..\..\Exe\[Link]
You can optionally enter the name of the deck file that
Debugging
Command arguments you wish to debug here, to bypass the file/open dialog
in [Link]
Additional Include
Preprocessor ..\..\..\SourceCode\Include, ..\TRNDll\x64\Debug
Directories
Libraries Runtime library Debug Multithreaded
Fortran
Runtime Error Checking All
Run-time Generate Traceback
Yes
Information
copy "x64\Debug\[Link]"
Build Post-build Command Line
"..\..\..\UserLib\DebugDLLs\[Link]"
events Event
Description Post-build: Copying .dll to the UserLib folder
In the "configuration" drop-down list box, select "Release". We will now choose the settings that only
apply to the Release configuration. Here again, only the settings that must be changed from their default
values are mentioned.

Table [Link]-3: TRNDll Settings – IVF Composer XE, Win64 Release

Branch Category Parameter Value


Additional Include
Preprocessor ..\..\..\SourceCode\Include, ..\TRNDll\x64\Release
Fortran Directories
Libraries Runtime library Multithreaded
copy "x64\Release\[Link]"
Build Post-build Command Line
"..\..\..\UserLib\ReleaseDLLs\[Link]"
events Event
Description Copying .dll to the UserLib folder
Notes:

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

[Link]. Project files


 In the Solution Explorer, you can optionally remove the "Header Files" and "Resource Files" folders
under "MyDll", since they are not used (right-click on the folder and select "Remove").
 Add the source file(s) for your Type(s) and possibly the routines, modules, etc. that they require
 Create a folder called "Libraries" under MyDll and add the [Link] file that is found under the
folder %TRNSYS18%\Compilers\TRNSYS\TRDll\x64\Debug. This will allow your DLL to use all
the symbols exported by TRNSYS (including the TrnsysFunctions).

[Link]. Building MyDLL


 Make sure the right project (MyDll) is active (its name should be in bold characters in the Solution
Explorer). If not, make it active (Select, right-click, choose "Set as StartUp Project").
 Select the appropriate configuration (Debug or Release) in Build/Configuration Manager
 Go to Build/Rebuild Solution

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

7.7. Programming a Type in C++


It is also possible to program a TRNSYS type using C++ as long as the DLL created by the compiler
correctly exports the Type. The general structure of the Type is the same as documented previously in
this volume. This chapter will highlight a number of the specific changes needed to use C++. In the
%TRNSYS18%\SourceCode\Templates directory, there is a header file (TRNSYS.h) needed for C++ and
an example Type written in C++ (CppType(v17).cpp).

7.7.1. Header File (TRNSYS.h)


The TRNSYS.h header file provides the interface for the TRNSYS functions and subroutines. The most
commonly used functions and subroutines have been included in the header file. Some of the more
advanced functions and subroutines that should only be used by expert users have not been included. If
these routines a needed, the programmer should have the knowledge to add these routines in the header
file when needed.

7.7.2. Type Declaration


In C++ the Type declaration and the DLL export is complete in the same line.

extern "C" __declspec(dllexport) void TYPEnn(void){}

Where nn refers to the Type number. Please refer to section 7.3.2 for guidance in
selecting the number for the Type.

7.7.3. Calling TRNSYS functions


The communication between C++ and FORTRAN can be a bit tricky. This section will give guidance in
how to correctly call five category of function calls: calling a TRNSYS Boolean function, passing a number
to TRNSYS, receiving a number from TRNSYS, passing a string to TRNSYS, and receiving a string from
TRNSYS. Not all of the possible function calls will be given an example here, but the examples here
should give you enough information to create any of the function calls used in TRNSYS.

[Link]. Calling a TRNSYS Boolean Function


No special syntax is needed for receiving the Boolean function value from TRNSYS. To call these
routines use a similar syntax as below for determining if this is the first call of the TRNSYS simulation.

if (getIsFirstCallofSimulation()) {}

7–183
TRNSYS 18 – Programmer's Guide

[Link]. Calling a Function that Passes a Number to TRNSYS


If you are passing a number from a C++ Type to TRNSYS use a similar syntax as below for setting the
number of Parameters for your Type.
int npar = 3;
setNumberofParameters(&npar);

[Link]. Calling a Function that Receives a Number from TRNSYS


If you are receiving a number from TRNSYS to a C++ Type use a similar syntax as below for getting the
value of a Parameters for your Type.
double qmax;
int index = 1;
qmax = getParameterValue(&index);

[Link]. Calling a Function that Passes a String to TRNSYS


String variables work very differently between FORTRAN and C++ and passing the strings back and forth
can be difficult. The TRNSYS code is compiled to expect the length of the string variable to be passed at
the end of the function call. The TRNSYS.h header file has been set-up following the same convention. If
you are passing a string from the C++ Type to TRNSYS use a similar syntax as below for passing an
error message to TRNSYS.
int CurrentUnit, CurrentType;
int errorCode = -1;
char type[20];
char message[400];
CurrentUnit = getCurrentUnit();
CurrentType = getCurrentType();
strcpy_s(type, "Fatal");
strcpy_s(message, "The error message for TRNSYS to print.");
messages(&errorCode, message, type, &CurrentUnit, &CurrentType,
(size_t)strlen(message), (size_t)strlen(type));

[Link]. Calling a Function that Receives a String from TRNSYS


String variables work very differently between FORTRAN and C++ and passing the strings back and forth
can be difficult. The TRNSYS code is compiled to expect the length of the string variable to be passed at
the end of the function call. The TRNSYS.h header file has been set-up following the same convention. If
you are receiving a string from TRNSYS to your C++ Type use a similar syntax as below for receiving a
Label from TRNSYS where “label” is the string returned from TRNSYS. Further string manipulations may
need to be executed in the C++ type but we leave that up to you the programmer.
int CurrentUnit;
int index = 1;
CurrentUnit = getCurrentUnit();
size_t maxlen = getMaxLabelLength();
char *label = new char[maxlen];
char *str2 = getLabel(label, maxlen, &CurrentUnit, &index);

7–184
TRNSYS 18 – Programmer's Guide

7.7.4. Example TRNSYS C++ Type


In the %TRNSYS18%\SourceCode\Templates directory there is an example of a TRNSYS Type written in
C++ called CppType(v17).cpp. This is a rewrite of the FORTRAN Type 138 component. It demonstrates
the basics of writing a component in C++.

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

You might also like