2
% PSI Programmer's Manual
4
% Essentials of a PSI Module
6
% David Sherrill, 31 January 1996
7
% Updates by TDC, 2002.
8
% Updates by CDS for C++, January 2008
11
To function as part of the PSI package, a program must incorporate
12
certain required elements. This section will discuss the header files,
13
global variables, and functions required to integrate a new C++ module
14
into \PSIthree. Here is a minimal \PSIthree\ program, whose elements
15
are described below. Note that we are using C++ namespaces to avoid
16
conflicting names between modules, as we are moving toward a
17
single-executable design. However, for legacy reasons certain globals and
18
the \celem{gprgid()} function need to have C-linkage.
23
#include <libipv1/ip_lib.h>
26
#include <libciomr/libciomr.h>
27
#include <libchkpt/chkpt.h>
28
#include <libpsio/psio.h>
31
FILE *infile, *outfile;
32
char *psi_file_prefix;
35
// begin module-specific namespace
36
namespace psi { namespace MODULE_NAME {
38
// global variables, function declarations, and
39
// #define statements here
41
}} // close namespace psi::MODULE_NAME
43
// main needs to be in the global namespace
44
// but give it access to the psi::MODULE_NAME namespace
46
using namespace psi::MODULE_NAME
48
int main(int argc, char *argv[])
51
psi_start(&infile, &outfile, &psi_file_prefix,
53
ip_cwk_add(":MODULE_NAME"); // MODULE_NAME all caps here
54
psio_init(); psio_ipv1_config();
56
/* to start timing, tstart(outfile); */
58
/* Insert code here */
60
/* to end timing, tstop(outfile); */
63
psi_stop(infile, outfile, psi_file_prefix);
66
// this needs to be global namespace also
70
char *prgid = "MODULE_NAME";
75
// all other stuff is in a special namespace
76
namespace psi { namespace MODULE_NAME {
79
double some_function(int x) {
83
}} // close namespace psi::MODULE_NAME
86
In the above example, we have included the typical C++ and PSI
87
header files, although for your specific module you may not need
88
all of these, or perhaps you may need additional ones (such as
89
\celem{string.h} or \celem{math.h}). The PSI include files used in this
90
example are \file{libipv1/ip\_lib.h} (the input parser, described
91
in section \ref{C_IP}), \file{psifiles.h} (definitions of all the
92
PSI file numbers for I/O), \file{libqt/qt.h} (the ``quantum
93
trio'' library, containing miscellaneous math and utility functions),
94
\file{libciomr/libciomr.h} (the old PSI I/O and math routines library
95
-- although it contains no I/O anymore), \file{libchkpt/chkpt.h} (a
96
library for accessing the checkpoint file to obtain quantities such
97
as the SCF or nuclear repulsion energy), and \file{libpsio/psio.h}
98
(the PSI I/O library, see section \ref{C_IO_New}). These include files
99
contain function declarations for all of the functions contained in
102
Note that all PSI modules require three global variables with C
103
linkage (i.e., inside an \celem{extern C} statement): \celem{infile},
104
\celem{outfile}, and \celem{psi\_file\_prefix}. Each PSI module must
105
also have a C-linkage function called \celem{gprgid()} defined as shown.
106
The \celem{main()} function must be in global scope, and other functions
107
should be inside a namespace with the name of the module (which is further
108
contained inside a \celem{psi} namespace). Consult a C++ book if you are
109
unfamiliar with namespaces.
111
The integer function \celem{main()} must be able to handle
112
command-line arguments required by the \PSIthree\ libraries. In
113
particular, all \PSIthree\ modules must be able to pass to the
114
function \celem{psi\_start()} arguments for the user's input and
115
output filenames, as well as a global file prefix to be used for
116
naming standard binary and text data files. (NB: the default names
117
for user input and output are \inputdat\ and \outputdat, respectively,
118
though any name may be used.) The current standard for command-line
119
arguments is for all module-specific arguments ({\em e.g.},
120
\celem{--quiet}, used in \module{detci}) {\em before} the input,
121
output, and prefix values. The \celem{psi\_start()} function expects
122
to find {\em only} these last three arguments at most, so the
123
programmer should pass as \celem{argv[]} the pointer to the first
124
non-module-specific argument. The above example is appropriate for a
125
\PSIthree\ module that requires no command-line arguments apart from
126
the input/output/prefix globals. See the \PSIthree\ modules
127
\module{input} and \module{detci} for more sophisticated examples.
128
The final argument to \celem{psi\_start()} is an integer whose value
129
indicates whether the output file should be overwitten (1) or appended
130
(0). Most \PSIthree\ modules should choose to append.
132
The \celem{psi\_start()} function initializes the user's input and
133
output files and sets the global variables \celem{infile},
134
\celem{outfile}, and \celem{psi\_file\_prefix}, based on (in order of
135
priority) the above command-line arguments or the environmental
136
variables \celem{PSI\_INPUT}, \celem{PSI\_OUTPUT}, and
137
\celem{PSI\_PREFIX}. The value of the global file prefix can also be
138
specified in the user's input file. The \celem{psi\_start()} function
139
will also initialize the input parser and sets up a default keyword
140
tree (described in detail in section \ref{C_IP}). This step is
141
required even if the program will not do any input parsing, because
142
some of the functionality of the input parser is assumed by
143
\library{libciomr.a} and \library{libpsio.a}. For instance, opening a
144
binary file via \celem{psio\_open()} (see section \ref{C_IO_New})
145
requires parsing the \keyword{files} section of the user's input so
146
that a unit number (e.g.~52) can be translated into a filename.
147
The \celem{psi\_stop()} function shuts down the input parser and closes
148
the user's input and output files.
150
Timing information (when the program starts and stops, and how much
151
user, system, and wall-clock time it requires) can be printed to the
152
output file by adding calls to \celem{tstart()} and \celem{tstop()}
153
(from \library{libciomr.a}).
155
The sole purpose of the simple function \celem{gprgid()} is to provide
156
the input parser a means to determine the name of the current program.
157
This allows the input parser to add the name of the program to the
158
input parsing keyword tree. This function is used by
159
\library{libpsio.a}, though the functionality it provides is rarely
162
In all but the most trivial of modules, you will probably need to split
163
your code into multiple files. The \PSIthree\ convention is to put
164
the \celem{main()} function, \celem{gprgid()}, and the allocation of
165
\celem{infile}, \celem{outfile}, and \celem{psi\_file\_prefix} into a
166
file with the same name as that of the module (and a .cc extension).
167
Other C++ source files should have everything wrapped within the
168
\celem{psi::MODULE\_NAME} namespace. Any module-specific header files
169
should look like this:
172
#ifndef _psi_src_bin_MODULE_NAME_h
173
#define _psi_src_bin_MODULE_NAME_h
175
// if you need infile, outfile, and psi_file_prefix in the header,
176
// include them like this:
178
extern FILE *infile, *outfile;
179
extern char *psi_file_prefix;
182
namespace psi { namespace MODULE_NAME {
184
/* header stuff goes here */
186
}} // namespace psi::MODULE_NAME
188
#endif // header guard
191
If you add \celem{infile}, etc, to a header file, make sure they are
192
within an \celem{extern "C"} statement and in the global namespace.
193
Since these variables are defined in MODULE\_NAME.cc, you should also
194
precede these variables with \celem{extern} to tell the compiler they've
195
been allocated in another module (e.g., \celem{extern FILE *infile}).
196
However, that means you then wouldn't be able to include that header
197
file in MODULE\_NAME.cc, because then you'd be telling the compiler
198
both that \celem{infile}, etc, are allocated elsewhere (according
199
to \celem{extern FILE *infile} in the header file) and also that it's
200
allocated in the current file (\celem{FILE *infile} in MODULE\_NAME.cc),
201
an obvious contradition. Most of the official \PSIthree\ modules
202
use a trick defining or undefining a variable called \celem{EXTERN}
203
to avoid this apparent paradox and allow the use of the same header
204
file containing global variables (often called \file{globals.h}) in
205
MODULE\_NAME.cc and all other C++ source files.
207
As always, you are encouraged to avoid use of global variables when at
208
all possible. It is customary to wrap variables that would otherwise be
209
global into data structures such as MOInfo (for things like the number
210
of orbitals) and Params (for user-specified parameters). In the next
211
stage of PSI development, these commonly-used data structures will be
212
standardized as new C++ objects for maximum code re-use and flexibility.