xref: /petsc/src/dm/tutorials/ex26.c (revision af2269012df9f78a2e64b5a712f72d93507752c9)
1 static char help[] = "Calculates moments for Gaussian functions.\n\n";
2 
3 #include <petscviewer.h>
4 #include <petscdt.h>
5 #include <petscvec.h>
6 
7 #include <gsl/gsl_sf_hermite.h>
8 #include <gsl/gsl_randist.h>
9 
10 int main(int argc, char **argv)
11 {
12   int            s,n = 15;
13   PetscInt       tick, moment = 0,momentummax = 7;
14   PetscReal      *zeros,*weights,scale,h,sigma = 1/sqrt(2), g = 0, mu = 0;
15 
16   PetscFunctionBeginUser;
17   PetscCall(PetscInitialize(&argc,&argv,NULL,help));
18 
19   PetscCall(PetscOptionsGetInt(NULL,NULL,"-n",&n,NULL));
20   PetscCall(PetscOptionsGetInt(NULL,NULL,"-moment_max",&momentummax,NULL));
21   PetscCall(PetscOptionsGetReal(NULL,NULL,"-sigma",&sigma,NULL));
22   PetscCall(PetscOptionsGetReal(NULL,NULL,"-mu",&mu,NULL));
23 
24   /* calulate zeros and roots of Hermite Gauss quadrature */
25   PetscCall(PetscMalloc1(n,&zeros));
26   zeros[0] = 0;
27   tick = n % 2;
28   for (s=0; s<n/2; s++) {
29     zeros[2*s+tick]   =  -gsl_sf_hermite_zero(n,s+1);
30     zeros[2*s+1+tick] =  gsl_sf_hermite_zero(n,s+1);
31   }
32 
33   PetscCall(PetscDTFactorial(n, &scale));
34   scale = exp2(n-1)*scale*PetscSqrtReal(PETSC_PI)/(n*n);
35   PetscCall(PetscMalloc1(n+1,&weights));
36   for (s=0; s<n; s++) {
37     h          = gsl_sf_hermite(n-1, (double) zeros[s]);
38     weights[s] = scale/(h*h);
39   }
40   /* zeros and weights verfied up to n = 5 with http://mathworld.wolfram.com/Hermite-GaussQuadrature.html */
41 
42   for (moment=0; moment<momentummax; moment++) {
43 
44     /* http://www.wouterdenhaan.com/numerical/integrationslides.pdf */
45     /* https://en.wikipedia.org/wiki/Gauss-Hermite_quadrature */
46     /*
47        int_{-infinity}^{infinity} \frac{1}{sigma sqrt(2pi)} exp(- \frac{(x - mu)^2}{2 sigma^2) h(x) dx
48 
49        then approx equals 1/pi sum_i w_i h( sqrt(2) sigma x_i + mu)
50     */
51     g = 0;
52     for (s=0; s<n; s++) {
53       g += weights[s]*PetscPowRealInt(sqrt(2)*sigma*zeros[s] + mu,moment);
54     }
55     g /= sqrt(PETSC_PI);
56     /* results confirmed with https://en.wikipedia.org/wiki/Normal_distribution#Moments sigma^p * (p-1)!!*/
57     PetscCall(PetscPrintf(PETSC_COMM_WORLD,"Moment %" PetscInt_FMT " %g \n",moment,(double)g));
58 
59   }
60   PetscCall(PetscFree(zeros));
61   PetscCall(PetscFree(weights));
62   PetscCall(PetscFinalize());
63   return 0;
64 }
65 
66 /*TEST
67 
68   build:
69     requires: gsl double
70 
71   test:
72 
73 TEST*/
74