Streamer fluid modeling - An overview of ARCoS  1.0
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
dft.c
Go to the documentation of this file.
1 
16 #include <math.h>
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 
21 #include <fftw3.h>
22 
23 #include "cdr.h"
24 #include "cstream.h"
25 #include "grid.h"
26 #include "parameters.h"
27 #include "proto.h"
28 #include "rz_array.h"
29 #include "species.h"
30 
31 static void renormalize (cdr_grid_t *grid, rz_array_t *var);
32 static double rnd_gauss (double mu, double sigma);
33 static double ranf (void);
34 
36 void
37 dft_transform (rz_array_t *in, rz_array_t *out, int sign)
38 {
39  int i;
40  fftw_plan *plans;
41  fftw_r2r_kind kind;
42 
43  debug (2, "dft_transform (..., sign = %d)\n", sign);
44 
45  if (sign > 0) kind = FFTW_R2HC;
46  else kind = FFTW_HC2R;
47 
48  assert(in->dim == 3 && out->dim == 3);
49  assert(in->ntheta == out->ntheta && in->nr == out->nr && in->nz == out->nz);
50 
51  /* Unfortunately, the fftw planning routines are not thread-safe. */
52 
53  /* The +4 here is because we also transform the buffer, which is
54  useful to easily set boundaries, etc. */
55  plans = xmalloc (sizeof (fftw_plan) * (in->nz + 4));
56 
57  for (i = 0; i < in->nz + 4; i++) {
58  plans[i] = fftw_plan_many_r2r (1, /* Rank */
59  &in->ntheta, /* n[] */
60  in->nr + 4, /* howmany */
61  RZTP (in, in->r0, in->z0 + i, 0),
62  /* in */
63  &in->ntheta, /* inembed */
64  in->strides[THETA_INDX], /* istride */
65  in->strides[R_INDX], /* idist */
66  RZTP (out, in->r0, out->z0 + i, 0),
67  /* out */
68  &out->ntheta, /* onembed */
69  out->strides[THETA_INDX], /* ostride */
70  out->strides[R_INDX], /* odist */
71  &kind, /* kind */
72  FFTW_ESTIMATE); /* flags */
73 
74  }
75 
76 #pragma omp parallel
77  {
78 #pragma omp for
79  for (i = 0; i < in->nz + 4; i++) {
80  fftw_execute (plans[i]);
81  }
82  }
83 
84 
85  for (i = 0; i < in->nz + 4; i++) {
86  fftw_destroy_plan (plans[i]);
87  }
88 
89  free (plans);
90  fftw_cleanup();
91 }
92 
93 
96 void
98 {
99  int ir, iz, k;
100 
101  debug (2, "dft_diff (" grid_printf_str ", ...)\n", grid_printf_args(grid));
102 
103  /* The parallelization here is not optimal if max_ntheta is not a multiple
104  of 2. */
105 #pragma omp parallel
106  {
107 #pragma omp for private(ir, iz)
108  for (k = 0; k < grid->ntheta / 2 + 1; k++) {
109  if (k < grid->ntheta / 2) {
110  iter_grid_n (grid, ir, iz, 2) {
111  double re, im, re_f, im_f;
112 
113  /* For k == 0, everything is real. */
114  re_f = RZT (f, ir, iz, k);
115  im_f = (k == 0? 0: RZT (f, ir, iz, grid->ntheta - k));
116 
117  re = re_f * wk[k] - (k == 0? 0: im_f * wk[grid->ntheta - k]);
118  im = (k == 0? 0: re_f * wk[grid->ntheta - k] + im_f * wk[k]);
119 
120  RZT (f, ir, iz, k) = re / r_at (ir, grid->level);
121  if (k != 0)
122  RZT (f, ir, iz, grid->ntheta - k) = im / r_at (ir, grid->level);
123  }
124  } else if ((grid->ntheta % 2) == 0) {
125  iter_grid_n (grid, ir, iz, 2) {
126  /* Also for k = ntheta / 2, everything is real. */
127  RZT (f, ir, iz, k) = wk[k] * RZT (f, ir, iz, k)
128  / r_at (ir, grid->level);
129  }
130  }
131  }
132  }
133 }
134 
135 
142 void
143 dft_weight (cdr_grid_t *cdr, rz_array_t *var, double weights[], double power)
144 {
145  int k, ir, iz;
146  double pwr, tmp;
147 
148  debug (2, "dft_weigth(" grid_printf_str ", ...)\n", grid_printf_args(cdr));
149 
150 #pragma omp parallel
151  {
152 #pragma omp for private(ir, iz, pwr, tmp)
153  for (k = 0; k < cdr->ntheta; k++) {
154  pwr = 0;
155  iter_grid(cdr, ir, iz) {
156  /* Slow, since power is usually 1 or 2,
157  but this is outside the main loop, so we buy generality
158  at the cost of speed. */
159  tmp = pow(RZT(var, ir, iz, k), power);
160  pwr += (tmp * r_at(ir, cdr->level));
161  }
162  weights[k] = twopi * pwr * dr[cdr->level] * dz[cdr->level];
163  }
164  }
165 }
166 
167 
176 void
177 dft_out_weights (cdr_grid_t *grid, const char *prefix, double t)
178 {
179  static FILE *fp_charge = NULL;
180  static FILE *fp_electrons = NULL;
181  static double *powers_charge = NULL;
182  static double *powers_electrons = NULL;
183  int i;
184 
185  if (NULL == fp_charge) {
186  char *fname;
187  asprintf (&fname, "%s/charge-weights.tsv", prefix);
188  fp_charge = fopen (fname, "w");
189 
190  if (NULL == fp_charge) {
191  fatal ("Unable to open %s\n", fname);
192  return;
193  }
194  free (fname);
195 
196  asprintf (&fname, "%s/electrons-weights.tsv", prefix);
197  fp_electrons = fopen (fname, "w");
198 
199  if (NULL == fp_electrons) {
200  fatal ("Unable to open %s\n", fname);
201  return;
202  }
203  free (fname);
204  }
205 
206  if (NULL == powers_charge) {
207  powers_charge = xmalloc (sizeof(double) * grid->ntheta);
208  powers_electrons = xmalloc (sizeof(double) * grid->ntheta);
209  }
210 
211  dft_transform (grid->charge, grid->charge, 1);
212  dft_weight (grid, grid->charge, powers_charge, 2.0);
213 
214  /* The electron density has to be transformed back, since we will still need
215  it. */
216  dft_transform (grid->dens[electrons], grid->dens[electrons], 1);
217  dft_weight (grid, grid->dens[electrons], powers_electrons, 1.0);
218  dft_transform (grid->dens[electrons], grid->dens[electrons], -1);
219  renormalize(grid, grid->dens[electrons]);
220 
221  fprintf (fp_charge, "%g", t);
222  fprintf (fp_electrons, "%g", t);
223 
224  for (i = 0; i < grid->ntheta; i++) {
225  fprintf (fp_charge, "\t%g", powers_charge[i]);
226  fprintf (fp_electrons, "\t%g", powers_electrons[i]);
227  }
228 
229  fprintf (fp_charge, "\n");
230  fprintf (fp_electrons, "\n");
231 
232  fflush(fp_charge);
233  fflush(fp_electrons);
234 }
235 
236 
245 void
246 dft_perturb (cdr_grid_t *cdr, rz_array_t *var, double *epsilon_k)
247 {
248  int k, ir, iz;
249 
250 #pragma omp parallel
251  {
252 #pragma omp for private(ir, iz)
253  for (k = 1; k < cdr->ntheta; k++) {
254  if (k > perturb_max_k && k < (cdr->ntheta - perturb_max_k))
255  continue;
256 
257  iter_grid_n (cdr, ir, iz, 2) {
258  RZT (var, ir, iz, k) =
259  /* We multiply the perturbation by r to ensure that it is
260  continuous at r -> 0. */
261  epsilon_k[k - 1] * RZT (var, ir, iz, 0) * r_at (ir, cdr->level);
262  }
263  }
264  }
265 }
266 
269 void
270 dft_dens_perturb_r (cdr_grid_t *grid, int species, double *epsilon_k)
271 {
272  int ir, iz, k, allocated = FALSE;
273  cdr_grid_t *leaf;
274  double A;
275 
276  debug (2, "dft_dens_perturb_r(" grid_printf_str ", %s)\n",
277  grid_printf_args(grid), spec_index[species]->name);
278 
279  /* We normalize the perturbation using the maximum of the densities. */
281 
282  if (NULL == epsilon_k) {
283  epsilon_k = (double*) xmalloc (sizeof(double) * (grid->ntheta - 1));
284 
285  for (k = 1; k < grid->ntheta; k++) {
286  /* We divide by ntheta because the FFT is not normalized and we want
287  to express perturb_epsilon as a fraction of the k=0 mode. */
288  epsilon_k[k - 1] = rnd_gauss (0, perturb_epsilon) / grid->ntheta / A;
289  }
290 
291  allocated = TRUE;
292  }
293 
294  iter_childs (grid, leaf) {
295  dft_dens_perturb_r (leaf, species, epsilon_k);
296  }
297 
298  dft_transform (grid->dens[species], grid->dens[species], 1);
299 
300  renormalize(grid, grid->dens[species]);
301 
302  dft_perturb (grid, grid->dens[species], epsilon_k);
303  dft_transform (grid->dens[species], grid->dens[species], -1);
304 
305  if (allocated) free (epsilon_k);
306 }
307 
308 
318 static void
320 {
321  int ir, iz, itheta;
322 
323 #pragma omp parallel
324  {
325 #pragma omp for private(ir, iz)
326  for (itheta = 0; itheta < grid->ntheta; itheta++) {
327  iter_grid_n (grid, ir, iz, 2) {
328  RZT(var, ir, iz, itheta) /= grid->ntheta;
329  }
330  }
331  }
332 }
333 
334 
338 static double
339 rnd_gauss(double mu, double sigma)
340 {
341  double x1, x2, w;
342  static double y1, y2;
343  static int has_more = FALSE;
344 
345 
346  if (has_more) {
347  has_more = FALSE;
348  return mu + y2 * sigma;
349  }
350 
351  do {
352  x1 = 2.0 * ranf() - 1.0;
353  x2 = 2.0 * ranf() - 1.0;
354  w = x1 * x1 + x2 * x2;
355  } while (w >= 1.0);
356 
357  w = sqrt ((-2.0 * log (w)) / w);
358  y1 = x1 * w;
359  y2 = x2 * w;
360 
361  has_more = TRUE;
362 
363  return mu + y1 * sigma;
364 }
365 
366 #define AM (1.0 / RAND_MAX)
367 
369 static double
370 ranf (void)
371 {
372  return rand() * AM;
373 }