FV3 Bundle
fv_climate_nudge_nlm.F90
Go to the documentation of this file.
2 
4 use fms_mod, only: open_namelist_file, check_nml_error, &
5  close_file, stdlog, mpp_pe, mpp_root_pe, &
6  write_version_number, string, error_mesg, &
7  fatal, warning, note, file_exist
8 use mpp_mod, only: input_nml_file
17  operator(<), operator(+)
20 use mpp_mod, only: mpp_min, mpp_max
21 use constants_mod, only: rdgas, rvgas, pi, kappa, cp_air
22 use fv_mapz_nlm_mod, only: mappm
23 implicit none
24 private
25 
28 
30  integer :: is, ie, js, je, npz
31  integer :: time_level
32  real(FVPRC), pointer, dimension(:,:) :: ps
33  real(FVPRC), pointer, dimension(:,:,:) :: u, v, t
34  real(FVPRC), pointer, dimension(:,:,:,:) :: q
35 end type
36 
37 interface assignment(=)
38  module procedure var_state_assignment
39 end interface
40 
41 interface remap_xy
42  module procedure remap_xy_2d
43  module procedure remap_xy_3d
44 end interface
45 
46 
47 integer, allocatable :: id1(:,:), id2(:,:), jdc(:,:)
48 real(FVPRC), allocatable :: s2c(:,:,:)
49 
51 integer :: jsd, jed
52 real(FVPRC), allocatable, dimension(:) :: lon_obs, lat_obs, ak_obs, bk_obs
53 type(time_type), allocatable :: timelist(:)
54 type(var_state_type) :: state(2)
55 logical :: do_state_alloc = .true.
56 logical :: module_is_initialized = .false.
57 
58 integer :: freq = 0 ! frequency in seconds
59 real(FVPRC) :: u_tau = -1. ! relaxation time in seconds (no insertion if < 0)
60 real(FVPRC) :: v_tau = -1.
61 real(FVPRC) :: t_tau = -1.
62 real(FVPRC) :: q_tau = -1.
63 real(FVPRC) :: ps_tau = -1.
64 integer :: skip_top_v = 2 ! momentum
65 integer :: skip_bot_v = 0
66 integer :: skip_top_t = 0 ! temperature
67 integer :: skip_bot_t = 21
68 integer :: skip_top_q = 8 ! specific humidity
69 integer :: skip_bot_q = 0
70 logical :: use_pdep_nudge = .false. ! impose nudging strength that varies with pressure
71 logical :: use_sub_domain = .false. ! only read data needed
72 integer :: verbose = 0 ! 0 .le. verbose .ge. 2
73 
74 namelist /fv_climate_nudge_nml/ freq, u_tau, v_tau, t_tau, q_tau, ps_tau, &
80 
85 logical :: do_u, do_v, do_t, do_q, do_ps
87 
88 integer :: id_index, id_coeff
89 
90 real(FVPRC), parameter :: zvir = rvgas/rdgas-1.
91 
92 CONTAINS
93 
94 !###################################################################################
95 
96 subroutine fv_climate_nudge_init ( Time, axes, flag )
97 type(time_type), intent(in) :: time
98 integer, dimension(3), intent(in) :: axes
99 logical, optional, intent(out) :: flag
100 integer :: n, ierr, io, unit
101 character(len=128) :: units, calendar, desc
102 #ifdef OVERLOAD_R4
103 real(4), allocatable :: tlevels(:)
104 #else
105 real(8), allocatable :: tlevels(:)
106 #endif
107 real(FVPRC) :: eps = 1.e-10
108 real(FVPRC) :: missing_value = -1.e10
109 
110  if (module_is_initialized) return
111 
112  ! read namelist
113 #ifdef INTERNAL_FILE_NML
114  read (input_nml_file, nml=fv_climate_nudge_nml, iostat=io)
115  ierr = check_nml_error(io, 'fv_climate_nudge_nml')
116 #else
117  if (file_exist('input.nml') ) then
118  unit = open_namelist_file()
119  ierr=1
120  do while (ierr /= 0)
121  read (unit, nml=fv_climate_nudge_nml, iostat=io, end=10)
122  ierr = check_nml_error(io, 'fv_climate_nudge_nml')
123  enddo
124 10 call close_file (unit)
125  endif
126 #endif
127 
128 !----- write version and namelist to log file -----
129 
130  unit = stdlog()
131  call write_version_number ('0.0','fv3-jedi-lm')
132  if (mpp_pe() == mpp_root_pe()) write (unit, nml=fv_climate_nudge_nml)
133 
134  ! initialize flags
135  do_u = .false.; if ( u_tau > -eps) do_u = .true.
136  do_v = .false.; if ( v_tau > -eps) do_v = .true.
137  do_t = .false.; if ( t_tau > -eps) do_t = .true.
138  do_q = .false.; if ( q_tau > -eps) do_q = .true.
139  do_ps = .false.; if (ps_tau > -eps) do_ps = .true.
140 
141  ! namelist dummy checks
142  ! if no overrides turned on then set freq = 0
143  if (freq > 0) then
144  if ( .not.do_u .and. .not.do_v .and. .not.do_t .and. &
145  .not.do_q .and. .not.do_ps ) then
146  call error_mesg ('fv_climate_nudge_nlm_mod', 'no variables specified '//&
147  'for override', warning)
148  endif
149  else
150  if ( do_u .or. do_v .or. do_t .or. do_q .or. do_ps ) then
151  call error_mesg ('fv_climate_nudge_nlm_mod', 'variables specified '//&
152  'for override when freq = 0', fatal)
153  endif
154  freq = 0
155  endif
156 
157  ! return flag = true when override is needed
158  if (present(flag)) then
159  flag = freq .gt. 0
160  endif
161 
162  ! what is the next time for data insertion
163 
164  time_next = time + set_time(freq)
165 
166  ! initialize diagnostics
167 
168  desc = ' tendency due to data insertion'
169 
170  id_udt = register_diag_field('atmos_nudge', 'udt_nudge', axes, time, &
171  'zonal wind'//trim(desc), 'm/s2', missing_value=missing_value)
172  id_vdt = register_diag_field('atmos_nudge', 'vdt_nudge', axes, time, &
173  'meridional wind'//trim(desc), 'm/s2',missing_value=missing_value)
174  id_tdt = register_diag_field('atmos_nudge', 'tdt_nudge', axes, time, &
175  'temperature'//trim(desc), 'degK/s',missing_value=missing_value)
176  id_qdt = register_diag_field('atmos_nudge', 'qdt_nudge', axes, time, &
177  'specific humidity'//trim(desc), 'kg/kg/s',missing_value=missing_value)
178  id_psdt = register_diag_field('atmos_nudge', 'psdt_nudge', axes(1:2), time, &
179  'surface pressure'//trim(desc), 'Pa/s',missing_value=missing_value)
180 
181  desc = ' bias'
182 
183  id_uerr = register_diag_field('atmos_nudge', 'u_bias', axes, time, &
184  'zonal wind'//trim(desc), 'm/s2', missing_value=missing_value)
185  id_verr = register_diag_field('atmos_nudge', 'v_bias', axes, time, &
186  'meridional wind'//trim(desc), 'm/s2',missing_value=missing_value)
187  id_terr = register_diag_field('atmos_nudge', 't_bias', axes, time, &
188  'temperature'//trim(desc), 'degK/s',missing_value=missing_value)
189  id_qerr = register_diag_field('atmos_nudge', 'q_bias', axes, time, &
190  'specific humidity'//trim(desc), 'kg/kg/s',missing_value=missing_value)
191  id_pserr = register_diag_field('atmos_nudge', 'ps_bias', axes(1:2), time, &
192  'surface pressure'//trim(desc), 'Pa/s',missing_value=missing_value)
193 
194  desc = ' observation used for nudging'
195 
196  id_uobs = register_diag_field('atmos_nudge', 'u_obs', axes, time, &
197  'zonal wind'//trim(desc), 'm/s2', missing_value=missing_value)
198  id_vobs = register_diag_field('atmos_nudge', 'v_obs', axes, time, &
199  'meridional wind'//trim(desc), 'm/s2',missing_value=missing_value)
200  id_tobs = register_diag_field('atmos_nudge', 't_obs', axes, time, &
201  'temperature'//trim(desc), 'degK/s',missing_value=missing_value)
202  id_qobs = register_diag_field('atmos_nudge', 'q_obs', axes, time, &
203  'specific humidity'//trim(desc), 'kg/kg/s',missing_value=missing_value)
204  id_psobs = register_diag_field('atmos_nudge', 'ps_obs', axes(1:2), time, &
205  'surface pressure'//trim(desc), 'Pa/s',missing_value=missing_value)
206 
207  id_index = register_static_field('atmos_nudge', 'jdc', axes(1:2), 'interp index', 'none' )
208  id_coeff = register_static_field('atmos_nudge', 's2c', axes(1:2), 'interp coeff', 'none' )
209 
210  ! set flags
211  get_wind = do_u .or. id_udt>0 .or. id_uerr>0 .or. id_uobs>0 .or. do_v .or. id_vdt>0 .or. id_verr>0 .or. id_vobs>0
212  get_temp = do_t .or. id_tdt>0 .or. id_terr>0 .or. id_tobs>0
213  get_qhum = do_q .or. id_qdt>0 .or. id_qerr>0 .or. id_qobs>0
214 
215  if (.not.get_wind .and. .not.get_temp .and. .not.get_qhum .and. freq.eq.0) return
216 !--------------------------------------------
217 ! initialize input data from file
218 ! get the size of the global data
219  call error_mesg ('fv_climate_nudge_nlm_mod', 'initializing nudging', note)
221  if (verbose .gt. 1 .and. mpp_pe() .eq. mpp_root_pe()) then
222  print '(a,4i10)', 'fv_climate_nudge: nlon_obs, nlat_obs, nlev_obs, ntime_obs = ', &
224  endif
225 
226 ! read the time level information
227  allocate ( tlevels(ntime_obs) )
228  allocate ( timelist(ntime_obs) )
229  call read_time ( tlevels, units, calendar )
230  do n = 1, ntime_obs
231  timelist(n) = get_cal_time( tlevels(n), trim(units), trim(calendar), &
232  permit_calendar_conversion=.true. )
233  enddo
234  deallocate ( tlevels )
235 
236 ! read the grid information
239 
240  if (mpp_pe() .eq. mpp_root_pe()) then
241  if (verbose .gt. 1) then
242  print *, 'fv_climate_nudge: ak_obs=',ak_obs
243  print *, 'fv_climate_nudge: bk_obs=',bk_obs
244  endif
245  if (verbose .gt. 0) then
246  call print_date (timelist(1),'nudging data, start date: ')
247  call print_date (timelist(ntime_obs),'nudging data, final date: ')
248  endif
249  endif
250 
251  module_is_initialized = .true.
252 
253 end subroutine fv_climate_nudge_init
254 
255 !###################################################################################
256 
257 subroutine fv_climate_nudge (Time, dt, is, ie, js, je, npz, pfull, &
258  lon, lat, phis, ptop, ak, bk, &
259  ps, u, v, t, q, psdt, udt, vdt, tdt, qdt )
260 type(time_type), intent(in) :: time
261 real(FVPRC), intent(in) :: dt
262 integer, intent(in) :: is, ie, js, je, npz
263 real(FVPRC), intent(IN) :: ptop
264 
265 real(FVPRC), intent(in) :: phis(is:ie,js:je)
266 real(FVPRC), intent(in) :: lon (is:ie,js:je)
267 real(FVPRC), intent(in) :: lat (is:ie,js:je)
268 real(FVPRC), intent(in) :: ak (npz+1)
269 real(FVPRC), intent(in) :: bk (npz+1)
270 real(FVPRC), intent(in) :: pfull (npz)
271 
272 real(FVPRC), intent(inout) :: ps (is:ie,js:je)
273 real(FVPRC), intent(inout) :: psdt(is:ie,js:je)
274 
275 real(FVPRC), intent(inout) :: u(is:ie,js:je,npz)
276 real(FVPRC), intent(inout) :: v(is:ie,js:je,npz)
277 real(FVPRC), intent(inout) :: t(is:ie,js:je,npz)
278 real(FVPRC), intent(inout) :: q(is:ie,js:je,npz,1)
279 
280 real(FVPRC), intent(inout) :: udt(is:ie,js:je,npz)
281 real(FVPRC), intent(inout) :: vdt(is:ie,js:je,npz)
282 real(FVPRC), intent(inout) :: tdt(is:ie,js:je,npz)
283 real(FVPRC), intent(inout) :: qdt(is:ie,js:je,npz,1)
284 
285 ! local arrays
286 real(FVPRC), dimension(is:ie,js:je,nlev_obs) :: u_obs, v_obs, t_obs
287 real(FVPRC), dimension(is:ie,js:je,nlev_obs) :: q_obs
288 real(FVPRC), dimension(is:ie,js:je) :: ps_obs, phis_obs
289 
290 real(FVPRC), dimension(is:ie,js:je,nlev_obs+1) :: phaf_obs, lphaf_obs
291 real(FVPRC), dimension(is:ie,js:je,npz+1) :: phaf, lphaf
292 
293 !real, dimension(nlon_obs,jsd:jed,nlev_obs) :: dat3
294 real(FVPRC), allocatable :: dat3(:,:,:)
295 
296 real(FVPRC), dimension(is:ie,js:je,npz) :: obs, tend
297 real(FVPRC) :: factor(npz,3), wght(2)
298 logical :: sent
299 integer :: itime(2), k, n
300 character(len=128) :: str
301 character(len=8) :: rstr(2)
302 character(len=256) :: err_msg
303 
304 ! this variable addresses a bug with high resolution GFS analyses
305 ! before a certain date preprocessing scripts did not convert virtual temperature to temperature
306 logical :: virtual_temp_obs = .false.
307 
308  if (.not.module_is_initialized) then
309  call error_mesg ('fv_climate_nudge_nlm_mod', 'module not initialized', fatal)
310  endif
311 
312  ! is it time for data forcing
313  if (time < time_next) then
314  return
315  endif
317 
318  ! only one tracer (specific humidity) can be interpolated
319  ! if (size(q,4).ne.1 .or. size(qdt,4).ne.1) then
320  ! call error_mesg ('fv_climate_nudge_nlm_mod', 'only one tracer (sphum) allowed', FATAL)
321  ! endif
322 
323  ! vertically dependent factor
324  call get_factor (npz,pfull, factor)
325  ! first time allocate state
326  if (do_state_alloc) then
327  call var_state_init ( is, ie, js, je, npz, state(1) )
328  call var_state_init ( is, ie, js, je, npz, state(2) )
329 
330  ! sub-domain initialization
331  if (use_sub_domain) then
332  call read_sub_domain_init (minval(lat), maxval(lat), lat_obs, jsd, jed)
333  else
334  jsd=1; jed=nlat_obs
335  endif
336 
337  ! also initalize coefficient for horizontal interpolation
338  allocate ( id1(is:ie,js:je), id2(is:ie,js:je), jdc(is:ie,js:je), s2c(is:ie,js:je,4) )
339  call remap_coef ( 1, nlon_obs, jsd, jed, lon_obs, lat_obs(jsd:jed), &
340  is, ie, js, je, lon, lat, id1, id2, jdc, s2c )
341  do_state_alloc = .false.
342  if (id_index > 0) sent = send_data(id_index, real(jdc), time)
343  if (id_coeff > 0) sent = send_data(id_coeff, real(s2c(:,:,1)), time)
344  endif
345 
346 !//////////////////////////////////////////////////////
347 
348  ! get the time indices needed
349  call time_interp (time, timelist, wght(2), itime(1), itime(2), err_msg=err_msg)
350  if(err_msg /= '') then
351  call error_mesg('fv_climate_nudge_nlm_mod',trim(err_msg), fatal)
352  endif
353 
354  wght(1) = 1. - wght(2)
355  if (verbose .gt. 1 .and. mpp_pe() .eq. mpp_root_pe()) then
356  write (rstr(1),'(f8.6)') wght(1)
357  write (rstr(2),'(f8.6)') wght(2)
358  str = 'Data Nudging: itime='//trim(string(itime(1)))//','//trim(string(itime(2)))// &
359  '; wght='//rstr(1)//','//rstr(2)//'; Date: '
360  call print_date (time,trim(str))
361  endif
362 
363  do n = 1, 2
364 
365  if (itime(n) .ne. state(n)%time_level) then
366  if (n .eq. 1) then
367  if (itime(1) .eq. state(2)%time_level) then
368  state(1) = state(2)
369  cycle
370  endif
371  endif
372  if (.not.allocated(dat3)) allocate (dat3(nlon_obs,jsd:jed,nlev_obs))
373 
374  ! ---- horizontal interpolation ----
375  ! geop hght
376  call read_climate_nudge_data (itime(n), 'phis', dat3(:,:,1), 1, jsd)
377  if (verbose .gt. 1) call prt_minmax_2d('phis_obs(mn,mx)=',dat3(:,:,1))
378  call remap_xy (1, nlon_obs, jsd, jed, dat3(:,:,1), is, ie, js, je, id1, id2, jdc, s2c, phis_obs)
379  ! surf pres
380  call read_climate_nudge_data (itime(n), 'psrf', dat3(:,:,1), 1, jsd)
381  if (verbose .gt. 1) call prt_minmax_2d('ps_obs(mn,mx)=',dat3(:,:,1))
382  call remap_xy (1, nlon_obs, jsd, jed, dat3(:,:,1), is, ie, js, je, id1, id2, jdc, s2c, ps_obs)
383  !if (verbose .gt. 1) call prt_minmax_2d('ps_obs_adj(mn,mx)=',ps_obs)
384 
385  ! compute pressure and ln pres at layer interfaces
386  do k = 1, nlev_obs+1
387  phaf_obs(:,:,k) = ak_obs(k) + bk_obs(k)*ps_obs
388  enddo
389  do k = 2, nlev_obs+1
390  lphaf_obs(:,:,k) = log(phaf_obs(:,:,k))
391  enddo
392  where (phaf_obs(:,:,1) .gt. 0.0)
393  lphaf_obs(:,:,1) = log(phaf_obs(:,:,1))
394  elsewhere
395  lphaf_obs(:,:,1) = lphaf_obs(:,:,2)-2.
396  endwhere
397  lphaf_obs(:,:,1) = max(lphaf_obs(:,:,1),0.0)
398 
399  ! wind interpolation
400  if (get_wind) then
401  call read_climate_nudge_data (itime(n), 'uwnd', dat3, 1, jsd)
402  if (verbose .gt. 1) call prt_minmax_3d('u_obs(mn,mx)=',dat3)
403  call remap_xy (1, nlon_obs, jsd, jed, nlev_obs, dat3, is, ie, js, je, id1, id2, jdc, s2c, u_obs)
404  call read_climate_nudge_data (itime(n), 'vwnd', dat3, 1, jsd)
405  if (verbose .gt. 1) call prt_minmax_3d('v_obs(mn,mx)=',dat3)
406  call remap_xy (1, nlon_obs, jsd, jed, nlev_obs, dat3, is, ie, js, je, id1, id2, jdc, s2c, v_obs)
407  endif
408  ! spec hum (always need for virt temp)
409  ! if (get_qhum) then
410  call read_climate_nudge_data (itime(n), 'qhum', dat3, 1, jsd)
411  if (verbose .gt. 1) call prt_minmax_3d('q_obs(mn,mx)=',dat3)
412  call remap_xy (1, nlon_obs, jsd, jed, nlev_obs, dat3, is, ie, js, je, id1, id2, jdc, s2c, q_obs)
413  ! endif
414  ! temperature (always need for surf pres remapping)
415  ! if (get_temp) then
416  call read_climate_nudge_data (itime(n), 'temp', dat3, 1, jsd)
417  if (verbose .gt. 1) call prt_minmax_3d('t_obs(mn,mx)=',dat3)
418  call remap_xy (1, nlon_obs, jsd, jed, nlev_obs, dat3, is, ie, js, je, id1, id2, jdc, s2c, t_obs)
419  if (.not.virtual_temp_obs) then
420  t_obs = t_obs*(1.+zvir*q_obs) ! virtual effect
421  endif
422  ! endif
423 
424  ! VERTICAL REMAPPING
425  ! remap surface pressure for different surface height
426  call remap_ps (is, ie, js, je, nlev_obs, phis_obs, phaf_obs, lphaf_obs, t_obs, phis, state(n)%ps)
427 
428  ! compute pressure and ln pres at layer interfaces
429  do k = 1, npz+1
430  phaf(:,:,k) = ak(k) + bk(k)*state(n)%ps
431  lphaf(:,:,k) = log(phaf(:,:,k))
432  enddo
433 
434  if (get_wind) then
435  call remap_3d (is, ie, js, je, nlev_obs, npz, phaf_obs, u_obs, phaf, state(n)%u, -1, ptop)
436  call remap_3d (is, ie, js, je, nlev_obs, npz, phaf_obs, v_obs, phaf, state(n)%v, -1, ptop)
437  endif
438  if (get_qhum .or. get_temp) then
439  call remap_3d (is, ie, js, je, nlev_obs, npz, phaf_obs, q_obs, phaf, state(n)%q(:,:,:,1), 0, ptop)
440  endif
441  if (get_temp) then
442  ! use logp
443  call remap_3d (is, ie, js, je, nlev_obs, npz, lphaf_obs, t_obs, lphaf, state(n)%t, 1, ptop)
444  state(n)%t = state(n)%t/(1.+zvir*state(n)%q(:,:,:,1)) ! virtual effect
445  endif
446 
447  state(n)%time_level = itime(n)
448  if (verbose .gt. 1) then
449  !call prt_minmax_2d('phis(mn,mx)=',phis)
450  call prt_minmax_2d('ps(mn,mx)=',state(n)%ps)
451  if (get_wind) call prt_minmax_3d('u(mn,mx)=',state(n)%u)
452  if (get_wind) call prt_minmax_3d('v(mn,mx)=',state(n)%v)
453  if (get_temp) call prt_minmax_3d('t(mn,mx)=',state(n)%t)
454  if (get_qhum) call prt_minmax_3d('q(mn,mx)=',state(n)%q(:,:,:,1))
455  endif
456  endif
457  enddo
458  if (allocated(dat3)) deallocate (dat3)
459 
460 !//////////////////////////////////////////////////////
461 
462 ! zonal wind component
463  if (do_u .or. id_udt>0 .or. id_uerr>0 .or. id_uobs>0) then
464  obs = state(1)%u*wght(1) + state(2)%u*wght(2)
465  if (do_u) then
466  do k = 1, npz
467  tend(:,:,k) = (obs(:,:,k) - u(:,:,k)) / (u_tau + dt) * factor(k,1)
468  u(:,:,k) = u(:,:,k) + dt*tend(:,:,k)
469  udt(:,:,k) = udt(:,:,k) + tend(:,:,k)
470  enddo
471  else if (id_udt > 0) then
472  tend = 0.0
473  endif
474  if (id_udt > 0) sent = send_data(id_udt, tend, time)
475  if (id_uerr > 0) then
476  tend = u - obs
477  sent = send_data(id_uerr, tend, time)
478  endif
479  if (id_uobs > 0) sent = send_data(id_uobs, obs, time)
480  endif
481 
482 ! meridional wind component
483  if (do_v .or. id_vdt>0 .or. id_verr>0 .or. id_vobs>0) then
484  obs = state(1)%v*wght(1) + state(2)%v*wght(2)
485  if (do_v) then
486  do k = 1, npz
487  tend(:,:,k) = (obs(:,:,k) - v(:,:,k)) / (v_tau + dt) * factor(k,1)
488  v(:,:,k) = v(:,:,k) + dt*tend(:,:,k)
489  vdt(:,:,k) = vdt(:,:,k) + tend(:,:,k)
490  enddo
491  else if (id_vdt > 0) then
492  tend = 0.0
493  endif
494  if (id_vdt > 0) sent = send_data(id_vdt, tend, time)
495  if (id_verr > 0) then
496  tend = v - obs
497  sent = send_data(id_verr, tend, time)
498  endif
499  if (id_vobs > 0) sent = send_data(id_vobs, obs, time)
500  endif
501 
502 ! temperature
503  if (do_t .or. id_tdt>0 .or. id_terr>0 .or. id_tobs>0) then
504  obs = state(1)%t*wght(1) + state(2)%t*wght(2)
505  if (do_t) then
506  do k = 1, npz
507  tend(:,:,k) = (obs(:,:,k) - t(:,:,k)) / (t_tau + dt) * factor(k,2)
508  t(:,:,k) = t(:,:,k) + dt*tend(:,:,k)
509  tdt(:,:,k) = tdt(:,:,k) + tend(:,:,k)
510  enddo
511  else if (id_tdt > 0) then
512  tend = 0.0
513  endif
514  if (id_tdt > 0) sent = send_data(id_tdt, tend, time)
515  if (id_terr > 0) then
516  tend = t - obs
517  sent = send_data(id_terr, tend, time)
518  endif
519  if (id_tobs > 0) sent = send_data(id_tobs, obs, time)
520  endif
521 
522 ! specific humidity
523  if (do_q .or. id_qdt>0 .or. id_qerr>0 .or. id_qobs>0) then
524  obs = state(1)%q(:,:,:,1)*wght(1) + state(2)%q(:,:,:,1)*wght(2)
525  if (do_q) then
526  do k = 1, npz
527  tend(:,:,k) = (obs(:,:,k) - q(:,:,k,1)) / (q_tau + dt) * factor(k,2)
528  q(:,:,k,1) = q(:,:,k,1) + dt*tend(:,:,k)
529  qdt(:,:,k,1) = qdt(:,:,k,1) + tend(:,:,k)
530  enddo
531  else if (id_qdt > 0) then
532  tend = 0.0
533  endif
534  if (id_qdt > 0) sent = send_data(id_qdt, tend, time)
535  if (id_qerr > 0) then
536  tend = q(:,:,:,1) - obs
537  sent = send_data(id_qerr, tend, time)
538  endif
539  if (id_qobs > 0) sent = send_data(id_qobs, obs, time)
540  endif
541 
542 ! surface pressure
543  if (do_ps .or. id_psdt>0 .or. id_pserr>0 .or. id_psobs>0) then
544  obs(:,:,1) = state(1)%ps*wght(1) + state(2)%ps*wght(2)
545  if (do_ps) then
546  tend(:,:,1) = (obs(:,:,1) - ps) / (ps_tau + dt)
547  ps = ps + dt*tend(:,:,1)
548  psdt = psdt + tend(:,:,1)
549  else if (id_psdt > 0) then
550  tend(:,:,1) = 0.0
551  endif
552  if (id_psdt > 0) sent = send_data(id_psdt, tend(:,:,1), time)
553  if (id_pserr > 0) then
554  tend(:,:,1) = ps - obs(:,:,1)
555  sent = send_data(id_pserr, tend(:,:,1), time)
556  endif
557  if (id_psobs > 0) sent = send_data(id_psobs, obs(:,:,1), time)
558  endif
559 
560 end subroutine fv_climate_nudge
561 
562 !###################################################################################
563 
564 subroutine get_factor (nlev,pfull,factor)
565 integer, intent(in) :: nlev
566 real(FVPRC), intent(in) :: pfull(nlev)
567 real(FVPRC), intent(out) :: factor(nlev,3)
568 integer :: k
569 real(FVPRC) :: psurf
570 
571 ! vertically dependent Tau
572 ! very crude - zero at top/bottom + linear increase with level downward/upward
573 
574  factor = 1.
575 
576 !------------------------------------------------------------------
577 ! Momentum:
578  if (skip_top_v > 0) then
579 !++amf
580 ! factor(1,1) = 0.
581 ! do k = 2, skip_top_v
582 ! factor(k,1) = factor(k-1,1) + 1./real(skip_top_v)
583 ! enddo
584  factor(skip_top_v+1,1) = 0.25
585  factor(skip_top_v+2,1) = 0.5
586  do k = 1, skip_top_v
587  factor(k,1) = 0.
588  enddo
589  endif
590  if (skip_bot_v > 0) then
591  factor(nlev,1) = 0.
592  do k = nlev-1, nlev-skip_bot_v+1, -1
593  factor(k,1) = factor(k+1,1) + 1./real(skip_bot_v)
594  enddo
595  endif
596 
597 ! temperature
598  if (skip_top_t > 0) then
599 !++amf
600 ! factor(1,2) = 0.
601 ! do k = 2, skip_top_t
602 ! factor(k,2) = factor(k-1,2) + 1./real(skip_top_t)
603 ! enddo
604  factor(skip_top_t+1,2) = 0.25
605  factor(skip_top_t+2,2) = 0.5
606  do k = 1, skip_top_t
607  factor(k,2) = 0.
608  enddo
609 !--amf
610  endif
611  if (skip_bot_t > 0) then
612  factor(nlev-skip_bot_t-1,2) = 0.5
613  factor(nlev-skip_bot_t, 2) = 0.25
614  do k=nlev-skip_bot_t+1,nlev
615  factor(k,2) = 0.
616  enddo
617  endif
618 
619 ! Specific humidity
620  if (skip_top_q > 0) then
621  do k = 1, skip_top_q
622  factor(k,3) = 0.
623  enddo
624  factor(skip_top_q+1,3) = 0.25
625  factor(skip_top_q+2,3) = 0.5
626  endif
627  if (skip_bot_q > 0) then
628  factor(nlev,3) = 0.
629  do k = nlev-1, nlev-skip_bot_q+1, -1
630  factor(k,3) = factor(k+1,3) + 1./real(skip_bot_q)
631  enddo
632  endif
633 
634 !++amf Apply scaling such that nudging strength falls off with pressure.
635 
636  if (use_pdep_nudge) then
637  psurf = pfull(nlev)
638  do k = 1, nlev
639  factor(k,:) = factor(k,:)*(pfull(k)/psurf)
640  ! print*, 'AMF: k,pfull(k),psurf, factor = ', k, pfull(k), psurf, pfull(k)/psurf
641  enddo
642  endif
643 
644 !--amf
645 
646 !------------------------------------------------------------------
647 
648 end subroutine get_factor
649 
650 !###################################################################################
651 
652 subroutine var_state_init ( is, ie, js, je, npz, State )
653 type(var_state_type), intent(inout) :: State
654 integer, intent(in) :: is, ie, js, je, npz
655 
656  state%is = is
657  state%ie = ie
658  state%js = js
659  state%je = je
660  state%npz = npz
661  state%time_level = -1
662  allocate (state%ps(is:ie,js:je))
663  if (get_wind) then
664  allocate (state%u(is:ie,js:je,1:npz))
665  allocate (state%v(is:ie,js:je,1:npz))
666  endif
667  if (get_temp) then
668  allocate (state%t(is:ie,js:je,1:npz))
669  endif
670  if (get_qhum .or. get_temp) then
671  allocate (state%q(is:ie,js:je,1:npz,1:1))
672  endif
673 
674 end subroutine var_state_init
675 
676 !-----------------------------------------------------
677 
678 subroutine var_state_assignment (State1,State2)
679 type(var_state_type), intent(inout) :: State1
680 type(var_state_type), intent(in) :: State2
681 
682  ! resolution must match
683  if (state1%is /= state2%is .or. state1%ie /= state2%ie .or. &
684  state1%js /= state2%js .or. state1%je /= state2%je .or. &
685  state1%npz /= state2%npz) then
686  call error_mesg ('fv_climate_nudge_nlm_mod', 'invalid var_state assignment: '// &
687  'dimensions must match', fatal)
688  endif
689 
690  ! copy data - must be allocated
691  state1%time_level = state2%time_level
692  state1%ps = state2%ps
693  if (associated(state1%u)) state1%u = state2%u
694  if (associated(state1%v)) state1%v = state2%v
695  if (associated(state1%t)) state1%t = state2%t
696  if (associated(state1%q)) state1%q = state2%q
697 
698 end subroutine var_state_assignment
699 
700 !-----------------------------------------------------
701 
702 subroutine var_state_del ( State )
703 type(var_state_type), intent(inout) :: State
704 
705  state%is = 1
706  state%ie = 0
707  state%js = 1
708  state%je = 0
709  state%npz = 0
710  state%time_level = -1
711  deallocate (state%ps)
712  if (get_wind) then
713  if (associated(state%u)) deallocate (state%u)
714  if (associated(state%v)) deallocate (state%v)
715  endif
716  if (get_temp) then
717  if (associated(state%t)) deallocate (state%t)
718  endif
719  if (get_qhum .or. get_temp) then
720  if (associated(state%q)) deallocate (state%q)
721  endif
722 
723 end subroutine var_state_del
724 
725 !###################################################################################
726 
727 subroutine fv_climate_nudge_end
729  if (.not.module_is_initialized) return
730 
731  deallocate ( timelist )
732  deallocate ( lon_obs, lat_obs, ak_obs, bk_obs )
733 
734  if (.not.do_state_alloc) then
735  call var_state_del ( state(1) )
736  call var_state_del ( state(2) )
737  deallocate ( id1, id2, jdc, s2c )
738  do_state_alloc = .true.
739  endif
740 
742 
743  module_is_initialized = .false.
744 end subroutine fv_climate_nudge_end
745 
746 !###################################################################################
747 
748 subroutine prt_minmax_2d (str,a)
749 character(len=*), intent(in) :: str
750 real(FVPRC), intent(in) :: a(:,:)
751 real(FVPRC) :: local_min, local_max
752 
753  local_min = minval(a)
754  local_max = maxval(a)
755  call mpp_min(local_min)
756  call mpp_max(local_max)
757  if (mpp_pe()==mpp_root_pe()) then
758  print *, trim(str),local_min,local_max
759  endif
760 
761 end subroutine prt_minmax_2d
762 
763 !------------------------------------------
764 
765 subroutine prt_minmax_3d (str,a)
766 character(len=*), intent(in) :: str
767 real(FVPRC), intent(in) :: a(:,:,:)
768 real(FVPRC) :: local_min, local_max
769 
770  local_min = minval(a)
771  local_max = maxval(a)
772  call mpp_min(local_min)
773  call mpp_max(local_max)
774  if (mpp_pe()==mpp_root_pe()) then
775  print *, trim(str),local_min,local_max
776  endif
777 
778 end subroutine prt_minmax_3d
779 
780 !###################################################################################
781 !###################################################################################
782 ! For data nudging with the FV cubed sphere dynamical core:
783 ! Contact S.-J. Lin, NOAA/GFDL, for more information
784 
785  subroutine remap_coef( isd, ied, jsd, jed, lon_in, lat_in, &
786  is, ie, js, je, lon_out, lat_out, &
787  id1, id2, jdc, s2c )
788 !--------
789 ! Input:
790 !--------
791 ! Data Input: data must be global
792  integer, intent(in):: isd, ied ! Data x-dimension (W->E; must be periodic)
793  integer, intent(in):: jsd, jed ! Data y-dimension (S->N)
794  real(FVPRC), intent(in):: lon_in(isd:ied) ! Data longitude (Radian; periodic)
795  real(FVPRC), intent(in):: lat_in(jsd:jed) ! Data latitude (increases from SP to NP)
796 
797 ! Model input:
798  integer, intent(in):: is, ie, js, je ! model horizontal dimensions (un-ghosted sub-domian)
799  real(FVPRC), intent(in):: lon_out(is:ie,js:je) ! model longitude (Radian)
800  real(FVPRC), intent(in):: lat_out(is:ie,js:je) ! model latitude (Radian)
801 
802 !--------
803 ! Output:
804 !--------
805 !
806  integer, intent(out), dimension(is:ie,js:je ):: id1, id2, jdc
807  real(FVPRC), intent(out), dimension(is:ie,js:je,4):: s2c
808 
809 !===============================================================================================
810 
811 ! local:
812  real(FVPRC):: rdlon(isd:ied)
813  real(FVPRC):: rdlat(jsd:jed)
814  real(FVPRC):: a1, b1
815  integer i, j, i1, i2, jc, i0, j0
816 
817  !pk0(1) = ak_in(1)**KAPPA
818  !pn_top = log(ak_in(1))
819 
820  do i=isd,ied-1
821  rdlon(i) = 1. / (lon_in(i+1) - lon_in(i))
822  enddo
823  rdlon(ied) = 1. / (lon_in(isd) + 2.*pi - lon_in(ied)) ! periodic assumption
824 
825  do j=jsd,jed-1
826  rdlat(j) = 1. / (lat_in(j+1) - lat_in(j))
827  enddo
828 
829 ! * Interpolate to cubed sphere cell center
830  do 5000 j=js,je
831 
832  do i=is,ie
833 
834  if ( lon_out(i,j) .gt. lon_in(ied) ) then
835  i1 = ied; i2 = isd
836  a1 = (lon_out(i,j)-lon_in(ied)) * rdlon(ied)
837  elseif ( lon_out(i,j) .lt. lon_in(1) ) then
838  i1 = ied; i2 = isd
839  a1 = (lon_out(i,j)+2.*pi-lon_in(ied)) * rdlon(ied)
840  else
841  do i0=isd,ied-1
842  if ( lon_out(i,j) .ge. lon_in(i0) .and. lon_out(i,j) .le. lon_in(i0+1) ) then
843  i1 = i0; i2 = i0+1
844  a1 = (lon_out(i,j)-lon_in(i1)) * rdlon(i0)
845  go to 111
846  endif
847  enddo
848  endif
849 
850 111 continue
851 
852  if ( lat_out(i,j) .lt. lat_in(jsd) ) then
853  jc = jsd
854  b1 = 0.
855  elseif ( lat_out(i,j) .gt. lat_in(jed) ) then
856  jc = jed-1
857  b1 = 1.
858  else
859  do j0=jsd,jed-1
860  if ( lat_out(i,j) .ge. lat_in(j0) .and. lat_out(i,j) .le. lat_in(j0+1) ) then
861  jc = j0
862  b1 = (lat_out(i,j)-lat_in(jc)) * rdlat(jc)
863  go to 222
864  endif
865  enddo
866  endif
867 222 continue
868 
869 ! Debug codes:
870 ! if ( a1<0.0 .or. a1>1.0 .or. b1<0.0 .or. b1>1.0 ) then
871 ! write(*,*) i,j,a1, b1
872 ! endif
873 
874  s2c(i,j,1) = (1.-a1) * (1.-b1)
875  s2c(i,j,2) = a1 * (1.-b1)
876  s2c(i,j,3) = a1 * b1
877  s2c(i,j,4) = (1.-a1) * b1
878  id1(i,j) = i1
879  id2(i,j) = i2
880  jdc(i,j) = jc
881 
882  enddo
883 5000 continue
884 
885  end subroutine remap_coef
886 
887 !---------------------------------------------------
888 
889  subroutine remap_xy_3d( isd, ied, jsd, jed, km, q_in, &
890  is, ie, js, je, id1, id2, jdc, s2c, &
891  q_out )
892 !--------
893 ! Input:
894 !--------
895 ! Data Input: data must be global
896  integer, intent(in):: isd, ied ! Data x-dimension (W->E; must be periodic)
897  integer, intent(in):: jsd, jed ! Data y-dimension (S->N)
898  integer, intent(in):: km ! Data vertical-dimension
899  real(FVPRC), intent(in), dimension(isd:ied,jsd:jed,km) :: q_in ! Data on input grid
900 
901 ! Model input:
902  integer, intent(in):: is, ie, js, je ! model horizontal dimensions (un-ghosted sub-domian)
903 
904 ! Indices and coefficients for bilinear interpolation
905  integer, intent(in), dimension(is:ie,js:je ):: id1, id2, jdc
906  real(FVPRC), intent(in), dimension(is:ie,js:je,4):: s2c
907 
908 !--------
909 ! Output:
910 !--------
911 ! Data Output: on local model horizontal grid and input data vertical grid
912  real(FVPRC), intent(out), dimension(is:ie,js:je,km):: q_out
913 
914  integer :: i, j, k
915 
916  do k=1,km
917  do j=js,je
918  do i=is,ie
919  q_out(i,j,k) = s2c(i,j,1)*q_in(id1(i,j),jdc(i,j), k) + s2c(i,j,2)*q_in(id2(i,j),jdc(i,j), k) + &
920  s2c(i,j,3)*q_in(id2(i,j),jdc(i,j)+1,k) + s2c(i,j,4)*q_in(id1(i,j),jdc(i,j)+1,k)
921  enddo
922  enddo
923  enddo
924 
925  end subroutine remap_xy_3d
926 
927 !---------------------------------------------------
928 
929  subroutine remap_xy_2d( isd, ied, jsd, jed, q_in, &
930  is, ie, js, je, id1, id2, jdc, s2c, &
931  q_out )
932 !--------
933 ! Input:
934 !--------
935  integer, intent(in):: isd, ied ! Data x-dimension (W->E; must be periodic)
936  integer, intent(in):: jsd, jed ! Data y-dimension (S->N)
937  real(FVPRC), intent(in), dimension(isd:ied,jsd:jed) :: q_in ! Data on input grid
938  integer, intent(in):: is, ie, js, je ! model horizontal dimensions (un-ghosted sub-domian)
939  integer, intent(in), dimension(is:ie,js:je ):: id1, id2, jdc
940  real(FVPRC), intent(in), dimension(is:ie,js:je,4):: s2c
941 !--------
942 ! Output:
943 !--------
944  real(FVPRC), intent(out), dimension(is:ie,js:je):: q_out
945 
946 ! Local:
947  real(FVPRC), dimension(isd:ied,jsd:jed,1) :: q3d_in
948  real(FVPRC), dimension(is:ie,js:je,1) :: q3d_out
949 
950  q3d_in(:,:,1) = q_in
951  call remap_xy_3d( isd, ied, jsd, jed, 1, q3d_in, &
952  is, ie, js, je, id1, id2, jdc, s2c, &
953  q3d_out )
954  q_out = q3d_out(:,:,1)
955 
956  end subroutine remap_xy_2d
957 
958 !---------------------------------------------------
959 
960  subroutine remap_ps( is, ie, js, je, km, &
961  gz_dat, ph_dat, pn_dat, tp_dat, phis, ps )
963 !--------
964 ! Input:
965 !--------
966  integer, intent(in):: is, ie, js, je ! model horizontal dimensions (un-ghosted sub-domian)
967  integer, intent(in):: km ! model horizontal dimensions (un-ghosted sub-domian)
968  real(FVPRC), intent(in):: gz_dat(is:ie,js:je) ! Data surface geop height (m2/s2)
969  real(FVPRC), intent(in):: ph_dat(is:ie,js:je,km+1) ! Data pressure at layer interfaces (Pa)
970  real(FVPRC), intent(in):: pn_dat(is:ie,js:je,km+1) ! Data natural log pressure at layer interfaces (Pa)
971  real(FVPRC), intent(in):: tp_dat(is:ie,js:je,km) ! Data temperature in layers (K)
972  real(FVPRC), intent(in):: phis (is:ie,js:je) ! Model surface geop height (m2/s2)
973 
974 !--------
975 ! Output:
976 !--------
977  real(FVPRC), intent(out):: ps (is:ie,js:je) ! Model surface pressure (pa)
978 
979 ! local
980  integer :: i, j, k
981  real(FVPRC) :: pk0(km+1), gz(km+1), pt0, pst
982 ! needed: real, parameter :: kappa, rdgas, cp_air
983 
984  do j = js,je
985  do i = is,ie
986 
987 ! Adjust interpolated ps to model terrain
988  gz(km+1) = gz_dat(i,j)
989  pk0(km+1) = ph_dat(i,j,km+1)**kappa
990  do k=km,1,-1
991  gz(k) = gz(k+1) + rdgas*tp_dat(i,j,k)*(pn_dat(i,j,k+1)-pn_dat(i,j,k))
992  pk0(k) = ph_dat(i,j,k)**kappa
993  enddo
994  if ( phis(i,j) .gt. gz_dat(i,j) ) then
995  do k=km,1,-1
996  if( phis(i,j) < gz(k) .and. &
997  phis(i,j) >= gz(k+1) ) then
998  pst = pk0(k) + (pk0(k+1)-pk0(k))*(gz(k)-phis(i,j))/(gz(k)-gz(k+1))
999  go to 123
1000  endif
1001  enddo
1002  else
1003 ! Extrapolation into the ground
1004 ! lowest layer potential temp is needed
1005  pt0= tp_dat(i,j,km)/(pk0(km+1)-pk0(km))*(kappa*(pn_dat(i,j,km+1)-pn_dat(i,j,km)))
1006  pst = pk0(km+1) + (gz_dat(i,j)-phis(i,j))/(cp_air*pt0)
1007  endif
1008  123 ps(i,j) = pst**(1./kappa)
1009 
1010  enddo
1011  enddo
1012 
1013 
1014  end subroutine remap_ps
1015 
1016 !---------------------------------------------------
1017 
1018  subroutine remap_3d( is, ie, js, je, km, npz, &
1019  pe0, qn0, pe1, qn1, n, ptop )
1021 !--------
1022 ! Input:
1023 !--------
1024  integer, intent(in):: is, ie, js, je ! model horizontal dimensions (un-ghosted sub-domian)
1025  integer, intent(in):: km ! vertical dimension for input data
1026  integer, intent(in):: npz ! vertical dimension for model data
1027  real(FVPRC), intent(in):: pe0(is:ie,js:je,km+1) ! pressure at layer interfaces for input data
1028  real(FVPRC), intent(in):: qn0(is:ie,js:je,km) ! scalar quantity on input data levels
1029  real(FVPRC), intent(in):: pe1(is:ie,js:je,npz+1) ! pressure at layer interfaces for model data
1030  integer, intent(in):: n ! -1 wind; 0 sphum; +1 ptemp
1031  real(FVPRC), intent(IN):: ptop
1032 
1033 !--------
1034 ! Output:
1035 !--------
1036  real(FVPRC), intent(out):: qn1(is:ie,js:je,npz) ! Scalar quantity on 3d model grid
1037 
1038 ! local
1039  integer :: i, j, k
1040 
1041  do j = js,je
1042  call mappm(km, pe0(is:ie,j,:), qn0(is:ie,j,:), npz, pe1(is:ie,j,:), qn1(is:ie,j,:), is,ie, n, 8, ptop)
1043  enddo
1044 
1045  end subroutine remap_3d
1046 
1047 !###################################################################################
1048 !###################################################################################
1049 
1050 end module fv_climate_nudge_nlm_mod
1051 
Definition: fms.F90:20
integer, parameter real8
real(fvprc), dimension(:), allocatable lat_obs
real(fvprc), dimension(:), allocatable lon_obs
subroutine remap_3d(is, ie, js, je, km, npz, pe0, qn0, pe1, qn1, n, ptop)
subroutine, public fv_climate_nudge_init(Time, axes, flag)
subroutine var_state_init(is, ie, js, je, npz, State)
integer, dimension(:,:), allocatable jdc
integer function, public register_static_field(module_name, field_name, axes, long_name, units, missing_value, range, mask_variant, standard_name, DYNAMIC, do_not_log, interp_method, tile_count, area, volume, realm)
subroutine, public fv_climate_nudge(Time, dt, is, ie, js, je, npz, pfull, lon, lat, phis, ptop, ak, bk, ps, u, v, t, q, psdt, udt, vdt, tdt, qdt)
real, parameter, public rdgas
Gas constant for dry air [J/kg/deg].
Definition: constants.F90:77
type(time_type) function, public get_cal_time(time_increment, units, calendar, permit_calendar_conversion)
integer, parameter real4
Definition: mpp.F90:39
integer function, public check_nml_error(IOSTAT, NML_NAME)
Definition: fms.F90:658
subroutine get_factor(nlev, pfull, factor)
subroutine remap_coef(isd, ied, jsd, jed, lon_in, lat_in, is, ie, js, je, lon_out, lat_out, id1, id2, jdc, s2c)
subroutine var_state_assignment(State1, State2)
character(len=input_str_length), dimension(:), allocatable, target, public input_nml_file
Definition: mpp.F90:1378
real(fvprc), dimension(:,:,:), allocatable s2c
integer, dimension(:,:), allocatable id2
real(fvprc), parameter zvir
real(fvprc), dimension(:), allocatable ak_obs
real, parameter, public rvgas
Gas constant for water vapor [J/kg/deg].
Definition: constants.F90:78
subroutine, public fv_climate_nudge_end
real, parameter, public cp_air
Specific heat capacity of dry air at constant pressure [J/kg/deg].
Definition: constants.F90:83
subroutine remap_ps(is, ie, js, je, km, gz_dat, ph_dat, pn_dat, tp_dat, phis, ps)
real(fvprc), dimension(:), allocatable bk_obs
subroutine remap_xy_3d(isd, ied, jsd, jed, km, q_in, is, ie, js, je, id1, id2, jdc, s2c, q_out)
integer, dimension(:,:), allocatable id1
subroutine, public mappm(km, pe1, q1, kn, pe2, q2, i1, i2, iv, kord, ptop)
subroutine, public read_grid(lon, lat, ak, bk)
#define max(a, b)
Definition: mosaic_util.h:33
subroutine, public read_sub_domain_init(ylo, yhi, ydat, js, je)
subroutine, public read_time(times, units, calendar)
subroutine, public error_mesg(routine, message, level)
Definition: fms.F90:529
integer, parameter fvprc
subroutine, public read_climate_nudge_data_init(nlon, nlat, nlev, ntime)
real, parameter, public kappa
RDGAS / CP_AIR [dimensionless].
Definition: constants.F90:82
type(time_type), dimension(:), allocatable timelist
type(var_state_type), dimension(2) state
subroutine, public print_date(Time, str, unit)
real(fp), parameter, public pi
subroutine remap_xy_2d(isd, ied, jsd, jed, q_in, is, ie, js, je, id1, id2, jdc, s2c, q_out)