V3FIT
point_wise_to_power.f
1  SUBROUTINE point_wise_to_power(npts, x, f, n, ac, i_full,
2  1 nsp_pts)
3  USE stel_kinds
4  IMPLICIT NONE
5 !-----------------------------------------------
6 ! D u m m y A r g u m e n t s
7 !-----------------------------------------------
8  INTEGER, INTENT(IN) :: npts, i_full, nsp_pts, n
9  REAL(rprec), DIMENSION(npts), INTENT(IN) :: x, f
10  REAL(rprec), DIMENSION(0:n), INTENT(OUT) :: ac
11 !-----------------------------------------------
12  REAL, PARAMETER :: tol_res = 0.005_dp
13  INTEGER :: i, j, k , n_count, n_int
14  CHARACTER(len=2) :: cdum
15  CHARACTER(len=15) :: form
16  REAL(rprec) :: res, ohs_sp
17  REAL(rprec), DIMENSION(:), ALLOCATABLE :: tc, norm, y,
18  1 fy, y_sp, fy_sp
19  REAL(rprec), DIMENSION(:,:), ALLOCATABLE :: a_inv, b_inv,
20  1 a, b, inorm, tleg
21 !-----------------------------------------------
22 ! E x t e r n a l F u n c t i o n s
23 !-----------------------------------------------
24  REAL(rprec) , EXTERNAL :: integral
25 !--------------------------------------------------------------------------------
26 ! MEANING OF ARGUMENTS:
27 ! NPTS = number of points where the point-wise function is given
28 ! X = independent variable values for these points in [0,1]
29 ! F = dependent variable values on the X points
30 ! N = input number, 0:n, of Legendre polynomials used in the expansion
31 ! N_INT = actual computed number, 0:N_INT
32 ! AC = final power series coefficients in x ([0,1])
33 ! I_FULL =0, if input data on full mesh; =1, if on half mesh
34 ! NSP_PTS = number of points for the spline fit of F on the half mesh.
35 !--------------------------------------------------------------------------------
36 !
37 ! ABSTRACT:
38 ! Conversion of a point-wise solution in [0,1] given on a discrete set
39 ! of NPTS radial points (either on the half or the full mesh, see below)
40 ! first to an expansion in Legendre polynomials in [-1,1] via:
41 !
42 ! F = sum_m=0^N <F,P_m>/<P_m,P_m> <f,g> == int_[-1,1] f(x)g(x)dx
43 !
44 ! and defining the Legendre coefficient vector TC as:
45 !
46 ! TC = {<F,P_m>/<P_m,P_m>, m=1, N}
47 !
48 ! Then calculates the equivalent power series coefficients vector in
49 ! [0,1], AC:
50 !
51 ! AC = TC*A_inv*B_inv
52 !
53 ! The value of Legendre Polynomials used "N" depends CRITICALLY on the
54 ! number of points NPTS in the discrete data set of the incoming point-wise
55 ! solution. Because if the integrals are evaluated using these points, the
56 ! wiggles in the polynomial may not be well sampled by the existing set of
57 ! points and may cause deviations of the ortogonality condition:
58 !
59 ! <P_m,P_n> = 2/(2*n+1)* delta_{mn}
60 !
61 ! This makes the reconstruction deteriorate quickly for increasing "N".
62 ! To avoid this, the incoming data values are splined to a number of points
63 ! NSP_PTS on a half-like mesh using Hermite cubic splines. Then, the
64 ! value of "N" is chosen requiring:
65 !
66 ! | 1- .5*(2*n+1)*<P_N,P_n> | < TOL_RES
67 !
68 ! TOL_RES is prescribed to be <= .5%. Until this condition is achieved, "N" is
69 ! subsequently reduced. If "N" gets equal to 2 in this reduction, the
70 ! calculation is stopped and an error message issued.
71 !
72 ! WARNING: The point-wise solution MAY BE given on the half mesh or full mesh
73 ! of a equally spaced radial grid, that is:
74 !
75 ! ***I_FULL = 1 beginning with x(3/2) and finishing with x(M-1/2), where
76 ! x(1) = 0. and x(M) = 1.
77 ! ***I_FULL = 0 beginning with x(1) = 0. and finishing with x(M) = 1.
78 !
79 !--------------------------------------------------------------------------------
80 
81  ac = 0
82  res = 1
83 
84 !... Map [0,1] to [-1,1]
85 
86  ALLOCATE (y(npts), fy(npts),
87  1 y_sp(nsp_pts), fy_sp(nsp_pts), stat=i)
88  IF (i .ne. 0) stop 'Allocation error in point_wise_to_power!'
89 
90  y(:npts) = 2*x(:npts) - 1
91  fy(:npts) = f(:npts)
92  IF (i_full .eq. 1) fy(1)= fy(2)
93 
94 !... i_full = 0 IF FY given on the full mesh, and =1 IF on the half mesh.
95 ! FY is splined on nsp_pts on the half_mesh
96 
97  ohs_sp = 2._dp/nsp_pts
98  y_sp= (/( -1 + (i -0.5_dp)*ohs_sp, i = 1,nsp_pts)/)
99 
100  CALL spline_it(npts, y, fy, nsp_pts, y_sp, fy_sp, i_full)
101 
102 !... Determine number of Legendre Polynomials to be used
103 
104  n_count = 0
105  DO WHILE(res .gt. tol_res)
106  n_int = n - n_count
107  IF(n_int < n) DEALLOCATE (a, b, a_inv, b_inv, tleg,
108  1 inorm, norm)
109  ALLOCATE(a(0:n_int,0:n_int), b(0:n_int,0:n_int),
110  1 a_inv(0:n_int,0:n_int), b_inv(0:n_int,0:n_int),
111  2 tleg(0:n_int, nsp_pts), inorm(0:n_int,0:n_int),
112  3 norm(0:n_int), stat=i)
113  IF (i .ne. 0) stop 'Allocation error in point_wise_to_power!'
114 
115  norm(0:n_int) = (/(2._dp/(2*i+1), i=0, n_int)/)
116 
117  CALL build_matrices_legendre (n_int, a, b, a_inv, b_inv)
118 
119 !... Build Initial Legendre polynomials on grid
120 
121  DO i = 0, n_int
122  tleg(i,:nsp_pts) = 0
123  DO k = n_int, 0, -1
124  tleg(i,:nsp_pts) = a_inv(i,k) + y_sp(:nsp_pts)
125  1 * tleg(i,:nsp_pts)
126  END DO
127  END DO
128 
129 !... Compute orthogonality and norms
130 
131  DO j = 0, n_int
132  DO i = 0, n_int
133  inorm(i,j) = integral(nsp_pts, y_sp, tleg(j,1:nsp_pts),
134  1 tleg(i,1:nsp_pts))
135  END DO
136  WRITE(cdum,'(i2)')n_int+1
137  cdum = adjustl(cdum)
138  form = '('//trim(cdum)//'(x,f8.3))'
139  form = adjustl(form)
140 ! WRITE(20,TRIM(form)) (inorm(i,j), i=0, n)
141  END DO
142 
143 !... Compute residual. If res > tol_res, reduce N and iterate while loop
144 
145  res = abs((norm(n_int) - inorm(n_int,n_int))/(norm(n_int)))
146  n_count = n_count + 1
147  IF(n_count == n-1) stop 'Precision bad for even 2 Polynomial'
148 
149  END DO
150 
151  ALLOCATE(tc(0:n_int))
152  DO j = 0, n_int
153  tc(j) = integral(nsp_pts, y_sp, fy_sp, tleg(j,1:nsp_pts))
154  1 /norm(j)
155  END DO
156 
157 !
158 ! FIND ac COEFFICIENTS, 0:n_int; IF n_int < n, ac(n_int:n) = 0
159 !
160  CALL legendre_to_power(n_int, a_inv, b_inv, tc, ac(0))
161 
162  DEALLOCATE(a_inv, b_inv, a, b, tc, tleg, inorm, norm, y,
163  1 fy, y_sp, fy_sp)
164 
165  END SUBROUTINE point_wise_to_power