FV3-JEDI
fv3jedi_vc_vertremap_mod.f90
Go to the documentation of this file.
1 ! (C) Copyright 2020 UCAR
2 !
3 ! This software is licensed under the terms of the Apache Licence Version 2.0
4 ! which can be obtained at http://www.apache.org/licenses/LICENSE-2.0.
5 
7 
8 ! fckit
9 use fckit_configuration_module, only: fckit_configuration
10 
11 ! fms
12 use constants_mod, only: grav
13 use field_manager_mod, only: model_atmos
14 use mpp_domains_mod, only: mpp_update_domains
15 use tracer_manager_mod, only: get_number_tracers, get_tracer_names, get_tracer_index, no_tracer, &
16  set_tracer_profile
17 
18 ! fv3
19 use external_ic_mod, only: remap_scalar, remap_dwinds, source
20 use fv_arrays_mod, only: fv_atmos_type, deallocate_fv_atmos_type, r_grid
21 use fv_grid_utils_mod, only: mid_pt_sphere, get_unit_vect2, get_latlon_vector, inner_prod
22 use test_cases_mod, only: checker_tracers
23 
24 ! fv3jedi
25 use fv_prec_mod, only: kind_fv3
26 use fv_init_mod, only: fv_init
32 
33 implicit none
34 private
35 public :: fv3jedi_vc_vertremap
36 
38  type(fv_atmos_type), allocatable :: atm(:)
39  logical, allocatable :: grids_on_this_pe(:)
40  logical :: from_cold_start, checker_tr
41  integer :: nt_checker
42  contains
43  procedure :: create
44  procedure :: delete
45  procedure :: changevar
46 end type fv3jedi_vc_vertremap
47 
48 ! --------------------------------------------------------------------------------------------------
49 
50 contains
51 
52 ! --------------------------------------------------------------------------------------------------
53 
54 subroutine create(self, geom, conf)
55 
56 class(fv3jedi_vc_vertremap), intent(inout) :: self
57 type(fv3jedi_geom), intent(in) :: geom
58 type(fckit_configuration), intent(in) :: conf
59 
60 integer :: gtile, p_split = 1, n
61 logical :: checks_passed
62 character(len=:), allocatable :: str
63 
64 ! Create Atm structure
65 call fv_init(self%Atm, 300.0_kind_real, self%grids_on_this_pe, p_split, gtile)
66 
67 ! Flag to use cold starts
68 if( .not. conf%get('input is cold starts', self%from_cold_start) ) self%from_cold_start = .true.
69 
70 ! Check tracers
71 if( .not. conf%get('check tracers', self%checker_tr) ) self%checker_tr = .false.
72 if( .not. conf%get('check tracers nt', self%nt_checker) ) self%nt_checker = 0
73 
74 ! Set global source variable in external_ic
75 if (.not. conf%get("source of inputs", str)) then
76  str = 'FV3GFS GAUSSIAN NETCDF FILE'
77 endif
78 source = trim(str)
79 
80 ! Remapping needs nggps_ic to be true
81 self%Atm(1)%flagstruct%nggps_ic = .true.
82 
83 ! ak/bk
84 self%Atm(1)%ak = real(geom%ak,kind_fv3)
85 self%Atm(1)%bk = real(geom%bk,kind_fv3)
86 self%Atm%ptop = real(geom%ak(1),kind_fv3)
87 
88 ! Sanity checks
89 checks_passed = .true.
90 if (checks_passed) checks_passed = geom%npx == self%Atm(1)%npx
91 if (checks_passed) checks_passed = geom%npy == self%Atm(1)%npy
92 if (checks_passed) checks_passed = geom%npz == self%Atm(1)%npz
93 if (checks_passed) checks_passed = geom%isd == self%Atm(1)%bd%isd
94 if (checks_passed) checks_passed = geom%ied == self%Atm(1)%bd%ied
95 if (checks_passed) checks_passed = geom%jsd == self%Atm(1)%bd%jsd
96 if (checks_passed) checks_passed = geom%jed == self%Atm(1)%bd%jed
97 if (.not.checks_passed) call abor1_ftn("fv3jedi_vc_vertremap_mod.field_fail: Geometry generated"// &
98  " here does not match fv3-jedi geometry.")
99 
100 if (.not.size(self%Atm)==1) call abor1_ftn("fv3jedi_vc_vertremap_mod.field_fail: Atm strucutre"// &
101  " with size > 1 not supported.")
102 
103 end subroutine create
104 
105 ! --------------------------------------------------------------------------------------------------
106 
107 subroutine delete(self)
108 
109 class(fv3jedi_vc_vertremap), intent(inout) :: self
110 
111 integer :: n
112 
113 do n = 1,size(self%Atm)
114  call deallocate_fv_atmos_type(self%Atm(n))
115 enddo
116 deallocate(self%Atm)
117 deallocate(self%grids_on_this_pe)
118 
119 end subroutine delete
120 
121 ! --------------------------------------------------------------------------------------------------
122 
123 subroutine changevar(self, xin, xout)
124 
125 class(fv3jedi_vc_vertremap), target, intent(inout) :: self
126 type(fv3jedi_state), intent(in) :: xin
127 type(fv3jedi_state), intent(inout) :: xout
128 
129 ! Copy versus transform control
130 integer :: f
131 character(len=field_clen), allocatable :: fields_to_do(:)
132 type(fv3jedi_field), pointer :: field_ptr
133 
134 ! Local versions of fv3jedi state
135 real(kind=kind_real), allocatable :: orog_filt(:,:,:)
136 real(kind=kind_real), allocatable :: ps_cold(:,:,:)
137 real(kind=kind_real), allocatable :: zh_cold(:,:,:)
138 real(kind=kind_real), allocatable :: w_cold(:,:,:)
139 real(kind=kind_real), allocatable :: t_cold(:,:,:)
140 real(kind=kind_real), allocatable :: q_tmp(:,:,:)
141 real(kind=kind_real), allocatable :: ud_cold(:,:,:)
142 real(kind=kind_real), allocatable :: vd_cold(:,:,:)
143 
144 logical :: have_remapped
145 type(fv_atmos_type), pointer :: Atm
146 integer:: i, j, k, nt, ntracers, ntprog, itoa, levp, isc, iec, jsc, jec, npz, nts
147 integer:: liq_wat, ice_wat, rainwat, snowwat, graupel, ntclamt
148 character(len=64) :: tracer_name
149 real(kind=kind_fv3), allocatable :: ak(:), bk(:)
150 real(kind=kind_fv3), allocatable :: q_cold(:,:,:,:)
151 real(kind=kind_fv3) :: wt, qt, m_fac
152 
153 ! Field names
154 character(len=field_clen) :: ps_fname
155 character(len=field_clen) :: zh_fname
156 character(len=field_clen) :: w_fname
157 character(len=field_clen) :: t_fname
158 character(len=field_clen) :: ud_fname
159 character(len=field_clen) :: vd_fname
160 
161 
162 ! Identity part of the change of variables
163 ! ----------------------------------------
164 call copy_subset(xin%fields, xout%fields, fields_to_do)
165 
166 
167 ! If variable change is the identity early exit
168 ! ---------------------------------------------
169 if (.not.allocated(fields_to_do)) return
170 
171 
172 ! Field names
173 ! -----------
174 ps_fname = 'ps'
175 zh_fname = 'zh'
176 w_fname = 'w'
177 t_fname = 't'
178 ud_fname = 'ud'
179 vd_fname = 'vd'
180 if (self%from_cold_start) then
181  ps_fname = trim(ps_fname)//'_cold'
182  zh_fname = trim(zh_fname)//'_cold'
183  w_fname = trim(w_fname)//'_cold'
184  t_fname = trim(t_fname)//'_cold'
185  ud_fname = trim(ud_fname)//'_cold'
186  vd_fname = trim(vd_fname)//'_cold'
187 endif
188 
189 
190 ! Remap to new Lagrangian vertical coordinate
191 ! -------------------------------------------
192 have_remapped = .false.
193 if ( xin%has_field(ps_fname) .and. xin%has_field(zh_fname) .and. &
194  xin%has_field(w_fname) .and. &
195  xin%has_field('orog_filt') .and. &
196  xin%has_field(ud_fname) .and. xin%has_field(vd_fname) ) then
197 
198  ! Shortcuts
199  atm => self%Atm(1)
200  isc = atm%bd%is
201  iec = atm%bd%ie
202  jsc = atm%bd%js
203  jec = atm%bd%je
204  npz = atm%npz
205 
206  ! Orography
207  call xin%get_field('orog_filt', orog_filt)
208  atm%phis(isc:iec,jsc:jec) = real(orog_filt(isc:iec,jsc:jec,1),kind_fv3)*grav ! Convert to phis
209 
210  ! Dynamics fields
211  call xin%get_field(ps_fname, ps_cold)
212  call xin%get_field(zh_fname, zh_cold)
213  call xin%get_field( w_fname, w_cold)
214 
215  ! akbk from cold starts have different levels (for now extra levels are zero)
216  levp = size(w_cold,3)
217  itoa = levp - npz + 1
218 
219  allocate(ak(levp+1))
220  allocate(bk(levp+1))
221  ak = 0.0_kind_fv3
222  bk = 0.0_kind_fv3
223  ak(itoa:levp+1) = atm%ak(1:npz+1)
224  bk(itoa:levp+1) = atm%bk(1:npz+1)
225  ak(1) = max(1.e-9_kind_fv3, ak(1))
226 
227  ! Tracers
228  ! -------
229  ! Number of tracers in Atm
230  call get_number_tracers(model_atmos, num_tracers=ntracers, num_prog=ntprog)
231  call get_number_tracers(model_atmos, num_tracers=ntracers, num_prog=ntprog)
232 
233  ! initialize all tracers to default values prior to being input
234  do nt = 1, ntprog
235  call get_tracer_names(model_atmos, nt, tracer_name)
236  ! set all tracers to an initial profile value
237  call set_tracer_profile (model_atmos, nt, atm%q(:,:,:,nt) )
238  enddo
239  do nt = ntprog+1, ntracers
240  call get_tracer_names(model_atmos, nt, tracer_name)
241  ! set all tracers to an initial profile value
242  call set_tracer_profile (model_atmos, nt, atm%qdiag(:,:,:,nt) )
243  enddo
244 
245  ! Copy from fv3-jedi to temporary cold q structure
246  allocate (q_cold(isc:iec, jsc:jec, levp, ntracers))
247  q_cold = 0.0_kind_fv3
248  do nt = 1, ntracers
249  call get_tracer_names(model_atmos, nt, tracer_name)
250  if (self%from_cold_start) tracer_name = trim(tracer_name)//"_cold"
251  if (xin%has_field(trim(tracer_name))) then
252  call xin%get_field(trim(tracer_name), q_tmp)
253  q_cold(:,:,:,nt) = real(q_tmp, kind_fv3)
254  endif
255  enddo
256 
257  ! Call remapping non-wind variables
258  ! ---------------------------------
259  if (xin%has_field(t_fname)) then
260  call xin%get_field( t_fname, t_cold)
261  call remap_scalar(atm, levp, npz, ntracers, ak, bk, real(ps_cold(:,:,1),kind_fv3), q_cold, &
262  real(zh_cold,kind_fv3), real(w_cold,kind_fv3), real(t_cold,kind_fv3))
263  else
264  call remap_scalar(atm, levp, npz, ntracers, ak, bk, real(ps_cold(:,:,1),kind_fv3), q_cold, &
265  real(zh_cold,kind_fv3), real(w_cold,kind_fv3))
266  endif
267 
268  ! Call remapping wind variables
269  ! -----------------------------
270  call xin%get_field(ud_fname, ud_cold)
271  call xin%get_field(vd_fname, vd_cold)
272 
273  call remap_dwinds(levp, npz, ak, bk, real(ps_cold(:,:,1),kind_fv3), real(ud_cold,kind_fv3), &
274  real(vd_cold,kind_fv3), Atm)
275 
276  ! Tracer weighting
277  ! ----------------
278  liq_wat = get_tracer_index(model_atmos, 'liq_wat')
279  ice_wat = get_tracer_index(model_atmos, 'ice_wat')
280  rainwat = get_tracer_index(model_atmos, 'rainwat')
281  snowwat = get_tracer_index(model_atmos, 'snowwat')
282  graupel = get_tracer_index(model_atmos, 'graupel')
283  ntclamt = get_tracer_index(model_atmos, 'cld_amt')
284 
285  if (self%from_cold_start) then
286  do k = 1,npz
287  do j = jsc,jec
288  do i = isc,iec
289  wt = atm%delp(i,j,k)
290  if ( atm%flagstruct%nwat == 6 ) then
291  qt = wt*(1.0_kind_fv3 + atm%q(i,j,k,liq_wat) + atm%q(i,j,k,ice_wat) + &
292  atm%q(i,j,k,rainwat) + atm%q(i,j,k,snowwat) + &
293  atm%q(i,j,k,graupel))
294  else
295  qt = wt*(1.0_kind_fv3 + sum(atm%q(i,j,k,2:atm%flagstruct%nwat)))
296  endif
297  atm%delp(i,j,k) = qt
298  if (ntclamt > 0) atm%q(i,j,k,ntclamt) = 0.0
299  enddo
300  enddo
301  enddo
302  else
303  ! TODO Question is do we need this if just remapping after adding the increment, say?
304  do k = 1,npz
305  do j = jsc,jec
306  do i = isc,iec
307  wt = atm%delp(i,j,k)
308  if ( atm%flagstruct%nwat == 6 ) then
309  qt = wt*(1.0_kind_fv3 + atm%q(i,j,k,liq_wat) + atm%q(i,j,k,ice_wat) + &
310  atm%q(i,j,k,rainwat) + atm%q(i,j,k,snowwat) + &
311  atm%q(i,j,k,graupel))
312  else
313  qt = wt*(1.0_kind_fv3 + sum(atm%q(i,j,k,2:atm%flagstruct%nwat)))
314  endif
315  m_fac = wt / qt
316  do nt=1,ntracers
317  atm%q(i,j,k,nt) = m_fac * atm%q(i,j,k,nt)
318  enddo
319  atm%delp(i,j,k) = qt
320  if (ntclamt > 0) atm%q(i,j,k,ntclamt) = 0.0
321  enddo
322  enddo
323  enddo
324  endif
325 
326  if (self%checker_tr) then
327  nts = ntracers - self%nt_checker+1
328  call checker_tracers(isc, iec, jsc, jec, atm%bd%isd, atm%bd%ied, atm%bd%jsd, atm%bd%jed, &
329  self%nt_checker, npz, atm%q(:,:,:,nts:ntracers), &
330  atm%gridstruct%agrid_64(isc:iec,jsc:jec,1), &
331  atm%gridstruct%agrid_64(isc:iec,jsc:jec,2), &
332  real(9.0_kind_real,kind_fv3), real(9.0_kind_real,kind_fv3))
333  endif
334 
335  have_remapped = .true.
336 
337 endif
338 
339 
340 ! Loop over the fields not found in the input state and work through cases
341 ! ------------------------------------------------------------------------
342 do f = 1, size(fields_to_do)
343 
344  ! Remapping needs to have happened in order to copy anything
345  if (.not. have_remapped) call field_fail(fields_to_do(f))
346 
347  call xout%get_field(trim(fields_to_do(f)), field_ptr)
348 
349  select case (trim(fields_to_do(f)))
350 
351  case ("ud")
352 
353  field_ptr%array(isc:iec,jsc:jec+1,:) = atm%u(isc:iec,jsc:jec+1,:)
354 
355  case ("vd")
356 
357  field_ptr%array(isc:iec+1,jsc:jec,:) = atm%v(isc:iec+1,jsc:jec,:)
358 
359  case ("t")
360 
361  field_ptr%array(isc:iec,jsc:jec,:) = atm%pt(isc:iec,jsc:jec,:)
362 
363  case ("delp")
364 
365  field_ptr%array(isc:iec,jsc:jec,:) = atm%delp(isc:iec,jsc:jec,:)
366 
367  case ("ps")
368 
369  field_ptr%array(isc:iec,jsc:jec,1) = atm%ps(isc:iec,jsc:jec)
370 
371  case ("delz")
372 
373  field_ptr%array(isc:iec,jsc:jec,:) = atm%delz(isc:iec,jsc:jec,:)
374 
375  case ("w")
376 
377  field_ptr%array(isc:iec,jsc:jec,:) = atm%w(isc:iec,jsc:jec,:)
378 
379  case ("phis")
380 
381  field_ptr%array(isc:iec,jsc:jec,1) = atm%phis(isc:iec,jsc:jec)
382 
383  case ('sphum','liq_wat','ice_wat','o3mr','graupel','snowwat','rainwat')
384 
385  nt = get_tracer_index(model_atmos, trim(fields_to_do(f)))
386  if (nt == no_tracer) call field_fail(fields_to_do(f))
387  field_ptr%array(isc:iec,jsc:jec,:) = atm%q(isc:iec,jsc:jec,:,nt)
388 
389  case ('sgs_tke','cld_amt')
390 
391  field_ptr%array = 0.0_kind_real
392 
393  case default
394 
395  call abor1_ftn("fv3jedi_vc_coldstartwinds_mod.changevar unknown field: "//trim(fields_to_do(f))&
396  //". Not in input field and no transform case specified.")
397 
398  end select
399 
400 enddo
401 
402 
403 ! Copy calendar infomation
404 ! ------------------------
405 xout%calendar_type = xin%calendar_type
406 xout%date_init = xin%date_init
407 
408 end subroutine changevar
409 
410 ! --------------------------------------------------------------------------------------------------
411 
412 end module fv3jedi_vc_vertremap_mod
fv3jedi_state_mod::fv3jedi_state
Fortran derived type to hold FV3JEDI state.
Definition: fv3jedi_state_mod.F90:30
fv3jedi_field_mod
Definition: fv3jedi_field_mod.f90:6
fv3jedi_fieldfail_mod::field_fail
subroutine, public field_fail(field)
Definition: fv3jedi_fieldfail_mod.f90:14
atm
Definition: atm.F90:1
fv_prec_mod
Definition: fv_prec_r4_mod.f90:6
fv_prec_mod::kind_fv3
integer, parameter, public kind_fv3
Definition: fv_prec_r4_mod.f90:11
fv3jedi_vc_vertremap_mod
Definition: fv3jedi_vc_vertremap_mod.f90:6
fv3jedi_state_mod
Definition: fv3jedi_state_mod.F90:6
fv3jedi_field_mod::copy_subset
subroutine, public copy_subset(field_in, field_ou, not_copied)
Definition: fv3jedi_field_mod.f90:236
fv_init_mod
Definition: fv_init_control_mod.f90:6
fv3jedi_geom_mod
Fortran module handling geometry for the FV3 model.
Definition: fv3jedi_geom_mod.f90:8
fv3jedi_geom_mod::fv3jedi_geom
Fortran derived type to hold geometry data for the FV3JEDI model.
Definition: fv3jedi_geom_mod.f90:46
fv3jedi_fieldfail_mod
Definition: fv3jedi_fieldfail_mod.f90:1
fv3jedi_vc_vertremap_mod::changevar
subroutine changevar(self, xin, xout)
Definition: fv3jedi_vc_vertremap_mod.f90:124
fv3jedi_vc_vertremap_mod::create
subroutine create(self, geom, conf)
Definition: fv3jedi_vc_vertremap_mod.f90:55
fv3jedi_kinds_mod::kind_real
integer, parameter, public kind_real
Definition: fv3jedi_kinds_mod.f90:14
fv3jedi_vc_vertremap_mod::fv3jedi_vc_vertremap
Definition: fv3jedi_vc_vertremap_mod.f90:37
fv3jedi_field_mod::fv3jedi_field
Definition: fv3jedi_field_mod.f90:36
fv3jedi_vc_vertremap_mod::delete
subroutine delete(self)
Definition: fv3jedi_vc_vertremap_mod.f90:108
fv3jedi_kinds_mod
Definition: fv3jedi_kinds_mod.f90:6
fv_init_mod::fv_init
subroutine, public fv_init(Atm, dt_atmos_in, grids_on_this_pe, p_split, gtile)
Definition: fv_init_control_mod.f90:28
fv3jedi_field_mod::field_clen
integer, parameter, public field_clen
Definition: fv3jedi_field_mod.f90:31