← Back to Documentation Home
CCPP SciDoc v8.0.0  v8.0.0
Common Community Physics Package Developed at DTC
 
Loading...
Searching...
No Matches
canopy_transfer.F90
1 module canopy_transfer_mod
2 contains
3
4!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
5 subroutine canopy_transfer_init( im, km, nkc, nkt, & !in
6 massair_can, massair, & !out
7 mmr_o3_can, & !inout
8 nfrct, ifrct, & !out
9 frctr2c, frctc2r, & !out
10 errmsg, errflg )
11
12! Input/Output variables, original Horizontal coordinate
13!
14! Local variables:
15! massair_can(:,nkt) : mass of air in canopy layers (kg)
16! massair (:, km) : mass of air in model layers (kg)
17! (gathered canopy + resolved scale columns)
18! nfrct (nkt, :) : Number of original model levels contributing to canopy level k
19! ifrct (nkt, 2,:) : Index of the original model level contributing to canopy level k
20! frctr2c(nkt, 2,:) : Fractional contribution of the original model level to canopy level k
21! frctc2r(nkt, 2,:) : Fractional contribution of the canopy level to the original model level
22!
23!=============================================================================
24
25 use machine , only : kind_phys
26
27 IMPLICIT NONE
28
29!...Arguments:
30
31 integer, intent(in) :: im, km, nkc, nkt
32
33 integer, intent(out) :: &
34 nfrct (km+nkc, im) , &
35 ifrct (km+nkc, 2, im)
36
37 real(kind=kind_phys), intent(out) :: &
38 massair_can(im, km+nkc) , &
39 massair(im, km) , &
40 mmr_o3_can(im, km+nkc) , &
41 frctr2c(km+nkc, 2, im) , &
42 frctc2r(km+nkc, 2, im)
43
44 character(len=*), intent(out) :: errmsg
45 integer, intent(out) :: errflg
46
47!...local variables
48
49! Initialize CCPP error handling variables
50 errmsg = ''
51 errflg = 0
52
53 massair_can(:,:) = 0.
54 massair(:,:) = 0.
55 mmr_o3_can(:,:) = 0.
56
57 nfrct(:,:) = 0
58 ifrct(:,:,:) = 0
59 frctr2c(:,:,:) = 1.
60 frctc2r(:,:,:) = 1.
61
62 return
63 end subroutine canopy_transfer_init
64
65!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
66
67 subroutine canopy_transfer_run( im, km, nkc, nkt, &
68 ntrac, ntoz, &
69 GAREA, &
70 zi, zl, zm, &
71 Q1, DENS, & !in: kg kg-1
72 FLAG, & !in
73 FRT_MASK, & !in
74 kmod, kcan3, & !in
75 zmom_can, zmid_can, & !in
76 PRES_CAN, DENS_CAN, & !in
77 Q1_MOD, Q1_CAN, Q1_2M, & !inout kg kg-1
78 massair_can, massair, & !inout
79 mmr_o3_can, & !inout
80 nfrct, ifrct, & !inout
81 frctr2c, frctc2r, & !inout
82 errmsg, errflg )
83
84! Arguments:
85! Input variables
86!-----------------------------------------------------------------------------
87! Array dimensions:
88! nkc : number of canopy levels
89! nkt= km + nkc : number of levels in gathered canopy + resolved scale columns
90! met???_CAN(:.:, nkt): : met 3d variables, gathered canopy + resolved scale columns
91! kmod(km) : Vertical index location of original ungathered model layer in combined
92! canopy + resolved scale column
93! flag : 0 -> resolved_to_canopy
94! 1 -> canopy_to_resolved
95!
96! Input/Output variables, original Horizontal coordinate
97! Q1_CAN(:,nkt, NSPCSD) : Chemical tracers concentrations kg kg-1 combined canopy and resolved model layers
98! Q1_MOD(:,km, NSPCSD) : Chemical tracers concentrations kg kg-1 on model levels (copy of CONC)
99! Q1 (:,km, NSPCSD) : Chemical tracers concentrations kg kg-1 on model levels
100! Q1_2M (:, NSPCSD)
101!
102! Local variables:
103! massair_can(:, nkt) : mass of air in canopy layers (kg)
104! massair (:, km) : mass of air in model layers (kg)
105! (gathered canopy + resolved scale columns)
106! nfrct (nkt, :) : Number of original model levels contributing to canopy level k
107! ifrct (nkt,2,:) : Index of the original model level contributing to canopy level k
108! frctr2c(nkt,2,:) : Fractional contribution of the original model level to canopy level k
109! frctc2r(nkt,2,:) : Fractional contribution of the canopy level to the original model level
110!
111!=============================================================================
112
113 use machine , only : kind_phys
114
115 IMPLICIT NONE
116
117!...Arguments:
118
119 integer, intent(in) :: im, km, nkc, nkt, ntrac, ntoz
120 integer, intent(in) :: flag
121 real(kind=kind_phys), intent(in) :: zi(im, km+1), zl(im, km), zm(im, km)
122 real(kind=kind_phys), intent(in) :: garea(im)
123
124! ** Q1 is concentration field (including gas and aerosol variables) mass mixing ratio kg kg-1
125 real(kind=kind_phys), intent(in) :: q1(im, km, ntrac)
126
127 real(kind=kind_phys), intent(in) :: dens(im, km)
128
129 integer, intent(in) :: kmod (im, km), kcan3 (im, nkc)
130
131 real(kind=kind_phys), intent(inout) :: zmom_can(im, nkt+1) , &
132 zmid_can(im, nkt)
133
134 real(kind=kind_phys), intent(in) :: frt_mask(im) , &
135! met3d arrays
136 pres_can(im, nkt) , &
137 dens_can(im, nkt)
138
139! all gas-phase species array
140 real(kind=kind_phys), intent(inout) :: q1_mod(im, km, ntrac), &
141 q1_can(im, nkt, ntrac)
142 real(kind=kind_phys), intent(inout) :: q1_2m(im, ntrac)
143
144 integer, intent(inout) :: nfrct (km+nkc, im) , &
145 ifrct (km+nkc, 2, im)
146
147 real(kind=kind_phys), intent(inout) :: massair_can(im, km+nkc), &
148 massair(im, km) , &
149 mmr_o3_can(im, km+nkc), &
150 frctr2c(km+nkc, 2, im), &
151 frctc2r(km+nkc, 2, im)
152
153 character(len=*), intent(out) :: errmsg
154 integer, intent(out) :: errflg
155
156!...Local arrays:
157
158 real(kind=kind_phys) :: zmid(km) , &
159 zmom(km+1), & ! Same as zfull !
160 z2(km+1), &
161 sigmid2(km+1), &
162 zcan3(nkc) ,&
163 pres_can3(nkt), pres3(km) , &
164 dens_can3(nkt), dens3(km) , &
165 klower_can(nkc) , &
166 dxdy(im)
167
168 real(kind=kind_phys) :: &
169 mass_canopy(nkt), &
170 mmr_canopy(nkt), &
171 vmr_canopy(nkt), &
172 mmr_resolved(km + 1), &
173 vmr_resolved(km + 1), &
174 mass_resolved(km), &
175 conc3(km), &
176 conc_can3(nkc)
177
178!...local variables
179
180 INTEGER :: i, S, IS
181
182 INTEGER :: LEV, L
183
184 INTEGER :: KOUNT
185
186! Diagnostic height is the assumed height above ground of the sampling for observations
187 real(kind=kind_phys), parameter :: diag_hgt = 2.0
188 real(kind=kind_phys), parameter :: epsilon = 1.e-10
189
190!--------------
191!hrinit.F: ...set scale factor for [ppm] -> [kg/kg]
192!
193! CGRID to CHEM Species conversion factor
194! FORWARD_CONV( N ) = 1.0E-3 * MWAIR / SPECIES_MOLWT( N ) ! ug kg-1 to ppm
195! CHEM to CGRID Species conversion factor
196! REVERSE_CONV( N ) = 1.0E+3 / MWAIR * SPECIES_MOLWT( N ) ! ppm to ug kg-1
197!--------------
198! Conversion factor from units in [kg kg-1] to [ug kg-1]
199 REAL(kind=kind_phys), PARAMETER :: forward_conv = 1.e-9 ! ug kg-1 -> kg kg-1
200 REAL(kind=kind_phys), PARAMETER :: reverse_conv = 1.e+9 ! kg kg-1 -> ug kg-1
201
202 real(kind=kind_phys) :: mmr_diag
203
204 logical(kind=4) :: chm_error_l = .false.
205
206 integer(kind=4) :: k, kk, kc, k2, II, npass
207
208 logical(kind=4) :: local_dbg
209 local_dbg = .true.
210
211! Initialize CCPP error handling variables
212 errmsg = ''
213 errflg = 0
214
215 conc_can3(:)=0.
216 conc3(:)=0.
217 mass_canopy(:) = 0.
218 mmr_canopy(:) = 0.
219 vmr_canopy(:) = 0.
220 mmr_resolved(:) = 0.
221 vmr_resolved(:) = 0.
222 mass_resolved(:) = 0.
223
224! RELWTEM( ICG ) = CONVMW / NR_MOLWT( SP_INDX )
225
226 DO i = 1, im !i-index
227
228!!! Non-Canopy columns
229 IF (frt_mask(i) <= 0.) THEN
230
231!!!!! Start all columns!!!!! canopy & non-canopy (canopy columns are overwritten below)
232 do k = 1, km ! from bottom to top
233 ii = km + 1 - k ! from top to bottom of resolved model layers km+1 ???
234!!! Paul's zmom is our zmom
235! zmom(1) = ZFULL(km) is top model layer height
236! zmom(km) = ZFULL(1) is bottom model layer height
237 zmom(ii) = zm(i,k) ! ZFULL(i,k)
238 dens3(ii) = dens(i,k) ! kg/m**3
239!! Heights of the original model layers for the canopy columns are extracted to the zmom array.
240
241 end do
242
243! Calculate mass of air in model levels
244 !Paul's zmom is our zmom
245 zmom(km + 1) = 0.0
246 do k = km, 1, -1
247 ! Paul's massairmod is our massair
248 massair(i, k) = dens3(k) * garea(i) * &
249 (zmom(k) - zmom(k + 1))
250 end do
251
252! First, carry over original model values for the matching layers
253 do k = 1, km ! from bottom to top of resolved model layers
254 massair_can(i, k) = massair(i, k) ! full layer height [m]
255 end do
256
257 do kc = 1, nkc ! from top to bottom of canopy layers
258 massair_can(i, km+kc) = massair(i, km)
259 end do ! kc = 1, nkc
260!!!!! Non-Canopy columns !!!!!
261
262!!!! Continuous forest canopy
263 ELSE IF (frt_mask(i) > 0.) THEN
264
265! Put vars on combined layers in layer order as in Paul's code (GEM-MACH)
266! 1 <= nkt is top model layer
267! ...
268! km<= (4) is 1st (bottom) model layer
269! nkt-2 <= (3) is 3rd (top) canopy layer
270! nkt-1 <= (2) is 2nd canopy layer
271! nkt <= (1) is 1st (bottom) canopy layer
272
273 do k = 1, nkt
274 ii = nkt + 1 - k
275 pres_can3(ii) = pres_can(i,k)
276 dens_can3(ii) = dens_can(i,k) ! kg/m**3
277 end do
278
279! Calculate mass of air on combined levels
280 !Paul's zmomcan is our zmom_can(im, nkt+ 1)
281 ! Layers in reverse order!
282 ! zmom_can(:,:,1) is top resolved layer
283 ! zmom_can(:,:,km) is 1hy resolved layer
284 ! zmom_can(:,:,nkt) is 1st canopy layer
285 zmom_can(i, nkt+ 1) = 0.0
286 do k = nkt, 1, -1
287 ! Paul's massaircan is our massair_can
288 massair_can(i, k) = dens_can3(k) * garea(i) * &
289 (zmom_can(i, k) - zmom_can(i, k + 1))
290 end do
291
292 do k = 1, km ! from bottom to top
293 ii = km + 1 - k ! from top to bottom of resolved model layers km+1 ???
294!!! Paul's zmom is our zmom
295! zmom(1) = ZFULL(km) is top model layer height
296! zmom(km) = ZFULL(1) is bottom model layer height
297 zmom(ii) = zm(i,k) ! ZFULL(i,k)
298 dens3(ii) = dens(i,k) ! kg/m**3
299!! Heights of the original model layers for the canopy columns are extracted to the zmom array.
300 end do
301
302! Calculate mass of air in model levels
303 !Paul's zmom is our zmom
304 zmom(km + 1) = 0.0
305 do k = km, 1, -1
306 ! Paul's massairmod is our massair
307 massair(i, k) = dens3(k) * garea(i) * &
308 (zmom(k) - zmom(k + 1))
309 end do
310
311! Next, we need a set of arrays which track mass transfer from resolved to model layers;
312! how much of the original (aka "resolved") model layer mass goes into each canopy layer,
313! given the above level structure. The three arrays are:
314! nfrct(k, :) : the number of resolved model levels contributing to canopy level k
315! ifrct(k,n,:) : the index of the resolved model level contributing to canopy level k (n is at most 2)
316! frctr2c(k,n,:) : the fractional contribution of the resolved model level to canopy level k
317! frctc2r(k,n,:) : the fractional contribution of the canopy model level to the resolved model level
318!
319! Check for coincident layers first:
320!
321 inner: do k = 1, km
322! If the following IF statement is true, then the canopy and resolved
323! model layer upper and lower boundaries coincide, and the entire resolved model
324! model layer contributes to the combined model layer (trivial case).
325 if (zmom_can(i, k) == zmom(k) .and. zmom_can(i, k+1) == zmom(k+1)) then
326 nfrct(k, i) = 1
327 ifrct(k, 1, i) = k
328 frctr2c(k, 1, i) = 1.0
329 frctc2r(k, 1, i) = 1.0
330 else
331 exit inner
332 end if
333 end do inner
334!
335! "k" is the first layer where boundary levels do not match on output from the above loops.
336! Determine fractions of original model layer structure contributing to canopy model layers.
337 k2 = k
338 do k = k2, nkt
339 do kk = k2, km
340! (1) Upper boundaries of combined and resolved model layers coincide,
341! lower boundary of combined layer is within resolved layer, so canopy
342! layer resides entirely within resolved layer, and shares an upper boundary
343! with the resolved layer:
344 if ((zmom_can(i, k) == zmom(kk) .and. zmom_can(i, k+1) > zmom(kk+1)) .or. &
345! (2) Lower boundaries coincide, upper boundary of combined layer is within resolved layer,
346! so canopy layer resides entirely within the resolved layer, and shares a lower boundary
347! with the canopy layer.
348 (zmom_can(i, k+1) == zmom(kk+1) .and. zmom_can(i, k) > zmom(kk)) .or. &
349! (3) Both canopy layer boundaries exist inside a resolved layer, with no shared boundaries:
350! nfrct(km + 1) = 1
351! ifrct(km + 1) = 64
352 (zmom_can(i, k) < zmom(kk) .and. zmom_can(i, k+1) >= zmom(kk+1))) then
353 nfrct(k, i) = 1
354 ifrct(k, 1, i) = kk
355! frctr2c(k, 1, i) = (zmom_can(i, k) - zmom_can(i, k+1)) / max(zmom(kk) - zmom(kk+1), epsilon)
356 frctr2c(k, 1, i) = (zmom_can(i, k) - zmom_can(i, k+1)) / (zmom(kk) - zmom(kk+1))
357 frctc2r(k, 1, i) = 1.0 ! canopy layer resides within resolved model layer
358 end if
359! Resolved layer boundary splits a combined canopy layer:
360! This case arises if, due to the use of the momentum levels in the canopy column
361! sometimes being half-way between the thermodynamic levels, a resolved model
362! momentum layer falls within the canopy layer. Since the resolved model layers are
363! defacto thicker than the canopy layers, this means that there can at most be two
364! resolved model layers contributing to the canopy layer (only case where nfrct = 2).
365 if (zmom_can(i, k+1) < zmom(kk) .and. zmom_can(i, k) > zmom(kk)) then
366 nfrct(k, i) = 2
367 ifrct(k, 1, i) = kk
368 ifrct(k, 2, i) = kk-1
369! Fraction of resolved model layer contributing to canopy layer:
370! frctr2c(k, 1, i) = (zmom(kk) - zmom_can(i, k+1)) / max(zmom(kk) - zmom(kk+1), epsilon)
371! frctr2c(k, 2, i) = (zmom_can(i, k) - zmom(kk)) / max(zmom(kk-1) - zmom(kk), epsilon)
372 frctr2c(k, 1, i) = (zmom(kk) - zmom_can(i, k+1)) / (zmom(kk) - zmom(kk+1))
373 frctr2c(k, 2, i) = (zmom_can(i, k) - zmom(kk)) / (zmom(kk-1) - zmom(kk) )
374! Fraction of canopy layer contributing to resolved model layer:
375! frctc2r(k, 1, i) = (zmom(kk) - zmom_can(i, k+1)) / max(zmom_can(i, k) - zmom_can(i, k+1), epsilon)
376! frctc2r(k, 2, i) = (zmom_can(i, k) - zmom(kk)) / max(zmom_can(i, k) - zmom_can(i, k+1), epsilon)
377 frctc2r(k, 1, i) = (zmom(kk) - zmom_can(i, k+1)) / (zmom_can(i, k) - zmom_can(i, k+1))
378 frctc2r(k, 2, i) = (zmom_can(i, k) - zmom(kk)) / (zmom_can(i, k) - zmom_can(i, k+1) )
379 end if
380 end do
381 end do
382
383!
384! massair_can thus contains the mass of air in the canopy layers in kg, while massair contains the
385! mass of air in the original model layers, at the canopy columns (i)
386!
387 END IF ! Continuous forest canopy: FRT_MASK == 1.
388
389
390 END DO !i = 1, im !I-index
391
392
393! return tracers to resolved scale model layers:
394
395 if (flag == 1) then ! "canopy_to_resolved"
396
397! At this point, the model mass is distributed over the combined layers,
398! and the tracer concentration arrays are both in the combined layer system.
399!
400 DO i = 1, im !I-index
401
402 kount = 0
403
404 ! loop over canopy columns
405 IF (frt_mask(i) > 0.) THEN
406
407! Q1_MOD/Q1_CAN:
408! Assigned/Initilized in canopy_levs FIRSTIME
409
410!...fetch all species in units kg kg-1 mass mixing ratio
411 do s = 1, ntrac-1 ! ntrac1= 197 (ntrac=ntke=198)
412
413! Flip resolved layer arrays into a new array for use here
414 do k = 1, km ! from bottom to top
415 ii = km + 1 - k ! from top to bottom of resolved model layers
416 ! conc3(1) is top model layer
417 ! conc3(km) is 1st (bottom) model layer
418 ! Paul's chem_tr is our conc3 = vmr_resolved
419! NB. mfpbltq_mod: q1(ix,km,ntrac1) kg kg-1
420 ! Paul's chem_tr is our vmr_resolved =conc3
421 vmr_resolved(ii) = q1_mod(i, k, s) ! kg kg-1
422 end do
423
424! Flip combined layer arrays into a new array for use here
425 do k = 1, nkt ! from top to bottom
426 ii = nkt + 1 - k ! from bottom to top of resolved model layers
427 ! Paul's trppm is our vmr_canopy (conc_can)
428 ! (km) is top model layer
429 ! (1) is 1hy model layer
430 vmr_canopy(ii) = q1_can(i, k, s) !kg kg-1
431 end do
432
433! (ii): Canopy shaded layers
434 do kc = 1, nkc
435 k = kcan3(i, kc) ! kcan3(1,2,3) = 65,66,67
436
437 ! Paul's tracers_can is our conc_can3 array
438 conc_can3(kc) = vmr_canopy(k) ! kg kg-1
439 end do
440
441! (1) We start off by converting these mass mixing ratio [kg kg-1] to mass in [ug]:
442
443 do k = 1, km
444 ! kmod(1) is 1 top model layer
445 ! kmod(km) is 65 top canopy layer (modified after mono adj.)
446 kk = kmod(i, k)
447
448! ...fetch gas mass mix. ratios [kg kg-1] and convert to [ug kg-1]
449 ! Paul's conc is our mmr_canopy
450 !mmr_canopy(kk) = REVERSE_CONV * conc3(k) ! ug kg-1
451 mmr_canopy(kk) = reverse_conv * vmr_resolved(k) ! ug kg-1
452 end do
453
454 do k = 1, nkc
455 ! kcan3(k=1,2,3) = 65,66,67
456 kc = kcan3(i, k)
457
458! ...fetch gas mass mix. ratios [kg kg-1] and convert to [ug kg-1]
459 mmr_canopy(kc) = reverse_conv * conc_can3(k) ! ug kg-1
460 end do
461
462! (2) Array "mass_canopy" now holds the mass of the tracer in each of the combined levels.
463! This mass must be added back to the resolved levels:
464 ! Paul's masscan is our mass_canopy
465 ! Paul's mass_resolved is our mass_resolved
466 mass_resolved(:) = 0.
467 do k = 1, nkt
468
469! Output diag
470 if(s == 11) mmr_o3_can(i,k) = mmr_canopy(k) ! nto3=11 "canopy_to_resolved"
471
472 mass_canopy(k) = mmr_canopy(k) * massair_can(i, k) ! ug
473 do kk = 1, nfrct(k, i)
474 kc = ifrct(k, kk, i)
475 mass_resolved(kc) = mass_resolved(kc) + mass_canopy(k) * frctc2r(k,kk,i) ! ug
476 end do
477 end do
478
479!
480! Check: total mass in the column should be the same
481 if (local_dbg) then
482 call canopy_mass_check(mass_canopy, mass_resolved, i, flag, nkc, nkt, errmsg, errflg)
483 if (errflg /= 0) return
484 end if
485!
486! (3) The masses in [ug] need to be converted back to [kg kg-1]
487 do k = 1, km
488!
489 ! Paul's massairmod is our massair
490 ! Paul's mass_resolved is our mass_resolved
491! mmr_resolved(k) = mass_resolved(k) / max(massair(i, k), epsilon) ! ug kg-1
492 mmr_resolved(k) = mass_resolved(k) / (massair(i, k)) ! ug kg-1
493
494! (3a) Convert back m.m.r. [ug kg-1] to [kg kg-1]
495 ! NB. This is Q1_MOD to be used in gas-phase hrdriver call on canopy columns
496 ! Paul's chem_tr is our conc3 = vmr_resolved
497 vmr_resolved(k) = forward_conv * mmr_resolved(k) ! kg kg-1
498
499 end do
500
501 do k = 1, km ! from bottom to top
502 ii = km + 1 - k ! from top to bottom of resolved model layers
503 ! zmid(1) = ZM(km) is top model layer height
504 ! zmid(km) = ZM(1) is bottom model layer height
505 ! Paul's zt (or ZPLUS) is our zmid
506 zmid(ii) = zl(i,k) ! mid layer height [m]
507!!! Heights of the original model layers for the canopy columns are extracted to the zmid array.
508 end do
509
510!
511! (4) Evaluate the diagnostic level concentration
512! Find the bounding layers above and below the diagnostic height:
513! kk'th layer is the layer above the inlet height
514 kk = nkt
515 do k = nkt, nkt-8, -1
516 ! Paul's zt_can (MV3D_ZPLUS) is our zmid
517 if (diag_hgt <= zmid_can(i, k-1) .and. &
518 diag_hgt > zmid_can(i, k)) then
519 kk = k - 1
520 end if
521 end do
522! If the diagnostic height is less than the lowest level, then use that level
523! for the concentration.
524 if (kk == nkt) then
525 mmr_diag = mmr_canopy(nkt) ! ug kg-1
526 vmr_resolved(km + 1) = forward_conv * mmr_canopy(nkt) ! kg kg-1
527
528 else
529! Diagnostic height 2m is always above the lowest model hybrid level ~42m
530! The lines below never executed
531 mmr_diag = &
532 mmr_canopy(kk) + &
533 (mmr_canopy(kk) - mmr_canopy(kk + 1)) / &
534! max(zmid_can(i, kk) - zmid_can(i, kk + 1), epsilon) * &
535 (zmid_can(i, kk) - zmid_can(i, kk + 1)) * &
536 (diag_hgt - zmid_can(i, kk + 1)) ! ug kg-1
537 vmr_resolved(km + 1) = forward_conv * mmr_diag ! kg kg-1
538
539 end if
540
541! Flip back resolved layers arrays for gas-phase integration (hrdriver)
542 do k = 1, km ! from top to bottom
543 ii = km + 1 - k ! from bottom to top of resolved model layers
544 ! Paul's trppm is our conc_can (vmr_canopy)
545 ! (km) is top model layer
546 ! (1) is 1hy model layer
547 q1_mod(i, ii, s) = vmr_resolved(k) ! kg kg-1
548 end do
549
550! 2M Diagnostics
551 q1_2m(i, s) = vmr_resolved(km+1) ! kg kg-1
552
553 end do ! number of species loop s = 1, NUMB_MECH_SPC
554
555! Print up to KOUNT number of canopy columns
556 kount = kount + 1
557!
558 END IF ! loop over canopy columns FRT_MASK == 1.
559
560
561 END DO !I = 1, im !I-index
562
563! Done transferring from combined canopy + resolved scale back to resolved scale. :)
564!
565! ========================================================================
566 else ! if (flag == 0) then (canopy_transfer == "resolved_to_canopy") then
567!
568! In: Q1_MOD
569!
570! Out: Q1_CAN (vmr_canopy)
571! NB. ! Paul's trppm (mach_gas_canopy) is our vmr_canopy
572! ========================================================================
573!
574
575 DO i = 1, im !I-index
576
577 kount = 0
578
579 IF (frt_mask(i) > 0.) THEN
580
581!...fetch all species and convert to kg kg-1 mass mixing ratio
582 DO s = 1, ntrac-1 ! ntrac1= 197 (ntrac=ntke=198)
583! DO ISP = 1, 1 ! ntqv=1 ntoz=7 nto3=11
584
585 ! S = CGRID_INDEX( ISP )
586
587! Flip resolved layer arrays into a new array for use here
588! (i): Model resolved layers
589 do k = 1, km
590 ii = km + 1 - k ! from top to bottom of resolved model layers km+1 ???
591 ! Paul's chem_tr is our conc3 = vmr_resolved (q1_mod)
592 ! conc3(1) is top model layer
593 ! conc3(km) is 1st (bottom) model layer
594 ! conc3(II) = Q1 (i, k, S) ! kg kg-1
595 conc3(ii) = q1_mod(i, k, s) ! kg kg-1
596 vmr_resolved(ii) = q1_mod(i, k, s) ! kg kg-1
597 end do
598
599! (1) We start off by converting these mass mixing ratio [kg kg-1]to mass in [ug]:
600 do k = 1, km
601! ...fetch gas mass mixing ratios [kg kg-1] and convert to [ug kg-1]
602 ! Paul's conc is our mmr_resolved
603 mmr_resolved(k) = reverse_conv * conc3(k) ! ug kg-1
604 end do
605
606! (1) Convert the original model domain values in the current column to mass from mass mixing ratio:
607! mass_resolved = Mass mixing ratio * (density) / (volume of original model layer) (ug)
608 do k = 1, km
609 mass_resolved(k) = mmr_resolved(k) * massair(i, k) ! ug
610 end do
611
612! (2) Use the array fractions defined earlier to divide the resolved layer masses into the canopy layers,
613! and convert back to mixing ratios. Note that the frctr2c fractions are vertical extent of the
614! contribution of the resolved layer into the canopy layer, hence the mass/volume can be divided up
615! this way:
616! mmr_canopy = sum of masses contributed / (density * volume of canopy model layeri)
617 ! Paul's mmr_canopy is our mmr_canopy in ug kg-1
618 ! Paul's masscan is our mass_canopy
619 mmr_canopy(:) = 0.
620 mass_canopy(:) = 0.
621 do k = 1, nkt
622 do kk = 1, nfrct(k, i)
623 kc = ifrct(k, kk, i)
624 mass_canopy(k) = mass_canopy(k) + mass_resolved(kc) * frctr2c(k, kk, i) ! ug
625 end do
626 end do
627
628!
629! Check: total mass in the column should be the same
630 if (local_dbg) then
631 call canopy_mass_check(mass_canopy, mass_resolved, i, flag, nkc, nkt, errmsg, errflg)
632 if (errflg /= 0) return
633 end if
634!
635 do k = 1, nkt
636 ! Paul's massaircan is our massair_can
637! mmr_canopy(k) = mass_canopy(k) / max(massair_can(i, k), epsilon) ! ug kg-1
638 mmr_canopy(k) = mass_canopy(k) / (massair_can(i, k)) ! ug kg-1
639
640! Output diags
641! ! if(S == 11) mmr_o3_can(i,k) = mmr_canopy(k) ! nto3=11 "resolved_to_canopy"
642! if(S == 11) mmr_o3_can(i,k) = frctr2c(k, 1, i) ! "resolved_to_canopy"
643 if(s == 11) mmr_o3_can(i,k) = frctr2c(k, 2, i)
644 end do
645
646
647!
648! (3) Replace the original model layer values with the corresponding canopy layer values, when
649! a canopy exists:
650 do kk = 1, km
651 k = kmod(i, kk)
652 ! Paul's chem_tr is our conc3 = vmr_resolved (q1_mod) <================
653! conc3(kk) = FORWARD_CONV * mmr_canopy(k) ! kg kg-1
654 vmr_resolved(kk) = forward_conv * mmr_canopy(k) ! kg kg-1
655 end do
656
657! (i): Model resolved layers: for hrdriver (trppm from mach_gas_canopy)
658 do kk = 1, km
659 ! kmod(1) is 1 top model layer
660 ! kmod(km) is 65 top canopy layer (modified after mono adj.)
661 k = kmod(i, kk)
662
663 ! Paul's trppm is our vmr_canopy (conc_can)
664! vmr_canopy(k) = conc3(kk) ! kg kg-1
665 vmr_canopy(k) = vmr_resolved(kk) ! kg kg-1
666 end do
667!
668! (4) Fill the canopy layers with the new mass mixing ratios
669 do kc = 1, nkc
670 k = kcan3(i, kc)
671 ! Paul's tracers_can is our conc_can3 <====================
672 conc_can3(kc) = forward_conv * mmr_canopy(k) ! kg kg-1
673 end do
674
675! (ii): Canopy shaded layers (for hrdriver) (trppm from mach_gas_canopy)
676 do kc = 1, nkc
677 ! Paul's trppm is our vmr_canopy (conc_can)
678 ! kcan3(1) = 65
679 ! kcan3(2) = 66
680 ! kcan3(3) = 67
681 k = kcan3(i, kc)
682 vmr_canopy(k) = conc_can3(kc) ! kg kg-1
683 end do
684
685! Prepare array for gas-phase chemical integration. (Paul's mach_gas_canopy)
686!
687! Flip back augmented canopy+resolved arrays for gas-phase integration (hrdriver)
688 do k = 1, nkt ! from top to bottom
689 ii = nkt + 1 - k ! from bottom to top of resolved model layers
690 ! (nkt) is top model layer
691 ! (4) is 1hy model layer
692 ! (1-3) are canopy layers
693 ! Paul's trppm is our vmr_canopy (conc_can)
694 q1_can(i, ii, s) = vmr_canopy(k) ! kg kg-1
695 end do
696
697 end do !species index loop S (formerly isp)
698
699! Print up to KOUNT number of canopy columns
700 kount = kount + 1
701
702! loop over canopy columns
703 END IF ! loop over canopy columns FRT_MASK == 1.
704!
705 END DO !i = 1, im !I-index
706!
707 end if ! 1="canopy_to_resolved" 0= "resolved_to_canopy"
708
709 return
710
711 contains
712
713 subroutine canopy_mass_check(mass_canopy, mass_model, i, flag, nkc, nkt, errmsg, errflg)
714 implicit none
715 integer(kind=4), intent(in) :: flag, i, nkc, nkt
716 real(kind=kind_phys), intent(in) :: mass_canopy(nkt), mass_model(km)
717 character(len=*), intent(out) :: errmsg
718 integer, intent(out) :: errflg
719
720 character(len=18) :: mode_transfer
721 real(kind=kind_phys) :: masstotcan, masstotres, massrat
722 real(kind=kind_phys) :: sum2can(nkt), sum2res(nkt)
723
724 masstotcan = 0.
725 masstotres = 0.
726 do k = 1, nkt
727 masstotcan = masstotcan + mass_canopy(k)
728 end do
729 do k = 1, km
730 masstotres = masstotres + mass_model(k)
731 end do
732
733 if (flag == 1) then
734 mode_transfer = "canopy_to_resolved"
735 else
736 mode_transfer = "resolved_to_canopy"
737 end if
738
739! if (masstotres > epsilon) then
740 if (masstotres > 0.0 ) then
741 massrat = masstotcan / masstotres
742 if (massrat > 1.001 .or. massrat < 0.999) then
743 write(errmsg,fmt='(*(a,f10.4,a,f10.4))') 'Conversion of mass in ccpp_canopy_transfer not conserved ' // &
744 'during ' // mode_transfer // ' evaluation. masstotcan = ', masstotcan, &
745 ' and masstotres = ', masstotres
746 errflg = 1
747 return
748 end if
749 end if
750!
751! Check on the values of the fractions: they should sum to unity across the number
752! of original model levels!
753 sum2can = 0.
754 sum2res = 0.
755 do k = nkt, 1, -1
756 do kk = 1, nfrct(k, i)
757 kc = ifrct(k, kk, i)
758 sum2can(kc) = sum2can(kc) + frctr2c(k, kk, i)
759 sum2res(k) = sum2res(k) + frctc2r(k, kk, i)
760 end do
761 end do
762
763 do k = km , 1, -1
764 if (sum2can(k) < 0.999 .or. sum2can(k) > 1.001) then
765 write(errmsg,fmt='(*(a,i0,a,i0,a,f10.4))') 'layer mismatch in canopy level setup in resolved to canopy indexing: ' // &
766 'column ', i, ' layer ', k, ' sum=', sum2can(k)
767 errflg = 1
768 return
769 end if
770 end do
771 do k = nkt, 1, -1
772 if (sum2res(k) < 0.999 .or. sum2res(k) > 1.001) then
773 write(errmsg,fmt='(*(a,i0,a,i0,a,f10.4))') 'layer mismatch in canopy level setup in canopy to resolved indexing: ' // &
774 'column ', i, ' layer ', k, ' sum=', sum2res(k)
775 errflg = 1
776 return
777 end if
778 end do
779
780!
781 return
782 end subroutine canopy_mass_check
783
784 end subroutine canopy_transfer_run
785
786 end module canopy_transfer_mod