PB3D [2.47]
Ideal linear high-n MHD stability in 3-D
Loading...
Searching...
No Matches
vac_utilities.f90
Go to the documentation of this file.
1!------------------------------------------------------------------------------!
2!> Numerical utilities related to the vacuum response.
3!!
4!! \see vac_ops for information.
5!------------------------------------------------------------------------------!
7#include <PB3D_macros.h>
8#include <wrappers.h>
9 use strumpackdensepackage
11 use messages
12 use output_ops
13 use num_vars, only: dp, pi, max_str_ln, iu
14 use vac_vars, only: vac_type
15
16 implicit none
17 private
20
21contains
22 !> Calculate G_ij and H_ij on an interval for field line aligned
23 !! configurations.
24 !!
25 !! The indices for the source variables are <tt>[left:right,dim]</tt> where
26 !! \c dim is the Cartesian dimension. The same holds for \c ql.
27 !!
28 !! For subintegrals close to the singularity, the procedure uses the
29 !! analytical approximation.
30 !!
31 !! \note This routine does not calculate the contribution \f$2\beta\f$.
32 subroutine calc_gh_int_1(G,H,x_s,x_in,norm_s,h_fac_in,step_size,tol)
33 ! input / output
34 real(dp), intent(inout) :: g(2) !< G
35 real(dp), intent(inout) :: h(2) !< H
36 real(dp), intent(in) :: x_s(2,3) !< position vector at left and right limit of source interval
37 real(dp), intent(in) :: x_in(3) !< position vector at which to calculate influence
38 real(dp), intent(in) :: norm_s(2,3) !< normal vector at left and right limit of source interval
39 real(dp), intent(in) :: h_fac_in(4) !< metric factors at which to calculate influence
40 real(dp), intent(in) :: step_size(2) !< step sizes in parallel direction and alpha
41 real(dp), intent(in) :: tol !< tolerance on distance between points
42
43 ! local variables
44 integer :: kd ! counter
45 real(dp) :: r2(2) ! distance between source and influence points
46 real(dp) :: e_fac ! factor E
47 real(dp) :: sineps ! sin(eps)
48 real(dp) :: dum_fac(2) ! dummy factors
49
50 ! initialize
51 g = 0._dp
52 h = 0._dp
53
54 ! calculate distance between source points
55 do kd = 1,2
56 r2(kd) = sum((x_s(kd,:)-x_in)**2)
57 end do
58
59 ! check for (near-)singular point
60 if (minval(r2).le.tol) then
61 e_fac = sqrt(h_fac_in(1)/h_fac_in(3))*step_size(2)/step_size(1) ! |e_alpha|/|e_theta| d_par_X / d_par_X
62 sineps = h_fac_in(2)/sqrt(h_fac_in(1)*h_fac_in(3))
63 dum_fac(1) = sqrt(1+2*e_fac*sineps+e_fac**2)
64 dum_fac(2) = sqrt(1-2*e_fac*sineps+e_fac**2)
65 g = -0.5_dp/sqrt(h_fac_in(1)) * step_size(1) * (&
66 &log(abs((dum_fac(2) + e_fac + sineps)/&
67 &(dum_fac(1) - e_fac + sineps))) &
68 &- e_fac/sineps**2* &
69 &log(abs((dum_fac(2) + e_fac + sineps)/&
70 &(dum_fac(1) - e_fac + sineps))) &
71 &)
72 h = h_fac_in(4)*g
73 else
74 g = -1._dp/sqrt(r2)
75 do kd = 1,2
76 h(kd) = sum(norm_s(kd,:)*(x_s(kd,:)-x_in))*(-g(kd))**(-3)
77 end do
78 end if
79 end subroutine calc_gh_int_1
80
81 !> Calculate G_ij and H_ij on an interval for axisymmetric configurations.
82 !!
83 !! The indices for the source variables are <tt>[left:right,dim]</tt> where
84 !! \c dim is the Cartesian dimension. The same holds for \c ql.
85 !!
86 !! For subintegrals close to the singularity (i.e. where the tolerance is no
87 !! being met), the routine approximates the toroidal functions with the
88 !! analytical approximation.
89 !! If one of the boundaries of the subintegral is far enough from the
90 !! singularity, there is an additional contribution due to the difference
91 !! between the actual toroidal function and the approximation. This
92 !! contribution is zero if both boundaries are close, because in this case
93 !! it is assumed that the entire integral is given by the analytical
94 !! approximation.
95 !!
96 !! \note This routine does not calculate the contribution \f$2\beta\f$.
97 subroutine calc_gh_int_2(G,H,t_s,t_in,x_s,x_in,norm_s,norm_in,Aij,ql,tol,&
98 &b_coeff,n_tor)
99 ! input / output
100 real(dp), intent(inout) :: g(2) !< G
101 real(dp), intent(inout) :: h(2) !< H
102 real(dp), intent(in) :: t_s(2) !< pol. angle at left and right limit of source interval
103 real(dp), intent(in) :: t_in !< pol. angle at which to calculate influence
104 real(dp), intent(in) :: x_s(2,2) !< position vector at left and right limit of source interval
105 real(dp), intent(in) :: x_in(2) !< position vector at which to calculate influence
106 real(dp), intent(in) :: norm_s(2,2) !< normal vector at left and right limit of source interval
107 real(dp), intent(in) :: norm_in(2) !< normal vector at which to calculate influence
108 real(dp), intent(in) :: aij(2) !< Aij helper variable for H
109 real(dp), intent(in) :: ql(2,2) !< ql for n-1 and n at left and right limit of source interval
110 real(dp), intent(in) :: tol !< tolerance on rho2
111 real(dp), intent(in) :: b_coeff(2) !< \f$b = \sum_{k=1}^n \frac{2}{2k-1}\f$ for n and n-1
112 integer, intent(in) :: n_tor !< toroidal mode number
113
114 ! local variables
115 integer :: kd, jd ! counters
116 integer :: kd_bound ! counter for boundary
117 real(dp) :: a_coeff ! coefficient a = |norm|/8R^2 at influence point
118 real(dp) :: t_in_loc ! local t_in, possibly shifted by 2pi
119 real(dp) :: delta_t(2) ! t_in - t_s
120 real(dp) :: rho2(2) ! square of distance in projected poloidal plane
121 real(dp) :: dlogd(2) ! delta log delta
122 real(dp) :: n_loc(2) ! norm_s / |norm_s|
123 real(dp) :: dn_loc(2) ! d n_loc / dtheta
124
125 ! initialize
126 g = 0._dp
127 h = 0._dp
128 do kd = 1,2
129 rho2(kd) = sum((x_s(kd,:)-x_in)**2)
130 end do
131 if (pi .lt. sum(t_s)/2 - t_in) then ! t_s closer to t_in + 2pi
132 t_in_loc = t_in + 2*pi
133 else if (-pi .gt. sum(t_s)/2 - t_in) then ! t_s closer to t_in - 2pi
134 t_in_loc = t_in - 2*pi
135 else ! t_s closer to t_in
136 t_in_loc = t_in
137 end if
138 n_loc = (norm_s(2,:)/sqrt(sum(norm_s(2,:)**2))+&
139 &norm_s(1,:)/sqrt(sum(norm_s(1,:)**2))) / 2._dp
140 dn_loc = (norm_s(2,:)/sqrt(sum(norm_s(2,:)**2))-&
141 &norm_s(1,:)/sqrt(sum(norm_s(1,:)**2))) / (t_s(2)-t_s(1))
142
143 ! check for (near-)singular point
144 if (minval(rho2).le.tol) then
145 ! There is at least one singular point: use analytical approach
146 a_coeff = sqrt(sum(norm_in**2))/(8._dp*x_in(1)**2)
147 do kd = 1,2
148 if (kd.eq.1) then
149 delta_t(1) = t_s(1) - t_in_loc
150 delta_t(2) = t_s(2) - t_in_loc
151 else
152 delta_t(1) = -(t_s(2) - t_in_loc)
153 delta_t(2) = -(t_s(1) - t_in_loc)
154 end if
155 do jd = 1,2
156 if (abs(delta_t(jd)).le.0._dp) then
157 dlogd(jd) = 0._dp
158 else
159 dlogd(jd) = log(a_coeff*abs(delta_t(jd)))
160 end if
161 end do
162 g(kd) = 1._dp/sqrt(x_in(1)*x_s(kd,1)) * (&
163 &b_coeff(2)*(delta_t(2)-delta_t(1)) + &
164 &0.5_dp*delta_t(1) - 1.5_dp*delta_t(2) + &
165 &1._dp/(delta_t(2)-delta_t(1)) * &
166 &(delta_t(1)*(delta_t(1)-2*delta_t(2))*dlogd(1) + &
167 &delta_t(2)**2 * dlogd(2)) &
168 &)
169 h(kd) = 0.5*norm_s(kd,1)/x_s(kd,1) * g(kd) + &
170 &(delta_t(2)-delta_t(1)) * (n_tor-0.5_dp)**(-1) * &
171 &aij(kd)/sqrt(x_in(1)*x_s(kd,1))
172 end do
173
174 ! Check if we are at the boundary of the analytical approach. In
175 ! this case there is an extra component due to the difference
176 ! between the toroidal function and the analytical approximation.
177 ! This will be implemented through a trapezoidal contribution of
178 ! which one side is zero.
179 if (maxval(rho2).gt.tol) then
180 ! fill G's and H's
181 if (rho2(2).gt.rho2(1)) then ! right boundary
182 kd_bound = 2
183 else ! left boundary
184 kd_bound = 1
185 end if
186 g(kd_bound) = g(kd_bound) - 0.5_dp*(t_s(2)-t_s(1))*2._dp/&
187 &sqrt(x_in(1)*x_s(kd_bound,1)) * (ql(kd_bound,2)+&
188 &log(a_coeff*abs(t_s(kd_bound)-t_in_loc))+b_coeff(2))
189 h(kd_bound) = h(kd_bound) + 0.5_dp*(t_s(2)-t_s(1))*2._dp/&
190 &sqrt(x_in(1)*x_s(kd_bound,1)) * &
191 &( (-0.5_dp*norm_s(kd_bound,1)/x_s(kd_bound,1) - &
192 &(1._dp+rho2(kd_bound)/(2*x_in(1)*x_s(kd_bound,1)))*&
193 &aij(kd_bound)) * (ql(kd_bound,2)+&
194 &log(a_coeff*abs(t_s(kd_bound)-t_in_loc))+b_coeff(2)) + &
195 &aij(kd_bound) * (ql(kd_bound,1)+&
196 &log(a_coeff*abs(t_s(kd_bound)-t_in_loc))+b_coeff(1)))
197 end if
198 else
199 do kd = 1,2
200 ! fill G's and H's
201 g(kd) = - (t_s(2)-t_s(1))/sqrt(x_in(1)*x_s(kd,1)) * &
202 &ql(kd,2)
203 h(kd) = (t_s(2)-t_s(1))/sqrt(x_in(1)*x_s(kd,1)) * &
204 &( (-0.5_dp*norm_s(kd,1)/x_s(kd,1) - &
205 &(1._dp+rho2(kd)/(2*x_in(1)*x_s(kd,1)))*&
206 &aij(kd))*ql(kd,2) + aij(kd)*ql(kd,1) )
207 end do
208 end if
209 end subroutine calc_gh_int_2
210
211 !> Gathers a distributed vector on a single process.
212 !!
213 !! For the distributed vector, the limits of the different subrows need to
214 !! be provided, as discussed in init_vac().
215 !!
216 !! By default, the result lands on the master process, but this can be
217 !! changed using \c proc. If it is negative, all processes receive the
218 !! result. In any case, \c vec_loc will be utilized.
219 !!
220 !! \note \c vec_loc needs to be allocated to the total dimensions, even when
221 !! the results is not received by the process.
222 integer function vec_dis2loc(ctxt,vec_dis,lims,vec_loc,proc) result(ierr)
223 use num_vars, only: n_procs
224 use vac_vars, only: in_context
225
226 character(*), parameter :: rout_name = 'vec_dis2loc'
227
228 ! input / output
229 integer, intent(in) :: ctxt !< context for vector
230 real(dp), intent(in) :: vec_dis(:) !< distributed vector
231 integer, intent(in) :: lims(:,:) !< limits for different subrows
232 real(dp), intent(inout) :: vec_loc(:) !< local vector
233 integer, intent(in), optional :: proc !< which process receives result
234
235 ! local variables
236 integer :: id ! index of subrow
237 integer :: limsl(2) ! local limits
238 integer :: proc_loc ! local proc
239 integer :: proc_dest(2) ! destination process index
240
241 ! initialize ierr
242 ierr = 0
243
244 ! select only processes that are in the context
245 if (.not.in_context(ctxt)) return
246
247 ! set up destination process index
248 proc_loc = 0
249 if (present(proc)) proc_loc = proc
250 if (proc_loc.gt.0 .and. proc_loc.lt.n_procs) then
251 call blacs_pcoord(ctxt,proc_loc,proc_dest(1),proc_dest(2))
252 else
253 proc_dest = [-1,-1]
254 end if
255
256 ! set up total copy of vector
257 vec_loc = 0._dp
258 do id = 1,size(lims,2)
259 ! set local limits
260 if (size(vec_dis) .gt. 0) then
261 limsl = sum(lims(2,1:id-1)-lims(1,1:id-1)+1) + &
262 &lims(:,id)-lims(1,id)+1
263 vec_loc(lims(1,id):lims(2,id)) = vec_dis(limsl(1):limsl(2))
264 end if
265 end do
266
267 ! add them together
268 call dgsum2d(ctxt,'all',' ',size(vec_loc),1,vec_loc,size(vec_loc),&
269 &proc_dest(1),proc_dest(2))
270 end function vec_dis2loc
271
272 !> Gathers a distributed vector on a single process.
273 !!
274 !! \see See vec_dis2loc() for exaplanation.
275 integer function mat_dis2loc(ctxt,mat_dis,lims_r,lims_c,mat_loc,proc) &
276 &result(ierr)
277 use num_vars, only: n_procs
278 use vac_vars, only: in_context
279
280 character(*), parameter :: rout_name = 'mat_dis2loc'
281
282 ! input / output
283 integer, intent(in) :: ctxt !< context for matrix
284 real(dp), intent(in) :: mat_dis(:,:) !< distributed matrix
285 integer, intent(in) :: lims_r(:,:) !< limits for different subrows
286 integer, intent(in) :: lims_c(:,:) !< limits for different subcolumns
287 real(dp), intent(inout) :: mat_loc(:,:) !< local matrix
288 integer, intent(in), optional :: proc !< which process receives result
289
290 ! local variables
291 integer :: i_rd, i_cd ! index of subrow and subcolumn
292 integer :: limsl_r(2) ! local row limits
293 integer :: limsl_c(2) ! local column limits
294 integer :: proc_loc ! local proc
295 integer :: proc_dest(2) ! destination process index
296
297 ! initialize ierr
298 ierr = 0
299
300 ! select only processes that are in the context
301 if (.not.in_context(ctxt)) return
302
303 ! set up destination process index
304 proc_loc = 0
305 if (present(proc)) proc_loc = proc
306 if (proc_loc.gt.0 .and. proc_loc.lt.n_procs) then
307 call blacs_pcoord(ctxt,proc_loc,proc_dest(1),proc_dest(2))
308 else
309 proc_dest = [-1,-1]
310 end if
311
312 ! set up total copy of matrix
313 mat_loc = 0._dp
314 do i_rd = 1,size(lims_r,2)
315 if (size(mat_dis,1) .gt. 0) then
316 limsl_r = sum(&
317 &lims_r(2,1:i_rd-1)-lims_r(1,1:i_rd-1)+1) + &
318 &lims_r(:,i_rd)-lims_r(1,i_rd)+1
319 do i_cd = 1,size(lims_c,2)
320 if (size(mat_dis,2) .gt. 0) then
321 limsl_c = sum(&
322 &lims_c(2,1:i_cd-1)-lims_c(1,1:i_cd-1)+1) + &
323 &lims_c(:,i_cd)-lims_c(1,i_cd)+1
324 mat_loc(lims_r(1,i_rd):lims_r(2,i_rd),&
325 &lims_c(1,i_cd):lims_c(2,i_cd)) = mat_dis(&
326 &limsl_r(1):limsl_r(2),limsl_c(1):limsl_c(2))
327 end if
328 end do
329 end if
330 end do
331
332 ! add them together
333 call dgsum2d(ctxt,'all',' ',size(mat_loc,1),size(mat_loc,2),mat_loc,&
334 &size(mat_loc,1),proc_dest(1),proc_dest(2))
335 end function mat_dis2loc
336
337 !> Copies vacuum variables of a previous level into the appropriate,
338 !! interlaced place of a next level.
339 !!
340 !! This is done by multiplying left by \f$\overline{\text{T}}\f$ and right
341 !! by \f$\overline{\text{T}}^T\f$ with
342 !! \f[
343 !! a_{ij} =
344 !! \left\{\begin{aligned}
345 !! 1 \quad &\text{for} \left(i,j\right) =
346 !! \left(2j-1+(i-1)n_\text{old},j+(i-1)n_\text{old}\right) \\
347 !! 0 \quad &\text{otherwise}
348 !! \end{aligned}\right.
349 !! \f]
350 !! where \f$i\f$ ranges from \f$1\f$ to \f$n_\text{old}\f$ and \f$j\f$ from
351 !! \f$1\f$ to \f$m_\text{old}\f$, with the size of \f$\overline{\text{T}}\f$
352 !! equal to \f$n_\text{new} \times n_\text{old} \f$ where \f$n\f$ refers to
353 !! \c n_bnd(1) and \f$m\f$ to \c n_bnd(2).
354 integer function interlaced_vac_copy(vac_old,vac) result(ierr)
355#if ldebug
356 use num_vars, only: ltest, n_procs, rank
357 use input_utilities, only: get_log
358#endif
359
360 character(*), parameter :: rout_name = 'interlaced_vac_copy'
361
362 ! input / output
363 type(vac_type), intent(in) :: vac_old !< old vacuum
364 type(vac_type), intent(inout) :: vac !< vacuum
365
366 ! local variables
367 integer :: id ! counter
368 integer :: i_cd ! index of subcol
369 integer :: i_rd ! index of subrow
370 integer :: rd, cd ! global counter for row and col
371 integer :: rdl, cdl ! local counter for row and col
372 integer :: alpha_id ! field line on which an index is situated
373 integer :: par_id ! index point on field line
374 integer :: n_ang(2) ! number of points in angular directions
375 integer :: n_ang_old(2) ! number of points in angular directions in old vacuum
376 real(dp), allocatable :: loc_a(:,:) ! local transformation matrix
377 real(dp), allocatable :: loc_b(:,:) ! local dummy matrix
378 integer :: desc_loc(blacsctxtsize) ! descriptor for loc_A and loc_B
379 integer :: desc_loc_old(blacsctxtsize) ! descriptor for loc_A and loc_B in old vacuum context
380 character(len=max_str_ln) :: err_msg ! error message
381#if ldebug
382 logical :: test_redist ! whether to test the redistribution of H and G
383 real(dp), allocatable :: hg_ser(:,:) ! serial versions of H and G
384 real(dp), allocatable :: hg_ser_old(:,:) ! serial versions of H and G in old vacuum
385#endif
386
387 ! initialize ierr
388 ierr = 0
389
390 ! initialize
391 n_ang = vac%n_ang
392 n_ang_old = vac_old%n_ang
393
394 ! test
395 if (n_ang(2).ne.n_ang_old(2)) then
396 ierr = 1
397 err_msg = 'Old and new vacuum need to have an equal number of &
398 &field lines'
399 chckerr(err_msg)
400 end if
401 if (n_ang(1).ne.2*n_ang_old(1)-1) then
402 ierr = 1
403 err_msg = 'Old and new vacuum need to have a compatible number of &
404 &points along the field lines'
405 chckerr(err_msg)
406 end if
407
408 ! loop over all field lines
409 do id = 1,n_ang(2)
410 ! copy normal and position vector
411 vac%norm((id-1)*n_ang(1)+1:id*n_ang(1):2,:) = &
412 &vac_old%norm((id-1)*n_ang_old(1)+1:id*n_ang_old(1):1,:)
413 vac%x_vec((id-1)*n_ang(1)+1:id*n_ang(1):2,:) = &
414 &vac_old%x_vec((id-1)*n_ang_old(1)+1:id*n_ang_old(1):1,:)
415
416 ! copy variables specific to style
417 select case (vac%style)
418 case (1) ! field-line 3-D
419 vac%h_fac((id-1)*n_ang(1)+1:id*n_ang(1):2,:) = vac_old%&
420 &h_fac((id-1)*n_ang_old(1)+1:id*n_ang_old(1):1,:)
421 case (2) ! axisymmetric
422 vac%dnorm((id-1)*n_ang(1)+1:id*n_ang(1):2,:) = &
423 &vac_old%dnorm((id-1)*n_ang_old(1)+1:id*n_ang_old(1):1,:)
424 vac%ang((id-1)*n_ang(1)+1:id*n_ang(1):2,:) = &
425 &vac_old%ang((id-1)*n_ang_old(1)+1:id*n_ang_old(1):1,:)
426 end select
427 end do
428
429 ! set up transformation matrix A and dummy matrix B
430 allocate(loc_a(vac%n_loc(1),vac_old%n_loc(2)))
431 allocate(loc_b(vac%n_loc(1),vac_old%n_loc(2)))
432 loc_a = 0._dp
433 loc_b = 0._dp
434 subcols: do i_cd = 1,size(vac_old%lims_c,2)
435 col: do cd = vac_old%lims_c(1,i_cd),vac_old%lims_c(2,i_cd)
436 ! set field line index and point index and calculate row
437 alpha_id = (cd-1)/n_ang_old(1)+1
438 par_id = mod(cd-1,n_ang_old(1))+1
439 rd = 2*par_id-1 + (alpha_id-1)*n_ang(1)
440
441 ! set local column index
442 cdl = sum(vac_old%lims_c(2,1:i_cd-1)-&
443 &vac_old%lims_c(1,1:i_cd-1)+1) + &
444 &cd-vac_old%lims_c(1,i_cd)+1
445
446 subrows: do i_rd = 1,size(vac%lims_r,2)
447 ! set local row index if in this subrow
448 if (rd.ge.vac%lims_r(1,i_rd) .and. &
449 &rd.le.vac%lims_r(2,i_rd)) then
450 rdl = sum(vac%lims_r(2,1:i_rd-1)-&
451 &vac%lims_r(1,1:i_rd-1)+1) + &
452 &rd-vac%lims_r(1,i_rd)+1
453
454 loc_a(rdl,cdl) = 1._dp
455 end if
456 end do subrows
457 end do col
458 end do subcols
459 call descinit(desc_loc,vac%n_bnd,vac_old%n_bnd,vac%bs,&
460 &vac%bs,0,0,vac%ctxt_HG,max(1,vac%n_loc(1)),ierr)
461 chckerr('descinit failed for loc')
462 call descinit(desc_loc_old,vac%n_bnd,vac_old%n_bnd,vac%bs,&
463 &vac%bs,0,0,vac_old%ctxt_HG,max(1,vac%n_loc(1)),ierr)
464 chckerr('descinit failed for loc_old')
465
466 ! treat H
467 chckerr('')
468 call pdgemm('N','N',vac%n_bnd,vac_old%n_bnd,vac_old%n_bnd,&
469 &1._dp,loc_a,1,1,desc_loc_old,vac_old%H,1,1,&
470 &vac_old%desc_H,0._dp,loc_b,1,1,desc_loc_old)
471 call pdgemm('N','T',vac%n_bnd,vac%n_bnd,vac_old%n_bnd,&
472 &1._dp,loc_b,1,1,desc_loc,loc_a,1,1,&
473 &desc_loc,0._dp,vac%H,1,1,vac%desc_H)
474
475 ! treat G
476 call pdgemm('N','N',vac%n_bnd,vac_old%n_bnd,vac_old%n_bnd,&
477 &1._dp,loc_a,1,1,desc_loc_old,vac_old%G,1,1,&
478 &vac_old%desc_G,0._dp,loc_b,1,1,desc_loc_old)
479 call pdgemm('N','T',vac%n_bnd,vac%n_bnd,vac_old%n_bnd,&
480 &1._dp,loc_b,1,1,desc_loc,loc_a,1,1,&
481 &desc_loc,0._dp,vac%G,1,1,vac%desc_G)
482
483#if ldebug
484 ! test
485 if (ltest) then
486 call writo('test resdistribution of H?')
487 test_redist = get_log(.false.)
488 else
489 test_redist = .false.
490 end if
491 if (test_redist) then
492 allocate(hg_ser(vac%n_bnd,vac%n_bnd))
493 allocate(hg_ser_old(vac_old%n_bnd,vac_old%n_bnd))
494 ierr = mat_dis2loc(vac_old%ctxt_HG,vac_old%H,&
495 &vac_old%lims_r,vac_old%lims_c,hg_ser_old,&
496 &proc=n_procs-1)
497 chckerr('')
498 ierr = mat_dis2loc(vac%ctxt_HG,vac%H,&
499 &vac%lims_r,vac%lims_c,hg_ser,&
500 &proc=n_procs-1)
501 chckerr('')
502 if (rank.eq.n_procs-1) then
503 call writo('old H:',persistent=rank.eq.n_procs-1)
504 call print_ar_2(hg_ser_old)
505 call writo('new H:',persistent=rank.eq.n_procs-1)
506 call print_ar_2(hg_ser)
507 call plot_hdf5('HG_ser_old','HG_ser_old',&
508 &reshape(hg_ser_old,[vac_old%n_bnd,vac_old%n_bnd,1]))
509 call plot_hdf5('HG_ser','HG_ser',&
510 &reshape(hg_ser,[vac%n_bnd,vac%n_bnd,1]))
511 end if
512 end if
513#endif
514
515 ! clean up
516 deallocate(loc_a,loc_b)
517 end function interlaced_vac_copy
518end module vac_utilities
Prints variables vars with names var_names in an HDF5 file with name c file_name and accompanying XDM...
Numerical utilities related to input.
logical function, public get_log(yes, ind)
Queries for a logical value yes or no, where the default answer is also to be provided.
Numerical utilities related to giving output.
Definition messages.f90:4
subroutine, public print_ar_2(arr)
Print an array of dimension 2 on the screen.
Definition messages.f90:475
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
logical, public ltest
whether or not to call the testing routines
Definition num_vars.f90:112
real(dp), parameter, public pi
Definition num_vars.f90:83
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
Operations concerning giving output, on the screen as well as in output files.
Definition output_ops.f90:5
Operations on strings.
Numerical utilities related to the vacuum response.
subroutine, public calc_gh_int_2(g, h, t_s, t_in, x_s, x_in, norm_s, norm_in, aij, ql, tol, b_coeff, n_tor)
Calculate G_ij and H_ij on an interval for axisymmetric configurations.
integer function, public vec_dis2loc(ctxt, vec_dis, lims, vec_loc, proc)
Gathers a distributed vector on a single process.
subroutine, public calc_gh_int_1(g, h, x_s, x_in, norm_s, h_fac_in, step_size, tol)
Calculate G_ij and H_ij on an interval for field line aligned configurations.
integer function, public interlaced_vac_copy(vac_old, vac)
Copies vacuum variables of a previous level into the appropriate, interlaced place of a next level.
integer function, public mat_dis2loc(ctxt, mat_dis, lims_r, lims_c, mat_loc, proc)
Gathers a distributed vector on a single process.
Variables pertaining to the vacuum quantities.
Definition vac_vars.f90:4
logical function, public in_context(ctxt)
Indicates whether current process is in the context.
Definition vac_vars.f90:378
vacuum type
Definition vac_vars.f90:46