module GVTDX_sub !! Sub module for GVTDX procedures. implicit none real, parameter :: pi=3.14159265e0 !! Pi for real real, parameter :: radius=6.371e6 !! polar radius of the Earth (m) complex, parameter :: img=(0.0,1.0) !! Imaginary unit for real double precision, parameter :: pi_dp=3.14159265358979d0 !! Pi for double double precision, parameter :: radius_dp=6.371d6 !! polar radius of the Earth (m) double precision, parameter :: omega_dp=7.2918933286303412732d-5 !! rotational angular velocity of Earth (s-1) complex(kind(0d0)), parameter :: img_cdp=(0.0d0,1.0d0) !! Imaginary unit for double contains !------------------------------------------ subroutine prod_vortex_structure( r, t, rmax, vmax, c1u, c2u, & & Vt, Vr, Vt_pert, Vr_pert, Vt_pert_ang, Vr_pert_ang, & & ropt, dopt, Vt_0, Vr_0, Uxm, Vym, flag_disp ) !! Producing vortex structure with rmax, vmax, and umax implicit none double precision, intent(in) :: r(:) !! radius [m] double precision, intent(in) :: t(:) !! azimuthal angle [rad] double precision, intent(in) :: rmax !! radius of maximum tangential wind speed [m] double precision, intent(in) :: vmax !! maximum tangential wind speed [m s-1] double precision, intent(in) :: c1u !! coefficient 1 for radial wind [s-1] double precision, intent(in) :: c2u !! coefficient 2 for radial wind [s-1] double precision, intent(out) :: Vt(size(r),size(t)) !! Profile of tangential wind double precision, intent(out) :: Vr(size(r),size(t)) !! Profile of radial wind double precision, intent(in), optional :: Vt_pert(:) !! perturbations of tangential wind [m s-1] double precision, intent(in), optional :: Vr_pert(:) !! perturbations of radial wind [m s-1] double precision, intent(in), optional :: Vt_pert_ang(:) !! angles of tangential wind [rad] double precision, intent(in), optional :: Vr_pert_ang(:) !! angles of radial wind [rad] logical, intent(in), optional :: ropt !! option for radial variation of perturbation Vt and Vr logical, intent(in), optional :: dopt !! option for divergent components of perturbation Vt and Vr double precision, intent(out), optional :: Vt_0(:) !! Radial profile of axisymmetric Vt [m s-1] double precision, intent(out), optional :: Vr_0(:) !! Radial profile of axisymmetric Vr [m s-1] double precision, intent(out), optional :: Uxm(2) !! Azimuthal averaged X-wind of wavenumber-1 component [m s-1] double precision, intent(out), optional :: Vym(2) !! Azimuthal averaged Y-wind of wavenumber-1 component [m s-1] logical, intent(in), optional :: flag_disp ! Flag for displaying each amplitude of asymmetric winds (default: .false.) integer :: nr, nt, i, j, k, nvtp, nvrp, nvpmax double precision :: tmp_vtp1, tmp_vrp1, tmp_vtp2n, tmp_vrp2n, rad_coef, radp_coef, lin_coef, dr double precision :: tmp_vtp1_div, tmp_vrp1_div double precision :: umean(2), vmean(2) double precision :: r_inv(size(r)) double precision, allocatable, dimension(:) :: Vtp_omax, Vrp_omax double precision, allocatable, dimension(:,:) :: zetap, divp double precision, allocatable, dimension(:,:,:) :: gkrr, dgkrr double precision, allocatable, dimension(:,:,:) :: gkrr_d, dgkrr_d logical rad_opt nr=size(r) nt=size(t) if(present(Vt_pert))then nvtp=size(Vt_pert) else nvtp=0 end if if(present(Vr_pert))then nvrp=size(Vr_pert) else nvrp=0 end if nvpmax=max(nvtp,nvrp) dr=r(2)-r(1) rad_opt=.false. if(present(ropt))then rad_opt=ropt if(nvpmax>0)then allocate(gkrr(nvpmax,nr+1,nr+1)) allocate(dgkrr(nvpmax,nr+1,nr+1)) allocate(zetap(nvpmax,nr+1)) gkrr=0.0d0 dgkrr=0.0d0 zetap=0.0d0 divp=0.0d0 do k=1,nvpmax do j=1,nr do i=1,nr if(r(i)-0.5d0*dr<0.0d0)then gkrr(k,i,j)=green_func( 0.0d0, r(j), k ) else gkrr(k,i,j)=green_func( r(i)-0.5d0*dr, r(j), k ) end if end do end do do j=1,nr gkrr(k,nr+1,j)=green_func( r(nr)+0.5d0*dr, r(j), k ) end do do i=1,nr gkrr(k,i,nr+1)=green_func( r(i)+0.5d0*dr, r(nr)+dr, k ) end do do j=1,nr do i=1,nr+1 dgkrr(k,i,j)=(gkrr(k,i,j+1)-gkrr(k,i,j))/dr end do end do do i=1,nr ! if(r(i)<2.0d0*rmax)then if(r(i)>=0.1d0*rmax.and.r(i)<2.0d0*rmax)then zetap(k,i)=abs(Vt_pert(k))/rmax end if end do end do end if end if if(present(dopt))then if(nvpmax>0)then allocate(gkrr_d(nvpmax,nr+1,nr+1)) allocate(dgkrr_d(nvpmax,nr+1,nr+1)) allocate(divp(nvpmax,nr+1)) gkrr_d=0.0d0 dgkrr_d=0.0d0 divp=0.0d0 do k=1,nvpmax do j=1,nr do i=1,nr if(r(i)-0.5d0*dr<0.0d0)then gkrr_d(k,i,j)=green_func( 0.0d0, r(j), k ) else gkrr_d(k,i,j)=green_func( r(i)-0.5d0*dr, r(j), k ) end if end do end do do j=1,nr gkrr_d(k,nr+1,j)=green_func( r(nr)+0.5d0*dr, r(j), k ) end do do i=1,nr gkrr_d(k,i,nr+1)=green_func( r(i)+0.5d0*dr, r(nr)+dr, k ) end do do j=1,nr do i=1,nr+1 dgkrr_d(k,i,j)=(gkrr_d(k,i,j+1)-gkrr_d(k,i,j))/dr end do end do do i=1,nr !ORGif(r(i)>=0.1d0*rmax.and.r(i)<2.0d0*rmax)then if(r(i)>=0.9d0*rmax.and.r(i)<2.0d0*rmax)then divp(k,i)=abs(Vr_pert(k))/rmax end if end do end do end if end if do i=1,nr if(r(i)/=0.0d0)then r_inv(i)=1.0d0/r(i) else r_inv(i)=0.0d0 end if end do do j=1,nt do i=1,nr tmp_vtp1=0.0d0 tmp_vrp1=0.0d0 tmp_vtp2n=0.0d0 tmp_vrp2n=0.0d0 tmp_vtp1_div=0.0d0 tmp_vrp1_div=0.0d0 if(present(Vt_pert))then if(rad_opt.eqv..true.)then if(nvtp>1)then ! do k=2,nvtp do k=1,nvtp lin_coef=line_integral( nr-1, r, dgkrr(k,1:nr,i), zetap(k,1:nr) )*dr tmp_vtp2n=tmp_vtp2n+(-lin_coef*dcos(dble(k)*(t(j)+Vt_pert_ang(k)))) end do end if else do k=1,nvtp tmp_vtp1=tmp_vtp1+Vt_pert(k)*dcos(dble(k)*(t(j)+Vt_pert_ang(k))) end do end if if(dopt.eqv..true.)then if(nvtp>1)then k=1 ! only WN-1 lin_coef=line_integral( nr-1, r, gkrr_d(k,1:nr,i), divp(k,1:nr) )*dr tmp_vtp2n=tmp_vtp2n+lin_coef*dsin(dble(k)*(t(j)+Vt_pert_ang(k)))*r_inv(i) end if end if end if if(present(Vr_pert))then if(rad_opt.eqv..true.)then if(nvrp>1)then ! do k=2,nvrp do k=1,nvrp lin_coef=line_integral( nr-1, r, gkrr(k,1:nr,i), zetap(k,1:nr) )*dr tmp_vrp2n=tmp_vrp2n+(-dble(k)*lin_coef*dsin(dble(k)*(t(j)+Vt_pert_ang(k)))*r_inv(i)) ! same as Vt_pert_ang end do end if else do k=1,nvrp tmp_vrp1=tmp_vrp1+Vr_pert(k)*dcos(dble(k)*(t(j)+Vr_pert_ang(k))) end do end if if(dopt.eqv..true.)then if(nvrp>1)then k=1 ! only WN-1 lin_coef=line_integral( nr-1, r, dgkrr_d(k,1:nr,i), divp(k,1:nr) )*dr tmp_vrp2n=tmp_vrp2n+(-dble(k)*lin_coef*dcos(dble(k)*(t(j)+Vt_pert_ang(k)))) ! same as Vt_pert_ang end if end if end if if(r(i)<=rmax)then rad_coef=r(i)/rmax radp_coef=r(i)/rmax Vt(i,j)=vmax*rad_coef Vr(i,j)=c1u*dsqrt((rmax-r(i))*r(i)) Vr(i,j)=Vr(i,j)*4.0*1.0e-3 ! 多分これが必要 [m] -> [km] else rad_coef=rmax*r_inv(i) if((r(i)>rmax).and.(r(i)<=1.5d0*rmax))then radp_coef=1.0d0 else radp_coef=rmax*r_inv(i) end if Vt(i,j)=vmax*rad_coef Vr(i,j)=-c2u*dsqrt(r(i)-rmax)*(rmax*r_inv(i)) Vr(i,j)=Vr(i,j)/dsqrt(1000.0d0) ! 多分これが必要 [m] -> [km] end if if(j==1)then if(present(Vt_0))then Vt_0(i)=Vt(i,j) end if if(present(Vr_0))then Vr_0(i)=Vr(i,j) end if end if if(rad_opt.eqv..true.)then Vt(i,j)=Vt(i,j)+tmp_vtp1*radp_coef+tmp_vtp2n Vr(i,j)=Vr(i,j)+tmp_vrp1*radp_coef+tmp_vrp2n else Vt(i,j)=Vt(i,j)+tmp_vtp1+tmp_vtp2n Vr(i,j)=Vr(i,j)+tmp_vrp1+tmp_vrp2n end if end do end do if(present(Uxm))then umean(1)=0.0d0 umean(2)=0.0d0 do j=1,nt umean(1)=umean(1)+(Vr(1,j)*dcos(t(j))-Vt(1,j)*dsin(t(j))) umean(2)=umean(2)+(Vr(nr,j)*dcos(t(j))-Vt(nr,j)*dsin(t(j))) end do umean(1)=umean(1)/dble(nt) umean(2)=umean(2)/dble(nt) Uxm(1:2)=umean(1:2) end if if(present(Vym))then vmean(1)=0.0d0 vmean(2)=0.0d0 do j=1,nt vmean(1)=vmean(1)+(Vr(1,j)*dsin(t(j))+Vt(1,j)*dcos(t(j))) vmean(2)=vmean(2)+(Vr(nr,j)*dsin(t(j))+Vt(nr,j)*dcos(t(j))) end do vmean(1)=vmean(1)/dble(nt) vmean(2)=vmean(2)/dble(nt) Vym(1:2)=vmean(1:2) end if if(present(flag_disp))then ! Only displaying values allocate(Vtp_omax(nvtp)) allocate(Vrp_omax(nvrp)) if((flag_disp.eqv..true.).and.(nvpmax>0))then if(present(Vt_pert))then if(rad_opt.eqv..true.)then do k=1,nvtp do i=1,nr Vtp_omax(k)=-line_integral( nr-1, r, dgkrr(k,1:nr,i), zetap(k,1:nr) )*dr ! write(*,'(a4,i2,a8,1PE16.8,a6)') "Vtp(", k ,",r_m) = ", Vtp_omax(k), "[m/s]." end do end do else do k=1,nvtp Vtp_omax(k)=Vt_pert(k) end do end if do k=1,nvtp write(*,'(a4,i2,a8,1PE16.8,a6)') "Vtp(", k ,",r_m) = ", Vtp_omax(k), "[m/s]." end do end if if(present(Vr_pert))then if(rad_opt.eqv..true.)then do k=1,nvrp do i=1,nr Vrp_omax(k)=-dble(k)*line_integral( nr-1, r, gkrr(k,1:nr,i), zetap(k,1:nr) )*dr*r_inv(i) ! write(*,'(a4,i2,a8,1PE16.8,a6)') "Vrp(", k ,",r_i) = ", Vrp_omax(k), "[m/s]." end do end do else do k=1,nvrp Vrp_omax(k)=Vr_pert(k) end do end if do k=1,nvrp write(*,'(a4,i2,a8,1PE16.8,a6)') "Vrp(", k ,",r_m) = ", Vrp_omax(k), "[m/s]." end do end if end if deallocate(Vtp_omax) deallocate(Vrp_omax) end if if(present(ropt))then if(nvpmax>0)then deallocate(gkrr) deallocate(dgkrr) deallocate(zetap) end if end if if(present(ropt))then if(nvpmax>0)then deallocate(gkrr_d) deallocate(dgkrr_d) deallocate(divp) end if end if end subroutine prod_vortex_structure !-------------------------------------------------- !-------------------------------------------------- subroutine prod_vortex_structure_L06( r, t, rmax, zmax, epsr, Vt_pert_ang, Vt, Vr ) !! Producing vortex structure with rmax, vmax, and umax in Lee et al. (2006) implicit none double precision, intent(in) :: r(:) !! radius [m] double precision, intent(in) :: t(:) !! azimuthal angle [rad] double precision, intent(in) :: rmax !! radius of maximum tangential wind speed [m] double precision, intent(in) :: zmax !! constant vorticity in the eye [s-1] double precision, intent(in) :: epsr !! distance of epsilon for WN2 [m] double precision, intent(in) :: Vt_pert_ang !! angles of tangential wind [rad] double precision, intent(out) :: Vt(size(r),size(t)) !! Profile of tangential wind double precision, intent(out) :: Vr(size(r),size(t)) !! Profile of radial wind integer :: nr, nt, i, j double precision :: R_ell nr=size(r) nt=size(t) do j=1,nt R_ell=rmax+epsr*dcos(2.0d0*t(j)+Vt_pert_ang) do i=1,nr if(r(i)<=R_ell)then Vt(i,j)=0.5d0*zmax*r(i)*(1.0d0+(epsr/rmax)*dcos(2.0d0*t(j)+Vt_pert_ang)) Vr(i,j)=0.5d0*zmax*r(i)*((epsr/rmax)*dsin(2.0d0*t(j)+Vt_pert_ang)) else Vt(i,j)=0.5d0*zmax*(rmax**2/r(i))*(1.0d0-epsr*(rmax/(r(i)**2))*dcos(2.0d0*t(j)+Vt_pert_ang)) Vr(i,j)=0.5d0*zmax*(rmax**2/r(i))*(epsr*(rmax/(r(i)**2))*dsin(2.0d0*t(j)+Vt_pert_ang)) end if end do end do end subroutine prod_vortex_structure_L06 !-------------------------------------------------- !-------------------------------------------------- !subroutine prod_radar_along_vel() ! implicit none ! !end subroutine prod_radar_along_vel !-------------------------------------------------- !-------------------------------------------------- subroutine conv_VtVr2VxVy_rt( r, t, Vt, Vr, Vx, Vy, undef ) !! Convert Vt and Vr to Vx and Vy on R-T coordinates implicit none double precision, intent(in) :: r(:) !! R-coordinate [m] double precision, intent(in) :: t(:) !! T-coordinate [rad] double precision, intent(in) :: Vt(size(r),size(t)) !! tangential wind component on R-T coordinates double precision, intent(in) :: Vr(size(r),size(t)) !! radial wind component on R-T coordinates double precision, intent(out) :: Vx(size(r),size(t)) !! X-component of wind on R-T coordinates double precision, intent(out) :: Vy(size(r),size(t)) !! Y-component of wind on R-T coordinates double precision, intent(in), optional :: undef !! Undefined value integer :: nr, nt, i, j nr=size(r) nt=size(t) if(present(undef))then Vx=undef Vy=undef do j=1,nt do i=1,nr if(Vt(i,j)/=undef.and.Vr(i,j)/=undef)then Vx(i,j)=Vr(i,j)*dcos(t(j))-Vt(i,j)*dsin(t(j)) Vy(i,j)=Vr(i,j)*dsin(t(j))+Vt(i,j)*dcos(t(j)) end if end do end do else do j=1,nt do i=1,nr Vx(i,j)=Vr(i,j)*dcos(t(j))-Vt(i,j)*dsin(t(j)) Vy(i,j)=Vr(i,j)*dsin(t(j))+Vt(i,j)*dcos(t(j)) end do end do end if end subroutine conv_VtVr2VxVy_rt !-------------------------------------------------- !-------------------------------------------------- subroutine conv_VxVy2VtVr_rt( r, t, Vx, Vy, Vt, Vr, undef ) !! Convert Vx and Vy to Vr and Vt on R-T coordinates implicit none double precision, intent(in) :: r(:) !! R-coordinate [m] double precision, intent(in) :: t(:) !! T-coordinate [rad] double precision, intent(in) :: Vx(size(r),size(t)) !! X-component of wind on R-T coordinates double precision, intent(in) :: Vy(size(r),size(t)) !! Y-component of wind on R-T coordinates double precision, intent(out) :: Vt(size(r),size(t)) !! tangential wind component on R-T coordinates double precision, intent(out) :: Vr(size(r),size(t)) !! radial wind component on R-T coordinates double precision, intent(in), optional :: undef !! Undefined value integer :: nr, nt, i, j nr=size(r) nt=size(t) if(present(undef))then Vr=undef Vt=undef do j=1,nt do i=1,nr if(Vx(i,j)/=undef.and.Vy(i,j)/=undef)then Vr(i,j)=Vx(i,j)*dcos(t(j))+Vy(i,j)*dsin(t(j)) Vt(i,j)=-Vx(i,j)*dsin(t(j))+Vy(i,j)*dcos(t(j)) end if end do end do else do j=1,nt do i=1,nr Vr(i,j)=Vx(i,j)*dcos(t(j))+Vy(i,j)*dsin(t(j)) Vt(i,j)=-Vx(i,j)*dsin(t(j))+Vy(i,j)*dcos(t(j)) end do end do end if end subroutine conv_VxVy2VtVr_rt !-------------------------------------------------- !-------------------------------------------------- subroutine conv_VxVy2VtVr_xy( x, y, xc, yc, Vx, Vy, Vt, Vr, undef ) !! Convert Vx and Vy to Vr and Vt on X-Y coordinates implicit none double precision, intent(in) :: x(:) !! X-coordinate [m] double precision, intent(in) :: y(:) !! Y-coordinate [m] double precision, intent(in) :: xc !! X component of the center [m] double precision, intent(in) :: yc !! Y component of the center [m] double precision, intent(in) :: Vx(size(x),size(y)) !! X-component of wind on X-Y coordinates double precision, intent(in) :: Vy(size(x),size(y)) !! Y-component of wind on X-Y coordinates double precision, intent(out) :: Vt(size(x),size(y)) !! tangential wind component on X-Y coordinates double precision, intent(out) :: Vr(size(x),size(y)) !! radial wind component on X-Y coordinates double precision, intent(in), optional :: undef !! Undefined value integer :: nx, ny, i, j double precision :: radi, radi_i nx=size(x) ny=size(y) if(present(undef))then Vr=undef Vt=undef do j=1,ny do i=1,nx if(Vx(i,j)/=undef.and.Vy(i,j)/=undef)then radi=dsqrt(dabs((x(i)-xc)**2+(y(j)-yc)**2)) if(radi/=0.0d0)then radi_i=1.0d0/radi Vr(i,j)=((x(i)-xc)*radi_i)*Vx(i,j)+((y(j)-yc)*radi_i)*Vy(i,j) Vt(i,j)=((x(i)-xc)*radi_i)*Vy(i,j)-((y(j)-yc)*radi_i)*Vx(i,j) else Vr(i,j)=0.0d0 Vt(i,j)=0.0d0 end if end if end do end do else do j=1,ny do i=1,nx radi=dsqrt(dabs((x(i)-xc)**2+(y(j)-yc)**2)) if(radi/=0.0d0)then radi_i=1.0d0/radi Vr(i,j)=((x(i)-xc)*radi_i)*Vx(i,j)+((y(j)-yc)*radi_i)*Vy(i,j) Vt(i,j)=((x(i)-xc)*radi_i)*Vy(i,j)-((y(j)-yc)*radi_i)*Vx(i,j) else Vr(i,j)=0.0d0 Vt(i,j)=0.0d0 end if end do end do end if end subroutine conv_VxVy2VtVr_xy !-------------------------------------------------- !-------------------------------------------------- subroutine proj_VxVy2Vraxy( x, y, rax, ray, Vx, Vy, Vraxy, undef ) !! Calculate Vx and Vy to Vd along with radar beams on X-Y coodinates implicit none double precision, intent(in) :: x(:) !! X-coordinate double precision, intent(in) :: y(:) !! Y-coordinate double precision, intent(in) :: rax !! X-coodinate of radar location double precision, intent(in) :: ray !! Y-coodinate of radar location double precision, intent(in) :: Vx(size(x),size(y)) !! X-component of wind on X-Y coordinates double precision, intent(in) :: Vy(size(x),size(y)) !! Y-component of wind on X-Y coordinates double precision, intent(out) :: Vraxy(size(x),size(y)) !! velocity along with beam on X-Y coordinates double precision, intent(in), optional :: undef !! Undefined value integer :: nx, ny, i, j double precision :: rad nx=size(x) ny=size(y) if(present(undef))then Vraxy=undef do j=1,ny do i=1,nx rad=dsqrt((x(i)-rax)**2+(y(j)-ray)**2) if(rad>0.0d0)then if(Vx(i,j)/=undef.and.Vy(i,j)/=undef)then Vraxy(i,j)=((x(i)-rax)/rad)*Vx(i,j)+((y(j)-ray)/rad)*Vy(i,j) end if end if end do end do else Vraxy=0.0d0 do j=1,ny do i=1,nx rad=dsqrt((x(i)-rax)**2+(y(j)-ray)**2) if(rad>0.0d0)then Vraxy(i,j)=((x(i)-rax)/rad)*Vx(i,j)+((y(j)-ray)/rad)*Vy(i,j) end if end do end do end if end subroutine proj_VxVy2Vraxy !-------------------------------------------------- !-------------------------------------------------- subroutine proj_VtVr2Vrart( r, t, td, Vt, Vr, Vra, undef ) !! Convert Vt and Vr to Vx and Vy on R-T coordinates implicit none double precision, intent(in) :: r(:) !! R-coordinate [m] double precision, intent(in) :: t(:) !! T-coordinate [rad] double precision, intent(in) :: td(size(r),size(t)) !! radar azimuthal angle on R-T coordinate [rad] double precision, intent(in) :: Vt(size(r),size(t)) !! tangential wind component on R-T coordinates double precision, intent(in) :: Vr(size(r),size(t)) !! radial wind component on R-T coordinates double precision, intent(out) :: Vra(size(r),size(t)) !! Velocity along beam on R-T coordinates double precision, intent(in), optional :: undef !! undefined value integer :: nr, nt, i, j nr=size(r) nt=size(t) do j=1,nt do i=1,nr if(Vt(i,j)/=undef.and.Vr(i,j)/=undef.and.td(i,j)/=undef)then Vra(i,j)=-Vt(i,j)*dsin(t(j)-td(i,j))+Vr(i,j)*dcos(t(j)-td(i,j)) else Vra(i,j)=undef end if end do end do end subroutine proj_VtVr2Vrart !-------------------------------------------------- !-------------------------------------------------- double precision function line_integral( nr, rdh, gkrr, div_r, undef ) !! Calculate a line integral (actually, sum for arguments) implicit none integer, intent(in) :: nr !! Radial grid number double precision, intent(in) :: rdh(nr+1) !! R-coordinate [m] double precision, intent(in) :: gkrr(nr+1) !! Green function double precision, intent(in) :: div_r(nr+1) !! Integral of gkrr double precision, intent(in), optional :: undef !! Undefined value integer :: ii, jj double precision :: tmpval double precision :: vareps(nr+1) tmpval=0.0d0 vareps=1.0d0 vareps(1)=0.5d0 vareps(nr+1)=0.5d0 do ii=1,nr+1 tmpval=tmpval+vareps(ii)*rdh(ii)*gkrr(ii)*div_r(ii) end do line_integral=tmpval return end function line_integral !-------------------------------------------------- !-------------------------------------------------- double precision function green_func( rc, r, nval ) !! Calculation of the Green function: \(,\; \) <br> !! \( G_n(r_c;r)=-(2^{-n})(r/r_c)^n, r<r_c \) <br> !! \( G_n(r_c;r)=-(2^{-n})(r_c/r)^n, r\geq r_c \) <br> !! \( n= \)nval implicit none double precision, intent(in) :: rc !! Source radius double precision, intent(in) :: r !! Non-source radius integer, intent(in) :: nval !! Order number double precision :: res, nr nr=dble(nval) if(rc<0.0d0.or.r<0.0d0)then call stdout( "rc and r must not be negative", "green_func", 1 ) write(*,*) "rc and r = ", rc, r end if if(r==rc)then res=-(0.5d0/nr) else if(r<rc)then res=-(0.5d0/nr)*((r/rc)**nval) else ! (r/rc)**nval == exp(nval*(log(r/rc))) if(rc==0.0d0)then res=0.0d0 else res=-(0.5d0/nr)*exp(dble(nval)*(log(rc)-log(r))) end if end if end if green_func=res return end function green_func !-------------------------------------------------- !-------------------------------------------------- subroutine div_curl_2d( r, t, ur, vt, divr, curl, undef ) !! Calculation of rotation and divergence from radial and tangential winds <br> !! divr = \(\dfrac{\partial ru_r}{r\partial r} + \dfrac{\partial v_t}{r\partial \theta} \) <br> !! curl = \(\dfrac{\partial rv_t}{r\partial r} - \dfrac{\partial u_r}{r\partial \theta} \) implicit none double precision, intent(in) :: r(:) !! radius [m] double precision, intent(in) :: t(:) !! angle [rad] double precision, intent(in) :: ur(size(r),size(t)) !! Ur [m/s] double precision, intent(in) :: vt(size(r),size(t)) !! Vt [m/s] double precision, intent(out) :: divr(size(r),size(t)) !! divergence [1/s] double precision, intent(out) :: curl(size(r),size(t)) !! rotation [1/s] double precision, intent(in), optional :: undef !! Undefined value integer :: ii, jj, ni, nj double precision :: dr, dt logical :: undeflag(size(r),size(t)) ni=size(r) nj=size(t) dr=r(2)-r(1) dt=t(2)-t(1) if(present(undef))then divr=undef curl=undef undeflag=.false. do jj=2,nj-1 do ii=2,ni-1 if(ur(ii,jj)==undef.or.vt(ii,jj)==undef)then undeflag(ii,jj)=.true. undeflag(ii-1,jj)=.true. undeflag(ii+1,jj)=.true. undeflag(ii,jj-1)=.true. undeflag(ii,jj+1)=.true. end if end do end do do jj=2,nj-1 if(ur(1,jj)==undef.or.vt(1,jj)==undef)then undeflag(1,jj)=.true. undeflag(2,jj)=.true. undeflag(1,jj-1)=.true. undeflag(1,jj+1)=.true. end if if(ur(ni,jj)==undef.or.vt(ni,jj)==undef)then undeflag(ni,jj)=.true. undeflag(ni-1,jj)=.true. undeflag(ni,jj-1)=.true. undeflag(ni,jj+1)=.true. end if end do do ii=2,ni-1 if(ur(ii,1)==undef.or.vt(ii,1)==undef)then undeflag(ii,1)=.true. undeflag(ii-1,1)=.true. undeflag(ii+1,1)=.true. undeflag(ii,2)=.true. end if if(ur(ii,nj)==undef.or.vt(ii,nj)==undef)then undeflag(ii,nj)=.true. undeflag(ii-1,nj)=.true. undeflag(ii+1,nj)=.true. undeflag(ii,nj-1)=.true. end if end do if(ur(1,1)==undef.or.vt(1,1)==undef)then undeflag(1,1)=.true. undeflag(2,1)=.true. undeflag(1,2)=.true. end if if(ur(ni,1)==undef.or.vt(ni,1)==undef)then undeflag(ni,1)=.true. undeflag(ni-1,1)=.true. undeflag(ni,2)=.true. end if if(ur(1,nj)==undef.or.vt(1,nj)==undef)then undeflag(1,nj)=.true. undeflag(2,nj)=.true. undeflag(1,nj-1)=.true. end if if(ur(ni,nj)==undef.or.vt(ni,nj)==undef)then undeflag(ni,nj)=.true. undeflag(ni-1,nj)=.true. undeflag(ni,nj-1)=.true. end if do jj=2,nj-1 do ii=2,ni-1 if(undeflag(ii,jj).eqv..false.)then divr(ii,jj)=0.5d0*(ur(ii+1,jj)-ur(ii-1,jj))/dr & & +ur(ii,jj)/r(ii) & & +0.5d0*(vt(ii,jj+1)-vt(ii,jj-1))/(r(ii)*dt) curl(ii,jj)=0.5d0*(vt(ii+1,jj)-vt(ii-1,jj))/dr & & +vt(ii,jj)/r(ii) & & -0.5d0*(ur(ii,jj+1)-ur(ii,jj-1))/(r(ii)*dt) end if end do end do if(r(1)>0.0d0)then do jj=2,nj-1 if(undeflag(1,jj).eqv..false.)then divr(1,jj)=(ur(2,jj)-ur(1,jj))/dr & & +ur(1,jj)/r(1) & & +0.5d0*(vt(1,jj+1)-vt(1,jj-1))/(r(1)*dt) curl(1,jj)=(vt(2,jj)-vt(1,jj))/dr & & +vt(1,jj)/r(1) & & -0.d50*(ur(1,jj+1)-ur(1,jj-1))/(r(1)*dt) end if end do end if do jj=2,nj-1 if(undeflag(ni,jj).eqv..false.)then divr(ni,jj)=(ur(ni,jj)-ur(ni-1,jj))/dr & & +ur(ni,jj)/r(ni) & & +0.5d0*(vt(ni,jj+1)-vt(ni,jj-1))/(r(ni)*dt) curl(ni,jj)=(vt(ni,jj)-vt(ni-1,jj))/dr & & +vt(ni,jj)/r(ni) & & -0.5d0*(ur(ni,jj+1)-ur(ni,jj-1))/(r(ni)*dt) end if end do do ii=2,ni-1 if(undeflag(ii,1).eqv..false.)then divr(ii,1)=0.5d0*(ur(ii+1,1)-ur(ii-1,1))/dr & & +ur(ii,1)/r(ii) & & +(vt(ii,2)-vt(ii,1))/(r(ii)*dt) curl(ii,1)=0.5d0*(vt(ii+1,1)-vt(ii-1,1))/dr & & +vt(ii,1)/r(ii) & & -(ur(ii,2)-ur(ii,1))/(r(ii)*dt) end if if(undeflag(ii,nj).eqv..false.)then divr(ii,nj)=0.5d0*(ur(ii+1,nj)-ur(ii-1,nj))/dr & & +ur(ii,nj)/r(ii) & & +(vt(ii,nj)-vt(ii,nj-1))/(r(ii)*dt) curl(ii,nj)=0.5d0*(vt(ii+1,nj)-vt(ii-1,nj))/dr & & +vt(ii,nj)/r(ii) & & -(ur(ii,nj)-ur(ii,nj-1))/(r(ii)*dt) end if end do if(r(1)>0.0d0)then if(undeflag(1,1).eqv..false.)then divr(1,1)=(ur(2,1)-ur(1,1))/dr & & +ur(1,1)/r(1) & & +(vt(1,2)-vt(1,1))/(r(1)*dt) curl(1,1)=(vt(2,1)-vt(1,1))/dr & & +vt(1,1)/r(1) & & -(ur(1,2)-ur(1,1))/(r(1)*dt) end if if(undeflag(1,nj).eqv..false.)then divr(1,nj)=(ur(2,nj)-ur(1,nj))/dr & & +ur(1,nj)/r(1) & & +(vt(1,nj)-vt(1,nj-1))/(r(1)*dt) curl(1,nj)=(vt(2,nj)-vt(1,nj))/dr & & +vt(1,nj)/r(1) & & -(ur(1,nj)-ur(1,nj-1))/(r(1)*dt) end if end if if(undeflag(ni,1).eqv..false.)then divr(ni,1)=(ur(ni,1)-ur(ni-1,1))/dr & & +ur(ni,1)/r(ni) & & +(vt(ni,2)-vt(ni,1))/(r(ni)*dt) curl(ni,1)=(vt(ni,1)-vt(ni-1,1))/dr & & +vt(ni,1)/r(ni) & & -(ur(ni,2)-ur(ni,1))/(r(ni)*dt) end if if(undeflag(ni,nj).eqv..false.)then divr(ni,nj)=(ur(ni,nj)-ur(ni-1,nj))/dr & & +ur(ni,nj)/r(ni) & & +(vt(ni,nj)-vt(ni,nj-1))/(r(ni)*dt) curl(ni,nj)=(vt(ni,nj)-vt(ni-1,nj))/dr & & +vt(ni,nj)/r(ni) & & -(ur(ni,nj)-ur(ni,nj-1))/(r(ni)*dt) end if else divr=0.0d0 curl=0.0d0 do jj=2,nj-1 do ii=2,ni-1 divr(ii,jj)=0.5d0*(ur(ii+1,jj)-ur(ii-1,jj))/dr & & +ur(ii,jj)/r(ii) & & +0.5d0*(vt(ii,jj+1)-vt(ii,jj-1))/(r(ii)*dt) curl(ii,jj)=0.5d0*(vt(ii+1,jj)-vt(ii-1,jj))/dr & & +vt(ii,jj)/r(ii) & & -0.5d0*(ur(ii,jj+1)-ur(ii,jj-1))/(r(ii)*dt) end do end do if(r(1)>0.0d0)then do jj=2,nj-1 divr(1,jj)=(ur(2,jj)-ur(1,jj))/dr & & +ur(1,jj)/r(1) & & +0.5d0*(vt(1,jj+1)-vt(1,jj-1))/(r(1)*dt) curl(1,jj)=(vt(2,jj)-vt(1,jj))/dr & & +vt(1,jj)/r(1) & & -0.d50*(ur(1,jj+1)-ur(1,jj-1))/(r(1)*dt) divr(ni,jj)=(ur(ni,jj)-ur(ni-1,jj))/dr & & +ur(ni,jj)/r(ni) & & +0.5d0*(vt(ni,jj+1)-vt(ni,jj-1))/(r(ni)*dt) curl(ni,jj)=(vt(ni,jj)-vt(ni-1,jj))/dr & & +vt(ni,jj)/r(ni) & & -0.5d0*(ur(ni,jj+1)-ur(ni,jj-1))/(r(ni)*dt) end do else do jj=2,nj-1 divr(ni,jj)=(ur(ni,jj)-ur(ni-1,jj))/dr & & +ur(ni,jj)/r(ni) & & +0.5d0*(vt(ni,jj+1)-vt(ni,jj-1))/(r(ni)*dt) curl(ni,jj)=(vt(ni,jj)-vt(ni-1,jj))/dr & & +vt(ni,jj)/r(ni) & & -0.5d0*(ur(ni,jj+1)-ur(ni,jj-1))/(r(ni)*dt) end do end if do ii=2,ni-1 divr(ii,1)=0.5d0*(ur(ii+1,1)-ur(ii-1,1))/dr & & +ur(ii,1)/r(ii) & & +(vt(ii,2)-vt(ii,1))/(r(ii)*dt) curl(ii,1)=0.5d0*(vt(ii+1,1)-vt(ii-1,1))/dr & & +vt(ii,1)/r(ii) & & -(ur(ii,2)-ur(ii,1))/(r(ii)*dt) divr(ii,nj)=0.5d0*(ur(ii+1,nj)-ur(ii-1,nj))/dr & & +ur(ii,nj)/r(ii) & & +(vt(ii,nj)-vt(ii,nj-1))/(r(ii)*dt) curl(ii,nj)=0.5d0*(vt(ii+1,nj)-vt(ii-1,nj))/dr & & +vt(ii,nj)/r(ii) & & -(ur(ii,nj)-ur(ii,nj-1))/(r(ii)*dt) end do if(r(1)>0.0d0)then divr(1,1)=(ur(2,1)-ur(1,1))/dr & & +ur(1,1)/r(1) & & +(vt(1,2)-vt(1,1))/(r(1)*dt) curl(1,1)=(vt(2,1)-vt(1,1))/dr & & +vt(1,1)/r(1) & & -(ur(1,2)-ur(1,1))/(r(1)*dt) divr(1,nj)=(ur(2,nj)-ur(1,nj))/dr & & +ur(1,nj)/r(1) & & +(vt(1,nj)-vt(1,nj-1))/(r(1)*dt) curl(1,nj)=(vt(2,nj)-vt(1,nj))/dr & & +vt(1,nj)/r(1) & & -(ur(1,nj)-ur(1,nj-1))/(r(1)*dt) end if divr(ni,1)=(ur(ni,1)-ur(ni-1,1))/dr & & +ur(ni,1)/r(ni) & & +(vt(ni,2)-vt(ni,1))/(r(ni)*dt) curl(ni,1)=(vt(ni,1)-vt(ni-1,1))/dr & & +vt(ni,1)/r(ni) & & -(ur(ni,2)-ur(ni,1))/(r(ni)*dt) divr(ni,nj)=(ur(ni,nj)-ur(ni-1,nj))/dr & & +ur(ni,nj)/r(ni) & & +(vt(ni,nj)-vt(ni,nj-1))/(r(ni)*dt) curl(ni,nj)=(vt(ni,nj)-vt(ni-1,nj))/dr & & +vt(ni,nj)/r(ni) & & -(ur(ni,nj)-ur(ni,nj-1))/(r(ni)*dt) end if end subroutine div_curl_2d !-------------------------------------------------- !-------------------------------------------------- subroutine rotate_thetad_tc( thetad_tc, Vx, Vy, undef ) !! Rotate horizontal winds in the east-west and north-south directions to the storm-relative direction. implicit none double precision, intent(in) :: thetad_tc !! Angle of the direction from the radar to the storm center [rad] double precision, intent(inout) :: Vx(:,:) !! Horizontal wind component in the east-west direction [m/s] double precision, intent(inout) :: Vy(size(Vx,1),size(Vx,2)) !! Horizontal wind component in the north-south direction [m/s] double precision, intent(in), optional :: undef !! Undefined value integer :: ii, jj, ni, nj double precision :: tmpu, tmpv ni=size(Vx,1) nj=size(Vx,2) if(present(undef))then do jj=1,nj do ii=1,ni if(Vx(ii,jj)/=undef.and.Vy(ii,jj)/=undef)then tmpu=Vx(ii,jj)*dcos(thetad_tc)+Vy(ii,jj)*dsin(thetad_tc) tmpv=-Vx(ii,jj)*dsin(thetad_tc)+Vy(ii,jj)*dcos(thetad_tc) Vx(ii,jj)=tmpu Vy(ii,jj)=tmpv end if end do end do else do jj=1,nj do ii=1,ni tmpu=Vx(ii,jj)*dcos(thetad_tc)+Vy(ii,jj)*dsin(thetad_tc) tmpv=-Vx(ii,jj)*dsin(thetad_tc)+Vy(ii,jj)*dcos(thetad_tc) Vx(ii,jj)=tmpu Vy(ii,jj)=tmpv end do end do end if end subroutine rotate_thetad_tc !-------------------------------------------------- !-------------------------------------------------- subroutine conv_d2r_1d( ival, oval ) !! Convert double to real implicit none double precision, intent(in) :: ival(:) !! Input real, intent(out) :: oval(size(ival)) !! Output integer :: ii, ni ni=size(ival) do ii=1,ni oval(ii)=real(ival(ii)) end do end subroutine conv_d2r_1d !-------------------------------------------------- !-------------------------------------------------- subroutine conv_d2r_2d( ival, oval ) !! Convert double to real implicit none double precision, intent(in) :: ival(:,:) !! Input real, intent(out) :: oval(size(ival,1),size(ival,2)) !! Output integer :: ii, jj, ni, nj ni=size(ival,1) nj=size(ival,2) do jj=1,nj do ii=1,ni oval(ii,jj)=real(ival(ii,jj)) end do end do end subroutine conv_d2r_2d !-------------------------------------------------- !-------------------------------------------------- subroutine conv_d2r_3d( ival, oval ) !! convert double to real implicit none double precision, intent(in) :: ival(:,:,:) !! input array real, intent(out) :: oval(size(ival,1),size(ival,2),size(ival,3)) !! output array integer :: ii, jj, kk, ni, nj, nk !! internal variables ni=size(ival,1) nj=size(ival,2) nk=size(ival,3) do kk=1,nk do jj=1,nj do ii=1,ni !write(*,*) "checkii", ii, jj, kk, ival(ii,jj,kk) if(dabs(ival(ii,jj,kk))>1.0d15)then oval(ii,jj,kk)=-1.0e3 else oval(ii,jj,kk)=real(ival(ii,jj,kk)) end if end do end do end do end subroutine conv_d2r_3d !-------------------------------------------------- !-------------------------------------------------- subroutine conv_r2d_2d( ival, oval ) !! convert real to double implicit none real, intent(in) :: ival(:,:) !! input array double precision, intent(out) :: oval(size(ival,1),size(ival,2)) !! output array integer :: ii, jj, ni, nj !! internal variables ni=size(ival,1) nj=size(ival,2) do jj=1,nj do ii=1,ni oval(ii,jj)=dble(ival(ii,jj)) end do end do end subroutine conv_r2d_2d !-------------------------------------------------- !-------------------------------------------------- subroutine sum_1d( val, res, undef ) !! Calculation of sum for 1D variable implicit none double precision, intent(in) :: val(:) !! input double precision, intent(out) :: res !! output double precision, intent(in), optional :: undef integer :: ii, ni, icount ni=size(val) icount=0 res=0.0d0 if(present(undef))then do ii=1,ni if(val(ii)/=undef)then res=res+val(ii) icount=icount+1 end if end do if(icount>0)then res=res/dble(icount) else res=undef end if else do ii=1,ni res=res+val(ii) end do res=res/dble(ni) end if end subroutine sum_1d !-------------------------------------------------- !-------------------------------------------------- subroutine add_2d( ioval, ival, undef ) !! add ival implicit none double precision, intent(inout) :: ioval(:,:) !! Base value double precision, intent(in) :: ival(size(ioval,1),size(ioval,2)) !! added double precision, intent(in), optional :: undef !! Undefined value integer :: ii, jj, ni, nj ni=size(ioval,1) nj=size(ioval,2) if(present(undef))then do jj=1,nj do ii=1,ni if(ioval(ii,jj)/=undef.and.ival(ii,jj)/=undef)then ioval(ii,jj)=ioval(ii,jj)+ival(ii,jj) else ioval(ii,jj)=undef end if end do end do else do jj=1,nj do ii=1,ni ioval(ii,jj)=ioval(ii,jj)+ival(ii,jj) end do end do end if end subroutine add_2d !-------------------------------------------------- !-------------------------------------------------- subroutine add_3d( ioval, ival, undef ) !! add ival implicit none double precision, intent(inout) :: ioval(:,:,:) !! Base value double precision, intent(in) :: ival(size(ioval,1),size(ioval,2),size(ioval,3)) !! added double precision, intent(in), optional :: undef !! Undefined value integer :: ii, jj, kk, ni, nj, nk ni=size(ioval,1) nj=size(ioval,2) nk=size(ioval,3) if(present(undef))then do kk=1,nk do jj=1,nj do ii=1,ni if(ioval(ii,jj,kk)/=undef.and.ival(ii,jj,kk)/=undef)then ioval(ii,jj,kk)=ioval(ii,jj,kk)+ival(ii,jj,kk) else ioval(ii,jj,kk)=undef end if end do end do end do else do kk=1,nk do jj=1,nj do ii=1,ni ioval(ii,jj,kk)=ioval(ii,jj,kk)+ival(ii,jj,kk) end do end do end do end if end subroutine add_3d !-------------------------------------------------- !-------------------------------------------------- subroutine subst_2d( ioval, ival, undef ) !! subtract ival implicit none double precision, intent(inout) :: ioval(:,:) !! Base value double precision, intent(in) :: ival(size(ioval,1),size(ioval,2)) !! Subtracted double precision, intent(in), optional :: undef !! Undefined value integer :: ii, jj, ni, nj ni=size(ioval,1) nj=size(ioval,2) if(present(undef))then do jj=1,nj do ii=1,ni if(ioval(ii,jj)/=undef.and.ival(ii,jj)/=undef)then ioval(ii,jj)=ioval(ii,jj)-ival(ii,jj) else ioval(ii,jj)=undef end if end do end do else do jj=1,nj do ii=1,ni ioval(ii,jj)=ioval(ii,jj)-ival(ii,jj) end do end do end if end subroutine subst_2d !-------------------------------------------------- !-------------------------------------------------- subroutine subst_2d_r( ioval, ival, undef ) !! subtract ival implicit none real, intent(inout) :: ioval(:,:) !! Base value real, intent(in) :: ival(size(ioval,1),size(ioval,2)) !! Subtracted value real, intent(in), optional :: undef !! Undefined value integer :: ii, jj, ni, nj ni=size(ioval,1) nj=size(ioval,2) if(present(undef))then do jj=1,nj do ii=1,ni if(ioval(ii,jj)/=undef.and.ival(ii,jj)/=undef)then ioval(ii,jj)=ioval(ii,jj)-ival(ii,jj) else ioval(ii,jj)=undef end if end do end do else do jj=1,nj do ii=1,ni ioval(ii,jj)=ioval(ii,jj)-ival(ii,jj) end do end do end if end subroutine subst_2d_r !-------------------------------------------------- !-------------------------------------------------- subroutine rearrange_3d_2d( val3d, val2d ) !! Rearrange 3d variable to 2d variable (k,i,j -> i*j,k) implicit none double precision, intent(in) :: val3d(:,:,:) !! Input double precision, intent(out) :: val2d(size(val3d,2)*size(val3d,3),size(val3d,1)) !! Output integer :: ii, jj, kk, ni, nj, nk nk=size(val3d,1) ni=size(val3d,2) nj=size(val3d,3) do kk=1,nk do jj=1,nj do ii=1,ni val2d(ni*(jj-1)+ii,kk)=val3d(kk,ii,jj) end do end do end do end subroutine rearrange_3d_2d !-------------------------------------------------- !-------------------------------------------------- subroutine rearrange_2d_1d( val2d, val1d ) !! Rearrange 2d variable to 1d variable (i,j -> i*j) implicit none double precision, intent(in) :: val2d(:,:) !! Input double precision, intent(out) :: val1d(size(val2d,1)*size(val2d,2)) !! Output integer :: ii, jj, ni, nj ni=size(val2d,1) nj=size(val2d,2) do jj=1,nj do ii=1,ni val1d(ni*(jj-1)+ii)=val2d(ii,jj) end do end do end subroutine rearrange_2d_1d !-------------------------------------------------- !-------------------------------------------------- subroutine display_1val_max( val, undef, cout, vout ) !! Display the maximum of the array val implicit none real, intent(in) :: val(:,:) !! Input 1 real, intent(in), optional :: undef !! Undefined value character(*), intent(out), optional :: cout !! Maximum value by character real, intent(out), optional :: vout !! Maximum value by float integer :: ii, jj, ni, nj, maxi, maxj real :: maxv, dval ni=size(val,1) nj=size(val,2) maxv=0.0 maxi=0 maxj=0 if(present(undef))then do jj=1,nj do ii=1,ni if(val(ii,jj)/=undef)then dval=abs(val(ii,jj)) if(maxv<dval)then maxv=dval maxi=ii maxj=jj end if end if end do end do else do jj=1,nj do ii=1,ni dval=abs(val(ii,jj)) if(maxv<dval)then maxv=dval maxi=ii maxj=jj end if end do end do end if write(*,'(a21,1PE16.8,a5,i4,a1,i4,a2)') "Maximum difference = ", maxv, & & " at (", maxi, ",", maxj, ")." if(present(cout))then write(cout,'(1PE8.1)') maxv end if if(present(vout))then vout=maxv end if end subroutine display_1val_max !-------------------------------------------------- !-------------------------------------------------- subroutine display_2valdiff_max( val1, val2, undef, cout, vout ) !! Display the maximum of the difference between val1 and val2 implicit none double precision, intent(in) :: val1(:,:) !! Input 1 double precision, intent(in) :: val2(size(val1,1),size(val1,2)) !! Input 2 double precision, intent(in), optional :: undef !! Undefined value character(*), intent(out), optional :: cout !! Maximum value by character real, intent(out), optional :: vout !! Maximum value by float integer :: ii, jj, ni, nj, maxi, maxj double precision :: maxv, dval ni=size(val1,1) nj=size(val1,2) maxv=0.0d0 maxi=0 maxj=0 if(present(undef))then do jj=1,nj do ii=1,ni if(val1(ii,jj)/=undef.and.val2(ii,jj)/=undef)then dval=dabs(val1(ii,jj)-val2(ii,jj)) if(maxv<dval)then maxv=dval maxi=ii maxj=jj end if end if end do end do else do jj=1,nj do ii=1,ni dval=dabs(val1(ii,jj)-val2(ii,jj)) if(maxv<dval)then maxv=dval maxi=ii maxj=jj end if end do end do end if write(*,'(a21,1PE16.8,a5,i4,a1,i4,a2)') "Maximum difference = ", maxv, & & " at (", maxi, ",", maxj, ")." if(present(cout))then write(cout,'(1PE8.1)') maxv end if if(present(vout))then vout=maxv end if end subroutine display_2valdiff_max !-------------------------------------------------- !-------------------------------------------------- subroutine stdout( message, routine_name, mtype ) !! Standard output for message implicit none character(*), intent(in) :: message !! output message character(*), intent(in) :: routine_name !! called routine name integer, intent(in) :: mtype !! message type !! 0: message, -1: error, 1: warning character(100) :: tname, forma character(10000) :: all_mess tname='' all_mess='' select case (mtype) case (0) ! message tname(1:7)="MESSAGE" case (-1) ! error tname(1:5)="ERROR" case (1) ! warning tname(1:7)="WARNING" end select all_mess="*** "//trim(adjustl(tname))//"("//trim(adjustl(routine_name)) & & //") *** : "//trim(adjustl(message)) write(forma,*) len_trim(adjustl(all_mess)) forma='(a'//trim(adjustl(forma))//')' write(6,trim(adjustl(forma))) trim(adjustl(all_mess)) end subroutine stdout !------------------------------------------------------------! ! Reuse the subroutine from the STPK library (0.9.20.0) ! ! STPK library (LGPL2.1): ! ! https://www.gfd-dennou.org/library/davis/stpk/index.htm.en ! !------------------------------------------------------------! subroutine fp_gauss( c, d, x ) !! Gauss-Jordan method with fully pivotting (from STPK) implicit none double precision, intent(in) :: d(:) !! Vector double precision, intent(in) :: c(size(d),size(d)) !! Square matrix (array is the first elements) double precision, intent(inout) :: x(size(d)) !! Vector for unknown variables !-- internal variables double precision :: b(size(d)) ! == d double precision :: a(size(d),size(d)) ! == c double precision :: s, pivotb ! working variables for pivotting double precision :: pivot(size(d)+1), y(size(d)) ! working variables for pivotting integer :: i, j, k, nmax, pivi, pivj, ipv integer :: ipivot(size(d)) ! temporary store of the original values for replacement nmax=size(b) do k=1,nmax do j=1,nmax a(k,j)=c(j,k) ! Replacement between the column and array end do b(k)=d(k) ipivot(k)=k end do !-- Forward erasure --- !-- Forward erasure for a(i,j) --- do k=1,nmax-1 !-- Start the pivotting procedure --- !-- Determine the maximum value in the matrix elements --- pivi=k pivj=k do i=k,nmax do j=k,nmax if(dabs(a(i,j)).gt.dabs(a(pivi,pivj)))then pivi=i pivj=j end if end do end do ipv=ipivot(pivj) ipivot(pivj)=ipivot(k) ipivot(k)=ipv !-- Replacing the column with the maximum value to the current column --- do i=1,nmax pivot(i)=a(i,k) a(i,k)=a(i,pivj) a(i,pivj)=pivot(i) end do !-- Replacing the array with the maximum value to the current array --- do j=k,nmax pivot(j)=a(k,j) a(k,j)=a(pivi,j) a(pivi,j)=pivot(j) end do pivotb=b(k) b(k)=b(pivi) b(pivi)=pivotb if(dabs(a(k,k))<=1.0d-10)then write(*,*) "detect small", a(k,k:nmax) end if !-- End the pivotting procedure --- do i=k+1,nmax a(k,i)=a(k,i)/a(k,k) end do b(k)=b(k)/a(k,k) a(k,k)=1.0d0 do j=k+1,nmax do i=k+1,nmax a(j,i)=a(j,i)-a(k,i)*a(j,k) end do b(j)=b(j)-b(k)*a(j,k) a(j,k)=0.0d0 end do end do b(nmax)=b(nmax)/a(nmax,nmax) a(nmax,nmax)=1.0d0 !-- Back substitution of x(i) y(nmax)=b(nmax) do i=nmax-1,1,-1 s=b(i) do j=i+1,nmax s=s-a(i,j)*y(j) end do y(i)=s end do do i=1,nmax x(ipivot(i))=y(i) end do end subroutine fp_gauss !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine fp_invert_mat( ax, xx ) !! Calculate the inverse "xx" for the matrix "ax" (from STPK) implicit none double precision, intent(in) :: ax(:,:) !! Input matrix double precision, intent(inout) :: xx(size(ax,1),size(ax,2)) !! Inverse integer :: i, j, k double precision :: c(size(ax,1),size(ax,2)) double precision :: d(size(ax,1),size(ax,2)) integer :: nx nx=size(ax,1) c=0.0d0 do i=1,nx c(i,i)=1.0d0 end do d(1:nx,1:nx)=ax(1:nx,1:nx) !$omp parallel default(shared) !$omp do schedule(runtime) private(i) do i=1,nx call fp_gauss( d, c(1:nx,i), xx(1:nx,i) ) end do !$omp end do !$omp end parallel end subroutine fp_invert_mat !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine tangent_conv_scal( x, y, xc, yc, u, r, theta, v, & & undef, undefg, stdopt ) !! Convert the Cartesian grid to polar grid with the origin of !! the storm center (from STPK) !! The procedure: !! (1) Define the given polar grid (r-theta) on the Cartesian grid !! (2) Search the 4 nearest points on the Cartesian grid (x-y) for each polar grid point !! (3) Performing the bilinear interpolation of the 4 values defined on the !! Cartesian grid to the polar grid. implicit none double precision, intent(in) :: x(:) !! X-coordinate on the Cartesian grid double precision, intent(in) :: y(:) !! Y-coordinate on the Cartesian grid double precision, intent(in) :: u(size(x),size(y)) !! Values defined on the Cartesian grid double precision, intent(in) :: xc !! X-component of the storm center double precision, intent(in) :: yc !! Y-component of the storm center double precision, intent(in) :: r(:) !! R-coordinate on the polar grid with the origin (xc, yc). double precision, intent(in) :: theta(:) !! theta-coordinate of the polar grid with the origin (xc, yc) [rad] double precision, intent(out) :: v(size(r),size(theta)) !! Values converted to the polar grid double precision, intent(in), optional :: undef !! Missing value for the outside of the polar grid area (default: -999.0) double precision, intent(in), optional :: undefg !! Missing value for the inside of the polar grid area (default: -999.0) logical, intent(in), optional :: stdopt !! Display debug messages. !! (default: .false. == No display) !-- internal variables integer :: i, j, nx, ny, nr, nt, i_undef double precision :: r_undef, r_undefg double precision :: work(size(r),size(theta)) double precision :: point(size(r),size(theta),2) integer :: ip(size(r),size(theta),2) double precision :: tmpx(2), tmpy(2), tmpz(2,2), inter(2) double precision :: tmppointd1, tmppointd2 logical :: ucf, stderr nx=size(x) ny=size(y) nr=size(r) nt=size(theta) i_undef=0 if(present(undef))then r_undef=undef else r_undef=-999.0d0 end if if(present(undefg))then r_undefg=undefg else r_undefg=-999.0d0 end if if(present(stdopt))then stderr=stdopt else stderr=.false. end if !-- Process (1) --- do j=1,nt do i=1,nr call rt_2_xy( r(i), theta(j), point(i,j,1), point(i,j,2) ) point(i,j,1)=xc+point(i,j,1) point(i,j,2)=yc+point(i,j,2) end do end do !-- Process (2) --- do j=1,nt do i=1,nr call interpo_search_2d( x, y, point(i,j,1), point(i,j,2), & & ip(i,j,1), ip(i,j,2), undeff=i_undef, & & stdopt=stderr ) end do end do !-- Process (3) --- do j=1,nt do i=1,nr if(ip(i,j,1)/=i_undef.and.ip(i,j,2)/=i_undef.and. & & ip(i,j,1)/=nx.and.ip(i,j,2)/=ny)then tmpx(1)=x(ip(i,j,1)) tmpx(2)=x(ip(i,j,1)+1) tmpy(1)=y(ip(i,j,2)) tmpy(2)=y(ip(i,j,2)+1) tmpz(1,1)=u(ip(i,j,1),ip(i,j,2)) tmpz(2,1)=u(ip(i,j,1)+1,ip(i,j,2)) tmpz(1,2)=u(ip(i,j,1),ip(i,j,2)+1) tmpz(2,2)=u(ip(i,j,1)+1,ip(i,j,2)+1) inter(1)=point(i,j,1) inter(2)=point(i,j,2) if(present(undefg))then ucf=undef_checker_2d( tmpz, undefg ) if(ucf.eqv..false.)then call interpolation_2d( tmpx, tmpy, tmpz, inter, work(i,j) ) else work(i,j)=r_undefg end if else call interpolation_2d( tmpx, tmpy, tmpz, inter, work(i,j) ) end if else work(i,j)=r_undef end if end do end do do j=1,nt do i=1,nr v(i,j)=work(i,j) end do end do end subroutine tangent_conv_scal !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine cart_conv_scal( r, theta, v, x, y, xc, yc, u, & & undef, undefg, stdopt ) !! Convert polar grid with the origin of the storm center to !! the Cartesian grid (from STPK) !! The procedure: !! (1) Define the given Cartesian grid (x-y) on the polar grid !! (2) Search the 4 nearest points on the polar grid for each Cartesian grid point !! (3) Performing the bilinear interpolation of the 4 values defined on the !! polar grid to the Cartesian grid. implicit none double precision, intent(in) :: r(:) !! R-coordinate on the polar grid with the origin (xc, yc). double precision, intent(in) :: theta(:) !! theta-coordinate of the polar grid with the origin (xc, yc) [rad] double precision, intent(in) :: v(size(r),size(theta)) !! Values defined on the polar grid double precision, intent(in) :: x(:) !! X-coordinate on the Cartesian grid double precision, intent(in) :: y(:) !! Y-coordinate on the Cartesian grid double precision, intent(in) :: xc !! X-component of the storm center double precision, intent(in) :: yc !! Y-component of the storm center double precision, intent(out) :: u(size(x),size(y)) !! Values converted to the Cartesian grid double precision, intent(in), optional :: undef !! Missing value for the outside of the Cartesian grid area (default: -999.0) double precision, intent(in), optional :: undefg !! Missing value for the inside of the Cartesian grid area (default: -999.0) logical, intent(in), optional :: stdopt !! Display debug messages. !! (default: .false. == No display) !-- internal variables integer :: i, j, nx, ny, nr, nt, i_undef double precision :: r_undef, r_undefg double precision :: work(size(x),size(y)) double precision :: point(size(x),size(y),2) integer :: ip(size(x),size(y),2) double precision :: tmpx(2), tmpy(2), tmpz(2,2), inter(2) double precision :: tmppoint1, tmppoint2 logical :: ucf, stderr nx=size(x) ny=size(y) nr=size(r) nt=size(theta) i_undef=0 if(present(undef))then r_undef=undef else r_undef=-999.0d0 end if if(present(undefg))then r_undefg=undefg else r_undefg=-999.0d0 end if if(present(stdopt))then stderr=stdopt else stderr=.false. end if !-- Process (1) --- do j=1,ny do i=1,nx call xy_2_rt( x(i), y(j), xc, yc, point(i,j,1), point(i,j,2) ) ! if(point(i,j,2)<0.0d0)then ! point(i,j,2)=point(i,j,2)+2.0d0*pi_dp ! end if if(point(i,j,2)<theta(1))then ! +2pi do while(point(i,j,2)<theta(1)) point(i,j,2)=point(i,j,2)+2.0d0*pi_dp end do else if(point(i,j,2)>theta(nt))then ! -2pi do while(point(i,j,2)>theta(nt)) point(i,j,2)=point(i,j,2)-2.0d0*pi_dp end do end if end do end do !-- Process (2) --- do j=1,ny do i=1,nx call interpo_search_2d( r, theta, point(i,j,1), point(i,j,2), & & ip(i,j,1), ip(i,j,2), undeff=i_undef, & & stdopt=stderr ) end do end do !-- Process (3) --- do j=1,ny do i=1,nx if(ip(i,j,1)/=i_undef.and.ip(i,j,2)/=i_undef.and. & & ip(i,j,1)/=nr.and.ip(i,j,2)/=nt)then tmpx(1)=r(ip(i,j,1)) tmpx(2)=r(ip(i,j,1)+1) tmpy(1)=theta(ip(i,j,2)) tmpy(2)=theta(ip(i,j,2)+1) tmpz(1,1)=v(ip(i,j,1),ip(i,j,2)) tmpz(2,1)=v(ip(i,j,1)+1,ip(i,j,2)) tmpz(1,2)=v(ip(i,j,1),ip(i,j,2)+1) tmpz(2,2)=v(ip(i,j,1)+1,ip(i,j,2)+1) inter(1)=point(i,j,1) inter(2)=point(i,j,2) if(present(undefg))then ucf=undef_checker_2d( tmpz, undefg ) if(ucf.eqv..false.)then call interpolation_2d( tmpx, tmpy, tmpz, inter, work(i,j) ) else work(i,j)=r_undefg end if else call interpolation_2d( tmpx, tmpy, tmpz, inter, work(i,j) ) end if else work(i,j)=r_undef end if end do end do do j=1,ny do i=1,nx u(i,j)=work(i,j) end do end do end subroutine cart_conv_scal !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine Mean_1d( x, ave, error, nc ) !! Average x implicit none double precision, intent(in) :: x(:) !! Input data double precision, intent(inout) :: ave !! Output mean value double precision, intent(in), optional :: error !! Missing value integer, intent(inout), optional :: nc !! Number of sampling data without error integer :: i, nt integer :: nx ! sampling number of x double precision :: summ summ=0.0d0 nt=0 nx=size(x) if(present(error))then do i=1,nx if(x(i)/=error)then summ=summ+x(i) nt=1+nt end if end do if(nt/=0)then ave=summ/dble(nt) else ave=error end if if(present(nc))then nc=nt end if else do i=1,nx summ=summ+x(i) end do ave=summ/dble(nx) end if end subroutine Mean_1d !-------------------------------------------------------------- !-------------------------------------------------------------- logical function undef_checker_2d( val, undef ) !! Check missing value in "val" implicit none double precision, dimension(:,:), intent(in) :: val !! Input double precision, intent(in) :: undef !! Undefined value integer :: i, nx logical :: checker nx=size(val,2) checker=.false. do i=1,nx checker=undef_checker_1d( val(:,i), undef ) if(checker.eqv..true.)then exit end if end do undef_checker_2d=checker return end function undef_checker_2d !-------------------------------------------------------------- !-------------------------------------------------------------- logical function undef_checker_1d( val, undef ) !! Check missing value in "val" implicit none double precision, dimension(:), intent(in) :: val !! Input double precision, intent(in) :: undef !! Undefined value integer :: i, nx logical :: checker nx=size(val) checker=.false. do i=1,nx if(val(i)==undef)then checker=.true. exit end if end do undef_checker_1d=checker return end function undef_checker_1d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine interpo_search_2d( x, y, pointx, pointy, i, j, undeff, stdopt ) !! Floor function for the real grid points (from STPK) implicit none double precision, intent(in) :: x(:) !! X-coordinate double precision, intent(in) :: y(:) !! Y-coordinate double precision, intent(in) :: pointx !! The X point in real double precision, intent(in) :: pointy !! The Y point in real integer, intent(out) :: i !! floor(pointx) integer, intent(out) :: j !! floor(pointy) integer, intent(in), optional :: undeff !! In case of (x(1)>pointx or y(1)>pointy), the value returned to i and j !! (default = 0) logical, intent(in), optional :: stdopt !! Display debug messages !! (default = .false. = Not display) !-- internal variables integer :: just logical :: stderr if(present(stdopt))then stderr=stdopt else stderr=.false. end if if(present(undeff))then just=undeff call interpo_search_1d( x, pointx, i, just, stdopt=stderr ) call interpo_search_1d( y, pointy, j, just, stdopt=stderr ) else call interpo_search_1d( x, pointx, i, stdopt=stderr ) call interpo_search_1d( y, pointy, j, stdopt=stderr ) end if end subroutine interpo_search_2d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine interpo_search_1d( x, point, i, undeff, stdopt ) !! Floor function for the real grid points (from STPK) implicit none double precision, intent(in) :: x(:) !! X-coordinate double precision, intent(in) :: point !! The X point in real integer, intent(out) :: i !! floor(pointx) integer, intent(in), optional :: undeff !! In case of (x(1)>pointx or y(1)>pointy), the value returned to i and j !! (default = 0) logical, intent(in), optional :: stdopt !! Display debug messages !! (default = .false. = Not display) !-- internal variables integer :: nx, j integer :: just logical :: stderr nx=size(x) if(present(undeff))then just=undeff else just=0 end if if(present(stdopt))then stderr=stdopt else stderr=.false. end if if(x(1)>point)then if(stderr.eqv..false.)then write(*,*) "****** WARNING ******" write(*,*) "searching point was not found :", x(1), point write(*,*) "Abort. Exit.!!!" end if i=just else do j=1,nx if(x(j)<=point)then i=j else exit end if end do end if end subroutine interpo_search_1d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine xy_2_rt( x, y, xc, yc, r, t ) !! Convert the Cartesian (x-y) grid to the polar (r-t) grid (from STPK) implicit none double precision, intent(in) :: x !! X-coordinate [m] double precision, intent(in) :: y !! Y-coordinate [m] double precision, intent(in) :: xc !! X-coordinate of the center on the polar grid double precision, intent(in) :: yc !! Y-coordinate of the center on the polar grid double precision, intent(out) :: r !! Radius [m] double precision, intent(out) :: t !! Angle [rad] double precision :: rx, ry rx=x-xc ry=y-yc r=dsqrt(rx**2+ry**2) if(rx==0.0d0.and.ry==0.0d0)then t=0.0d0 else if(rx==0.0d0.and.ry/=0.0d0)then if(ry>0.0d0)then t=0.5d0*pi_dp else t=1.5d0*pi_dp end if else if(rx/=0.0d0.and.ry==0.0d0)then if(rx>0.0d0)then t=0.0d0 else t=pi_dp end if else if(rx>0.0d0.and.ry>0.0d0)then t=datan(ry/rx) else if(rx<0.0d0.and.ry>0.0d0)then t=pi_dp-datan(ry/dabs(rx)) else if(rx>0.0d0.and.ry<0.0d0)then t=2.0d0*pi_dp-datan(dabs(ry)/rx) else if(rx<0.0d0.and.ry<0.0d0)then t=pi_dp+datan(ry/rx) end if end if end subroutine xy_2_rt !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine rt_2_xy( r, t, x, y ) !! Convert the polar grid (r-t) to the Cartesian (x-y) grid (from STPK) implicit none double precision, intent(in) :: r !! Radius [m] double precision, intent(in) :: t !! Angle [rad] double precision, intent(out) :: x !! X-coordinate [m] double precision, intent(out) :: y !! Y-coordinate [m] x=r*dcos(t) y=r*dsin(t) end subroutine rt_2_xy !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine interpolation_2d( x, y, z, point, val ) !! Perform bilinear interpolation to the "point" on the Cartesian (x-y) grid (from STPK) implicit none double precision, intent(in) :: x(2) !! The nearest west and east points for "point" double precision, intent(in) :: y(2) !! The nearest south and north points for "point" double precision, intent(in) :: z(2,2) !! Values defined at (x,y). !! z(1,1) at x(1), y(1) !! z(1,2) at x(1), y(2) !! z(2,1) at x(2), y(1) !! z(2,2) at x(2), y(2) double precision, intent(in) :: point(2) !! The target point for the interpolation double precision, intent(out) :: val !! Interpolated value ! internal variables double precision :: valx(2) call interpolation_1d( x, (/z(1,1), z(2,1)/), point(1), valx(1) ) call interpolation_1d( x, (/z(1,2), z(2,2)/), point(1), valx(2) ) call interpolation_1d( y, valx, point(2), val ) end subroutine interpolation_2d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine interpolation_1d( x, y, point, val ) !! Perform linear interpolation to the "point" on the Cartesian (x) grid (from STPK) implicit none double precision, intent(in) :: x(2) !! The nearest west and east points for "point" double precision, intent(in) :: y(2) !! Values defined at x. !! y(1) at x(1) !! y(2) at x(2) double precision, intent(in) :: point !! The target point for the interpolation double precision, intent(out) :: val !! Interpolated value ! internal variables double precision :: fd, dt double precision :: tmin double precision :: tmax double precision :: xmin double precision :: xmax tmin=x(1) tmax=x(2) xmin=y(1) xmax=y(2) dt=point-tmin fd=(xmax-xmin)/(tmax-tmin) val=xmin+dt*fd end subroutine interpolation_1d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine auto_interpolation_2d( x, y, r, q, u, v, undef, stdopt ) !! Automatic interpolation for 2d data (continuous running of interpolation_2d) implicit none double precision, intent(in) :: x(:) !! reference grid 1 double precision, intent(in) :: y(:) !! reference grid 2 double precision, intent(in) :: r(:) !! target grid 1 double precision, intent(in) :: q(:) !! target grid 2 double precision, intent(in) :: u(size(x),size(y)) !! reference data double precision, intent(inout) :: v(size(r),size(q)) !! interpolated data double precision, intent(in), optional :: undef !! undefined value logical, intent(in), optional :: stdopt !! Display debug messages. !! (default: .false. == No display) integer :: ir(size(r)), iq(size(q)) integer :: i, j, nx, ny, nr, nq double precision :: defun logical :: stderr nx=size(x) ny=size(y) nr=size(r) nq=size(q) if(present(undef))then defun=undef else defun=-999.0d0 end if if(present(stdopt))then stderr=stdopt else stderr=.false. end if call auto_interpo_search_2d( x, y, r, q, ir, iq, undeff=0, stdopt=stderr ) do j=1, nq do i=1, nr if(ir(i)/=0.and.iq(j)/=0)then if(u(ir(i),iq(j))/=defun)then if(ir(i)<nx.and.iq(j)<ny)then if(u(ir(i),iq(j)+1)/=defun.and. & & u(ir(i)+1,iq(j))/=defun.and. & & u(ir(i)+1,iq(j)+1)/=defun)then call interpolation_2d( x(ir(i):ir(i)+1), & & y(iq(j):iq(j)+1), & & u(ir(i):ir(i)+1,iq(j):iq(j)+1), & & (/r(i), q(j)/), v(i,j) ) else v(i,j)=defun end if else if(x(nx)==r(i).and.y(ny)==q(j))then v(i,j)=u(nx,ny) else if(x(nx)==r(i).and.iq(j)<ny)then if(u(nx,iq(j)+1)/=defun)then call interpolation_1d( y(iq(j):iq(j)+1), & & u(nx,iq(j):iq(j)+1), & & q(j), v(i,j) ) else v(i,j)=defun end if else if(y(ny)==q(j).and.ir(i)<nx)then if(u(ir(i)+1,ny)/=defun)then call interpolation_1d( x(ir(i):ir(i)+1), & & u(ir(i):ir(i)+1,ny), & & r(i), v(i,j) ) else v(i,j)=defun end if else v(i,j)=defun end if else v(i,j)=defun end if else v(i,j)=defun end if end do end do end subroutine auto_interpolation_2d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine auto_interpo_search_1d( x, point, i, undeff, stdopt ) !! continuous running of interpo_search_1d implicit none double precision, intent(in) :: x(:) !! gradual increasing array double precision, intent(in) :: point(:) !! searching points integer, intent(inout) :: i(size(point)) !! floor for each "point" integer, intent(in), optional :: undeff !! In case of (x(1)>pointx), the value returned to i !! (default = 0) logical, intent(in), optional :: stdopt !! Display debug messages. !! (default: .false. == No display) integer :: nx, ni, j, icount, jcount integer :: just logical :: stderr nx=size(x) ni=size(point) if(present(undeff))then just=undeff else just=0 end if if(present(stdopt))then stderr=stdopt else stderr=.false. end if jcount=1 do j=1,ni if(x(1)>point(j))then if(stderr.eqv..false.)then write(*,*) "****** WARNING ******" write(*,*) "searching point was not found :", x(1), point(j) write(*,*) "Abort. Exit.!!!" end if i(j)=just else jcount=j exit end if end do icount=1 do j=jcount,ni if(x(icount)<=point(j))then do while(x(icount)<=point(j)) i(j)=icount icount=icount+1 if(icount>nx)then i(j:ni)=nx exit end if end do icount=icount-1 else icount=icount+1 end if end do end subroutine auto_interpo_search_1d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine auto_interpo_search_2d( x, y, pointx, pointy, i, j, undeff, stdopt ) !! continuous running of auto_interpo_search_1d implicit none double precision, intent(in) :: x(:) !! gradual increasing array 1 double precision, intent(in) :: y(:) !! gradual increasing array 2 double precision, intent(in) :: pointx(:) !! searching points for x double precision, intent(in) :: pointy(:) !! searching points for y integer, intent(inout) :: i(size(pointx)) !! floor for pointx integer, intent(inout) :: j(size(pointy)) !! floor for pointy integer, intent(in), optional :: undeff !! In case of (x(1)>pointx or y(1)>pointy), the value returned to i and j !! (default = 0) logical, intent(in), optional :: stdopt !! 探索範囲が見つからない旨の標準出力を表示させないようにする. integer :: just logical :: stderr if(present(stdopt))then stderr=stdopt else stderr=.false. end if if(present(undeff))then just=undeff call auto_interpo_search_1d( x, pointx, i, just, stdopt=stderr ) call auto_interpo_search_1d( y, pointy, j, just, stdopt=stderr ) else call auto_interpo_search_1d( x, pointx, i, stdopt=stderr ) call auto_interpo_search_1d( y, pointy, j, stdopt=stderr ) end if end subroutine auto_interpo_search_2d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine max_val_1d(var, mamv, undef) !! Get the max value (from STPK) implicit none double precision, intent(in) :: var(:) !! Searched array double precision, intent(inout) :: mamv !! Max value in var double precision, intent(in), optional :: undef !! undefined value integer :: nx integer :: i logical :: undeflag nx=size(var) undeflag=.true. if(present(undef))then do i=1,nx if(var(i)/=undef)then if(undeflag.eqv..true.)then undeflag=.false. mamv=dabs(var(i)) else if(dabs(var(i))>mamv)then mamv=dabs(var(i)) end if end if end if end do if(undeflag.eqv..true.)then mamv=undef end if else mamv=dabs(var(1)) do i=2,nx if(dabs(var(i))>mamv)then mamv=dabs(var(i)) end if end do end if end subroutine max_val_1d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine stand_devi( x, true_val, anor, undef ) !! Calculate RMSE of x for the "true_val" (from STPK) <br> !! Definition: RMSE \(= \sqrt{\sum^{N}_{i=1}{(1/N)(x(i)-x_t)^2}}, \) <br> !! \(x_t=\mathrm{true\_val} \) implicit none double precision, intent(in) :: x(:) !! sampling data double precision, intent(in) :: true_val !! reference data double precision, intent(out) :: anor !! RMSE double precision, intent(in), optional :: undef !! missing value integer :: i integer :: nx ! data number integer :: nt double precision :: anorval nx=size(x) anorval=0.0d0 if(present(undef))then nt=0 do i=1,nx if(x(i)/=undef)then anorval=anorval+(x(i)-true_val)**2 nt=nt+1 end if end do if(anorval/=undef.and.nt/=0)then anorval=dsqrt(anorval/dble(nt)) end if else do i=1,nx anorval=anorval+(x(i)-true_val)**2 end do anorval=dsqrt(anorval/dble(nx)) end if anor=anorval end subroutine stand_devi !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine ll2rt( lon0, lat0, lon1, lat1, r, theta ) !! calculate radial and azimuthal location at (lon1,lat1) on the !! polar coordinate with the center of (lon0,lat0) implicit none double precision, intent(in) :: lon0 !! the center longitude (rad) double precision, intent(in) :: lat0 !! the center latitude (rad) double precision, intent(in) :: lon1 !! target longitude (rad) double precision, intent(in) :: lat1 !! target latitude (rad) double precision, intent(inout) :: r !! radial distance (m) double precision, intent(inout) :: theta !! azimuthal angle (rad) double precision :: tmpcos, tmpsin, tmptan r=ll2radi( lon0, lat0, lon1, lat1 ) if(r>0.0d0)then tmpcos=dcos(lat1)*dsin(lon1-lon0) tmpsin=dsin(lat1)*dcos(lat0)-dcos(lat1)*dsin(lat0)*dcos(lon1-lon0) if(tmpcos==0.0d0.and.tmpsin==0.0d0)then theta=0.0d0 else if(tmpcos==0.0d0.and.tmpsin>0.0d0)then theta=0.5d0*pi_dp else if(tmpcos==0.0d0.and.tmpsin<0.0d0)then theta=1.5d0*pi_dp else if(tmpcos>0.0d0.and.tmpsin==0.0d0)then theta=0.0d0 else if(tmpcos<0.0d0.and.tmpsin==0.0d0)then theta=pi_dp else if(tmpcos>0.0d0.and.tmpsin>0.0d0)then tmptan=tmpsin/tmpcos theta=datan(tmptan) else if(tmpcos<0.0d0.and.tmpsin>0.0d0)then tmptan=tmpsin/dabs(tmpcos) theta=pi_dp-datan(tmptan) else if(tmpcos>0.0d0.and.tmpsin<0.0d0)then tmptan=dabs(tmpsin)/tmpcos theta=2.0d0*pi_dp-datan(tmptan) else if(tmpcos<0.0d0.and.tmpsin<0.0d0)then tmptan=tmpsin/tmpcos theta=pi_dp+datan(tmptan) end if end if else theta=0.0d0 end if end subroutine ll2rt !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine rt2ll( r, theta, lon0, lat0, lon, lat ) !! calculate (lon,lat) from radial and azimuthal grid (r,theta) !! on the polar coordinate with the origin of (lon0,lat0) implicit none double precision, intent(in) :: r !! radial distance from (lon0,lat0) (m) double precision, intent(in) :: theta !! azimuthal angle from (lon0,lat0) (rad) double precision, intent(in) :: lon0 !! longitude of the center on the polar coordinate (rad) double precision, intent(in) :: lat0 !! latitude of the center on the polar coordinate (rad) double precision, intent(inout) :: lon !! target longitude (rad) double precision, intent(inout) :: lat !! target latitude (rad) double precision :: thetad, lond, latd, tmplon, tmplat, rratio thetad=180.0d0*theta/pi_dp lond=180.0d0*lon0/pi_dp latd=180.0d0*lat0/pi_dp rratio=r/radius_dp do while(thetad>360.0d0) thetad=thetad-360.0d0 end do if(thetad==-90.0d0.or.thetad==270.0d0)then lon=lon0 lat=lat0-rratio else if(thetad==90.0d0)then lon=lon0 lat=lat0+rratio else if((-90.0d0<thetad.and.90.0d0>thetad).or. & & (270.0d0<thetad.and.360.0d0>=thetad))then tmplat=dcos(lat0)*dsin(rratio)*dsin(theta)+dsin(lat0)*dcos(rratio) lat=dasin(tmplat) tmplon=dsin(rratio)*dcos(theta)/dcos(dasin(tmplat)) lon=lon0+dasin(tmplon) else if((90.0d0<thetad.and.270.0d0>thetad).or. & & (-180.0d0<=thetad.and.-90.0d0>thetad))then tmplat=dcos(lat0)*dsin(rratio)*dsin(theta)+dsin(lat0)*dcos(rratio) lat=dasin(tmplat) tmplon=-dsin(rratio)*dcos(theta)/dcos(dasin(tmplat)) lon=lon0-dasin(tmplon) else write(*,*) "### ERROR : (rt2ll:Map_Function)" write(*,*) "argument 'theta' is not valid : ", theta write(*,*) "STOP." stop end if end subroutine rt2ll !-------------------------------------------------------------- !-------------------------------------------------------------- real function ll2radi( lon1, lat1, lon2, lat2, forcef ) !! calculate arc distance between two points on the sphere implicit none double precision, intent(in) :: lon1 !! longitude1 (rad) double precision, intent(in) :: lat1 !! latitude1 (rad) double precision, intent(in) :: lon2 !! longitude2 (rad) double precision, intent(in) :: lat2 !! latitude2 (rad) logical, intent(in), optional :: forcef !! truncating flag for numerical error, !! default = .false. (no truncating) double precision :: lond1, lond2, latd1, latd2, tmp logical :: fflag lond1=lon1 lond2=lon2 latd1=lat1 latd2=lat2 if(present(forcef))then fflag=forcef else fflag=.false. end if if(lond1==lond2.and.latd1==latd2)then ll2radi=0.0d0 else tmp=dsin(latd1)*dsin(latd2)+dcos(latd1)*dcos(latd2)*dcos(lond2-lond1) if(tmp<-1.0d0.or.tmp>1.0d0)then if(fflag.eqv..true.)then write(*,*) "*** WARGNING (ll2radi) *** : Detect over 1", & & tmp, latd1, latd2, lond1, lond2 write(*,*) "tmp value is forced to 1. " if(tmp<-1.0d0)then tmp=-1.0d0 else tmp=1.0d0 end if else write(*,*) "*** ERROR (ll2radi) *** : Detect error", & & tmp, latd1, latd2, lond1, lond2 stop end if end if ll2radi=dacos(tmp)*radius_dp end if return end function ll2radi !-------------------------------------------------------------- !-------------------------------------------------------------- integer function line_number_counter( fname, funit ) !! count the line in the fname implicit none character(*), intent(in) :: fname !! counting the file name integer, intent(in), optional :: funit !! file unit (default: 11) ! integer, intent(inout) :: res integer :: i, err, unitn character(1) :: dummy if(present(funit))then unitn=funit else unitn=11 end if i=0 open(unit=unitn,file=trim(fname),iostat=err,status='old') do while(err==0) read(unitn,*,iostat=err) dummy i=i+1 end do close(unit=unitn) line_number_counter=i-1 return end function line_number_counter !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine read_file_text( fname, nx, ny, val, skip, forma, funit ) !! read ASCII file implicit none character(*), intent(in) :: fname !! file name in reading integer, intent(in) :: nx !! column number for fname integer, intent(in) :: ny !! line number for fname character(*), intent(out) :: val(nx,ny) !! read data integer, intent(in), optional :: skip !! line number for skipping from the head character(*), intent(in), optional :: forma !! Fortran format in reading integer, intent(in), optional :: funit !! file unit integer :: i, j, unitn character(1) :: dummy if(present(funit))then unitn=funit else unitn=11 end if open(unit=unitn, file=trim(adjustl(fname)), status='old') if(present(skip))then do i=1,skip read(unitn,*) dummy end do end if if(present(forma))then do j=1,ny read(unitn,forma) (val(i,j),i=1,nx) end do else do j=1,ny read(unitn,*) (val(i,j),i=1,nx) end do end if close(unit=unitn) end subroutine !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine read_file_2d( file_name, nx, ny, rec_num, var, offset, funit ) !! read float data from 4-byte unformatted binary implicit none integer, intent(in) :: nx !! data number in x integer, intent(in) :: ny !! data number in y integer, intent(in) :: rec_num !! record number for reading data character(*), intent(in) :: file_name !! file name real, intent(out) :: var(nx,ny) ! output data integer, intent(in), optional :: offset !! offset in reading integer, intent(in), optional :: funit !! file unit integer :: i, j, l, err, unitn ! working variables integer, parameter :: bnum=4 if(present(funit))then unitn=funit else unitn=11 end if err=0 if(present(offset))then open(unit=unitn, file=trim(adjustl(file_name)), access='direct', & & recl=bnum, status='old', iostat=err) if(err/=0)then call stdout( "File Not Found : "//trim(adjustl(file_name)), "read_file_2d", 1 ) end if l=offset do j=1,ny do i=1,nx l=l+1 read(unitn,rec=l,iostat=err) var(i,j) if(err/=0)then call stdout( "Can not read : "//trim(adjustl(file_name)), "read_file_2d", 1 ) end if end do end do close(unit=unitn) else open(unit=unitn, file=trim(adjustl(file_name)), access='direct', & & recl=bnum*nx*ny, status='old', iostat=err) if(err/=0)then call stdout( "File Not Found : "//trim(adjustl(file_name)), "read_file_2d", 1 ) end if read(unitn,rec=rec_num,iostat=err) ((var(i,j),i=1,nx),j=1,ny) if(err/=0)then call stdout( "Can not read : "//trim(adjustl(file_name)), "read_file_2d", 1 ) end if close(unit=unitn) end if end subroutine read_file_2d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine read_file_3d( file_name, nx, ny, nz, rec_num, var, offset, funit ) !! read float data from 4-byte unformatted binary implicit none integer, intent(in) :: nx !! data number in x integer, intent(in) :: ny !! data number in y integer, intent(in) :: nz !! data number in z integer, intent(in) :: rec_num !! record number for reading data character(*), intent(in) :: file_name !! file name real, intent(out) :: var(nx,ny,nz) ! output data integer, intent(in), optional :: offset !! offset in reading integer, intent(in), optional :: funit !! file unit integer :: i, j, k, l, err, unitn ! working variables integer, parameter :: bnum=4 if(present(funit))then unitn=funit else unitn=11 end if err=0 if(present(offset))then open(unit=unitn, file=trim(adjustl(file_name)), access='direct', & & recl=bnum, status='old', iostat=err) if(err/=0)then call stdout( "File Not Found : "//trim(adjustl(file_name)), "read_file_3d", 1 ) end if l=offset do k=1,nz do j=1,ny do i=1,nx l=l+1 read(unitn,rec=l,iostat=err) var(i,j,k) if(err/=0)then call stdout( "Can not read : "//trim(adjustl(file_name)), "read_file_3d", 1 ) end if end do end do end do close(unit=unitn) else open(unit=unitn, file=trim(adjustl(file_name)), access='direct', & & recl=bnum*nx*ny, status='old', iostat=err) if(err/=0)then call stdout( "File Not Found : "//trim(adjustl(file_name)), "read_file_3d", 1 ) end if do k=1,nz read(unitn,rec=rec_num+k-1,iostat=err) ((var(i,j,k),i=1,nx),j=1,ny) if(err/=0)then call stdout( "Can not read : "//trim(adjustl(file_name)), "read_file_3d", 1 ) end if end do close(unit=unitn) end if end subroutine read_file_3d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine write_file_3d( file_name, nx, ny, nz, rec_num, var, mode, funit ) !! write float data from 4-byte unformatted binary implicit none integer, intent(in) :: nx !! data number in x integer, intent(in) :: ny !! data number in y integer, intent(in) :: nz !! data number in z integer, intent(in) :: rec_num !! record number for reading data character(*), intent(in) :: file_name !! file name real, intent(in) :: var(nx,ny,nz) !! output data character(*), optional, intent(in) :: mode !! option for output integer, intent(in), optional :: funit !! file unit integer :: i, j, k, unitn character(10) :: cmode integer, parameter :: bnum=4 cmode='' if(present(funit))then unitn=funit else unitn=11 end if if(present(mode))then cmode=mode else cmode='unknown' end if open(unit=unitn, file=trim(adjustl(file_name)), access='direct', & & recl=bnum*nx*ny, status=trim(cmode)) do k=1,nz write(unitn,rec=rec_num+k-1) ((var(i,j,k),i=1,nx),j=1,ny) end do close(unit=unitn) end subroutine write_file_3d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine write_file_2d( file_name, nx, ny, rec_num, var, mode, funit ) !! write float data from 4-byte unformatted binary implicit none integer, intent(in) :: nx !! data number in x integer, intent(in) :: ny !! data number in y integer, intent(in) :: rec_num !! record number for reading data character(*), intent(in) :: file_name !! file name real, intent(in) :: var(nx,ny) !! output data character(*), optional, intent(in) :: mode !! option for output integer, intent(in), optional :: funit !! file unit integer :: i, j, unitn character(10) :: cmode integer, parameter :: bnum=4 cmode='' if(present(funit))then unitn=funit else unitn=11 end if if(present(mode))then cmode=mode else cmode='unknown' end if open(unit=unitn, file=trim(adjustl(file_name)), access='direct', & & recl=bnum*nx*ny, status=trim(cmode)) write(unitn,rec=rec_num) ((var(i,j),i=1,nx),j=1,ny) close(unit=unitn) end subroutine write_file_2d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine grad_1d( x, u, dudx, undef ) !! Calculate gradient of "u" in one dimension based on the 2nd order central differential approximation:<br> !! \(\frac{\partial u}{\partial x}\approx \frac{u_{i+1}-u_{i-1}}{2dx} \) implicit none double precision, intent(in) :: x(:) !! Axis point double precision, intent(in) :: u(size(x)) !! Target variable double precision, intent(out) :: dudx(size(x)) !! du/dx double precision, intent(in) :: undef !! undefined dudxue integer :: i !! iteration index integer :: nx !! grid number nx=size(x) dudx=undef do i=2,nx-1 if(u(i+1)/=undef.and.u(i-1)/=undef)then dudx(i)=(u(i+1)-u(i-1))/(x(i+1)-x(i-1)) end if end do if(u(1)/=undef.and.u(2)/=undef)then dudx(1)=(u(2)-u(1))/(x(2)-x(1)) end if if(u(nx)/=undef.and.u(nx-1)/=undef)then dudx(nx)=(u(nx)-u(nx-1))/(x(nx)-x(nx-1)) end if end subroutine grad_1d !-------------------------------------------------------------- !-------------------------------------------------------------- subroutine grad_2d( x, y, u, dudx, dudy, undef ) !! Calculate gradient of "u" in two dimensions based on the 2nd order central differential approximation:<br> !! \(\frac{\partial u}{\partial x}\approx \frac{u_{i+1}-u_{i-1}}{2dx} \) !! \(\nabla u\approx \left(\frac{p_{i+1,j}-p_{i-1,j}}{2dx} ,\; \frac{p_{i,j+1}-p_{i,j-1}}{2dy} \right) \) implicit none double precision, intent(in) :: x(:) !! Axis point 1 double precision, intent(in) :: y(:) !! Axis point 2 double precision, intent(in) :: u(size(x),size(y)) ! Target variable double precision, intent(out) :: dudx(size(x),size(y)) ! du/dx double precision, intent(out) :: dudy(size(x),size(y)) ! du/dy double precision, intent(in), optional :: undef integer :: i, j ! iteration index integer :: nx, ny ! grid points for x and y nx=size(x) ny=size(y) do i=1,ny call grad_1d(x, u(:,i), dudx(:,i), undef) end do do i=1,nx call grad_1d(y, u(i,:), dudy(i,:), undef) end do end subroutine grad_2d !-------------------------------------------------------------- !-------------------------------------------------------------- real function c2r_convert( cval ) !! convert char to float implicit none character(*), intent(in) :: cval !! char read(cval,*) c2r_convert return end function !-------------------------------------------------------------- !-------------------------------------------------------------- end module GVTDX_sub