File: develop.dox

package info (click to toggle)
mpqc 2.3.1-6
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 39,580 kB
  • ctags: 16,804
  • sloc: cpp: 258,686; sh: 8,584; perl: 6,017; ansic: 5,491; makefile: 2,769; fortran: 1,970; lisp: 1,269; yacc: 313; lex: 177; csh: 45
file content (398 lines) | stat: -rw-r--r-- 14,269 bytes parent folder | download | duplicates (9)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398

/** \page develop Developing Code Using SC

In addition to the executables, the Scientific Computing toolkit libraries
and include files can be installed on your machine.  This is described in
the \ref compile section of this manual.

The <tt>sc-config</tt> program can be use to obtain the compilers, compiler
options, and libraries needed to use the SC toolkit from your program.
This utility is discussed below, along with how the SC toolkit must be
initialized in your <tt>main</tt> subroutine.

<ul>
  <li> \ref scconfig
  <li> \ref scinit
  <li> \ref devsamp
  <li> \ref scexcept
  <li> \ref devcheck
</ul>

\section scconfig The sc-config Program

The sc-config program returns information about how SC was compiled
and installed.  See \ref sc-config for more information.                        

\section scinit Initializing SC

First the execution environment must be initialized using
the ExEnv init member.

<pre>
  ExEnv::init(argc, argv);
</pre>

By default, all output will go to the console stream, cout.  To change
this, use the following code:

<pre>
  ostream *outstream = new ofstream(outputfilename);
  ExEnv::set_out(outstream);
</pre>

MPI is allowed wait until MPI_Init is called to fill in argc and argv, so
you may have to call MPI_Init before you even know that we ready to
construct MPIMessageGrp.  So if an MPIMessageGrp is needed, it is up to the
developer to call MPI_Init to get the argument list for certain MPI
implementations.

<pre>
  MPI_Init(&argc, &argv);
</pre>

When files are read and written, an extension is added to a
basename to construct the file name.  The default is "SC".
To use another basename, make the following call, where
<tt>basename</tt> is a <tt>const char *</tt>:

<pre>
  SCFormIO::set_default_basename(basename);
</pre>

If your job might run in parallel, then make the following
call or the nodes will print redundant information.  The
<tt>myproc</tt> argument is the rank of the called node.

<pre>
  SCFormIO::init_mp(myproc);
</pre>

This segment of code sets up an object to provide multi-threading:

<pre>
  RefThreadGrp thread = ThreadGrp::initial_threadgrp(argc, argv);
  ThreadGrp::set_default_threadgrp(thread);
  if (thread.nonnull())
    ThreadGrp::set_default_threadgrp(thread);
  else
    thread = ThreadGrp::get_default_threadgrp();
</pre>

This segment of code sets up the message passing object:

<pre>
  RefMessageGrp grp = MessageGrp::initial_messagegrp(argc, argv);
  if (grp.nonnull())
    MessageGrp::set_default_messagegrp(grp);
  else
    grp = MessageGrp::get_default_messagegrp();
</pre>

\section devsamp MP2 Implementation Example

This section illustrates how to add a new method a new method to MPQC.

\subsection devsampsrc MP2 Implementation Example: Source

This example code illustrates a complete MP2 energy
implementation using the SC Toolkit.  First an MP2 class is
declared and the necesary base class member functions are
provided.  Next a ClassDesc is defined.  Finally, the member
functions are defined.

Note that no main routine is provided.  This is because this file
is designed to be used to extend the functionality of the mpqc
executable.  To generate a new mpqc executable with the new class
available for use, see the \ref devsampmak section.

\include mp2.cc

\subsection devsampmak MP2 Implementation Example: Makefile

This example Makefile demonstrates how to link in a new class to
form a new mpqc executable, here named mp2.  The code is given in
the \ref devsampsrc section.  The \ref scconfig "sc-config command"
is used to obtain information about how the SC toolkit
was compiled and installed.  The library specified with -lmpqc
provides the main routine from mpqc.

\include Makefile

\subsection devsampinp MP2 Implementation Example: Input

This input file can be used with the program illustrated in
the \ref devsampsrc section.  It will compute the MP2 energy
using the new MP2 class.  Note that only the
\ref mpqcoo "object-oriented input format" can be used with
user provided classes.

\include mp2.in

\section scexcept Exception Handling in SC

The development of SC began before exception handling was available in C++.
A retrofit of the code to use exceptions is in progress.  It is difficult
to retrofit a code, especially a parallel code, to do exception handling.
There will be some limitations: exception handling will not work well for
parallel jobs, objects whose members throw might be left in a questionable
state, etc.  However, it is intended that SC objects will be usable in an
interactive environment.  It is also planned that exceptions be used
internally to facilitate recover from certain problems.

All new code should use exceptions instead of exit or abort and allocate
resources in such a way that, if an exception occurs, all resources such as
memory or locks are released.  A hierarchy of exception classes has been
created that maps better to scientific computing than the standard
exceptions.  More information is below, as well as in the documentation for
the SCException class and its derivatives.

<ul>
  <li> \ref scexceptmem
  <li> \ref scexceptlocks
  <li> \ref scexcepttimer
  <li> \ref scexceptexample
  <li> \ref scexceptdebug
</ul>

\subsection scexceptmem Exceptions and Memory Allocation

Consider the following code fragment:

<pre>
Object *obj = new Object;
double *array = new double[n];

f(obj, array, mol);

delete obj;
delete[] array;
</pre>

If an exception is thrown in the function f(), then storage for array and
obj will not be released.  The standard C++ library provides a class,
auto_ptr, to deal with obj, and the SC toolkit provides a class, auto_vec,
to deal with array.

The include files for these two classes are:

<pre>
#include \<memory\>
#include \<util/misc/autovec.h\>
</pre>

the code would be modified as follows:

<pre>
std::auto_ptr<Object> obj(new Object);
sc::auto_vec<double> array(new double[n]);

f(obj.get(), array.get());

obj.release();  // or just let the destructor release it
array.release();  // or just let the destructor release it
</pre>

Note that when sc::Ref is used to store pointers, the storage will
automatically be released when necessary.  No special treatment is needed
to deal with exceptions.

\subsection scexceptlocks Exceptions and Locks

Consider the following code fragment:

<pre>
g(const sc::Ref<sc::ThreadLock> &lock)
{
  lock->lock();
  f();
  lock->unlock();
}
</pre>

If f() throws, then the lock is never released.  The ThreadLock
lock() and unlock() members should not be used anymore.  Now
do the following:

<pre>
g(const sc::Ref<sc::ThreadLock> &lock)
{
  sc::ThreadLockHolder lockholder(lock);
  f();
  lockholder->unlock(); // or let the destructor unlock it
}
</pre>

\subsection scexcepttimer Exceptions and Region Timers

Consider the following code fragment:

<pre>
g(const sc::Ref<sc::RegionTimer> &regtim)
{
  regtim->enter("f()");
  f();
  regtim->exit();
}
</pre>

If f() throws, then the "f()" timing region is never exited.
Instead use the following:

<pre>
g(const sc::Ref<sc::RegionTimer> &regtim)
{
  sc::Timer timer(regtim, "f()");
  f();
  timer.reset(); // or let the destructor exit the region
}
</pre>

\subsection scexceptexample Using the SC Exception Classes

The SC exceptions provide information that can be used into two
ways. First, text information is provided so that if the exception is not
caught at a lower level, then the mpqc executable will catch it and write
information about the problem to the terminal or an output file.  Second,
information about the nature of the problem is provided, to permit
developers to catch the exception and deal with it in some way.  The
documentation for sc::SCException and all of its derivatives gives more
information about the exceptions that are available.  As an example,
consider the following loop, where a maximum number of iterations is
permitted:

<pre>
XYZ::update()
{
  for (int i=0; i<maxiter; i++) {
    // ... compute xyz update ...
    if (residual < threshold) return;
  }
  throw MaxIterExceeded("too many iterations xyz computation",
                        __FILE__, __LINE__, maxiter, class_desc());
}
</pre>

The first argument to the exception class is a brief description of the
error.  Additional information can be provided,
see SCException::elaborate() description below.
The next two arguments are
the filename and line number.  The C preprocessor provides these for you
with the __FILE__ and __LINE__ macros.  The next argument is specific to
the MaxIterExceeded exception; it is the maximum number of iterations.
Finally, a ClassDesc* can be given, which will be used to print out the
class name of the object that failed.  All of these arguments are optional;
however, the first three should always be given.

It is possible to provide additional information using the
SCException::elaborate() member.  This will return a ostream, and the
additional information can be written to this stream.  However, if for some
reason it is not possible to write to this stream (say, there wasn't enough
memory to allocate it), then an exception will be thrown.  For this reason,
the string description given as the first argument should be informative
since the additional information might not be available, and attempts to
use elaborate() should be in a try block.  So, for example, the elaborate()
member could be used in the above example as follows:

<pre>
XYZ::update()
{
  for (int i=0; i<maxiter; i++) {
    // ... compute xyz update ...
    if (residual < threshold) return;
  }
  MaxIterExceeded ex("too many iterations in xyz computation",
                     __FILE__, __LINE__, maxiter, class_desc());
  try {
    ex.elaborate() << "this can happen when the stepsize is too small"
                   << std::endl
                   << "the stepsize is " << stepsize
                   << std::endl;
  }
  catch (...) {}
  throw ex;
}
</pre>

Note that writing to stream returned by elaborate() won't necessarily cause
anything to get written to the terminal or an output file.  The information
will be available when the what() member is called, if writing to the
stream succeeds.  If the exception is caught by the mpqc main routine, then
it will be printed for the user to see.  If the program catches the
exception and determines that it is possible to proceed in a different way,
then the user will never see the text.

\subsection scexceptdebug Debugging Code with Exceptions

Usually, exceptions are not the desired behaviour in a program, and it is
necessary to debug a program that throws an exception.  This was easy when
abort was called, because abort would raise a signal that was caught by the
debugger and the code is stopped at the appropriate place.  With exceptions
the matter is more complex, because the stack is unwound when an exception
is thrown and most debugging information is lost.  To work around this
problem, a breakpoint can be set in code that will be reached only in an
exception, and will be run before the stack unwind begins.  A useful place
to do this when GCC is used as the compiler is in the routine
__cxa_allocate_exception().  So, in gdb, the following could be done:

<pre>
$ gdb ./scextest
(gdb) b main
(gdb) run
Breakpoint 1, main () at /home/cljanss/src/SC/src/lib/util/misc/scextest.cc:172
172           f();
(gdb) b __cxa_allocate_exception
(gdb) cont
Breakpoint 2, 0x40582d46 in __cxa_allocate_exception ()
   from /usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.5/libstdc++.so.5
(gdb) where
#0  0x40582d46 in __cxa_allocate_exception ()
   from /usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.5/libstdc++.so.5
#1  0x0804b3f7 in f () at /home/cljanss/src/SC/src/lib/util/misc/scextest.cc:60
#2  0x0804b9e9 in main ()
    at /home/cljanss/src/SC/src/lib/util/misc/scextest.cc:172
</pre>

Giving gdb "b main" followed by "run" was required before gdb could find the
__cxa_allocate_exception symbol.

\section devcheck Adding Test Cases to the Verification Suite

There are two ways to test an MPQC build.  The <tt>testbuild</tt> and
<tt>testrun</tt> make targets can be used to run test programs in
various library directories, and the <tt>check</tt> and related make
targets can be used to run MPQC on sets of input files.  See
\ref mpqcval for more information about how to run the tests.

Test programs can be added to the library directories by providing a source
file with a main routine.  The set of test programs that is to be built and
run by <tt>testbuild</tt> and <tt>testrun</tt>, respectively, is given by
the <tt>TESTPROGS</tt> variable in the library's <tt>Makefile</tt>.  It may
be necessary for an explicit rule to be given for building the test program
to ensure that necessary libraries are linked in.  If a file named after
the test program with a <tt>.out</tt> suffix is found in the source
directory, then <tt>testrun</tt> fail if the command's output differs from
that file.  Care must be taken to ensure that the output is architecture
independent in this case.  Otherwise, <tt>testrun</tt> will fail only if
running the command results in a nonzero return code.

Additional MPQC test inputs can be added in the
<tt>src/bin/mpqc/validate</tt> directory.  These inputs can be provided in
one of two ways.  An input which is used to automatically generate multiple
test cases can be written (with a <tt>.qci</tt> suffix), or a subdirectory
with each input can be made.  See <tt>Makefile</tt>, <tt>basis1.qci</tt>,
and <tt>input</tt> in the <tt>src/bin/mpqc/validate</tt> directory for
examples.

After you have added new inputs and modified the Makefile, change into the
<tt>src/bin/mpqc/validate</tt> subdirectory of your object directory (where
you compiled MPQC) and type <tt>make inputs</tt>.  This will create a
<tt>input</tt> subdirectory containing MPQC input files with a
<tt>.in</tt> suffix.  Files ending with a <tt>.qci</tt> suffix will also be
placed in the <tt>input</tt> directory.  These contain a description of the
calculation that is used by the utility program that checks the results of
the validation suite.  Both the <tt>.in</tt> and <tt>.qci</tt> files for the
new test cases must be copied into the <tt>ref</tt> directory in the source
tree.  Note that inputs that are not useful in your build environment are
not created by <tt>make inputs</tt>.

*/