1 2/** \page develop Developing Code Using SC 3 4In addition to the executables, the Scientific Computing toolkit libraries 5and include files can be installed on your machine. This is described in 6the \ref compile section of this manual. 7 8The <tt>sc-config</tt> program can be use to obtain the compilers, compiler 9options, and libraries needed to use the SC toolkit from your program. 10This utility is discussed below, along with how the SC toolkit must be 11initialized 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 23The sc-config program returns information about how SC was compiled 24and installed. See \ref sc-config for more information. 25 26\section scinit Initializing SC 27 28First the execution environment must be initialized using 29the ExEnv init member. 30 31<pre> 32 ExEnv::init(argc, argv); 33</pre> 34 35By default, all output will go to the console stream, cout. To change 36this, use the following code: 37 38<pre> 39 ostream *outstream = new ofstream(outputfilename); 40 ExEnv::set_out(outstream); 41</pre> 42 43MPI is allowed wait until MPI_Init is called to fill in argc and argv, so 44you may have to call MPI_Init before you even know that we ready to 45construct MPIMessageGrp. So if an MPIMessageGrp is needed, it is up to the 46developer to call MPI_Init to get the argument list for certain MPI 47implementations. 48 49<pre> 50 MPI_Init(&argc, &argv); 51</pre> 52 53When files are read and written, an extension is added to a 54basename to construct the file name. The default is "SC". 55To 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 62If your job might run in parallel, then make the following 63call 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 70This 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 81This 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 93This section illustrates how to add a new method a new method to MPQC. 94 95\subsection devsampsrc MP2 Implementation Example: Source 96 97This example code illustrates a complete MP2 energy 98implementation using the SC Toolkit. First an MP2 class is 99declared and the necesary base class member functions are 100provided. Next a ClassDesc is defined. Finally, the member 101functions are defined. 102 103Note that no main routine is provided. This is because this file 104is designed to be used to extend the functionality of the mpqc 105executable. To generate a new mpqc executable with the new class 106available for use, see the \ref devsampmak section. 107 108\include mp2.cc 109 110\subsection devsampmak MP2 Implementation Example: Makefile 111 112This example Makefile demonstrates how to link in a new class to 113form a new mpqc executable, here named mp2. The code is given in 114the \ref devsampsrc section. The \ref scconfig "sc-config command" 115is used to obtain information about how the SC toolkit 116was compiled and installed. The library specified with -lmpqc 117provides the main routine from mpqc. 118 119\include Makefile 120 121\subsection devsampinp MP2 Implementation Example: Input 122 123This input file can be used with the program illustrated in 124the \ref devsampsrc section. It will compute the MP2 energy 125using the new MP2 class. Note that only the 126\ref mpqcoo "object-oriented input format" can be used with 127user provided classes. 128 129\include mp2.in 130 131\section scexcept Exception Handling in SC 132 133The development of SC began before exception handling was available in C++. 134A retrofit of the code to use exceptions is in progress. It is difficult 135to retrofit a code, especially a parallel code, to do exception handling. 136There will be some limitations: exception handling will not work well for 137parallel jobs, objects whose members throw might be left in a questionable 138state, etc. However, it is intended that SC objects will be usable in an 139interactive environment. It is also planned that exceptions be used 140internally to facilitate recover from certain problems. 141 142All new code should use exceptions instead of exit or abort and allocate 143resources in such a way that, if an exception occurs, all resources such as 144memory or locks are released. A hierarchy of exception classes has been 145created that maps better to scientific computing than the standard 146exceptions. More information is below, as well as in the documentation for 147the 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 159Consider the following code fragment: 160 161<pre> 162Object *obj = new Object; 163double *array = new double[n]; 164 165f(obj, array, mol); 166 167delete obj; 168delete[] array; 169</pre> 170 171If an exception is thrown in the function f(), then storage for array and 172obj will not be released. The standard C++ library provides a class, 173auto_ptr, to deal with obj, and the SC toolkit provides a class, auto_vec, 174to deal with array. 175 176The include files for these two classes are: 177 178<pre> 179#include \<memory\> 180#include \<util/misc/autovec.h\> 181</pre> 182 183the code would be modified as follows: 184 185<pre> 186std::auto_ptr<Object> obj(new Object); 187sc::auto_vec<double> array(new double[n]); 188 189f(obj.get(), array.get()); 190 191obj.release(); // or just let the destructor release it 192array.release(); // or just let the destructor release it 193</pre> 194 195Note that when sc::Ref is used to store pointers, the storage will 196automatically be released when necessary. No special treatment is needed 197to deal with exceptions. 198 199\subsection scexceptlocks Exceptions and Locks 200 201Consider the following code fragment: 202 203<pre> 204g(const sc::Ref<sc::ThreadLock> &lock) 205{ 206 lock->lock(); 207 f(); 208 lock->unlock(); 209} 210</pre> 211 212If f() throws, then the lock is never released. The ThreadLock 213lock() and unlock() members should not be used anymore. Now 214do the following: 215 216<pre> 217g(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 227Consider the following code fragment: 228 229<pre> 230g(const sc::Ref<sc::RegionTimer> ®tim) 231{ 232 regtim->enter("f()"); 233 f(); 234 regtim->exit(); 235} 236</pre> 237 238If f() throws, then the "f()" timing region is never exited. 239Instead use the following: 240 241<pre> 242g(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 252The SC exceptions provide information that can be used into two 253ways. First, text information is provided so that if the exception is not 254caught at a lower level, then the mpqc executable will catch it and write 255information about the problem to the terminal or an output file. Second, 256information about the nature of the problem is provided, to permit 257developers to catch the exception and deal with it in some way. The 258documentation for sc::SCException and all of its derivatives gives more 259information about the exceptions that are available. As an example, 260consider the following loop, where a maximum number of iterations is 261permitted: 262 263<pre> 264XYZ::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 275The first argument to the exception class is a brief description of the 276error. Additional information can be provided, 277see SCException::elaborate() description below. 278The next two arguments are 279the filename and line number. The C preprocessor provides these for you 280with the __FILE__ and __LINE__ macros. The next argument is specific to 281the MaxIterExceeded exception; it is the maximum number of iterations. 282Finally, a ClassDesc* can be given, which will be used to print out the 283class name of the object that failed. All of these arguments are optional; 284however, the first three should always be given. 285 286It is possible to provide additional information using the 287SCException::elaborate() member. This will return a ostream, and the 288additional information can be written to this stream. However, if for some 289reason it is not possible to write to this stream (say, there wasn't enough 290memory to allocate it), then an exception will be thrown. For this reason, 291the string description given as the first argument should be informative 292since the additional information might not be available, and attempts to 293use elaborate() should be in a try block. So, for example, the elaborate() 294member could be used in the above example as follows: 295 296<pre> 297XYZ::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 316Note that writing to stream returned by elaborate() won't necessarily cause 317anything to get written to the terminal or an output file. The information 318will be available when the what() member is called, if writing to the 319stream succeeds. If the exception is caught by the mpqc main routine, then 320it will be printed for the user to see. If the program catches the 321exception and determines that it is possible to proceed in a different way, 322then the user will never see the text. 323 324\subsection scexceptdebug Debugging Code with Exceptions 325 326Usually, exceptions are not the desired behaviour in a program, and it is 327necessary to debug a program that throws an exception. This was easy when 328abort was called, because abort would raise a signal that was caught by the 329debugger and the code is stopped at the appropriate place. With exceptions 330the matter is more complex, because the stack is unwound when an exception 331is thrown and most debugging information is lost. To work around this 332problem, a breakpoint can be set in code that will be reached only in an 333exception, and will be run before the stack unwind begins. A useful place 334to 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 341Breakpoint 1, main () at /home/cljanss/src/SC/src/lib/util/misc/scextest.cc:172 342172 f(); 343(gdb) b __cxa_allocate_exception 344(gdb) cont 345Breakpoint 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 355Giving 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 360There 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 362various library directories, and the <tt>check</tt> and related make 363targets 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 366Test programs can be added to the library directories by providing a source 367file with a main routine. The set of test programs that is to be built and 368run by <tt>testbuild</tt> and <tt>testrun</tt>, respectively, is given by 369the <tt>TESTPROGS</tt> variable in the library's <tt>Makefile</tt>. It may 370be necessary for an explicit rule to be given for building the test program 371to ensure that necessary libraries are linked in. If a file named after 372the test program with a <tt>.out</tt> suffix is found in the source 373directory, then <tt>testrun</tt> fail if the command's output differs from 374that file. Care must be taken to ensure that the output is architecture 375independent in this case. Otherwise, <tt>testrun</tt> will fail only if 376running the command results in a nonzero return code. 377 378Additional MPQC test inputs can be added in the 379<tt>src/bin/mpqc/validate</tt> directory. These inputs can be provided in 380one of two ways. An input which is used to automatically generate multiple 381test cases can be written (with a <tt>.qci</tt> suffix), or a subdirectory 382with each input can be made. See <tt>Makefile</tt>, <tt>basis1.qci</tt>, 383and <tt>input</tt> in the <tt>src/bin/mpqc/validate</tt> directory for 384examples. 385 386After 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 388you 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 391placed in the <tt>input</tt> directory. These contain a description of the 392calculation that is used by the utility program that checks the results of 393the validation suite. Both the <tt>.in</tt> and <tt>.qci</tt> files for the 394new test cases must be copied into the <tt>ref</tt> directory in the source 395tree. Note that inputs that are not useful in your build environment are 396not created by <tt>make inputs</tt>. 397 398*/ 399