The Cloudy Style Page


Routines to do common tasks

The MultiArrPage describes the new multi_arr structure for allocating and accessing multi-dimensional arrays in Cloudy.

fp_equal( arg1, arg2, n ) - returns true if the two arguments are within a relative precision of n epsilon of one another. When unspecified, n defaults to 3.

fp_equal_tol( arg1, arg2, tol ) - returns true if the two arguments differ by no more than tol. It is fundamentally different from fp_equal in that it can return true when arg1 and arg2 have different sign, while fp_equal cannot.

sign( arg1, arg2 ) - the Fortran sign function, returns arg1 with the sign of arg2. If arg2 == 0, +arg1 is returned.

sign3( arg ) - the Pascal sign function, returns -1 if arg1 < 0, returns 0 when arg1 == 0, and +1 when arg > 0.

set_nan( var ) / set_nan( arr, n ) - sets the argument (a simple variable "var" or an array "arr[n]") to signaling NaN (not a number) which will cause the code to crash if the variable is used in a floating point operation before it is properly initialized. Note that this will fool valgrind / purify, but this is OK as long as FP traps are enabled.

SDIV( arg ) - "safe division". BEWARE: this macro is neither safe, nor does it do any division. All it does is guard against division by zero, but it does not guard against overflow when dividing by a very small number, nor does it preserve the sign when dividing by a very small negative number. This macro should gradually be phased out due to its poorly defined behavior. For new code the routine safe_div described below should be used.

safe_div( x, y ) - carries out a safe division x/y in the sense that division by zero and overflow exceptions are avoided under all circumstances; the code will however still produce invalid FP exceptions where appropriate (this includes 0/0). If the results would otherwise have overflowed (this includes division of a non-zero number by zero), +/-DBL_MAX or +/-FLT_MAX is returned. Note that this routine carries quite a bit of overhead, so only use it where it is really needed.

STATIC - this is used to declare that a routine is file static. This should never be used to declare the scope of a variable or to cause it to retain its value when going out of scope. Declaring the macro USE_GPROF during compilation will cause the STATIC qualifier to be redefined to an empty string and all routines will be globally visible. This influences gprof output as it disables inlining of certain routines. It is also needed in unit testing if you want to test the results of a static routine.

dprintf - generates print output with DEBUG prepended. The script checkall.pl in the test suite directories checks for this string since it is easy to forget that print statements were enabled.

cdEXIT( arg ) - the exit handler. The argument is either EXIT_FAILURE or EXIT_SUCCESS. This must be called to exit to insure that output is properly closed.

DEBUG_ENTRY( "routine()" ) - This routine produces a call trace (recording entry and exit of each routine) when the macro DEBUG_FUN is defined during compilation. This produces lots of output and is only used as a last resort when all other debugging methods fail to uncover where the code crashes. To keep the bulk of the output down, trivial routines typically do not have the DEBUG_ENTRY call. This is especially the case for code that is intended to be inlined. Any routine that calls cdEXIT also must have a call to DEBUG_ENTRY at the start. The debugtrace class generated by the DEBUG_ENTRY call is used as a source of the routine name so that it can be printed in the exit message. Once the C++0x standard is in effect, this can be replaced with the __func__ string, but for now this is the only reliable source of the routine name.

ASSERT - the Cloudy form of the assert macro. Should always be used. This will normally throw an exception that can be caught. Typically it will be caught by the main program, which is not useful for debugging. If you want to debug a failed assert, you can insert the SET ASSERT ABORT command in the input script, or (even better) run Cloudy with the -a command line flag. The latter form is strictly needed when the assert fails before the input is even parsed. This will cause the code to abort rather than throw an exception on a failed assert. The abort will then be caught by the debugger.

The industry standard behavior of the assert macro can be recovered by defining the macro ASSERTDEBUG. GJF recommends that this macro always be defined on the compile step. When defined the code will call MyAssert. You can place breakpoints within MyAssert and debug the code. Another benefit of the macro ASSERTDEBUG is that a grid run will abort. An assert is thrown when insanity is detected. If the macro ASSERTDEBUG is not included the grid will continue after detecting a major bug. None of the grid results should be trusted if an assert occurs so continuing the grid is a waste of time. If an assert is thrown during a calculation you should immediately either report the bug on the discussion board or fix the bug yourself.

Always include the ASSERTDEBUG macro for safe and sane behavior.

MALLOC / CALLOC / REALLOC - the Cloudy forms of malloc, calloc, realloc. In debug mode (more precisely, when the macros NDEBUG and NOINIT are not set) MALLOC will trash the allocated memory to guard against uninitialized use. Be aware that this is not fool-proof though, uninitialized use may still go undetected! Use valgrind / purify for proper detection of uninitialized use of vars (NB - see also the compiler macro NOINIT below). CAVEAT: never use these routines to allocate memory for a class or struct with a constructor and/or destructor as these will not be executed! Use new / delete instead if you want a single instance, or new [] / delete[] if you want an array (or even better: use a container class like valarray, multi_arr, etc., since they will automatically deallocate the memory for you). As a rule of thumb, prefer new / delete over MALLOC / CALLOC / REALLOC in all cases, but certainly never use the latter for anything other than fundamental types.

TorF( bool ) - returns the character T or F indicating the value of the bool argument. This allows values of logical variables to be printed in way that makes sense to people.

Routines that set flags

fixit() / broken() - code that needs to be fixed or is broken. There is clearly some overlap between the two. Typical use for fixit() would be when you see code that needs to be improved, but you don't want to deal with that now. Prepend the code with a call to fixit() and a short comment explaining what needs to be done. On the other hand, broken() is typically used when you e.g. hack the code to disable some physics or deliberately feed wrong input during testing. In that case prepend the hack with a call to broken() to assure it gets deleted after testing is complete. Also add a comment explaining what needs to be done to get back to normal behavior of the code.

TotalInsanity() - used to close clauses that cannot possibly happen.

ShowMe() - generates a request to show the output to the group, along with a printout of the input stream that caused it.

Compiler macros

These macros are set with compiler options. For most compilers the macro OPTION would be set with -DOPTION

MPI_ENABLED - the compile-time macro that is set to enable MPI. If set then MPI header files will be included in parts of the source.

Profiling

USE_GPROF This removes the STATIC command so that all routines are global. This means that all the cpu time is correctly ascribed to the chunk of code which used it. However, it also means that the performance benefits of inlining are lost, so it isn't clear whether this information is meaningful once you've done it. Note that this only effects inlined functions, rather than things with file scope.

Array bounds

BOUNDS_CHECK enables array bounds checking for those arrays that use the multi_arr or flex_arr method. This is described further on the MultiArrPage page. A failed bounds check will throw an exception that is caught in the main program. This is not useful for debugging. If you want to debug a failed bounds check, run Cloudy with the -a command line parameter, which will cause the code to abort rather than throw an exception. The abort will then be caught by the debugger.

Memory checking

NOINIT - The fact that MALLOC trashes its memory will fool valgrind / purify into believing that the allocated memory was properly initialized. So in valgrind / purify runs, compile with NOINIT to disable this behavior in order to properly detect use of uninitialized vars.


Return to DeveloperPages

Return to main wiki page

Return to nublado.org