aboutsummaryrefslogtreecommitdiff
path: root/src/patch/test_fd_grid.cc
blob: f23092a8a0a58257f009258ac2cabbdd44d93997 (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
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
// test_fd_grid.cc -- test driver for fd_grid and lower-level classes
// $Id$

//
// main
/// test_grid - test various grid:: member functions
///
/// f - test function
/// derivs - analytical derivatives of f (code generated by Maple)
///

#include <stdio.h>
#include <assert.h>
#include <math.h>

#include "jt/stdc.h"
#include "jt/util++.hh"
#include "jt/array.hh"
#include "jt/linear_map.hh"

#include "fp.hh"
#include "coords.hh"
#include "grid.hh"
#include "fd_grid.hh"

using jtutil::error_exit;

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

//
// This program is a test driver for the classes fd_grid::, grid_arrays::,
// and grid::.
//

const char *usage =
"\
Usage:\n\
   test_fd_grid  delta_drho  delta_dsigma  [ N_rhosigma ]\n\
                 [ fn | drho | dsigma | drhorho | drhosigma | dsigmasigma ] \n\
where\n\
   delta_drho  and  delta_dsigma  are the (rho,sigma) grid spacings\n\
   N_rhosigma , if specified, shrinks the max_{rho,sigma} grid bounds so\n\
      the grid has about that many points in each of the rho and sigma\n\
      directions\n\
\n\
This program tests the fd_grid:: finite differencing code by setting\n\
up a test function, finite differencing it, computing the analytical\n\
derivatives, and printing a table of the difference between the finite\n\
difference and analytical derivatives.  It also tests various grid::\n\
member functions by comparing their results against correct results.\n\
\n\
By default, the finite differencing test uses a combination of all\n\
the partial derivatives.  If the 4th argument is specified, then this\n\
restricts the test to only that derivative (this is useful for debugging\n\
problems with class fd_grid::).\n\
\n\
The program prints an ASCII data file on standard output, suitable for\n\
the gnuplot `splot' command, giving the error\n\
   finite differencing - analytical\n\
";

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

// bit-mask flags to encode which derivative to test
static const int flag_fn          = 0x01,
		 flag_drho        = 0x02,
		 flag_dsigma      = 0x04,
		 flag_drhorho     = 0x08,
		 flag_drhosigma   = 0x10,
		 flag_dsigmasigma = 0x20,
		 flag_all = flag_fn
			    | flag_drho | flag_dsigma
			    | flag_drhorho | flag_drhosigma | flag_dsigmasigma;

// when testing multiple derivatives, we combine them together
// with these weights (chosen from digits of pi)
static const fp weight_fn          = 3.1,
		weight_drho        = 4.1,
		weight_dsigma      = 5.9,
		weight_drhorho     = 2.6,
		weight_drhosigma   = 5.3,
		weight_dsigmasigma = 5.8;

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

// fixed parameters for the grid

const fp min_drho   = - 70.0;
      fp max_drho   = +110.0;		// may be shrunk (via N_rhosigma)
const fp min_dsigma = -100.0;
      fp max_dsigma = +120.0;		// may be shruna (via N_rhosigma)

const int   min_rho_N_ghost_zones = 3;
const int   max_rho_N_ghost_zones = 4;
const int min_sigma_N_ghost_zones = 2;
const int max_sigma_N_ghost_zones = 5;

const int N_gridfns = 4;

// gfns
const int gfn_fn = 0;
const int gfn_deriv_true = 1;
const int gfn_deriv_fd = 2;
const int gfn_error = 3;

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

//
// function prototypes
//

namespace {
void test_grid(const grid& g,
	       double delta_drho, double delta_dsigma,
	       int min_irho, int max_irho, int min_isigma, int max_isigma);

void setup_fn(grid& g);
void setup_deriv_true(grid& g, int flags);
void setup_deriv_fd(fd_grid& g, int flags);
void compute_error(grid& g);

fp fn(fp rho, fp sigma);
fp deriv(fp rho, fp sigma, int flags);
	  };

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

int main(int argc, const char *argv[])
{
//
// ***** parse the arguments
//

fp delta_drho, delta_dsigma;
if (! (    ((argc == 3) || (argc == 4) || (argc == 5))
	&& (sscanf(argv[1], FP_SCANF_FORMAT, &delta_drho) == 1)
	&& (sscanf(argv[2], FP_SCANF_FORMAT, &delta_dsigma) == 1)    ) )
   then error_exit(ERROR_EXIT, "%s", usage);			/*NOTREACHED*/

if (argc >= 4)
   then {
	int N_rhosigma;
	if (! (sscanf(argv[3], "%d", &N_rhosigma) == 1) )
	   then error_exit(ERROR_EXIT, "%s", usage);		/*NOTREACHED*/

	// size specified ==> shrink the grid to that size
	max_drho = min_drho + fp(N_rhosigma)*delta_drho;
	max_dsigma = min_dsigma + fp(N_rhosigma)*delta_dsigma;
	}

int flags = flag_all;
if (argc >= 5)
   then {
	if      (STRING_EQUAL(argv[4], "fn")) then flags = flag_fn;
	else if (STRING_EQUAL(argv[4], "drho")) then flags = flag_drho;
	else if (STRING_EQUAL(argv[4], "dsigma")) then flags = flag_dsigma;
	else if (STRING_EQUAL(argv[4], "drhorho")) then flags = flag_drhorho;
	else if (STRING_EQUAL(argv[4], "drhosigma"))
	   then flags = flag_drhosigma;
	else if (STRING_EQUAL(argv[4], "dsigmasigma"))
	   then flags = flag_dsigmasigma;
	else	error_exit(ERROR_EXIT, "%s", usage);		/*NOTREACHED*/
	}

if (! (    fuzzy<fp>::is_integer(min_drho  /delta_drho  )
	&& fuzzy<fp>::is_integer(max_drho  /delta_drho  )
	&& fuzzy<fp>::is_integer(min_dsigma/delta_dsigma)
	&& fuzzy<fp>::is_integer(max_dsigma/delta_dsigma)    ) )
   then error_exit(ERROR_EXIT,
		   "grid spacings must divide grid min/max bounds!\n");
								/*NOTREACHED*/
const int min_irho   = round<fp>::to_integer(min_drho  /delta_drho  );
const int max_irho   = round<fp>::to_integer(max_drho  /delta_drho  );
const int min_isigma = round<fp>::to_integer(min_dsigma/delta_dsigma);
const int max_isigma = round<fp>::to_integer(max_dsigma/delta_dsigma);

struct grid_arrays::array_pars grid_array_pars;
grid_array_pars.  min_irho =   min_irho;
grid_array_pars.  max_irho =   max_irho;
grid_array_pars.min_isigma = min_isigma;
grid_array_pars.max_isigma = max_isigma;
grid_array_pars.  min_rho_N_ghost_zones =   min_rho_N_ghost_zones;
grid_array_pars.  max_rho_N_ghost_zones =   max_rho_N_ghost_zones;
grid_array_pars.min_sigma_N_ghost_zones = min_sigma_N_ghost_zones;
grid_array_pars.max_sigma_N_ghost_zones = max_sigma_N_ghost_zones;

struct grid::grid_pars grid_pars;
grid_pars.    min_drho =     min_drho;
grid_pars.  delta_drho =   delta_drho;
grid_pars.    max_drho =     max_drho;
grid_pars.  min_dsigma =   min_dsigma;
grid_pars.delta_dsigma = delta_dsigma;
grid_pars.  max_dsigma =   max_dsigma;

printf("## creating fd_grid...\n");
fd_grid g(grid_array_pars, grid_pars, N_gridfns);

test_grid(g,
	  delta_drho, delta_dsigma,
	  min_irho, max_irho, min_isigma, max_isigma);

setup_fn(g);
setup_deriv_true(g, flags);
setup_deriv_fd(g, flags);
compute_error(g);
g.print_gridfn(gfn_error);
}

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

//
// This function does some basic tests on grid:: and grid_arrays::
// member functions.
//
namespace {
void test_grid(const grid& g,
	       double delta_drho, double delta_dsigma,
	       int min_irho, int max_irho, int min_isigma, int max_isigma)
{
printf("## doing basic sanity checks on grid...\n");

assert( g.N_gridfns() == N_gridfns );

assert( fuzzy<fp>::EQ(g.min_drho(), min_drho) );
assert( fuzzy<fp>::EQ(g.delta_drho(), delta_drho) );
assert( fuzzy<fp>::EQ(g.max_drho(), max_drho) );
assert( fuzzy<fp>::EQ(g.min_dsigma(), min_dsigma) );
assert( fuzzy<fp>::EQ(g.delta_dsigma(), delta_dsigma) );
assert( fuzzy<fp>::EQ(g.max_dsigma(), max_dsigma) );

assert( g.min_irho() == min_irho );
assert( g.max_irho() == max_irho );
assert( g.min_isigma() == min_isigma );
assert( g.max_isigma() == max_isigma );

assert( g.full_grid__min_irho() == min_irho - min_rho_N_ghost_zones );
assert( g.full_grid__max_irho() == max_irho + max_rho_N_ghost_zones );
assert( g.full_grid__min_isigma() == min_isigma - min_sigma_N_ghost_zones );
assert( g.full_grid__max_isigma() == max_isigma + max_sigma_N_ghost_zones );
}
	  }

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

//
// This function sets up the test function for the finite differencing
// tests.  It sets it up on the *full* grid, i.e. including the ghost
// zones.
//
namespace {
void setup_fn(grid& g)
{
printf("## setting up function...\n");

	for (int irho = g.full_grid__min_irho() ;
	     irho <= g.full_grid__max_irho() ;
	     ++irho)
	{
	for (int isigma = g.full_grid__min_isigma() ;
	     isigma <= g.full_grid__max_isigma() ;
	     ++isigma)
	{
	const fp rho = g.rho_of_irho(irho);
	const fp sigma = g.sigma_of_isigma(isigma);
	g.gridfn(gfn_fn, irho,isigma) = fn(rho,sigma);
	}
	}
}
	  }

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

//
// This function sets up the analytic derivative expression for the
// finite differencing tests.
//
namespace {
void setup_deriv_true(grid& g, int flags)
{
printf("## setting up analytic derivatives...\n");

	for (int irho = g.min_irho() ; irho <= g.max_irho() ; ++irho)
	{
	for (int isigma = g.min_isigma() ; isigma <= g.max_isigma() ; ++isigma)
	{
	const fp rho = g.rho_of_irho(irho);
	const fp sigma = g.sigma_of_isigma(isigma);
	g.gridfn(gfn_deriv_true, irho,isigma) = deriv(rho,sigma, flags);
	}
	}
}
	  }

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

//
// This function sets up the analytic derivative expression for the
// finite differencing tests.
//
namespace {
void setup_deriv_fd(fd_grid& g, int flags)
{
printf("## computing finite-difference derivatives...\n");

	for (int irho = g.min_irho() ; irho <= g.max_irho() ; ++irho)
	{
	for (int isigma = g.min_isigma() ; isigma <= g.max_isigma() ; ++isigma)
	{
	g.gridfn(gfn_deriv_fd, irho,isigma) = 0.0;

	// function
	if (flags & flag_fn)
	   then g.gridfn(gfn_deriv_fd, irho,isigma)
			+= weight_fn * g.gridfn(gfn_fn, irho,isigma);

	// 1st derivatives
	if (flags & flag_drho)
	   then g.gridfn(gfn_deriv_fd, irho,isigma)
			+= weight_drho * g.partial_rho(gfn_fn, irho,isigma);
	if (flags & flag_dsigma)
	   then g.gridfn(gfn_deriv_fd, irho,isigma)
			+= weight_dsigma * g.partial_sigma(gfn_fn, irho,isigma);

	// 2nd derivatives
	if (flags & flag_drhorho)
	   then g.gridfn(gfn_deriv_fd, irho,isigma)
			+= weight_drhorho
			   * g.partial_rho_rho(gfn_fn, irho,isigma);
	if (flags & flag_drhosigma)
	   then g.gridfn(gfn_deriv_fd, irho,isigma)
			+= weight_drhosigma
			   * g.partial_rho_sigma(gfn_fn, irho,isigma);
	if (flags & flag_dsigmasigma)
	   then g.gridfn(gfn_deriv_fd, irho,isigma)
			+= weight_dsigmasigma
			   * g.partial_sigma_sigma(gfn_fn, irho,isigma);
	}
	}
}
	  }

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

//
// This function sets up the test function for the finite differencing
// tests.
//
namespace {
void compute_error(grid& g)
{
printf("## computing error...\n");

	for (int irho = g.min_irho() ; irho <= g.max_irho() ; ++irho)
	{
	for (int isigma = g.min_isigma() ; isigma <= g.max_isigma() ; ++isigma)
	{
	g.gridfn(gfn_error, irho,isigma)
		= g.gridfn(gfn_deriv_fd, irho,isigma)
		  - g.gridfn(gfn_deriv_true, irho,isigma);
	}
	}
}
	  }

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

//
// this is the test function for our finite differencing tests
//
namespace {
fp fn(fp rho, fp sigma)
{
return exp(sin(rho) + tanh(sigma));
}
	  };

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

//
// This function computes the sum of our linear combination of
// various (analytical) derivatives of fn().  The derivatives were
// machine-generated via Maple's codegen[C]() function.
//
// "test_fd_grid.maple" is the Maple input
// "test_fd_grid.out" is the Maple input; code here is cut-n-pasted
//		       from the Maple codegen[C]() output there
//
// Arguments:
// flags = A bit-mask of flags specifying which terms to use in the
//	   linear combination.
//
namespace {
fp deriv(fp rho, fp sigma, int flags)
{
fp sum = 0.0;

// function
if (flags & flag_fn)
   then {
	fp temp = fn(rho,sigma);
	sum += weight_fn * temp;
	}

// 1st derivatives
if (flags & flag_drho)
   then {
	fp temp = cos(rho)*exp((sin(rho)*cosh(sigma)+sinh(sigma))
		  / cosh(sigma));
	sum += weight_drho * temp;
	}
if (flags & flag_dsigma)
   then {
	fp temp = exp((sin(rho)*cosh(sigma)+sinh(sigma))/cosh(sigma))
		  / pow(cosh(sigma),2.0);
	sum += weight_dsigma * temp;
	}

// 2nd derivatives
if (flags & flag_drhorho)
   then {
	fp temp = -exp((sin(rho)*cosh(sigma)+sinh(sigma))/cosh(sigma))
		   * (sin(rho)-pow(cos(rho),2.0));
	sum += weight_drhorho * temp;
	}
if (flags & flag_drhosigma)
   then {
	fp temp = cos(rho)*exp((sin(rho)*cosh(sigma)+sinh(sigma))/cosh(sigma))
		  / pow(cosh(sigma),2.0);
	sum += weight_drhosigma * temp;
	}
if (flags & flag_dsigmasigma)
   then {
	fp temp = -exp((sin(rho)*cosh(sigma)+sinh(sigma))/cosh(sigma))
		   * (2.0*sinh(sigma)*cosh(sigma)-1.0)
		   / pow(cosh(sigma),4.0);
	sum += weight_dsigmasigma * temp;
	}

return sum;
}
	  };