[0b990d] | 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 | */
|
---|