V3FIT
siesta_bfield.f90
Go to the documentation of this file.
1 !*******************************************************************************
4 !
5 ! Note separating the Doxygen comment block here so detailed decription is
6 ! found in the Module not the file.
7 !
9 !*******************************************************************************
11  USE v3_utilities, ONLY: assert
12  USE stel_kinds
13  USE stel_constants
14  USE nscalingtools, ONLY: startglobrow, endglobrow
15  USE timer_mod
16  USE fourier
17 
18  IMPLICIT NONE
19 
20  CONTAINS
21 
22 !*******************************************************************************
23 ! UTILITY SUBROUTINES
24 !*******************************************************************************
25 !-------------------------------------------------------------------------------
35 !-------------------------------------------------------------------------------
36  SUBROUTINE update_bfield(l_add_res)
38  USE descriptor_mod, ONLY: inhessian
41 
42  IMPLICIT NONE
43 
44 ! Declare Arguments
45  LOGICAL, INTENT(in) :: l_add_res
46 
47 ! local variables
48  INTEGER :: istat
49  INTEGER :: js
50  INTEGER :: nsmin
51  INTEGER :: nsmax
52  REAL (dp), DIMENSION(:,:,:), ALLOCATABLE :: resistivity
53  REAL (dp) :: ton
54  REAL (dp) :: toff
55  REAL (dp) :: rho
56  REAL (dp) :: delt_cfl
57  REAL (dp) :: eta_prof
58  REAL (dp), DIMENSION(:,:,:), ALLOCATABLE :: esubsijf
59  REAL (dp), DIMENSION(:,:,:), ALLOCATABLE :: esubuijf
60  REAL (dp), DIMENSION(:,:,:), ALLOCATABLE :: esubvijf
61  REAL (dp), DIMENSION(:,:,:), POINTER :: esubsmnf
62  REAL (dp), DIMENSION(:,:,:), POINTER :: esubumnf
63  REAL (dp), DIMENSION(:,:,:), POINTER :: esubvmnf
64 
65 ! Start of executable code
66  CALL second0(ton)
67 
68  nsmin = max(1, startglobrow - 1)
69  nsmax = min(ns, endglobrow + 1)
70 
71 ! Calculate covariant components of (non-resistive) electric field E = -v X B
72 ! on full-space mesh.
73  ALLOCATE(esubsijf(ntheta,nzeta,nsmin:nsmax), &
74  esubuijf(ntheta,nzeta,nsmin:nsmax), &
75  esubvijf(ntheta,nzeta,nsmin:nsmax), stat=istat)
76  CALL assert_eq(0, istat, 'Allocation1 failed in UPDATE_BFIELD')
77 
78 ! Compute electric field.
79 !
80 ! E = V X B
81 !
82 ! Note V contains a jacobian factor so E has none since it cancels out with the
83 ! cross product.
84 ! -E_s = V^uB^v - V^vB^u : jv -> jac*v
85  esubsijf = -(jvsupuijf(:,:,nsmin:nsmax)*bsupvijf0(:,:,nsmin:nsmax) - &
86  jvsupvijf(:,:,nsmin:nsmax)*bsupuijf0(:,:,nsmin:nsmax))
87 ! -E_u = V^vB^s - V^sB^v
88  esubuijf = -(jvsupvijf(:,:,nsmin:nsmax)*bsupsijf0(:,:,nsmin:nsmax) - &
89  jvsupsijf(:,:,nsmin:nsmax)*bsupvijf0(:,:,nsmin:nsmax))
90 ! -E_v = V^sB^u - V^uB^s
91  esubvijf = -(jvsupsijf(:,:,nsmin:nsmax)*bsupuijf0(:,:,nsmin:nsmax) - &
92  jvsupuijf(:,:,nsmin:nsmax)*bsupsijf0(:,:,nsmin:nsmax))
93 
94  IF (nsmin .eq. 1) THEN
95  esubuijf(:,:,1) = 0
96  END IF
97 
98 ! Verify boundary condition: esubu,v(s=1) = 0 (tangential E vanishes at bdy =>
99 ! dB^s = 0). FIXME: Does this still hold in free boundary?
100  IF (nsmax .eq. ns) THEN
101  CALL assert(all(esubuijf(:,:,ns).EQ.zero), &
102  'esubuijf(ns) != 0 in UPDATE_BFIELD')
103  END IF
104  IF (nsmax .eq. ns) THEN
105  CALL assert(all(esubvijf(:,:,ns).EQ.zero), &
106  'esubvijf(ns) != 0 in UPDATE_BFIELD')
107  END IF
108 
109 ! Note this will LOWER the energy due to eta*|J|||**2 heating
110 !
111 ! esubX(resistive) = eta(JdotB/B^2)*BsubX
112 !
113 ! so the magnetic energy decreased due to this term. Note ksubX=JsubX are the
114 ! covariant components of the current.
115  IF (lresistive .and. (l_add_res .or. ALLOCATED(buv_res))) THEN
116  delt_cfl = hs_i*hs_i*abs(eta_factor)
117  IF (fsq_total .lt. fsq_res) THEN
118  delt_cfl = delt_cfl*sqrt(fsq_total/fsq_res)
119  END IF
120 
121  ALLOCATE(resistivity(ntheta,nzeta,nsmin:nsmax), stat=istat)
122  CALL assert_eq(0, istat, 'Allocation2 failed in update_bfield')
123 
124  DO js = nsmin, nsmax
125  rho = hs_i*(js - 1)
126  eta_prof = rho*rho*(1 - rho)
127  resistivity(:,:,js) = delt_cfl*eta_prof
128  END DO
129 
130  IF (ALLOCATED(buv_res)) THEN
131  resistivity = resistivity*buv_res(:,:,nsmin:nsmax)
132  ELSE
133 ! Divide out jacobf factor from cv_currents.
134  resistivity = resistivity/jacobf(:,:,nsmin:nsmax)
135  END IF
136 
137 ! Isotropic resistivity, E ~ eta*J. When adding the perturbation, K ~ B in
138 ! init_state.
139  esubsijf = esubsijf + resistivity*ksubsijf(:,:,nsmin:nsmax)
140  esubuijf = esubuijf + resistivity*ksubuijf(:,:,nsmin:nsmax)
141  esubvijf = esubvijf + resistivity*ksubvijf(:,:,nsmin:nsmax)
142 
143  IF (nsmin .eq. 1) THEN
144  esubuijf(:,:,1) = 0
145  END IF
146 
147  DEALLOCATE (resistivity)
148  END IF
149 
150 ! Update Bfield using Faraday's Law
151  CALL faraday(djbsupsmnsh, djbsupumnch, djbsupvmnch, &
152  esubsijf, esubuijf, esubvijf, f_sin, nsmin, nsmax)
153  IF (lasym) THEN
154  CALL faraday(djbsupsmnch, djbsupumnsh, djbsupvmnsh, &
155  esubsijf, esubuijf, esubvijf, f_cos, nsmin, nsmax)
156  END IF
157 
158  DEALLOCATE(esubsijf, esubuijf, esubvijf, stat=istat)
159  CALL assert_eq(0, istat, 'Deallocation failed in update_bfield')
160 
161  CALL second0(toff)
162  time_update_bfield = time_update_bfield + (toff - ton)
163 
164  END SUBROUTINE
165 
166 !-------------------------------------------------------------------------------
184 !-------------------------------------------------------------------------------
185  SUBROUTINE faraday(djbsupsmnh, djbsupumnh, djbsupvmnh, &
186  esubsijf, esubuijf, esubvijf, parity, nsmin, nsmax)
187  USE shared_data, ONLY: l_natural, delta_t
188  USE hessian, ONLY: l_compute_hessian
189  USE utilities, ONLY: curl_ftoh, set_bndy_full_origin
190  USE island_params, ONLY: mpol => mpol_i, ntor => ntor_i, fourier_context
191 
192  IMPLICIT NONE
193 
194 ! Declare Arguments
195  REAL (dp), DIMENSION(:,:,:), ALLOCATABLE, INTENT(inout) :: djbsupsmnh
196  REAL (dp), DIMENSION(:,:,:), ALLOCATABLE, INTENT(inout) :: djbsupumnh
197  REAL (dp), DIMENSION(:,:,:), ALLOCATABLE, INTENT(inout) :: djbsupvmnh
198  REAL (dp), DIMENSION(:,:,:), INTENT(in) :: esubsijf
199  REAL (dp), DIMENSION(:,:,:), INTENT(in) :: esubuijf
200  REAL (dp), DIMENSION(:,:,:), INTENT(in) :: esubvijf
201  INTEGER, INTENT(in) :: parity
202  INTEGER, INTENT(in) :: nsmin
203  INTEGER, INTENT(in) :: nsmax
204 
205 ! local variables
206  INTEGER :: fours
207  INTEGER :: fouruv
208  REAL (dp) :: sparity
209  REAL (dp) :: r12
210  REAL (dp), DIMENSION(:,:,:), POINTER :: esubsmnf
211  REAL (dp), DIMENSION(:,:,:), POINTER :: esubumnf
212  REAL (dp), DIMENSION(:,:,:), POINTER :: esubvmnf
213 
214 ! Start of executable code
215  IF (parity .EQ. f_sin) THEN
216 ! e_s (sin), e_u (cos), e_v (cos)
217  fours = f_sin
218  fouruv = f_cos
219  sparity = 1
220  ELSE
221 ! e_s (cos), e_u (sin), e_v (sin)
222  fours = f_cos
223  fouruv = f_sin
224  sparity = -1
225  END IF
226 
227 ! Allocate working arrays used in Faraday. FIXME: Move to inside faraday.
228  ALLOCATE(esubsmnf(0:mpol,-ntor:ntor,nsmin:nsmax), &
229  esubumnf(0:mpol,-ntor:ntor,nsmin:nsmax), &
230  esubvmnf(0:mpol,-ntor:ntor,nsmin:nsmax))
231 
232 ! Calculate harmonics of electric field
233  CALL fourier_context%tomnsp(esubsijf, esubsmnf, fours)
234  CALL fourier_context%tomnsp(esubuijf, esubumnf, fouruv)
235  CALL fourier_context%tomnsp(esubvijf, esubvmnf, fouruv)
236 
237 ! Impose boundary consition at first half-grid point.
238  IF (startglobrow .EQ. 1) THEN
239 ! These conditions are needed so that delta-W jogs (CheckForces) agree with
240 ! forces at origin.
241  CALL set_bndy_full_origin(esubsmnf, esubumnf, esubvmnf)
242 
243 ! IF (.not.l_natural) THEN
244 ! r12 = sparity*hs_i/2
245 ! djbsupsmnh(m1,:,2) = (esubsmnf(m1,:,1) + esubsmnf(m1,:,2))/2
246 ! djbsupumnh(m1,:,2) = (esubumnf(m1,:,1) + esubumnf(m1,:,2))/2
247 ! djbsupsmnh(m1,:,1) = r12*djbsupsmnh(m1,:,2) - djbsupumnh(m1,:,2) !-> 0
248 ! This constrains [esubs(2)*r12 - esubu(2)] = 0 at s=r12 (first half grid pt)
249 ! needed to make djb^s ~ r12*djb^u there
250 ! esubsmnf(m1,:,1) = esubsmnf(m1,:,1) - djbsupsmnh(m1,:,1)/r12
251 ! esubumnf(m1,:,1) = esubumnf(m1,:,1) + djbsupsmnh(m1,:,1)
252 ! END IF
253  END IF
254 
255 ! dB = -Curl(E)
256  CALL curl_ftoh(esubsmnf, esubumnf, esubvmnf, &
257  djbsupsmnh, djbsupumnh, djbsupvmnh, &
258  parity, nsmin, nsmax)
259 
260  DEALLOCATE(esubsmnf, esubumnf, esubvmnf)
261 
262 ! Boundary conditions at origin (Used to compute bfields at origin in
263 ! siesta_init and siesta_forces).
264  IF (nsmin .eq. 1) THEN
265  djbsupsmnh(:,:,1) = 0
266  djbsupsmnh(m1,:,1) = djbsupsmnh(m1,:,2)
267  djbsupumnh(:,:,1) = 0
268  djbsupumnh(m0:m1,:,1) = djbsupumnh(m0:m1,:,2)
269  djbsupvmnh(:,:,1) = 0
270  djbsupvmnh(m0,:,1) = djbsupvmnh(m0,:,2);
271  END IF
272 
273 ! Calculate increment of the magnetic field harmonics: use Euler scheme with dt
274 ! given by vsub*mn advance equations. Results computed here for half-grid
275 ! perturbations in mn space are used in the calculation of the force and to
276 ! advance the B's in UPDATE_STATE (in siesta_state module). Minus sign since
277 ! Faraday is dB = -Curl(E).
278  djbsupsmnh = -delta_t*djbsupsmnh
279  djbsupumnh = -delta_t*djbsupumnh
280  djbsupvmnh = -delta_t*djbsupvmnh
281 
282  END SUBROUTINE
283 
284  END MODULE
shared_data::l_natural
logical, parameter l_natural
Natural boundry condition flag.
Definition: shared_data.f90:47
shared_data::delta_t
real(dp) delta_t
Time step.
Definition: shared_data.f90:125
shared_data::fsq_total
real(dp) fsq_total
|F|^2 WITH column scaling.
Definition: shared_data.f90:91
quantities
This file contains subroutines for allocating and initializing curvilinear magnetic covariant and pre...
Definition: quantities.f90:11
v3_utilities::assert_eq
Definition: v3_utilities.f:62
siesta_bfield
This file contains subroutines for updating half-grid magnetic fields.
Definition: siesta_bfield.f90:10
island_params::fourier_context
type(fourier_class), pointer fourier_context
Fourier transform object.
Definition: island_params.f90:76
fourier
Module contains subroutines for computing FFT on parallel radial intervals. Converts quantities betwe...
Definition: fourier.f90:13
siesta_bfield::update_bfield
subroutine update_bfield(l_add_res)
Update contravariant componets of the magnetic field.
Definition: siesta_bfield.f90:37
fourier::m0
integer, parameter m0
m = 0 mode.
Definition: fourier.f90:58
v3_utilities::assert
Definition: v3_utilities.f:55
fourier::f_sin
integer, parameter f_sin
Sine parity.
Definition: fourier.f90:27
shared_data::buv_res
real(dp), dimension(:,:,:), allocatable buv_res
Resonant magnetic field perturbation.
Definition: shared_data.f90:104
siesta_namelist::eta_factor
real(dp) eta_factor
Resistivity value.
Definition: siesta_namelist.f90:148
island_params
This file contains fix parameters related to the computational grids.
Definition: island_params.f90:10
shared_data::lasym
logical lasym
Use non-stellarator symmetry.
Definition: shared_data.f90:230
siesta_bfield::faraday
subroutine faraday(djbsupsmnh, djbsupumnh, djbsupvmnh,
Use Faraday's law dB = -curl(E) to compute magnitic field perturbation.
Definition: siesta_bfield.f90:186
shared_data::fsq_res
real(dp), parameter fsq_res
Threshold force for turning off resistive perturbations.
Definition: shared_data.f90:27
siesta_namelist::lresistive
logical lresistive
Use resistive perturbaton.
Definition: siesta_namelist.f90:126
fourier::m1
integer, parameter m1
m = 1 mode.
Definition: fourier.f90:60
fourier::f_cos
integer, parameter f_cos
Cosine parity.
Definition: fourier.f90:25
siesta_namelist
This file contains all the variables and maximum sizes of the inputs for a SIESTA namelist input file...
Definition: siesta_namelist.f90:103
shared_data
This file contains variables and parameters used by many modules in SIESTA.
Definition: shared_data.f90:10