5 #include <PB3D_macros.h>
58 module procedure calc_xuq_ind
60 module procedure calc_xuq_arr
65 integer function calc_xuq_arr(mds_X,mds_sol,grid_eq,grid_X,grid_sol,eq_1,&
66 &eq_2,X,sol,X_id,XUQ_style,time,XUQ,deriv)
result(ierr)
76 character(*),
parameter :: rout_name =
'calc_XUQ_arr'
80 type(
modes_type),
intent(in),
target :: mds_sol
86 type(
x_1_type),
intent(in),
target :: x
88 integer,
intent(in) :: x_id
89 integer,
intent(in) :: xuq_style
90 real(dp),
intent(in) :: time(:)
91 complex(dp),
intent(inout) :: xuq(:,:,:,:)
92 logical,
intent(in),
optional :: deriv
101 integer :: n_loc, m_loc
102 integer :: id, jd, kd
103 integer :: xuq_dims(4)
104 integer :: kdl_x(2), kdl_sol(2)
105 integer :: id_lim_x(2), id_lim_sol(2)
106 integer,
pointer :: sec_x_loc(:,:), sec_sol_loc(:,:)
107 real(dp),
allocatable :: expon(:,:,:)
108 real(dp),
allocatable :: par_fac(:)
109 real(dp),
allocatable :: jq(:)
110 real(dp),
allocatable :: s(:,:,:), inv_j(:,:,:)
111 real(dp),
pointer :: r_x_loc(:), r_sol_loc(:)
112 real(dp),
pointer :: theta_f(:,:,:), zeta_f(:,:,:)
113 complex(dp) :: sqrt_sol_val_norm
114 complex(dp),
allocatable :: fac_0(:,:,:), fac_1(:,:,:)
115 complex(dp),
allocatable :: xuq_loc(:,:)
116 complex(dp),
allocatable :: sol_vec(:,:)
117 complex(dp),
allocatable :: sol_vec_tot(:,:,:)
118 complex(dp),
allocatable :: dsol_vec(:,:)
119 complex(dp),
pointer :: u0(:,:,:), u1(:,:,:)
120 logical :: extrap = .true.
122 character(len=max_str_ln) :: err_msg
125 real(dp),
allocatable :: sol_vec_alt(:)
133 xuq_dims = shape(xuq)
137 if (
present(deriv)) deriv_loc = deriv
140 if (grid_eq%n(1).ne.grid_x%n(1) .or. grid_eq%n(2).ne.grid_x%n(2))
then
142 err_msg =
'Grids need to be compatible'
145 if (grid_eq%n(1).ne.xuq_dims(1) .or. grid_eq%n(2).ne.xuq_dims(2) .or. &
146 &grid_sol%loc_n_r.ne.xuq_dims(3) .or. n_t.ne.xuq_dims(4))
then
148 err_msg =
'XUQ needs to have the correct dimensions'
154 ierr =
trim_modes(mds_x,mds_sol,id_lim_x,id_lim_sol)
156 sec_x_loc => mds_x%sec(id_lim_x(1):id_lim_x(2),:)
157 sec_sol_loc => mds_sol%sec(id_lim_sol(1):id_lim_sol(2),:)
159 n_mod_tot =
size(sec_x_loc,1)
161 if (
size(sec_x_loc,1).ne.
size(sec_sol_loc,1))
then
163 err_msg =
'modes X and sol have inconsistent sizes'
168 sqrt_sol_val_norm = sqrt(sol%val(x_id))
169 if (ip(sqrt_sol_val_norm).gt.0) sqrt_sol_val_norm = - sqrt_sol_val_norm
170 sqrt_sol_val_norm = sqrt_sol_val_norm / abs(sqrt_sol_val_norm)
173 allocate(jq(xuq_dims(3)))
174 allocate(s(xuq_dims(1),xuq_dims(2),xuq_dims(3)))
175 if ((xuq_style.eq.3 .or. xuq_style.eq.4)) &
176 &
allocate(inv_j(xuq_dims(1),xuq_dims(2),xuq_dims(3)))
177 allocate(xuq_loc(xuq_dims(1),xuq_dims(2)))
178 allocate(dsol_vec(sol%n_mod,xuq_dims(3)))
182 ierr =
spline(grid_eq%loc_r_F,eq_1%q_saf_FD(:,0),&
186 ierr =
spline(grid_eq%loc_r_F,eq_1%rot_t_FD(:,0),&
190 do jd = 1,xuq_dims(2)
191 do id = 1,xuq_dims(1)
192 ierr =
spline(grid_eq%loc_r_F,eq_2%S(id,jd,:),&
195 if ((xuq_style.eq.3 .or. xuq_style.eq.4))
then
196 ierr =
spline(grid_eq%loc_r_F,&
197 &1._dp/eq_2%jac_FD(id,jd,:,0,0,0),grid_sol%loc_r_F,&
211 if (xuq_style.eq.2 .or. xuq_style.eq.4)
then
213 allocate(sol_vec_tot(n_mod_tot,grid_sol%loc_n_r,0:1))
221 sol_vec_tot(:,:,id) = sol_vec
227 call writo(
'For mode '//trim(
i2str(m))//
', testing &
228 &whether Dsol_vec is correct by comparing its integral &
229 &with original sol_vec')
230 kdl_sol = sec_sol_loc(m,2:3)
231 allocate(sol_vec_alt(1:kdl_sol(2)-kdl_sol(1)+1))
233 ierr =
calc_int(rp(sol_vec_tot(m,kdl_sol(1):kdl_sol(2),1)),&
234 &grid_sol%loc_r_F(kdl_sol(1):kdl_sol(2)),sol_vec_alt)
237 &[rp(sol_vec_tot(m,kdl_sol(1):kdl_sol(2),0)),&
238 &sol_vec_alt],[kdl_sol(2)-kdl_sol(1)+1,2]),x=reshape(&
239 &grid_sol%loc_r_F(kdl_sol(1):kdl_sol(2)),&
240 &[kdl_sol(2)-kdl_sol(1)+1,1])/
max_flux_f*2*pi)
241 ierr =
calc_int(ip(sol_vec_tot(m,kdl_sol(1):kdl_sol(2),1)),&
242 &grid_sol%loc_r_F(kdl_sol(1):kdl_sol(2)),sol_vec_alt)
245 &[ip(sol_vec_tot(m,kdl_sol(1):kdl_sol(2),0)),&
246 &sol_vec_alt],[kdl_sol(2)-kdl_sol(1)+1,2]),x=reshape(&
247 &grid_sol%loc_r_F(kdl_sol(1):kdl_sol(2)),&
248 &[kdl_sol(2)-kdl_sol(1)+1,1])/
max_flux_f*2*pi)
249 deallocate(sol_vec_alt)
260 deallocate(sol_vec,sol_vec_tot)
268 allocate(theta_f(xuq_dims(1),xuq_dims(2),xuq_dims(3)))
269 allocate(zeta_f(xuq_dims(1),xuq_dims(2),xuq_dims(3)))
270 do jd = 1,xuq_dims(2)
271 do id = 1,xuq_dims(1)
272 ierr =
spline(grid_eq%loc_r_F,grid_eq%theta_F(id,jd,:),&
273 &grid_sol%loc_r_F,theta_f(id,jd,:))
275 ierr =
spline(grid_eq%loc_r_F,grid_eq%zeta_F(id,jd,:),&
276 &grid_sol%loc_r_F,zeta_f(id,jd,:))
281 theta_f => grid_x%theta_F
282 zeta_f => grid_x%zeta_F
288 if (sec_x_loc(m,1).ne.sec_sol_loc(m,1))
then
290 err_msg =
'For mode '//trim(
i2str(m))//&
291 &
', no consistency for modes in grid_X and grid_sol'
296 kdl_x = sec_x_loc(m,2:3)
297 kdl_sol = sec_sol_loc(m,2:3)
300 kdl_x(1) = max(kdl_x(1),grid_x%i_min)
301 kdl_x(2) = min(kdl_x(2),grid_x%i_max)
302 kdl_sol(1) = max(kdl_sol(1),grid_sol%i_min)
303 kdl_sol(2) = min(kdl_sol(2),grid_sol%i_max)
306 kdl_x = kdl_x - grid_x%i_min + 1
307 kdl_sol = kdl_sol - grid_sol%i_min + 1
310 if (kdl_x(1).gt.kdl_x(2) .or. kdl_sol(1).gt.kdl_sol(2)) cycle
313 r_x_loc => grid_x%loc_r_F(kdl_x(1):kdl_x(2))
314 r_sol_loc => grid_sol%loc_r_F(kdl_sol(1):kdl_sol(2))
317 ind_x = sec_x_loc(m,4)
318 ind_sol = sec_sol_loc(m,4)
333 allocate(expon(xuq_dims(1),xuq_dims(2),kdl_sol(1):kdl_sol(2)))
334 allocate(fac_0(xuq_dims(1),xuq_dims(2),kdl_sol(1):kdl_sol(2)))
335 allocate(fac_1(xuq_dims(1),xuq_dims(2),kdl_sol(1):kdl_sol(2)))
336 allocate(par_fac(kdl_sol(1):kdl_sol(2)))
339 do kd = kdl_sol(1),kdl_sol(2)
341 kd_tot = kd + grid_sol%i_min - 1
342 n_loc = mds_sol%n(kd_tot,ind_sol)
343 m_loc = mds_sol%m(kd_tot,ind_sol)
348 err_msg =
'mode numbers not consistent'
354 par_fac(kd) = n_loc*jq(kd) - m_loc
356 par_fac(kd) = n_loc - m_loc*jq(kd)
358 expon(:,:,kd) = n_loc*zeta_f(:,:,kd) - &
359 &m_loc*theta_f(:,:,kd)
363 select case (xuq_style)
366 do kd = kdl_sol(1),kdl_sol(2)
367 fac_0(:,:,kd) = iu*par_fac(kd)
377 allocate(u0(xuq_dims(1),xuq_dims(2),&
378 &kdl_sol(1):kdl_sol(2)))
379 allocate(u1(xuq_dims(1),xuq_dims(2),&
380 &kdl_sol(1):kdl_sol(2)))
383 &x%DU_0(:,:,kdl_x(1):kdl_x(2),ind_x),u0,&
384 &r_x_loc,r_sol_loc,extrap)
387 &x%DU_1(:,:,kdl_x(1):kdl_x(2),ind_x),u1,&
388 &r_x_loc,r_sol_loc,extrap)
392 &x%U_0(:,:,kdl_x(1):kdl_x(2),ind_x),u0,&
393 &r_x_loc,r_sol_loc,extrap)
396 &x%U_1(:,:,kdl_x(1):kdl_x(2),ind_x),u1,&
397 &r_x_loc,r_sol_loc,extrap)
402 u0 => x%DU_0(:,:,kdl_x(1):kdl_x(2),ind_x)
403 u1 => x%DU_1(:,:,kdl_x(1):kdl_x(2),ind_x)
405 u0 => x%U_0(:,:,kdl_x(1):kdl_x(2),ind_x)
406 u1 => x%U_1(:,:,kdl_x(1):kdl_x(2),ind_x)
424 err_msg =
'For XUQ_style = '//trim(
i2str(xuq_style))//&
425 &
' calculation of parallel derivative not supported'
428 do kd = kdl_sol(1),kdl_sol(2)
429 fac_0(:,:,kd) = iu*par_fac(kd)*inv_j(:,:,kd)
435 err_msg =
'For XUQ_style = '//trim(
i2str(xuq_style))//&
436 &
' calculation of parallel derivative not supported'
440 allocate(u0(xuq_dims(1),xuq_dims(2),&
441 &kdl_sol(1):kdl_sol(2)))
442 allocate(u1(xuq_dims(1),xuq_dims(2),&
443 &kdl_sol(1):kdl_sol(2)))
449 &x%DU_0(:,:,kdl_x(1):kdl_x(2),ind_x),u0,&
450 &r_x_loc,r_sol_loc,extrap)
453 &x%DU_1(:,:,kdl_x(1):kdl_x(2),ind_x),u1,&
454 &r_x_loc,r_sol_loc,extrap)
462 u0 => x%DU_0(:,:,kdl_x(1):kdl_x(2),ind_x)
463 u1 => x%DU_1(:,:,kdl_x(1):kdl_x(2),ind_x)
468 fac_0 = u0*inv_j(:,:,kdl_sol(1):kdl_sol(2)) - &
469 &s(:,:,kdl_sol(1):kdl_sol(2))
470 fac_1 = u1*inv_j(:,:,kdl_sol(1):kdl_sol(2))
480 err_msg =
'No XUQ style associated with '//&
481 &trim(
i2str(xuq_style))
487 do kd = kdl_sol(1),kdl_sol(2)
489 xuq_loc = exp(iu*expon(:,:,kd)) * &
490 &(sol%vec(ind_sol,kd,x_id)*fac_0(:,:,kd) + &
491 &dsol_vec(ind_sol,kd)*fac_1(:,:,kd))
496 xuq(:,:,kd,id) = xuq(:,:,kd,id) + xuq_loc * &
497 &exp(iu*sqrt_sol_val_norm*time(id)*2*pi)
502 deallocate(fac_0,fac_1,expon,par_fac)
508 deallocate(theta_f,zeta_f)
512 nullify(r_x_loc,r_sol_loc)
513 nullify(theta_f,zeta_f)
515 nullify(sec_x_loc,sec_sol_loc)
516 end function calc_xuq_arr
518 integer function calc_xuq_ind(mds_X,mds_sol,grid_eq,grid_X,grid_sol,eq_1,&
519 &eq_2,X,sol,X_id,XUQ_style,time,XUQ,deriv)
result(ierr)
521 character(*),
parameter :: rout_name =
'calc_XUQ_ind'
533 integer,
intent(in) :: x_id
534 integer,
intent(in) :: xuq_style
535 real(
dp),
intent(in) :: time
536 complex(dp),
intent(inout) :: xuq(:,:,:)
537 logical,
intent(in),
optional :: deriv
540 complex(dp),
allocatable :: xuq_arr(:,:,:,:)
543 allocate(xuq_arr(
size(xuq,1),
size(xuq,2),
size(xuq,3),1))
546 ierr = calc_xuq_arr(mds_x,mds_sol,grid_eq,grid_x,grid_sol,eq_1,eq_2,x,&
547 &sol,x_id,xuq_style,[time],xuq_arr,deriv=deriv)
551 xuq = xuq_arr(:,:,:,1)
555 end function calc_xuq_ind
585 character(*),
parameter :: rout_name =
'calc_tot_sol_vec'
590 complex(dp),
intent(in) :: sol_vec_loc(:,:)
591 complex(dp),
intent(inout),
allocatable :: sol_vec_tot(:,:)
592 integer,
intent(in),
optional :: deriv
595 character(len=max_str_ln) :: err_msg
605 complex(dp),
allocatable :: dsol_vec_loc(:)
611 n_r =
size(sol_vec_loc,2)
615 if (
present(deriv)) deriv_loc = deriv
630 err_msg =
'normal discretization precision for solution &
631 &cannot be higher than 3 or lower than 0'
634 if (deriv_loc.lt.0 .or. deriv_loc.gt.max_deriv)
then
636 err_msg =
'deriv must be between 0 and '//trim(
i2str(max_deriv))//&
645 if (
allocated(sol_vec_tot))
then
646 if (
size(sol_vec_tot,1).ne.
size(sol_vec_loc,1) .or. &
647 &
size(sol_vec_tot,2).ne.
size(sol_vec_loc,2))
then
649 err_msg =
'Local and total solution vectors need to &
650 &be of the same length'
654 allocate(sol_vec_tot(
size(sol_vec_loc,1),n_r))
658 if (deriv_loc.eq.0)
then
659 sol_vec_tot = sol_vec_loc
661 do ld = 1,
size(sol_vec_tot,1)
662 ierr =
spline(grid_sol%r_F,sol_vec_loc(ld,:),&
663 &grid_sol%r_F,sol_vec_tot(ld,:),&
671 n_mod_tot =
size(mds%sec,1)
674 if (
allocated(sol_vec_tot))
then
675 if (
size(sol_vec_tot,1).ne.n_mod_tot .or. &
676 &
size(sol_vec_tot,2).ne.
size(sol_vec_loc,2))
then
678 err_msg =
'Total solution vectors needs to be of &
679 &correct length '//trim(
i2str(n_mod_tot))
683 allocate(sol_vec_tot(n_mod_tot,n_r))
688 do ld = 1,
size(mds%sec,1)
689 ld_loc = mds%sec(ld,1)-minval(mds%sec(:,1),1)+1
690 kdl = [mds%sec(ld,2),mds%sec(ld,3)]-grid_sol%i_min+1
691 kdl = max(1,min(kdl,n_r))
692 if (deriv_loc.eq.0)
then
693 sol_vec_tot(ld_loc,kdl(1):kdl(2)) = &
694 &sol_vec_loc(mds%sec(ld,4),kdl(1):kdl(2))
696 allocate(dsol_vec_loc(kdl(2)-kdl(1)+1))
699 if (kdl(2)-kdl(1)+1.ge.min_range)
then
700 ierr =
spline(grid_sol%r_F(kdl(1):kdl(2)),&
701 &sol_vec_loc(mds%sec(ld,4),kdl(1):kdl(2)),&
702 &grid_sol%r_F(kdl(1):kdl(2)),dsol_vec_loc,&
706 sol_vec_tot(ld_loc,kdl(1):kdl(2)) = dsol_vec_loc
708 deallocate(dsol_vec_loc)
725 character(*),
parameter :: rout_name =
'calc_loc_sol_vec'
729 integer,
intent(in) :: i_min
730 complex(dp),
intent(in) :: sol_vec_tot(:,:)
731 complex(dp),
intent(inout),
allocatable :: sol_vec_loc(:,:)
734 character(len=max_str_ln) :: err_msg
743 n_r =
size(sol_vec_tot,2)
752 if (
allocated(sol_vec_loc))
then
753 if (
size(sol_vec_loc,1).ne.
size(sol_vec_tot,1) .or. &
754 &
size(sol_vec_loc,2).ne.
size(sol_vec_tot,2))
then
756 err_msg =
'Local and total solution vectors need to &
757 &be of the same length'
761 allocate(sol_vec_loc(
size(sol_vec_tot,1),n_r))
763 sol_vec_loc = sol_vec_tot
767 n_mod_tot =
size(mds%sec,1)
770 if (
allocated(sol_vec_loc))
then
771 if (
size(sol_vec_loc,1).ne.n_mod_loc .or. &
772 &
size(sol_vec_loc,2).ne.
size(sol_vec_tot,2))
then
774 err_msg =
'Total solution vectors needs to be of &
775 &correct length '//trim(
i2str(n_mod_loc))
779 allocate(sol_vec_loc(n_mod_loc,n_r))
784 do ld = 1,
size(mds%sec,1)
785 ld_loc = mds%sec(ld,1)-minval(mds%sec(:,1),1)+1
786 kdl = [mds%sec(ld,2),mds%sec(ld,3)]-i_min+1
787 kdl = max(1,min(kdl,n_r))
788 sol_vec_loc(mds%sec(ld,4),kdl(1):kdl(2)) = &
789 &sol_vec_tot(ld_loc,kdl(1):kdl(2))
804 character(*),
parameter :: rout_name =
'interp_V_spline'
807 complex(dp),
intent(in) :: v_i(:,:,:)
808 complex(dp),
intent(out) :: v_o(:,:,:)
809 real(
dp),
intent(in) :: r_i(:)
810 real(
dp),
intent(in) :: r_o(:)
811 logical,
intent(in) :: extrap
812 integer,
intent(out),
optional :: ivs_stat
815 integer :: id, jd, kd
816 character(len=max_str_ln) :: err_msg
823 if (
size(r_i).ne.
size(v_i,3))
then
825 err_msg =
'r_i and V_i are not compatible'
828 if (
size(r_o).ne.
size(v_o,3))
then
830 err_msg =
'r_o and V_o are not compatible'
833 if (
size(v_i,1).ne.
size(v_o,1) .or.
size(v_i,2).ne.
size(v_o,2))
then
835 err_msg =
'V_i and V_o are not compatible'
841 select case (
size(r_i))
843 do kd = 1,
size(v_o,3)
844 v_o(:,:,kd) = v_i(:,:,1)
846 if (
present(ivs_stat)) ivs_stat = 1
848 do jd = 1,
size(v_i,2)
849 do id = 1,
size(v_i,1)
850 ierr =
spline(r_i,v_i(id,jd,:),r_o,v_o(id,jd,:),&
851 &ord=1,extrap=extrap)
855 if (
present(ivs_stat)) ivs_stat = 2
857 do jd = 1,
size(v_i,2)
858 do id = 1,
size(v_i,1)
859 ierr =
spline(r_i,v_i(id,jd,:),r_o,v_o(id,jd,:),&
860 &ord=3,extrap=extrap)
864 if (
present(ivs_stat)) ivs_stat = 3
868 chckerr(
'Need more than 0 points')
874 do jd = 1,
size(v_i,2)
875 do id = 1,
size(v_i,1)
877 call plot_comp(
'real part',r_i,rp(v_i(id,jd,:)),&
878 &r_o,rp(v_o(id,jd,:)))
879 call plot_comp(
'imaginary part',r_i,ip(v_i(id,jd,:)),&
880 &r_o,ip(v_o(id,jd,:)))
886 subroutine plot_comp(plot_name,x_i,y_i,x_o,y_o)
888 character(len=*),
intent(in) :: plot_name
889 real(
dp),
intent(in) :: x_i(:)
890 real(
dp),
intent(in) :: y_i(:)
891 real(
dp),
intent(in) :: x_o(:)
892 real(
dp),
intent(in) :: y_o(:)
895 real(
dp),
allocatable :: x_plot(:,:)
896 real(
dp),
allocatable :: y_plot(:,:)
897 character(len=max_str_ln) :: var_names(2)
899 allocate(x_plot(max(
size(x_i),
size(x_o)),2))
900 allocate(y_plot(max(
size(x_i),
size(x_o)),2))
902 x_plot(1:
size(x_i),1) = x_i
903 x_plot(
size(x_i):
size(x_plot,1),1) = x_i(
size(x_i))
904 x_plot(1:
size(x_o),2) = x_o
905 x_plot(
size(x_o):
size(x_plot,1),2) = x_o(
size(x_o))
907 y_plot(1:
size(x_i),1) = y_i(:)
908 y_plot(
size(x_i):
size(y_plot,1),1) = y_i(
size(x_i))
909 y_plot(1:
size(x_o),2) = y_o(:)
910 y_plot(
size(x_o):
size(y_plot,1),2) = y_o(
size(x_o))
912 var_names(1) =
'input '//plot_name
913 var_names(2) =
'output '//plot_name
915 end subroutine plot_comp