Octopus
poisson_cutoffs.c
Go to the documentation of this file.
1/*
2 Copyright (C) 2006-2008 Luis Matos, A. Castro
3
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17 02110-1301, USA.
18
19*/
20
21#include <assert.h>
22#include <config.h>
23#include <gsl/gsl_errno.h>
24#include <gsl/gsl_integration.h>
25#include <gsl/gsl_sf_bessel.h>
26#include <gsl/gsl_sf_expint.h>
27#include <math.h>
28#include <stdio.h>
29
30#define M_EULER_MASCHERONI 0.5772156649015328606065120
31
32/*
33This file contains the definition of functions used by Fortran module
34poisson_cutoff_m. There are four functions to be defined:
35
36c_poisson_cutoff_3d_1d_finite: For the cutoff of 3D/0D cases, in which however
37 we want the region of the cutoff to be a
38cylinder. c_poisson_cutoff_2d_0d:
39
40c_poisson_cutoff_2d_1d:
41
42*/
44/************************************************************************/
45/************************************************************************/
46/* C_POISSON_CUTOFF_3D_1D_FINITE */
47/************************************************************************/
48/************************************************************************/
49
50struct parameters {
51 double kx;
52 double kr;
53 double x0;
54 double r0;
55 int index;
56};
57
58/* the index is the type of integral. This is necessary because depending of the
59 value of k the the integral needs to be performed in different ways */
60#define PFC_F_0 0
61#define PFC_F_KX 1
62#define PFC_F_KR 2
63
64static const double tol = 1e-7;
65static double zero = 1e-100;
66
67static double f(double w, void *p) {
68 struct parameters *params = (struct parameters *)p;
69 const double kx = (params->kx);
70 double kr = (params->kr);
71 double x0 = (params->x0);
72 double r0 = (params->r0);
73 int index = (params->index);
74 double result;
75
76 if (w == 0)
77 w = zero;
78
79 if (fabs(kx - w) > tol) {
80 result = sin((kx - w) * x0) / (kx - w) *
81 sqrt(pow(w, 2.0 * index) * pow(r0, 2.0 * index)) /
82 (kr * kr + w * w) * gsl_sf_bessel_Kn(index, r0 * fabs(w));
83 } else {
84 result = x0 * sqrt(pow(w, 2.0 * index)) / (kr * kr + w * w) *
85 gsl_sf_bessel_Kn(index, r0 * fabs(w));
86 }
87 return result;
88}
89
90static double f_kx_zero(double w, void *p) {
91 struct parameters *params = (struct parameters *)p;
92 double kr = (params->kr);
93 double x0 = (params->x0);
94 double result;
95
96 if (w == 0.0)
97 w = zero;
98
99 result = 2.0 * M_PI * w * gsl_sf_bessel_J0(kr * w) *
100 (log(x0 + sqrt(w * w + x0 * x0)) - log(-x0 + sqrt(w * w + x0 * x0)));
101 return result;
102}
103
104static double f_kr_zero(double w, void *p) {
105 struct parameters *params = (struct parameters *)p;
106 double kx = (params->kx);
107 double r0 = (params->r0);
108 double result;
109
110 result = 4.0 * M_PI * cos(kx * w) * (sqrt(r0 * r0 + w * w) - fabs(w));
111 return result;
112}
113
114static double int_aux(int index, double kx, double kr, double x0, double r0,
115 int which_int) {
116 /*variables*/
117 double result, error;
118 double xinf = 100.0 / r0;
119 struct parameters params;
120
121 /*pass the given parameters to program*/
122 const size_t wrk_size = 5000;
123 /* I believe that 1e-6 is over-killing, a substantial gain in time
124 is obtained by setting this threshold to 1e-3 */
125 /* const double epsilon_abs = 1e-6; */
126 /* const double epsilon_rel = 1e-6; */
127 const double epsilon_abs = 1e-3;
128 const double epsilon_rel = 1e-3;
129
130 /*creating the workspace*/
131 gsl_integration_workspace *ws = gsl_integration_workspace_alloc(wrk_size);
132
133 /*create the function*/
134 gsl_function F;
135
136 assert(which_int == PFC_F_0 || which_int == PFC_F_KR ||
137 which_int == PFC_F_KX);
138
139 params.kx = kx;
140 params.kr = kr;
141 params.x0 = x0;
142 params.r0 = r0;
143 params.index = index;
144
145 F.params = &params;
146
147 /*select the integration method*/
148 switch (which_int) {
149 case PFC_F_0:
150 F.function = &f;
151 gsl_integration_qag(&F, -xinf, xinf, epsilon_abs, epsilon_rel, wrk_size, 3,
152 ws, &result, &error);
153 break;
154 case PFC_F_KX:
155 F.function = &f_kx_zero;
156 gsl_integration_qag(&F, 0.0, r0, epsilon_abs, epsilon_rel, wrk_size, 3, ws,
157 &result, &error);
158 break;
159 case PFC_F_KR:
160 F.function = &f_kr_zero;
161 gsl_integration_qag(&F, 0.0, x0, epsilon_abs, epsilon_rel, wrk_size, 3, ws,
162 &result, &error);
163 break;
164 }
165
166 /*free the integration workspace*/
167 gsl_integration_workspace_free(ws);
168
169 /*return*/
170 return result;
171}
172
173double poisson_finite_cylinder(double kx, double kr, double x0, double r0) {
174 double result;
175
176 if ((kx >= tol) & (kr >= tol)) {
177 result =
178 4.0 * kr * r0 * gsl_sf_bessel_Jn(1, kr * r0) *
179 int_aux(0, kx, kr, x0, r0, PFC_F_0) -
180 4.0 * gsl_sf_bessel_Jn(0, kr * r0) *
181 int_aux(1, kx, kr, x0, r0, PFC_F_0) +
182 4.0 * M_PI / (kx * kx + kr * kr) *
183 (1.0 + exp(-kr * x0) * (kx / kr * sin(kx * x0) - cos(kx * x0)));
184 } else if ((kx < tol) & (kr >= tol)) {
185 result = int_aux(0, kx, kr, x0, r0, PFC_F_KX);
186 } else if ((kx >= tol) & (kr < tol)) {
187 result = int_aux(0, kx, kr, x0, r0, PFC_F_KR);
188 } else
189 result = -2.0 * M_PI *
190 (log(r0 / (x0 + sqrt(r0 * r0 + x0 * x0))) * r0 * r0 +
191 x0 * (x0 - sqrt(r0 * r0 + x0 * x0)));
192
193 /* the 1/(4pi) factor is due to the factor on the poissonsolver3d (end)*/
194 return result / (4.0 * M_PI);
195}
196
197/* --------------------- Interface to Fortran ---------------------- */
198double FC_FUNC_(c_poisson_cutoff_3d_1d_finite,
199 C_POISSON_CUTOFF_3D_1D_FINITE)(double *gx, double *gperp,
200 double *xsize, double *rsize) {
201 return poisson_finite_cylinder(*gx, *gperp, *xsize, *rsize);
202}
203
204/************************************************************************/
205/************************************************************************/
206/* C_POISSON_CUTOFF_2D_0D */
207/************************************************************************/
208/************************************************************************/
209static double bessel_J0(double w, void *p) { return gsl_sf_bessel_J0(w); }
210
211/* --------------------- Interface to Fortran ---------------------- */
212double FC_FUNC_(c_poisson_cutoff_2d_0d, C_POISSON_CUTOFF_2D_0D)(double *x,
213 double *y) {
214 double result, error;
215 const size_t wrk_size = 500;
216 const double epsilon_abs = 1e-3;
217 const double epsilon_rel = 1e-3;
218
219 gsl_integration_workspace *ws = gsl_integration_workspace_alloc(wrk_size);
220 gsl_function F;
221
222 F.function = &bessel_J0;
223 gsl_integration_qag(&F, *x, *y, epsilon_abs, epsilon_rel, wrk_size, 3, ws,
224 &result, &error);
225 gsl_integration_workspace_free(ws);
226
227 return result;
228}
229
230/************************************************************************/
231/************************************************************************/
232/* INTCOSLOG */
233/************************************************************************/
234/************************************************************************/
235/* Int_0^mu dy cos(a*y) log(abs(b*y)) =
236 (1/a) * (log(|b*mu|)*sin(a*mu) - Si(a*mu) ) */
237double FC_FUNC(intcoslog, INTCOSLOG)(double *mu, double *a, double *b) {
238 if (fabs(*a) > 0.0) {
239 return (1.0 / (*a)) *
240 (log((*b) * (*mu)) * sin((*a) * (*mu)) - gsl_sf_Si((*a) * (*mu)));
241 } else {
242 return (*mu) * (log((*mu) * (*b)) - 1.0);
243 }
244}
245
246/************************************************************************/
247/************************************************************************/
248/* C_POISSON_CUTOFF_2D_1D */
249/************************************************************************/
250/************************************************************************/
251struct parameters_2d_1d {
252 double gx;
253 double gy;
254 double rc;
255};
256
257static double cutoff_2d_1d(double w, void *p) {
258 double k0arg, k0;
259 struct parameters_2d_1d *params = (struct parameters_2d_1d *)p;
260 double gx = (params->gx);
261 double gy = (params->gy);
262
263 k0arg = fabs(w * gx);
264 if (k0arg < 0.05) {
265 k0 = -(log(k0arg / 2) + M_EULER_MASCHERONI);
266 } else if (k0arg < 50.0) {
267 k0 = gsl_sf_bessel_K0(k0arg);
268 } else {
269 k0 = sqrt(2.0 * M_PI / k0arg) * exp(-k0arg);
270 }
271 return 4.0 * cos(w * gy) * k0;
272}
273
274/* --------------------- Interface to Fortran ---------------------- */
275double FC_FUNC_(c_poisson_cutoff_2d_1d,
276 C_POISSON_CUTOFF_2D_1D)(double *gy, double *gx, double *rc) {
277 double result, error, res, b;
278 struct parameters_2d_1d params;
279 const size_t wrk_size = 5000;
280 const double epsilon_abs = 1e-3;
281 const double epsilon_rel = 1e-3;
282
283 double mu;
284 gsl_integration_workspace *ws = gsl_integration_workspace_alloc(wrk_size);
285 gsl_function F;
286
287 mu = 0.1 / (*gx);
288 b = fabs((*gx)) / 2.0;
289
290 params.gx = *gx;
291 params.gy = *gy;
292 params.rc = *rc;
293
294 F.function = &cutoff_2d_1d;
295 F.params = &params;
296
297 res = -4.0 * FC_FUNC(intcoslog, INTCOSLOG)(&mu, gy, &b);
298
299 if (fabs(*gy) > 0.0) {
300 res = res - (4.0 * M_EULER_MASCHERONI / (*gy)) * sin((*gy) * mu);
301 } else {
302 res = res - 4.0 * M_EULER_MASCHERONI * mu;
303 }
304
305 gsl_integration_qag(&F, mu, (*rc), epsilon_abs, epsilon_rel, wrk_size, 3, ws,
306 &result, &error);
307 res = res + result;
308
309 gsl_integration_workspace_free(ws);
310 return res;
311}
312
313/************************************************************************/
314/************************************************************************/
315/* C_POISSON_CUTOFF_1D_0D */
316/************************************************************************/
317/************************************************************************/
318
319struct parameters_1d_0d {
320 double g;
321 double a;
322};
323
324static double cutoff_1d_0d(double w, void *p) {
325 struct parameters_1d_0d *params = (struct parameters_1d_0d *)p;
326 double g = (params->g);
327 double a = (params->a);
328 return 2.0 * (cos(w) / sqrt(w * w + a * a * g * g));
329}
330
331/* --------------------- Interface to Fortran ---------------------- */
332double FC_FUNC_(c_poisson_cutoff_1d_0d,
333 C_POISSON_CUTOFF_1D_0D)(double *g, double *a, double *rc) {
334 double result, error;
335 struct parameters_1d_0d params;
336 const size_t wrk_size = 5000;
337 const double epsilon_abs = 1e-3;
338 const double epsilon_rel = 1e-3;
339 int status;
340 gsl_integration_workspace *ws;
341 gsl_function F;
342
343 if ((*g) <= 0.0) {
344 return 2.0 * asinh((*rc) / (*a));
345 };
346 // Given the definition of g and rc, there is a point exactly 100 \pi.
347 // Given that the integral is only computed at 1e-3 absolution tolerance
348 // a small rounding error can lead to a 1e-3 jump. This is why we use here 100.1 - NTD
349 if ((*g) * (*rc) > 100.1 * M_PI) {
350 return 2.0 * gsl_sf_bessel_K0((*a) * (*g));
351 };
352
353 gsl_set_error_handler_off();
354
355 ws = gsl_integration_workspace_alloc(wrk_size);
356
357 params.g = *g;
358 params.a = *a;
359
360 F.function = &cutoff_1d_0d;
361 F.params = &params;
362
363 status = gsl_integration_qag(&F, 0.0, (*rc) * (*g), epsilon_abs, epsilon_rel,
364 wrk_size, 3, ws, &result, &error);
365
366 gsl_integration_workspace_free(ws);
367
368 if (status) {
369 return 0.0;
370 } else {
371 return result;
372 }
373}
double pow(double __x, double __y) __attribute__((__nothrow__
double log(double __x) __attribute__((__nothrow__
double exp(double __x) __attribute__((__nothrow__
double sin(double __x) __attribute__((__nothrow__
double fabs(double __x) __attribute__((__nothrow__
double sqrt(double __x) __attribute__((__nothrow__
double asinh(double __x) __attribute__((__nothrow__
double cos(double __x) __attribute__((__nothrow__
const int *restrict index
Definition: operate_inc.c:13