1 |
! $Header: $ |
2 |
! $Name: $ |
3 |
|
4 |
! ============================================================================ |
5 |
module surface_flux_mod |
6 |
! ============================================================================ |
7 |
|
8 |
! use fms_mod, only: FATAL, close_file, mpp_pe, mpp_root_pe, & |
9 |
! write_version_number |
10 |
! use fms_mod, only: file_exist, check_nml_error, open_namelist_file, stdlog |
11 |
|
12 |
use monin_obukhov_mod, only: mo_drag, mo_profile |
13 |
use simple_sat_vapor_pres_mod, only: escomp, descomp |
14 |
use gcm_params_mod, only: gcm_LEN_MBUF, gcm_SQZ_R, gcm_stdMsgUnit |
15 |
use constants_mod, only: cp_air, hlv, stefan, rdgas, rvgas, grav |
16 |
|
17 |
implicit none |
18 |
private |
19 |
|
20 |
! ==== public interface ====================================================== |
21 |
public surface_flux |
22 |
! ==== end of public interface =============================================== |
23 |
|
24 |
|
25 |
interface surface_flux |
26 |
! module procedure surface_flux_0d |
27 |
! module procedure surface_flux_1d |
28 |
module procedure surface_flux_2d |
29 |
end interface |
30 |
|
31 |
!----------------------------------------------------------------------- |
32 |
|
33 |
character(len=*), parameter :: version = '$Id: surface_flux_mod.F90,v 1.1 2012/09/11 03:53:05 jmc Exp $' |
34 |
character(len=*), parameter :: tagname = '$Name: $' |
35 |
|
36 |
logical :: do_init = .true. |
37 |
|
38 |
real, parameter :: d622 = rdgas/rvgas |
39 |
real, parameter :: d378 = 1.-d622 |
40 |
real, parameter :: hlars = hlv/rvgas |
41 |
real, parameter :: gcp = grav/cp_air |
42 |
real, parameter :: kappa = rdgas/cp_air |
43 |
real :: d608 = d378/d622 |
44 |
! d608 set to zero at initialization if the use of |
45 |
! virtual temperatures is turned off in namelist |
46 |
|
47 |
|
48 |
! ---- namelist with default values ------------------------------------------ |
49 |
logical :: no_neg_q = .false. ! for backwards compatibility |
50 |
logical :: use_virtual_temp = .true. |
51 |
logical :: alt_gustiness = .false. |
52 |
logical :: use_mixing_ratio = .false. |
53 |
real :: gust_const = 1.0 |
54 |
|
55 |
namelist /surface_flux_nml/ no_neg_q, & |
56 |
use_virtual_temp, & |
57 |
alt_gustiness, & |
58 |
gust_const, & |
59 |
use_mixing_ratio |
60 |
|
61 |
|
62 |
|
63 |
contains |
64 |
|
65 |
|
66 |
! ============================================================================ |
67 |
subroutine surface_flux_1d ( & |
68 |
t_atm, q_atm_in, u_atm, v_atm, p_atm, z_atm, & |
69 |
p_surf, t_surf, t_ca, q_surf, & |
70 |
u_surf, v_surf, & |
71 |
rough_mom, rough_heat, rough_moist, gust, & |
72 |
flux_t, flux_q, flux_r, flux_u, flux_v, & |
73 |
cd_m, cd_t, cd_q, & |
74 |
w_atm, u_star, b_star, q_star, & |
75 |
dhdt_surf, dedt_surf, dedq_surf, drdt_surf, & |
76 |
dhdt_atm, dedq_atm, dtaudv_atm, & |
77 |
! + slm Mar 28 2002 -- it is not necessary here since it is just cd_q*wind |
78 |
! drag_q, & |
79 |
! - slm Mar 28 2002 |
80 |
dt, land, avail, myThid ) |
81 |
! ============================================================================ |
82 |
! ---- arguments ----------------------------------------------------------- |
83 |
logical, intent(in), dimension(:) :: land, avail |
84 |
real, intent(in), dimension(:) :: & |
85 |
t_atm, q_atm_in, u_atm, v_atm, & |
86 |
p_atm, z_atm, t_ca, & |
87 |
p_surf, t_surf, u_surf, v_surf, & |
88 |
rough_mom, rough_heat, rough_moist, gust |
89 |
real, intent(out), dimension(:) :: & |
90 |
flux_t, flux_q, flux_r, flux_u, flux_v, & |
91 |
dhdt_surf, dedt_surf, dedq_surf, drdt_surf, & |
92 |
dhdt_atm, dedq_atm, dtaudv_atm, & |
93 |
w_atm, u_star, b_star, q_star, & |
94 |
cd_m, cd_t, cd_q |
95 |
real, intent(inout), dimension(:) :: q_surf |
96 |
real, intent(in) :: dt |
97 |
integer, intent(in) :: myThid |
98 |
|
99 |
! ---- local constants ----------------------------------------------------- |
100 |
! temperature increment and its reciprocal value for comp. of derivatives |
101 |
real, parameter:: del_temp=0.1, del_temp_inv=1.0/del_temp |
102 |
|
103 |
! ---- local vars ---------------------------------------------------------- |
104 |
real, dimension(size(t_atm)) :: & |
105 |
thv_atm, th_atm, tv_atm, thv_surf, & |
106 |
e_sat, e_sat1, q_sat, q_sat1, p_ratio, & |
107 |
t_surf0, t_surf1, u_dif, v_dif, & |
108 |
rho_drag, drag_t, drag_m, drag_q, rho, & |
109 |
q_atm, q_surf0 |
110 |
|
111 |
integer :: i, nbad |
112 |
|
113 |
|
114 |
if (do_init) call surface_flux_init(myThid) |
115 |
|
116 |
!---- use local value of surf temp ---- |
117 |
|
118 |
t_surf0 = 200. ! avoids out-of-bounds in es lookup |
119 |
where (avail) |
120 |
where (land) |
121 |
t_surf0 = t_ca |
122 |
elsewhere |
123 |
t_surf0 = t_surf |
124 |
endwhere |
125 |
endwhere |
126 |
|
127 |
t_surf1 = t_surf0 + del_temp |
128 |
|
129 |
call escomp ( t_surf0, e_sat ) ! saturation vapor pressure |
130 |
call escomp ( t_surf1, e_sat1 ) ! perturbed vapor pressure |
131 |
|
132 |
if(use_mixing_ratio) then |
133 |
! surface mixing ratio at saturation |
134 |
q_sat = d622*e_sat /(p_surf-e_sat ) |
135 |
q_sat1 = d622*e_sat1/(p_surf-e_sat1) |
136 |
else |
137 |
! surface specific humidity at saturation |
138 |
q_sat = d622*e_sat /(p_surf-d378*e_sat ) |
139 |
q_sat1 = d622*e_sat1/(p_surf-d378*e_sat1) |
140 |
endif |
141 |
|
142 |
! initilaize surface air humidity according to surface type |
143 |
where (land) |
144 |
q_surf0 = q_surf ! land calculates it |
145 |
elsewhere |
146 |
q_surf0 = q_sat ! everything else assumes saturated sfc humidity |
147 |
endwhere |
148 |
|
149 |
! check for negative atmospheric humidities |
150 |
where(avail) q_atm = q_atm_in |
151 |
if(no_neg_q) then |
152 |
where(avail .and. q_atm_in < 0.0) q_atm = 0.0 |
153 |
endif |
154 |
|
155 |
! generate information needed by monin_obukhov |
156 |
where (avail) |
157 |
p_ratio = (p_surf/p_atm)**kappa |
158 |
|
159 |
tv_atm = t_atm * (1.0 + d608*q_atm) ! virtual temperature |
160 |
th_atm = t_atm * p_ratio ! potential T, using p_surf as refernce |
161 |
thv_atm = tv_atm * p_ratio ! virt. potential T, using p_surf as reference |
162 |
thv_surf= t_surf0 * (1.0 + d608*q_surf0 ) ! surface virtual (potential) T |
163 |
! thv_surf= t_surf0 ! surface virtual (potential) T -- just for testing tun off the q_surf |
164 |
|
165 |
u_dif = u_surf - u_atm ! velocity components relative to surface |
166 |
v_dif = v_surf - v_atm |
167 |
endwhere |
168 |
|
169 |
if(alt_gustiness) then |
170 |
where(avail) & |
171 |
w_atm = max(sqrt(u_dif*u_dif + v_dif*v_dif), gust_const) |
172 |
else |
173 |
where(avail) & |
174 |
w_atm = sqrt(u_dif*u_dif + v_dif*v_dif + gust*gust) |
175 |
endif |
176 |
|
177 |
! monin-obukhov similarity theory |
178 |
call mo_drag (thv_atm, thv_surf, z_atm, & |
179 |
rough_mom, rough_heat, rough_moist, w_atm, & |
180 |
cd_m, cd_t, cd_q, u_star, b_star, myThid, avail ) |
181 |
|
182 |
|
183 |
where (avail) |
184 |
! surface layer drag coefficients |
185 |
drag_t = cd_t * w_atm |
186 |
drag_q = cd_q * w_atm |
187 |
drag_m = cd_m * w_atm |
188 |
|
189 |
! density |
190 |
rho = p_atm / (rdgas * tv_atm) |
191 |
|
192 |
! sensible heat flux |
193 |
rho_drag = cp_air * drag_t * rho |
194 |
flux_t = rho_drag * (t_surf0 - th_atm) ! flux of sensible heat (W/m**2) |
195 |
dhdt_surf = rho_drag ! d(sensible heat flux)/d(surface temperature) |
196 |
dhdt_atm = -rho_drag*p_ratio ! d(sensible heat flux)/d(atmos temperature) |
197 |
|
198 |
! evaporation |
199 |
rho_drag = drag_q * rho |
200 |
flux_q = rho_drag * (q_surf0 - q_atm) ! flux of water vapor (Kg/(m**2 s)) |
201 |
where (land) |
202 |
dedq_surf = rho_drag |
203 |
dedt_surf = 0 |
204 |
elsewhere |
205 |
dedq_surf = 0 |
206 |
dedt_surf = rho_drag * (q_sat1 - q_sat) *del_temp_inv |
207 |
endwhere |
208 |
|
209 |
dedq_atm = -rho_drag ! d(latent heat flux)/d(atmospheric mixing ratio) |
210 |
|
211 |
q_star = flux_q / (u_star * rho) ! moisture scale |
212 |
! ask Chris and Steve K if we still want to keep this for diagnostics |
213 |
q_surf = q_atm + flux_q / (rho*cd_q*w_atm) ! surface specific humidity |
214 |
|
215 |
! upward long wave radiation |
216 |
flux_r = stefan*t_surf**4 ! (W/m**2) |
217 |
drdt_surf = 4*stefan*t_surf**3 ! d(upward longwave)/d(surface temperature) |
218 |
|
219 |
! stresses |
220 |
rho_drag = drag_m * rho |
221 |
flux_u = rho_drag * u_dif ! zonal component of stress (Nt/m**2) |
222 |
flux_v = rho_drag * v_dif ! meridional component of stress |
223 |
dtaudv_atm = -rho_drag ! d(stress component)/d(atmos wind) |
224 |
|
225 |
elsewhere |
226 |
! zero-out un-available data in output only fields |
227 |
flux_t = 0.0 |
228 |
flux_q = 0.0 |
229 |
flux_r = 0.0 |
230 |
flux_u = 0.0 |
231 |
flux_v = 0.0 |
232 |
dhdt_surf = 0.0 |
233 |
dedt_surf = 0.0 |
234 |
dedq_surf = 0.0 |
235 |
drdt_surf = 0.0 |
236 |
dhdt_atm = 0.0 |
237 |
dedq_atm = 0.0 |
238 |
dtaudv_atm = 0.0 |
239 |
u_star = 0.0 |
240 |
b_star = 0.0 |
241 |
q_star = 0.0 |
242 |
q_surf = 0.0 |
243 |
w_atm = 0.0 |
244 |
endwhere |
245 |
|
246 |
end subroutine surface_flux_1d |
247 |
|
248 |
!####################################################################### |
249 |
|
250 |
subroutine surface_flux_0d ( & |
251 |
t_atm_0, q_atm_0, u_atm_0, v_atm_0, p_atm_0, z_atm_0, & |
252 |
p_surf_0, t_surf_0, t_ca_0, q_surf_0, & |
253 |
u_surf_0, v_surf_0, & |
254 |
rough_mom_0, rough_heat_0, rough_moist_0, gust_0, & |
255 |
flux_t_0, flux_q_0, flux_r_0, flux_u_0, flux_v_0, & |
256 |
cd_m_0, cd_t_0, cd_q_0, & |
257 |
w_atm_0, u_star_0, b_star_0, q_star_0, & |
258 |
dhdt_surf_0, dedt_surf_0, dedq_surf_0, drdt_surf_0, & |
259 |
dhdt_atm_0, dedq_atm_0, dtaudv_atm_0, & |
260 |
dt, land_0, avail_0, myThid ) |
261 |
|
262 |
! ---- arguments ----------------------------------------------------------- |
263 |
logical, intent(in) :: land_0, avail_0 |
264 |
real, intent(in) :: & |
265 |
t_atm_0, q_atm_0, u_atm_0, v_atm_0, & |
266 |
p_atm_0, z_atm_0, t_ca_0, & |
267 |
p_surf_0, t_surf_0, u_surf_0, v_surf_0, & |
268 |
rough_mom_0, rough_heat_0, rough_moist_0, gust_0 |
269 |
real, intent(out) :: & |
270 |
flux_t_0, flux_q_0, flux_r_0, flux_u_0, flux_v_0, & |
271 |
dhdt_surf_0, dedt_surf_0, dedq_surf_0, drdt_surf_0, & |
272 |
dhdt_atm_0, dedq_atm_0, dtaudv_atm_0, & |
273 |
w_atm_0, u_star_0, b_star_0, q_star_0, & |
274 |
cd_m_0, cd_t_0, cd_q_0 |
275 |
real, intent(inout) :: q_surf_0 |
276 |
real, intent(in) :: dt |
277 |
integer, intent(in) :: myThid |
278 |
|
279 |
! ---- local vars ---------------------------------------------------------- |
280 |
logical, dimension(1) :: land, avail |
281 |
real, dimension(1) :: & |
282 |
t_atm, q_atm, u_atm, v_atm, & |
283 |
p_atm, z_atm, t_ca, & |
284 |
p_surf, t_surf, u_surf, v_surf, & |
285 |
rough_mom, rough_heat, rough_moist, gust |
286 |
real, dimension(1) :: & |
287 |
flux_t, flux_q, flux_r, flux_u, flux_v, & |
288 |
dhdt_surf, dedt_surf, dedq_surf, drdt_surf, & |
289 |
dhdt_atm, dedq_atm, dtaudv_atm, & |
290 |
w_atm, u_star, b_star, q_star, & |
291 |
cd_m, cd_t, cd_q |
292 |
real, dimension(1) :: q_surf |
293 |
|
294 |
|
295 |
avail = .true. |
296 |
|
297 |
t_atm(1) = t_atm_0 |
298 |
q_atm(1) = q_atm_0 |
299 |
u_atm(1) = u_atm_0 |
300 |
v_atm(1) = v_atm_0 |
301 |
p_atm(1) = p_atm_0 |
302 |
z_atm(1) = z_atm_0 |
303 |
p_surf(1) = p_surf_0 |
304 |
t_surf(1) = t_surf_0 |
305 |
u_surf(1) = u_surf_0 |
306 |
v_surf(1) = v_surf_0 |
307 |
rough_mom(1) = rough_mom_0 |
308 |
rough_heat(1) = rough_heat_0 |
309 |
rough_moist(1) = rough_moist_0 |
310 |
gust(1) = gust_0 |
311 |
|
312 |
call surface_flux_1d ( & |
313 |
t_atm, q_atm, u_atm, v_atm, p_atm, z_atm, & |
314 |
p_surf, t_surf, t_ca, q_surf, & |
315 |
u_surf, v_surf, & |
316 |
rough_mom, rough_heat, rough_moist, gust, & |
317 |
flux_t, flux_q, flux_r, flux_u, flux_v, & |
318 |
cd_m, cd_t, cd_q, & |
319 |
w_atm, u_star, b_star, q_star, & |
320 |
dhdt_surf, dedt_surf, dedq_surf, drdt_surf, & |
321 |
dhdt_atm, dedq_atm, dtaudv_atm, & |
322 |
dt, land, avail, myThid ) |
323 |
|
324 |
flux_t_0 = flux_t(1) |
325 |
flux_q_0 = flux_q(1) |
326 |
flux_r_0 = flux_r(1) |
327 |
flux_u_0 = flux_u(1) |
328 |
flux_v_0 = flux_v(1) |
329 |
dhdt_surf_0 = dhdt_surf(1) |
330 |
dedt_surf_0 = dedt_surf(1) |
331 |
drdt_surf_0 = drdt_surf(1) |
332 |
dedq_surf_0 = dedq_surf(1) |
333 |
dhdt_atm_0 = dhdt_atm(1) |
334 |
dedq_atm_0 = dedq_atm(1) |
335 |
dtaudv_atm_0 = dtaudv_atm(1) |
336 |
w_atm_0 = w_atm(1) |
337 |
u_star_0 = u_star(1) |
338 |
b_star_0 = b_star(1) |
339 |
q_star_0 = q_star(1) |
340 |
q_surf_0 = q_surf(1) |
341 |
cd_m_0 = cd_m(1) |
342 |
cd_t_0 = cd_t(1) |
343 |
cd_q_0 = cd_q(1) |
344 |
|
345 |
end subroutine surface_flux_0d |
346 |
|
347 |
subroutine surface_flux_2d ( & |
348 |
t_atm, q_atm_in, u_atm, v_atm, p_atm, z_atm, & |
349 |
p_surf, t_surf, t_ca, q_surf, & |
350 |
u_surf, v_surf, & |
351 |
rough_mom, rough_heat, rough_moist, gust, & |
352 |
flux_t, flux_q, flux_r, flux_u, flux_v, & |
353 |
cd_m, cd_t, cd_q, & |
354 |
w_atm, u_star, b_star, q_star, & |
355 |
dhdt_surf, dedt_surf, dedq_surf, drdt_surf, & |
356 |
dhdt_atm, dedq_atm, dtaudv_atm, & |
357 |
dt, land, avail, myThid ) |
358 |
|
359 |
! ---- arguments ----------------------------------------------------------- |
360 |
logical, intent(in), dimension(:,:) :: land, avail |
361 |
real, intent(in), dimension(:,:) :: & |
362 |
t_atm, q_atm_in, u_atm, v_atm, & |
363 |
p_atm, z_atm, t_ca, & |
364 |
p_surf, t_surf, u_surf, v_surf, & |
365 |
rough_mom, rough_heat, rough_moist, gust |
366 |
real, intent(out), dimension(:,:) :: & |
367 |
flux_t, flux_q, flux_r, flux_u, flux_v, & |
368 |
dhdt_surf, dedt_surf, dedq_surf, drdt_surf, & |
369 |
dhdt_atm, dedq_atm, dtaudv_atm, & |
370 |
w_atm, u_star, b_star, q_star, & |
371 |
cd_m, cd_t, cd_q |
372 |
real, intent(inout), dimension(:,:) :: q_surf |
373 |
real, intent(in) :: dt |
374 |
integer, intent (in) :: myThid |
375 |
|
376 |
! ---- local vars ----------------------------------------------------------- |
377 |
integer :: j |
378 |
do j = 1, size(t_atm,2) |
379 |
call surface_flux_1d ( & |
380 |
t_atm(:,j), q_atm_in(:,j), u_atm(:,j), v_atm(:,j), p_atm(:,j), z_atm(:,j), & |
381 |
p_surf(:,j), t_surf(:,j), t_ca(:,j), q_surf(:,j), & |
382 |
u_surf(:,j), v_surf(:,j), & |
383 |
rough_mom(:,j), rough_heat(:,j), rough_moist(:,j), gust(:,j), & |
384 |
flux_t(:,j), flux_q(:,j), flux_r(:,j), flux_u(:,j), flux_v(:,j), & |
385 |
cd_m(:,j), cd_t(:,j), cd_q(:,j), & |
386 |
w_atm(:,j), u_star(:,j), b_star(:,j), q_star(:,j), & |
387 |
dhdt_surf(:,j), dedt_surf(:,j), dedq_surf(:,j), drdt_surf(:,j), & |
388 |
dhdt_atm(:,j), dedq_atm(:,j), dtaudv_atm(:,j), & |
389 |
dt, land(:,j), avail(:,j), myThid ) |
390 |
end do |
391 |
end subroutine surface_flux_2d |
392 |
|
393 |
|
394 |
! ============================================================================ |
395 |
subroutine surface_flux_init (myThid) |
396 |
! ============================================================================ |
397 |
! initializes surface flux module |
398 |
! ---- local vars ---------------------------------------------------------- |
399 |
integer, intent(in) :: myThid |
400 |
integer :: unit, ierr, io |
401 |
!-- added: |
402 |
integer :: iUnit |
403 |
CHARACTER*(gcm_LEN_MBUF) :: msgBuf |
404 |
|
405 |
! read namelist |
406 |
|
407 |
! _BARRIER |
408 |
! _BEGIN_MASTER(myThid) |
409 |
CALL BARRIER(myThid) |
410 |
IF ( myThid.EQ.1 ) THEN |
411 |
|
412 |
WRITE(msgBuf,'(A)') 'SURFACE_FLUX_INIT: opening data.atm_gray' |
413 |
CALL PRINT_MESSAGE( msgBuf, gcm_stdMsgUnit, gcm_SQZ_R, myThid ) |
414 |
CALL OPEN_COPY_DATA_FILE( & |
415 |
'data.atm_gray', 'SURFACE_FLUX_INIT', & |
416 |
iUnit, & |
417 |
myThid ) |
418 |
! Read parameters from open data file |
419 |
READ(UNIT=iUnit,NML=surface_flux_nml) |
420 |
WRITE(msgBuf,'(A)') & |
421 |
'SURFACE_FLUX_INIT: finished reading data.atm_gray' |
422 |
CALL PRINT_MESSAGE( msgBuf, gcm_stdMsgUnit, gcm_SQZ_R, myThid ) |
423 |
! Close the open data file |
424 |
CLOSE(iUnit) |
425 |
|
426 |
! if ( file_exist('input.nml')) then |
427 |
! unit = open_namelist_file () |
428 |
! ierr=1; |
429 |
! do while (ierr /= 0) |
430 |
! read (unit, nml=surface_flux_nml, iostat=io, end=10) |
431 |
! ierr = check_nml_error(io,'surface_flux_nml') |
432 |
! enddo |
433 |
!10 call close_file (unit) |
434 |
! endif |
435 |
|
436 |
! ! write version number |
437 |
! call write_version_number(version, tagname) |
438 |
|
439 |
! if ( mpp_pe() == mpp_root_pe() ) write (stdlog(), nml=surface_flux_nml) |
440 |
|
441 |
|
442 |
! if(.not. use_virtual_temp) d608 = 0.0 |
443 |
|
444 |
do_init = .false. |
445 |
|
446 |
ENDIF |
447 |
CALL BARRIER (myThid) |
448 |
|
449 |
end subroutine surface_flux_init |
450 |
|
451 |
|
452 |
end module surface_flux_mod |