aboutsummaryrefslogtreecommitdiff
path: root/src/NaNCheck.cc
diff options
context:
space:
mode:
Diffstat (limited to 'src/NaNCheck.cc')
-rw-r--r--src/NaNCheck.cc1127
1 files changed, 1127 insertions, 0 deletions
diff --git a/src/NaNCheck.cc b/src/NaNCheck.cc
new file mode 100644
index 0000000..d9eda83
--- /dev/null
+++ b/src/NaNCheck.cc
@@ -0,0 +1,1127 @@
+/*@@
+ @file NaNCheck.c
+ @date Sat 21 Apr 2001
+ @author Thomas Radke
+ @desc
+ Routines to check CCTK real and complex variables
+ against Not-a-Number values.
+ @enddesc
+ @version $Id: NaNCheck.c 101 2012-03-27 03:16:10Z rhaas $
+ @@*/
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "cctk.h"
+#include "cctk_WarnLevel.h"
+#include "cctk_Arguments.h"
+#include "cctk_Parameters.h"
+#include "cctk_Termination.h"
+#include "cctk_FortranString.h"
+
+#include "util_String.h"
+
+#include "NaNCheck.h"
+
+
+/* the rcsid and the macro to use it */
+static const char *rcsid = "$Header$";
+CCTK_FILEVERSION(CactusUtils_NaNChecker_NaNCheck_c)
+
+
+/********************************************************************
+ ******************** External Routines ************************
+ ********************************************************************/
+extern "C" {
+void NaNChecker_ResetCounter (CCTK_ARGUMENTS);
+void NaNChecker_NaNCheck (CCTK_ARGUMENTS);
+void NaNChecker_TakeAction (CCTK_ARGUMENTS);
+}
+
+/********************************************************************
+ ******************** Fortran Wrappers ************************
+ ********************************************************************/
+extern "C" {
+void CCTK_FCALL CCTK_FNAME (NaNChecker_CheckVarsForNaN)
+ (int *ierror,
+ const cGH **GH,
+ const int *report_max,
+ THREE_FORTSTRING_ARG);
+void CCTK_FCALL CCTK_FNAME (NaNChecker_SetVarsToNaN)
+ (int *ierror,
+ const cGH **GH,
+ ONE_FORTSTRING_ARG);
+}
+
+
+/********************************************************************
+ ******************** Internal Routines ************************
+ ********************************************************************/
+static void CheckForNaN (int vindex, const char *optstring, void *arg);
+static void SetToNaN (int vindex, const char *optstring, void *arg);
+static void PrintWarning (const char *error_type,
+ int verbose,
+ int linear_index,
+ int reflevel,
+ int cctk_iteration,
+ int fp_type,
+ const CCTK_REAL *const coords[],
+ const char *fullname,
+ const cGroupDynamicData *gdata);
+
+/********************************************************************
+ ******************** Internal Typedefs ************************
+ ********************************************************************/
+typedef struct
+{
+ const cGH *GH;
+ int verbose;
+ int report_max;
+ const char *action_if_found;
+ CCTK_INT count;
+ CCTK_INT *NaNmask;
+ int bitmask;
+#ifdef HAVE_FINITE
+ enum {CHECK_FOR_NAN = 0, CHECK_FOR_INF = 1, CHECK_FOR_BOTH = 2} check_for;
+#endif
+ int cctk_iteration;
+ int ignore_restricted_points;
+ const char *restriction_mask;
+} t_nanchecker_info;
+
+
+/********************************************************************
+ ******************** Static Variables ************************
+ ********************************************************************/
+static int last_iteration_output = -1;
+
+
+ /*@@
+ @routine NaNChecker_ResetCounter
+ @author Thomas Radke
+ @date Tue 22 June 2004
+ @desc
+ Set the NaNChecker::NaNsFound counter to 0.
+ @enddesc
+
+ @var GH
+ @vdesc Pointer to CCTK GH
+ @vtype const cGH *
+ @vio in
+ @endvar
+@@*/
+void NaNChecker_ResetCounter (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+
+ *NaNsFound = 0;
+}
+
+
+ /*@@
+ @routine NaNChecker_NaNCheck
+ @author Thomas Radke
+ @date Sat 21 Apr 2001
+ @desc
+ If it is time to check, loop through all variables to check
+ for NaN values
+ @enddesc
+ @calls CCTK_TraverseString
+ CheckForNaN
+
+ @var GH
+ @vdesc Pointer to CCTK GH
+ @vtype const cGH *
+ @vio in
+ @endvar
+@@*/
+static t_nanchecker_info info;
+extern "C"
+void NaNChecker_NaNCheck_Prepare (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+ int i, nelems;
+
+
+ if (cctk_iteration < check_after || cctk_iteration % check_every)
+ {
+ return;
+ }
+
+ info.GH = cctkGH;
+ info.count = 0;
+ info.bitmask = 0;
+ info.report_max = report_max;
+ info.action_if_found = action_if_found;
+ info.verbose = CCTK_Equals (verbose, "all");
+ info.cctk_iteration = cctk_iteration;
+ info.ignore_restricted_points = ignore_restricted_points;
+ info.restriction_mask = restriction_mask;
+
+ info.NaNmask = out_NaNmask ? NaNmask : NULL;
+ if (info.NaNmask)
+ {
+ /* NaNmask can only be output once per iteration */
+ if (cctk_iteration == last_iteration_output)
+ {
+ CCTK_WARN (2, "Already output NaNmask at this iteration");
+ return;
+ }
+
+ /* zero out the NaN mask */
+ for (i = 0, nelems = 1; i < cctk_dim; i++)
+ {
+ nelems *= cctk_lsh[i];
+ }
+ memset (info.NaNmask, 0, nelems * sizeof (CCTK_INT));
+ }
+
+#ifdef HAVE_FINITE
+ if (CCTK_Equals (check_for, "NaN"))
+ {
+ info.check_for = t_nanchecker_info::CHECK_FOR_NAN;
+ }
+ else if (CCTK_Equals (check_for, "Inf"))
+ {
+ info.check_for = t_nanchecker_info::CHECK_FOR_INF;
+ }
+ else
+ {
+ info.check_for = t_nanchecker_info::CHECK_FOR_BOTH;
+ }
+#endif
+}
+void NaNChecker_NaNCheck_Check (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ if (cctk_iteration < check_after || cctk_iteration % check_every ||
+ (info.NaNmask && cctk_iteration == last_iteration_output))
+ {
+ return;
+ }
+
+ CCTK_TraverseString (check_vars, CheckForNaN, &info, CCTK_GROUP_OR_VAR);
+}
+void NaNChecker_NaNCheck_Finish (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+ if (cctk_iteration < check_after || cctk_iteration % check_every ||
+ (info.NaNmask && cctk_iteration == last_iteration_output))
+ {
+ return;
+ }
+
+ /* reduce the NaN counter globally and accumulate in NaNChecker::NaNsFound */
+ int sum_handle = CCTK_ReductionHandle ("sum");
+ CCTK_INT count = 0;
+ CCTK_ReduceLocalScalar (cctkGH, -1, sum_handle, &info.count, &count,
+ CCTK_VARIABLE_INT);
+ *NaNsFound += count;
+}
+
+
+ /*@@
+ @routine NaNChecker_TakeAction
+ @author Thomas Radke
+ @date Tue 22 June 2004
+ @desc
+ If any NaNs were found, output the NaNmask (if requested)
+ and take some action (according to NaNChecker::action_if_found).
+ @enddesc
+
+ @var GH
+ @vdesc Pointer to CCTK GH
+ @vtype const cGH *
+ @vio in
+ @endvar
+@@*/
+extern "C"
+void NaNChecker_TakeAction (CCTK_ARGUMENTS)
+{
+ DECLARE_CCTK_ARGUMENTS;
+ DECLARE_CCTK_PARAMETERS;
+
+
+ /* if no NaNs were found then this routine doesn't do anything */
+ if (! *NaNsFound)
+ {
+ return;
+ }
+
+ /* output NaN mask with the 'IOHDF5' I/O method */
+ if (out_NaNmask)
+ {
+ if (CCTK_Equals (verbose, "all"))
+ {
+ CCTK_INFO ("Write out NaN mask using the 'IOHDF5' I/O method");
+ }
+ CCTK_OutputVarAsByMethod (cctkGH,
+ "NaNChecker::NaNmask{downsample={1 1 1}}",
+ "IOHDF5", "NaNmask");
+
+ /* save the iteration of the last NaNmask output */
+ last_iteration_output = cctk_iteration;
+ }
+
+ if (CCTK_Equals (action_if_found, "terminate"))
+ {
+ CCTK_WARN (1, "'action_if_found' parameter is set to 'terminate' - "
+ "scheduling graceful termination of Cactus");
+ CCTK_TerminateNext (cctkGH);
+ }
+ else if (CCTK_Equals (action_if_found, "abort"))
+ {
+ CCTK_WARN (1, "'action_if_found' parameter is set to 'abort' - "
+ "aborting Cactus now");
+ CCTK_Abort (cctkGH, 0);
+ }
+}
+
+
+ /*@@
+ @routine NaNChecker_CheckVarsForNaN
+ @author Thomas Radke
+ @date Wed 5 Dec 2001
+ @desc
+ User-callable routine to check for NaN values
+ in CCTK grid variables.
+ @enddesc
+ @calls CCTK_TraverseString
+ CheckForNaN
+
+ @var GH
+ @vdesc Pointer to CCTK GH
+ @vtype const cGH *
+ @vio in
+ @endvar
+ @var report_max
+ @vdesc How many NaN's to report
+ @vtype int
+ @vio in
+ @endvar
+ @var vars
+ @vdesc Groups and/or variables to check for NaN's
+ @vtype const char *
+ @vio in
+ @endvar
+ @var check_for
+ @vdesc Whether to check for NaN's and/or infinite numbers
+ This is only evaluated if finite(3) is available.
+ @vtype const char *
+ @vio in
+ @endvar
+ @var action_if_found
+ @vdesc What do do if a NaN was found
+ This is treated the same as the KEYWORD parameter
+ 'NaNChecker::action_if_found' in that it can only take certain
+ values, or NULL if the routine should be quiet and just return
+ the number of NaN values found.
+ @vtype const char *
+ @vio in
+ @endvar
+
+ @returntype int
+ @returndesc
+ the total number of NaN values found, or<BR>
+ -1 if NaNChecker was already called at this iteration,<BR>
+ -2 if a NULL pointer was passed for 'GH' and/or 'vars',<BR>
+ -3 if an unknown keyword was passed in 'action_if_found',<BR>
+ -4 if the 'vars' string couldn't be parsed
+ @endreturndesc
+@@*/
+extern "C"
+int NaNChecker_CheckVarsForNaN (const cGH *GH,
+ int report_max,
+ const char *vars,
+ const char *check_for,
+ const char *action_if_found)
+{
+ CCTK_STRING verbose = (CCTK_STRING)CCTK_ParameterGet("verbose", "NaNChecker", NULL);
+ assert(verbose);
+ const CCTK_INT * ignore_restricted_points = (const CCTK_INT *)CCTK_ParameterGet("ignore_restricted_points", "NaNChecker", NULL);
+ assert(ignore_restricted_points);
+
+ t_nanchecker_info info;
+
+
+ if (GH == NULL || vars == NULL)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "NULL pointer passed for 'GH' and/or 'vars' argument");
+ return (-2);
+ }
+#if 0
+ if (cctk_iteration == last_iteration_output)
+ {
+ CCTK_WARN (2, "Already called NaNChecker I/O method at this iteration");
+ return (-1);
+ }
+#endif
+
+ if (action_if_found && (! CCTK_Equals (action_if_found, "just warn") &&
+ ! CCTK_Equals (action_if_found, "terminate") &&
+ ! CCTK_Equals (action_if_found, "abort")))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Unknown keyword '%s' for 'action_if_found' argument",
+ action_if_found);
+ return (-3);
+ }
+
+ info.GH = GH;
+ info.count = 0;
+ info.bitmask = 0;
+ info.verbose = CCTK_Equals (verbose, "all");
+ info.report_max = report_max;
+ info.action_if_found = action_if_found;
+ info.NaNmask = NULL;
+ info.cctk_iteration = GH->cctk_iteration;
+ info.ignore_restricted_points = *ignore_restricted_points;
+
+#ifdef HAVE_FINITE
+ if (CCTK_Equals (check_for, "NaN"))
+ {
+ info.check_for = t_nanchecker_info::CHECK_FOR_NAN;
+ }
+ else if (CCTK_Equals (check_for, "Inf"))
+ {
+ info.check_for = t_nanchecker_info::CHECK_FOR_INF;
+ }
+ else
+ {
+ if (! CCTK_Equals (check_for, "both"))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Invalid value '%s' passed for 'check_for' parameter. "
+ "Defaulting to 'both' instead.", check_for);
+ }
+ info.check_for = t_nanchecker_info::CHECK_FOR_BOTH;
+ }
+#endif
+
+ if (CCTK_TraverseString (vars, CheckForNaN, &info, CCTK_GROUP_OR_VAR) < 0)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Couldn't traverse 'vars' string '%s'", vars);
+ return (-4);
+ }
+
+#if 0
+ /* save the iteration of the last call */
+ last_iteration_output = GH->cctk_iteration;
+#endif
+
+ if (info.count > 0 && info.action_if_found)
+ {
+ if (CCTK_Equals (info.action_if_found, "terminate"))
+ {
+ CCTK_WARN (1, "'action_if_found' parameter is set to 'terminate' - "
+ "scheduling graceful termination of Cactus");
+ CCTK_TerminateNext (NULL);
+ }
+ else if (info.action_if_found && CCTK_Equals (info.action_if_found, "abort"))
+ {
+ CCTK_WARN (1, "'action_if_found' parameter is set to 'abort' - "
+ "aborting Cactus now");
+ CCTK_Abort (NULL, 0);
+ }
+ }
+
+ return (info.count);
+}
+
+extern "C"
+void CCTK_FCALL CCTK_FNAME (NaNChecker_CheckVarsForNaN)
+ (int *ierror,
+ const cGH **GH,
+ const int *report_max,
+ THREE_FORTSTRING_ARG)
+{
+ THREE_FORTSTRING_CREATE (vars, check_for, action_if_found);
+ *ierror = NaNChecker_CheckVarsForNaN (*GH, *report_max, vars, check_for,
+ *action_if_found ? action_if_found : NULL);
+ free (vars);
+ free (check_for);
+ free (action_if_found);
+}
+
+
+ /*@@
+ @routine NaNChecker_SetVarsToNaN
+ @author Thomas Radke
+ @date Sun 9 Dec 2001
+ @desc
+ User-callable routine to set CCTK grid variables to NaN values.
+ @enddesc
+ @calls CCTK_TraverseString
+ SetToNaN
+
+ @var GH
+ @vdesc Pointer to CCTK GH
+ @vtype const cGH *
+ @vio in
+ @endvar
+ @var vars
+ @vdesc Groups and/or variables to set to NaN's
+ @vtype const char *
+ @vio in
+ @endvar
+
+ @returntype int
+ @returndesc
+ 0 for success, or<BR>
+ -1 if a NULL pointer was passed for 'GH' and/or 'vars',<BR>
+ -2 if the 'vars' string couldn't be parsed
+ @endreturndesc
+@@*/
+extern "C"
+int NaNChecker_SetVarsToNaN (const cGH *GH,
+ const char *vars)
+{
+ t_nanchecker_info info;
+
+
+ if (GH == NULL || vars == NULL)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "NULL pointer passed for 'GH' and/or 'vars' argument");
+ return (-1);
+ }
+
+ info.GH = GH;
+ info.count = 0;
+ if (CCTK_TraverseString (vars, SetToNaN, &info, CCTK_GROUP_OR_VAR) < 0)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Couldn't traverse 'vars' string '%s'", vars);
+ return (-2);
+ }
+
+ return (info.count);
+}
+
+extern "C"
+void CCTK_FCALL CCTK_FNAME (NaNChecker_SetVarsToNaN)
+ (int *ierror,
+ const cGH **GH,
+ ONE_FORTSTRING_ARG)
+{
+ ONE_FORTSTRING_CREATE (vars);
+ *ierror = NaNChecker_SetVarsToNaN (*GH, vars);
+ free (vars);
+}
+
+
+/********************************************************************
+ ******************** Internal Routines ************************
+ ********************************************************************/
+
+ /*@@
+ @routine PrintWarning
+ @author Thomas Radke
+ @date Sat 21 Apr 2001
+ @desc
+ Prints a warning for a Inf/NaN found in a variable
+ at the given processor-local linear index.
+ The warning includes the variable's fullname along with
+ the global index of the NaN element in fortran order.
+ If coordinates are available, the NaN's location on the grid
+ is also output.
+ @enddesc
+ @calls CCTK_VWarn
+
+ @var error_type
+ @vdesc string containing the error value found (NaN or Inf)
+ @vtype const char *
+ @vio in
+ @endvar
+ @var verbose
+ @vdesc how much information to give
+ @vtype int
+ @vio in
+ @endvar
+ @var linear_index
+ @vdesc processor-local linear index of the NaN/Inf
+ @vtype int
+ @vio in
+ @endvar
+ @var reflevel
+ @vdesc current refinement level (0 for unigrid)
+ @vtype int
+ @vio in
+ @endvar
+ @var cctk_iteration
+ @vdesc current iteration
+ @vtype int
+ @vio in
+ @endvar
+ @var fp_type
+ @vdesc indicates if variable of of real or complex type
+ @vtype int
+ @vio in
+ @endvar
+ @var fullname
+ @vdesc full name of the variable
+ @vtype const char *
+ @vio in
+ @endvar
+ @var coords
+ @vdesc array of coordinates
+ @vtype const CCTK_REAL *const [ dimension of variable ]
+ @vio in
+ @endvar
+ @var gdata
+ @vdesc size information on the variable to compute the global index
+ @vtype const cGroupDynamicData *
+ @vio in
+ @endvar
+@@*/
+static void PrintWarning (const char *error_type,
+ int verbose,
+ int linear_index,
+ int reflevel,
+ int cctk_iteration,
+ int fp_type,
+ const CCTK_REAL *const coords[],
+ const char *fullname,
+ const cGroupDynamicData *gdata)
+{
+ int i;
+ char *index_string, *coord_string;
+ const char *complex_part;
+ int amended_index;
+
+
+ if (fp_type == 2)
+ {
+ complex_part = linear_index & 1 ? "imag part of " : "real part of ";
+ linear_index /= 2;
+ }
+ else
+ {
+ complex_part = "";
+ }
+
+ if (gdata->dim == 0)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "%s caught in %svariable '%s'",
+ error_type, complex_part, fullname);
+ }
+ else if (verbose)
+ {
+ /* assume max. 10 characters per index number and 40 characters per
+ coordinate value (including separators) */
+ index_string = (char *)malloc (5 * 10 * gdata->dim);
+ coord_string = index_string + 10 * gdata->dim;
+
+ amended_index = linear_index;
+
+ sprintf (index_string, "%d",
+ (amended_index % gdata->lsh[0]) + gdata->lbnd[0] + 1);
+ if (coords)
+ {
+ sprintf (coord_string, "%5.3e", (double) coords[0][linear_index]);
+ }
+ for (i = 1; i < gdata->dim; i++)
+ {
+ amended_index /= gdata->lsh[i - 1];
+ sprintf (index_string, "%s, %d", index_string,
+ (amended_index % gdata->lsh[i]) + gdata->lbnd[i] + 1);
+ if (coords)
+ {
+ sprintf (coord_string, "%s, %5.3e", coord_string,
+ (double) coords[i][linear_index]);
+ }
+ }
+
+ if (coords)
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "%s caught in %svariable '%s' at index (%s) level %d with coordinates "
+ "(%s) in iteration %d", error_type, complex_part, fullname, index_string,
+ reflevel, coord_string, cctk_iteration);
+ }
+ else
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "%s caught in %svariable '%s' at (%s) level %d in iteration %d",
+ error_type, complex_part, fullname, index_string,
+ reflevel, cctk_iteration);
+ }
+
+ free (index_string);
+ }
+}
+
+
+ /*@@
+ @routine CHECK_DATA
+ @date Sat 21 Apr 2001
+ @author Thomas Radke
+ @desc
+ Macro to check a given typed array against NaN's.
+ If finite(3) is available on the system it will also check
+ for Inf values.
+ @enddesc
+ @calls PrintWarning
+
+ @var cctk_type
+ @vdesc CCTK variable type of variable to check
+ @vtype <CCTK vartype>
+ @vio in
+ @endvar
+@@*/
+template<class cctk_type> static void
+CHECK_DATA(const cctk_type *_data, int nelems, const CCTK_REAL *CarpetWeights,
+ const t_nanchecker_info *info, CCTK_INT &nans_found,
+ int reflevel, CCTK_INT cctk_iteration, int fp_type, const CCTK_REAL * const *coords,
+ const char *fullname, const cGroupDynamicData &gdata, CCTK_INT gtype)
+{
+ /* now loop over all elements and check against NaN's */
+#pragma omp parallel for schedule(dynamic)
+ for (int _i = 0; _i < nelems; _i++)
+ {
+ if ((!CarpetWeights || CarpetWeights[_i] > 0.0) && (
+#if defined(HAVE_ISNAN) && defined(HAVE_FINITE)
+ ! finite ((double) _data[_i]) && (info->check_for == t_nanchecker_info::CHECK_FOR_BOTH ||
+ ((isnan ((double) _data[_i]) & 1) ^ info->check_for))
+#elif defined(NAVE_ISNAN)
+ isnan ((double) _data[_i])
+#else
+ 0
+#endif
+ ))
+ {
+#pragma omp critical
+ {
+ nans_found++;
+ if (info->action_if_found &&
+ (info->report_max < 0 || nans_found <= info->report_max))
+ {
+ PrintWarning (isnan ((double) _data[_i]) ? "NaN" : "Inf",
+ info->verbose, _i, reflevel, cctk_iteration, fp_type,
+ coords, fullname, &gdata);
+ }
+ if (info->NaNmask && gtype == CCTK_GF)
+ {
+ info->NaNmask[_i] |= 1 << info->bitmask;
+ }
+ }
+ }
+ }
+}
+
+
+
+ /*@@
+ @routine CheckForNaN
+ @date Sat 21 Apr 2001
+ @author Thomas Radke
+ @desc
+ Checks a CCTK variable given by its index against NaN's.
+ If an 'action_if_found' was given it will issue a warning
+ each time a NaN was found and also terminate Cactus afterwards
+ if requested.
+ Note that only floating point typed variables are checked.
+ <BR>
+ This routine is called as a callback via CCTK_TraverseString().
+ @enddesc
+ @calls CHECK_DATA
+
+ @var vindex
+ @vdesc index of variable to check
+ @vtype int
+ @vio in
+ @endvar
+ @var optstring
+ @vdesc optional timelevel string appended to the group/variable name
+ @vtype const char *
+ @vio in
+ @endvar
+ @var _info
+ @vdesc Pointer to NaNChecker info structure
+ @vtype void *
+ @vio in
+ @endvar
+@@*/
+static void CheckForNaN (int vindex, const char *optstring, void *_info)
+{
+ t_nanchecker_info *info;
+ int i, sum_handle;
+ CCTK_INT nans_found, global_nans_found;
+ int timelevel, fp_type, vtype, gtype, gindex, nelems;
+ char *fullname, *endptr;
+ const char *vtypename;
+ char coord_system_name[10];
+ const CCTK_REAL **coords;
+ cGroupDynamicData gdata;
+ const void *data;
+ CCTK_REAL *CarpetWeights;
+ int reflevel;
+ int cctk_iteration, ignore_restricted_points;
+ const char *restriction_mask;
+
+
+ info = (t_nanchecker_info *)_info;
+ cctk_iteration = info->cctk_iteration;
+ ignore_restricted_points = info->ignore_restricted_points;
+ restriction_mask = info->restriction_mask;
+
+ vtype = CCTK_VarTypeI (vindex);
+ fullname = CCTK_FullName (vindex);
+ if(CCTK_IsFunctionAliased("GetRefinementLevel"))
+ {
+ reflevel = GetRefinementLevel(info->GH);
+ }
+ else
+ {
+ reflevel = 0;
+ }
+
+ /* check if the variable type is some floating point */
+ vtypename = CCTK_VarTypeName (vtype);
+ if (strncmp (vtypename, "CCTK_VARIABLE_REAL", 18) == 0)
+ {
+ fp_type = nelems = 1;
+ }
+ else if (strncmp (vtypename, "CCTK_VARIABLE_COMPLEX", 22) == 0)
+ {
+ fp_type = nelems = 2;
+ }
+ else
+ {
+ CCTK_VWarn (9, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "CheckForNaN: Ignoring variable '%s' "
+ "(not a floating-point variable)", fullname);
+ free (fullname);
+ return;
+ }
+
+ /* check if variable has storage assigned */
+ gindex = CCTK_GroupIndexFromVarI (vindex);
+ if (CCTK_QueryGroupStorageI (info->GH, gindex)<=0)
+ {
+ CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "CheckForNaN: Ignoring variable '%s' (no storage)", fullname);
+ free (fullname);
+ return;
+ }
+
+ /* get the timelevel to check */
+ if (optstring)
+ {
+ if (strncmp (optstring, "timelevel=", 10))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "CheckForNaN: Invalid option string '%s' given for variable "
+ "'%s'", optstring, fullname);
+ free (fullname);
+ return;
+ }
+ else
+ {
+ timelevel = strtol (optstring + 10, &endptr, 10);
+ if (*endptr != ']' ||
+ timelevel < 0 || timelevel >= CCTK_MaxTimeLevelsVI (vindex))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "CheckForNaN: Invalid timelevel '%s' given for variable "
+ "'%s'", optstring + 10, fullname);
+ free (fullname);
+ return;
+ }
+ }
+ }
+ else
+ {
+ /* default timelevel */
+ timelevel = 0;
+ }
+
+ /* get the number of elements to check for this variable */
+ gdata.dim = 0;
+ coords = NULL;
+ gtype = CCTK_GroupTypeI (gindex);
+ if (gtype != CCTK_SCALAR)
+ {
+ CCTK_GroupDynamicData (info->GH, gindex, &gdata);
+ if (gtype == CCTK_GF)
+ {
+ sprintf (coord_system_name, "cart%dd", gdata.dim);
+ if (CCTK_CoordSystemHandle (coord_system_name) >= 0)
+ {
+ coords = (const CCTK_REAL **)malloc (gdata.dim * sizeof (const CCTK_REAL *));
+ }
+ }
+ for (i = 0; i < gdata.dim; i++)
+ {
+ nelems *= gdata.lsh[i];
+ if (coords)
+ {
+ coords[i] = (const CCTK_REAL *) CCTK_VarDataPtrI (info->GH, 0,
+ CCTK_CoordIndex (i + 1, NULL, coord_system_name));
+ if (! coords[i])
+ {
+ free (coords);
+ coords = NULL;
+ }
+ }
+ }
+ }
+
+ /* get the pointer to the data (current time level) */
+ data = CCTK_VarDataPtrI (info->GH, timelevel, vindex);
+ if (ignore_restricted_points)
+ {
+ CarpetWeights = (CCTK_REAL *)(CCTK_VarDataPtr(info->GH, timelevel, restriction_mask));
+ if (NULL == CarpetWeights)
+ {
+ static char *warned_about = NULL;
+#pragma omp critical
+ if (NULL == warned_about || strcmp(warned_about, restriction_mask) != 0)
+ {
+ if (NULL != warned_about)
+ free(warned_about);
+ warned_about = Util_Strdup(restriction_mask);
+ CCTK_VWarn (CCTK_WARN_ALERT, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "Could not obtain pointer to restriction mask '%s', reverting to check all points",
+ restriction_mask);
+ }
+ }
+ }
+ else
+ {
+ CarpetWeights = NULL;
+ }
+
+ /* do the checking according to the variable's type */
+ nans_found = 0;
+ if (vtype == CCTK_VARIABLE_REAL || vtype == CCTK_VARIABLE_COMPLEX)
+ {
+ CHECK_DATA((CCTK_REAL *)data, nelems, CarpetWeights,
+ info, nans_found, reflevel, cctk_iteration, fp_type, coords,
+ fullname, gdata, gtype);
+ }
+#ifdef CCTK_REAL4
+ else if (vtype == CCTK_VARIABLE_REAL4 || vtype == CCTK_VARIABLE_COMPLEX8)
+ {
+ CHECK_DATA((CCTK_REAL4 *)data, nelems, CarpetWeights,
+ info, nans_found, reflevel, cctk_iteration, fp_type, coords,
+ fullname, gdata, gtype);
+ }
+#endif
+#ifdef CCTK_REAL8
+ else if (vtype == CCTK_VARIABLE_REAL8 || vtype == CCTK_VARIABLE_COMPLEX16)
+ {
+ CHECK_DATA((CCTK_REAL8 *)data, nelems, CarpetWeights,
+ info, nans_found, reflevel, cctk_iteration, fp_type, coords,
+ fullname, gdata, gtype);
+ }
+#endif
+#ifdef CCTK_REAL16
+ else if (vtype == CCTK_VARIABLE_REAL16 || vtype == CCTK_VARIABLE_COMPLEX32)
+ {
+ CHECK_DATA((CCTK_REAL16 *)data, nelems, CarpetWeights,
+ info, nans_found, reflevel, cctk_iteration, fp_type, coords,
+ fullname, gdata, gtype);
+ }
+#endif
+ else
+ {
+ CCTK_VWarn (0, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "NanCheck: Unknown variable type '%s' for variable '%s'",
+ vtypename, fullname);
+ }
+
+ /* Do more than just print a warning ? */
+ if (nans_found > 0 && info->action_if_found && gdata.dim > 0)
+ {
+ if (info->NaNmask && gtype == CCTK_GF && info->bitmask < 8*sizeof (CCTK_INT))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "There were %d NaN/Inf value(s) found in variable '%s' "
+ "(NaNmask bitfield %d)",
+ (int) nans_found, fullname, info->bitmask);
+ }
+ else
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "There were %d NaN/Inf value(s) found in variable '%s'",
+ (int) nans_found, fullname);
+ }
+ }
+ /* check if the (global) bitmask needs to be incremented */
+ if (info->NaNmask && gtype == CCTK_GF && info->bitmask < 8*sizeof (CCTK_INT))
+ {
+ sum_handle = CCTK_ReductionHandle ("sum");
+ CCTK_ReduceLocalScalar (info->GH, -1, sum_handle, &nans_found,
+ &global_nans_found, CCTK_VARIABLE_INT);
+ if (global_nans_found)
+ {
+ info->bitmask++;
+ }
+ }
+ info->count += nans_found;
+
+ if (coords)
+ {
+ free (coords);
+ }
+ free (fullname);
+}
+
+
+ /*@@
+ @routine SetToNaN
+ @date Sun 9 Dec 2001
+ @author Thomas Radke
+ @desc
+ Initializes a CCTK variable given by its index to all NaN's.
+ Note that only floating point typed variables are initialized.
+ <BR>
+ This routine is called as a callback via CCTK_TraverseString().
+ @enddesc
+
+ @var vindex
+ @vdesc index of variable to initialize
+ @vtype int
+ @vio in
+ @endvar
+ @var optstring
+ @vdesc optional timelevel string appended to the group/variable name
+ @vtype const char *
+ @vio in
+ @endvar
+ @var _info
+ @vdesc Pointer to NaNChecker info structure
+ @vtype void *
+ @vio in
+ @endvar
+@@*/
+static void SetToNaN (int vindex, const char *optstring, void *_info)
+{
+ t_nanchecker_info *info;
+ int i, timelevel, vtype, gindex, nelems;
+ const char *vtypename;
+ char *fullname, *endptr;
+ cGroupDynamicData gdata;
+
+
+ info = (t_nanchecker_info *)_info;
+
+ vtype = CCTK_VarTypeI (vindex);
+ fullname = CCTK_FullName (vindex);
+
+ /* check if the variable type is some floating point */
+ vtypename = CCTK_VarTypeName (vtype);
+ if (strncmp (vtypename, "CCTK_VARIABLE_REAL", 18) == 0)
+ {
+ nelems = 1;
+ }
+ else if (strncmp (vtypename, "CCTK_VARIABLE_COMPLEX", 22) == 0)
+ {
+ nelems = 2;
+ }
+ else
+ {
+ CCTK_VWarn (9, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "SetToNaN: Ignoring variable '%s' "
+ "(not a floating-point variable)", fullname);
+ free (fullname);
+ return;
+ }
+
+ /* check if variable has storage assigned */
+ gindex = CCTK_GroupIndexFromVarI (vindex);
+ if (CCTK_QueryGroupStorageI (info->GH, gindex)<=0)
+ {
+ CCTK_VWarn (3, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "SetToNaN: Ignoring variable '%s' (no storage)", fullname);
+ free (fullname);
+ return;
+ }
+
+ /* get the timelevel to initialize */
+ if (optstring)
+ {
+ if (strncmp (optstring, "timelevel=", 10))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "SetToNaN: Invalid option string '%s' given for variable "
+ "'%s'", optstring, fullname);
+ free (fullname);
+ return;
+ }
+ else
+ {
+ timelevel = strtol (optstring + 10, &endptr, 10);
+ if (timelevel < 0 || timelevel >= CCTK_MaxTimeLevelsVI (vindex))
+ {
+ CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING,
+ "SetToNaN: Invalid timelevel '%s' given for variable "
+ "'%s'", optstring + 10, fullname);
+ free (fullname);
+ return;
+ }
+ }
+ }
+ else
+ {
+ /* default timelevel */
+ timelevel = 0;
+ }
+
+ /* get the number of elements to initialize for this variable */
+ if (CCTK_GroupTypeI (gindex) != CCTK_SCALAR)
+ {
+ CCTK_GroupDynamicData (info->GH, gindex, &gdata);
+ for (i = 0; i < gdata.dim; i++)
+ {
+ nelems *= gdata.lsh[i];
+ }
+ }
+
+ /* do the initialization */
+ memset (CCTK_VarDataPtrI (info->GH, timelevel, vindex),
+ -1, CCTK_VarTypeSize (vtype) * nelems);
+
+ /* count up the total number of variables initialized */
+ info->count++;
+
+ /* clean up */
+ free (fullname);
+}
+
+
+/********************************************************************
+ ******************** Schedule Wrappers ***********************
+ ********************************************************************/
+
+CCTK_INT
+NaNChecker_CheckVarsForNaN_Wrapper (CCTK_POINTER_TO_CONST const cctkGH_,
+ CCTK_INT const report_max,
+ CCTK_STRING const vars,
+ CCTK_STRING const check_for,
+ CCTK_STRING const action_if_found)
+{
+ return NaNChecker_CheckVarsForNaN ((cGH const *) cctkGH_,
+ report_max,
+ vars, check_for, action_if_found);
+}
+
+CCTK_INT
+NaNChecker_SetVarsToNaN_Wrapper (CCTK_POINTER_TO_CONST const cctkGH_,
+ CCTK_STRING const vars)
+{
+ return NaNChecker_SetVarsToNaN ((cGH const *) cctkGH_,
+ vars);
+}