1 |
|
---|
2 | /** \page develop Developing Code Using SC
|
---|
3 |
|
---|
4 | In addition to the executables, the Scientific Computing toolkit libraries
|
---|
5 | and include files can be installed on your machine. This is described in
|
---|
6 | the \ref compile section of this manual.
|
---|
7 |
|
---|
8 | The <tt>sc-config</tt> program can be use to obtain the compilers, compiler
|
---|
9 | options, and libraries needed to use the SC toolkit from your program.
|
---|
10 | This utility is discussed below, along with how the SC toolkit must be
|
---|
11 | initialized in your <tt>main</tt> subroutine.
|
---|
12 |
|
---|
13 | <ul>
|
---|
14 | <li> \ref scconfig
|
---|
15 | <li> \ref scinit
|
---|
16 | <li> \ref devsamp
|
---|
17 | <li> \ref scexcept
|
---|
18 | <li> \ref devcheck
|
---|
19 | </ul>
|
---|
20 |
|
---|
21 | \section scconfig The sc-config Program
|
---|
22 |
|
---|
23 | The sc-config program returns information about how SC was compiled
|
---|
24 | and installed. See \ref sc-config for more information.
|
---|
25 |
|
---|
26 | \section scinit Initializing SC
|
---|
27 |
|
---|
28 | First the execution environment must be initialized using
|
---|
29 | the ExEnv init member.
|
---|
30 |
|
---|
31 | <pre>
|
---|
32 | ExEnv::init(argc, argv);
|
---|
33 | </pre>
|
---|
34 |
|
---|
35 | By default, all output will go to the console stream, cout. To change
|
---|
36 | this, use the following code:
|
---|
37 |
|
---|
38 | <pre>
|
---|
39 | ostream *outstream = new ofstream(outputfilename);
|
---|
40 | ExEnv::set_out(outstream);
|
---|
41 | </pre>
|
---|
42 |
|
---|
43 | MPI is allowed wait until MPI_Init is called to fill in argc and argv, so
|
---|
44 | you may have to call MPI_Init before you even know that we ready to
|
---|
45 | construct MPIMessageGrp. So if an MPIMessageGrp is needed, it is up to the
|
---|
46 | developer to call MPI_Init to get the argument list for certain MPI
|
---|
47 | implementations.
|
---|
48 |
|
---|
49 | <pre>
|
---|
50 | MPI_Init(&argc, &argv);
|
---|
51 | </pre>
|
---|
52 |
|
---|
53 | When files are read and written, an extension is added to a
|
---|
54 | basename to construct the file name. The default is "SC".
|
---|
55 | To use another basename, make the following call, where
|
---|
56 | <tt>basename</tt> is a <tt>const char *</tt>:
|
---|
57 |
|
---|
58 | <pre>
|
---|
59 | SCFormIO::set_default_basename(basename);
|
---|
60 | </pre>
|
---|
61 |
|
---|
62 | If your job might run in parallel, then make the following
|
---|
63 | call or the nodes will print redundant information. The
|
---|
64 | <tt>myproc</tt> argument is the rank of the called node.
|
---|
65 |
|
---|
66 | <pre>
|
---|
67 | SCFormIO::init_mp(myproc);
|
---|
68 | </pre>
|
---|
69 |
|
---|
70 | This segment of code sets up an object to provide multi-threading:
|
---|
71 |
|
---|
72 | <pre>
|
---|
73 | RefThreadGrp thread = ThreadGrp::initial_threadgrp(argc, argv);
|
---|
74 | ThreadGrp::set_default_threadgrp(thread);
|
---|
75 | if (thread.nonnull())
|
---|
76 | ThreadGrp::set_default_threadgrp(thread);
|
---|
77 | else
|
---|
78 | thread = ThreadGrp::get_default_threadgrp();
|
---|
79 | </pre>
|
---|
80 |
|
---|
81 | This segment of code sets up the message passing object:
|
---|
82 |
|
---|
83 | <pre>
|
---|
84 | RefMessageGrp grp = MessageGrp::initial_messagegrp(argc, argv);
|
---|
85 | if (grp.nonnull())
|
---|
86 | MessageGrp::set_default_messagegrp(grp);
|
---|
87 | else
|
---|
88 | grp = MessageGrp::get_default_messagegrp();
|
---|
89 | </pre>
|
---|
90 |
|
---|
91 | \section devsamp MP2 Implementation Example
|
---|
92 |
|
---|
93 | This section illustrates how to add a new method a new method to MPQC.
|
---|
94 |
|
---|
95 | \subsection devsampsrc MP2 Implementation Example: Source
|
---|
96 |
|
---|
97 | This example code illustrates a complete MP2 energy
|
---|
98 | implementation using the SC Toolkit. First an MP2 class is
|
---|
99 | declared and the necesary base class member functions are
|
---|
100 | provided. Next a ClassDesc is defined. Finally, the member
|
---|
101 | functions are defined.
|
---|
102 |
|
---|
103 | Note that no main routine is provided. This is because this file
|
---|
104 | is designed to be used to extend the functionality of the mpqc
|
---|
105 | executable. To generate a new mpqc executable with the new class
|
---|
106 | available for use, see the \ref devsampmak section.
|
---|
107 |
|
---|
108 | \include mp2.cc
|
---|
109 |
|
---|
110 | \subsection devsampmak MP2 Implementation Example: Makefile
|
---|
111 |
|
---|
112 | This example Makefile demonstrates how to link in a new class to
|
---|
113 | form a new mpqc executable, here named mp2. The code is given in
|
---|
114 | the \ref devsampsrc section. The \ref scconfig "sc-config command"
|
---|
115 | is used to obtain information about how the SC toolkit
|
---|
116 | was compiled and installed. The library specified with -lmpqc
|
---|
117 | provides the main routine from mpqc.
|
---|
118 |
|
---|
119 | \include Makefile
|
---|
120 |
|
---|
121 | \subsection devsampinp MP2 Implementation Example: Input
|
---|
122 |
|
---|
123 | This input file can be used with the program illustrated in
|
---|
124 | the \ref devsampsrc section. It will compute the MP2 energy
|
---|
125 | using the new MP2 class. Note that only the
|
---|
126 | \ref mpqcoo "object-oriented input format" can be used with
|
---|
127 | user provided classes.
|
---|
128 |
|
---|
129 | \include mp2.in
|
---|
130 |
|
---|
131 | \section scexcept Exception Handling in SC
|
---|
132 |
|
---|
133 | The development of SC began before exception handling was available in C++.
|
---|
134 | A retrofit of the code to use exceptions is in progress. It is difficult
|
---|
135 | to retrofit a code, especially a parallel code, to do exception handling.
|
---|
136 | There will be some limitations: exception handling will not work well for
|
---|
137 | parallel jobs, objects whose members throw might be left in a questionable
|
---|
138 | state, etc. However, it is intended that SC objects will be usable in an
|
---|
139 | interactive environment. It is also planned that exceptions be used
|
---|
140 | internally to facilitate recover from certain problems.
|
---|
141 |
|
---|
142 | All new code should use exceptions instead of exit or abort and allocate
|
---|
143 | resources in such a way that, if an exception occurs, all resources such as
|
---|
144 | memory or locks are released. A hierarchy of exception classes has been
|
---|
145 | created that maps better to scientific computing than the standard
|
---|
146 | exceptions. More information is below, as well as in the documentation for
|
---|
147 | the SCException class and its derivatives.
|
---|
148 |
|
---|
149 | <ul>
|
---|
150 | <li> \ref scexceptmem
|
---|
151 | <li> \ref scexceptlocks
|
---|
152 | <li> \ref scexcepttimer
|
---|
153 | <li> \ref scexceptexample
|
---|
154 | <li> \ref scexceptdebug
|
---|
155 | </ul>
|
---|
156 |
|
---|
157 | \subsection scexceptmem Exceptions and Memory Allocation
|
---|
158 |
|
---|
159 | Consider the following code fragment:
|
---|
160 |
|
---|
161 | <pre>
|
---|
162 | Object *obj = new Object;
|
---|
163 | double *array = new double[n];
|
---|
164 |
|
---|
165 | f(obj, array, mol);
|
---|
166 |
|
---|
167 | delete obj;
|
---|
168 | delete[] array;
|
---|
169 | </pre>
|
---|
170 |
|
---|
171 | If an exception is thrown in the function f(), then storage for array and
|
---|
172 | obj will not be released. The standard C++ library provides a class,
|
---|
173 | auto_ptr, to deal with obj, and the SC toolkit provides a class, auto_vec,
|
---|
174 | to deal with array.
|
---|
175 |
|
---|
176 | The include files for these two classes are:
|
---|
177 |
|
---|
178 | <pre>
|
---|
179 | #include \<memory\>
|
---|
180 | #include \<util/misc/autovec.h\>
|
---|
181 | </pre>
|
---|
182 |
|
---|
183 | the code would be modified as follows:
|
---|
184 |
|
---|
185 | <pre>
|
---|
186 | std::auto_ptr<Object> obj(new Object);
|
---|
187 | sc::auto_vec<double> array(new double[n]);
|
---|
188 |
|
---|
189 | f(obj.get(), array.get());
|
---|
190 |
|
---|
191 | obj.release(); // or just let the destructor release it
|
---|
192 | array.release(); // or just let the destructor release it
|
---|
193 | </pre>
|
---|
194 |
|
---|
195 | Note that when sc::Ref is used to store pointers, the storage will
|
---|
196 | automatically be released when necessary. No special treatment is needed
|
---|
197 | to deal with exceptions.
|
---|
198 |
|
---|
199 | \subsection scexceptlocks Exceptions and Locks
|
---|
200 |
|
---|
201 | Consider the following code fragment:
|
---|
202 |
|
---|
203 | <pre>
|
---|
204 | g(const sc::Ref<sc::ThreadLock> &lock)
|
---|
205 | {
|
---|
206 | lock->lock();
|
---|
207 | f();
|
---|
208 | lock->unlock();
|
---|
209 | }
|
---|
210 | </pre>
|
---|
211 |
|
---|
212 | If f() throws, then the lock is never released. The ThreadLock
|
---|
213 | lock() and unlock() members should not be used anymore. Now
|
---|
214 | do the following:
|
---|
215 |
|
---|
216 | <pre>
|
---|
217 | g(const sc::Ref<sc::ThreadLock> &lock)
|
---|
218 | {
|
---|
219 | sc::ThreadLockHolder lockholder(lock);
|
---|
220 | f();
|
---|
221 | lockholder->unlock(); // or let the destructor unlock it
|
---|
222 | }
|
---|
223 | </pre>
|
---|
224 |
|
---|
225 | \subsection scexcepttimer Exceptions and Region Timers
|
---|
226 |
|
---|
227 | Consider the following code fragment:
|
---|
228 |
|
---|
229 | <pre>
|
---|
230 | g(const sc::Ref<sc::RegionTimer> ®tim)
|
---|
231 | {
|
---|
232 | regtim->enter("f()");
|
---|
233 | f();
|
---|
234 | regtim->exit();
|
---|
235 | }
|
---|
236 | </pre>
|
---|
237 |
|
---|
238 | If f() throws, then the "f()" timing region is never exited.
|
---|
239 | Instead use the following:
|
---|
240 |
|
---|
241 | <pre>
|
---|
242 | g(const sc::Ref<sc::RegionTimer> ®tim)
|
---|
243 | {
|
---|
244 | sc::Timer timer(regtim, "f()");
|
---|
245 | f();
|
---|
246 | timer.reset(); // or let the destructor exit the region
|
---|
247 | }
|
---|
248 | </pre>
|
---|
249 |
|
---|
250 | \subsection scexceptexample Using the SC Exception Classes
|
---|
251 |
|
---|
252 | The SC exceptions provide information that can be used into two
|
---|
253 | ways. First, text information is provided so that if the exception is not
|
---|
254 | caught at a lower level, then the mpqc executable will catch it and write
|
---|
255 | information about the problem to the terminal or an output file. Second,
|
---|
256 | information about the nature of the problem is provided, to permit
|
---|
257 | developers to catch the exception and deal with it in some way. The
|
---|
258 | documentation for sc::SCException and all of its derivatives gives more
|
---|
259 | information about the exceptions that are available. As an example,
|
---|
260 | consider the following loop, where a maximum number of iterations is
|
---|
261 | permitted:
|
---|
262 |
|
---|
263 | <pre>
|
---|
264 | XYZ::update()
|
---|
265 | {
|
---|
266 | for (int i=0; i<maxiter; i++) {
|
---|
267 | // ... compute xyz update ...
|
---|
268 | if (residual < threshold) return;
|
---|
269 | }
|
---|
270 | throw MaxIterExceeded("too many iterations xyz computation",
|
---|
271 | __FILE__, __LINE__, maxiter, class_desc());
|
---|
272 | }
|
---|
273 | </pre>
|
---|
274 |
|
---|
275 | The first argument to the exception class is a brief description of the
|
---|
276 | error. Additional information can be provided,
|
---|
277 | see SCException::elaborate() description below.
|
---|
278 | The next two arguments are
|
---|
279 | the filename and line number. The C preprocessor provides these for you
|
---|
280 | with the __FILE__ and __LINE__ macros. The next argument is specific to
|
---|
281 | the MaxIterExceeded exception; it is the maximum number of iterations.
|
---|
282 | Finally, a ClassDesc* can be given, which will be used to print out the
|
---|
283 | class name of the object that failed. All of these arguments are optional;
|
---|
284 | however, the first three should always be given.
|
---|
285 |
|
---|
286 | It is possible to provide additional information using the
|
---|
287 | SCException::elaborate() member. This will return a ostream, and the
|
---|
288 | additional information can be written to this stream. However, if for some
|
---|
289 | reason it is not possible to write to this stream (say, there wasn't enough
|
---|
290 | memory to allocate it), then an exception will be thrown. For this reason,
|
---|
291 | the string description given as the first argument should be informative
|
---|
292 | since the additional information might not be available, and attempts to
|
---|
293 | use elaborate() should be in a try block. So, for example, the elaborate()
|
---|
294 | member could be used in the above example as follows:
|
---|
295 |
|
---|
296 | <pre>
|
---|
297 | XYZ::update()
|
---|
298 | {
|
---|
299 | for (int i=0; i<maxiter; i++) {
|
---|
300 | // ... compute xyz update ...
|
---|
301 | if (residual < threshold) return;
|
---|
302 | }
|
---|
303 | MaxIterExceeded ex("too many iterations in xyz computation",
|
---|
304 | __FILE__, __LINE__, maxiter, class_desc());
|
---|
305 | try {
|
---|
306 | ex.elaborate() << "this can happen when the stepsize is too small"
|
---|
307 | << std::endl
|
---|
308 | << "the stepsize is " << stepsize
|
---|
309 | << std::endl;
|
---|
310 | }
|
---|
311 | catch (...) {}
|
---|
312 | throw ex;
|
---|
313 | }
|
---|
314 | </pre>
|
---|
315 |
|
---|
316 | Note that writing to stream returned by elaborate() won't necessarily cause
|
---|
317 | anything to get written to the terminal or an output file. The information
|
---|
318 | will be available when the what() member is called, if writing to the
|
---|
319 | stream succeeds. If the exception is caught by the mpqc main routine, then
|
---|
320 | it will be printed for the user to see. If the program catches the
|
---|
321 | exception and determines that it is possible to proceed in a different way,
|
---|
322 | then the user will never see the text.
|
---|
323 |
|
---|
324 | \subsection scexceptdebug Debugging Code with Exceptions
|
---|
325 |
|
---|
326 | Usually, exceptions are not the desired behaviour in a program, and it is
|
---|
327 | necessary to debug a program that throws an exception. This was easy when
|
---|
328 | abort was called, because abort would raise a signal that was caught by the
|
---|
329 | debugger and the code is stopped at the appropriate place. With exceptions
|
---|
330 | the matter is more complex, because the stack is unwound when an exception
|
---|
331 | is thrown and most debugging information is lost. To work around this
|
---|
332 | problem, a breakpoint can be set in code that will be reached only in an
|
---|
333 | exception, and will be run before the stack unwind begins. A useful place
|
---|
334 | to do this when GCC is used as the compiler is in the routine
|
---|
335 | __cxa_allocate_exception(). So, in gdb, the following could be done:
|
---|
336 |
|
---|
337 | <pre>
|
---|
338 | $ gdb ./scextest
|
---|
339 | (gdb) b main
|
---|
340 | (gdb) run
|
---|
341 | Breakpoint 1, main () at /home/cljanss/src/SC/src/lib/util/misc/scextest.cc:172
|
---|
342 | 172 f();
|
---|
343 | (gdb) b __cxa_allocate_exception
|
---|
344 | (gdb) cont
|
---|
345 | Breakpoint 2, 0x40582d46 in __cxa_allocate_exception ()
|
---|
346 | from /usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.5/libstdc++.so.5
|
---|
347 | (gdb) where
|
---|
348 | #0 0x40582d46 in __cxa_allocate_exception ()
|
---|
349 | from /usr/lib/gcc-lib/i686-pc-linux-gnu/3.3.5/libstdc++.so.5
|
---|
350 | #1 0x0804b3f7 in f () at /home/cljanss/src/SC/src/lib/util/misc/scextest.cc:60
|
---|
351 | #2 0x0804b9e9 in main ()
|
---|
352 | at /home/cljanss/src/SC/src/lib/util/misc/scextest.cc:172
|
---|
353 | </pre>
|
---|
354 |
|
---|
355 | Giving gdb "b main" followed by "run" was required before gdb could find the
|
---|
356 | __cxa_allocate_exception symbol.
|
---|
357 |
|
---|
358 | \section devcheck Adding Test Cases to the Verification Suite
|
---|
359 |
|
---|
360 | There are two ways to test an MPQC build. The <tt>testbuild</tt> and
|
---|
361 | <tt>testrun</tt> make targets can be used to run test programs in
|
---|
362 | various library directories, and the <tt>check</tt> and related make
|
---|
363 | targets can be used to run MPQC on sets of input files. See
|
---|
364 | \ref mpqcval for more information about how to run the tests.
|
---|
365 |
|
---|
366 | Test programs can be added to the library directories by providing a source
|
---|
367 | file with a main routine. The set of test programs that is to be built and
|
---|
368 | run by <tt>testbuild</tt> and <tt>testrun</tt>, respectively, is given by
|
---|
369 | the <tt>TESTPROGS</tt> variable in the library's <tt>Makefile</tt>. It may
|
---|
370 | be necessary for an explicit rule to be given for building the test program
|
---|
371 | to ensure that necessary libraries are linked in. If a file named after
|
---|
372 | the test program with a <tt>.out</tt> suffix is found in the source
|
---|
373 | directory, then <tt>testrun</tt> fail if the command's output differs from
|
---|
374 | that file. Care must be taken to ensure that the output is architecture
|
---|
375 | independent in this case. Otherwise, <tt>testrun</tt> will fail only if
|
---|
376 | running the command results in a nonzero return code.
|
---|
377 |
|
---|
378 | Additional MPQC test inputs can be added in the
|
---|
379 | <tt>src/bin/mpqc/validate</tt> directory. These inputs can be provided in
|
---|
380 | one of two ways. An input which is used to automatically generate multiple
|
---|
381 | test cases can be written (with a <tt>.qci</tt> suffix), or a subdirectory
|
---|
382 | with each input can be made. See <tt>Makefile</tt>, <tt>basis1.qci</tt>,
|
---|
383 | and <tt>input</tt> in the <tt>src/bin/mpqc/validate</tt> directory for
|
---|
384 | examples.
|
---|
385 |
|
---|
386 | After you have added new inputs and modified the Makefile, change into the
|
---|
387 | <tt>src/bin/mpqc/validate</tt> subdirectory of your object directory (where
|
---|
388 | you compiled MPQC) and type <tt>make inputs</tt>. This will create a
|
---|
389 | <tt>input</tt> subdirectory containing MPQC input files with a
|
---|
390 | <tt>.in</tt> suffix. Files ending with a <tt>.qci</tt> suffix will also be
|
---|
391 | placed in the <tt>input</tt> directory. These contain a description of the
|
---|
392 | calculation that is used by the utility program that checks the results of
|
---|
393 | the validation suite. Both the <tt>.in</tt> and <tt>.qci</tt> files for the
|
---|
394 | new test cases must be copied into the <tt>ref</tt> directory in the source
|
---|
395 | tree. Note that inputs that are not useful in your build environment are
|
---|
396 | not created by <tt>make inputs</tt>.
|
---|
397 |
|
---|
398 | */
|
---|