VMEC 8.52
3D Equilibrium solver with nested flux surfaces.
Loading...
Searching...
No Matches
guess_axis.f90
Go to the documentation of this file.
1
3
10SUBROUTINE guess_axis(r1, z1, ru0, zu0)
11 USE vmec_main
12 USE vmec_params, ONLY: nscale, signgs
13 USE realspace, ONLY: sqrts
14
15 use dbgout
16
17 IMPLICIT NONE
18
19 REAL(rprec), DIMENSION(ns,nzeta,ntheta3,0:1), INTENT(in) :: r1, z1
20 REAL(rprec), DIMENSION(ns,nzeta,ntheta3), INTENT(in) :: ru0, zu0
21
22 INTEGER, PARAMETER :: limpts = 61
23 REAL(rprec), PARAMETER :: p5 = 0.5_dp, two = 2.0_dp
24
25 INTEGER :: iv, iu, iu_r, ivminus, nlim, ns12, klim, n
26! REAL(rprec), DIMENSION(nzeta) :: rcom, zcom
27! REAL(rprec), DIMENSION(nzeta,ntheta1) :: r1b, z1b, rub, zub
28! REAL(rprec), DIMENSION(nzeta,ntheta1) :: r12, z12
29! REAL(rprec), DIMENSION(nzeta,ntheta1) :: rs, zs, tau, ru12, zu12, tau0
30
31 REAL(rprec), DIMENSION(:), allocatable :: rcom, zcom
32 REAL(rprec), DIMENSION(:,:), allocatable :: r1b, z1b, rub, zub
33 REAL(rprec), DIMENSION(:,:), allocatable :: r12, z12
34 REAL(rprec), DIMENSION(:,:), allocatable :: rs, zs, tau, ru12, zu12, tau0
35
36 REAL(rprec) :: rlim, zlim
37 REAL(rprec) :: rmax, rmin, zmax, zmin, dzeta
38 REAL(rprec) :: ds, mintau, mintemp
39
40 integer :: ivmax
41
42 if (.not.lasym) then
43 ivmax = nzeta/2+1
44 else
45 ivmax = nzeta
46 end if
47
48 allocate(rcom(nzeta))
49 allocate(zcom(nzeta))
50
51 allocate(r1b(nzeta,ntheta1)); r1b = cbig
52 allocate(z1b(nzeta,ntheta1)); z1b = cbig
53 allocate(rub(nzeta,ntheta1)); rub = cbig
54 allocate(zub(nzeta,ntheta1)); zub = cbig
55 allocate(r12(nzeta,ntheta1)); r12 = cbig
56 allocate(z12(nzeta,ntheta1)); z12 = cbig
57 allocate(rs(nzeta,ntheta1)); rs = cbig
58 allocate(zs(nzeta,ntheta1)); zs = cbig
59 allocate(tau(nzeta,ntheta1)); tau = cbig
60 allocate(ru12(nzeta,ntheta1)); ru12 = cbig
61 allocate(zu12(nzeta,ntheta1)); zu12 = cbig
62 allocate(tau0(nzeta,ntheta1)); tau0 = cbig
63
64 ! COMPUTES GUESS FOR MAGNETIC AXIS IF USER GUESS
65 ! LEADS TO INITIAL SIGN CHANGE OF JACOBIAN. DOES A GRID
66 ! SEARCH (irgrid, izgrid) IN EACH PHI-PLANE FOR POINTS WHICH
67 ! YIELD A VALUE FOR THE JACOBIAN WITH THE CORRECT SIGN (SIGNGS)
68 ! CHOOSES THE AXIS POSITION SO THE MIN VALUE OF THE JACOBIAN IS MAXIMIZED
69
70 ns12 = (ns+1)/2
71
72 planes: DO iv = 1, nzeta/2+1
73
74 r1b(iv,:ntheta3) = r1(ns,iv,:,0) + r1(ns,iv,:,1)
75 z1b(iv,:ntheta3) = z1(ns,iv,:,0) + z1(ns,iv,:,1)
76
77 r12(iv,:ntheta3) = r1(ns12,iv,:,0) + r1(ns12,iv,:,1)*sqrts(ns12)
78 z12(iv,:ntheta3) = z1(ns12,iv,:,0) + z1(ns12,iv,:,1)*sqrts(ns12)
79
80 rub(iv,:ntheta3) = ru0(ns,iv,:)
81 zub(iv,:ntheta3) = zu0(ns,iv,:)
82
83 ru12(iv,:ntheta3) = p5*(ru0(ns,iv,:) + ru0(ns12,iv,:))
84 zu12(iv,:ntheta3) = p5*(zu0(ns,iv,:) + zu0(ns12,iv,:))
85
86 IF (.not.lasym) THEN
87
88 ! USE Z(v,-u) = -Z(twopi-v,u), R(v,-u) = R(twopi-v,u)
89 ! TO DO EXTEND R,Z, etc. OVER ALL THETA (NOT JUST 0,PI)
90
91 ! (twopi-v)
92 ivminus = mod(nzeta - (iv - 1), nzeta) + 1
93 DO iu = 1+ntheta2, ntheta1
94 iu_r = ntheta1 + 2 - iu ! (ntheta1 + 1) - (iu - 1)
95
96 r1b(iv,iu) = r1(ns, ivminus,iu_r,0) + r1( ns, ivminus,iu_r,1)
97 z1b(iv,iu) =-( z1(ns, ivminus,iu_r,0) + z1( ns, ivminus,iu_r,1))
98 rub(iv,iu) =- ru0(ns, ivminus,iu_r)
99 zub(iv,iu) = zu0(ns, ivminus,iu_r)
100
101 r12(iv,iu) = r1(ns12,ivminus,iu_r,0) + r1( ns12,ivminus,iu_r,1)*sqrts(ns12)
102 z12(iv,iu) =-( z1(ns12,ivminus,iu_r,0) + z1( ns12,ivminus,iu_r,1)*sqrts(ns12))
103 ru12(iv,iu)=-(ru0(ns, ivminus,iu_r) + ru0(ns12,ivminus,iu_r))*p5
104 zu12(iv,iu)= (zu0(ns, ivminus,iu_r) + zu0(ns12,ivminus,iu_r))*p5
105 END DO
106 END IF
107
108 ! Scan over r-z grid for interior point
109 rmin = minval(r1b(iv,:))
110 rmax = maxval(r1b(iv,:))
111 zmin = minval(z1b(iv,:))
112 zmax = maxval(z1b(iv,:))
113
114 ! initial guess for new axis: center of grid
115 rcom(iv) = (rmax + rmin)/2.0_dp
116 zcom(iv) = (zmax + zmin)/2.0_dp
117
118 ! Estimate jacobian based on boundary and 1/2 surface
119 ds = (ns - ns12)*hs
120 DO iu = 1, ntheta1
121 ! (1,iv,1,0) == axis, iv, theta=0, even-m
122 rs(iv,iu) = (r1b(iv,iu) - r12(iv,iu))/ds + r1(1,iv,1,0)
123 zs(iv,iu) = (z1b(iv,iu) - z12(iv,iu))/ds + z1(1,iv,1,0)
124 tau0(iv,iu) = ru12(iv,iu)*zs(iv,iu) - zu12(iv,iu)*rs(iv,iu)
125 END DO
126
127 mintau = 0.0_dp
128
129 DO nlim = 1, limpts
130 zlim = zmin + ((zmax - zmin)*(nlim-1))/(limpts-1)
131
132 IF (.not.lasym .and. (iv.eq.1 .or. iv.eq.nzeta/2+1)) THEN
133 zlim = 0.0_dp
134 IF (nlim .gt. 1) then
135 EXIT
136 end if
137 END IF
138
139 ! Find value of magnetic axis that maximizes the minimum jacobian value
140 DO klim = 1, limpts
141 rlim = rmin + ((rmax - rmin)*(klim-1))/(limpts-1)
142
143 tau(iv,:) = signgs*(tau0(iv,:) - ru12(iv,:)*zlim + zu12(iv,:)*rlim)
144
145 mintemp = minval(tau(iv,:))
146 IF (mintemp .gt. mintau) THEN
147 mintau = mintemp
148 rcom(iv) = rlim
149 zcom(iv) = zlim
150 ELSE IF (mintemp .eq. mintau) THEN
151 ! If up-down symmetric and lasym=T, need this to pick z = 0
152 IF (abs(zcom(iv)).gt.abs(zlim)) then
153 zcom(iv) = zlim
154 end if
155 END IF
156 END DO
157 END DO
158
159 END DO planes
160
161 if (.not. lasym) then
162 ! For a stellarator-symmetric case,
163 ! mirror the rest of the toroidal range based on the first ~half.
164 do iv = nzeta/2+2, nzeta
165 rcom(iv) = rcom(nzeta+1-(iv-1))
166 zcom(iv) =-zcom(nzeta+1-(iv-1))
167 end do ! iv
168 end if ! .not. lasym
169
170 ! FOURIER TRANSFORM RCOM, ZCOM
171 dzeta = two/nzeta
172 DO n = 0, ntor
173 raxis_cc(n) = dzeta*sum(cosnv(:,n)*rcom(:))/nscale(n)
174 zaxis_cs(n) =-dzeta*sum(sinnv(:,n)*zcom(:))/nscale(n)
175
176 raxis_cs(n) =-dzeta*sum(sinnv(:,n)*rcom(:))/nscale(n)
177 zaxis_cc(n) = dzeta*sum(cosnv(:,n)*zcom(:))/nscale(n)
178 IF (n.eq.0 .or. n.eq.nzeta/2) THEN
179 raxis_cc(n) = p5*raxis_cc(n)
180 zaxis_cc(n) = p5*zaxis_cc(n)
181 END IF
182 END DO
183
184 ! debugging output from guess_axis
185 if (open_dbg_context("guess_axis")) then
186
187 ! axis geometry on entry into this routine
188 call add_real_1d("raxis_in" , ivmax, r1(1,1:ivmax,1,0) )
189 call add_real_1d("zaxis_in" , ivmax, z1(1,1:ivmax,1,0) )
190
191 call add_real_2d("r1b" , ivmax, ntheta1, r1b(1:ivmax,:) )
192 call add_real_2d("z1b" , ivmax, ntheta1, z1b(1:ivmax,:) )
193 call add_real_2d("rub" , ivmax, ntheta1, rub(1:ivmax,:) )
194 call add_real_2d("zub" , ivmax, ntheta1, zub(1:ivmax,:) )
195
196 call add_real_2d("r12" , ivmax, ntheta1, r12(1:ivmax,:) )
197 call add_real_2d("z12" , ivmax, ntheta1, z12(1:ivmax,:) )
198 call add_real_2d("ru12", ivmax, ntheta1, ru12(1:ivmax,:))
199 call add_real_2d("zu12", ivmax, ntheta1, zu12(1:ivmax,:))
200
201 call add_real_2d("rs" , ivmax, ntheta1, rs(1:ivmax,:) )
202 call add_real_2d("zs" , ivmax, ntheta1, zs(1:ivmax,:) )
203
204 call add_real_2d("tau0", ivmax, ntheta1, tau0(1:ivmax,:))
205
206 ! Actually tau would need to be ivmax * limpts * limpts * ntheta1,
207 ! since it gets set for every grid point.
208 ! As of now, it contains the entries for the (rmax, zmax) grid point.
209 call add_real_2d("tau" , ivmax, ntheta1, tau(1:ivmax,:) )
210
211 call add_real_1d("rcom", nzeta, rcom)
212 call add_real_1d("zcom", nzeta, zcom)
213
214 call add_real_1d("raxis_cc", ntor+1, raxis_cc)
215 call add_real_1d("zaxis_cs", ntor+1, zaxis_cs)
216 call add_real_1d("raxis_cs", ntor+1, raxis_cs)
217 call add_real_1d("zaxis_cc", ntor+1, zaxis_cc)
218
219 call close_dbg_out()
220 end if
221
222 deallocate(rcom, zcom)
223 deallocate(r1b, z1b, rub, zub, &
224 r12, z12, &
225 rs, zs, tau, ru12, zu12, tau0)
226
227END SUBROUTINE guess_axis
subroutine guess_axis(r1, z1, ru0, zu0)
Computes guess for magnetic axis if user guess leads to initial sign change of Jacobian.
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 sqrts
sqrt(s), two-dimensional array on full-grid
Definition realspace.f90:32
real(rprec) hs
radial mesh size increment
Definition vmec_main.f90:84
real(rprec) signgs
sign of Jacobian : must be =1 (right-handed) or =-1 (left-handed)
real(rprec), dimension(:), allocatable nscale
array for norming zeta -trig functions (internal use only)