Manticore  Version 2.0alpha
Physics of Molecular Clouds
kgauss.cc
Go to the documentation of this file.
1 
10 #include <cmath>
11 #include <cstdio>
12 
13 #include <algorithm>
14 
15 
16 namespace mutils {
17 
25 template<typename R>
26 R sqr(R x) { return x*x; }
27 
28 
29 #define MAXIT (sizeof(xptr)/sizeof(xptr[0])-1)
30 
31 static double c_gl, (*func_gl)(double x);
32 
33 static double hifn(double x)
34 {
35  return((*func_gl)(x)/sqrt(x<c_gl ? c_gl-x : 1e-16*(c_gl ? fabs(c_gl) : 1)));
36 }
37 
38 static double lofn(double x)
39 {
40  return((*func_gl)(x)/sqrt(x>c_gl ? x-c_gl : 1e-16*(c_gl ? fabs(c_gl) : 1)));
41 }
42 
43 
44 typedef struct {
45  double (*func)(double, void *);
46  void *fdata;
47  double c;
48 } integ_data_t;
49 
50 static double hifn_r(double x, void *vdata)
51 {
52  integ_data_t *data = (integ_data_t *)vdata;
53  double ac = data->c;
54  return((*data->func)(x, data->fdata)/
55  sqrt(x<ac ? ac-x : 1e-16*(ac ? fabs(ac) : 1)));
56 }
57 
58 static double lofn_r(double x, void *vdata)
59 {
60  integ_data_t *data = (integ_data_t *)vdata;
61  double ac = data->c;
62  return((*data->func)(x, data->fdata)/
63  sqrt(x>ac ? x-ac : 1e-16*(ac ? fabs(ac) : 1)));
64 }
65 
66 
67 double kgauss_sub(double (*f)(double x), double (*f_r)(double x, void *),
68  void *fdata, double a, double b, double c, double *acc,
69  int root, int lev, double I0, int maxrecur, int paranoid)
70 {
71  static double
72 x7[]=
73  {0.9491079123427585245, 0.7415311855993944399, 0.40584515137739716691, 0},
74 w7[]=
75  {0.12948496616886969327, 0.27970539148927666790, 0.38183005050511894495,
76  0.20897959183673469388},
77 x15[]=
78  {0.9914553711208126392, 0.8648644233597690728, 0.5860872354676911303,
79  0.20778495500789846760},
80 w15[]=
81  {0.06309209262997855329, 0.14065325971552591875, 0.19035057806478540991,
82  0.10474107054236391401, 0.022935322010529224964, 0.10479001032225018384,
83  0.16900472663926790283, 0.20443294007529889241},
84 x31[]=
85  {0.9986871096784667298, 0.9753835882088933697, 0.9122048827832628784,
86  0.8076889391724375091, 0.6673480981043001754, 0.49863678655283200429,
87  0.30857924791058777890, 0.10452827381078071340},
88 w31[]=
89  {0.031577706217045857274, 0.07033204641040065094, 0.09517802993183068012,
90  0.052371606782402922364, 0.011319468444683435107, 0.052384370820982692472,
91  0.08449876530124302120, 0.10221418000570274392, 0.0036349311950498838561,
92  0.021039446258726795607, 0.042193500584546594485, 0.061821985645449856431,
93  0.07787534711524599642, 0.09026180214655860231, 0.09919685766743291249,
94  0.10409995547269735501},
95 x63[]=
96  {0.9998092141980435177, 0.9960402386259685431, 0.9846371438756441798,
97  0.9635649536133961699, 0.9319846573806651406, 0.8898093648749426400,
98  0.8374568325601445865, 0.7756739083583348141, 0.7053824093748503091,
99  0.6275454213822932614, 0.5430823509867011311, 0.45285563284960723138,
100  0.35771483158603327041, 0.25855961875447247355, 0.15639264033608140153,
101  0.052344665459830506663},
102 w63[]=
103  {0.015788872779215423953, 0.035166023524553984272, 0.047589015038602680558,
104  0.026185803412726870878, 0.005660867725095312756, 0.026192186880710567449,
105  0.042249382781031758514, 0.051107090052427067322, 0.0018039393894459073286,
106  0.010519600488254708543, 0.021096745715199243564, 0.030910992205938984344,
107  0.038937673364353656898, 0.045130900978520531208, 0.049598428775219425281,
108  0.052049977691713990513, 0.0005394072866580217702,
109  0.0035577405571320363985, 0.008008877528118372922, 0.013129713474427210903,
110  0.018455916099884639804, 0.023683152580752000206, 0.028605857490498295944,
111  0.033099092907400232260, 0.037111404910397191759, 0.040648875788571024107,
112  0.043742748418925043826, 0.046413730813032435148, 0.048652555041851185681,
113  0.050419337829027882637, 0.051653256012700288788, 0.052290832457614024465},
114 x127[]=
115  {0.9999732140537096663, 0.9994072045541133135, 0.9975832115407271425,
116  0.9940109708349837137, 0.9883399710474278217, 0.9803243695495499628,
117  0.9698006651097387898, 0.9566689345185500717, 0.9408797537558513210,
118  0.9224249470755334487, 0.9013304843743343536, 0.8776505702242030085,
119  0.8514623710548997088, 0.8228610497537872099, 0.7919549469554387927,
120  0.7588609140247034710, 0.7236999634679475019, 0.6865935263842583902,
121  0.6476606483346630945, 0.6070163823125118480, 0.5647714587971209075,
122  0.5210330881098700049, 0.47590656926256125696, 0.42949731364743432232,
123  0.38191294949982269268, 0.33326529310537285172, 0.28367206848397232384,
124  0.23325827809314719522, 0.18215708913074090694, 0.13051006423363166234,
125  0.07846658760948939210, 0.026182433405385318012},
126 w127[]=
127  {0.007894436389622294500, 0.017583011762276993951, 0.023794507519301340354,
128  0.013092901706363435451, 0.0028304340009942515258, 0.013096093440355333640,
129  0.021124691390515879519, 0.025553545026213533694, 0.0009020326132240592195,
130  0.005259800244982030301, 0.010548372857600215651, 0.015455496102969499733,
131  0.019468836682176829061, 0.022565450489260265736, 0.024799214387609712688,
132  0.026024988845856995283, 0.00026824492648199271332,
133  0.0017788676370217658788, 0.004004438754554190525, 0.006564856737114416480,
134  0.009227958049939655524, 0.011841576290375841473, 0.014302928745249129776,
135  0.016549546453700112606, 0.018555702455198594863, 0.020324437894285511663,
136  0.021871374209462521731, 0.023206865406516217476, 0.024326277520925592782,
137  0.025209668914513941280, 0.025826628006350144365, 0.026145416228807012208,
138  0.00007666028154662839408, 0.0005490365712772494279,
139  0.0013149375828678979980, 0.0022863309701736851777,
140  0.0034049581223715159493, 0.004624110998701176147, 0.005907814428674106763,
141  0.007227959698738149350, 0.008561844248934732274, 0.009890749642424429307,
142  0.011199152457074135131, 0.012474289971042915773, 0.013705938795913981808,
143  0.014886315023128753955, 0.016010013553407559797, 0.017073903395086741336,
144  0.018076904204550982752, 0.019019598918148049863, 0.019903688814155477260,
145  0.020731356767667036739, 0.021504646454995216775, 0.022224966589876512971,
146  0.022892785760346567564, 0.023507517384958226284, 0.024067543172072124703,
147  0.024570314471893502741, 0.025012500880974706687, 0.025390194359438009696,
148  0.025699193007816822839, 0.025935371167822469283, 0.026095105661905096599,
149  0.026175694952196227010},
150 x255[]=
151  {0.9999963067486951954, 0.9999152752559348126, 0.9996433483555746783,
152  0.9990913137344203859, 0.9981867960827265115, 0.9968697356940136751,
153  0.9950890556563352695, 0.9928012000738545143, 0.9899695008102539966,
154  0.9865635049160346460, 0.9825582265834872996, 0.9779334496251760458,
155  0.9726731369993381727, 0.9667649473643406394, 0.9601998389233076039,
156  0.9529717393703213579, 0.9450772648209298621, 0.9365154750708113300,
157  0.9272876559818071015, 0.9173971221917106181, 0.9068490349651485285,
158  0.8956502311299054918, 0.8838090598842230091, 0.8713352249541538215,
159  0.8582396302130598049, 0.8445342274991779505, 0.8302318660071731089,
160  0.8153461432903685913, 0.7998912585787304708, 0.7838818697648637995,
161  0.7673329559944715517, 0.7502596882683412608, 0.7326773107667189801,
162  0.7146010356960037625, 0.6960459542984969734, 0.6770269662478566161,
163  0.6575587289946255923, 0.6376556277780920590, 0.6173317660619912557,
164  0.5966009751817463673, 0.5754768411167735517, 0.5539727456204857446,
165  0.5321019185252632801, 0.5098774979234026434, 0.48731259509574956027,
166  0.46442036146072008750, 0.44121405535670282430, 0.41770710704249008257,
167  0.39391318079976768177, 0.36984623336963443023, 0.34552056811136913486,
168  0.32095088424031443935, 0.29615232032684852625, 0.27114049099145203618,
169  0.24593151549383166774, 0.22054203676240731795, 0.19498922939984828060,
170  0.16929079535915298899, 0.14346494631303911128, 0.11753037221284078240,
171  0.09150619611020609502, 0.06541191594510644914, 0.039267334634802255021,
172  0.013092480382206823402},
173 w255[]=
174  {0.003947218194811147250, 0.008791505881138496975, 0.011897253759650670177,
175  0.006546450853181717726, 0.0014152170004971327031, 0.006548046720177666820,
176  0.010562345695257939759, 0.012776772513106766847,
177  0.00045101631047035672287, 0.0026299001224910151504,
178  0.005274186428800107826, 0.007727748051484749866, 0.009734418341088414530,
179  0.011282725244630132868, 0.012399607193804856344, 0.013012494422928497641,
180  0.00013412814082582891278, 0.0008894338185147723354,
181  0.0020022193772770952853, 0.0032824283685572082402,
182  0.004613979024969827762, 0.005920788145187920736, 0.007151464372624564888,
183  0.008274773226850056303, 0.009277851227599297431, 0.010162218947142755831,
184  0.010935687104731260865, 0.011603432703258108738, 0.012163138760462796391,
185  0.012604834457256970640, 0.012913314003175072183, 0.013072708114403506104,
186  0.000038150115729678883900, 0.00027451814107948522455,
187  0.0006574687913192254503, 0.0011431654850866902753,
188  0.0017024790611857576058, 0.0023120554993505880716,
189  0.0029539072143370533817, 0.0036139798493690746749,
190  0.004280922124467366137, 0.004945374821212214654, 0.005599576228537067565,
191  0.006237144985521457886, 0.006852969397956990904, 0.007443157511564376978,
192  0.008005006776703779898, 0.008536951697543370668, 0.009038452102275491376,
193  0.009509799459074024932, 0.009951844407077738630, 0.010365678383833518369,
194  0.010752323227497608387, 0.011112483294938256485, 0.011446392880173283782,
195  0.011753758692479113142, 0.012033771586036062351, 0.012285157235946751371,
196  0.012506250440487353344, 0.012695097179719004848, 0.012849596503908411419,
197  0.012967685583911234641, 0.013047552830952548299, 0.013087847476098113505,
198  0.000010631773187689331551, 0.00007993324160416183366,
199  0.00019934629225661752482, 0.00035868882139811536585,
200  0.0005508028934055661185, 0.0007705041764177031044,
201  0.0010138011699455911823, 0.0012771043628389088432,
202  0.0015571262359162832193, 0.0018509459382531284054,
203  0.0021560121638169668193, 0.0024700972126411342886,
204  0.0027912405830786672989, 0.0031176998048792041352,
205  0.0034479123342294940334, 0.0037804671803520797730,
206  0.004114083913896834036, 0.004447597043058076436, 0.004779944312994714648,
207  0.005110157949984851451, 0.005437358183979665448, 0.005760748571634470826,
208  0.006079612745214887369, 0.006393312261301573719, 0.006701285238160699107,
209  0.007003045467007902253, 0.007298181671581202210, 0.007586356581948386573,
210  0.007867305490660966780, 0.008140833979476674666, 0.008406814548503037823,
211  0.008665181949799686451, 0.008915927123675733374, 0.009159089753242067779,
212  0.009394749581797212635, 0.009623016765016277986, 0.009844021640034099622,
213  0.010057904370771690380, 0.010264804960494993925, 0.010464854101398603935,
214  0.010658165257317194199, 0.010844828258217972251, 0.011024904540326784412,
215  0.011198424015314858577, 0.011365383419231345237, 0.011525745897233022556,
216  0.011679441536946909568, 0.011826368574785933586, 0.011966395058237419718,
217  0.012099360836564130280, 0.012225079850850787912, 0.012343342780032364446,
218  0.012453920155062457233, 0.012556566069048776249, 0.012651022586171432515,
219  0.012737024893523940703, 0.012814307159984132831, 0.012882608979232163138,
220  0.012941682193613858686, 0.012991297832248668971, 0.013031252857161437795,
221  0.013061376397838128294, 0.013081535166722437529, 0.013091637782748817614},
222  *xptr[]={x7, x15, x31, x63, x127, x255},
223  *wptr[]={w7, w15, w31, w63, w127, w255};
224 
225  static int first=1;
226 
227  double acc1, sum_1=0, sum0, sum, *w, *x, epst, dx, xm, xr, xs1, xs2,
228  fn[128], r, rc, eps, eps0;
229  int i, num, iter, lm, looks_ok=1;
230 
231  if (a==b) return(0);
232  xm=0.5*(a+b);
233  if (root) {
234  xs1=0.5*sqrt(c-a); xs2=0.5*sqrt(c-b); xr=2*(xs1-xs2);
235  } else {
236  xr=0.5*(b-a); xs1=xs2=0; /* not used */
237  }
238  acc1=std::max(1e-16, fabs(*acc));
239  sum=0; iter=0; num=7; lm=(num+1)/2-1; x=xptr[0], w=wptr[0];
240  if (root) {
241  if (f_r) {
242  for (i=0; i<lm; i++) {
243  double z1=1+x[i], z2=1-x[i];
244 
245  fn[i]=(*f_r)(c+root*sqr(z1*xs1+z2*xs2), fdata)+
246  (*f_r)(c+root*sqr(z1*xs2+z2*xs1), fdata);
247  sum+=w[i]*fn[i];
248  }
249  fn[lm]=2*(*f_r)(c+root*sqr(xs1+xs2), fdata); sum+=w[lm]*fn[lm];
250  } else {
251  for (i=0; i<lm; i++) {
252  double z1=1+x[i], z2=1-x[i];
253 
254  fn[i]=(*f)(c+root*sqr(z1*xs1+z2*xs2))+
255  (*f)(c+root*sqr(z1*xs2+z2*xs1));
256  sum+=w[i]*fn[i];
257  }
258  fn[lm]=2*(*f)(c+root*sqr(xs1+xs2)); sum+=w[lm]*fn[lm];
259  }
260  } else {
261  if (f_r) {
262  for (i=0; i<lm; i++) {
263  dx=xr*x[i]; fn[i]=(*f_r)(xm-dx, fdata)+(*f_r)(xm+dx, fdata);
264  sum+=w[i]*fn[i];
265  }
266  fn[lm]=2*(*f_r)(xm, fdata); sum+=w[lm]*fn[lm];
267  } else {
268  for (i=0; i<lm; i++) {
269  dx=xr*x[i]; fn[i]=(*f)(xm-dx)+(*f)(xm+dx);
270  sum+=w[i]*fn[i];
271  }
272  fn[lm]=2*(*f)(xm); sum+=w[lm]*fn[lm];
273  }
274  }
275 
276  lm++; rc=4*0.15; eps=0.05/(0.5*rc); /* Causes subdivision if first eps>0.05 */
277  do {
278  sum0=sum;
279  iter++; x=xptr[iter]-lm; w=wptr[iter]; rc*=0.5;
280  for (i=0, sum=0; i<lm; i++) sum+=w[i]*fn[i];
281  if (root) {
282  if (f_r) {
283  for (i=lm; i<=num; i++) {
284  double z1=1+x[i], z2=1-x[i];
285 
286  fn[i]=(*f_r)(c+root*sqr(z1*xs1+z2*xs2), fdata)+
287  (*f_r)(c+root*sqr(z1*xs2+z2*xs1), fdata);
288  sum+=w[i]*fn[i];
289  }
290  } else {
291  for (i=lm; i<=num; i++) {
292  double z1=1+x[i], z2=1-x[i];
293 
294  fn[i]=(*f)(c+root*sqr(z1*xs1+z2*xs2))+
295  (*f)(c+root*sqr(z1*xs2+z2*xs1));
296  sum+=w[i]*fn[i];
297  }
298  }
299  } else {
300  if (f_r) {
301  for (i=lm; i<=num; i++) {
302  dx=xr*x[i]; fn[i]=(*f_r)(xm-dx, fdata)+(*f_r)(xm+dx, fdata);
303  sum+=w[i]*fn[i];
304  }
305  } else {
306  for (i=lm; i<=num; i++) {
307  dx=xr*x[i]; fn[i]=(*f)(xm-dx)+(*f)(xm+dx);
308  sum+=w[i]*fn[i];
309  }
310  }
311  }
312 
313  eps0=eps; lm=num+1; num=2*num+1;
314  if (sum) eps=1e-16+fabs((sum0-sum)/sum); else eps=1;
315  r=eps/eps0; if (I0) epst=fabs(xr*(sum-sum0)/I0); else epst=eps;
316 
317  /* Now estimate the true error from the local convergence rate. */
318  if (iter>1) epst*=3*(r<1e-4 ? 1e-4 : r>1 ? 1 : r);
319 
320  /* If we're being ultraconservative, see if three successive values agree */
321  if (paranoid) {
322  if (I0)
323  looks_ok=(fabs(xr*(sum_1-sum0))<=acc1*fabs(I0) &&
324  fabs(xr*(sum0-sum))<=acc1*fabs(I0) &&
325  fabs(xr*(sum_1-sum))<=acc1*fabs(I0));
326  else
327  looks_ok=(fabs(sum_1-sum0)<=acc1*fabs(sum0) &&
328  fabs(sum0-sum)<=acc1*fabs(sum) &&
329  fabs(sum_1-sum)<=acc1*fabs(sum));
330  sum_1=sum0;
331  }
332 
333  /* Subdivide if convergence too slow or final iteration before forced
334  subdivision looks like it won't achieve accuracy goal. */
335  if (r>rc || (iter==MAXIT-1 && epst*0.5*r>acc1)) {
336  if (iter==1) epst*=3; /* First iter looks iffy, be more conservative. */
337  break;
338  }
339  } while (((!looks_ok && epst<acc1) || (sum0!=sum && epst>acc1))
340  && iter!=MAXIT);
341 
342  if (sum0==sum) epst=1e-16;
343  if (!looks_ok || epst>acc1)
344  if (lev<maxrecur && a!=xm) {
345  if (I0==0 && epst<0.1) I0=xr*sum;
346  /* main pass failed, so bias toward several small intervals with
347  small maxiter, use estimate of integral I0 (if any good at all)
348  to ensure each subinterval computed only as accurately as needed.
349  */
350  if (root) {
351  integ_data_t data;
352  data.func = f_r;
353  data.fdata = fdata;
354  data.c = c;
355 
356  if (root<0) {
357  return(kgauss_sub(hifn, hifn_r, &data, a, xm, c,
358  acc, 0, lev+1, I0, maxrecur, paranoid)+
359  kgauss_sub(f, f_r, fdata, xm, b, c,
360  acc, -1, lev+1, I0, maxrecur, paranoid));
361  } else {
362  return(kgauss_sub(lofn, lofn_r, &data, 2*c-xm, 2*c-a, c,
363  acc, 0, lev+1, I0,maxrecur, paranoid)+
364  kgauss_sub(f, f_r, fdata, xm, b, c,
365  acc, 1, lev+1, I0, maxrecur, paranoid));
366  }
367  } else
368  return(kgauss_sub(f, f_r, fdata, a, xm, c,
369  acc, 0, lev+1, I0, maxrecur, paranoid)+
370  kgauss_sub(f, f_r, fdata, xm, b, c,
371  acc, 0, lev+1, I0, maxrecur, paranoid));
372  } else {
373  if (*acc>0 && first) {
374  fprintf(stderr, "Precision not met in kgauss (%.1e/%.1e) in "
375  "[%.12g,%.12g]\n", epst, acc1, xm-0.5*(b-a), xm+0.5*(b-a));
376  first=0;
377  }
378  if (lev==0) *acc=(-epst);
379  }
380  else if (lev==0) *acc=epst;
381  return(xr*sum);
382 }
383 
384 double kgauss(double (*f)(double x), double a, double b, double err)
385 {
386  return(kgauss_sub(f, NULL, NULL, a, b, 0.0, &err, 0, 0, 0., 100, 0));
387 }
388 
389 double kgauss2(double (*f)(double x), double a, double b, double err)
390 {
391  return(kgauss_sub(f, NULL, NULL, a, b, 0.0, &err, 0, 0, 0., 100, 1));
392 }
393 
394 double ksqrtgauss(double (*f)(double x), double a, double b, double c,
395  double err)
396 {
397  /* Integrate f(x)/sqrt(x-c) or f(x)/sqrt(c-x) between arbitrary limits. */
398  int sgn;
399 
400  func_gl=f; c_gl=c;
401  if (a>b) { double tmp=a; a=b; b=tmp; sgn=-1; } else sgn=1;
402  if (a>=c)
403  return(sgn*kgauss_sub(f, NULL, NULL, 2*c-b, 2*c-a, c,
404  &err, 1, 0, 0., 100, 0));
405  else if (b<=c)
406  return(sgn*kgauss_sub(f, NULL, NULL, a, b, c,
407  &err, -1, 0, 0., 100, 0));
408  else
409  return(NAN);
410 }
411 
412 double kgauss_r(double (*f_r)(double x, void *), void *fdata,
413  double a, double b, double err)
414 {
415  return(kgauss_sub(NULL, f_r, fdata, a, b, 0.0, &err, 0, 0, 0., 100, 0));
416 }
417 
418 double kgauss2_r(double (*f_r)(double x, void *), void *fdata,
419  double a, double b, double err)
420 {
421  return(kgauss_sub(NULL, f_r, fdata, a, b, 0.0, &err, 0, 0, 0., 100, 1));
422 }
423 
424 double ksqrtgauss_r(double (*f_r)(double x, void *), void *fdata,
425  double a, double b, double c, double err)
426 {
427  /* Integrate f(x)/sqrt(x-c) or f(x)/sqrt(c-x) between arbitrary limits. */
428  int sgn;
429 
430  if (a>b) { double tmp=a; a=b; b=tmp; sgn=-1; } else sgn=1;
431  if (a>=c)
432  return(sgn*kgauss_sub(NULL, f_r, fdata, 2*c-b, 2*c-a, c,
433  &err, 1, 0, 0., 100, 0));
434  else if (b<=c)
435  return(sgn*kgauss_sub(NULL, f_r, fdata, a, b, c,
436  &err, -1, 0, 0., 100, 0));
437  else
438  return(NAN);
439 }
440 
441 } // namespace mutils
double ksqrtgauss_r(double(*f_r)(double x, void *), void *fdata, double a, double b, double c, double err)
Definition: kgauss.cc:424
static double hifn_r(double x, void *vdata)
Definition: kgauss.cc:50
double kgauss_sub(double(*f)(double x), double(*f_r)(double x, void *), void *fdata, double a, double b, double c, double *acc, int root, int lev, double I0, int maxrecur, int paranoid)
Definition: kgauss.cc:67
static double c_gl
Definition: kgauss.cc:31
static double hifn(double x)
Definition: kgauss.cc:33
double(* func)(double, void *)
Definition: kgauss.cc:45
static double lofn_r(double x, void *vdata)
Definition: kgauss.cc:58
double kgauss2_r(double(*f_r)(double x, void *), void *fdata, double a, double b, double err)
Definition: kgauss.cc:418
MathUtils package.
Definition: CommandLine.cc:10
double kgauss(double(*f)(double x), double a, double b, double err)
Definition: kgauss.cc:384
static double(* func_gl)(double x)
Definition: kgauss.cc:31
static double lofn(double x)
Definition: kgauss.cc:38
#define MAXIT
Definition: kgauss.cc:29
double kgauss2(double(*f)(double x), double a, double b, double err)
Definition: kgauss.cc:389
double ksqrtgauss(double(*f)(double x), double a, double b, double c, double err)
Definition: kgauss.cc:394
double kgauss_r(double(*f_r)(double x, void *), void *fdata, double a, double b, double err)
Definition: kgauss.cc:412
R sqr(R x)
Definition: kgauss.cc:26