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