Streamer fluid modeling - An overview of ARCoS  1.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
poisson.c
Go to the documentation of this file.
1 
5 #include <stdlib.h>
6 #include <stdio.h>
7 #include <math.h>
8 
9 #include "cdr.h"
10 #include "cstream.h"
11 #include "fishpack.h"
12 #include "grid.h"
13 #include "interpol2.h"
14 #include "mapper.h"
15 #include "parameters.h"
16 #include "poisson.h"
17 #include "proto.h"
18 #include "rz_array.h"
19 #include "species.h"
20 
21 static void get_bound_cond (pois_grid_t *grid, pois_problem_t *prob,
22  int *r_bound_cond, int *z_bound_cond,
23  double lambda);
24 static int needs_refinement (pois_grid_t *grid, int ir, int iz,
25  double threshold);
26 static int refine_in (pois_grid_t *grid, int cr0, int cz0, int cr1, int cz1);
27 
30 decl_mapper_funcs(etheta);
31 decl_mapper_funcs(charge);
37 /* Global variables for the computations of inhomogeneous fields:
38  * initialized in pois_inhom_init. */
39 
47 double pois_inhom_L;
48 double pois_inhom_z;
49 double pois_inhom_dphi;
60 extern double E_x, E_y, E_z;
61 
62 static double inhom_phi_term (double r, double z, double b);
63 static double inhom_e_term (double r, double z, double b);
64 static double inhom_er_term (double r, double z, double b);
65 static double inhom_ez_term (double r, double z, double b);
81 
83 
85 void
86 pois_init (void)
87 {
88  if (pois_inhom) {
89  pois_inhom_init ();
90  }
91  else {
93  }
95 
96  pois_electrostatic = xmalloc (sizeof (pois_problem_t));
97 
98  pois_electrostatic->max_level = pois_max_level;
99  pois_electrostatic->extra_levels = extra_pois_levels;
100  pois_electrostatic->max_error = pois_max_error;
101 
102  pois_electrostatic->bnd_right = pois_bnd_right;
103  pois_electrostatic->bnd_top = pois_bnd_top;
104  pois_electrostatic->bnd_bottom = pois_bnd_bottom;
105 }
106 
109 pois_new_a (int r0, int z0, int r1, int z1)
110 {
111  pois_grid_t *grid;
112 
113  grid = pois_new_3d_a (r0, z0, r1, z1, 1);
114 
115  return grid;
116 }
117 
123 pois_new_3d_a (int r0, int z0, int r1, int z1, int ntheta)
124 {
125  rz_array_t *phi, *charge, *error;
126  pois_grid_t *grid;
127 
128  debug (2, "pois_new_a (r0 = %d, z0 = %d, r1 = %d, z1 = %d)\n",
129  r0, z0, r1, z1);
130 
131  phi = rz_new_3d_a (r0, z0, r1, z1, ntheta);
132  error = rz_new_3d_a (r0, z0, r1, z1, ntheta);
133 
134 #ifdef F_PHI_SAME_AS_CHARGE
135  charge = phi;
136 #else
137  charge = rz_new_3d_a (r0, z0, r1, z1, ntheta);
138 #endif /* F_PHI_SAME_AS_CHARGE */
139 
140  grid = (pois_grid_t *) xmalloc (sizeof (pois_grid_t));
141 
142  grid->r0 = r0;
143  grid->r1 = r1;
144  grid->z0 = z0;
145  grid->z1 = z1;
146  grid->ntheta = ntheta;
147 
148  grid->phi = phi;
149  grid->charge = charge;
150  grid->error = error;
151 
152  /* By default, the array does not have any external boundary. */
153  grid->ext_bound = BND_NONE;
154 
155  /* Initially, a grid does not have any relatives. */
156  init_leaf (grid);
157 
158  return grid;
159 }
160 
162 void
164 {
165  debug (3, "pois_free (...)\n");
166 
167  /* The decission of whether to use the same memory for the charge and
168  * the potential can be made elsewhere.
169  */
170  if (grid->phi != grid->charge)
171  rz_free (grid->charge);
172  rz_free (grid->phi);
173  rz_free (grid->error);
174 
175  free (grid);
176 }
177 
179 void
181 {
182  pois_grid_t *leaf;
183 
184  debug (3, "pois_free_r (" grid_printf_str ")\n", grid_printf_args (grid));
185 
186  free_childs (grid, leaf, pois_free_r);
187 
188  pois_free (grid);
189 }
190 
196 pois_new_glob_a (int r0, int z0, int r1, int z1, int level)
197 {
198  debug (3, "pois_new_glob_a (%d, %d, %d, %d)\n", r0, r1, z0, z1);
199  pois_grid_t *grid;
200 
201  if (level >= 0) {
202  grid = pois_new_a (r0 << level, z0 << level,
203  r1 << level, z1 << level);
204  } else {
205  level = -level;
206  grid = pois_new_a (r0 >> level, z0 >> level,
207  r1 >> level, z1 >> level);
208  }
209  return grid;
210 }
211 
217 pois_init_tree_a (int r0, int z0, int r1, int z1)
218 {
219  pois_grid_t *coarsest, *sub_coarsest;
220  int level;
221 
222  debug (3, "pois_init_tree_a (%d, %d, %d, %d)\n", r0, z0, r1, z1);
223 
224  level = -extra_pois_levels;
225 
226  coarsest = pois_new_glob_a (r0, z0, r1, z1, level);
227  coarsest->ext_bound = BND_MASK_ALL;
228  coarsest->level = level;
229 
230  sub_coarsest = pois_new_glob_a (r0, z0, r1, z1, level + 1);
231 
232  add_child (coarsest, sub_coarsest);
233  grid_inherit_ext_bound ((grid_t *) sub_coarsest);
234 
235  return coarsest;
236 }
237 
243 REAL*
244 pois_boundary_a (pois_grid_t *grid, int boundary)
245 {
246  pois_grid_t *parent;
247 
248  /* Forget the 0s, they are there to shut up the compiler. */
249  int stride = 0, ortho_stride = 0, icells, invert, n;
250  int rb, zb;
251  double interp_array[3][3] = {{-4.0, 1.0, 18.0},
252  {-2.0, 78.0, 14.0},
253  {-6.0, -7.0, 4.0}};
254 
255  const double prefactor = 1 / 96.0;
256  REAL *bnd, *p, *lstart;
257 
258  debug (3, "pois_boundary_a (..., %d)\n", boundary);
259 
260  parent = grid->parent;
261 
262  /* First we check if the boundary is in r or in z. */
263  if (boundary & BND_AT_Z) {
264  icells = grid->r1 - grid->r0;
265  zb = 1; rb = 0;
266  if (NULL != parent) {
267  stride = parent->phi->strides[R_INDX];
268  ortho_stride = parent->phi->strides[Z_INDX];
269  }
270  } else {
271  zb = 0; rb = 1;
272  icells = grid->z1 - grid->z0;
273  if (NULL != parent) {
274  stride = parent->phi->strides[Z_INDX];
275  ortho_stride = parent->phi->strides[R_INDX];
276  }
277  }
278 
279  debug (3, " grid->ext_bound = %d\n", grid->ext_bound);
280 
281  if (grid->ext_bound & BND_MASK (boundary)) {
282  /* If the boundary is external, we apply homogeneous Dirichlet/Neumann. */
283  bnd = (REAL *) xcalloc (sizeof (REAL), icells);
284  debug (3, "pois_boundary_a (...) -> [0.0] * %d\n", icells);
285 
286  assert (grid->r1 != 0);
287  return bnd;
288  } else {
289  bnd = (REAL *) xmalloc (sizeof (REAL) * icells);
290  }
291  /* If the grid is root it should have returned in the previous if */
292  assert (NULL != parent);
293 
294  /* Now we check if the boundary is at {r,z} minimum or {r,z} maximum */
295  if (boundary & BND_MAX) {
296  lstart = RZP (parent->phi,
297  (grid->r1 >> 1) - 1 + rb,
298  (grid->z1 >> 1) - 1 + zb);
299  stride = -stride;
300  ortho_stride = -ortho_stride;
301  invert = TRUE;
302  } else {
303  lstart = RZP (parent->phi, (grid->r0 >> 1) - rb, (grid->z0 >> 1) - zb);
304  invert = FALSE;
305  }
306 
307  for (p = lstart, n = 0; n < icells; p += stride, n += 2) {
308  /* p points to the cell in the parent grid and p + stride points to
309  an adjacent cell. */
310  double s = 0.0, s2 = 0.0;
311  int i, j;
312  for (i = -1; i <= 1; i++) {
313  for (j = -1; j <= 1; j++) {
314  s += *(p + i * stride + j * ortho_stride) * interp_array[i + 1][j + 1];
315  s2 += *(p - i * stride + j * ortho_stride) * interp_array[i + 1][j + 1];
316  }
317  }
318  if (!invert) {
319  bnd[n] = prefactor * s;
320  if (n < icells - 1) bnd[n + 1] = prefactor * s2;
321  } else {
322  bnd[icells - n - 1] = prefactor * s;
323  if (n < icells - 1) bnd[icells - n - 2] = prefactor * s2;
324  }
325  }
326  return bnd;
327 }
328 
333 void
335  double lambda, double s)
336 {
337  REAL *boundaries[4];
338  int i, z_bound_cond, r_bound_cond;
339  double rmin, rmax, zmin, zmax;
340 
341  debug (3, "pois_solve_grid (..., lambda = %f, s = %f)\n", lambda, s);
342 
343  for (i = 0; i < 4; i++) {
344  boundaries[i] = pois_boundary_a (grid, i);
345  debug (3, "boundaries[%d] = %p\n", i, boundaries[i]);
346  }
347 
348 #ifndef F_PHI_SAME_AS_CHARGE
349  rz_copy (grid->charge, grid->r0, grid->z0,
350  grid->phi, grid->r0, grid->z0,
351  grid->r1 - grid->r0, grid->z1 - grid->z0);
352 #endif
353 
354  rmin = grid->r0 * dr[grid->level];
355  rmax = grid->r1 * dr[grid->level];
356  zmin = grid->z0 * dz[grid->level];
357  zmax = grid->z1 * dz[grid->level];
358 
359  debug (3, "HSTCYL/HSTCRT in a grid %d x %d\n", grid->r1 - grid->r0,
360  grid->z1 - grid->z0);
361 
362  get_bound_cond (grid, prob, &r_bound_cond, &z_bound_cond, lambda);
363 
364 #ifndef TRUE2D
365  fish_hstcyl (rmin, rmax, grid->r1 - grid->r0,
366  r_bound_cond, boundaries[BND_LEFT], boundaries[BND_RIGHT],
367  zmin, zmax, grid->z1 - grid->z0,
368  z_bound_cond, boundaries[BND_BOTTOM], boundaries[BND_TOP],
369  lambda, s,
370  RZP (grid->phi, grid->r0, grid->z0),
371  grid->phi->strides[Z_INDX]);
372 #else
373  fish_hstcrt (rmin, rmax, grid->r1 - grid->r0,
374  r_bound_cond, boundaries[BND_LEFT], boundaries[BND_RIGHT],
375  zmin, zmax, grid->z1 - grid->z0,
376  z_bound_cond, boundaries[BND_BOTTOM], boundaries[BND_TOP],
377  lambda,
378  RZP (grid->phi, grid->r0, grid->z0),
379  grid->phi->strides[Z_INDX]);
380 #endif
381  debug (3, "Finished HSTCYL/HSTCRT in a grid %d x %d\n", grid->r1 - grid->r0,
382  grid->z1 - grid->z0);
383 
384  pois_set_phi_boundaries (grid, boundaries,
385  (grid->ext_bound & BND_MASK (BND_LEFT))
386  && 0. == lambda,
387 
388  prob->bnd_right == BND_CND_HNEUMANN
389  && (grid->ext_bound & BND_MASK (BND_RIGHT)),
390 
392  && (grid->ext_bound & BND_MASK (BND_BOTTOM)),
393 
394  prob->bnd_top == BND_CND_HNEUMANN
395  && (grid->ext_bound & BND_MASK (BND_TOP)));
396 
397  for (i = 0; i < 4; i++) {
398  debug (3, "boundaries[%d] = %p\n", i, boundaries[i]);
399  free (boundaries[i]);
400  }
401  debug (3, " <- pos_solve_grid (...)\n");
402 }
403 
411 static void
413  int *r_bound_cond, int *z_bound_cond, double lambda)
414 {
415  static int right_inside[] = {FISH_UNS_DIR, FISH_NEU_DIR, FISH_DIR_DIR};
416  static int right_ext_neu[] = {FISH_UNS_NEU, FISH_NEU_NEU, FISH_DIR_NEU};
417  static int *right_ext_dir = right_inside;
418  static int fish_order[4] = { FISH_DIR_DIR, FISH_DIR_NEU,
419  FISH_NEU_DIR, FISH_NEU_NEU};
420 
421  int bottom, top;
422  int *right_sel;
423 
424  if ((grid->ext_bound & BND_MASK (BND_TOP))
425  && prob->bnd_top == BND_CND_HNEUMANN)
426  top = 1;
427  else top = 0;
428 
429  if ((grid->ext_bound & BND_MASK (BND_BOTTOM))
430  && prob->bnd_bottom == BND_CND_HNEUMANN)
431  bottom = 1;
432  else bottom = 0;
433 
434  *z_bound_cond = fish_order[(bottom << 1) + top];
435 
436  if ((grid->ext_bound & BND_MASK (BND_RIGHT))) {
437  if (prob->bnd_right == BND_CND_HNEUMANN)
438  right_sel = right_ext_neu;
439  else
440  right_sel = right_ext_dir;
441  } else {
442  right_sel = right_inside;
443  }
444 
445 #ifndef TRUE2D
446  *r_bound_cond = ((grid->ext_bound & BND_MASK (BND_LEFT)) && 0. == lambda)?
447  right_sel[0]: right_sel[2];
448 #else
449  *r_bound_cond = ((grid->ext_bound & BND_MASK (BND_LEFT))?
450  right_sel[1]: right_sel[2]);
451 #endif
452 
453 }
454 
464 void
465 pois_set_phi_boundaries (pois_grid_t *grid, REAL *boundaries[],
466  int left_neu, int right_neu, int bottom_neu,
467  int top_neu)
468 {
469  int i;
470 
471  debug (3, "pois_set_phi_boundaries (...)\n");
472 
473  if ((grid->ext_bound & BND_MASK(BND_BOTTOM)) && bottom_neu) {
474  for (i = grid->r0; i < grid->r1; i++) {
475  RZ (grid->phi, i, grid->z0 - 1) = RZ (grid->phi, i, grid->z0);
476  }
477  } else {
478  for (i = grid->r0; i < grid->r1; i++) {
479  RZ (grid->phi, i, grid->z0 - 1) =
480  2 * boundaries[BND_BOTTOM][i - grid->r0] - RZ (grid->phi, i, grid->z0);
481  }
482  }
483 
484  if ((grid->ext_bound & BND_MASK(BND_TOP)) && top_neu) {
485  for (i = grid->r0; i < grid->r1; i++) {
486  RZ (grid->phi, i, grid->z1) = RZ (grid->phi, i, grid->z1 - 1);
487  }
488  } else {
489  for (i = grid->r0; i < grid->r1; i++) {
490  RZ (grid->phi, i, grid->z1) = 2 * boundaries[BND_TOP][i - grid->r0]
491  - RZ(grid->phi, i, grid->z1 - 1);
492  }
493  }
494 
495  if (left_neu) {
496  for (i = grid->z0; i < grid->z1; i++) {
497  RZ (grid->phi, grid->r0 - 1, i) = RZ(grid->phi, grid->r0, i);
498  }
499  } else {
500  for (i = grid->z0; i < grid->z1; i++) {
501  RZ(grid->phi, grid->r0 - 1, i) = 2 * boundaries[BND_LEFT][i - grid->z0]
502  - RZ(grid->phi, grid->r0, i);
503  }
504  }
505 
506  if (right_neu) {
507  for (i = grid->z0; i < grid->z1; i++) {
508  RZ (grid->phi, grid->r1, i) = RZ(grid->phi, grid->r1 - 1, i);
509  }
510  } else {
511  for (i = grid->z0; i < grid->z1; i++) {
512  RZ(grid->phi, grid->r1, i) = 2 * boundaries[BND_RIGHT][i - grid->z0]
513  - RZ(grid->phi, grid->r1 - 1, i);
514  }
515  }
516 
517  /* This is quite nightmarish. Think about rewritting. */
518  if ((grid->ext_bound & BND_MASK(BND_RIGHT)) && right_neu) {
519  RZ(grid->phi, grid->r1, grid->z0 - 1) = RZ(grid->phi, grid->r1 - 1,
520  grid->z0 - 1);
521  RZ(grid->phi, grid->r1, grid->z1) = RZ(grid->phi, grid->r1 - 1,
522  grid->z1);
523  } else {
524  RZ(grid->phi, grid->r1, grid->z0 - 1) =
525  RZ(grid->phi, grid->r1 - 1, grid->z0 - 1)
526  + RZ(grid->phi, grid->r1, grid->z0)
527  - 0.5 * (RZ(grid->phi, grid->r1 - 2, grid->z0 - 1)
528  + RZ(grid->phi, grid->r1, grid->z0 + 1));
529 
530  RZ(grid->phi, grid->r1, grid->z1) =
531  RZ(grid->phi, grid->r1 - 1, grid->z1)
532  + RZ(grid->phi, grid->r1, grid->z1 - 1)
533  - 0.5 * (RZ(grid->phi, grid->r1 - 2, grid->z1)
534  + RZ(grid->phi, grid->r1, grid->z1 - 2));
535  }
536 
537  if ((grid->ext_bound & BND_MASK(BND_LEFT)) && left_neu) {
538  RZ(grid->phi, grid->r0 - 1, grid->z0 - 1) = RZ(grid->phi, grid->r0,
539  grid->z0 - 1);
540  RZ(grid->phi, grid->r0 - 1, grid->z1) = RZ(grid->phi, grid->r0,
541  grid->z1);
542  } else {
543  RZ(grid->phi, grid->r0 - 1, grid->z0 - 1) =
544  RZ(grid->phi, grid->r0, grid->z0 - 1)
545  + RZ(grid->phi, grid->r0 - 1, grid->z0)
546  - 0.5 * (RZ(grid->phi, grid->r0 + 1, grid->z0 - 1)
547  + RZ(grid->phi, grid->r0 - 1, grid->z0 + 1));
548 
549  RZ(grid->phi, grid->r0 - 1, grid->z1) =
550  RZ(grid->phi, grid->r0, grid->z1)
551  + RZ(grid->phi, grid->r0 - 1, grid->z1 - 1)
552  - 0.5 * (RZ(grid->phi, grid->r0 + 1, grid->z1)
553  + RZ(grid->phi, grid->r0 - 1, grid->z1 - 2));
554  }
555 }
556 
560 void
562 {
563  pois_grid_t *parent;
564  interpol_t *interpol;
565  int pr, pz;
566 
567  debug (3, "pois_set_error(...)\n");
568 
569  parent = grid->parent;
570  assert (NULL != parent);
571 
572  interpol = interpol_new_a (2.0, 2.0, &interpol_wackers);
573 
574  iter_grid_parent (grid, pr, pz) {
575  int i, j;
576 
577  interpol_set_stencil_at ((grid_t *) grid, interpol,
578  pr * 2.0 + 1, pz * 2.0 + 1,
579  parent->phi, pr, pz, 0);
580  for (i = 0; i < 2; i++)
581  for (j = 0; j < 2; j++) {
582  int cr, cz;
583  double v;
584 
585  cr = (pr << 1) + i;
586  cz = (pz << 1) + j;
587 
588  v = interpol_apply (interpol, (double) cr + 0.5, (double) cz + 0.5);
589 
590  /* The error will only be used as its abs value. Therefore
591  we calculate it here and forever. */
592  RZ (grid->error, cr, cz) = fabs (RZ (grid->phi, cr, cz) - v);
593 
594  }
595  }
596  interpol_free (interpol);
597 }
598 
605 int
606 pois_refine (pois_grid_t *grid, double threshold)
607 {
608  int ir, iz;
609  int zmin, zmax, rmin, rmax;
610  /* Be careful: cz1 and cr1 are inclusive: when the child is actually
611  created, one has to increse them by 1. */
612  int cr0, cr1, cz0, cz1;
613  int all_ok = TRUE;
614 
615  int tainted_line = FALSE;
616 
617  debug (3, "pois_refine(...)\n");
618 
619  /* Initially we set values out of the grid, so the first comparisons
620  * always change the values.
621  */
622  cr0 = grid->r1; cr1 = grid->r0 - 1;
623  cz0 = grid->z1; cz1 = grid->z0 - 1;
624 
625  /* The boundary can only coincide with the parent's boundary if this
626  * is an external boundary.
627  */
628  rmin = (grid->ext_bound & BND_MASK(BND_LEFT))? grid->r0: (grid->r0 + 1);
629  rmax = (grid->ext_bound & BND_MASK(BND_RIGHT))? grid->r1: (grid->r1 - 1);
630  zmin = (grid->ext_bound & BND_MASK(BND_BOTTOM))? grid->z0: (grid->z0 + 1);
631  zmax = (grid->ext_bound & BND_MASK(BND_TOP))? grid->z1: (grid->z1 - 1);
632 
633  for (iz = zmin; iz < zmax && all_ok; iz++) {
634  tainted_line = FALSE;
635  for (ir = rmin; ir < rmax; ir++) {
636  if (needs_refinement (grid, ir, iz, threshold)) {
637  tainted_line = TRUE;
638  if (ir < cr0) cr0 = ir;
639  if (ir > cr1) cr1 = ir;
640  }
641  }
642  if (tainted_line) {
643  if (iz < cz0) cz0 = iz;
644  if (iz > cz1) cz1 = iz;
645  } else if (cr1 >= cr0 && cz1 >= cz0) {
646  all_ok = all_ok && refine_in (grid, cr0, cz0, cr1, cz1);
647  cr0 = grid->r1; cr1 = grid->r0 - 1;
648  cz0 = grid->z1; cz1 = grid->z0 - 1;
649  }
650  }
651 
652  if (cr1 >= cr0 && cz1 >= cz0) {
653  all_ok = all_ok && refine_in (grid, cr0, cz0, cr1, cz1);
654  }
655 
656  /* If there was some error with some refinement, we delete the created
657  * sub-grids and go back to the caller, which has to increase the refinement
658  * threshold.
659  */
660  if (!all_ok) {
661  pois_grid_t *leaf;
662  free_childs (grid, leaf, pois_free_r);
663  set_childless (grid);
664  }
665  return all_ok;
666 }
667 
668 #define REFINE_IN_MAX_WARN_CNT 20;
669 
675 static int
676 refine_in (pois_grid_t *grid, int cr0, int cz0, int cr1, int cz1)
677 {
678  pois_grid_t *child;
679  int nr0, nr1, nz0, nz1;
680  static int warn_cnt = REFINE_IN_MAX_WARN_CNT;
681 
682  nr0 = cr0 << 1;
683  nz0 = cz0 << 1;
684  nr1 = (++cr1) << 1;
685  nz1 = (++cz1) << 1;
686 
687  if ((nr1 - nr0) > FISH_MAX_GRIDPOINTS ||
688  (nz1 - nz0) > FISH_MAX_GRIDPOINTS) {
689  if (warn_cnt > 0) {
690  warning ("FISHPACK limit exceeded. Not refining grid "
691  grid_printf_str ".\n", nr0, nz0, nr1, nz1, grid->level + 1);
692  warn_cnt --;
693  }
694  if (warn_cnt == 0) {
695  warning ("No more warnings about FISHPACK limit.\n");
696  warn_cnt --;
697  }
698  return FALSE;
699  }
700 
701  child = pois_new_a (nr0, nz0, nr1, nz1);
702 
703  add_child (grid, child);
704  grid_inherit_ext_bound ((grid_t *) child);
705  debug (3, "new child created {r0 = %d, z0 = %d, r1 = %d, z1 = %d, "
706  "level = %d}\n", child->r0, child->z0, child->r1, child->z1,
707  child->level);
708 
709  return TRUE;
710 }
711 
716 void
717 pois_error_measures (pois_grid_t *grid, double *L1, double *L2, double *Lmax)
718 {
719  int ir, iz, i;
720  double err;
721  *L2 = 0.0;
722  *L1 = 0.0;
723  *Lmax = 0.0;
724  i = 0;
725 
726  iter_grid (grid, ir, iz) {
727  i++;
728  err = RZ (grid->error, ir, iz);
729  if (err > *Lmax) *Lmax = err;
730  *L1 += err;
731  *L2 += err * err;
732  }
733 
734  *L1 /= i;
735  *L2 = sqrt (*L2 / i);
736 
737 }
738 
742 void
744 {
745  double L1, L2, Lmax;
746  pois_grid_t *child;
747 
748  pois_error_measures (grid, &L1, &L2, &Lmax);
749 
750  fprintf (fp, "%d %g %g %g %g %g\n", grid->level, dr[grid->level],
751  dz[grid->level], L1, L2, Lmax);
752 
753  iter_childs (grid, child) {
754  pois_write_error_r (child, fp);
755  }
756 }
757 
762 pois_grid_t **
764 {
765  /* Call to the generic Poisson/Helmholtz solver */
766  return pois_gen_solve_a (cdr, prob, e_mappers, 0.0);
767 }
768 
776 pois_grid_t **
778  mapper_t **mappers, double es)
779 {
780  cdr_grid_t *tree;
781  pois_grid_t **pois_modes;
782  int mode;
783 
784  pois_modes = (pois_grid_t**) xmalloc (sizeof(pois_grid_t*) * max_ntheta);
785  assert (0 == cdr->level);
786  tree = cdr_add_coarser_grids_a (cdr, prob->extra_levels);
787 
788  /* This is the high-level parallelizable loop! */
789 #pragma omp parallel
790  {
791 #pragma omp for schedule(dynamic)
792  for (mode = 0; mode < max_ntheta; mode++) {
793  pois_modes[mode] = pois_solve_mode (tree, cdr, prob, mode, es);
794 
795  if (pois_inhom && es == 0.0 && mode == 0) {
796  /* Add the inhomogeneous laplacian potential to phi.
797  * It has only to be added to the zero mode.
798  */
799  double q_factor;
800  q_factor = pois_inhom_q_factor (pois_modes[0]);
801 
802  /* Was:
803  pois_add_inhom_phi_r (pois_modes[0], q_factor);
804  */
805  pois_add_inhom_phi_r (pois_modes[0], -q_factor);
806  }
807 
808  /* For the interpolation, we require an extra buffer cell
809  * in some boundaries and we check for overflows inside the
810  * mapper methods.
811  */
812  map_trees_r (mappers, (grid_t*) pois_modes[mode], (grid_t*) cdr,
813  mode, FALSE, TRUE, FALSE,
814  /*s_buf = */ 2,
815  /*t_buf = */ 4);
816  map_trees_r (mappers, (grid_t*) pois_modes[mode], (grid_t*) cdr,
817  mode, TRUE, FALSE, TRUE,
818  /*s_buf = */ 1,
819  /*t_buf = */ 2);
820  }
821  }
823 
824  return pois_modes;
825 }
826 
835 pois_grid_t *
837  int mode, double es)
838 {
839  pois_grid_t *pois;
840 
842 
843  /* Solves the coarsest Poisson grid. */
844  /* Changed Wed Mar 19 13:50:23 2008: was s_buf = 1. */
845  map_trees_r (charge_mappers, (grid_t *) tree, (grid_t *) pois,
846  mode, TRUE, TRUE, FALSE, 0, 2);
847  pois_solve_grid (pois, prob, -w2k[mode], es);
848 
849  /* Wed May 14 11:00:30 2008:
850  * I divide pois_max_error by abs(wk[mode]) because in the calculation
851  * of e_theta, the errors get multiplied by wk[mode]. Hence if we
852  * want to get similar errors in all modes, we have to remove it from the
853  * threshold. The 1 is because wk[0] = 0, but we do not want to have
854  * a \inf threshold.
855  */
856  pois_solve_r (pois->first_child, tree, prob, mode, es,
857  prob->max_error / (1 + abs(wk[mode])));
858 
859  return pois;
860 }
861 
862 #define POIS_SOLVE_R_MAX_WARN 50
863 
865 void
867  int mode, double es, double threshold)
868 {
869  pois_grid_t *child;
870  int succeeded = FALSE;
871  static int warn_cnt = POIS_SOLVE_R_MAX_WARN;
872 
873  /* Changed Wed Mar 19 13:51:00 2008: was s_buf = 1 */
874  map_grid_r (charge_mappers, (grid_t *) cdr, (grid_t *) pois,
875  mode, TRUE, TRUE, FALSE, 0, 2);
876  debug(3, "w2k[mode = %d] = %f\n", mode, w2k[mode]);
877 
878  pois_solve_grid (pois, prob, -w2k[mode], es);
879 
880  if (pois->level >= prob->max_level) return;
881 
882  pois_set_error (pois);
883 
884  while (!succeeded) {
885  succeeded = pois_refine (pois, threshold);
886 
887  if (!succeeded) {
888  threshold *= 2;
889  if (warn_cnt > 0) {
890  warning ("Poisson error threshold was too small: trying %g.\
891  Consider increasing pois_max_error\n",
892  threshold);
893  if (warn_cnt >= 0) warn_cnt --;
894  }
895  }
896  }
897  iter_childs (pois, child) {
898  pois_solve_r (child, cdr, prob, mode, es, threshold);
899  }
900 }
901 
908 static int
909 needs_refinement (pois_grid_t *grid, int ir, int iz, double threshold)
910 {
911  int i, j;
912  int r = FALSE;
913  int irmin, irmax, izmin, izmax;
914 
915  irmin = ir > grid->r0 + 3? ir - 1: grid->r0;
916  irmax = ir < grid->r1 - 4? ir + 1: grid->r1 - 1;
917  izmin = iz > grid->z0 + 3? iz - 1: grid->z0;
918  izmax = iz < grid->z1 - 4? iz + 1: grid->z1 - 1;
919 
920  for (i = irmin; i <= irmax && !r; i++)
921  for (j = izmin; j <= izmax; j++)
922  if (RZ(grid->error, i, j) > threshold) {
923  r = TRUE;
924  break;
925  }
926 
927  return r;
928 }
929 
930 /*****************************************************************************
931  * Functions for the implemetation of a needle-plate discharge. *
932  * The method used here is that of the "floating charge": *
933  * A charge is located at pois_inhom_z, which is used to keep the potential *
934  * at L_z constant. *
935  ****************************************************************************/
936 
938 void
940 {
941  /* The domain of solution of the Poisson equation will be different
942  * from that of the CDR equation. The difference between them is
943  * given by the parameter needle_length, but has to be rounded
944  * to a multiple of the grid size at level 0.
945  */
947  + (int) nearbyint (needle_length / dz[0]));
949 
952 
953 }
954 
955 /* We use the following functions to calculate the fields and potential
956  * created by a unit charge located at (r = 0, z = b).
957  * These are created by the method of mirror charges, with a total of
958  * pois_inhom_reflections charges.
959  */
960 
961 /* Single term of phi. */
962 static double
963 inhom_phi_term (double r, double z, double b)
964 {
965  double insqrt;
966 
967  insqrt = (SQ(z - b) + SQ(r));
968 
969  return invfourpi / sqrt (insqrt);
970 }
971 
973 static double
974 inhom_e_term (double r, double z, double b)
975 {
976  double insqrt;
977 
978  insqrt = (SQ(z - b) + SQ(r));
979  insqrt = insqrt * insqrt * insqrt;
980 
981  return invfourpi / sqrt (insqrt);
982 }
983 
985 static double
986 inhom_er_term (double r, double z, double b)
987 {
988  return r * inhom_e_term (r, z, b);
989 }
990 
992 static double
993 inhom_ez_term (double r, double z, double b)
994 {
995  return (z - b) * inhom_e_term (r, z, b);
996 }
997 
998 /* Since we have to sum over the same locations of the mirror charges
999  * but with different "field functions", we use the following macro.
1000  *
1001  * Note that using a single function for inhom_phi, inhom_er, and inhom_ez
1002  * would not be a good idea since they are evaluated at different points.
1003  * Passing that function a pointer to another function would have been somewhat
1004  * slower and, I think, not so readable.
1005  */
1006 #define sum_reflections(total_, field_, r_, z_) \
1007  do { \
1008  int i__; \
1009  total_ = (field_ (r_, z_, pois_inhom_z) - \
1010  field_ (r_, z_, -pois_inhom_z)); \
1011  \
1012  for (i__ = 2; i__ <= pois_inhom_reflections; i__ += 2) { \
1013  total_ += (field_ (r_, z_, pois_inhom_z + i__ * pois_inhom_L) + \
1014  field_ (r_, z_, pois_inhom_z - i__ * pois_inhom_L)); \
1015  \
1016  total_ -= (field_ (r_, z_, -pois_inhom_z + i__ * pois_inhom_L) + \
1017  field_ (r_, z_, -pois_inhom_z - i__ * pois_inhom_L)); \
1018  } \
1019  } while (0)
1020 
1024 double
1025 pois_inhom_phi (double r, double z)
1026 {
1027  double res;
1028 
1029  sum_reflections (res, inhom_phi_term, r, z);
1030 
1031  return res;
1032 }
1033 
1035 double
1036 pois_inhom_er (double r, double z)
1037 {
1038  double res;
1039 
1040  sum_reflections (res, inhom_er_term, r, z);
1041 
1042  return res;
1043 }
1044 
1046 double
1047 pois_inhom_ez (double r, double z)
1048 {
1049  double res;
1050 
1051  sum_reflections (res, inhom_ez_term, r, z);
1052 
1053  return res;
1054 }
1055 
1066 double
1068 {
1069  double u;
1070  /* Note that the signs preceding the numerical potentials are inverted since
1071  * in our notation, we use the opposite of the physical one, in order
1072  * to use the charge as the source of the Poisson equation.
1073  */
1074 
1075  if (pois_inhom_fixed_q != 0.0) {
1076  return pois_inhom_fixed_q_t;
1077  }
1078 
1079  /* Was:
1080  u = - E_z * (pois_inhom_L - L_z) + pois_phi_at (pois, 0.0, L_z, 0.0);
1081  */
1082 
1083  u = E_z * (L_z - pois_inhom_L) + pois_phi_at (pois, 0.0, L_z, 0.0);
1084 
1085  return -u / pois_inhom_dphi;
1086 }
1087 
1100 void
1102 {
1103  int ir, iz;
1104  pois_grid_t *child;
1105  double res;
1106 
1107  debug (2, "pois_add_inhom_phi_r (" grid_printf_str ", q = %f)\n",
1108  grid_printf_args(grid), q);
1109 
1110  /* Note that there is no factor grid->ntheta coming from thr FFT
1111  un-normalization. The reason is that actually q is sqrt(N) smaller
1112  than it has to be and later, in the inverse FFT we will multiply by
1113  sqrt(N). So everything is correct, I believe. */
1114  iter_grid_n (grid, ir, iz, 2) {
1115 
1116  sum_reflections (res, inhom_phi_term, r_at(ir, grid->level), z_at(iz, grid->level));
1117 
1118 
1119  RZ(grid->phi, ir, iz) += q * res;
1120  }
1121 
1122  iter_childs (grid, child) {
1123  pois_add_inhom_phi_r (child, q);
1124  }
1125 }
1126 
1127 /***************************************************************
1128  * Mapper functions for the components of the electric field. *
1129  * See mapper.h for an explanation of each of these methods. *
1130  ***************************************************************/
1131 
1133 void
1134 er_copy (mapper_t *mapper, grid_t *source, grid_t *target,
1135  int ir, int iz, int itheta)
1136 {
1137  cdr_grid_t *cdr;
1138  pois_grid_t *pois;
1139 
1140  cdr = (cdr_grid_t*) target;
1141  pois = (pois_grid_t*) source;
1142 
1143  if (ir < pois->r1)
1144  RZT (cdr->er, ir, iz, itheta) = ER_RZ (pois, ir, iz);
1145 }
1146 
1148 void
1149 ez_copy (mapper_t *mapper, grid_t *source, grid_t *target,
1150  int ir, int iz, int itheta)
1151 {
1152  cdr_grid_t *cdr;
1153  pois_grid_t *pois;
1154 
1155  cdr = (cdr_grid_t*) target;
1156  pois = (pois_grid_t*) source;
1157 
1158  if (iz < pois->z1)
1159  RZT (cdr->ez, ir, iz, itheta) = EZ_RZ (pois, ir, iz);
1160 }
1161 
1163 void
1164 etheta_copy (mapper_t *mapper, grid_t *source, grid_t *target,
1165  int ir, int iz, int itheta)
1166 {
1167  cdr_grid_t *cdr;
1168  pois_grid_t *pois;
1169 
1170  cdr = (cdr_grid_t*) target;
1171  pois = (pois_grid_t*) source;
1172 
1173  RZT (cdr->etheta, ir, iz, itheta) = RZ (pois->phi, ir, iz);
1174 }
1175 
1177 void
1178 er_coarsen (mapper_t *mapper, grid_t *source, grid_t *target,
1179  int ir, int iz, int itheta)
1180 {
1181  cdr_grid_t *cdr;
1182  pois_grid_t *pois;
1183  int level_diff, er_ir, er_iz;
1184 
1185  cdr = (cdr_grid_t*) target;
1186  pois = (pois_grid_t*) source;
1187 
1188  level_diff = pois->level - cdr->level;
1189 
1190  er_iz = (iz << level_diff) + (1 << (level_diff - 1));
1191  er_ir = ((ir + 1) << level_diff) - 1;
1192 
1193  if (grid_contains (source, er_ir, er_iz - 1, GRID_INSIDE) &&
1194  grid_contains (source, er_ir, er_iz, GRID_INSIDE)) {
1195 
1196  RZT (cdr->er, ir, iz, itheta) = 0.5 * (ER_RZ(pois, er_ir, er_iz) +
1197  ER_RZ(pois, er_ir, er_iz - 1));
1198  }
1199 }
1200 
1202 void
1203 ez_coarsen (mapper_t *mapper, grid_t *source, grid_t *target,
1204  int ir, int iz, int itheta)
1205 {
1206  cdr_grid_t *cdr;
1207  pois_grid_t *pois;
1208  int level_diff, ez_ir, ez_iz;
1209 
1210  cdr = (cdr_grid_t*) target;
1211  pois = (pois_grid_t*) source;
1212 
1213  level_diff = pois->level - cdr->level;
1214 
1215  ez_iz = ((iz + 1) << level_diff) - 1;
1216  ez_ir = (ir << level_diff) + (1 << (level_diff - 1));
1217 
1218  if (grid_contains (source, ez_ir - 1, ez_iz, GRID_INSIDE) &&
1219  grid_contains (source, ez_ir, ez_iz, GRID_INSIDE)) {
1220 
1221  RZT(cdr->ez, ir, iz, itheta) = 0.5 * (EZ_RZ(pois, ez_ir, ez_iz) +
1222  EZ_RZ(pois, ez_ir - 1, ez_iz));
1223  }
1224 }
1225 
1227 void
1228 etheta_coarsen (mapper_t *mapper, grid_t *source, grid_t *target,
1229  int ir, int iz, int itheta)
1230 {
1231  cdr_grid_t *cdr;
1232  pois_grid_t *pois;
1233  int level_diff, ez_ir, er_iz;
1234 
1235  cdr = (cdr_grid_t*) target;
1236  pois = (pois_grid_t*) source;
1237 
1238  level_diff = pois->level - cdr->level;
1239 
1240  er_iz = (iz << level_diff) + (1 << (level_diff - 1));
1241  ez_ir = (ir << level_diff) + (1 << (level_diff - 1));
1242 
1243  if (grid_contains (source, ez_ir, er_iz, GRID_INSIDE) &&
1244  grid_contains (source, ez_ir - 1, er_iz, GRID_INSIDE) &&
1245  grid_contains (source, ez_ir, er_iz - 1, GRID_INSIDE) &&
1246  grid_contains (source, ez_ir - 1, er_iz - 1, GRID_INSIDE)) {
1247 
1248  RZT (cdr->etheta, ir, iz, itheta) = 0.25 *
1249  (RZ (pois->phi, ez_ir, er_iz)
1250  + RZ (pois->phi, ez_ir - 1, er_iz)
1251  + RZ (pois->phi, ez_ir, er_iz - 1)
1252  + RZ (pois->phi, ez_ir - 1, er_iz - 1));
1253  }
1254 }
1255 
1257 int
1258 er_interpol_set (mapper_t *mapper, grid_t *source, interpol_t *interpol,
1259  int pr, int pz, int itheta)
1260 {
1261  pois_grid_t *pois;
1262 
1263  pois = (pois_grid_t*) source;
1264 
1265  /* When we set Neumann b.c. in one boundary and Dirichlet in the opposite
1266  * a larger-than-usual error appears in the boundaries because we are
1267  * matching potetntials in one side and fields in the other. The only way
1268  * I see of avoiding this is to forget about the extrapolated values of
1269  * the grids. But we still need those values on the external boundaries.
1270  */
1271  if (pr < pois->r0 || pz < pois->z0
1272  || pr > pois->r1 - 1 || pz > pois->z1)
1273  return FALSE;
1274 
1275  interpol_set_stencil (interpol,
1276  er_r_at (pr - 1, pois->level),
1277  er_z_at (pz - 1, pois->level),
1278  ER_RZ (pois, pr - 1, pz - 1),
1279  ER_RZ (pois, pr - 1, pz),
1280  ER_RZ (pois, pr, pz - 1),
1281  ER_RZ (pois, pr, pz));
1282 
1283  return TRUE;
1284 }
1285 
1287 int
1288 ez_interpol_set (mapper_t *mapper, grid_t *source, interpol_t *interpol,
1289  int pr, int pz, int itheta)
1290 {
1291  pois_grid_t *pois;
1292 
1293  pois = (pois_grid_t*) source;
1294 
1295  if (pr < pois->r0 || pz < pois->z0
1296  || pr > pois->r1 || pz > pois->z1 - 1)
1297  return FALSE;
1298 
1299  interpol_set_stencil (interpol,
1300  ez_r_at (pr - 1, pois->level),
1301  ez_z_at (pz - 1, pois->level),
1302  EZ_RZ (pois, pr - 1, pz - 1),
1303  EZ_RZ (pois, pr - 1, pz),
1304  EZ_RZ (pois, pr, pz - 1),
1305  EZ_RZ (pois, pr, pz));
1306  return TRUE;
1307 }
1308 
1310 int
1311 etheta_interpol_set (mapper_t *mapper, grid_t *source, interpol_t *interpol,
1312  int pr, int pz, int itheta)
1313 {
1314  pois_grid_t *pois;
1315 
1316  pois = (pois_grid_t*) source;
1317 
1318  if (pr < pois->r0 || pz < pois->z0
1319  || pr > pois->r1 - 1|| pz > pois->z1 - 1)
1320  return FALSE;
1321 
1322  interpol_set_stencil_at (source, interpol,
1323  r_at (pr, pois->level),
1324  z_at (pz, pois->level),
1325  pois->phi, pr, pz, 0);
1326  return TRUE;
1327 }
1328 
1330 void
1331 er_interpol (mapper_t *mapper, grid_t *source, grid_t *target,
1332  interpol_t *interpol, int ir, int iz, int itheta)
1333 {
1334  double er_r, er_z;
1335  cdr_grid_t *cdr;
1336  pois_grid_t *pois;
1337  int level_diff;
1338 
1339  cdr = (cdr_grid_t *) target;
1340  pois = (pois_grid_t *) source;
1341 
1342  level_diff = cdr->level - pois->level;
1343 
1344  /* Note that when pr = pois->r1, the electric field is calculated
1345  * from the extrapolation of phi and it is hence less accurate.
1346  * The same applies below to pz and pois->z1.
1347  */
1348  if ((ir >> level_diff) >= pois->r1) return;
1349 
1350  er_r = er_r_at (ir, cdr->level);
1351  er_z = er_z_at (iz, cdr->level);
1352 
1353  RZT (cdr->er, ir, iz, itheta) = interpol_apply (interpol, er_r, er_z);
1354 }
1355 
1357 void
1358 ez_interpol (mapper_t *mapper, grid_t *source, grid_t *target,
1359  interpol_t *interpol, int ir, int iz, int itheta)
1360 {
1361  double ez_r, ez_z;
1362  cdr_grid_t *cdr;
1363  pois_grid_t *pois;
1364  int level_diff;
1365 
1366  cdr = (cdr_grid_t *) target;
1367  pois = (pois_grid_t *) source;
1368 
1369  level_diff = cdr->level - pois->level;
1370 
1371  if ((iz >> level_diff) >= pois->z1) return;
1372 
1373  ez_r = ez_r_at (ir, cdr->level);
1374  ez_z = ez_z_at (iz, cdr->level);
1375 
1376  RZT (cdr->ez, ir, iz, itheta) = interpol_apply (interpol, ez_r, ez_z);
1377 }
1378 
1380 void
1381 etheta_interpol (mapper_t *mapper, grid_t *source, grid_t *target,
1382  interpol_t *interpol, int ir, int iz, int itheta)
1383 {
1384  double eth_r, eth_z;
1385  cdr_grid_t *cdr;
1386 
1387  cdr = (cdr_grid_t *) target;
1388 
1389  eth_r = r_at (ir, cdr->level);
1390  eth_z = z_at (iz, cdr->level);
1391 
1392  RZT (cdr->etheta, ir, iz, itheta) =
1393  interpol_apply (interpol, eth_r, eth_z);
1394 }
1395 
1397 void
1398 charge_copy (mapper_t *mapper, grid_t *source, grid_t *target,
1399  int ir, int iz, int itheta)
1400 {
1401  cdr_grid_t *cdr;
1402  pois_grid_t *pois;
1403 
1404  pois = (pois_grid_t*) target;
1405  cdr = (cdr_grid_t*) source;
1406 
1407  RZ (pois->charge, ir, iz) = RZT (cdr->charge, ir, iz, itheta);
1408 }
1409 
1411 int
1412 charge_interpol_set (mapper_t *mapper, grid_t *source, interpol_t *interpol,
1413  int pr, int pz, int itheta)
1414 {
1415  cdr_grid_t *cdr;
1416 
1417  cdr = (cdr_grid_t*) source;
1418 
1419  if (pr < cdr->r0 || pz < cdr->z0
1420  || pr > cdr->r1 - 1|| pz > cdr->z1 - 1)
1421  return FALSE;
1422 
1423  interpol_set_stencil_at (source, interpol,
1424  r_at (pr, cdr->level),
1425  z_at (pz, cdr->level),
1426  cdr->charge, pr, pz, itheta);
1427  return TRUE;
1428 }
1429 
1431 void
1432 charge_interpol (mapper_t *mapper, grid_t *source, grid_t *target,
1433  interpol_t *interpol,
1434  int ir, int iz, int itheta)
1435 {
1436  double r, z;
1437  pois_grid_t *pois;
1438 
1439  pois = (pois_grid_t *) target;
1440 
1441  r = r_at (ir, pois->level);
1442  z = z_at (iz, pois->level);
1443 
1444  RZT (pois->charge, ir, iz, 0) = interpol_apply (interpol, r, z);
1445 }
1446 
1451 double
1452 pois_phi_at (pois_grid_t *grid, double r, double z, double theta)
1453 {
1454  int ir, iz, itheta, it, itn;
1455  REAL phi_it[2];
1456  interpol_t *phi_at_interpol = NULL;
1457 
1458  debug (3, "pois_phi_at (" grid_printf_str ", r = %g, z = %g, theta = %g)\n",
1459  grid_printf_args (grid), r, z, theta);
1460 
1461  grid = (pois_grid_t *) grid_finest_containing_r ((grid_t*) grid, r, z);
1462 
1463  if (NULL == grid) {
1464  fatal ("In pois_phi_at: potential outside the grid");
1465  }
1466 
1467  phi_at_interpol = interpol_new_a (dr[grid->level], dz[grid->level],
1469 
1470  ir = (int) (r / dr[grid->level]);
1471  iz = (int) (z / dz[grid->level]);
1472 
1473  /* If r == 0, it doesn't matter which theta we use, so we use 0.
1474  * also if we are in a 2D simulation.
1475  */
1476  if (grid->ntheta > 1 && r > 0.0) {
1477  itheta = (int) (theta / dtheta);
1478  itn = 2;
1479  } else {
1480  itheta = 0;
1481  itn = 1;
1482  }
1483 
1484  for (it = 0; it < itn; it++) {
1485  interpol_set_stencil_at ((grid_t *) grid, phi_at_interpol,
1486  r_at (ir, grid->level),
1487  z_at (iz, grid->level),
1488  grid->phi, ir, iz, itheta + it);
1489 
1490  phi_it[it] = interpol_apply (phi_at_interpol, r, z);
1491  }
1492 
1493  interpol_free (phi_at_interpol);
1494 
1495  if (grid->ntheta > 1 && r > 0.0) {
1496  return (phi_it[0] * (theta - theta_at (itheta)) +
1497  phi_it[1] * (theta_at (itheta + 1) - theta)) / dtheta;
1498  } else {
1499  return phi_it[0];
1500  }
1501 }
1502 
1506 void
1507 pois_dump (pois_grid_t *grid, const char *prefix, const char *name)
1508 {
1509  char *fname;
1510  int m = pois_output_margin;
1511 
1512  asprintf (&fname, "%s/r.%s.tsv", prefix, name);
1513  rz_axis_dump (fname, grid->r0 - m, grid->r1 + m, dr[grid->level]);
1514  free (fname);
1515 
1516  asprintf (&fname, "%s/z.%s.tsv", prefix, name);
1517  rz_axis_dump (fname, grid->z0 - m, grid->z1 + m, dz[grid->level]);
1518  free (fname);
1519 
1520  asprintf (&fname, "%s/phi.%s.tsv", prefix, name);
1521  rz_dump (grid->phi, fname, "w", grid->r0 - m, grid->z0 - m,
1522  grid->r1 + m, grid->z1 + m);
1523  free (fname);
1524 
1525  asprintf (&fname, "%s/charge.%s.tsv", prefix, name);
1526  rz_dump (grid->charge, fname, "w", grid->r0 - m, grid->z0 - m,
1527  grid->r1 + m, grid->z1 + m);
1528  free (fname);
1529 
1530  asprintf (&fname, "%s/error.%s.tsv", prefix, name);
1531  rz_dump (grid->error, fname, "w", grid->r0 - m, grid->z0 - m,
1532  grid->r1 + m, grid->z1 + m);
1533  free (fname);
1534 }
1535 
1539 void
1540 pois_dump_r (pois_grid_t *grid, const char *prefix, const char *name)
1541 {
1542  pois_grid_t *child;
1543  char *cname;
1544  int i = 0, nchilds;
1545  char codes[] = "abcdefghijklmnopqrstuvwxyz";
1546 
1547  pois_dump (grid, prefix, name);
1548 
1549  nchilds = grid_howmany_children ((grid_t *) grid);
1550 
1551  for (i = 0; i < nchilds; i++) {
1552  child = (pois_grid_t *) grid_get_child ((grid_t*) grid, nchilds - i - 1);
1553 
1554  assert (NULL != child);
1555 
1556  if (i > sizeof(codes) - 2)
1557  asprintf (&cname, "%s{%d}", name, i);
1558  else
1559  asprintf (&cname, "%s%c", name, codes[i]);
1560 
1561  pois_dump_r (child, prefix, cname);
1562  free (cname);
1563  }
1564 }