aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README1
-rw-r--r--interface.ccl4
-rw-r--r--param.ccl5
-rw-r--r--schedule.ccl20
-rw-r--r--src/make.code.defn2
-rw-r--r--src/patch/ghost_zone.cc14
-rw-r--r--src/patch/ghost_zone.hh160
-rw-r--r--src/patch/test_patch_system.cc190
8 files changed, 306 insertions, 90 deletions
diff --git a/README b/README
index 11ba877..164beed 100644
--- a/README
+++ b/README
@@ -66,3 +66,4 @@ Portability
This thorn is known to compile and run successfully on the following
systems:
* Red Hat GNU/Linux, gcc/g++ version 2.96 20000731 (Red Hat Linux 7.1 2.96-98)
+* OpenBSD, gcc/g++ version 2.95.3 20010125 (prerelease)
diff --git a/interface.ccl b/interface.ccl
index 3cb9303..6a8c611 100644
--- a/interface.ccl
+++ b/interface.ccl
@@ -2,5 +2,5 @@
# $Header$
implements: AHFinder
-inherits: grid
-inherits: einstein
+##inherits: grid
+##inherits: einstein
diff --git a/param.ccl b/param.ccl
index d2a0ea7..3b43c96 100644
--- a/param.ccl
+++ b/param.ccl
@@ -172,3 +172,8 @@ real NP_Jacobian__perturbation_amplitude \
{
(0.0:* :: "any real number > 0"
} 1.0e-6
+
+string Jacobian_file_name "name of the Jacobian output file"
+{
+.+ :: "any valid file name"
+} "Jacobian.dat"
diff --git a/schedule.ccl b/schedule.ccl
index afe9ce2..f413ed0 100644
--- a/schedule.ccl
+++ b/schedule.ccl
@@ -8,14 +8,14 @@
# ==> quick-n-dirty hack for now: just schedule at POSTINITIAL
#
-schedule AHFinderDirect_driver at CCTK_POSTINITIAL
-{
-lang: C
-options: global
-} "find apparent horizon(s)"
-
-##schedule test_patch_system at CCTK_POSTINITIAL
+##schedule AHFinderDirect_driver at CCTK_POSTINITIAL
##{
-##LANG: C
-##OPTIONS: global
-##} "test driver to verify that src/util/ and src/jtutil/ code works properly"
+##lang: C
+##options: global
+##} "find apparent horizon(s)"
+
+schedule test_patch_system at CCTK_POSTINITIAL
+{
+LANG: C
+OPTIONS: global
+} "test driver to verify that src/util/ and src/jtutil/ code works properly"
diff --git a/src/make.code.defn b/src/make.code.defn
index b60ca69..cc06be4 100644
--- a/src/make.code.defn
+++ b/src/make.code.defn
@@ -5,4 +5,4 @@
SRCS =
# Subdirectories containing source files
-SUBDIRS = jtutil util gr
+SUBDIRS = jtutil util ## gr
diff --git a/src/patch/ghost_zone.cc b/src/patch/ghost_zone.cc
index 8516241..3197e2e 100644
--- a/src/patch/ghost_zone.cc
+++ b/src/patch/ghost_zone.cc
@@ -175,7 +175,7 @@ interpatch_ghost_zone::interpatch_ghost_zone(const patch_edge& my_edge_in,
min_ipar_used_(NULL), max_ipar_used_(NULL),
other_par_(NULL),
interp_result_buffer_(NULL),
- Jacobian_oipar_posn_(NULL), Jacobian_buffer_(NULL) // no comma
+ Jacobian_y_ipar_posn_(NULL), Jacobian_buffer_(NULL) // no comma
{
//
// verify that we have the expected relationships between
@@ -330,7 +330,7 @@ other_iperp_ = new jtutil::cpm_map<fp>(min_iperp(), max_iperp(),
interpatch_ghost_zone::~interpatch_ghost_zone()
{
delete Jacobian_buffer_;
-delete Jacobian_oipar_posn_;
+delete Jacobian_y_ipar_posn_;
delete interp_result_buffer_;
delete other_par_;
delete max_ipar_used_;
@@ -589,18 +589,18 @@ assert(other_patch_interp_ != NULL);
other_patch_interp_->verify_Jacobian_sparsity_pattern_ok();
-other_patch_interp_->molecule_minmax_ipar_m(min_oipar_m_, max_oipar_m_);
+other_patch_interp_->molecule_minmax_ipar_m(min_y_ipar_m_, max_y_ipar_m_);
-if (Jacobian_oipar_posn_ == NULL)
- then Jacobian_oipar_posn_ = new jtutil::array2d<CCTK_INT>
+if (Jacobian_y_ipar_posn_ == NULL)
+ then Jacobian_y_ipar_posn_ = new jtutil::array2d<CCTK_INT>
(min_other_iperp_, max_other_iperp_,
extreme_min_ipar_, extreme_max_ipar_);
-other_patch_interp_->molecule_posn(*Jacobian_oipar_posn_);
+other_patch_interp_->molecule_posn(*Jacobian_y_ipar_posn_);
if (Jacobian_buffer_ == NULL)
then Jacobian_buffer_ = new jtutil::array3d<fp>
(min_other_iperp_, max_other_iperp_,
extreme_min_ipar_, extreme_max_ipar_,
- min_oipar_m_, max_oipar_m_);
+ min_y_ipar_m_, max_y_ipar_m_);
other_patch_interp_->Jacobian(*Jacobian_buffer_);
}
diff --git a/src/patch/ghost_zone.hh b/src/patch/ghost_zone.hh
index 70b7f3b..1cf1517 100644
--- a/src/patch/ghost_zone.hh
+++ b/src/patch/ghost_zone.hh
@@ -249,6 +249,11 @@ public:
// operation into internal buffers; the following functions
// provide access to that Jacobian.
//
+ // n.b. terminology is
+ // partial gridfn at x
+ // -------------------
+ // partial gridfn at y
+ //
// FIXME: should these be moved out into a separate Jacobian
// object/class?
//
@@ -262,46 +267,44 @@ public:
// The API in the remaining functions implicitly assumes that
// the Jacobian is independent of ghosted_gfn , and also that
// the structure of the Jacobian is "simple", in that the set of
- // points (with nonzero Jacobian values) in a single row of the
+ // y points (with nonzero Jacobian values) in a single row of the
// Jacobian matrix (i.e. the set of points on which a single
// ghost-zone point depends),
- // - lies entirely within a single patch
- // - has the same number of points for every point in this ghost zone
- // - has a single oiperp value (= iperp value in their patch)
- // (depending on our iperp, of course)
- // - have a contiguous interval of oipar (= ipar in their patch)
- // (depending on our iperp and ipar, of course), whose
- // size is
+ // - lies entirely within a single y patch
+ // - has the same number of points for every x point in this ghost zone
+ // - has a single yiperp value (depending on our iperp, of course)
+ // - have a contiguous interval of yipar (depending on our iperp
+ //and ipar, of course), whose size is
// [or can be taken to be without an unreasonable
// amount of zero-padding]
// independent of our iperp and ipar; we parameterize this
- // interval as oipar = posn+m where posn is determined by
+ // interval as yipar = posn+m where posn is determined by
// our iperp and ipar, and m has a fixed range independent
// of our iperp and ipar
//
- // to which patch/edge do the points in this Jacobian row belong?
- virtual const patch& Jacobian_patch() const = 0;
- virtual const patch_edge& Jacobian_edge() const = 0;
+ // to which patch/edge do the y points in this Jacobian row belong?
+ virtual patch& Jacobian_y_patch() const = 0;
+ virtual const patch_edge& Jacobian_y_edge() const = 0;
// what is the [min,max] range of m for this ghost zone?
- virtual int Jacobian_min_oipar_m() const = 0;
- virtual int Jacobian_max_oipar_m() const = 0;
+ virtual int Jacobian_y_min_ipar_m() const = 0;
+ virtual int Jacobian_y_max_ipar_m() const = 0;
- // what is the oiperp of the Jacobian points (= iperp in their patch)?
- virtual int Jacobian_oiperp(int iperp) const = 0;
+ // what is the iperp of the Jacobian y points in their (y) patch?
+ virtual int Jacobian_y_iperp(int x_iperp) const = 0;
- // what is the posn value of the points in this Jacobian row?
- virtual int Jacobian_oipar_posn(int iperp, int ipar) const = 0;
+ // what is the posn value of the y points in this Jacobian row?
+ virtual int Jacobian_y_ipar_posn(int x_iperp, int x_ipar) const = 0;
// what is the Jacobian
- // partial synchronize gridfn(ghosted_gfn, iperp, ipar)
- // ------------------------------------------------------------
- // partial other patch gridfn(ghosted_gfn, oiperp, posn+ipar_m)
+ // partial synchronize() px.gridfn(ghosted_gfn, x_iperp, x_ipar)
+ // -------------------------------------------------------------
+ // partial py.gridfn(ghosted_gfn, y_iperp, y_posn+y_ipar_m)
// where
- // oiperp = Jacobian_oiperp(iperp)
- // posn = Jacobian_oipar_posn(iperp, ipar)
- virtual fp Jacobian(int iperp, int ipar, int ipar_m) const = 0;
+ // y_iperp = Jacobian_y_iperp(x_iperp)
+ // y_posn = Jacobian_y_ipar_posn(x_iperp, x_ipar)
+ virtual fp Jacobian(int x_iperp, int x_ipar, int y_ipar_m) const = 0;
public:
@@ -466,6 +469,11 @@ public:
//
// ***** Jacobian of synchronize() *****
//
+ // n.b. terminology is
+ // partial gridfn at x
+ // -------------------
+ // partial gridfn at y
+ //
// allocate internal buffers, compute Jacobian
// ... this function is a no-op in this class
@@ -475,30 +483,31 @@ public:
bool want_max_par_corner)
{ }
- // to which patch/edge do the points in this Jacobian row belong?
- const patch& Jacobian_patch() const { return symmetry_patch_; }
- const patch_edge& Jacobian_edge() const { return symmetry_edge_; }
+ // to which patch/edge do the y points in this Jacobian row belong?
+ patch& Jacobian_y_patch() const { return symmetry_patch_; }
+ const patch_edge& Jacobian_y_edge() const { return symmetry_edge_; }
// what is the [min,max] range of m for this ghost zone?
- int Jacobian_min_oipar_m() const { return 0; }
- int Jacobian_max_oipar_m() const { return 0; }
+ int Jacobian_y_min_ipar_m() const { return 0; }
+ int Jacobian_y_max_ipar_m() const { return 0; }
// what is the oiperp of the Jacobian points (= iperp in their patch)?
- virtual int Jacobian_oiperp(int iperp) const
- { return iperp_map_of_iperp(iperp); }
+ virtual int Jacobian_y_iperp(int x_iperp) const
+ { return iperp_map_of_iperp(x_iperp); }
// what is the posn value of the points in this Jacobian row?
- int Jacobian_oipar_posn(int iperp, int ipar) const
- { return ipar_map_of_ipar(ipar); }
+ int Jacobian_y_ipar_posn(int x_iperp, int x_ipar) const
+ { return ipar_map_of_ipar(x_ipar); }
// what is the Jacobian
- // partial synchronize gridfn(ghosted_gfn, iperp, ipar)
- // ------------------------------------------------------------
- // partial other patch gridfn(ghosted_gfn, oiperp, posn+ipar_m)
+ // partial synchronize() px.gridfn(ghosted_gfn, x_iperp, x_ipar)
+ // -------------------------------------------------------------
+ // partial py.gridfn(ghosted_gfn, y_iperp, y_posn+y_ipar_m)
// where
- // oiperp = Jacobian_oiperp(iperp)
- // posn = Jacobian_oipar_posn(iperp, ipar)
- fp Jacobian(int iperp, int ipar, int ipar_m) const { return 1.0; }
+ // y_iperp = Jacobian_y_iperp(x_iperp)
+ // y_posn = Jacobian_y_ipar_posn(x_iperp, x_ipar)
+ fp Jacobian(int x_iperp, int x_ipar, int y_ipar_m) const
+ { return (y_ipar_m == 0) ? 1.0 : 0.0; }
//
@@ -506,7 +515,7 @@ public:
//
// symmetry-map coordinates
- const patch& symmetry_patch() const { return symmetry_patch_; }
+ patch& symmetry_patch() const { return symmetry_patch_; }
const patch_edge& symmetry_edge() const { return symmetry_edge_; }
int iperp_map_of_iperp(int iperp) const
{ return iperp_map_->map(iperp); }
@@ -544,7 +553,7 @@ private:
private:
// symmetry mapping --> interior of which patch? which edge?
- const patch& symmetry_patch_;
+ patch& symmetry_patch_;
const patch_edge& symmetry_edge_;
// symmetry mappings for (iperp,ipar)
@@ -602,6 +611,11 @@ public:
//
// ***** Jacobian of synchronize() *****
//
+ // n.b. terminology is
+ // partial gridfn at x
+ // -------------------
+ // partial gridfn at y
+ //
// allocate internal buffers, compute Jacobian
//
@@ -613,36 +627,43 @@ public:
bool want_noncorner,
bool want_max_par_corner);
- // to which patch/edge do the points in this Jacobian row belong?
- const patch& Jacobian_patch() const { return other_patch_; }
- const patch_edge& Jacobian_edge() const { return other_edge_; }
+ // to which patch/edge do the y points in this Jacobian row belong?
+ patch& Jacobian_y_patch() const { return other_patch_; }
+ const patch_edge& Jacobian_y_edge() const { return other_edge_; }
// what is the [min,max] range of m for this ghost zone?
- int Jacobian_min_oipar_m() const { return min_oipar_m_; }
- int Jacobian_max_oipar_m() const { return max_oipar_m_; }
+ int Jacobian_y_min_ipar_m() const { return min_y_ipar_m_; }
+ int Jacobian_y_max_ipar_m() const { return max_y_ipar_m_; }
- // what is the oiperp of the Jacobian points (= iperp in their patch)?
- int Jacobian_oiperp(int iperp) const { return other_iperp(iperp); }
+ // what is the iperp of the Jacobian y points in their (y) patch?
+ // ... the ipar row of grid points is actually the same, so
+ // we just have to translate x_iperp to the y patch's coordinates
+ int Jacobian_y_iperp(int x_iperp) const { return other_iperp(x_iperp); }
- // what is the posn value of the points in this Jacobian row?
- int Jacobian_oipar_posn(int iperp, int ipar) const
+ // what is the posn value of the y points in this Jacobian row?
+ int Jacobian_y_ipar_posn(int x_iperp, int x_ipar) const
{
- assert(Jacobian_oipar_posn_ != NULL);
- const int oiperp = other_iperp(iperp);
- return (*Jacobian_oipar_posn_)(oiperp, ipar);
+ assert(Jacobian_y_ipar_posn_ != NULL);
+ const int y_iperp = Jacobian_y_iperp(x_iperp);
+ return (*Jacobian_y_ipar_posn_)(y_iperp, x_ipar);
}
// what is the Jacobian
- // partial synchronize gridfn(ghosted_gfn, iperp, ipar)
- // ------------------------------------------------------------
- // partial other patch gridfn(ghosted_gfn, oiperp, posn+ipar_m)
+ // partial synchronize() px.gridfn(ghosted_gfn, x_iperp, x_ipar)
+ // -------------------------------------------------------------
+ // partial py.gridfn(ghosted_gfn, y_iperp, y_posn+y_ipar_m)
// where
- // posn = Jacobian_oipar_posn(iperp, ipar)
- fp Jacobian(int iperp, int ipar, int ipar_m) const
+ // y_iperp = Jacobian_y_iperp(x_iperp)
+ // y_posn = Jacobian_y_ipar_posn(x_iperp, x_ipar)
+ fp Jacobian(int x_iperp, int x_ipar, int y_ipar_m) const
{
assert(Jacobian_buffer_ != NULL);
- const int oiperp = other_iperp(iperp);
- return (*Jacobian_buffer_)(oiperp, ipar, ipar_m);
+ if ((y_ipar_m >= min_y_ipar_m_) && (y_ipar_m <= max_y_ipar_m_))
+ then {
+ const int y_iperp = Jacobian_y_iperp(x_iperp);
+ return (*Jacobian_buffer_)(y_iperp, x_ipar, y_ipar_m);
+ }
+ else return 0.0;
}
//
@@ -650,10 +671,8 @@ public:
//
// basic connectivity info
- const patch& other_patch() const
- { return other_patch_; }
- const patch_edge& other_edge() const
- { return other_edge_; }
+ patch& other_patch() const { return other_patch_; }
+ const patch_edge& other_edge() const { return other_edge_; }
// check consistency of this and the other patch's ghost zones
// and patch_interp objects
@@ -754,13 +773,18 @@ private:
//
// stuff computed by compute_Jacobian()
//
- int min_oipar_m_, max_oipar_m_;
+ // n.b. terminology is
+ // partial gridfn at x
+ // -------------------
+ // partial gridfn at y
+ //
+ int min_y_ipar_m_, max_y_ipar_m_;
- // other patch's ipar posn for a Jacobian row
+ // other patch's y ipar posn for a Jacobian row
// ... subscripts are (oiperp, ipar)
- jtutil::array2d<CCTK_INT>* Jacobian_oipar_posn_;
+ jtutil::array2d<CCTK_INT>* Jacobian_y_ipar_posn_;
// Jacobian values
- // ... subscripts are (oiperp, ipar, oipar_m)
+ // ... subscripts are (y_iperp, x_ipar, y_ipar_m)
jtutil::array3d<fp>* Jacobian_buffer_;
};
diff --git a/src/patch/test_patch_system.cc b/src/patch/test_patch_system.cc
index 16d89a4..5143f26 100644
--- a/src/patch/test_patch_system.cc
+++ b/src/patch/test_patch_system.cc
@@ -98,12 +98,18 @@ extern "C"
void test_patch_system(CCTK_ARGUMENTS);
namespace {
+void test_synchronize_Jacobians(patch_system& ps,
+ int test_gfn, int NP_test_gfn,
+ fp perturbation_amplitude,
+ const char Jacobian_file_name[]);
+
void setup_sym_fn_xyz(patch_system& ps, int ghosted_gfn, bool want_ghost_zones);
void setup_fn_rho_sigma(patch_system& ps, int ghosted_gfn);
void finite_diff(patch_system& ps,
int ghosted_gfn_src, int gfn_dst,
int which_derivs);
void analytic_derivs(patch_system& ps, int gfn_dst, int which_derivs);
+
void gridfn_minus(patch_system& ps,
int gfn_x, int gfn_y, int gfn_dst);
void ghosted_gridfn_minus(patch_system& ps,
@@ -169,28 +175,40 @@ if (STRING_EQUAL(which_test, "gridfn"))
setup_sym_fn_xyz(ps, test_fn_gfn, true);
ps.print_ghosted_gridfn(test_fn_gfn, "test_fn.dat");
}
-else if (STRING_EQUAL(which_test, "read-gridfn"))
+
+else if (STRING_EQUAL(which_test, "read gridfn"))
then {
ps.read_ghosted_gridfn(test_fn_gfn, "test_fn.dat");
ps.print_ghosted_gridfn(test_fn_gfn, "test_fn2.dat");
}
+
else if (STRING_EQUAL(which_test, "synchronize"))
then {
setup_sym_fn_xyz(ps, test_fn_gfn, false);
ps.print_ghosted_gridfn(test_fn_gfn, "test_fn_init.dat");
+
setup_sym_fn_xyz(ps, test_fn_copy_gfn, true);
ps.print_ghosted_gridfn(test_fn_copy_gfn, "test_fn_copy.dat");
+
ps.synchronize_ghost_zones(test_fn_gfn, test_fn_gfn);
ps.print_ghosted_gridfn(test_fn_gfn, "test_fn_sync.dat");
+
ghosted_gridfn_minus(ps,
test_fn_gfn, test_fn_copy_gfn,
ghosted_error_gfn);
ps.print_ghosted_gridfn(ghosted_error_gfn, "ghosted_error.dat");
}
+
+else if (STRING_EQUAL(which_test, "synchronize Jacobian"))
+ then test_synchronize_Jacobians(ps,
+ test_fn_copy_gfn, test_fn_gfn,
+ NP_Jacobian__perturbation_amplitude,
+ Jacobian_file_name);
+
else if (STRING_EQUAL(which_test, "derivatives"))
then {
setup_fn_rho_sigma(ps, test_fn_gfn);
- ps.print_gridfn(nominal_error_gfn, "test_fn.dat");
+ ps.print_gridfn(test_fn_gfn, "test_fn.dat");
finite_diff(ps, test_fn_gfn, FD_derivs_gfn, which_derivs);
ps.print_gridfn(FD_derivs_gfn, "FD_derivs.dat");
analytic_derivs(ps, analytic_derivs_gfn, which_derivs);
@@ -200,6 +218,7 @@ else if (STRING_EQUAL(which_test, "derivatives"))
nominal_error_gfn);
ps.print_gridfn(nominal_error_gfn, "nominal_error.dat");
}
+
else CCTK_VWarn(-1, __LINE__, __FILE__, CCTK_THORNSTRING,
"unknown which_test=\"%s\"!",
which_test); /*NOTREACHED*/
@@ -212,6 +231,173 @@ CCTK_VInfo(CCTK_THORNSTRING, "destroying patch system");
//******************************************************************************
//
+// This function tests the computation of the Jacobian of the
+// patch_system::synchronize() operation. In outline, it does the following:
+//
+// set up a test function in test_gfn on the nominal grid
+// synchronize test_gfn
+// print ths synchronized function
+// set up the same test function in NP_test_gfn on the nominal grid
+// for each patch p and ghost zone pgz
+// {
+// compute the synchronize() Jacobian for this ghost zone
+// (via pgz.compute_Jacobian() et al)
+// for each point x in (p,pgz)
+// {
+// for each point y in gz.Jacobian_y_patch()
+// {
+// const fp save_y_gridfn = NP_test_gfn at y
+// NP_test_gfn at y += perturbation_amplitude
+// synchronize NP_test_gfn
+// NP_Jacobian = (NP_test_gfn at x - test_gfn at x)
+// / perturbation_amplitude
+// NP_test_gfn at y = save_y_gridfn
+// Jacobian = pgz.Jacobian(...)
+// if (m in molecule || the Jacobians differ)
+// then print Jacobian, NP_Jacobian,
+// Jacobian error
+// }
+// }
+// }
+//
+// Arguments:
+// ps = (in out) THe patch system in/on which to do the computations.
+// test_gfn, NP_test_gfn = The gfns of two ghosted test gridfns.
+// perturbation_amplitude = The perturbation amplitude for the NP Jacobian.
+// Jacobian_file_name = The name of the output file to which both Jacobians
+// should be written.
+//
+namespace {
+void test_synchronize_Jacobians(patch_system& ps,
+ int test_gfn, int NP_test_gfn,
+ fp perturbation_amplitude,
+ const char Jacobian_file_name[])
+{
+setup_sym_fn_xyz(ps, test_gfn, false);
+ps.synchronize_ghost_zones(test_fn_gfn, test_fn_gfn);
+ps.print_ghosted_gridfn(test_fn_copy_gfn, "test_fn_copy.dat");
+
+setup_sym_fn_xyz(ps, NP_test_gfn, false);
+
+FILE *fileptr = fopen(Jacobian_file_name, "w");
+if (fileptr == NULL)
+ then CCTK_VWarn(-1, __LINE__, __FILE__, CCTK_THORNSTRING,
+"test_synchronize_Jacobians(): can't open output plot file \"%s\"!",
+ Jacobian_file_name); /*NOTREACHED*/
+fprintf(fileptr, "# column 1 = x patch number\n");
+fprintf(fileptr, "# column 2 = x ghost_zone is_min()\n");
+fprintf(fileptr, "# column 3 = x ghost_zone is_rho()\n");
+fprintf(fileptr, "# column 4 = x_iperp\n");
+fprintf(fileptr, "# column 5 = x_ipar\n");
+fprintf(fileptr, "# column 6 = x_irho\n");
+fprintf(fileptr, "# column 7 = x_isigma\n");
+fprintf(fileptr, "# column 8 = y patch number\n");
+fprintf(fileptr, "# column 9 = y ghost_zone is_min()\n");
+fprintf(fileptr, "# column 10 = y ghost_zone is_rho()\n");
+fprintf(fileptr, "# column 11 = y_iperp\n");
+fprintf(fileptr, "# column 12 = y_ipar\n");
+fprintf(fileptr, "# column 13 = y_irho\n");
+fprintf(fileptr, "# column 14 = y_isigma\n");
+fprintf(fileptr, "# column 15 = Jacobian\n");
+fprintf(fileptr, "# column 16 = NP_Jacobian\n");
+fprintf(fileptr, "# column 17 = Jacobian error\n");
+
+ //*** for each patch p and ghost zone pgz
+ for (int pn = 0 ; pn < ps.N_patches() ; ++pn)
+ {
+ patch& p = ps.ith_patch(pn);
+
+ // n.b. these loops must use _int_ variables for the loop
+ // to terminate!
+ for (int want_min = false ; want_min <= true ; ++want_min)
+ {
+ for (int want_rho = false ; want_rho <= true ; ++want_rho)
+ {
+ const patch_edge& pe = p.minmax_ang_patch_edge(want_min, want_rho);
+ ghost_zone& pgz = p.minmax_ang_ghost_zone(want_min, want_rho);
+
+ pgz.compute_Jacobian(test_gfn, test_gfn,
+ true, true, true); // want *all* of ghost zone
+ const int Jacobian_y_min_ipar_m = pgz.Jacobian_y_min_ipar_m();
+ const int Jacobian_y_max_ipar_m = pgz.Jacobian_y_max_ipar_m();
+
+ //*** for each point x in (p,pgz)
+ for (int x_iperp = pgz.min_iperp() ;
+ x_iperp <= pgz.max_iperp() ;
+ ++x_iperp)
+ {
+ // FIXME FIXME -- this includes corners when it shouldn't
+ for (int x_ipar = pgz.ghost_zone_min_ipar() ;
+ x_ipar <= pgz.ghost_zone_max_ipar() ;
+ ++x_ipar)
+ {
+ const int x_irho = pe. irho_of_iperp_ipar(x_iperp, x_ipar);
+ const int x_isigma = pe.isigma_of_iperp_ipar(x_iperp, x_ipar);
+
+ patch& q = pgz.Jacobian_y_patch();
+ const patch_edge& qe = pgz.Jacobian_y_edge();
+ const int Jacobian_y_iperp = pgz.Jacobian_y_iperp(x_iperp);
+ const int Jacobian_y_ipar_posn
+ = pgz.Jacobian_y_ipar_posn(x_iperp, x_ipar);
+
+ //*** for each point y in gz.Jacobian_patch()
+ for (int y_irho = q.min_irho() ; y_irho <= q.max_irho() ; ++y_irho)
+ {
+ for (int y_isigma = q.min_isigma() ;
+ y_isigma <= q.max_isigma() ;
+ ++y_isigma)
+ {
+ // compute the NP Jacobian
+ const fp save_y_gridfn
+ = q.ghosted_gridfn(NP_test_gfn, y_irho,y_isigma);
+ q.ghosted_gridfn(NP_test_gfn, y_irho,y_isigma)
+ += perturbation_amplitude;
+
+ ps.synchronize_ghost_zones(NP_test_gfn, NP_test_gfn);
+ const fp NP_Jacobian
+ = ( p.ghosted_gridfn(NP_test_gfn, x_irho,x_isigma)
+ - p.ghosted_gridfn( test_gfn, x_irho,x_isigma) )
+ / perturbation_amplitude;
+ q.ghosted_gridfn(NP_test_gfn, y_irho,y_isigma) = save_y_gridfn;
+
+ // compute the query Jacobian
+ const int y_iperp = qe.iperp_of_irho_isigma(y_irho,y_isigma);
+ const int y_ipar = qe. ipar_of_irho_isigma(y_irho,y_isigma);
+ const int y_ipar_m = y_ipar - Jacobian_y_ipar_posn;
+ const bool m_in_molecule
+ = (y_iperp == Jacobian_y_iperp)
+ && (y_ipar_m >= Jacobian_y_min_ipar_m)
+ && (y_ipar_m <= Jacobian_y_max_ipar_m);
+ const fp Jacobian = pgz.Jacobian(x_iperp, x_ipar, y_ipar_m);
+
+ // print the results
+ if (m_in_molecule || (Jacobian != NP_Jacobian))
+ then fprintf(fileptr,
+"%d %d %d\t%d %d\t%d %d\t%d %d %d\t%d %d\t%d %d\t%.10g\t%.10g\t%e\n",
+ p.patch_number(), pe.is_min(), pe.is_rho(),
+ x_iperp, x_ipar, x_irho, x_isigma,
+ q.patch_number(), qe.is_min(), qe.is_rho(),
+ y_iperp, y_ipar, y_irho, y_isigma,
+ double(Jacobian), double(NP_Jacobian),
+ double(Jacobian-NP_Jacobian));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ }
+
+fclose(fileptr);
+}
+ }
+
+//******************************************************************************
+//******************************************************************************
+//******************************************************************************
+
+//
// This function sets up the ghosted test function for the gridfn and
// synchronize tests, symmetrizing the test function to match the
// symmetry of the patch system.