FV3 Bundle
fv_fill_nlm.F90
Go to the documentation of this file.
1 !***********************************************************************
2 !* GNU General Public License *
3 !* This file is a part of fvGFS. *
4 !* *
5 !* fvGFS is free software; you can redistribute it and/or modify it *
6 !* and are expected to follow the terms of the GNU General Public *
7 !* License as published by the Free Software Foundation; either *
8 !* version 2 of the License, or (at your option) any later version. *
9 !* *
10 !* fvGFS is distributed in the hope that it will be useful, but *
11 !* WITHOUT ANY WARRANTY; without even the implied warranty of *
12 !* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
13 !* General Public License for more details. *
14 !* *
15 !* For the full text of the GNU General Public License, *
16 !* write to: Free Software Foundation, Inc., *
17 !* 675 Mass Ave, Cambridge, MA 02139, USA. *
18 !* or see: http://www.gnu.org/licenses/gpl.html *
19 !***********************************************************************
21 
23  use platform_mod, only: kind_phys => r8_kind
24 
25  implicit none
26  public fillz
27  public fill_gfs
28  public fill2d
29 
30 contains
31 
32  subroutine fillz(im, km, nq, q, dp)
33  integer, intent(in):: im ! No. of longitudes
34  integer, intent(in):: km ! No. of levels
35  integer, intent(in):: nq ! Total number of tracers
36  real , intent(in):: dp(im,km) ! pressure thickness
37  real , intent(inout) :: q(im,km,nq) ! tracer mixing ratio
38 ! !LOCAL VARIABLES:
39  logical:: zfix(im)
40  real :: dm(km)
41  integer i, k, ic, k1
42  real qup, qly, dup, dq, sum0, sum1, fac
43 
44  do ic=1,nq
45 #ifdef DEV_GFS_PHYS
46 ! Bottom up:
47  do k=km,2,-1
48  k1 = k-1
49  do i=1,im
50  if( q(i,k,ic) < 0. ) then
51  q(i,k1,ic) = q(i,k1,ic) + q(i,k,ic)*dp(i,k)/dp(i,k1)
52  q(i,k ,ic) = 0.
53  endif
54  enddo
55  enddo
56 ! Top down:
57  do k=1,km-1
58  k1 = k+1
59  do i=1,im
60  if( q(i,k,ic) < 0. ) then
61  q(i,k1,ic) = q(i,k1,ic) + q(i,k,ic)*dp(i,k)/dp(i,k1)
62  q(i,k ,ic) = 0.
63  endif
64  enddo
65  enddo
66 #else
67 ! Top layer
68  do i=1,im
69  if( q(i,1,ic) < 0. ) then
70  q(i,2,ic) = q(i,2,ic) + q(i,1,ic)*dp(i,1)/dp(i,2)
71  q(i,1,ic) = 0.
72  endif
73  enddo
74 
75 ! Interior
76  zfix(:) = .false.
77  do k=2,km-1
78  do i=1,im
79  if( q(i,k,ic) < 0. ) then
80  zfix(i) = .true.
81  if ( q(i,k-1,ic) > 0. ) then
82 ! Borrow from above
83  dq = min( q(i,k-1,ic)*dp(i,k-1), -q(i,k,ic)*dp(i,k) )
84  q(i,k-1,ic) = q(i,k-1,ic) - dq/dp(i,k-1)
85  q(i,k ,ic) = q(i,k ,ic) + dq/dp(i,k )
86  endif
87  if ( q(i,k,ic)<0.0 .and. q(i,k+1,ic)>0. ) then
88 ! Borrow from below:
89  dq = min( q(i,k+1,ic)*dp(i,k+1), -q(i,k,ic)*dp(i,k) )
90  q(i,k+1,ic) = q(i,k+1,ic) - dq/dp(i,k+1)
91  q(i,k ,ic) = q(i,k ,ic) + dq/dp(i,k )
92  endif
93  endif
94  enddo
95  enddo
96 
97 ! Bottom layer
98  k = km
99  do i=1,im
100  if( q(i,k,ic)<0. .and. q(i,k-1,ic)>0.) then
101  zfix(i) = .true.
102 ! Borrow from above
103  qup = q(i,k-1,ic)*dp(i,k-1)
104  qly = -q(i,k ,ic)*dp(i,k )
105  dup = min(qly, qup)
106  q(i,k-1,ic) = q(i,k-1,ic) - dup/dp(i,k-1)
107  q(i,k, ic) = q(i,k, ic) + dup/dp(i,k )
108  endif
109  enddo
110 
111 ! Perform final check and non-local fix if needed
112  do i=1,im
113  if ( zfix(i) ) then
114 
115  sum0 = 0.
116  do k=2,km
117  dm(k) = q(i,k,ic)*dp(i,k)
118  sum0 = sum0 + dm(k)
119  enddo
120 
121  if ( sum0 > 0. ) then
122  sum1 = 0.
123  do k=2,km
124  sum1 = sum1 + max(0., dm(k))
125  enddo
126  fac = sum0 / sum1
127  do k=2,km
128  q(i,k,ic) = max(0., fac*dm(k)/dp(i,k))
129  enddo
130  endif
131 
132  endif
133  enddo
134 #endif
135 
136  enddo
137  end subroutine fillz
138 
139  subroutine fill_gfs(im, km, pe2, q, q_min)
140 !SJL: this routine is the equivalent of fillz except that the vertical index is upside down
141  integer, intent(in):: im, km
142  real(kind=kind_phys), intent(in):: pe2(im,km+1) ! pressure interface
143  real(kind=kind_phys), intent(in):: q_min
144  real(kind=kind_phys), intent(inout):: q(im,km)
145 ! LOCAL VARIABLES:
146  real(kind=kind_phys) :: dp(im,km)
147  integer:: i, k, k1
148 
149  do k=1,km
150  do i=1,im
151  dp(i,k) = pe2(i,k) - pe2(i,k+1)
152  enddo
153  enddo
154 
155 ! From bottom up:
156  do k=1,km-1
157  k1 = k+1
158  do i=1,im
159  if ( q(i,k)<q_min ) then
160 ! Take mass from above so that q >= q_min
161  q(i,k1) = q(i,k1) + (q(i,k)-q_min)*dp(i,k)/dp(i,k1)
162  q(i,k ) = q_min
163  endif
164  enddo
165  enddo
166 
167 ! From top down:
168  do k=km,2,-1
169  k1 = k-1
170  do i=1,im
171  if ( q(i,k)<0.0 ) then
172 ! Take mass from below
173  q(i,k1) = q(i,k1) + q(i,k)*dp(i,k)/dp(i,k1)
174  q(i,k ) = 0.
175  endif
176  enddo
177  enddo
178 
179  end subroutine fill_gfs
180 
181 
182  subroutine fill2d(is, ie, js, je, ng, km, q, delp, area, domain, nested, npx, npy)
183 ! This is a diffusive type filling algorithm
184  type(domain2d), intent(INOUT) :: domain
185  integer, intent(in):: is, ie, js, je, ng, km, npx, npy
186  logical, intent(IN):: nested
187  real, intent(in):: area(is-ng:ie+ng, js-ng:je+ng)
188  real, intent(in):: delp(is-ng:ie+ng, js-ng:je+ng, km)
189  real, intent(inout):: q(is-ng:ie+ng, js-ng:je+ng, km)
190 ! LOCAL VARIABLES:
191  real, dimension(is-ng:ie+ng, js-ng:je+ng,km):: qt
192  real, dimension(is:ie+1, js:je):: fx
193  real, dimension(is:ie, js:je+1):: fy
194  real, parameter:: dif = 0.25
195  integer:: i, j, k
196  integer :: is1, ie1, js1, je1
197 
198  if (nested) then
199  if (is == 1) then
200  is1 = is-1
201  else
202  is1 = is
203  endif
204  if (ie == npx-1) then
205  ie1 = ie+1
206  else
207  ie1 = ie
208  endif
209  if (js == 1) then
210  js1 = js-1
211  else
212  js1 = js
213  endif
214  if (je == npy-1) then
215  je1 = je+1
216  else
217  je1 = je
218  endif
219  else
220  is1 = is
221  ie1 = ie
222  js1 = js
223  je1 = je
224  endif
225 
226 !$OMP parallel do default(shared)
227  do k=1, km
228  do j=js1,je1
229  do i=is1,ie1
230  qt(i,j,k) = q(i,j,k)*delp(i,j,k)*area(i,j)
231  enddo
232  enddo
233  enddo
234  call mpp_update_domains(qt, domain, whalo=1, ehalo=1, shalo=1, nhalo=1)
235 
236 !$OMP parallel do default(shared) private(fx,fy)
237  do k=1, km
238  fx(:,:) = 0.
239  do j=js,je
240  do i=is,ie+1
241  if( qt(i-1,j,k)*qt(i,j,k)<0. ) fx(i,j) = qt(i-1,j,k) - qt(i,j,k)
242  enddo
243  enddo
244  fy(:,:) = 0.
245  do j=js,je+1
246  do i=is,ie
247  if( qt(i,j-1,k)*qt(i,j,k)<0. ) fy(i,j) = qt(i,j-1,k) - qt(i,j,k)
248  enddo
249  enddo
250  do j=js,je
251  do i=is,ie
252  q(i,j,k) = q(i,j,k)+dif*(fx(i,j)-fx(i+1,j)+fy(i,j)-fy(i,j+1))/(delp(i,j,k)*area(i,j))
253  enddo
254  enddo
255  enddo
256 
257  end subroutine fill2d
258 
259 end module fv_fill_nlm_mod
subroutine, public fillz(im, km, nq, q, dp)
Definition: fv_fill_nlm.F90:33
integer, parameter r8_kind
Definition: platform.F90:24
#define max(a, b)
Definition: mosaic_util.h:33
subroutine, public fill_gfs(im, km, pe2, q, q_min)
#define min(a, b)
Definition: mosaic_util.h:32
subroutine, public fill2d(is, ie, js, je, ng, km, q, delp, area, domain, nested, npx, npy)