*
This module handles conversions between ECMWF eta coordinates and * internal meter coordinates * * Author: L. Bakels *
! SPDX-FileCopyrightText: FLEXPART 1998-2019, see flexpart_license.txt ! SPDX-License-Identifier: GPL-3.0-or-later !***************************************************************************** ! * ! This module handles conversions between ECMWF eta coordinates and * ! internal meter coordinates * ! * ! Author: L. Bakels * !***************************************************************************** module coord_ecmwf_mod use par_mod use com_mod use windfields_mod contains #ifdef ETA subroutine update_zeta_to_z(itime, ipart) use particle_mod implicit none integer, intent(in) :: & itime, & ! time index ipart ! particle index if (.not. part(ipart)%alive) return if (part(ipart)%etaupdate) return call zeta_to_z(itime,part(ipart)%xlon,part(ipart)%ylat, & part(ipart)%zeta,part(ipart)%z) part(ipart)%etaupdate = .true. part(ipart)%meterupdate = .true. end subroutine update_zeta_to_z subroutine update_z_to_zeta(itime, ipart) use particle_mod implicit none integer, intent(in) :: & itime, & ! time index ipart ! particle index if (.not. part(ipart)%alive) return if (part(ipart)%meterupdate) return call z_to_zeta(itime,part(ipart)%xlon,part(ipart)%ylat, & part(ipart)%z,part(ipart)%zeta) part(ipart)%etaupdate = .true. part(ipart)%meterupdate = .true. end subroutine update_z_to_zeta subroutine z_to_zeta(itime,xt,yt,zold,zteta) !***************************************************************************** ! Converting z from meter coordinates to eta using logarithmic vertical * ! interpolation * !***************************************************************************** ! * ! Variables: * ! itime [s] current temporal position * ! xt,yt,zold,zold spatial positions of trajectory (meters) * ! zteta vertical position in eta coordinates (output) * ! * ! etauvheight defined in windfields: half model heights for ETA coordinates * ! Constants: * ! * !***************************************************************************** use interpol_mod implicit none integer, intent(in) :: & itime ! time index integer :: & i,m,k,n ! loop indices real(kind=dp), intent(in) :: & xt,yt ! particle position real(kind=dp), intent(in) :: & zold ! particle verticle position in eta coordinates real(kind=dp), intent(inout) :: & zteta ! converted output z in meters real :: & frac, & ! fraction between z levels ztemp1,ztemp2, & ! z positions of the two encompassing levels ttemp1(2), & ! storing virtual temperature psint1(2),psint ! pressure of encompassing levels real :: & prx,pr1,pr2 ! pressure of encompassing levels if (.not. log_interpol) then call z_to_zeta_lin(itime,xt,yt,zold,zteta) return endif call find_ngrid(xt,yt) call find_grid_indices(real(xt),real(yt)) call find_grid_distances(real(xt),real(yt)) call find_time_vars(itime) ! Integration method as used in the original verttransform_ecmwf.f90 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! First estimate the level it is at, to reduce computation time n=nz-3 if (ngrid.le.0) then do i=2,nz-1 if ((etauvheight(ix,jy,i,memind(1)).gt.real(zold)) .or. & (etauvheight(ixp,jy,i,memind(1)).gt.real(zold)) .or. & (etauvheight(ix,jyp,i,memind(1)).gt.real(zold)) .or. & (etauvheight(ixp,jyp,i,memind(1)).gt.real(zold))) then n=i-2 exit endif end do else do i=2,nz-1 if ((etauvheightn(ix,jy,i,memind(1),ngrid).gt.real(zold)) .or. & (etauvheightn(ixp,jy,i,memind(1),ngrid).gt.real(zold)) .or. & (etauvheightn(ix,jyp,i,memind(1),ngrid).gt.real(zold)) .or. & (etauvheightn(ixp,jyp,i,memind(1),ngrid).gt.real(zold))) then n=i-2 exit endif end do endif n=max(n,2) ztemp1 = 0. do i=n,nz-1 k=i if (ngrid.le.0) then do m=1,2 call hor_interpol(etauvheight,ttemp1(m),i,memind(m),nzmax) end do else do m=1,2 call hor_interpol_nest(etauvheightn,ttemp1(m),i,memind(m),nzmax) end do endif call temporal_interpolation(ttemp1(1),ttemp1(2),ztemp2) if (ztemp2.gt.real(zold)) then !frac = (real(zold)-ztemp1)/(ztemp2-ztemp1) exit else if (i.eq.nz-1) then frac = 1. exit endif ztemp1=ztemp2 end do if (k.lt.nz-1) then if (ngrid.le.0) then do m=1,2 call hor_interpol(ps,psint1(m),1,memind(m),1) end do else do m=1,2 call hor_interpol_nest(psn,psint1(m),1,memind(m),1) end do endif call temporal_interpolation(psint1(1),psint1(2),psint) pr1=akz(k-1) + bkz(k-1)*psint pr2=akz(k) + bkz(k)*psint prx=pr1/exp(log(pr2/pr1)/(ztemp2-ztemp1)*ztemp1) * & exp(log(pr2/pr1)/(ztemp2-ztemp1)*real(zold)) frac=(prx-pr1)/(pr2 - pr1) endif zteta=real(uvheight(k-1)*(1.-frac)+uvheight(k)*frac,kind=dp) end subroutine z_to_zeta subroutine zeta_to_z(itime,xt,yt,zteta,ztout) !***************************************************************************** ! Converting z from eta coordinates to meters using logarithmic * ! vertical interpolation * !***************************************************************************** ! * ! Variables: * ! itime [s] current temporal position * ! xt,yt,zteta spatial position of trajectory * ! ztout vertical postion in meter (output) * ! * ! * !***************************************************************************** use interpol_mod implicit none integer, intent(in) :: & itime ! time index integer :: & i,k,m,ii ! loop indices real(kind=dp), intent(in) :: & xt,yt ! particle position real(kind=dp), intent(in) :: & zteta ! particle verticle position in eta coordinates real(kind=dp), intent(inout) :: & ztout ! converted output z in meters real(kind=dp) :: & frac, & ! fraction between z levels prx,pr1,pr2 ! pressure of encompassing levels real :: & ztemp1(2), & ! z positions of the two encompassing levels ttemp1(2), & ! storing virtual temperature psint1(2),psint ! pressure of encompassing levels if (.not. log_interpol) then call zeta_to_z_lin(itime,xt,yt,zteta,ztout) return endif ! Convert eta z coordinate to meters !*********************************** call find_ngrid(xt,yt) call find_grid_indices(real(xt),real(yt)) call find_grid_distances(real(xt),real(yt)) call find_time_vars(itime) k=nz-1 frac=1. do i=2,nz-1 k=i if (zteta.ge.real(uvheight(k),kind=dp)) then frac=(zteta-real(uvheight(k-1),kind=dp))/(real(uvheight(k)-uvheight(k-1),kind=dp)) exit endif end do if (ngrid.le.0) then do m=1,2 call hor_interpol(ps,psint1(m),1,memind(m),1) end do else do m=1,2 call hor_interpol_nest(psn,psint1(m),1,memind(m),1) end do endif call temporal_interpolation(psint1(1),psint1(2),psint) pr1=real(akz(k-1) + bkz(k-1)*psint,kind=dp) pr2=real(akz(k) + bkz(k)*psint,kind=dp) prx=pr1*(1.-frac) + pr2*frac if (ngrid.le.0) then do ii=1,2 do m=1,2 call hor_interpol(etauvheight,ttemp1(m),k+ii-2,memind(m),nzmax) end do call temporal_interpolation(ttemp1(1),ttemp1(2),ztemp1(ii)) end do else do ii=1,2 do m=1,2 call hor_interpol_nest(etauvheightn, & ttemp1(m),k+ii-2,memind(m),nzmax) end do call temporal_interpolation(ttemp1(1),ttemp1(2),ztemp1(ii)) end do endif if ((pr2.eq.0).or.(pr1.eq.0)) then ztout = real(ztemp1(1),kind=dp)*(1.-frac)+real(ztemp1(2),kind=dp)*frac return endif ztout = ztemp1(1) + (ztemp1(2)-ztemp1(1))/log(pr2/pr1)*log(prx/pr1) end subroutine zeta_to_z subroutine w_to_weta(itime,dt,xt,yt,z_old,zeta_old,w_in,weta_out) !***************************************************************************** ! Converting z from meter coordinates to eta using logarithmic vertical * ! interpolation * !***************************************************************************** ! * ! Variables: * ! itime [s] current temporal position * ! xt,yt,zold,zold spatial positions of trajectory (meters) * ! zteta vertical position in eta coordinates (output) * ! * ! etauvheight defined in windfields: half model heights for ETA coordinates * ! Constants: * ! * !***************************************************************************** use interpol_mod implicit none integer, intent(in) :: & itime ! time index real, intent(in) :: & dt ! time step real(kind=dp), intent(in) :: & xt,yt,z_old,zeta_old ! particle position real, intent(in) :: & w_in ! w in meters/s real, intent(inout) :: & weta_out ! converted output w in meters to eta real(kind=dp) :: & znew call z_to_zeta(itime,xt,yt,z_old+real(w_in*dt,kind=dp),znew) weta_out=real(znew-zeta_old)/dt end subroutine w_to_weta subroutine z_to_zeta_lin(itime,xt,yt,zold,zteta) !***************************************************************************** ! Converting z from meter coordinates to eta using linear interpolation * ! * !***************************************************************************** ! * ! Variables: * ! itime [s] current temporal position * ! xt,yt,zold,zold spatial positions of trajectory (meters) * ! zteta vertical position in eta coordinates (output) * ! * ! etauvheight defined in windfields: half model heights for ETA coordinates * ! Constants: * ! * !***************************************************************************** use interpol_mod implicit none integer, intent(in) :: & itime ! time index integer :: & i,m,k,n ! loop indices real(kind=dp), intent(in) :: & xt,yt ! particle position real(kind=dp), intent(in) :: & zold ! particle verticle position in eta coordinates real(kind=dp), intent(inout) :: & zteta ! converted output z in meters real :: & frac, & ! fraction between z levels ztemp1,ztemp2, & ! z positions of the two encompassing levels ttemp1(2) ! storing virtual temperature call find_ngrid(xt,yt) call find_grid_indices(real(xt),real(yt)) call find_grid_distances(real(xt),real(yt)) call find_time_vars(itime) ! Integration method as used in the original verttransform_ecmwf.f90 !+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ ! First estimate the level it is at, to reduce computation time n=nz-3 if (ngrid.le.0) then do i=2,nz-1 if ((etauvheight(ix,jy,i,memind(1)).gt.real(zold)) .or. & (etauvheight(ixp,jy,i,memind(1)).gt.real(zold)) .or. & (etauvheight(ix,jyp,i,memind(1)).gt.real(zold)) .or. & (etauvheight(ixp,jyp,i,memind(1)).gt.real(zold))) then n=i-2 exit endif end do else do i=2,nz-1 if ((etauvheightn(ix,jy,i,memind(1),ngrid).gt.real(zold)) .or. & (etauvheightn(ixp,jy,i,memind(1),ngrid).gt.real(zold)) .or. & (etauvheightn(ix,jyp,i,memind(1),ngrid).gt.real(zold)) .or. & (etauvheightn(ixp,jyp,i,memind(1),ngrid).gt.real(zold))) then n=i-2 exit endif end do endif n=max(n,2) ztemp1 = 0. frac = 0. k=n do i=n,nz-1 k=i if (ngrid.le.0) then do m=1,2 call hor_interpol(etauvheight,ttemp1(m),i,memind(m),nzmax) end do else do m=1,2 call hor_interpol_nest(etauvheightn,ttemp1(m),i,memind(m),nzmax) end do endif call temporal_interpolation(ttemp1(1),ttemp1(2),ztemp2) if (ztemp2.gt.real(zold)) then frac = (real(zold)-ztemp1)/(ztemp2-ztemp1) exit else if (i.eq.nz-1) then frac = 1. exit endif ztemp1=ztemp2 end do zteta=real(uvheight(k-1)*(1.-frac)+uvheight(k)*frac,kind=dp) end subroutine z_to_zeta_lin subroutine zeta_to_z_lin(itime,xt,yt,zteta,ztout) !***************************************************************************** ! Converting z from eta coordinates to meters using linear interpolation * ! * !***************************************************************************** ! * ! Variables: * ! itime [s] current temporal position * ! xt,yt,zteta spatial position of trajectory * ! ztout vertical postion in meter (output) * ! * ! * !***************************************************************************** use interpol_mod implicit none integer, intent(in) :: & itime ! time index integer :: & i,k,m,ii ! loop indices real(kind=dp), intent(in) :: & xt,yt ! particle position real(kind=dp), intent(in) :: & zteta ! particle verticle position in eta coordinates real(kind=dp), intent(inout) :: & ztout ! converted output z in meters real(kind=dp) :: & frac ! fraction between z levels real :: & ztemp1(2), & ! z positions of the two encompassing levels ttemp1(2) ! storing virtual temperature ! Convert eta z coordinate to meters !*********************************** call find_ngrid(xt,yt) call find_grid_indices(real(xt),real(yt)) call find_grid_distances(real(xt),real(yt)) call find_time_vars(itime) k=nz-1 frac=1. do i=2,nz-1 k=i if (zteta.ge.real(uvheight(k),kind=dp)) then frac=(zteta-real(uvheight(k-1),kind=dp))/(real(uvheight(k)-uvheight(k-1),kind=dp)) exit endif end do if (ngrid.le.0) then do ii=1,2 do m=1,2 call hor_interpol(etauvheight,ttemp1(m),k+ii-2,memind(m),nzmax) end do call temporal_interpolation(ttemp1(1),ttemp1(2),ztemp1(ii)) end do else do ii=1,2 do m=1,2 call hor_interpol_nest(etauvheightn,ttemp1(m),k+ii-2,memind(m),nzmax) end do call temporal_interpolation(ttemp1(1),ttemp1(2),ztemp1(ii)) end do endif ztout = real(ztemp1(1),kind=dp)*(1.-frac)+real(ztemp1(2),kind=dp)*frac end subroutine zeta_to_z_lin #endif end module coord_ecmwf_mod