VMEC 8.52
3D Equilibrium solver with nested flux surfaces.
Loading...
Searching...
No Matches
profil3d.f90
Go to the documentation of this file.
1
3
9SUBROUTINE profil3d(rmn, zmn, lreset)
10 USE vmec_main
11 USE vmec_params
12 USE realspace
13 USE xstuff
14
15 use dbgout
16
17 IMPLICIT NONE
18
19 REAL(rprec), DIMENSION(ns,0:ntor,0:mpol1,ntmax), INTENT(inout) :: rmn, zmn
20 LOGICAL, INTENT(in) :: lreset
21
22 INTEGER :: js, l, lk, lt, lz, ntype, m, n, mn
23 REAL(rprec), DIMENSION(0:ntor,ntmax) :: rold, zold
24 REAL(rprec) :: sm0, t1, facj, si, rax1, zax1
25 INTEGER :: jcount, jk, k
26
27! profil3d_calls = profil3d_calls + 1
28
29 ! expant to full surface grid
30 DO js = 1, ns
31 phip(js:nrzt:ns) = phips(js)
32 chip(js:nrzt:ns) = chips(js)
33 END DO
34
35 phip(nrzt+1) = 0.0_dp
36 faclam = 0.0_dp
37 wint(1:nrzt:ns) = 0.0_dp
38
39 lk = 0
40 DO lt = 1, ntheta3
41 DO lz = 1, nzeta
42 lk = lk + 1
43 DO js=2,ns
44 wint(js+ns*(lk-1)) = cosmui3(lt,0)/mscale(0)
45 END DO
46 END DO
47 END DO
48
49 ! COMPUTE ARRAY FOR REFLECTING v = -v (ONLY needed for lasym)
50 jcount = 0
51 DO k = 1, nzeta
52 jk = nzeta + 2 - k ! (nzeta+1) - (k-1)
53 IF (k .eq. 1) jk = 1
54 DO js = 1,ns
55 jcount = jcount+1
56 ! Index for 2pi-zeta[k]
57 ireflect(jcount) = js+ns*(jk-1)
58 ENDDO
59 END DO
60
61 ! INDEX FOR u = -u (need for lasym integration in wrout)
62 lk = 0
63 IF (.NOT.ALLOCATED(uminus)) ALLOCATE (uminus(nznt))
64 DO lt = 1, ntheta2
65 k = ntheta1-lt+2 ! (ntheta1+1) - (lt-1)
66 IF (lt .eq. 1) then
67 ! u=-0 => u=0
68 k = 1
69 end if
70 DO lz = 1, nzeta
71 lk = lk + 1
72 ! (-u), for u = 0,pi
73 uminus(lk) = k
74 END DO
75 END DO
76
77 ! COMPUTE INITIAL R AND Z FOURIER COEFFICIENTS FROM SCALED BOUNDARY VALUES
78 ! AND
79 ! SCALXC ARRAY (1/SQRTS FACTOR FOR ODD M VALUES)
80
81 ! print *, "initial guess for R_mn, Z_mn in profil3d"
82
83! write(*,*) "raxis_cc(0)=",raxis_cc(0)
84! DO m = 0, mpol1
85! DO n = 0, ntor
86! if (abs(rmn_bdy(n,m,rcc)) .gt. 1.0e-12_dp) then
87! write(*,*) n, m, rmn_bdy(n,m,rcc)
88! end if
89! if (abs(zmn_bdy(n,m,zcs)) .gt. 1.0e-12_dp) then
90! write(*,*) n, m, zmn_bdy(n,m,zcs)
91! end if
92! end do
93! end do
94
95 DO js = 1, ns
96
97 si = sqrts(js)*sqrts(js) ! s(js) --> ==1 at boundary
98 sm0 = one - si ! 1-s(js) --> ==1 at magn. axis
99
100 DO ntype = 1, ntmax
101 DO m = 0, mpol1
102 DO n = 0, ntor
103
104
105 !-----------------------!
106 ! compute scalxc(js, m) !
107 !-----------------------!
108 mn = n + ntor1*m ! linear index over Fourier modes
109 l = js + ns*mn + (ntype - 1)*mns ! linear index over all Fourier coefficents on all surfaces
110 IF (mod(m,2) .eq. 0) THEN
111 ! m is even
112 scalxc(l) = one
113 ELSE
114 ! m is odd
115
116 ! make sure to use at least sqrts(2)==1/(ns-1) as normalization/scaling factor,
117 ! since sqrts(1)==0 (see profil1d)
118 scalxc(l) = one/max(sqrts(js), sqrts(2))
119 ENDIF
120
121
122
123 ! ----------------------------------------------------------!
124 ! extrapolate R_mn, Z_mn from axis and boundary into volume !
125 ! ----------------------------------------------------------!
126 t1 = one/(mscale(m)*nscale(n)) ! --> divide out mscale, nscale from user input
127
128 ! Do not overwrite r,z if read in from wout file AND in free bdy mode
129 ! For fixed boundary, edge values MAY have been perturbed, so must execute this loop
130 IF (.not.lreset .and. lfreeb) cycle
131 ! == execute what is below if (lreset .or. .not. lfreeb)
132
133 ! below code segment does the extrapolation
134 ! of the boundary Fourier coefficients into the plasma volume
135
136 IF (m .eq. 0) THEN
137
138 IF (.not.lreset) cycle !Freeze axis if read in from wout file
139 ! above instruction cycles all n for m=0 --> skip axis, as said above!
140 ! == execute what is below if (lreset)
141 ! --> m=0 contributions only get updated if lreset == true
142
143 ! subtraction of the edge value of rmn, zmn is probably left-over
144 ! from the restart feature from a previous wout file
145 !if (abs(rmn(ns,n,m,ntype)) .ne. zero) then
146 ! print *, "spurious remnant in rmn: ", rmn(ns,n,m,ntype)
147 if (abs(rmn(js,n,m,ntype)) .ne. zero) then
148 print *, "spurious remnant in rmn: ", rmn(js,n,m,ntype)
149 stop
150 end if
151 !if (abs(zmn(ns,n,m,ntype)) .ne. zero) then
152 ! print *, "spurious remnant in zmn: ", zmn(ns,n,m,ntype)
153 if (abs(zmn(js,n,m,ntype)) .ne. zero) then
154 print *, "spurious remnant in zmn: ", zmn(js,n,m,ntype)
155 stop
156 end if
157 !rmn(js,n,m,ntype) = rmn(js,n,m,ntype) + si*(rmn_bdy(n,m,ntype)*t1 - rmn(ns,n,m,ntype))
158 !zmn(js,n,m,ntype) = zmn(js,n,m,ntype) + si*(zmn_bdy(n,m,ntype)*t1 - zmn(ns,n,m,ntype))
159
160 ! first contribution: boundary scaled into volume
161 rmn(js,n,m,ntype) = si * rmn_bdy(n,m,ntype)*t1
162 zmn(js,n,m,ntype) = si * zmn_bdy(n,m,ntype)*t1
163
164 !IF (js .eq. 1) THEN
165 ! ! rold, zold will be subtracted
166 ! ! --> this zeroes out any contribution as extrapolated from the boundary ?
167 ! ! since js=1 is handled first, this gets assigned once and is available then
168 ! ! on the other hand, there should be nothing in here (as checked in above spurious... tests)
169 ! ! --> ignore!
170 ! ! --> also for js=1, there is no contribution from above, since si=0 for js=1 !
171 ! rold(n,ntype) = rmn(1,n,0,ntype)
172 ! zold(n,ntype) = zmn(1,n,0,ntype)
173 !
174 ! if (abs(rold(n,ntype)) .ne. zero) then
175 ! print *, "remnant in rold: ", rold(n,ntype)
176 ! stop
177 ! end if
178 !
179 ! if (abs(zold(n,ntype)) .ne. zero) then
180 ! print *, "remnant in zold: ", zold(n,ntype)
181 ! stop
182 ! end if
183 !
184 !ENDIF
185
186 ! second contribution: axis scaled towards boundary
187 IF (ntype .eq. rcc) rax1 = raxis_cc(n)
188 IF (ntype .eq. rcs) rax1 =-raxis_cs(n)
189 IF (ntype.eq.rcc .or. ntype.eq.rcs) THEN
190 !rmn(js,n,m,ntype) = rmn(js,n,m,ntype) + sm0*(rax1*t1 - rold(n,ntype))
191 rmn(js,n,m,ntype) = rmn(js,n,m,ntype) + sm0 * rax1*t1
192 END IF
193
194 IF (ntype .eq. zcs) zax1 =-zaxis_cs(n)
195 IF (ntype .eq. zcc) zax1 = zaxis_cc(n)
196 IF (ntype.eq.zcs .or. ntype.eq.zcc) THEN
197 !zmn(js,n,m,ntype) = zmn(js,n,m,ntype) + sm0*(zax1*t1 - zold(n,ntype))
198 zmn(js,n,m,ntype) = zmn(js,n,m,ntype) + sm0 * zax1*t1
199 END IF
200
201 ELSE ! m != 0
202 ! TURN OFF BELOW LINES IF THIS ONE ACTIVATED
203 facj = sqrts(js)**m
204
205 ! IF (MOD(m,2) .eq. 0) THEN
206 ! facj = sqrts(js)*sqrts(js)
207 ! ELSE IF (MOD(m,2) .eq. 1) THEN
208 ! facj = sqrts(js)**MIN(m,3)
209 ! END IF
210
211 ! subtraction of the edge value of rmn, zmn is probably left-over
212 ! from the restart feature from a previous wout file
213 !if (abs(rmn(ns,n,m,ntype)) .ne. zero) then
214 ! print *, "spurious remnant in rmn: ", rmn(ns,n,m,ntype)
215 if (abs(rmn(js,n,m,ntype)) .ne. zero) then
216 print *, "spurious remnant in rmn: ", rmn(js,n,m,ntype)
217 stop
218 end if
219 !if (abs(zmn(ns,n,m,ntype)) .ne. zero) then
220 ! print *, "spurious remnant in zmn: ", zmn(ns,n,m,ntype)
221 if (abs(zmn(js,n,m,ntype)) .ne. zero) then
222 print *, "spurious remnant in zmn: ", zmn(js,n,m,ntype)
223 stop
224 end if
225 !rmn(js,n,m,ntype) = rmn(js,n,m,ntype) + (rmn_bdy(n,m,ntype)*t1 - rmn(ns,n,m,ntype))*facj
226 !zmn(js,n,m,ntype) = zmn(js,n,m,ntype) + (zmn_bdy(n,m,ntype)*t1 - zmn(ns,n,m,ntype))*facj
227
228 rmn(js,n,m,ntype) = facj * rmn_bdy(n,m,ntype)*t1
229 zmn(js,n,m,ntype) = facj * zmn_bdy(n,m,ntype)*t1
230 ENDIF
231
232
233
234 END DO
235 END DO
236 END DO
237 END DO
238
239 ! distribute scalxc content from R to Z components
241
242 ! distribute scalxc content from R to Lamda components
244
245 ! dump all relevant output to a text file
246 if (open_dbg_context("profil3d", num_eqsolve_retries)) then
247
248 call add_real_3d("scalxc", ns, ntor1, mpol, scalxc(:irzloff))
249 call add_real_4d("rmn", ntmax, ns, ntor1, mpol, rmn, order=(/ 2, 3, 4, 1 /) )
250 call add_real_4d("zmn", ntmax, ns, ntor1, mpol, zmn, order=(/ 2, 3, 4, 1 /) )
251
252 call close_dbg_out()
253 end if
254
255END SUBROUTINE profil3d
logical function open_dbg_context(context_name, repetition, id)
check if any output is desired for the current iteration check if the given context should be openend...
Definition dbgout.f90:17
real(rprec), dimension(:), allocatable wint
two-dimensional array for normalizing angle integrations
Definition realspace.f90:34
real(rprec), dimension(:), allocatable sqrts
sqrt(s), two-dimensional array on full-grid
Definition realspace.f90:32
real(rprec), dimension(:), allocatable chip
radial derivative of chi/(2*pi) on half-grid
Definition realspace.f90:30
real(rprec), dimension(:), allocatable phip
radial derivative of phi/(2*pi) on half-grid
Definition realspace.f90:29
integer irzloff
offset in xc array between R,Z,L components
real(rprec), dimension(:,:,:,:), allocatable faclam
Definition vmec_main.f90:28
real(rprec), dimension(:), allocatable chips
poloidal flux (same as chip), one-dimensional array
Definition vmec_main.f90:67
real(rprec), dimension(:,:,:), allocatable, target zmn_bdy
real(rprec), dimension(:,:,:), allocatable, target rmn_bdy
integer num_eqsolve_retries
integer, dimension(:), allocatable ireflect
two-dimensional array for computing 2pi-v angle
real(rprec), dimension(:), allocatable phips
toroidal flux (same as phip), one-dimensional array
Definition vmec_main.f90:68
real(rprec), dimension(:), allocatable mscale
array for norming theta-trig functions (internal use only) so that the discrete SUM[cos(mu)*cos(m'u)]...
integer, dimension(:), allocatable uminus
real(rprec), dimension(:), allocatable nscale
array for norming zeta -trig functions (internal use only)
integer ntmax
number of contributing Fourier basis function (can be 1, 2 or 4); assigned in read_indata()
real(rprec), dimension(:), allocatable scalxc
Definition xstuff.f90:50
subroutine profil3d(rmn, zmn, lreset)
Compute three-dimensional profiles of flux-surface geometry etc.
Definition profil3d.f90:10