aboutsummaryrefslogtreecommitdiff
path: root/src/GeneralizedPolynomial-Uniform/molecule_posn.c
blob: 44e78fc6c672c125e604576c53c78774b2b11008 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
 /*@@
   @file      molecule_posn.c
   @date      23 Oct 2001
   @author    Jonathan Thornburg <jthorn@aei.mpg.de>
   @desc      Worker function to compute molecule positions for interpolator.
   @enddesc
   @version   $Id$
 @@*/

#include <math.h>
#include <limits.h>
#include <stdlib.h>
#include <stdio.h>

#ifndef LOCALINTERP_STANDALONE_BUILD
  #include "cctk.h"
#endif

#include "InterpLocalUniform.h"

/* the rcs ID and its dummy function to use it */
static const char *rcsid = "$Header$";
#ifndef LOCALINTERP_STANDALONE_BUILD
  CCTK_FILEVERSION(CactusBase_LocalInterp_src_GeneralizedPolynomialUniform_molecule_posn_c)
#endif

/******************************************************************************/
/******************************************************************************/
/******************************************************************************/

/*@@
 @routine	LocalInterp_molecule_posn
 @date		23 Oct 2001
 @author	Jonathan Thornburg <jthorn@aei.mpg.de>
 @desc
	Given a uniformly-spaced grid, this function computes molecule
	positions for an interpolation or similar operation:
	(1) It computes the closest grid point to the input coordinate
	(2) It does the slightly tricky odd/even computation to decide where
	    to center the molecule
	(3) It checks for the molecule falling off the edge of the grid,
	    and off-centers it as appropriate.

	For (1), we assume that grid points have floating-point
	coordinates (we refer to these as "x") which are an arbitrary
	linear function of the integer grid coordinates (we refer to
	these as "i"), x = grid_origin + i*grid_delta.

	For (2), suppose we have a data array indexed by [i], from which we
	wish to select an N-point molecule [i_lo, i_hi] centered as close as
	possible to the point  x .  The problem is just how to choose the
	centering.  The following diagram illustrates the issues:

	N  i_lo  i_hi  [i-3]  [i-2]  [i-1]   [i]   [i+1]  [i+2]  [i+3]  [i+4]
	-  ----  ----  -----  -----  -----  -----  -----  -----  -----  -----
	2  i     i+1                          *xxxxxx*
	3  i-1   i+1                   *   xxx*xxx   *
	4  i-1   i+2                   *      *xxxxxx*      *
	5  i-2   i+2            *      *   xxx*xxx   *      *
	6  i-2   i+3            *      *      *xxxxxx*      *      *
	7  i-3   i+3     *      *      *   xxx*xxx   *      *      *
	8  i-3   i+4     *      *      *      *xxxxxx*      *      *      *

	The diagram shows the range of  x  values relative to the grid,
	for which we'll choose each centering.  Thus if N is even, the
	centering is based on which grid zone contains x (take the floor
	of the floating-point i coordinate), while if N is odd, the centering
	is based on which grid point is closest to x (round the floating-
	-point i coordinate to the nearest integer).

	It's also convenient to introduce the integer molecule coordinate m;
	this is the integer grid coordinate i relative to that of the molecule
	center, i.e. the above diagram has columns labelled with [i+m].
 @enddesc

 @var	grid_origin
 @vdesc	The floating-point coordinate x of the grid point i=0.
 @vtype	fp grid_origin
 @endvar

 @var	grid_delta
 @vdesc	The grid spacing (in the floating-point coordinate x).
 @vtype	fp grid_delta
 @endvar

 @var	grid_i_min
 @vdesc	The minimum integer coordinate i of the grid.
 @vtype	int grid_i_min
 @endvar

 @var	grid_i_max
 @vdesc	The maximum integer coordinate i of the grid.
 @vtype	int grid_i_max
 @endvar

 @var	molecule_size
 @vdesc	The size (number of points) of the molecule.
 @vtype	int molecule_size
 @endvar

 @var	out_of_range_tolerance_min, out_of_range_tolerance_max
 @vdesc	Specifies how out-of-range interpolation points should
	be handled for the {minimum,maximum} ends of the grid
	respectively.
	If out_of_range_tolerance >= 0.0,
	   then an interpolation point is considered to be
		"out of range" if and only if the interpolation
		point is > out_of_range_tolerance * grid_delta
		outside the grid in any coordinate.
	If out_of_range_tolerance == -1.0,
	   then an interpolation point is considered to be
		"out of range" if and only if a centered molecule
		would require data from outside the grid.
	Other values of out_of_range_tolerance are illegal.
 @vtype fp out_of_range_tolerance_min, out_of_range_tolerance_max
 @endvar

 @var	x
 @vdesc	The floating-point coordinate x at which we would like to center
	the molecule.
 @vtype	fp x
 @endvar

 @var	x_rel
 @vdesc	A pointer to a floating-point value where this function should
	store the x coordinate relative to the molecule center, measured
	in units of the grid spacing; or NULL to skip storing this.
 @vtype	fp *x_rel
 @vio	pointer to out
 @endvar

 @var	molecule_m_min, molecule_m_max
 @vdesc	A pointer to an int where this function should store the
	{minimum,maximum} molecule coordinate m of the molecule;
	or NULL to skip storing this.
 @vtype	int *molecule_m_min, *molecule_m_max
 @vio	pointer to out
 @endvar

 @returntype	int
 @returndesc
	This function returns the integer coordinate i_center at which
	the molecule should be centered, or one of the error codes
	(from <limits.h>)
	INT_MIN  if  x  is out-of-range on the min end of the grid
		 (i.e. x < the minimum allowable x)
	INT_MAX  if  x  is out-of-range on the max end of the grid
		 (i.e. x > the maximum allowable x)
 @endreturndesc
 @@*/
int LocalInterp_molecule_posn(fp grid_origin, fp grid_delta,
			      int grid_i_min, int grid_i_max,
			      int molecule_size,
			      fp out_of_range_tolerance_min,
			      fp out_of_range_tolerance_max,
			      fp x,
			      fp *x_rel,
			      int *molecule_m_min, int *molecule_m_max)
{
/* min/max molecule coordinates */
const int m_max = (molecule_size >> 1);		/* a positive number */
const int m_min = m_max - molecule_size + 1;	/* a negative number */

/* integer coordinate i of point x, as a floating-point number */
const fp fp_i = (x - grid_origin) / grid_delta;

/* is point x out-of-range? */
if (out_of_range_tolerance_min >= 0.0)
   then {
	const fp fp_effective_grid_i_min
		= ((fp) grid_i_min) - out_of_range_tolerance_min;
	if (fp_i < fp_effective_grid_i_min)
	   then return INT_MIN;				/*** ERROR RETURN ***/
	}
if (out_of_range_tolerance_max >= 0.0)
   then {
	const fp fp_effective_grid_i_max
		= ((fp) grid_i_max) + out_of_range_tolerance_max;
	if (fp_i > fp_effective_grid_i_max)
	   then return INT_MAX;				/*** ERROR RETURN ***/
	}

/* integer coordinate i where we will center the molecule */
/* (see diagram in header comment for explanation) */
/* ... as a floating-point number */
  {
const fp fp_i_center = is_even(molecule_size) ? floor(fp_i) : jt_round(fp_i);
/* ... as an integer */
int i_center = (int) fp_i_center;

/* min/max integer coordinates in molecule assuming it's fully centered */
const int centered_i_min = i_center + m_min;
const int centered_i_max = i_center + m_max;

/* check if off-centered molecules are forbidden? */
if ((out_of_range_tolerance_min == -1.0) && (centered_i_min < grid_i_min))
   then return INT_MIN;					/*** ERROR RETURN ***/
if ((out_of_range_tolerance_max == -1.0) && (centered_i_max > grid_i_max))
   then return INT_MAX;					/*** ERROR RETURN ***/

/* off-center as needed if we're close to the edge of the grid */
  {
int shift = 0;
if (centered_i_min < grid_i_min)
   then shift = grid_i_min - centered_i_min;	/* a positive number */
if (centered_i_max > grid_i_max)
   then shift = grid_i_max - centered_i_max;	/* a negative number */
i_center += shift;

/* store the results */
if (x_rel != NULL)
   then *x_rel = fp_i - ((fp) i_center);
if (molecule_m_min != NULL)
   then *molecule_m_min = m_min;
if (molecule_m_max != NULL)
   then *molecule_m_max = m_max;

return i_center;
  }
  }
}