FV3DYCORE  Version 2.0.0
fv_update_phys.F90
Go to the documentation of this file.
1 
2 !***********************************************************************
3 !* GNU Lesser General Public License
4 !*
5 !* This file is part of the FV3 dynamical core.
6 !*
7 !* The FV3 dynamical core is free software: you can redistribute it
8 !* and/or modify it under the terms of the
9 !* GNU Lesser General Public License as published by the
10 !* Free Software Foundation, either version 3 of the License, or
11 !* (at your option) any later version.
12 !*
13 !* The FV3 dynamical core is distributed in the hope that it will be
14 !* useful, but WITHOUT ANYWARRANTY; without even the implied warranty
15 !* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
16 !* See the GNU General Public License for more details.
17 !*
18 !* You should have received a copy of the GNU Lesser General Public
19 !* License along with the FV3 dynamical core.
20 !* If not, see <http://www.gnu.org/licenses/>.
21 !***********************************************************************
22 
25 
27 
28 ! Modules Included:
29 ! <table>
30 ! <tr>
31 ! <th>Module Name</th>
32 ! <th>Functions Included</th>
33 ! </tr>
34 ! <tr>
35 ! <td>boundary_mod</td>
36 ! <td>nested_grid_BC, extrapolation_BC</td>
37 ! </tr>
38 ! <tr>
39 ! <td>constants_mod</td>
40 ! <td>kappa, rdgas, rvgas, grav, cp_air, cp_vapor, pi=>pi_8, radius</td>
41 ! </tr>
42 ! <tr>
43 ! <td>field_manager_mod</td>
44 ! <td>MODEL_ATMOS</td>
45 ! </tr>
46 ! <tr>
47 ! <td>fv_arrays_mod</td>
48 ! <td>fv_flags_type, fv_nest_type, R_GRID</td>
49 ! </tr>
50 ! <tr>
51 ! <td>fv_diagnostics_mod</td>
52 ! <td>prt_maxmin</td>
53 ! </tr>
54 ! <tr>
55 ! <td>fv_eta_mod</td>
56 ! <td>get_eta_level</td>
57 ! </tr>
58 ! <tr>
59 ! <td>fv_mapz_mod</td>
60 ! <td>moist_cv, moist_cp</td>
61 ! </tr>
62 ! <tr>
63 ! <td>fv_mp_mod</td>
64 ! <td>start_group_halo_update, complete_group_halo_update,group_halo_update_type</td>
65 ! </tr>
66 ! <tr>
67 ! <td>fv_timing_mod</td>
68 ! <td>timing_on, timing_off</td>
69 ! </tr>
70 ! <tr>
71 ! <td>mpp_mod</td>
72 ! <td>FATAL, mpp_error,NOTE, WARNING</td>
73 ! </tr>
74 ! <tr>
75 ! <td>mpp_domains_mod</td>
76 ! <td>mpp_update_domains, domain2d</td>
77 ! </tr>
78 ! <tr>
79 ! <td>mpp_parameter_mod</td>
80 ! <td>AGRID_PARAM=>AGRID</td>
81 ! </tr>
82 ! <tr>
83 ! <td>time_manager_mod</td>
84 ! <td>time_type</td>
85 ! </tr>
86 ! <tr>
87 ! <td>tracer_manager_mod</td>
88 ! <td>get_tracer_index, adjust_mass, get_tracer_names</td>
89 ! </tr>
90 ! </table>
91 
92  use constants_mod, only: kappa, rdgas, rvgas, grav, cp_air, cp_vapor, pi=>pi_8, radius, tfreeze
93  use field_manager_mod, only: model_atmos
94  use mpp_domains_mod, only: mpp_update_domains, domain2d
95  use mpp_parameter_mod, only: agrid_param=>agrid
96  use mpp_mod, only: fatal, mpp_error
97  use mpp_mod, only: mpp_error, note, warning, mpp_pe
98  use time_manager_mod, only: time_type
99  use tracer_manager_mod, only: get_tracer_index, adjust_mass, get_tracer_names
100  use fv_mp_mod, only: start_group_halo_update, complete_group_halo_update
101  use fv_mp_mod, only: group_halo_update_type
103  use boundary_mod, only: nested_grid_bc
104  use boundary_mod, only: extrapolation_bc
105  use fv_eta_mod, only: get_eta_level
108  use fv_mapz_mod, only: moist_cv, moist_cp
109 #if defined (ATMOS_NUDGE)
110  use atmos_nudge_mod, only: get_atmos_nudge, do_ps
111 #elif defined (CLIMATE_NUDGE)
112  use fv_climate_nudge_mod, only: fv_climate_nudge, do_ps
113 #elif defined (ADA_NUDGE)
114  use fv_ada_nudge_mod, only: fv_ada_nudge
115 #else
116  use fv_nwp_nudge_mod, only: fv_nwp_nudge
117 #endif
121  use sat_vapor_pres_mod, only: tcmin, tcmax
122 #ifdef MULTI_GASES
124 #endif
125 
126  implicit none
127 
128  public :: fv_update_phys, del2_phys
129  real,parameter:: con_cp = cp_air
130 
131  contains
132 
133  subroutine fv_update_phys ( dt, is, ie, js, je, isd, ied, jsd, jed, ng, nq, &
134  u, v, w, delp, pt, q, qdiag, ua, va, ps, pe, peln, pk, pkz, &
135  ak, bk, phis, u_srf, v_srf, ts, delz, hydrostatic, &
136  u_dt, v_dt, t_dt, moist_phys, Time, nudge, &
137  gridstruct, lona, lata, npx, npy, npz, flagstruct, &
138  neststruct, bd, domain, ptop, phys_diag, q_dt)
139  real, intent(in) :: dt, ptop
140  integer, intent(in):: is, ie, js, je, ng
141  integer, intent(in):: isd, ied, jsd, jed
142  integer, intent(in):: nq ! tracers modified by physics
143  ! ncnst is the total number of tracers
144  logical, intent(in):: moist_phys
145  logical, intent(in):: hydrostatic
146  logical, intent(in):: nudge
147 
148  type(time_type), intent(in) :: time
149 
150  real, intent(in), dimension(npz+1):: ak, bk
151  real, intent(in) :: phis(isd:ied,jsd:jed)
152  real, intent(inout):: delz(is:,js:,1:)
153 
154 ! optional arguments for atmospheric nudging
155  real, intent(in), dimension(isd:ied,jsd:jed), optional :: &
156  lona, lata
157 
158 ! Winds on lat-lon grid:
159  real, intent(inout), dimension(isd:ied,jsd:jed,npz):: ua, va
160  real, intent(inout), dimension(isd: ,jsd: ,1: ):: w
161 
162 ! Tendencies from Physics:
163  real, intent(inout), dimension(isd:ied,jsd:jed,npz):: u_dt, v_dt
164  real, intent(inout):: t_dt(is:ie,js:je,npz)
165  real, intent(inout), optional :: q_dt(is:ie,js:je,npz,nq)
166  type(phys_diag_type), intent(inout) :: phys_diag
167 
168 ! Saved Bottom winds for GFDL Physics Interface
169  real, intent(out), dimension(is:ie,js:je):: u_srf, v_srf, ts
170 
171  type(fv_flags_type) :: flagstruct
172  type(fv_grid_bounds_type), intent(IN) :: bd
173  type(domain2d), intent(INOUT) :: domain
174 
175  real, intent(inout):: u(isd:ied ,jsd:jed+1,npz)
176  real, intent(inout):: v(isd:ied+1,jsd:jed ,npz)
177  real, intent(inout), dimension(isd:ied,jsd:jed,npz):: pt, delp
178  real, intent(inout):: q(isd:ied,jsd:jed,npz,nq)
179  real, intent(inout):: qdiag(isd:ied,jsd:jed,npz,nq+1:flagstruct%ncnst)
180 
181 !-----------------------------------------------------------------------
182 ! Auxilliary pressure arrays:
183 ! The 5 vars below can be re-computed from delp and ptop.
184 !-----------------------------------------------------------------------
185 ! dyn_aux:
186  real, intent(inout):: ps (isd:ied ,jsd:jed)
187  real, intent(inout):: pe (is-1:ie+1, npz+1,js-1:je+1)
188  real, intent(inout):: pk (is:ie,js:je , npz+1)
189  real, intent(inout):: peln(is:ie,npz+1,js:je)
190  real, intent(inout):: pkz (is:ie,js:je,npz)
191  real, parameter:: tice = 273.16
192 
193  type(fv_grid_type) :: gridstruct
194  type(fv_nest_type) :: neststruct
195 
196  real :: q_dt_nudge(is:ie,js:je,npz,nq)
197 
198  integer, intent(IN) :: npx, npy, npz
199 
200 !***********
201 ! Haloe Data
202 !***********
203  real, parameter:: q1_h2o = 2.2e-6
204  real, parameter:: q7_h2o = 3.8e-6
205  real, parameter:: q100_h2o = 3.8e-6
206  real, parameter:: q1000_h2o = 3.1e-6
207  real, parameter:: q2000_h2o = 2.8e-6
208  real, parameter:: q3000_h2o = 3.0e-6
209 
210 ! Local arrays:
211  real ps_dt(is:ie,js:je)
212  real cvm(is:ie), qc(is:ie)
213  real phalf(npz+1), pfull(npz)
214 
215 #ifdef MULTI_GASES
216  integer :: nn, nm
217 #endif
218 
219  type(group_halo_update_type), save :: i_pack(2)
220  integer i, j, k, m, n, nwat
221  integer sphum, liq_wat, ice_wat, cld_amt ! GFDL AM physics
222  integer rainwat, snowwat, graupel ! GFDL Cloud Microphysics
223  integer w_diff ! w-tracer for PBL diffusion
224  real:: qstar, dbk, rdg, zvir, p_fac, cv_air, gama_dt, tbad
225  logical :: bad_range
226 
227 !f1p
228 !account for change in air molecular weight because of H2O change
229  logical, dimension(nq) :: conv_vmr_mmr
230  real :: adj_vmr(is:ie,js:je,npz)
231  character(len=32) :: tracer_units, tracer_name
232 
233  cv_air = cp_air - rdgas ! = rdgas * (7/2-1) = 2.5*rdgas=717.68
234 
235  rdg = -rdgas / grav
236 
237  nwat = flagstruct%nwat
238 
239  if ( moist_phys .or. nwat/=0 ) then
240  zvir = rvgas/rdgas - 1.
241  else
242  zvir = 0.
243  endif
244 
245 !f1p
246  conv_vmr_mmr(1:nq) = .false.
247  if (flagstruct%adj_mass_vmr) then
248  do m=1,nq
249  call get_tracer_names (model_atmos, m, name = tracer_name, &
250  units = tracer_units)
251  if ( trim(tracer_units) .eq. 'vmr' ) then
252  conv_vmr_mmr(m) = .true.
253  else
254  conv_vmr_mmr(m) = .false.
255  end if
256  end do
257  end if
258 
259  sphum = get_tracer_index(model_atmos, 'sphum')
260  liq_wat = get_tracer_index(model_atmos, 'liq_wat')
261  ice_wat = get_tracer_index(model_atmos, 'ice_wat')
262  rainwat = get_tracer_index(model_atmos, 'rainwat')
263  snowwat = get_tracer_index(model_atmos, 'snowwat')
264  graupel = get_tracer_index(model_atmos, 'graupel')
265  cld_amt = get_tracer_index(model_atmos, 'cld_amt')
266 
267  if ( .not. hydrostatic ) then
268  w_diff = get_tracer_index(model_atmos, 'w_diff')
269 ! if ( w_diff<8 ) call mpp_error(FATAL,'W_tracer index error')
270  else
271  w_diff = 0
272  endif
273 
274  if ( .not. hydrostatic .and. .not. flagstruct%phys_hydrostatic .and. nwat == 0 ) then
275  gama_dt = dt*cp_air/cv_air
276  else
277  gama_dt = -1.e24
278  endif
279 
280  if ( flagstruct%fv_debug ) then
281  call prt_maxmin('delp_b_update', delp, is, ie, js, je, ng, npz, 0.01)
282  if (present(q_dt)) then
283  do m=1,nq
284  call prt_maxmin('q_dt', q_dt(is,js,1,m), is, ie, js, je, 0, npz, 1.)
285  enddo
286  endif
287  call prt_maxmin('u_dt', u_dt, is, ie, js, je, ng, npz, 1.)
288  call prt_maxmin('v_dt', v_dt, is, ie, js, je, ng, npz, 1.)
289  call prt_maxmin('T_dt', t_dt, is, ie, js, je, 0, npz, 1.)
290  endif
291 
292  call get_eta_level(npz, 1.0e5, pfull, phalf, ak, bk)
293 #ifdef MULTI_GASES
294  nm = max( nwat,num_gas)
295  nn = max(flagstruct%nwat,num_gas)
296 #endif
297 
298  if (size(neststruct%child_grids) > 1) then
299  call set_physics_bcs(ps, u_dt, v_dt, flagstruct, gridstruct, neststruct, npx, npy, npz, ng, ak, bk, bd)
300  endif
301 
302  if (allocated(phys_diag%phys_t_dt)) phys_diag%phys_t_dt = pt(is:ie,js:je,:)
303  if (present(q_dt)) then
304  if (allocated(phys_diag%phys_qv_dt)) phys_diag%phys_qv_dt = q(is:ie,js:je,:,sphum)
305  if (allocated(phys_diag%phys_ql_dt)) then
306  if (liq_wat < 0) call mpp_error(fatal, " phys_ql_dt needs at least one liquid water tracer defined")
307  phys_diag%phys_ql_dt = q(is:ie,js:je,:,liq_wat)
308  if (rainwat > 0) phys_diag%phys_ql_dt = q(is:ie,js:je,:,rainwat) + phys_diag%phys_ql_dt
309  endif
310  if (allocated(phys_diag%phys_qi_dt)) then
311  if (ice_wat < 0) then
312  call mpp_error(warning, " phys_qi_dt needs at least one ice water tracer defined")
313  phys_diag%phys_qi_dt = 0.
314  endif
315  phys_diag%phys_qi_dt = q(is:ie,js:je,:,ice_wat)
316  if (snowwat > 0) phys_diag%phys_qi_dt = q(is:ie,js:je,:,snowwat) + phys_diag%phys_qi_dt
317  if (graupel > 0) phys_diag%phys_qi_dt = q(is:ie,js:je,:,graupel) + phys_diag%phys_qi_dt
318  endif
319  endif
320 
321 !$OMP parallel do default(none) &
322 !$OMP shared(is,ie,js,je,npz,flagstruct,pfull,q_dt,sphum,q,qdiag, &
323 !$OMP nq,w_diff,dt,nwat,liq_wat,rainwat,ice_wat,snowwat, &
324 !$OMP graupel,delp,cld_amt,hydrostatic,pt,t_dt,delz,adj_vmr,&
325 !$OMP gama_dt,cv_air,ua,u_dt,va,v_dt,isd,ied,jsd,jed, &
326 #ifdef MULTI_GASES
327 !$OMP nn, nm, &
328 #endif
329 !$OMP conv_vmr_mmr,pe,ptop,gridstruct,phys_diag) &
330 !$OMP private(cvm, qc, qstar, ps_dt, p_fac,tbad)
331  do k=1, npz
332 
333  if (present(q_dt)) then
334 
335  if (flagstruct%tau_h2o<0.0 .and. pfull(k) < 100.e2 ) then
336 ! Wipe the stratosphere clean:
337 ! This should only be used for initialization from a bad model state
338  p_fac = -flagstruct%tau_h2o*86400.
339  do j=js,je
340  do i=is,ie
341  q_dt(i,j,k,sphum) = q_dt(i,j,k,sphum) + (3.e-6-q(i,j,k,sphum))/p_fac
342  enddo
343  enddo
344  elseif ( flagstruct%tau_h2o>0.0 .and. pfull(k) < 3000. ) then
345 ! Do idealized Ch4 chemistry
346 
347  if ( pfull(k) < 1. ) then
348  qstar = q1_h2o
349  p_fac = 0.2 * flagstruct%tau_h2o*86400.
350  elseif ( pfull(k) < 7. .and. pfull(k) >= 1. ) then
351  qstar = q1_h2o + (q7_h2o-q1_h2o)*log(pfull(k)/1.)/log(7.)
352  p_fac = 0.3 * flagstruct%tau_h2o*86400.
353  elseif ( pfull(k) < 100. .and. pfull(k) >= 7. ) then
354  qstar = q7_h2o + (q100_h2o-q7_h2o)*log(pfull(k)/7.)/log(100./7.)
355  p_fac = 0.4 * flagstruct%tau_h2o*86400.
356  elseif ( pfull(k) < 1000. .and. pfull(k) >= 100. ) then
357  qstar = q100_h2o + (q1000_h2o-q100_h2o)*log(pfull(k)/1.e2)/log(10.)
358  p_fac = 0.5 * flagstruct%tau_h2o*86400.
359  elseif ( pfull(k) < 2000. .and. pfull(k) >= 1000. ) then
360  qstar = q1000_h2o + (q2000_h2o-q1000_h2o)*log(pfull(k)/1.e3)/log(2.)
361  p_fac = 0.75 * flagstruct%tau_h2o*86400.
362  else
363  qstar = q3000_h2o
364  p_fac = flagstruct%tau_h2o*86400.
365  endif
366 
367  do j=js,je
368  do i=is,ie
369  q_dt(i,j,k,sphum) = q_dt(i,j,k,sphum) + (qstar-q(i,j,k,sphum))/p_fac
370  enddo
371  enddo
372  endif
373 
374 !----------------
375 ! Update tracers:
376 !----------------
377  do m=1,nq
378  if( m /= w_diff ) then
379  do j=js,je
380  do i=is,ie
381  q(i,j,k,m) = q(i,j,k,m) + dt*q_dt(i,j,k,m)
382  enddo
383  enddo
384  endif
385  enddo
386 
387 !--------------------------------------------------------
388 ! Adjust total air mass due to changes in water substance
389 !--------------------------------------------------------
390  do j=js,je
391  do i=is,ie
392 #ifdef MULTI_GASES
393  ps_dt(i,j) = 1. + dt*sum(q_dt(i,j,k,1:nm))
394 #else
395  ps_dt(i,j) = 1. + dt*sum(q_dt(i,j,k,1:nwat))
396 #endif
397  delp(i,j,k) = delp(i,j,k) * ps_dt(i,j)
398  if (flagstruct%adj_mass_vmr) then
399 #ifdef MULTI_GASES
400  adj_vmr(i,j,k) = &
401  (ps_dt(i,j) - sum(q(i,j,k,1:nn))) / &
402  (1.d0 - sum(q(i,j,k,1:nn)))
403 #else
404  adj_vmr(i,j,k) = &
405  (ps_dt(i,j) - sum(q(i,j,k,1:flagstruct%nwat))) / &
406  (1.d0 - sum(q(i,j,k,1:flagstruct%nwat)))
407 #endif
408  end if
409  enddo
410  enddo
411 
412 !-----------------------------------------
413 ! Adjust mass mixing ratio of all tracers
414 !-----------------------------------------
415  if ( nwat /=0 ) then
416  do m=1,flagstruct%ncnst
417 !-- check to query field_table to determine if tracer needs mass adjustment
418  if( m /= cld_amt .and. m /= w_diff .and. adjust_mass(model_atmos,m)) then
419  if (m <= nq) then
420  q(is:ie,js:je,k,m) = q(is:ie,js:je,k,m) / ps_dt(is:ie,js:je)
421  if (conv_vmr_mmr(m)) &
422  q(is:ie,js:je,k,m) = q(is:ie,js:je,k,m) * adj_vmr(is:ie,js:je,k)
423  else
424  qdiag(is:ie,js:je,k,m) = qdiag(is:ie,js:je,k,m) / ps_dt(is:ie,js:je)
425  endif
426  endif
427  enddo
428  endif
429 
430  endif ! present(q_dt)
431 
432  if ( hydrostatic ) then
433  do j=js,je
434  call moist_cp(is,ie,isd,ied,jsd,jed, npz, j, k, nwat, sphum, liq_wat, rainwat, &
435  ice_wat, snowwat, graupel, q, qc, cvm, pt(is:ie,j,k) )
436  do i=is,ie
437  pt(i,j,k) = pt(i,j,k) + t_dt(i,j,k)*dt*con_cp/cvm(i)
438  enddo
439  enddo
440  else
441  if ( flagstruct%phys_hydrostatic ) then
442 ! Constant pressure
443  do j=js,je
444  call moist_cp(is,ie,isd,ied,jsd,jed, npz, j, k, nwat, sphum, liq_wat, rainwat, &
445  ice_wat, snowwat, graupel, q, qc, cvm, pt(is:ie,j,k) )
446  do i=is,ie
447  delz(i,j,k) = delz(i,j,k) / pt(i,j,k)
448  pt(i,j,k) = pt(i,j,k) + t_dt(i,j,k)*dt*con_cp/cvm(i)
449  delz(i,j,k) = delz(i,j,k) * pt(i,j,k)
450  enddo
451  enddo
452  else
453  !NOTE: only works for either no physics or GFDL MP
454  if (nwat == 0) then
455  do j=js,je
456  do i=is,ie
457  pt(i,j,k) = pt(i,j,k) + t_dt(i,j,k)*gama_dt
458  enddo
459  enddo
460  else
461  do j=js,je
462  call moist_cv(is,ie,isd,ied,jsd,jed, npz, j, k, nwat, sphum, liq_wat, rainwat, &
463  ice_wat, snowwat, graupel, q, qc, cvm, pt(is:ie,j,k))
464  do i=is,ie
465  pt(i,j,k) = pt(i,j,k) + t_dt(i,j,k)*dt*con_cp/cvm(i)
466  enddo
467  enddo
468  endif
469  endif
470  endif
471 
472 #ifndef GFS_PHYS
473  do j=js,je
474  do i=is,ie
475  ua(i,j,k) = ua(i,j,k) + dt*u_dt(i,j,k)
476  va(i,j,k) = va(i,j,k) + dt*v_dt(i,j,k)
477  enddo
478  enddo
479 #endif
480 
481  enddo ! k-loop
482 
483  if (allocated(phys_diag%phys_t_dt)) phys_diag%phys_t_dt = (pt(is:ie,js:je,:) - phys_diag%phys_t_dt) / dt
484  if (present(q_dt)) then
485  if (allocated(phys_diag%phys_qv_dt)) phys_diag%phys_qv_dt = (q(is:ie,js:je,:,sphum) - phys_diag%phys_qv_dt) / dt
486  if (allocated(phys_diag%phys_ql_dt)) then
487  if (liq_wat < 0) call mpp_error(fatal, " phys_ql_dt needs at least one liquid water tracer defined")
488  phys_diag%phys_ql_dt = q(is:ie,js:je,:,liq_wat) - phys_diag%phys_qv_dt
489  if (rainwat > 0) phys_diag%phys_ql_dt = q(is:ie,js:je,:,rainwat) + phys_diag%phys_ql_dt
490  phys_diag%phys_ql_dt = phys_diag%phys_ql_dt / dt
491  endif
492  if (allocated(phys_diag%phys_qi_dt)) then
493  if (ice_wat < 0) then
494  call mpp_error(warning, " phys_qi_dt needs at least one ice water tracer defined")
495  phys_diag%phys_qi_dt = 0.
496  endif
497  phys_diag%phys_qi_dt = q(is:ie,js:je,:,ice_wat) - phys_diag%phys_qi_dt
498  if (snowwat > 0) phys_diag%phys_qi_dt = q(is:ie,js:je,:,snowwat) + phys_diag%phys_qi_dt
499  if (graupel > 0) phys_diag%phys_qi_dt = q(is:ie,js:je,:,graupel) + phys_diag%phys_qi_dt
500  phys_diag%phys_qi_dt = phys_diag%phys_qi_dt / dt
501  endif
502  endif
503 
504  if ( flagstruct%range_warn ) then
505  call range_check('PT UPDATE', pt, is, ie, js, je, ng, npz, gridstruct%agrid, &
506  tcmin+tfreeze, tcmax+tfreeze, bad_range, time)
507  if (bad_range) then
508  do k=1,npz
509  do j=js,je
510  do i=is,ie
511  if (pt(i,j,k) < tcmin+tfreeze .or. pt(i,j,k) > tcmax+tfreeze) then
512  write(*,*) 'PT UPDATE: ', t_dt(i,j,k)*dt, i,j,k, gridstruct%agrid(i,j,:)
513  endif
514  enddo
515  enddo
516  enddo
517  endif
518  endif
519 
520 ! [delp, (ua, va), pt, q] updated. Perform nudging if requested
521 !------- nudging of atmospheric variables toward specified data --------
522 
523  ps_dt(:,:) = 0.
524 
525  if ( nudge ) then
526 #if defined (ATMOS_NUDGE)
527 !--------------------------------------------
528 ! All fields will be updated; tendencies added
529 !--------------------------------------------
530  call get_atmos_nudge ( time, dt, is, ie, js, je, &
531  npz, ng, ps(is:ie,js:je), ua(is:ie, js:je,:), &
532  va(is:ie,js:je,:), pt(is:ie,js:je,:), &
533  q(is:ie,js:je,:,:), ps_dt(is:ie,js:je), u_dt(is:ie,js:je,:), &
534  v_dt(is:ie,js:je,:), t_dt(is:ie,js:je,:), &
535  q_dt_nudge(is:ie,js:je,:,:) )
536 
537 !--------------
538 ! Update delp
539 !--------------
540  if (do_ps) then
541 !$omp parallel do default(none) shared(is,ie,js,je,npz,bk,delp,ps_dt) private(dbk)
542  do k=1,npz
543  dbk = dt * (bk(k+1) - bk(k))
544  do j=js,je
545  do i=is,ie
546  delp(i,j,k) = delp(i,j,k) + dbk*ps_dt(i,j)
547  enddo
548  enddo
549  enddo
550  endif
551 #elif defined (CLIMATE_NUDGE)
552 !--------------------------------------------
553 ! All fields will be updated; tendencies added
554 !--------------------------------------------
555  call fv_climate_nudge ( time, dt, is, ie, js, je, npz, pfull, &
556  lona(is:ie,js:je), lata(is:ie,js:je), phis(is:ie,js:je), &
557  ptop, ak, bk, &
558  ps(is:ie,js:je), ua(is:ie,js:je,:), va(is:ie,js:je,:), &
559  pt(is:ie,js:je,:), q(is:ie,js:je,:,sphum:sphum), &
560  ps_dt(is:ie,js:je), u_dt(is:ie,js:je,:), &
561  v_dt(is:ie,js:je,:), t_dt(is:ie,js:je,:), &
562  q_dt_nudge(is:ie,js:je,:,sphum:sphum) )
563 
564 !--------------
565 ! Update delp
566 !--------------
567  if (do_ps) then
568 !$omp parallel do default(none) shared(is,ie,js,je,npz,dt,bk,delp,ps_dt) private(dbk)
569  do k=1,npz
570  dbk = dt * (bk(k+1) - bk(k))
571  do j=js,je
572  do i=is,ie
573  delp(i,j,k) = delp(i,j,k) + dbk*ps_dt(i,j)
574  enddo
575  enddo
576  enddo
577  endif
578 #elif defined (ADA_NUDGE)
579 ! All fields will be updated except winds; wind tendencies added
580 !$omp parallel do default(shared)
581  do j=js,je
582  do k=2,npz+1
583  do i=is,ie
584  pe(i,k,j) = pe(i,k-1,j) + delp(i,j,k-1)
585  enddo
586  enddo
587  do i=is,ie
588  ps(i,j) = pe(i,npz+1,j)
589  enddo
590  enddo
591  call fv_ada_nudge ( time, dt, npx, npy, npz, ps_dt, u_dt, v_dt, t_dt, q_dt_nudge, &
592  zvir, ptop, ak, bk, ts, ps, delp, ua, va, pt, &
593  nwat, q, phis, gridstruct, bd, domain )
594 #else
595 ! All fields will be updated except winds; wind tendencies added
596 !$OMP parallel do default(none) shared(is,ie,js,je,npz,pe,delp,ps)
597  do j=js,je
598  do k=2,npz+1
599  do i=is,ie
600  pe(i,k,j) = pe(i,k-1,j) + delp(i,j,k-1)
601  enddo
602  enddo
603  do i=is,ie
604  ps(i,j) = pe(i,npz+1,j)
605  enddo
606  enddo
607  call fv_nwp_nudge ( time, dt, npx, npy, npz, ps_dt, u_dt, v_dt, t_dt, q_dt_nudge, &
608  zvir, ptop, ak, bk, ts, ps, delp, ua, va, pt, &
609  nwat, q, phis, gridstruct, bd, domain )
610 #endif
611 
612  endif ! end nudging
613 
614  if ( .not.flagstruct%dwind_2d ) then
615 
616  call timing_on('COMM_TOTAL')
617  if ( gridstruct%square_domain ) then
618  call start_group_halo_update(i_pack(1), u_dt, domain, whalo=1, ehalo=1, shalo=1, nhalo=1, complete=.false.)
619  call start_group_halo_update(i_pack(1), v_dt, domain, whalo=1, ehalo=1, shalo=1, nhalo=1, complete=.true.)
620  else
621  call start_group_halo_update(i_pack(1), u_dt, domain, complete=.false.)
622  call start_group_halo_update(i_pack(1), v_dt, domain, complete=.true.)
623  endif
624  call timing_off('COMM_TOTAL')
625  endif
626 
627 !----------------------------------------
628 ! Update pe, peln, pkz, and surface winds
629 !----------------------------------------
630  if ( flagstruct%fv_debug ) then
631  call prt_maxmin('PS_b_update', ps, is, ie, js, je, ng, 1, 0.01)
632  call prt_maxmin('delp_a_update', delp, is, ie, js, je, ng, npz, 0.01)
633  endif
634 
635 !$OMP parallel do default(none) shared(is,ie,js,je,npz,pe,delp,peln,pk,ps,u_srf,v_srf, &
636 #ifdef MULTI_GASES
637 !$OMP q, &
638 #endif
639 !$OMP ua,va,pkz,hydrostatic)
640  do j=js,je
641  do k=2,npz+1
642  do i=is,ie
643  pe(i,k,j) = pe(i,k-1,j) + delp(i,j,k-1)
644  peln(i,k,j) = log( pe(i,k,j) )
645  pk(i,j,k) = exp( kappa*peln(i,k,j) )
646  enddo
647  enddo
648 
649  do i=is,ie
650  ps(i,j) = pe(i,npz+1,j)
651  u_srf(i,j) = ua(i,j,npz)
652  v_srf(i,j) = va(i,j,npz)
653  enddo
654 
655  if ( hydrostatic ) then
656  do k=1,npz
657  do i=is,ie
658  pkz(i,j,k) = (pk(i,j,k+1)-pk(i,j,k))/(kappa*(peln(i,k+1,j)-peln(i,k,j)))
659 #ifdef MULTI_GASES
660  pkz(i,j,k) = exp( virqd(q(i,j,k,:))/vicpqd(q(i,j,k,:)) * log( pkz(i,j,k) ) )
661 #endif
662  enddo
663  enddo
664  endif
665  enddo ! j-loop
666 
667  call timing_on(' Update_dwinds')
668  if ( flagstruct%dwind_2d ) then
669  call update2d_dwinds_phys(is, ie, js, je, isd, ied, jsd, jed, dt, u_dt, v_dt, u, v, gridstruct, &
670  npx,npy,npz,domain)
671  else
672 
673  !I have not seen dwind_2d be used for anything; so we will only handle nesting assuming dwind_2d == .false.
674 
675  call timing_on('COMM_TOTAL')
676 
677  call complete_group_halo_update(i_pack(1), domain)
678 
679  call timing_off('COMM_TOTAL')
680 !
681 ! for regional grid need to set values for u_dt and v_dt at the edges.
682 ! Note from Lucas:The physics only operates on the compute domain.
683 ! One snag is that in fv_update_phys.F90 u_dt and v_dt from the physics need to be interpolated to the D-grids,
684 ! which requires BCs for u_dt and v_dt. For the nested grid I can simply get the BCs from the coarse grid, but
685 ! in your case I would recommend just setting the boundary conditions to 0 or to constant values (ie the value
686 ! of the cell closest to the boundary).
687  if (gridstruct%regional) then
688  if (is == 1) then
689  do k=1,npz
690  do j = js,je
691  u_dt(is-1,j,k) = u_dt(is,j,k)
692  v_dt(is-1,j,k) = v_dt(is,j,k)
693  enddo
694  enddo
695  endif
696  if (ie == npx) then
697  do k=1,npz
698  do j = js,je
699  u_dt(ie+1,j,k) = u_dt(ie,j,k)
700  v_dt(ie+1,j,k) = v_dt(ie,j,k)
701  enddo
702  enddo
703  endif
704  if (js == 1) then
705  do k=1,npz
706  do i = is,ie
707  u_dt(i,js-1,k) = u_dt(i,js,k)
708  v_dt(i,js-1,k) = v_dt(i,js,k)
709  enddo
710  enddo
711  endif
712  if (je == npy) then
713  do k=1,npz
714  do i = is,ie
715  u_dt(i,je+1,k) = u_dt(i,je,k)
716  v_dt(i,je+1,k) = v_dt(i,je,k)
717  enddo
718  enddo
719  endif
720 !
721 ! corners
722 !
723  do k=1,npz
724  if (is == 1 .and. js == 1) then
725  u_dt(is-1,js-1,k) = u_dt(is,js,k)
726  v_dt(is-1,js-1,k) = v_dt(is,js,k)
727  elseif (is == 1 .and. je == npy) then
728  u_dt(is-1,je+1,k) = u_dt(is,je,k)
729  v_dt(is-1,je+1,k) = v_dt(is,je,k)
730  elseif (ie == npx .and. js == 1) then
731  u_dt(ie+1,js-1,k) = u_dt(ie,je,k)
732  v_dt(ie+1,js-1,k) = v_dt(ie,je,k)
733  elseif (ie == npx .and. je == npy) then
734  u_dt(ie+1,je+1,k) = u_dt(ie,je,k)
735  v_dt(ie+1,je+1,k) = v_dt(ie,je,k)
736  endif
737  enddo
738  endif !regional
739 !
740  call update_dwinds_phys(is, ie, js, je, isd, ied, jsd, jed, dt, u_dt, v_dt, u, v, gridstruct, npx, npy, npz, domain)
741  endif
742  call timing_off(' Update_dwinds')
743 #ifdef GFS_PHYS
744  call cubed_to_latlon(u, v, ua, va, gridstruct, &
745  npx, npy, npz, 1, gridstruct%grid_type, domain, gridstruct%bounded_domain, flagstruct%c2l_ord, bd)
746 #endif
747 
748  if ( flagstruct%fv_debug ) then
749  call prt_maxmin('PS_a_update', ps, is, ie, js, je, ng, 1, 0.01)
750  endif
751 
752  if (allocated(phys_diag%phys_u_dt)) then
753  do k=1,npz
754  do j=js,je
755  do i=is,ie
756  phys_diag%phys_u_dt(i,j,k) = u_dt(i,j,k)
757  enddo
758  enddo
759  enddo
760  endif
761  if (allocated(phys_diag%phys_v_dt)) then
762  do k=1,npz
763  do j=js,je
764  do i=is,ie
765  phys_diag%phys_v_dt(i,j,k) = v_dt(i,j,k)
766  enddo
767  enddo
768  enddo
769  endif
770 
771  end subroutine fv_update_phys
772 
774  subroutine del2_phys(qdt, delp, gridstruct, cd, npx, npy, km, is, ie, js, je, &
775  isd, ied, jsd, jed, ngc, domain)
776 ! This routine is for filtering the physics tendency
777  integer, intent(in):: npx, npy, km
778  integer, intent(in):: is, ie, js, je, isd, ied, jsd, jed, ngc
779  real, intent(in):: cd
780  real, intent(in ):: delp(isd:ied,jsd:jed,km)
781  real, intent(inout):: qdt(is-ngc:ie+ngc,js-ngc:je+ngc,km)
782  type(fv_grid_type), intent(IN), target :: gridstruct
783  type(domain2d), intent(INOUT) :: domain
784 
785  real, pointer, dimension(:,:) :: rarea, dx, dy, sina_u, sina_v, rdxc, rdyc
786  real, pointer, dimension(:,:,:) :: sin_sg
787 !
788  real :: q(isd:ied,jsd:jed,km)
789  real :: fx(is:ie+1,js:je), fy(is:ie,js:je+1)
790  real :: mask(is:ie+1,js:je+1)
791  real :: f1(is:ie+1), f2(js:je+1)
792  real :: damp
793  integer i,j,k
794 
795  rarea => gridstruct%rarea
796  dx => gridstruct%dx
797  dy => gridstruct%dy
798  sina_u => gridstruct%sina_u
799  sina_v => gridstruct%sina_v
800  rdxc => gridstruct%rdxc
801  rdyc => gridstruct%rdyc
802  sin_sg => gridstruct%sin_sg
803 
804 ! Applying mask to cd, the damping coefficient?
805  damp = 0.25 * cd * gridstruct%da_min
806 
807 ! Mask defined at corners
808 
809 !$OMP parallel do default(none) shared(is,ie,f1,npx)
810  do i=is,ie+1
811  f1(i) = (1. - sin(real(i-1)/real(npx-1)*pi))**2
812  enddo
813 
814 !$OMP parallel do default(none) shared(is,ie,js,je,f1,f2,npy,mask,damp)
815  do j=js,je+1
816  f2(j) = (1. - sin(real(j-1)/real(npy-1)*pi))**2
817  do i=is,ie+1
818  mask(i,j) = damp * (f1(i) + f2(j))
819  enddo
820  enddo
821 
822 ! mass weighted tendency from physics is filtered
823 
824 !$OMP parallel do default(none) shared(is,ie,js,je,km,q,qdt,delp)
825  do k=1,km
826  do j=js,je
827  do i=is,ie
828  q(i,j,k) = qdt(i,j,k)*delp(i,j,k)
829  enddo
830  enddo
831  enddo
832  call timing_on('COMM_TOTAL')
833  call mpp_update_domains(q, domain, complete=.true.)
834  call timing_off('COMM_TOTAL')
835 
836 !$OMP parallel do default(none) shared(is,ie,js,je,km,mask,dy,sina_u,q,rdxc,gridstruct, &
837 !$OMP sin_sg,npx,dx,npy,rdyc,sina_v,qdt,rarea,delp) &
838 !$OMP private(fx, fy)
839  do k=1,km
840  do j=js,je
841  do i=is,ie+1
842  fx(i,j) = &
843  (mask(i,j)+mask(i,j+1))*dy(i,j)*sina_u(i,j)* &
844  (q(i-1,j,k)-q(i,j,k))*rdxc(i,j)
845  enddo
846  if (is == 1 .and. .not. gridstruct%bounded_domain) fx(i,j) = &
847  (mask(is,j)+mask(is,j+1))*dy(is,j)*(q(is-1,j,k)-q(is,j,k))*rdxc(is,j)* &
848  0.5*(sin_sg(1,j,1) + sin_sg(0,j,3))
849  if (ie+1==npx .and. .not. gridstruct%bounded_domain) fx(i,j) = &
850  (mask(ie+1,j)+mask(ie+1,j+1))*dy(ie+1,j)*(q(ie,j,k)-q(ie+1,j,k))*rdxc(ie+1,j)* &
851  0.5*(sin_sg(npx,j,1) + sin_sg(npx-1,j,3))
852  enddo
853  do j=js,je+1
854  if ((j == 1 .OR. j == npy) .and. .not. gridstruct%bounded_domain) then
855  do i=is,ie
856  fy(i,j) = (mask(i,j)+mask(i+1,j))*dx(i,j)*&
857  (q(i,j-1,k)-q(i,j,k))*rdyc(i,j) &
858  *0.5*(sin_sg(i,j,2) + sin_sg(i,j-1,4) )
859  enddo
860  else
861  do i=is,ie
862  fy(i,j) = (mask(i,j)+mask(i+1,j))*dx(i,j)*sina_v(i,j)*&
863  (q(i,j-1,k)-q(i,j,k))*rdyc(i,j)
864  enddo
865  end if
866  enddo
867  do j=js,je
868  do i=is,ie
869  qdt(i,j,k) = qdt(i,j,k) + rarea(i,j)*(fx(i,j)-fx(i+1,j)+fy(i,j)-fy(i,j+1))/delp(i,j,k)
870  enddo
871  enddo
872  enddo
873 
874  end subroutine del2_phys
875 
876 end module fv_update_phys_mod
pure real function, public vicpqd(q)
The module &#39;fv_mp_mod&#39; is a single program multiple data (SPMD) parallel decompostion/communication m...
Definition: fv_mp_mod.F90:24
subroutine timing_off(blk_name)
The subroutine &#39;timing_off&#39; stops a timer.
Definition: fv_timing.F90:180
The type &#39;fv_grid_type&#39; is made up of grid-dependent information from fv_grid_tools and fv_grid_utils...
Definition: fv_arrays.F90:123
subroutine, public moist_cv(is, ie, isd, ied, jsd, jed, km, j, k, nwat, sphum, liq_wat, rainwat, ice_wat, snowwat, graupel, q, qd, cvm, t1)
The subroutine &#39;moist_cv&#39; computes the FV3-consistent moist heat capacity under constant volume...
Definition: fv_mapz.F90:3418
integer, public num_gas
Definition: multi_gases.F90:46
real, parameter con_cp
The module &#39;multi_gases&#39; peforms multi constitutents computations.
Definition: multi_gases.F90:25
subroutine, public get_eta_level(npz, p_s, pf, ph, ak, bk, pscale)
The subroutine &#39;get_eta_level&#39; returns the interface and layer-mean pressures for reference...
Definition: fv_eta.F90:1833
The module &#39;fv_update_phys&#39; applies physics tendencies consistent with the FV3 discretization and def...
integer, parameter, public r_grid
Definition: fv_arrays.F90:34
pure real function, public virqd(q)
The module fv_nwp_nudge contains routines for nudging to input analyses. note This module is currentl...
Definition: fv_nudge.F90:32
The module &#39;fv_timing&#39; contains FV3 timers.
Definition: fv_timing.F90:24
pure real function, public virq(q)
The module &#39;boundary&#39; contains utility routines for grid nesting and boundary conditions.
Definition: boundary.F90:25
subroutine, public fv_nwp_nudge(Time, dt, npx, npy, npz, ps_dt, u_dt, v_dt, t_dt, q_dt, zvir, ptop, ak, bk, ts, ps, delp, ua, va, pt, nwat, q, phis, gridstruct, bd, domain)
Ths subroutine &#39;fv_nwp_nudge&#39; computes and returns time tendencies for nudging to analysis...
Definition: fv_nudge.F90:306
The module &#39;fv_mapz&#39; contains the vertical mapping routines .
Definition: fv_mapz.F90:27
subroutine, public cubed_to_latlon(u, v, ua, va, gridstruct, npx, npy, km, mode, grid_type, domain, bounded_domain, c2l_ord, bd)
The module &#39;fv_arrays&#39; contains the &#39;fv_atmos_type&#39; and associated datatypes.
Definition: fv_arrays.F90:24
interface &#39;nested_grid_BC&#39; includes subroutines &#39;nested_grid_BC_2d&#39; and &#39;nested_grid_BC_3d&#39; that fetc...
Definition: boundary.F90:89
subroutine, public del2_phys(qdt, delp, gridstruct, cd, npx, npy, km, is, ie, js, je, isd, ied, jsd, jed, ngc, domain)
The subroutine &#39;del2_phys&#39; is for filtering the physics tendency.
The module &#39;fv_eta&#39; contains routine to set up the reference (Eulerian) pressure coordinate.
Definition: fv_eta.F90:25
subroutine, public moist_cp(is, ie, isd, ied, jsd, jed, km, j, k, nwat, sphum, liq_wat, rainwat, ice_wat, snowwat, graupel, q, qd, cpm, t1)
The subroutine &#39;moist_cp&#39; computes the FV3-consistent moist heat capacity under constant pressure...
Definition: fv_mapz.F90:3539
subroutine, public update_dwinds_phys(is, ie, js, je, isd, ied, jsd, jed, dt, u_dt, v_dt, u, v, gridstruct, npx, npy, npz, domain)
The subroutine &#39;update_dwinds_phys&#39; transforms the wind tendencies from the A grid to the D grid for ...
subroutine, public set_physics_bcs(ps, u_dt, v_dt, flagstruct, gridstruct, neststruct, npx, npy, npz, ng, ak, bk, bd)
Definition: fv_nesting.F90:687
subroutine timing_on(blk_name)
The subroutine &#39;timing_on&#39; starts a timer.
Definition: fv_timing.F90:116
@ The module &#39;fv_diagnostics&#39; contains routines to compute diagnosic fields.
The module &#39;fv_grid_utils&#39; contains routines for setting up and computing grid-related quantities...
subroutine, public prt_maxmin(qname, q, is, ie, js, je, n_g, km, fac)
subroutine, public fv_update_phys(dt, is, ie, js, je, isd, ied, jsd, jed, ng, nq, u, v, w, delp, pt, q, qdiag, ua, va, ps, pe, peln, pk, pkz, ak, bk, phis, u_srf, v_srf, ts, delz, hydrostatic, u_dt, v_dt, t_dt, moist_phys, Time, nudge, gridstruct, lona, lata, npx, npy, npz, flagstruct, neststruct, bd, domain, ptop, phys_diag, q_dt)
pure real function, public vicvqd(q)
subroutine, public extrapolation_bc(q, istag, jstag, npx, npy, bd, pd_in, debug_in)
The subroutine &#39;extrapolation_BC&#39; performs linear extrapolation into the halo region.
Definition: boundary.F90:133
subroutine, public update2d_dwinds_phys(is, ie, js, je, isd, ied, jsd, jed, dt, u_dt, v_dt, u, v, gridstruct, npx, npy, npz, domain)
The subroutine &#39;update2d_dwinds_phys&#39; transforms the wind tendencies.
The module &#39;fv_nesting&#39; is a collection of routines pertaining to grid nesting .
Definition: fv_nesting.F90:27