PB3D [2.47]
Ideal linear high-n MHD stability in 3-D
Loading...
Searching...
No Matches
X_utilities.f90
Go to the documentation of this file.
1!------------------------------------------------------------------------------!
2!> Numerical utilities related to perturbation operations.
3!------------------------------------------------------------------------------!
5#include <PB3D_macros.h>
7 use messages
9 use grid_vars, only: grid_type
10 use x_vars, only: n_mod_x
11
12 implicit none
13
14 private
17
18 ! interfaces
19
20 !> \public Returns the \c sec_ind_tot used to refer to a perturbation
21 !! quantity.
23 !> \public
24 module procedure sec_ind_loc2tot_1
25 !> \public
26 module procedure sec_ind_loc2tot_2
27 end interface
28
29contains
30 !> \private vectorial version
31 function sec_ind_loc2tot_1(id,lim_sec_X) result(res)
32 ! input / output
33 integer, intent(in) :: id !< mode index
34 integer, intent(in), optional :: lim_sec_x(2) !< limits of \c m_X (pol. flux) or \c n_X (tor. flux)
35 integer :: res !< output
36
37 ! local variables
38 integer :: lim_sec_x_loc(2) ! local lim_sec_X
39
40 ! set local lim_sec_X
41 lim_sec_x_loc = [1,n_mod_x]
42 if (present(lim_sec_x)) lim_sec_x_loc = lim_sec_x
43
44 ! set sec_ind_tot
45 res = lim_sec_x_loc(1)-1+id
46 end function sec_ind_loc2tot_1
47 !> \private tensorial version
48 function sec_ind_loc2tot_2(id,jd,lim_sec_X) result(res)
49 ! input / output
50 integer, intent(in) :: id !< mode index for dimension 1
51 integer, intent(in) :: jd !< mode index for dimension 1
52 integer, intent(in), optional :: lim_sec_x(2,2) !< limits of \c m_X (pol flux) or \c n_X (tor flux) for both dimensions
53 integer :: res(2) !< output
54
55 ! local variables
56 integer :: lim_sec_x_loc(2,2) ! local lim_sec_X
57
58 ! set local lim_sec_X
59 lim_sec_x_loc(:,1) = [1,n_mod_x]
60 lim_sec_x_loc(:,2) = [1,n_mod_x]
61 if (present(lim_sec_x)) lim_sec_x_loc = lim_sec_x
62
63 ! set sec_ind_tot
64 res = [lim_sec_x_loc(1,1)-1+id,lim_sec_x_loc(1,2)-1+jd]
65 end function sec_ind_loc2tot_2
66
67 !> Gets one of the the local ranges of contiguous tensorial perturbation
68 !! variables to be printed or read during one call of the corresponding HDF5
69 !! variables.
70 !!
71 !! More specifically, a range of indices \c k in the first dimension is
72 !! given for every value of the indices \c m in the second dimension.
73 !!
74 !! An example is now given for the subrange <tt>[2:3,2:5]</tt> of a the
75 !! total range <tt>[1:5, 1:5]</tt>. For asymmetric variables the situation
76 !! is simple: The \c k range is <tt>[2:3]</tt> for all 5 values of \c m.
77 !! However, for symmetric variables, the upper diagonal values are not
78 !! stored, which gives \c k ranges <tt>[2:3]</tt>, <tt>[3:3]</tt> and no
79 !! range for \c m = 4 and 5.
80 !!
81 !! This routine then translates these ranges to the corresponding 1-D ranges
82 !! that are used in the actual variables. For above example, the total
83 !! indices are
84 !! \f[
85 !! \left(\begin{array}{ccccc}
86 !! 1 & 6 & 11 & 16 & 21 \\
87 !! 2 & 7 & 12 & 17 & 22 \\
88 !! 3 & 8 & 13 & 18 & 23 \\
89 !! 4 & 9 & 14 & 19 & 24 \\
90 !! 5 & 10 & 15 & 20 & 25
91 !! \end{array}\right)
92 !! \rightarrow \left[7:8\right], \left[12:13\right],
93 !! \left[17:18\right] \ \text{and} \ \left[22:23\right],
94 !! \f]
95 !! for asymmetric variables and
96 !! \f[
97 !! \left(\begin{array}{ccccc}
98 !! 1 & 2 & 3 & 4 & 5 \\
99 !! 2 & 6 & 7 & 8 & 9 \\
100 !! 3 & 7 & 10 & 11 & 12 \\
101 !! 4 & 8 & 11 & 13 & 14 \\
102 !! 5 & 9 & 12 & 14 & 15
103 !! \end{array}\right)
104 !! \rightarrow \left[6:7\right], \left[10:10\right],
105 !! \left[:\right] \ \text{and} \ \left[:\right],
106 !! \f]
107 !! for symmetric variables.
108 !!
109 !! These can then related to the local indices for the variables in this
110 !! perturbation job.
111 !!
112 !! For above example, the results are:
113 !!
114 !! <tt>[1:2], [3:4], [5:6] and [7:8]</tt>,
115 !!
116 !! for asymmetric variables and
117 !!
118 !! <tt>[1:2], [3:3], [:] and [:]</tt>,
119 !!
120 !! for symmetric variables.
121 !!
122 !! As can be seen, the local ranges of the variables in the submatrix of
123 !! this perturbation job are (designed to be) contiguous, but the total
124 !! ranges of the variables in the submatrix are clearly not in general.
125 !!
126 !! The procedure outputs both the local and total ranges.
127 subroutine get_sec_x_range(sec_X_range_loc,sec_X_range_tot,m,sym,lim_sec_X)
128 use x_vars, only: n_mod_x
129 use num_utilities, only: c
130
131 ! input / output
132 integer, intent(inout) :: sec_x_range_loc(2) !< start and end of local range in dimension 1 (vertical)
133 integer, intent(inout) :: sec_x_range_tot(2) !< start and end of total range in dimension 1 (vertical)
134 integer, intent(in) :: m !< dimension 2 (horizontal)
135 logical, intent(in) :: sym !< whether the variable is symmetric
136 integer, intent(in), optional :: lim_sec_x(2,2) !< limits of \c m_X (pol. flux) or \c n_X (tor. flux)
137
138 ! local variables
139 integer :: k_range_loc(2) ! local range of k
140 integer :: k ! counter
141 integer :: n_mod ! local n_mod
142
143 ! set number of modes of dimension 1
144 if (present(lim_sec_x)) then
145 n_mod = lim_sec_x(2,1)-lim_sec_x(1,1)+1
146 else
147 n_mod = n_mod_x
148 endif
149
150 ! initialize secondary X range
151 k_range_loc = [n_mod+1,0] ! initialize to inverted values, out of bounds
152
153 ! find start and end of k range
154 find_start: do k = 1,n_mod
155 if (is_necessary_x(sym,[k,m],lim_sec_x)) then ! first necessary pair [k,m]
156 k_range_loc(1) = k
157 exit find_start
158 end if
159 end do find_start
160 find_stop: do k = n_mod,k_range_loc(1),-1
161 if (is_necessary_x(sym,[k,m],lim_sec_x)) then ! last necessary pair [k,m]
162 k_range_loc(2) = k
163 exit find_stop
164 end if
165 end do find_stop
166
167 ! translate k range and m value to 1-D index
168 do k = 1,2
169 sec_x_range_loc(k) = c([k_range_loc(k),m],sym,n_mod_x,lim_sec_x)
170 sec_x_range_tot(k) = c(sec_ind_loc2tot(k_range_loc(k),m,lim_sec_x),&
171 &sym,n_mod_x)
172 end do
173 end subroutine get_sec_x_range
174
175 !> Tests whether this perturbatino job should be done.
176 !!
177 !! Also increments \c X_job_nr
178 logical function do_x()
179 use num_vars, only: x_jobs_lims, x_job_nr
180
181 ! increment perturbation job nr.
182 x_job_nr = x_job_nr + 1
183
184 if (x_job_nr.le.size(x_jobs_lims,2)) then
185 do_x = .true.
186 else
187 do_x = .false.
188 end if
189 end function do_x
190
191 !> Determines whether a variable needs to be considered:
192 !!
193 !! This depends on whether the quantity is symmetric or not:
194 !! - Only if it is on or below the diagonal for symmetric quantities.
195 !! - Always for asymmetric quantities
196 logical function is_necessary_x(sym,sec_X_id,lim_sec_X) result(res)
197 ! input / output
198 logical, intent(in) :: sym !< whether the variable is symmetric
199 integer, intent(in) :: sec_x_id(2) !< mode indices
200 integer, intent(in), optional :: lim_sec_x(2,2) !< limits of \c m_X (pol flux) or \c n_X (tor flux) for both dimensions
201
202 ! local variables
203 integer :: lim_sec_x_loc(2,2) ! local version of lim_sec_X
204
205 ! initialize res
206 res = .true.
207
208 ! modify res depending on symmetry
209 if (sym) then
210 ! set local lim_sec_X
211 lim_sec_x_loc(:,1) = [1,n_mod_x]
212 lim_sec_x_loc(:,2) = [1,n_mod_x]
213 if (present(lim_sec_x)) lim_sec_x_loc = lim_sec_x
214
215 ! set res
216 if (lim_sec_x_loc(1,1)+sec_x_id(1).lt.&
217 &lim_sec_x_loc(1,2)+sec_x_id(2)) res = .false.
218 end if
219 end function is_necessary_x
220
221 !> Calculate memory in MB necessary for X variables.
222 !!
223 !! This depends on the order:
224 !! - order 1:
225 !! - <tt>4x n_par_X x n_geo x loc_n_r x n_mod</tt>
226 !! - order 2:
227 !! - <tt>2x n_par_X x n_geo x loc_n_r x n_mod^2</tt>
228 !! - <tt>4x n_par_X x n_geo x loc_n_r x n_mod(n_mod+1)/2</tt>
229 !! - higher order: not used
230 !!
231 !! where <tt>n_par_X x n_geo x loc_n_r</tt> should be passed as \c arr_size
232 !! and \c n_mod as well.
233 !!
234 !! \return ierr
235 integer function calc_memory_x(ord,arr_size,n_mod,mem_size) result(ierr)
236 use iso_c_binding
237
238 character(*), parameter :: rout_name = 'calc_memory_X'
239
240 ! input / output
241 integer, intent(in) :: ord !< order of data
242 integer, intent(in) :: arr_size !< size of part of X array
243 integer, intent(in) :: n_mod !< number of modes
244 real(dp), intent(inout) :: mem_size !< total size
245
246 ! local variables
247 integer(C_SIZE_T) :: dp_size ! size of dp
248 character(len=max_str_ln) :: err_msg ! error message
249
250 ! initialize ierr
251 ierr = 0
252
253 call lvl_ud(1)
254
255 ! get size of complex variable
256 dp_size = 2*sizeof(1._dp) ! complex variable
257
258 ! calculate memory depending on order
259 select case(ord)
260 case (1) ! vectorial data: U, DU
261 ! set memory size
262 mem_size = 4*arr_size
263 mem_size = mem_size*n_mod**ord
264 mem_size = mem_size*dp_size
265 case (2) ! tensorial data: PV, KV
266 ! set memory size
267 mem_size = arr_size
268 mem_size = mem_size*(2*n_mod**ord+4*n_mod*(n_mod+1)/2)
269 mem_size = mem_size*dp_size
270 case default
271 ierr = 1
272 err_msg = 'Orders > 2 are not implemented'
273 chckerr(err_msg)
274 end select
275
276 ! convert B to MB
277 mem_size = mem_size*1.e-6_dp
278
279 ! apply 50% safety factor (empirical)
280 mem_size = mem_size*1.5_dp
281
282 ! test overflow
283 if (mem_size.lt.0) then
284 ierr = 1
285 chckerr('Overflow occured')
286 end if
287
288 call lvl_ud(-1)
289 end function calc_memory_x
290
291 !> Limit input mode range to output mode range.
292 integer function trim_modes(mds_i,mds_o,id_lim_i,id_lim_o) result(ierr)
293 use x_vars, only: modes_type
294
295 character(*), parameter :: rout_name = 'trim_modes'
296
297 ! input / output
298 type(modes_type), intent(in) :: mds_i !< general modes variables for input
299 type(modes_type), intent(in) :: mds_o !< general modes variables for output
300 integer, intent(inout) :: id_lim_i(2) !< limits on input modes
301 integer, intent(inout) :: id_lim_o(2) !< limits on output modes
302
303 ! local variables
304 integer :: m ! counter
305 character(len=max_str_ln) :: err_msg ! error message
306
307 ! initialize ierr
308 ierr = 0
309
310 ! find limits point where input modes and output modes coincide
311 ! (input grid should comprise output grid)
312 id_lim_o = [1,size(mds_o%sec,1)]
313 id_lim_i = [-1,-1]
314 do m = 1,size(mds_i%sec,1)
315 if (mds_i%sec(m,1).eq.mds_o%sec(id_lim_o(1),1)) then
316 id_lim_i(1) = m
317 exit
318 end if
319 end do
320 do m = size(mds_i%sec,1),1,-1
321 if (mds_i%sec(m,1).eq.mds_o%sec(id_lim_o(2),1)) then
322 id_lim_i(2) = m
323 exit
324 end if
325 end do
326
327 ! test
328 if (any(id_lim_o.le.0)) then
329 ierr = 1
330 err_msg = 'Cannot find limits of input modes'
331 chckerr(err_msg)
332 end if
333 end function trim_modes
334end module x_utilities
Returns the sec_ind_tot used to refer to a perturbation quantity.
Variables pertaining to the different grids used.
Definition grid_vars.f90:4
Numerical utilities related to giving output.
Definition messages.f90:4
subroutine, public lvl_ud(inc)
Increases/decreases lvl of output.
Definition messages.f90:254
Numerical utilities.
integer function, public c(ij, sym, n, lim_n)
Convert 2-D coordinates (i,j) to the storage convention used in matrices.
integer, dimension(:,:), allocatable, public m
1-D array indices of metric indices
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
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, dimension(:,:), allocatable, public x_jobs_lims
data about X jobs: [ , , , ] for all jobs
Definition num_vars.f90:76
integer, public x_job_nr
nr. of X job
Definition num_vars.f90:78
Operations on strings.
Numerical utilities related to perturbation operations.
integer function, public calc_memory_x(ord, arr_size, n_mod, mem_size)
Calculate memory in MB necessary for X variables.
subroutine, public get_sec_x_range(sec_x_range_loc, sec_x_range_tot, m, sym, lim_sec_x)
Gets one of the the local ranges of contiguous tensorial perturbation variables to be printed or read...
logical function, public is_necessary_x(sym, sec_x_id, lim_sec_x)
Determines whether a variable needs to be considered:
logical function, public do_x()
Tests whether this perturbatino job should be done.
integer function, public trim_modes(mds_i, mds_o, id_lim_i, id_lim_o)
Limit input mode range to output mode range.
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
Type for grids.
Definition grid_vars.f90:59
mode number type
Definition X_vars.f90:36