diff options
Diffstat (limited to 'src/InterpLocalUniform.c')
-rw-r--r-- | src/InterpLocalUniform.c | 2314 |
1 files changed, 2314 insertions, 0 deletions
diff --git a/src/InterpLocalUniform.c b/src/InterpLocalUniform.c new file mode 100644 index 0000000..79e9e4c --- /dev/null +++ b/src/InterpLocalUniform.c @@ -0,0 +1,2314 @@ +/* InterpLocalUniform.c -- driver for this interpolator */ +/* $Header$ */ +/* +** *****data structures and functions local to this file ***** +** + * AEILocalInterp_U_Lagrange_TP - driver for Lagrange interpolator (tensor prod) + * AEILocalInterp_U_Lagrange_MD - driver for Lagrange interpolator (max degree) + * AEILocalInterp_U_Hermite - driver for Hermite interpolator +** +** InterpLocalUniform - main driver routine +** +** check_boundary_tolerances - check boundary tolerances for consistency +** get_and_decode_molecule_family - get & decode molecule_family from par table +** get_molecule_positions - get molecule_positions from parameter table +** get_Jacobian_query - get Jacobian-query info from parameter table +** set_error_info - set error information in parameter table +** set_molecule_structure - set molecule structure info in parameter table +** set_molecule_min_max_m - set molecule size info in parameter table +** +** get_and_check_INT - get and range-check CCTK_INT from parameter table +** get_INT_array - get CCTK_INT array from parameter table +** get_REAL_array - get CCTK_REAL array from parameter table + */ + +/*@@ + @file InterpLocalUniform.c + @date 22 Oct 2001 + @author Jonathan Thornburg <jthorn@aei.mpg.de> + @desc + Generalized Interpolation of processor-local arrays. + + This code interpolates a set of functions defined on a + uniform N-dimensional grid, to a set of interpolation points. + It can also do differentiation and/or smoothing in the process + of the interpolation. + + Conceptually, the generalized interpolation is done by + least-squares fitting a polynomial of the specified order + to the data values, applying the differentiation (if any) + to it, then evaluating the result at the interpolation points. + Since this ultimately yields _some_ linear combination of the + data values, we precompute the coefficients for efficiency. + This is done with separate Maple-generated formulas for each + combination of number of interpolation operator, number of + dimensions, molecule family, order, amount of Savitzky-Golay + smoothing to be done, and differentiation operator. + @enddesc + @version $Id$ + @@*/ + +#include <stdio.h> +#include <stdlib.h> /* malloc(), free() */ +#include <string.h> + +#include "cctk.h" +#include "util_ErrorCodes.h" +#include "util_String.h" +#include "util_Table.h" +#include "InterpLocalUniform.h" + +#include "Lagrange-tensor-product/all_prototypes.h" +#include "Lagrange-maximum-degree/all_prototypes.h" +#include "Hermite/all_prototypes.h" + +/* the rcs ID and its dummy function to use it */ +static const char* rcsid = "$Header$"; +CCTK_FILEVERSION(AEITHorns_AEILocalInterp_src_InterpLocalUniform_c) + +/******************************************************************************/ + +/* + * *****data structures and functions local to this file ***** + */ + +/**************************************/ + +/* + * data structures local to this file + */ + +/* this enum describes which interpolation operator we're using */ +enum interp_operator + { + interp_operator_Lagrange_TP, /* "Lagrange polynomial interpolation */ + /* (tensor product)" */ + interp_operator_Lagrange_MD, /* "Lagrange polynomial interpolation */ + /* (maximum degree)" */ + interp_operator_Hermite, /* "Hermite polynomial interpolation" */ + N_INTERP_OPERATORS /* this must be the last entry in the enum */ + }; + +/**************************************/ + +/* + * prototypes for functions local to this file + */ +static + int InterpLocalUniform(enum interp_operator interp_operator, + const char* interp_operator_string, + CCTK_REAL boundary_off_cntr_tol_default, + CCTK_REAL boundary_extrap_tol_default, + /***** misc arguments *****/ + int N_dims, + int param_table_handle, + /***** coordinate system *****/ + const CCTK_REAL coord_origin[], + const CCTK_REAL coord_delta[], + /***** interpolation points *****/ + int N_interp_points, + int interp_coords_type_code, + const void *const interp_coords[], + /***** input arrays *****/ + int N_input_arrays, + const CCTK_INT input_array_dims[], + const CCTK_INT input_array_type_codes[], + const void *const input_arrays[], + /***** output arrays *****/ + int N_output_arrays, + const CCTK_INT output_array_type_codes[], + void *const output_arrays[]); + +static + void check_boundary_tolerances + (int N_boundaries, + const CCTK_REAL boundary_off_centering_tolerance[MAX_N_BOUNDARIES], + const CCTK_REAL boundary_extrapolation_tolerance[MAX_N_BOUNDARIES]); +static + int get_and_decode_molecule_family + (int param_table_handle, + int buffer_size, char molecule_family_string_buffer[], + enum molecule_family *p_molecule_family); +static + int get_molecule_positions + (int param_table_handle, + int N_dims, CCTK_INT* molecule_positions_array[MAX_N_DIMS]); +static + int get_Jacobian_info(int param_table_handle, + int N_dims, int N_output_arrays, + struct Jacobian_info* p_Jacobian_info); +static + int set_error_info(int param_table_handle, + struct error_flags* p_error_flags); +static + int set_molecule_structure + (int param_table_handle, + const struct molecule_structure_flags* p_molecule_structure_flags); +static + int set_molecule_min_max_m + (int param_table_handle, + int N_dims, + const struct molecule_min_max_m_info* p_molecule_min_max_m_info); + +static + int get_and_check_INT + (int param_table_handle, const char name[], + bool mandatory_flag, int default_value, + bool check_range_flag, int min_value, int max_value, + const char max_value_string[], + int* p_value); +static + int get_INT_array(int param_table_handle, const char name[], + bool default_flag, int default_value, + int N, CCTK_INT buffer[], + bool* p_value_not_set); +static + int get_REAL_array(int param_table_handle, const char name[], + CCTK_REAL default_value, + int N, CCTK_REAL buffer[]); + +/**************************************/ + +/* + * table of function pointers pointing to the actual interpolation functions + */ + +/* + * typedef p_interp_fn_t as a function pointer pointing to an + * individual interpolator function of the sort defined by template.[ch] + */ +#undef FUNCTION_NAME +#define FUNCTION_NAME (*p_interp_fn_t) +typedef + #include "template.h" + +/* NULL (function) pointer of this type */ +#define NULL_INTERP_FN_PTR ((p_interp_fn_t) NULL) + +/* + * For each axis of this array which is marked with a "see above" comment + * in the array declaration, the array size is declared as X+1, so the + * legal subscripts are of course 0...X. But for these axes we actually + * only use 1...X. (Having the array oversize like this slightly simplifies + * the array subscripting.) + * + * In the comments on the initializers, "n.i." = "not implemented". + */ +static const p_interp_fn_t p_interp_fn_table[N_INTERP_OPERATORS] + [MAX_N_DIMS+1] /* see above */ + [N_MOLECULE_FAMILIES] + [MAX_ORDER+1] /* see above */ + [MAX_SMOOTHING+1] + = { + + { + /* interp_operator == interp_operator_Lagrange_TP */ + { + /* N_dims = 0 ==> unused */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=1 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=2 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=3 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=4 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=5 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (unused) */ + }, + }, + + { + /* N_dims = 1 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { AEILocalInterp_U_LagTP_1cube_10, }, /* order=1 */ + { AEILocalInterp_U_LagTP_1cube_20, }, /* order=2 */ + { AEILocalInterp_U_LagTP_1cube_30, }, /* order=3 */ + { AEILocalInterp_U_LagTP_1cube_40, }, /* order=4 */ + { AEILocalInterp_U_LagTP_1cube_50, }, /* order=5 */ + { AEILocalInterp_U_LagTP_1cube_60, }, /* order=6 */ + }, + }, + + { + /* N_dims = 2 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { AEILocalInterp_U_LagTP_2cube_10, }, /* order=1 */ + { AEILocalInterp_U_LagTP_2cube_20, }, /* order=2 */ + { AEILocalInterp_U_LagTP_2cube_30, }, /* order=3 */ + { AEILocalInterp_U_LagTP_2cube_40, }, /* order=4 */ + { NULL_INTERP_FN_PTR, }, /* order=5 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (n.i.) */ + }, + }, + + { + /* N_dims = 3 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { AEILocalInterp_U_LagTP_3cube_10, }, /* order=1 */ + { AEILocalInterp_U_LagTP_3cube_20, }, /* order=2 */ + { AEILocalInterp_U_LagTP_3cube_30, }, /* order=3 */ + { AEILocalInterp_U_LagTP_3cube_40, }, /* order=4 */ + { NULL_INTERP_FN_PTR, }, /* order=5 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (n.i.) */ + }, + }, + + /* end of interp_operator == interp_operator_Lagrange_TP */ + }, + + { + /* interp_operator == interp_operator_Lagrange_MD */ + { + /* N_dims = 0 ==> unused */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=1 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=2 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=3 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=4 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=5 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (unused) */ + }, + }, + + { + /* N_dims = 1 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { AEILocalInterp_U_LagMD_1cube_10, }, /* order=1 */ + { AEILocalInterp_U_LagMD_1cube_20, }, /* order=2 */ + { AEILocalInterp_U_LagMD_1cube_30, }, /* order=3 */ + { AEILocalInterp_U_LagMD_1cube_40, }, /* order=4 */ + { AEILocalInterp_U_LagMD_1cube_50, }, /* order=5 */ + { AEILocalInterp_U_LagMD_1cube_60, }, /* order=6 */ + }, + }, + + { + /* N_dims = 2 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { AEILocalInterp_U_LagMD_2cube_10, }, /* order=1 */ + { AEILocalInterp_U_LagMD_2cube_20, }, /* order=2 */ + { AEILocalInterp_U_LagMD_2cube_30, }, /* order=3 */ + { AEILocalInterp_U_LagMD_2cube_40, }, /* order=4 */ + { NULL_INTERP_FN_PTR, }, /* order=5 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (n.i.) */ + }, + }, + + { + /* N_dims = 3 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { AEILocalInterp_U_LagMD_3cube_10, }, /* order=1 */ + { AEILocalInterp_U_LagMD_3cube_20, }, /* order=2 */ + { AEILocalInterp_U_LagMD_3cube_30, }, /* order=3 */ + { AEILocalInterp_U_LagMD_3cube_40, }, /* order=4 */ + { NULL_INTERP_FN_PTR, }, /* order=5 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (n.i.) */ + }, + }, + + /* end of interp_operator == interp_operator_Lagrange_MD */ + }, + + { + /* interp_operator == interp_operator_Hermite */ + { + /* N_dims = 0 ==> unused */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=1 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=2 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=3 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=4 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=5 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (unused) */ + }, + }, + + { + /* N_dims = 1 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=1 (unused) */ + { AEILocalInterp_U_Herm_1cube_2, }, /* order=2 */ + { AEILocalInterp_U_Herm_1cube_3, }, /* order=3 */ + { AEILocalInterp_U_Herm_1cube_4, }, /* order=4 */ + { NULL_INTERP_FN_PTR, }, /* order=5 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (n.i.) */ + }, + }, + + { + /* N_dims = 2 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=1 (unused) */ + { AEILocalInterp_U_Herm_2cube_2, }, /* order=2 */ + { AEILocalInterp_U_Herm_2cube_3, }, /* order=3 */ + { NULL_INTERP_FN_PTR, }, /* order=4 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=5 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (n.i.) */ + }, + }, + + { + /* N_dims = 3 */ + { + /* molecule_family = molecule_family_cube */ + { NULL_INTERP_FN_PTR, }, /* order=0 (unused) */ + { NULL_INTERP_FN_PTR, }, /* order=1 (unused) */ + { AEILocalInterp_U_Herm_3cube_2, }, /* order=2 */ + { AEILocalInterp_U_Herm_3cube_3, }, /* order=3 */ + { NULL_INTERP_FN_PTR, }, /* order=4 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=5 (n.i.) */ + { NULL_INTERP_FN_PTR, }, /* order=6 (n.i.) */ + }, + }, + + /* end of interp_operator == interp_operator_Hermite */ + }, + + }; + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +/*@@ + @routine AEILocalInterp_U_Lagrange_TP + @date 22 Oct 2001 + @author Jonathan Thornburg <jthorn@aei.mpg.de> + @desc + This function is a top-level driver for + LocalInterp::CCTK_InterpLocalUniform(). + + It does Lagrange interpolation of a set of input arrays defined + on a uniform N-dimensional tensor-product grid, to a set of + interpolation points. For multidimensional interpolation, it + uses the tensor-product basis for the interpolating function, + so the interpolant is guaranteed to be continuous and to pass + through the input data at the grid points (up to floating-point + roundoff errors). + + This interpolator can also + * do differentiation and/or smoothing in the process of the + interpolation + * return information about the Jacobian of the interpolated + values with respect to the input arrays + + This function does nothing except pass all its arguments + down to InterpLocalUniform() with an extra 2 arguments + added to indicate the operator handle. See that function + for details on this function's arguments/results. + @enddesc + @@*/ +int AEILocalInterp_U_Lagrange_TP(int N_dims, + int param_table_handle, + /***** coordinate system *****/ + const CCTK_REAL coord_origin[], + const CCTK_REAL coord_delta[], + /***** interpolation points *****/ + int N_interp_points, + int interp_coords_type_code, + const void *const interp_coords[], + /***** input arrays *****/ + int N_input_arrays, + const CCTK_INT input_array_dims[], + const CCTK_INT input_array_type_codes[], + const void *const input_arrays[], + /***** output arrays *****/ + int N_output_arrays, + const CCTK_INT output_array_type_codes[], + void *const output_arrays[]) +{ +return InterpLocalUniform(interp_operator_Lagrange_TP, + "Lagrange polynomial interpolation (tensor product)", + LAGRANGE_BNDRY_OFF_CNTR_TOL_DEF, + LAGRANGE_BNDRY_EXTRAP_TOL_DEF, + N_dims, + param_table_handle, + coord_origin, coord_delta, + N_interp_points, + interp_coords_type_code, + interp_coords, + N_input_arrays, + input_array_dims, + input_array_type_codes, + input_arrays, + N_output_arrays, + output_array_type_codes, + output_arrays); +} + +/******************************************************************************/ + +/*@@ + @routine AEILocalInterp_U_Lagrange_MD + @date 22 Oct 2001 + @author Jonathan Thornburg <jthorn@aei.mpg.de> + @desc + This function is a top-level driver for + LocalInterp::CCTK_InterpLocalUniform(). + + It does Lagrange interpolation of a set of input arrays defined + on a uniform N-dimensional tensor-product grid, to a set of + interpolation points. For multidimensional interpolation, it + uses the maximum-degree basis for the interpolating function. + This means the interpolant is in general *not* continuous and + in general does *not* pass through the input data at the grid + points. + + This interpolator can also + * do differentiation and/or smoothing in the process of the + interpolation + * return information about the Jacobian of the interpolated + values with respect to the input arrays + + This function does nothing except pass all its arguments + down to InterpLocalUniform() with an extra 2 arguments + added to indicate the operator handle. See that function + for details on this function's arguments/results. + @enddesc + @@*/ +int AEILocalInterp_U_Lagrange_MD(int N_dims, + int param_table_handle, + /***** coordinate system *****/ + const CCTK_REAL coord_origin[], + const CCTK_REAL coord_delta[], + /***** interpolation points *****/ + int N_interp_points, + int interp_coords_type_code, + const void *const interp_coords[], + /***** input arrays *****/ + int N_input_arrays, + const CCTK_INT input_array_dims[], + const CCTK_INT input_array_type_codes[], + const void *const input_arrays[], + /***** output arrays *****/ + int N_output_arrays, + const CCTK_INT output_array_type_codes[], + void *const output_arrays[]) +{ +return InterpLocalUniform(interp_operator_Lagrange_MD, + "Lagrange polynomial interpolation (maximum degree)", + LAGRANGE_BNDRY_OFF_CNTR_TOL_DEF, + LAGRANGE_BNDRY_EXTRAP_TOL_DEF, + N_dims, + param_table_handle, + coord_origin, coord_delta, + N_interp_points, + interp_coords_type_code, + interp_coords, + N_input_arrays, + input_array_dims, + input_array_type_codes, + input_arrays, + N_output_arrays, + output_array_type_codes, + output_arrays); +} + +/******************************************************************************/ + +/*@@ + @routine AEILocalInterp_U_Hermite + @date 22 Oct 2001 + @author Jonathan Thornburg <jthorn@aei.mpg.de> + @desc + This function is a top-level driver for + LocalInterp::CCTK_InterpLocalUniform(). + + It does Hermite interpolation of a set of input arrays defined + on a uniform N-dimensional tensor-product grid, to a set of + interpolation points. It can also do differentiation and/or + smoothing in the process of the interpolation. It can also + return information about the Jacobian of the interpolated + values with respect to the input arrays. + + This function does nothing except pass all its arguments + down to InterpLocalUniform() with an extra 2 arguments + added to indicate the operator handle. See that function + for details on this function's arguments/results. + @enddesc + @@*/ +int AEILocalInterp_U_Hermite(int N_dims, + int param_table_handle, + /***** coordinate system *****/ + const CCTK_REAL coord_origin[], + const CCTK_REAL coord_delta[], + /***** interpolation points *****/ + int N_interp_points, + int interp_coords_type_code, + const void *const interp_coords[], + /***** input arrays *****/ + int N_input_arrays, + const CCTK_INT input_array_dims[], + const CCTK_INT input_array_type_codes[], + const void *const input_arrays[], + /***** output arrays *****/ + int N_output_arrays, + const CCTK_INT output_array_type_codes[], + void *const output_arrays[]) +{ +return InterpLocalUniform(interp_operator_Hermite, + "Hermite polynomial interpolation", + HERMITE_BNDRY_OFF_CNTR_TOL_DEF, + HERMITE_BNDRY_EXTRAP_TOL_DEF, + N_dims, + param_table_handle, + coord_origin, coord_delta, + N_interp_points, + interp_coords_type_code, + interp_coords, + N_input_arrays, + input_array_dims, + input_array_type_codes, + input_arrays, + N_output_arrays, + output_array_type_codes, + output_arrays); +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +/*@@ + @routine InterpLocalUniform + @date 22 Oct 2001 + @author Jonathan Thornburg <jthorn@aei.mpg.de> + @desc + This function is the main driver for + LocalInterp::CCTK_InterpLocalUniform(). + + It interpolates a set of input arrays defined on a uniform + N-dimensional tensor-product grid, to a set of interpolation + points. It can also do differentiation and/or smoothing + in the process of the interpolation. It can also return + information about the Jacobian of the interpolated values + with respect to the input arrays. + + This function is just a driver: it validates arguments, + extracts optional arguments from the parameter table, + then decodes + (interp_operator, N_dims, molecule_family, order, smoothing) + and calls the appropriate subfunction to do the actual + interpolation, then finally stores some results back in + the parameter table. + @enddesc + + @hdate 28.Jan.2003 + @hauthor Jonathan Thornburg <jthorn@aei.mpg.de> + @hdesc Support parameter-table entries + @var N_boundary_points_to_omit, + @var boundary_off_centering_tolerance, and + @var boundary_extrapolation_tolerance. + @endhdesc + + @hdate 1.Feb.2003 + @hauthor Jonathan Thornburg <jthorn@aei.mpg.de> + @hdesc Change defaults to "no off-centering" for Hermite interpolator, + split off most of this (huge) function into subfunctions + @endhdesc + + ***** operator arguments ***** + + @var interp_operator + @vdesc describes the interpolation operator + @vtype enum interp_operator interp_operator + @endvar + + @var interp_operator_string + @vdesc gives the character-string name of the interpolation operator + (this is used only for printing error messages) + @vtype const char* interp_operator_string + @endvar + + @var boundary_off_cntr_tol_default + @vdesc the default value for each element of + @var boundary_off_centering_default[] + if this key isn't present in the parameter table + @vtype CCTK_REAL boundary_off_cntr_tol_default + @endvar + + @var boundary_extrap_tol_default + @vdesc the default value for each element of + @var boundary_extrapolation_default[] + if this key isn't present in the parameter table + @vtype CCTK_REAL boundary_extrap_tol_default + @endvar + + ***** misc arguments ***** + + @var N_dims + @vdesc dimensionality of the interpolation + @vtype int N_dims (must be >= 1) + @endvar + + @var param_table_handle + @vdesc handle to a key-value table giving additonal parameters + for the interpolation + @vtype int param_table_handle (must be >= 0) + @endvar + + ***** arguments specifying the coordinate system ***** + + @var coord_origin + @vdesc (pointer to) array[N_dims] of values giving the + x,y,z,... coordinates which correspond to the + integer input-array subscripts (0,0,0,...,0) + (note there is no implication here that such a + grid point need actually exist; the arrays just + give the coordinates it would have if it did exist) + @vtype const CCTK_REAL coord_origin[N_dims] + @endvar + + @var coord_delta + @vdesc (pointer to) array[N_dims] of values giving the + coordinate spacing of the grid + @vtype const CCTK_REAL coord_delta[N_dims] + @endvar + + ***** arguments specifying the interpolation points ***** + + @var N_interp_points + @vdesc number of interpolation points + @vtype int N_interp_points (must be >= 0) + @endvar + + @var interp_coords_type_code + @vdesc one of the CCTK_VARIABLE_* codes giving the data + type of the arrays pointed to by interp_coords[] + @vtype int + @endvar + + @var interp_coords + @vdesc (pointer to) array[N_dims] of pointers + to arrays[N_interp_points] giving + x,y,z,... coordinates of interpolation points + @vtype const void *const interp_coords[N_dims] + @endvar + + ***** arguments specifying the inputs (the data to be interpolated) ***** + + @var N_input_arrays + @vdesc number of arrays input to the interpolation + @vtype int N_input_arrays (must be >= 0) + @endvar + + @var input_array_dims + @vdesc dimensions of the input arrays: unless overridden by + entries in the parameter table, all input arrays are + taken to have these dimensions, with [0] the most contiguous + axis and [N_dims-1] the least contiguous axis, and + array subscripts in the range 0 <= subscript < dims[axis] + @vtype const int input_array_dims[N_dims] + @endvar + + @var input_array_type_codes + @vdesc (pointer to) array of CCTK_VARIABLE_* codes + giving the data types of the input arrays + @vtype const int input_array_type_codes[N_input_arrays] + @endvar + + @var input_arrays + @vdesc (pointer to) array[N_input_arrays] of pointers to input arrays + @vtype const void *const input_arrays[N_input_arrays] + @endvar + + ***** arguments specifying the outputs (the interpolation results) ***** + + @var N_output_arrays + @vdesc number of arrays output from the interpolation + @vtype int N_output_arrays (must be >= 0) + @endvar + + @var output_array_type_codes + @vdesc (pointer to) array of CCTK_VARIABLE_* codes + giving the data types of the output arrays + @vtype const int output_array_type_codes[N_output_arrays] + @endvar + + @var output_arrays + @vdesc (pointer to) array[N_output_arrays] of pointers to output arrays + @vtype void *const output_arrays[N_output_arrays] + @endvar + + ***** input arguments passed in the parameter table ***** + + @var order + @vdesc Sets the order of the interpolating polynomial + (1=linear, 2=quadratic, 3=cubic, ...). + This table entry is mandatory; all others are optional. + @vtype int order + @endvar + + @var N_boundary_points_to_omit + @vdesc If this key is present, then this array specifies how many + input grid points to omit (not use for the interpolation) + on each grid boundary. The array elements are matched up + with the axes and minimum/maximum ends of the grid in the + order [x_min, x_max, y_min, y_max, z_min, z_max, ...]. + If this key isn't present, it defaults to all zeros, i.e. + to use all the input grid points in the interpolation. + @vtype const CCTK_INT N_boundary_points_to_omit[2*N_dims] + @endvar + + @var boundary_off_centering_tolerance + @vdesc If this key is present, then the interpolator allows + interpolation points to be up to (<=) this many grid + spacings outside the default-centering region on each + grid boundary, off-centering the interpolation molecules + as necessary. + The array elements are matched up with the axes and + minimum/maximum ends of the grid in the order + [x_min, x_max, y_min, y_max, z_min, z_max, ...]. + If this key isn't present, it defaults to all infinities, + i.e. to place no restriction on the interpolation point. + @vtype const CCTK_REAL boundary_off_centering_tolerance[2*N_dims] + @endvar + + @var boundary_extrapolation_tolerance + @vdesc If this key is present, then the interpolator allows + interpolation points to be up to (<=) this many grid + spacings outside the valid-data region on each grid + boundary, doing extrapolation instead of interpolation + as necessary. + The array elements are matched up with the axes and + minimum/maximum ends of the grid in the order + [x_min, x_max, y_min, y_max, z_min, z_max, ...]. + If this key isn't present, it defaults to all 1.0e-10, + i.e. to allow up to 1e-10 grid spacings of extrapolation. + @vtype const CCTK_REAL boundary_extrapolation_tolerance[2*N_dims] + @endvar + + @var input_array_offsets + @vdesc If this key is present, the value should be a pointer to + an array giving an "offset" for each input array, use in + the subscripting computation: for input array number in, + this computation (given for 3D; the generalization to other + numbers of dimensions is obvious) is + input_arrays[in][offset + i*istride + j*jstride + k*kstride] + where + offset = input_array_offsets[in] + or is 0 if input_array_offsets is absent + (istride,jstride,kstride,...) = input_array_stride[] + and where (i,j,k,...) run from input_array_min_subscripts[] + to input_array_max_subscripts[] inclusive. + @vtype const CCTK_INT input_array_offsets[N_input_arrays] + @endvar + + @var input_array_strides + @vdesc (pointer to) array giving strides of input arrays + (this is shared by all input arrays) + @vtype const CCTK_INT input_array_strides[N_dims] + @endvar + + @var input_array_min_subscripts + @vdesc (pointer to) array giving minimum subscripts of input arrays + (this is shared by all input arrays) + @vtype const CCTK_INT input_array_min_subscripts[N_dims] + @endvar + + @var input_array_max_subscripts + @vdesc (pointer to) array giving maximum subscripts of input arrays + (this is shared by all input arrays) + @vtype const CCTK_INT input_array_max_subscripts[N_dims] + @endvar + + @var operand_indices + @vdesc (pointer to) array of integer operand indices specifying + which input array (0-origin indexing into input_arrays[]) + is to be generalized-interpolated to produce this output + @vtype const CCTK_INT operand_indices[N_output_arrays] + @endvar + + @var operation_codes + @vdesc (pointer to) array of integer operation codes specifying + what (if any) derivatives are to be takin in the interpolation + process: 0=no derivative, 1=d/dx, 2=d/dy, 3=d/dz (for coords + (x,y,z)), 11=d^2/dx^2, 12=21=d^2/dxdy, etc etc. + @vtype const CCTK_INT operation_codes[N_output_arrays] + @endvar + + ***** output arguments passed in the parameter table ***** + + @var out_of_range_pt + @vdesc If an out-of-range point is detected, this table entry + is set to its pt value. + @vtype CCTK_INT out_of_range_pt + @vio out + @endvar + + @var out_of_range_axis + @vdesc If an out-of-range point is detected, this table entry + is set to the axis value which is out of range. + @vtype CCTK_INT out_of_range_axis + @vio out + @endvar + + @var out_of_range_end + @vdesc If an out-of-range point is detected, this table entry + is set to -1/+1 if the point is out of range on the min/max + end of the axis. + @vtype CCTK_INT out_of_range_end + @vio out + @endvar + + @var MSS_is_fn_of_interp_coords + @vdesc If the interpolation molecule size and/or shape vary + with the interpolation coordinates, this table entry + is set to 1. Otherwise (i.e. if the interpolation + molecule size and shape are independent of the + interpolation coordinates), it's set to 0. + @vtype CCTK_INT MSS_is_fn_of_interp_coords + @vio out + @endvar + + @var MSS_is_fn_of_which_operation + @vdesc If the interpolator supports computing derivatives, + and the interpolation molecule size and/or shape vary + from one operation_code[] value to another, this table + entry is set to 1. Otherwise (i.e. if the interpolator + doesn't support computing derivatives, or if the + interpolator does support computing derivatives but + the interpolation molecule size and shape are independent + of the operation_code[] values), it's set to 0. + Note that this query tests whether the molecule size + and/or shape depend on operation_codes[] in general, + independent of whether there are in fact any distinct values + (or even any values at all) passed in operation_codes[] + in this particular interpolator call. In other words, + this is a query about the basic design of this + interpolator, not about this particular call. + @vtype CCTK_INT MSS_is_fn_of_which_operation + @vio out + @endvar + + @var MSS_is_fn_of_input_array_values + @vdesc If the interpolation molecule size and/or shape vary + with the actual floating-point values of the input + arrays, this table entry is set to 1. Otherwise + (i.e. if the interpolation molecule size and shape + are independent of the input array values; this is + a necessary, but not sufficient, condition for the + interpolation to be linear), it's set to 0. + @vtype CCTK_INT MSS_is_fn_of_input_array_values + @vio out + @endvar + + @var Jacobian_is_fn_of_input_array_values + @vdesc If the actual floating-point values of the Jacobian (*) + (see the discussion of Jacobian_pointer below) + depends on the actual floating-point values of the + input arrays (i.e. if the interpolation is nonlinear), + this table entry is set to 1. Otherwise (i.e. if the + interpolation is linear), it's set to 0. + @vtype CCTK_INT Jacobian_is_fn_of_input_array_values + @vio out + @endvar + + @var molecule_min_m + @vdesc If this key is present (the value doesn't matter), + then the value is (re)set to an array of N_dims integers + giving the minimum molecule m coordinate in each axis + @vtype CCTK_INT molecule_min_m[N_dims] + @vio out + @endvar + + @var molecule_max_m + @vdesc If this key is present (the value doesn't matter), + then the value is (re)set to an array of N_dims integers + giving the maximum molecule m coordinate in each axis + @vtype CCTK_INT molecule_max_m[N_dims] + @vio out + @endvar + + @var molecule_positions + @vdesc If this key is present, then the value should be an + array of N_dims pointers to (caller-supplied) arrays + of N_interp_points CCTK_INTs each; the interpolator + will store the molecule positions in the pointed-to + arrays. + @vtype CCTK_INT *const molecule_positions[N_dims] + @vio out + @endvar + + @var Jacobian_pointer + @vdesc If this key is present, then the value should be an + array of N_output_arrays pointers to (caller-supplied) + arrays of CCTK_INTs; the interpolator will store the + Jacobian elements in the pointed-to arrays. For output + array number out, the subscripting computation (given + for 3D; the generalization to other numbers of dimensions + is obvious) is + Jacobian_pointer[out][offset + + pt*Jacobian_interp_point_stride + + mi*stride_i + mj*stride_j + mk*stride_k + + part*Jacobian_part_stride] + where + offset = Jacobian_offset[out] + or is 0 if Jacobian_offset[] is absent + pt = the point number + (stride_i,stride_j,stride_k) = Jacobian_m_strides[] + part = 0 for real values, + 0 for the real parts of complex values, + 1 for the imaginary parts of complex values, or + 0 if Jacobian_part_stride is absent + @vtype CCTK_REAL *const Jacobian_pointer[N_output_arrays] + @endvar + + @var Jacobian_offset + @vdesc If this key is present, then the value should be a + pointer to an array of N_output_arrays CCTK_INTs giving + offsets to use in the Jacobian subscripting computation. + If this key is absent, the effect is as if a default + array of all 0s had been supplied. + @vtype const CCTK_INT Jacobian_offset[N_output_arrays] + @endvar + + @var Jacobian_interp_point_stride + @vdesc The pt-stride for the Jacobian subscripting computation. + @vtype const CCTK_INT Jacobian_interp_point_stride + @endvar + + @var Jacobian_m_strides + @vdesc An array of N_dims CCTK_INTs giving the m strides along + each axis for the Jacobian subscripting computation + @vtype const CCTK_INT Jacobian_m_strides[N_dims] + @endvar + + @var Jacobian_part_stride + @vdesc If this key is present, it gives the part stride for the + Jacobian subscripting computation. If this key is absent, + the default value 0 is used (n.b. this is suitable only + for real data arrays) + @vtype const CCTK_INT Jacobian_m_strides[N_dims] + @endvar + + ***** return result ***** + + @returntype int + @returndesc 0 successful interpolation + UTIL_ERROR_BAD_INPUT one of the input arguments is invalid + UTIL_ERROR_NO_MEMORY unable to malloc() temporary memory + UTIL_ERROR_BAD_HANDLE invalid parameter table handle + CCTK_ERROR_INTERP_POINT_OUTSIDE + interpolation point is out of range + (in this case additional information + is reported through the parameter table) + or any error code returned by one of the Util_TableGet*() + functions called by this function + @endreturndesc + @@*/ +static + int InterpLocalUniform(enum interp_operator interp_operator, + const char* interp_operator_string, + CCTK_REAL boundary_off_cntr_tol_default, + CCTK_REAL boundary_extrap_tol_default, + /***** misc arguments *****/ + int N_dims, + int param_table_handle, + /***** coordinate system *****/ + const CCTK_REAL coord_origin[], + const CCTK_REAL coord_delta[], + /***** interpolation points *****/ + int N_interp_points, + int interp_coords_type_code, + const void *const interp_coords[], + /***** input arrays *****/ + int N_input_arrays, + const CCTK_INT input_array_dims[], + const CCTK_INT input_array_type_codes[], + const void *const input_arrays[], + /***** output arrays *****/ + int N_output_arrays, + const CCTK_INT output_array_type_codes[], + void *const output_arrays[]) +{ +/* + * Implementation Note: + * + * We malloc() several scratch arrays, some with sizes determined by + * N_{input,output}_arrays. Thus if N_{input,output}_arrays == 0, with + * the obvious code we would malloc(0). Alas, the C standard permits + * malloc(0) to return a NULL pointer, which the usual malloc() idiom + * CCTK_INT *const p = malloc(N * sizeof(CCTK_INT)); + * if (p == NULL) + * then return UTIL_ERROR_NO_MEMORY + * would falsely detect as an out-of-memory condition. + * + * As a workaround, we pad all our malloc request sizes, i.e. + * CCTK_INT* const p = (CCTK_INT*) malloc((N+1) * sizeof(CCTK_INT)); + * if (p == NULL) + * then return UTIL_ERROR_NO_MEMORY + * This is a kludge, but so are the other plausible solutions. :( :( + */ +int N_input_arrays1 = N_input_arrays + 1; +int N_output_arrays1 = N_output_arrays + 1; + +int status, status1, status2; +bool value_not_set; + +/******************************************************************************/ + +/* + * basic sanity checks on input parameters + */ +if ( (N_dims <= 0) + || (param_table_handle < 0) + || ((N_interp_points > 0) && (coord_origin == NULL)) + || ((N_interp_points > 0) && (coord_delta == NULL)) + || (N_interp_points < 0) + || ((N_interp_points > 0) && (interp_coords == NULL)) + || (N_input_arrays < 0) + /* no check here on input_array_dims, */ + /* since it may be NULL if overridden by parameter-table stuff */ + || ((N_input_arrays > 0) && (input_array_type_codes == NULL)) + || ((N_input_arrays > 0) && (input_arrays == NULL)) + || (N_output_arrays < 0) + || ((N_output_arrays > 0) && (output_array_type_codes == NULL)) + || ((N_output_arrays > 0) && (output_arrays == NULL)) ) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"CCTK_InterpLocalUniform(): invalid arguments\n" +" (N_dims <= 0, param_table_handle < 0, N_input_arrays < 0,\n" +" N_output_arrays < 0, and/or NULL pointers-that-shouldn't-be-NULL)!"); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + +if (N_dims > MAX_N_DIMS) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): implementation restriction: N_dims=%d\n" +" but we only support N_dims <= MAX_N_DIMS=%d!", + N_dims, + MAX_N_DIMS); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + +/******************************************************************************/ + +/* + * get the parameters from the parameter table, filling in defaults as needed + */ + + { +CCTK_INT order; +status = get_and_check_INT(param_table_handle, "order", + true, 0, /* this is a mandatory parameter */ + true, 1, MAX_ORDER, "MAX_ORDER", /* range check */ + &order); +if (status != 0) + then return status; /*** ERROR RETURN ***/ + + { +const int N_boundaries = 2*N_dims; +CCTK_INT N_boundary_points_to_omit[MAX_N_BOUNDARIES]; +status = get_INT_array(param_table_handle, "N_boundary_points_to_omit", + true, 0, /* default value */ + N_boundaries, N_boundary_points_to_omit, + NULL); +if (status != 0) + then return status; /*** ERROR RETURN ***/ + +/**************************************/ + + { +CCTK_REAL boundary_off_centering_tolerance[MAX_N_BOUNDARIES]; +CCTK_REAL boundary_extrapolation_tolerance[MAX_N_BOUNDARIES]; +status = get_REAL_array(param_table_handle, "boundary_off_centering_tolerance", + boundary_off_cntr_tol_default, + N_boundaries, boundary_off_centering_tolerance); +if (status != 0) + then return status; /*** ERROR RETURN ***/ +status = get_REAL_array(param_table_handle, "boundary_extrapolation_tolerance", + boundary_extrap_tol_default, + N_boundaries, boundary_extrapolation_tolerance); +if (status != 0) + then return status; /*** ERROR RETURN ***/ +check_boundary_tolerances(N_boundaries, + boundary_off_centering_tolerance, + boundary_extrapolation_tolerance); + +/**************************************/ + + { +#define MOLECULE_FAMILY_BUFSIZ (MAX_MOLECULE_FAMILY_STRLEN+1) +char molecule_family_string[MOLECULE_FAMILY_BUFSIZ]; +enum molecule_family molecule_family; +status = get_and_decode_molecule_family(param_table_handle, + MOLECULE_FAMILY_BUFSIZ, molecule_family_string, + &molecule_family); +if (status != 0) + then return status; /*** ERROR RETURN ***/ + + { +CCTK_INT smoothing; +status = get_and_check_INT(param_table_handle, "smoothing", + false, 0, /* optional, default value 0 */ + true, 0, MAX_SMOOTHING, "MAX_SMOOTHING", + /* range check */ + &smoothing); +if (status != 0) + then return status; /*** ERROR RETURN ***/ + +/**************************************/ + + { +CCTK_INT* const input_array_offsets + = (CCTK_INT*) malloc(N_input_arrays1 * sizeof(CCTK_INT)); +if (input_array_offsets == NULL) + then return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ +status = get_INT_array(param_table_handle, "input_array_offsets", + true, 0, /* default value */ + N_input_arrays, input_array_offsets, + NULL); +if (status != 0) + then { + free(input_array_offsets); + return status; /*** ERROR RETURN ***/ + } + + { +CCTK_INT input_array_strides[MAX_N_DIMS]; +status = get_INT_array(param_table_handle, "input_array_strides", + false, 0, /* don't set default value */ + N_dims, input_array_strides, + &value_not_set); +if (status != 0) + then { + free(input_array_offsets); + return status; /*** ERROR RETURN ***/ + } +if (value_not_set) + then { + /* default stride = Fortran storage order, */ + /* determined from input_array_dims[] */ + if (input_array_dims == NULL) + then { + free(input_array_offsets); + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): can't default \"input_array_strides\"\n" +" with input_array_dims == NULL!"); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + { + int stride = 1; + int axis; + for (axis = 0 ; axis < N_dims ; ++axis) + { + input_array_strides[axis] = stride; + stride *= input_array_dims[axis]; + } + } + } + + { +CCTK_INT input_array_min_subscripts[MAX_N_DIMS]; +CCTK_INT input_array_max_subscripts[MAX_N_DIMS]; +status = get_INT_array(param_table_handle, "input_array_min_subscripts", + true, 0, /* default value */ + N_dims, input_array_min_subscripts, + NULL); +if (status != 0) + then { + free(input_array_offsets); + return status; /*** ERROR RETURN ***/ + } + +status = get_INT_array(param_table_handle, "input_array_max_subscripts", + false, 0, /* don't set default value */ + N_dims, input_array_max_subscripts, + &value_not_set); +if (status != 0) + then { + free(input_array_offsets); + return status; /*** ERROR RETURN ***/ + } +if (value_not_set) + then { + /* default max subscript = input_array_dims[]-1 along each axis */ + if (input_array_dims == NULL) + then { + free(input_array_offsets); + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): can't default \"input_array_max_subscripts\"\n" +" with input_array_dims == NULL!"); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + { + int axis; + for (axis = 0 ; axis < N_dims ; ++axis) + { + input_array_max_subscripts[axis] = input_array_dims[axis] - 1; + } + } + } + +/**************************************/ + + { +CCTK_INT* const operand_indices + = (CCTK_INT*) malloc(N_output_arrays1 * sizeof(CCTK_INT)); +if (operand_indices == NULL) + then { + free(input_array_offsets); + return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ + } +status = get_INT_array(param_table_handle, "operand_indices", + false, 0, /* don't set default value */ + N_output_arrays, operand_indices, + &value_not_set); +if (status != 0) + then { + free(input_array_offsets); + free(operand_indices); + return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ + } +if (value_not_set) + then { + /* default operand will use each input exactly once, */ + /* but this only makes since if N_input_arrays == N_output_arrays */ + if (N_input_arrays != N_input_arrays) + then { + free(input_array_offsets); + free(operand_indices); + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): can't default \"operand_indices\"\n" +" with N_input_arrays=%d != N_output_arrays=%d!" + , + N_input_arrays, N_output_arrays); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + { + int out; + for (out = 0 ; out < N_output_arrays ; ++out) + { + operand_indices[out] = out; + } + } + } + +/**************************************/ + + { +CCTK_INT* const operation_codes + = (CCTK_INT*) malloc(N_output_arrays1 * sizeof(CCTK_INT)); +if (operation_codes == NULL) + then { + free(input_array_offsets); + free(operand_indices); + return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ + } +status = get_INT_array(param_table_handle, "operation_codes", + true, 0, /* default value */ + N_output_arrays, operation_codes, + NULL); +if (status != 0) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ + } + +/******************************************************************************/ + +/* + * set up for any molecule min/max m and/or position queries + */ + + { +struct molecule_min_max_m_info* p_molecule_min_max_m_info = NULL; +struct molecule_min_max_m_info molecule_min_max_m_info; + +/* molecule min/max m */ +status1 = Util_TableQueryValueInfo(param_table_handle, + NULL, NULL, + "molecule_min_m"); +status2 = Util_TableQueryValueInfo(param_table_handle, + NULL, NULL, + "molecule_max_m"); +if ((status1 < 0) || (status2 < 0)) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad \"molecule_{min,max}_m\"\n" +" table entry/entries in query!\n" +" error status1=%d status2=%d" + , + status1, status2); + return (status1 < 0) ? status1 : status2; /*** ERROR RETURN ***/ + } +if (status1 && status2) + then p_molecule_min_max_m_info = &molecule_min_max_m_info; + + { +CCTK_INT** p_molecule_positions = NULL; +CCTK_INT* molecule_positions_array[MAX_N_DIMS]; + +/* are we doing a molecule-positions query? */ +status = Util_TableQueryValueInfo(param_table_handle, + NULL, NULL, + "molecule_positions"); +if (status < 0) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad \"molecule_positions\"\n" +" table entry in query!\n" +" error status=%d" + , + status); + return status; /*** ERROR RETURN ***/ + } +if (status) + then { + /* yes, we're doing a molecule-positions query */ + status = get_molecule_positions(param_table_handle, + N_dims, molecule_positions_array); + if (status != 0) + then return status; /*** ERROR RETURN ***/ + p_molecule_positions = molecule_positions_array; + } + +/******************************************************************************/ + +/* + * set up for any Jacobian queries + */ + + { +struct Jacobian_info* p_Jacobian_info = NULL; +struct Jacobian_info Jacobian_info; +Jacobian_info.Jacobian_pointer = NULL; +Jacobian_info.Jacobian_offset = NULL; + +/* are we doing a Jacobian query? */ +status = Util_TableQueryValueInfo(param_table_handle, + NULL, NULL, + "Jacobian_pointer"); +if (status < 0) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad \"Jacobian_pointer\" table entry!\n" +" (preliminary check)\n" +" error status=%d" + , + status); + return status; /*** ERROR RETURN ***/ + } + +if (status) + then { + /* yes, we're doing a Jacobian query */ + status = get_Jacobian_info(param_table_handle, + N_dims, N_output_arrays, + &Jacobian_info); + if (status != 0) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + return status; /*** ERROR RETURN ***/ + } + p_Jacobian_info = & Jacobian_info; + } + +/******************************************************************************/ + +/* + * decode (interp_operator, N_dims, molecule_family, order, smoothing) + * and call the appropriate subfunction to do the actual interpolation + */ + + +/* firewall: make sure all the lookup indices are in range */ +/* ... commented-out comparisons are always true since enums are unsigned */ +if ( /*(interp_operator >= 0) &&*/ (interp_operator < N_INTERP_OPERATORS) + && (N_dims >= 0) && (N_dims <= MAX_N_DIMS) + && /*(molecule_family >= 0) &&*/ (molecule_family < N_MOLECULE_FAMILIES) + && (order >= 0) && (order <= MAX_ORDER) + && (smoothing >= 0) && (smoothing <= MAX_SMOOTHING) ) + then { + /* ok ==> no-op here */ + } + else { + CCTK_VWarn(BUG_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform():\n" +" internal error (interpolator bug!):\n" +" one or more function-pointer-table indices is out of range!\n" +" interp_operator=(int)%d, should be in [0,%d)\n" +" N_dims = %d, should be in [0,%d]\n" +" molecule_family=(int)%d, should be in [0,%d)\n" +" order = %d, should be in [0,%d]\n" +" smoothing = %d, should be in [0,%d]\n" + , + (int) interp_operator, (int) N_INTERP_OPERATORS, + (int) N_dims , (int) MAX_N_DIMS, + (int) molecule_family, (int) N_MOLECULE_FAMILIES, + (int) order , (int) MAX_ORDER, + (int) smoothing , (int) MAX_SMOOTHING); + /*NOTREACHED*/ + CCTK_Abort(NULL, BUG_ABORT_CODE); /*NOTREACHED*/ + } + +/* look up the subfunction to do the interpolation */ + { +const p_interp_fn_t p_interp_fn = p_interp_fn_table[interp_operator] + [N_dims] + [molecule_family] + [order] + [smoothing]; +if (p_interp_fn == NULL_INTERP_FN_PTR) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + if (p_Jacobian_info != NULL) + then { + free(Jacobian_info.Jacobian_offset); + free(Jacobian_info.Jacobian_pointer); + } + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform():\n" +" interpolation not implemented for the combination\n" +" interp_operator=\"%s\", N_dims=%d\n" +" molecule_family=\"%s\", order=%d, smoothing=%d", + interp_operator_string, N_dims, + molecule_family_string, order, smoothing); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + +/* call the subfunction to actually do the interpolation */ + { +struct error_flags error_flags; +struct molecule_structure_flags molecule_structure_flags; +const int return_code + = (*p_interp_fn)(coord_origin, coord_delta, + N_interp_points, + interp_coords_type_code, interp_coords, + N_boundary_points_to_omit, + boundary_off_centering_tolerance, + boundary_extrapolation_tolerance, + N_input_arrays, + input_array_offsets, input_array_strides, + input_array_min_subscripts, + input_array_max_subscripts, + input_array_type_codes, input_arrays, + N_output_arrays, + output_array_type_codes, output_arrays, + operand_indices, operation_codes, + &error_flags, + &molecule_structure_flags, + p_molecule_min_max_m_info, + p_molecule_positions, + p_Jacobian_info); + +/******************************************************************************/ + +/* + * is an interpolation point out of range? + */ +if (return_code == CCTK_ERROR_INTERP_POINT_OUTSIDE) + then { + status = set_error_info(param_table_handle, + &error_flags); + if (status != 0) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + if (p_Jacobian_info != NULL) + then { + free(Jacobian_info.Jacobian_offset); + free(Jacobian_info.Jacobian_pointer); + } + return status; /*** ERROR RETURN ***/ + } + } + +/******************************************************************************/ + +/* + * store query results + * + * ... only molecule structure and min/max m have to be stored explicitly; + * the other queries are stored directly into their final destinatios + * by the interpolation subfunction + */ + +status = set_molecule_structure(param_table_handle, + &molecule_structure_flags); +if (status != 0) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + if (p_Jacobian_info != NULL) + then { + free(Jacobian_info.Jacobian_offset); + free(Jacobian_info.Jacobian_pointer); + } + return status; /*** ERROR RETURN ***/ + } + +if (p_molecule_min_max_m_info != NULL) + then { + status = set_molecule_min_max_m(param_table_handle, + N_dims, p_molecule_min_max_m_info); + if (status != 0) + then { + free(input_array_offsets); + free(operand_indices); + free(operation_codes); + if (p_Jacobian_info != NULL) + then { + free(Jacobian_info.Jacobian_offset); + free(Jacobian_info.Jacobian_pointer); + } + return status; /*** ERROR RETURN ***/ + } + } + +/******************************************************************************/ + +free(input_array_offsets); +free(operand_indices); +free(operation_codes); +if (p_Jacobian_info != NULL) + then { + free(Jacobian_info.Jacobian_offset); + free(Jacobian_info.Jacobian_pointer); + } + +return return_code; /*** NORMAL RETURN ***/ + } + } + } + } + } + } + } + } + } + } + } + } + } + } + } +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +/* + * This function checks + * CCTK_REAL boundary_off_centering_tolerance[N_boundaries] + * CCTK_REAL boundary_extrapolation_tolerance[N_boundaries] + * for validity, warning about any dubious settings. + */ +static + void check_boundary_tolerances + (int N_boundaries, + const CCTK_REAL boundary_off_centering_tolerance[MAX_N_BOUNDARIES], + const CCTK_REAL boundary_extrapolation_tolerance[MAX_N_BOUNDARIES]) +{ +int ibndry; + for (ibndry = 0 ; ibndry < N_boundaries ; ++ibndry) + { + if ( (boundary_off_centering_tolerance[ibndry] == 0.0) + && (boundary_extrapolation_tolerance[ibndry] > 0.0) ) + then CCTK_VWarn(WARNING_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform():\n" +" warning: setting boundary_off_centering_tolerance[%d] == 0.0\n" +" and boundary_extrapolation_tolerance[%d] == %g > 0.0\n" +" is almost certainly a mistake\n" +" (the boundary_extrapolation_tolerance[%d] == %g\n" +" setting will have no effect because of the\n" +" boundary_off_centering_tolerance[%d] == 0.0 setting)" + , + ibndry, + ibndry, + (double) boundary_extrapolation_tolerance[ibndry], + ibndry, + (double) boundary_extrapolation_tolerance[ibndry], + ibndry); + } +} + +/******************************************************************************/ + +/* + * This function gets + * const char molecule_family[] + * from the parameter table, or sets the default value "cube" if this + * key isn't present. This function also decodes molecule_family into + * an enum molecule_family . + * + * Results: + * This function returns 0 for ok, or the (nonzero) return code for error. + */ +static + int get_and_decode_molecule_family + (int param_table_handle, + int buffer_size, char molecule_family_string_buffer[], + enum molecule_family *p_molecule_family) +{ +enum molecule_family molecule_family; +int status; + +status = Util_TableGetString(param_table_handle, + buffer_size, molecule_family_string_buffer, + "molecule_family"); + +if (status == UTIL_ERROR_TABLE_NO_SUCH_KEY) + then { + /* set the default value */ + Util_Strlcpy(molecule_family_string_buffer, "cube", buffer_size); + molecule_family = molecule_family_cube; + + /* set this key in the parameter table */ + /* to give the (default) molecule family we're going to use */ + status = Util_TableSetString(param_table_handle, + molecule_family_string_buffer, + "molecule_family"); + if (status < 0) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): error setting default molecule family\n" +" in parameter table!\n" +" error status=%d", + status); + return status; /*** ERROR RETURN ***/ + } + } +else if (status > 0) + then { + /* decode molecule family string */ + if (strcmp(molecule_family_string_buffer, "cube") == 0) + then molecule_family = molecule_family_cube; + else { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"CCTK_InterpLocalUniform(): unknown molecule_family string \"%s\"!", + molecule_family_string_buffer); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + } +else { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad table entry for\n" +" \"molecule_family\" parameter!\n" +" error status=%d", + status); + return status; /*** ERROR RETURN ***/ + } + +*p_molecule_family = molecule_family; +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ + +/* + * This function gets + * CCTK_INT* molecule_positions[N_dims] + * from the parameter table. + * + * Results: + * This function returns 0 for ok, or the (nonzero) return code for error. + */ +static + int get_molecule_positions + (int param_table_handle, + int N_dims, CCTK_INT* molecule_positions_array[MAX_N_DIMS]) +{ +CCTK_POINTER molecule_positions_temp[MAX_N_DIMS]; +int status; + +status = Util_TableGetPointerArray(param_table_handle, + N_dims, molecule_positions_temp, + "molecule_positions"); + +if (status == N_dims) + then { + /* type-cast CCTK_POINTER pointers to CCTK_INT* pointers */ + /* (which point to where the query results will be stored) */ + int axis; + for (axis = 0 ; axis < N_dims ; ++axis) + { + molecule_positions_array[axis] + = (CCTK_INT *) molecule_positions_temp[axis]; + } + } +else { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad \"molecule_positions\" table entry!\n" +" error status=%d", + status); + return status; /*** ERROR RETURN ***/ + } + +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ + +/* + * This function gets the Jacobian-query parameters + * CCTK_REAL* Jacobian_pointer[N_output_arrays] + * CCTK_INT Jacobian_offset [N_output_arrays] # optional, default=all 0 + * CCTK_INT Jacobian_interp_point_stride + * CCTK_INT Jacobian_m_point_strides[N_dims] + * CCTK_INT Jacobian_part_stride # optional, default=1 + * and stores them in a struct Jacobian_info . + * + * Results: + * This function returns 0 for ok, or the (nonzero) return code for error. + */ +static + int get_Jacobian_info(int param_table_handle, + int N_dims, int N_output_arrays, + struct Jacobian_info* p_Jacobian_info) +{ +/* padded array size, cf. InterpLocalUniform() header comments */ +const int N_output_arrays1 = N_output_arrays + 1; + +int status; + +p_Jacobian_info->Jacobian_pointer + = (CCTK_REAL**) malloc(N_output_arrays1 * sizeof(CCTK_REAL *)); +if (p_Jacobian_info->Jacobian_pointer == NULL) + then return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ + + { +CCTK_POINTER* Jacobian_pointer_temp + = (CCTK_POINTER*) malloc(N_output_arrays1 * sizeof(CCTK_POINTER)); +if (Jacobian_pointer_temp == NULL) + then { + free(p_Jacobian_info->Jacobian_pointer); + return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ + } +status = Util_TableGetPointerArray(param_table_handle, + N_output_arrays, Jacobian_pointer_temp, + "Jacobian_pointer"); +if (status == N_output_arrays) + then { + /* type-cast CCTK_POINTER pointers to CCTK_REAL* pointers */ + /* (which point to where the query results will be stored) */ + int out; + for (out = 0 ; out < N_output_arrays ; ++out) + { + p_Jacobian_info->Jacobian_pointer[out] + = (CCTK_REAL *) Jacobian_pointer_temp[out]; + } + free(Jacobian_pointer_temp); + } +else { + free(p_Jacobian_info->Jacobian_pointer); + free(Jacobian_pointer_temp); + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad \"Jacobian_pointer\" table entry!\n" +" error status=%d" + , + status); + return status; /*** ERROR RETURN ***/ + } + } + +p_Jacobian_info->Jacobian_offset + = (CCTK_INT*) malloc(N_output_arrays1 * sizeof(CCTK_INT)); +if (p_Jacobian_info->Jacobian_offset == NULL) + then { + free(p_Jacobian_info->Jacobian_pointer); + return UTIL_ERROR_NO_MEMORY; /*** ERROR RETURN ***/ + } +status = get_INT_array(param_table_handle, "Jacobian_offset", + true, 0, /* default value */ + N_output_arrays, p_Jacobian_info->Jacobian_offset, + NULL); +if (status != 0) + then { + free(p_Jacobian_info->Jacobian_pointer); + free(p_Jacobian_info->Jacobian_offset); + return status; /*** ERROR RETURN ***/ + } + +status = get_and_check_INT(param_table_handle, "Jacobian_interp_point_stride", + true, 0, /* this is a mandatory parameter */ + /* if we're executing this function */ + false, 0, 0, NULL, /* no range check */ + & p_Jacobian_info->Jacobian_interp_point_stride); +if (status != 0) + then { + free(p_Jacobian_info->Jacobian_offset); + free(p_Jacobian_info->Jacobian_pointer); + return status; /*** ERROR RETURN ***/ + } + +status = get_INT_array(param_table_handle, "Jacobian_m_strides", + false, 0, /* don't set default value */ + N_dims, p_Jacobian_info->Jacobian_m_strides, + NULL); /* this is a mandatory parameter */ + /* if we're executing this function */ +if (status != 0) + then { + free(p_Jacobian_info->Jacobian_pointer); + free(p_Jacobian_info->Jacobian_offset); + return status; /*** ERROR RETURN ***/ + } + +status = get_and_check_INT(param_table_handle, "Jacobian_part_stride", + false, 1, /* default value */ + false, 0, 0, NULL, /* no range check */ + & p_Jacobian_info->Jacobian_part_stride); +if (status != 0) + then { + free(p_Jacobian_info->Jacobian_pointer); + free(p_Jacobian_info->Jacobian_offset); + return status; /*** ERROR RETURN ***/ + } + +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ + +/* + * This function sets the error-info entries + * CCTK_INT error_pt + * CCTK_INT error_ibndry + * CCTK_INT error_axis + * CCTK_INT error_direction + * in the parameter table. + * + * Results: + * This function returns 0 for ok, or the (nonzero) return code for error. + */ +static + int set_error_info(int param_table_handle, + struct error_flags* p_error_flags) +{ +const int status1 = Util_TableSetInt(param_table_handle, + p_error_flags->error_pt, + "error_pt"); +const int status2 = Util_TableSetInt(param_table_handle, + p_error_flags->error_ibndry, + "error_ibndry"); +const int status3 = Util_TableSetInt(param_table_handle, + p_error_flags->error_axis, + "error_axis"); +const int status4 = Util_TableSetInt(param_table_handle, + p_error_flags->error_direction, + "error_direction"); +if ((status1 < 0) || (status2 < 0) || (status3 < 0) || (status4 < 0)) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform():\n" +" error setting error-info table entry/entries!\n" +" error status1=%d status2=%d status3=%d status4=%d" + , + status1, status2, status3, status4); + return (status1 < 0) ? status1 /*** ERROR RETURN ***/ + : (status2 < 0) ? status2 /*** ERROR RETURN ***/ + : (status3 < 0) ? status3 /*** ERROR RETURN ***/ + : status4; /*** ERROR RETURN ***/ + } + +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ + +/* + * This function sets the molecule structure flags + * CCTK_INT MSS_is_fn_of_interp_coords + * CCTK_INT MSS_is_fn_of_which_operation + * CCTK_INT MSS_is_fn_of_input_array_values + * CCTK_INT Jacobian_is_fn_of_input_array_values + * in the parameter table. + * + * Results: + * This function returns 0 for ok, or the (nonzero) return code for error. + */ +static + int set_molecule_structure + (int param_table_handle, + const struct molecule_structure_flags* p_molecule_structure_flags) +{ +const int status1 + = Util_TableSetInt(param_table_handle, + p_molecule_structure_flags->MSS_is_fn_of_interp_coords, + "MSS_is_fn_of_interp_coords"); +const int status2 + = Util_TableSetInt(param_table_handle, + p_molecule_structure_flags->MSS_is_fn_of_which_operation, + "MSS_is_fn_of_which_operation"); +const int status3 + = Util_TableSetInt(param_table_handle, + p_molecule_structure_flags->MSS_is_fn_of_input_array_values, + "MSS_is_fn_of_input_array_values"); +const int status4 + = Util_TableSetInt(param_table_handle, + p_molecule_structure_flags->Jacobian_is_fn_of_input_array_values, + "Jacobian_is_fn_of_input_array_values"); +if ((status1 < 0) || (status2 < 0) || (status3 < 0) || (status4 < 0)) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform():\n" +" error setting molecule structure flags table entry/entries!" +" error status1=%d status2=%d status3=%d status4=%d" + , + status1, status2, status3, status4); + return (status1 < 0) ? status1 /*** ERROR RETURN ***/ + : (status2 < 0) ? status2 /*** ERROR RETURN ***/ + : (status3 < 0) ? status3 /*** ERROR RETURN ***/ + : status4; /*** ERROR RETURN ***/ + } + +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ + +/* + * This function sets the molecule size parameters + * CCTK_INT molecule_min_m[N_dims] + * CCTK_INT molecule_max_m[N_dims] + * in the parameter table. + * + * Results: + * This function returns 0 for ok, or the (nonzero) return code for error. + */ +static + int set_molecule_min_max_m + (int param_table_handle, + int N_dims, + const struct molecule_min_max_m_info* p_molecule_min_max_m_info) +{ +const int status1 + = Util_TableSetIntArray(param_table_handle, + N_dims, p_molecule_min_max_m_info->molecule_min_m, + "molecule_min_m"); +const int status2 + = Util_TableSetIntArray(param_table_handle, + N_dims, p_molecule_min_max_m_info->molecule_max_m, + "molecule_max_m"); +if ((status1 < 0) || (status2 < 0)) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): error setting\n" +" \"molecule_{min,max}_m\" table entry/entries!" +" error status1=%d status2=%d", + status1, status2); + return (status1 < 0) ? status1 : status2; /*** ERROR RETURN ***/ + } + +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ +/******************************************************************************/ +/******************************************************************************/ + +/* + * This function gets and range-checks a CCTK_INT from the parameter table. + * + * Arguments: + * param_table_handle = handle to the Cactus key-value table + * name = the character-string key in the table + * mandatory_flag = true ==> the value must be present in the parameter + * table (default_value is ignored) + * false ==> the value is optional + * default_value = the default value (for each array element) if the + * key isn't in the parameter table and mandatory_flag == false + * check_range_flag = true ==> check that the value satisfies + * min_value <= value <= max_value + * false ==> don't do a range check, and ignore + * min_value, max_value, and max_value_string + * {min,max}_value = the inclusive range of valid values + * max_value_string = the character-string name of max_value (this is used + * only in formatting the out-of-range error message) + * p_value --> where we should store the value + * + * Results: + * This function returns 0 for ok, or the (nonzero) return code for error. + */ +static + int get_and_check_INT + (int param_table_handle, const char name[], + bool mandatory_flag, int default_value, + bool check_range_flag, int min_value, int max_value, + const char max_value_string[], + CCTK_INT* p_value) +{ +CCTK_INT value; + +const int status = Util_TableGetInt(param_table_handle, &value, name); + +if (status == 1) + then { } /* value set from table ==> no-op here */ +else if (status == UTIL_ERROR_TABLE_NO_SUCH_KEY) + then { + if (mandatory_flag) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): missing table entry for\n" +" \"%s\" parameter!\n" +" (this is a mandatory parameter)!\n" + , + name); + return status; /*** ERROR RETURN ***/ + } + else value = default_value; + } +else { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad table entry for\n" +" \"%s\" parameter!\n" +" error status=%d" + , + name, + status); + return status; /*** ERROR RETURN ***/ + } + +if (check_range_flag) + then { + if ((value < min_value) || (value > max_value)) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): %s=%d is invalid!\n" +" valid range is %d <= %s <= %s=%d", + name, value, + min_value, name, max_value_string, max_value); + return UTIL_ERROR_BAD_INPUT; /*** ERROR RETURN ***/ + } + } + +*p_value = value; +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ + +/* + * This function gets an array of CCTK_INT values from the parameter table. + * + * Arguments: + * param_table_handle = handle to the Cactus key-value table + * name = the character-string key in the table + * default_flag = false ==> ignore default_value and set + * *p_value_not_set to true if the + * key is not present in the parameter table, + * false if it is present + * true ==> if the key is not present in the parameter table, + * set each array element to default_value + * default_value = the default value (for each array element) if the + * key isn't in the parameter table + * N = the size of the array + * buffer --> a buffer in which to store the array + * p_value_not_set = NULL or a pointer to a flag to be set if and only if + * this function did *not* set values in the buffer. + * More precisely, if default_flag is set, this argument + * is ignored. Otherwise, the logic is this: + * if (this function set values in the buffer) + * then { + * if (p_value_not_set is non-NULL) + * then *p_value_not_set = false + * } + * else { + * if (p_value_not_set is non-NULL) + * then *p_value_not_set = true + * else give an error message that + * a mandatory value is missing + * from the parameter table, then + * return UTIL_ERROR_TABLE_NO_SUCH_KEY + * } + * + * Results: + * This function returns 0 for ok, or the desired (nonzero) error return + * code if something is wrong. Note that error return codes may be either + * positive or negative! + */ +static + int get_INT_array(int param_table_handle, const char name[], + bool default_flag, int default_value, + int N, CCTK_INT buffer[], + bool* p_value_not_set) +{ +const int status + = Util_TableGetIntArray(param_table_handle, + N, buffer, + name); + +if (status == UTIL_ERROR_TABLE_NO_SUCH_KEY) + then { + /* we didn't set values in the buffer */ + /* ==> either set the default value ourself, */ + /* or print an error message, */ + /* or notify our caller that we didn't do so */ + if (default_flag) + then { + int i; + for (i = 0 ; i < N ; ++i) + { + buffer[i] = default_value; + } + } + else { + if (p_value_not_set == NULL) + then { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): missing table entry for\n" +" \"%s\" parameter!\n" +" (this is a mandatory parameter)!\n" + , + name); + return UTIL_ERROR_TABLE_NO_SUCH_KEY; /*** ERROR RETURN ***/ + } + else *p_value_not_set = true; + } + } +else if (status == N) + then { + /* we did set values in the buffer */ + if (! default_flag) + then if (p_value_not_set != NULL) + then *p_value_not_set = false; + } +else { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad table entry for\n" +" \"%s\" parameter!\n" +" error status=%d", + name, status); + return status; /*** ERROR RETURN ***/ + } + +return 0; /*** NORMAL RETURN ***/ +} + +/******************************************************************************/ + +/* + * This function gets an array of CCTK_REAL values from the parameter table. + * + * Arguments: + * param_table_handle = handle to the Cactus key-value table + * name = the character-string key in the table + * default_value = the default value (for each array element) if the + * key isn't in the parameter table + * N = the size of the array + * buffer --> a buffer in which to store the array + * + * Results: + * This function returns 0 for ok, or the desired (nonzero) error return + * code if something is wrong. Note that error return codes may be either + * positive or negative! + */ +static + int get_REAL_array(int param_table_handle, const char name[], + CCTK_REAL default_value, + int N, CCTK_REAL buffer[]) +{ +const int status + = Util_TableGetRealArray(param_table_handle, + N, buffer, + name); +if (status == UTIL_ERROR_TABLE_NO_SUCH_KEY) + then { + /* set default value */ + int i; + for (i = 0 ; i < N ; ++i) + { + buffer[i] = default_value; + } + } +else if (status == N) + then { } /* ok ==> no-op here */ +else { + CCTK_VWarn(ERROR_MSG_SEVERITY_LEVEL, + __LINE__, __FILE__, CCTK_THORNSTRING, +"\n" +" CCTK_InterpLocalUniform(): bad table entry for\n" +" \"%s\" parameter!\n" +" error status=%d", + name, status); + return status; /*** ERROR RETURN ***/ + } + +return 0; /*** NORMAL RETURN ***/ +} |