PB3D [2.47]
Ideal linear high-n MHD stability in 3-D
Loading...
Searching...
No Matches
vac_vars.f90
Go to the documentation of this file.
1!------------------------------------------------------------------------------!
2!> Variables pertaining to the vacuum quantities.
3!------------------------------------------------------------------------------!
4module vac_vars
5#include <PB3D_macros.h>
6 use strumpackdensepackage
8 use messages
10 use grid_vars, only: grid_type
11
12 implicit none
13
14 private
16#if ldebug
17 public n_alloc_vacs
18#endif
19
20 ! global variables
21 integer, parameter :: bs = 16 !< Blocksize of the 2D block-cyclic distribution
22#if ldebug
23 integer :: n_alloc_vacs !< nr. of allocated vacs \ldebug
24#endif
25
26 !> vacuum type
27 !!
28 !! The arrays here are of the form:
29 !! - \c H, \c G: <tt>(n_loc,n_loc)</tt>
30 !! - \c res: <tt>(n_mod_X,n_mod_X)</tt>
31 !!
32 !! where \c n_loc is the number of points in the boundary, i.e. a subset of
33 !! \c n_bnd.
34 !!
35 !! For vacuum style 1, the vacuum is assumed to be equidsitant in the
36 !! coordinate along the magnetic field lines and, if there are multiple
37 !! field lines, also in the field line label \f$\alpha\f$. The limits
38 !! on the angles are assumed to be given by the global variables \c
39 !! grid_vars.min_par_x, \c grid_vars.max_par_x and \c grid_vars.min_alpha,
40 !! \c grid_vars.max_alpha.
41 !!
42 !! For vacuum style 2, there is an additional angle \c ang. It is composed
43 !! of the angles along the magnetic fields (which refers to \c angle_1 in
44 !! the discussion of \c grid_vars.grid_type), of which there can be
45 !! multiple, but the total sum must be equal to \c n_bnd.
46 type, public :: vac_type
47 integer :: style !< style of vacuum (1: field-line 3-D, 2: axisymmetric)
48 integer :: prim_x !< primary mode number
49 integer :: ctxt_hg !< context for H and G
50 integer :: n_bnd !< number of points in boundary
51 integer :: bs !< block size in cyclical storage
52 integer :: mpi_comm !< communicator for vacuum
53 integer :: desc_h(blacsctxtsize) !< descriptor for H
54 integer :: desc_g(blacsctxtsize) !< descriptor for G
55 integer :: n_p(2) !< nr. of processes in grid
56 integer :: n_ang(2) !< number of angles (1) and number of field lines (2)
57 integer :: ind_p(2) !< index of local process in grid
58 integer :: n_loc(2) !< local number of rows and columns
59 integer, allocatable :: sec_x(:) !< secondary mode numbers
60 integer, allocatable :: lims_c(:,:) !< column limits for different subrows of G and H
61 integer, allocatable :: lims_r(:,:) !< row limits for different subcolumns of G and H
62 real(dp) :: jq !< iota (tor. flux) or q (pol. flux) at edge
63 real(dp), allocatable :: ang(:,:) !< angle along field line, for each field line
64 real(dp), allocatable :: norm(:,:) !< J nabla psi normal vector
65 real(dp), allocatable :: dnorm(:,:) !< poloidal derivative of norm (only for style 2)
66 real(dp), allocatable :: h_fac(:,:) !< metric factors (1,1), (1,3) and (3,3) (only for style 1)
67 real(dp), allocatable :: x_vec(:,:) !< Cartesian vector of position
68 real(dp), allocatable :: h(:,:) !< H coefficient
69 real(dp), allocatable :: g(:,:) !< G coefficient
70 complex(dp), allocatable :: res(:,:) !< vacuum response
71#if ldebug
72 real(dp) :: estim_mem_usage !< estimated memory usage \ldebug
73#endif
74 contains
75 !> initialize
76 procedure :: init => init_vac
77 !> deallocate
78 procedure :: dealloc => dealloc_vac
79 end type
80
81contains
82 !> \public Initializes a vacuum type.
83 !!
84 !! The number of modes as well as \c n and \c m are also set up.
85 !!
86 !! The variables G and H are saved in a special format, based on the
87 !! block-cyclical distribution employed in scalapack. As a hypothetical
88 !! example, consider a process grid corresponding to block-size 1x2 and 2x3
89 !! processes with a total size of 3x15:
90 !! \f[\left[\begin{array}{ccccccccccccccc}
91 !! 0 & 0 & 1 & 1 & 2 & 2 & 0 & 0 & 1 & 1 & 2 & 2 & 0 & 0 & 1 \\
92 !! 3 & 3 & 4 & 4 & 5 & 5 & 3 & 3 & 4 & 4 & 5 & 5 & 3 & 3 & 4 \\
93 !! 0 & 0 & 1 & 1 & 2 & 2 & 0 & 0 & 1 & 1 & 2 & 2 & 0 & 0 & 1
94 !! \end{array}\right]\f]
95 !!
96 !! Therefore, the 3-D storage convention used is, for example, for process 1:
97 !! \f[\begin{bmatrix}
98 !! (1,3) & (1,4) & (1,9) & (1,10) & (1,15) & (1,\cdot) \\
99 !! (3,3) & (3,4) & (3,9) & (3,10) & (3,15) & (3,\cdot)
100 !! \end{bmatrix}\f]
101 !!
102 !! The information concerning the delimitations of the individual
103 !! subintervals in the horizontal and vertical direction can be saved once
104 !! per subinterval.
105 !! For process 4 of above example, this would be
106 !! \f[
107 !! \begin{bmatrix} 2 \\ 2 \end{bmatrix} ;
108 !! \f]
109 !! for the vertical direction, and
110 !! \f[
111 !! \begin{bmatrix} 3 & 9 & 15 \\ 4 & 10 & 15 \end{bmatrix} ;
112 !! \f]
113 !! for the horizontal direction.
114 !!
115 !! A value \f$\cdot\f$ indicates that the index is out of global bounds.
116 !! Practically, this is checked by seeing whether the total index does not
117 !! exceed the global bounds.
118 !!
119 !! \return ierr
120 integer function init_vac(vac,style,n_bnd,prim_X,n_ang,jq) result(ierr)
121 use mpi
122 use num_vars, only: n_procs, rank
123 use x_vars, only: n_mod_x
124#if ldebug
125 use num_vars, only: print_mem_usage
126#endif
127
128 character(*), parameter :: rout_name = 'init_vac'
129
130 ! input / output
131 class(vac_type), intent(inout) :: vac !< vacuum variables
132 integer, intent(in) :: style !< style of vacuum (1: field-line 3-D, 2: axisymmetric)
133 integer, intent(in) :: n_bnd !< total number of points in boundary
134 integer, intent(in) :: prim_x !< primary mode number
135 integer, intent(in) :: n_ang(2) !< number of angles (1) and number of field lines (2)
136 real(dp), intent(in) :: jq !< iota (tor. flux) or q (pol. flux) at edge
137
138 ! local variables
139 character(len=max_str_ln) :: err_msg ! error message
140 integer :: n_dims ! number of dimensions to be saved in x_vec and norm
141 integer :: jd ! counter
142 integer, allocatable :: proc_map(:,:) ! process map
143
144 ! initialize ierr
145 ierr = 0
146
147#if ldebug
148 ! initialize memory usage
149 if (print_mem_usage) vac%estim_mem_usage = 0._dp
150#endif
151
152 ! test
153 if (product(n_ang).ne.n_bnd) then
154 ierr = 1
155 err_msg = 'The total number of angles along B, '//&
156 &trim(i2str(product(n_ang)))//', is not equal to n_bnd = '//&
157 &trim(i2str(n_bnd))
158 chckerr(err_msg)
159 end if
160
161 ! set some variables
162 vac%bs = bs
163 if (n_procs.eq.1) vac%bs = n_bnd
164 vac%jq = jq
165 vac%n_ang = n_ang
166
167 ! Initialize the BLACS grid for H and G
168 vac%prim_X = prim_x
169 vac%n_bnd = n_bnd
170 vac%n_p(1)=floor(sqrt(n_procs*1._dp))
171 vac%n_p(2)=n_procs/vac%n_p(1)
172 allocate(proc_map(vac%n_p(1),vac%n_p(2)))
173 proc_map = transpose(reshape(&
174 &[(jd+n_procs-1-product(vac%n_p),jd=1,product(vac%n_p))],vac%n_p))
175 call blacs_get(0,0,vac%ctxt_HG)
176 call blacs_gridmap(vac%ctxt_HG,proc_map,vac%n_p(1),vac%n_p(1),&
177 &vac%n_p(2)) ! last MPI proc is also last process in map
178 call blacs_gridinfo(vac%ctxt_HG,vac%n_p(1),vac%n_p(2),vac%ind_p(1),&
179 &vac%ind_p(2)) ! get nr. of rows and columns and local index
180 if(minval(vac%ind_p).ge.0) then ! only the ranks that participate
181 do jd = 1,2 ! loop over rows, then columns
182 vac%n_loc(jd) = numroc(vac%n_bnd,vac%bs,vac%ind_p(jd),0,&
183 &vac%n_p(jd)) ! get local number of rows, then columns
184 end do
185 call descinit(vac%desc_H,n_bnd,n_bnd,vac%bs,vac%bs,0,0,vac%ctxt_HG,&
186 &max(1,vac%n_loc(1)),ierr)
187 chckerr('descinit failed')
188 call descinit(vac%desc_G,n_bnd,n_bnd,vac%bs,vac%bs,0,0,vac%ctxt_HG,&
189 &max(1,vac%n_loc(1)),ierr)
190 chckerr('descinit failed')
191 call mpi_comm_split(mpi_comm_world,1,rank,vac%MPI_Comm,ierr)
192 chckerr('')
193 else
194 vac%n_loc = [0,0]
195 call mpi_comm_split(mpi_comm_world,mpi_undefined,rank,&
196 &vac%MPI_Comm,ierr)
197 chckerr('')
198 end if
199
200 ! set limits
201 call set_loc_lims(vac%n_loc(1),vac%bs,vac%ind_p(1),vac%n_p(1),&
202 &vac%lims_r)
203 call set_loc_lims(vac%n_loc(2),vac%bs,vac%ind_p(2),vac%n_p(2),&
204 &vac%lims_c)
205
206 ! set n_dims
207 vac%style = style
208 select case (vac%style)
209 case (1) ! field-line 3-D
210 n_dims = 3
211 case (2) ! axisymmetric
212 n_dims = 2
213 case default
214 ierr = 1
215 err_msg = 'No vacuum style '//trim(i2str(vac%style))//&
216 &' possible'
217 chckerr(err_msg)
218 end select
219
220 ! allocate normal and position vector
221 allocate(vac%norm(vac%n_bnd,n_dims))
222 allocate(vac%x_vec(vac%n_bnd,n_dims))
223
224 ! allocate variables specific to style
225 select case (vac%style)
226 case (1) ! field-line 3-D
227 allocate(vac%h_fac(vac%n_bnd,4))
228 case (2) ! axisymmetric
229 allocate(vac%ang(n_ang(1),n_ang(2)))
230 allocate(vac%dnorm(vac%n_bnd,n_dims))
231 end select
232
233 ! allocate vacuum response if last process
234 if (rank.eq.n_procs-1) allocate(vac%res(n_mod_x,n_mod_x))
235
236 ! allocate H and G
237 allocate(vac%G(vac%n_loc(1),vac%n_loc(2)))
238 allocate(vac%H(vac%n_loc(1),vac%n_loc(2)))
239 vac%G = 0._dp
240 vac%H = 0._dp
241
242#if ldebug
243 ! set estimated memory usage
244 if (print_mem_usage) vac%estim_mem_usage = &
245 &vac%estim_mem_usage + size(vac%G) + n_mod_x**2
246
247 ! increment n_alloc_vacs
249
250 ! print memory usage
251 if (print_mem_usage) call writo('[rank '//trim(i2str(rank))//&
252 &' - Expected memory usage of vac: '//&
253 &trim(r2strt(vac%estim_mem_usage*weight_dp*2))//' kB]',alert=.true.)
254#endif
255 end function init_vac
256
257 !> Calculates the limits in local index.
258 !!
259 !! \see See init_var() for an explanation.
260 subroutine set_loc_lims(n_loc,bs,ind_p,n_p,lims)
261 ! input / output
262 integer, intent(in) :: n_loc !< number of points owned by local process
263 integer, intent(in) :: bs !< block size
264 integer, intent(in) :: ind_p !< index of current process in this dimension
265 integer, intent(in) :: n_p !< number of processes in this dimension
266 integer, intent(inout), allocatable :: lims(:,:) !< limits for different subregions in this dimension
267
268 ! local variables
269 integer :: jd ! counter
270
271 ! set limits
272 if (n_loc.gt.0) then
273 allocate(lims(2,ceiling(n_loc*1._dp/bs)))
274 do jd = 1,size(lims,2)
275 lims(1,jd) = indxl2g((jd-1)*bs+1,bs,ind_p,0,n_p)
276 lims(2,jd) = indxl2g(min(jd*bs,n_loc),bs,ind_p,0,n_p)
277 end do
278 else
279 ! these processes don't play along
280 allocate(lims(2,1))
281 lims(:,1) = [0,-1]
282 end if
283 end subroutine set_loc_lims
284
285 !> \public Deallocates vacuum variables.
286 subroutine dealloc_vac(vac)
287#if ldebug
288 use num_vars, only: rank, print_mem_usage
289#endif
290
291 ! input / output
292 class(vac_type), intent(inout) :: vac !< vacuum variables to be deallocated
293
294#if ldebug
295 ! local variables
296 integer :: mem_diff ! difference in memory
297 real(dp) :: estim_mem_usage ! estimated memory usage
298
299 ! memory usage before deallocation
300 if (print_mem_usage) then
301 mem_diff = get_mem_usage()
302 estim_mem_usage = vac%estim_mem_usage
303 end if
304#endif
305
306 ! free grid
307 if (in_context(vac%ctxt_HG)) call blacs_gridexit(vac%ctxt_HG)
308
309 ! deallocate allocatable variables
310 call dealloc_vac_final(vac)
311
312#if ldebug
313 ! decrement n_alloc_vacs
315
316 ! memory usage difference after deallocation
317 if (print_mem_usage) then
318 mem_diff = mem_diff - get_mem_usage()
319 call writo('[Rank '//trim(i2str(rank))//' - liberated '//&
320 &trim(i2str(mem_diff))//'kB deallocating vac ('//&
321 &trim(i2str(nint(100*mem_diff/&
322 &(estim_mem_usage*weight_dp*2))))//&
323 &'% of estimated)]',alert=.true.)
324 end if
325#endif
326 contains
327 ! Note: intent(out) automatically deallocates the variable
328 !> \private
329 subroutine dealloc_vac_final(vac)
330 ! input / output
331 type(vac_type), intent(out) :: vac ! vacuum variables to be deallocated
332 end subroutine dealloc_vac_final
333 end subroutine dealloc_vac
334
335 !> Copy a vacuum type.
336 !!
337 !! \note The copy should be unallocated.
338 integer function copy_vac(vac,vac_copy) result(ierr)
339 use num_vars, only: rank, n_procs
340
341 ! input / output
342 class(vac_type), intent(in) :: vac !< vac to be copied
343 class(vac_type), intent(inout) :: vac_copy !< copy
344
345 character(*), parameter :: rout_name = 'copy_vac'
346
347 ! initialize ierr
348 ierr = 0
349
350 ! reallocate
351 ierr = vac_copy%init(vac%style,vac%n_bnd,vac%prim_X,vac%n_ang,&
352 &vac%jq)
353 chckerr('')
354
355 ! copy normal and position vector
356 vac_copy%norm = vac%norm
357 vac_copy%x_vec = vac%x_vec
358
359 ! copy variables specific to style
360 select case (vac%style)
361 case (1) ! field-line 3-D
362 vac_copy%h_fac = vac%h_fac
363 case (2) ! axisymmetric
364 vac_copy%dnorm = vac%dnorm
365 vac_copy%ang = vac%ang
366 end select
367
368 ! copy vacuum response
369 if (rank.eq.n_procs-1) vac_copy%res = vac%res
370
371 ! copy H and G
372 vac_copy%H = vac%H
373 vac_copy%G = vac%G
374 end function copy_vac
375
376 !> Indicates whether current process is in the context.
377 logical function in_context(ctxt) result(res)
378 ! input / output
379 integer, intent(in) :: ctxt !< context for vector
380
381 ! local variables
382 integer :: n_p(2) ! nr. of processes in grid
383 integer :: ind_p(2) ! index of local process in grid
384
385 call blacs_gridinfo(ctxt,n_p(1),n_p(2),ind_p(1),ind_p(2))
386 res = ind_p(1).ge.0
387 end function in_context
388end module vac_vars
Variables pertaining to the different grids used.
Definition grid_vars.f90:4
Numerical utilities related to giving output.
Definition messages.f90:4
integer function, public get_mem_usage()
Returns the memory usage in kilobytes.
Definition messages.f90:554
subroutine, public writo(input_str, persistent, error, warning, alert)
Write output to file identified by output_i.
Definition messages.f90:275
Numerical variables used by most other modules.
Definition num_vars.f90:4
integer, parameter, public dp
double precision
Definition num_vars.f90:46
integer, parameter, public max_name_ln
maximum length of filenames
Definition num_vars.f90:51
logical, public print_mem_usage
print memory usage is printed
Definition num_vars.f90:149
integer, public n_procs
nr. of MPI processes
Definition num_vars.f90:69
complex(dp), parameter, public iu
complex unit
Definition num_vars.f90:85
integer, parameter, public max_str_ln
maximum length of strings
Definition num_vars.f90:50
integer, public rank
MPI rank.
Definition num_vars.f90:68
real(dp), parameter, public weight_dp
size of double precision in kB
Definition num_vars.f90:49
Operations on strings.
elemental character(len=max_str_ln) function, public i2str(k)
Convert an integer to string.
elemental character(len=max_str_ln) function, public r2strt(k)
Convert a real (double) to string.
Variables pertaining to the vacuum quantities.
Definition vac_vars.f90:4
integer, public n_alloc_vacs
nr. of allocated vacs
Definition vac_vars.f90:23
subroutine, public set_loc_lims(n_loc, bs, ind_p, n_p, lims)
Calculates the limits in local index.
Definition vac_vars.f90:261
integer function init_vac(vac, style, n_bnd, prim_x, n_ang, jq)
Initializes a vacuum type.
Definition vac_vars.f90:121
integer function, public copy_vac(vac, vac_copy)
Copy a vacuum type.
Definition vac_vars.f90:339
subroutine dealloc_vac(vac)
Deallocates vacuum variables.
Definition vac_vars.f90:287
logical function, public in_context(ctxt)
Indicates whether current process is in the context.
Definition vac_vars.f90:378
Variables pertaining to the perturbation quantities.
Definition X_vars.f90:4
integer, public n_mod_x
size of m_X (pol. flux) or n_X (tor. flux)
Definition X_vars.f90:129
integer, public prim_x
n_X (pol. flux) or m_X (tor. flux)
Definition X_vars.f90:126
Type for grids.
Definition grid_vars.f90:59
vacuum type
Definition vac_vars.f90:46