ROMS
Loading...
Searching...
No Matches
npzd_iron.h
Go to the documentation of this file.
1 MODULE biology_mod
2!
3!git $Id$
4!================================================== Hernan G. Arango ===
5! Copyright (c) 2002-2025 The ROMS Group Jerome Fiechter !
6! Licensed under a MIT/X style license !
7! See License_ROMS.md !
8!=======================================================================
9! !
10! Nutrient-Phytoplankton-Zooplankton-Detritus Model, !
11! including Iron Limitation on Phytoplankton Growth. !
12! !
13! This routine computes the biological sources and sinks and adds !
14! then the global biological fields. !
15! !
16! Reference: !
17! !
18! Fiechter, J., A.M. Moore, C.A. Edwards, K.W. Bruland, !
19! E. Di Lorenzo, C.V.W. Lewis, T.M. Powell, E. Curchitser !
20! and K. Hedstrom, 2009: Modeling iron limitation of primary !
21! production in the coastal Gulf of Alaska, Deep Sea Res. II !
22! !
23!=======================================================================
24!
25 implicit none
26!
27 PRIVATE
28 PUBLIC :: biology
29!
30 CONTAINS
31!
32!***********************************************************************
33 SUBROUTINE biology (ng,tile)
34!***********************************************************************
35!
36 USE mod_param
37 USE mod_forces
38 USE mod_grid
39 USE mod_ncparam
40 USE mod_ocean
41 USE mod_stepping
42!
43! Imported variable declarations.
44!
45 integer, intent(in) :: ng, tile
46!
47! Local variable declarations.
48!
49 character (len=*), parameter :: MyFile = &
50 & __FILE__
51!
52#include "tile.h"
53!
54! Set header file name.
55!
56#ifdef DISTRIBUTE
57 IF (lbiofile(inlm)) THEN
58#else
59 IF (lbiofile(inlm).and.(tile.eq.0)) THEN
60#endif
61 lbiofile(inlm)=.false.
62 bioname(inlm)=myfile
63 END IF
64!
65#ifdef PROFILE
66 CALL wclock_on (ng, inlm, 15, __line__, myfile)
67#endif
68 CALL npzd_iron_tile (ng, tile, &
69 & lbi, ubi, lbj, ubj, n(ng), nt(ng), &
70 & imins, imaxs, jmins, jmaxs, &
71 & nstp(ng), nnew(ng), &
72#ifdef MASKING
73 & grid(ng) % rmask, &
74#endif
75#ifdef IRON_LIMIT
76 & grid(ng) % h, &
77#endif
78 & grid(ng) % Hz, &
79 & grid(ng) % z_r, &
80 & grid(ng) % z_w, &
81 & forces(ng) % srflx, &
82 & ocean(ng) % t)
83
84#ifdef PROFILE
85 CALL wclock_off (ng, inlm, 15, __line__, myfile)
86#endif
87!
88 RETURN
89 END SUBROUTINE biology
90!
91!-----------------------------------------------------------------------
92 SUBROUTINE npzd_iron_tile (ng, tile, &
93 & LBi, UBi, LBj, UBj, UBk, UBt, &
94 & IminS, ImaxS, JminS, JmaxS, &
95 & nstp, nnew, &
96#ifdef MASKING
97 & rmask, &
98#endif
99#ifdef IRON_LIMIT
100 & h, &
101#endif
102 & Hz, z_r, z_w, &
103 & srflx, &
104 & t)
105!-----------------------------------------------------------------------
106!
107 USE mod_param
108 USE mod_biology
109 USE mod_ncparam
110 USE mod_scalars
111!
112! Imported variable declarations.
113!
114 integer, intent(in) :: ng, tile
115 integer, intent(in) :: LBi, UBi, LBj, UBj, UBk, UBt
116 integer, intent(in) :: IminS, ImaxS, JminS, JmaxS
117 integer, intent(in) :: nstp, nnew
118
119#ifdef ASSUMED_SHAPE
120# ifdef MASKING
121 real(r8), intent(in) :: rmask(LBi:,LBj:)
122# endif
123# ifdef IRON_LIMIT
124 real(r8), intent(in) :: h(LBi:,LBj:)
125# endif
126 real(r8), intent(in) :: Hz(LBi:,LBj:,:)
127 real(r8), intent(in) :: z_r(LBi:,LBj:,:)
128 real(r8), intent(in) :: z_w(LBi:,LBj:,0:)
129 real(r8), intent(in) :: srflx(LBi:,LBj:)
130 real(r8), intent(inout) :: t(LBi:,LBj:,:,:,:)
131#else
132# ifdef MASKING
133 real(r8), intent(in) :: rmask(LBi:UBi,LBj:UBj)
134# endif
135# ifdef IRON_LIMIT
136 real(r8), intent(in) :: h(LBi:UBi,LBj:UBj)
137# endif
138 real(r8), intent(in) :: Hz(LBi:UBi,LBj:UBj,UBk)
139 real(r8), intent(in) :: z_r(LBi:UBi,LBj:UBj,UBk)
140 real(r8), intent(in) :: z_w(LBi:UBi,LBj:UBj,0:UBk)
141 real(r8), intent(in) :: srflx(LBi:UBi,LBj:UBj)
142 real(r8), intent(inout) :: t(LBi:UBi,LBj:UBj,UBk,3,UBt)
143#endif
144!
145! Local variable declarations.
146!
147 integer, parameter :: Nsink = 2
148
149 integer :: Iter, i, ibio, isink, itime, itrc, iTrcMax, j, k, ks
150
151 integer, dimension(Nsink) :: idsink
152
153 real(r8), parameter :: MinVal = 1.0e-6_r8
154
155 real(r8) :: Att, ExpAtt, Itop, PAR
156 real(r8) :: cff, cff1, cff2, cff3, cff4, cff5, cff6, dtdays
157 real(r8) :: cffL, cffR, cu, dltL, dltR
158 real(r8) :: fac
159#ifdef IRON_LIMIT
160 real(r8) :: Nlimit, FNlim
161 real(r8) :: FNratio, FCratio, FCratioE, Flimit
162 real(r8) :: FeC2FeN, FeN2FeC
163 real(r8) :: cffFe
164# ifdef IRON_RELAX
165 real(r8) :: FeNudgCoef
166# endif
167#endif
168 real(r8), dimension(Nsink) :: Wbio
169
170 integer, dimension(IminS:ImaxS,N(ng)) :: ksource
171
172 real(r8), dimension(IminS:ImaxS) :: PARsur
173
174 real(r8), dimension(NT(ng),2) :: BioTrc
175
176 real(r8), dimension(IminS:ImaxS,N(ng),NT(ng)) :: Bio
177 real(r8), dimension(IminS:ImaxS,N(ng),NT(ng)) :: Bio_old
178
179 real(r8), dimension(IminS:ImaxS,0:N(ng)) :: FC
180
181 real(r8), dimension(IminS:ImaxS,N(ng)) :: Hz_inv
182 real(r8), dimension(IminS:ImaxS,N(ng)) :: Hz_inv2
183 real(r8), dimension(IminS:ImaxS,N(ng)) :: Hz_inv3
184 real(r8), dimension(IminS:ImaxS,N(ng)) :: Light
185 real(r8), dimension(IminS:ImaxS,N(ng)) :: WL
186 real(r8), dimension(IminS:ImaxS,N(ng)) :: WR
187 real(r8), dimension(IminS:ImaxS,N(ng)) :: bL
188 real(r8), dimension(IminS:ImaxS,N(ng)) :: bR
189 real(r8), dimension(IminS:ImaxS,N(ng)) :: qc
190
191#include "set_bounds.h"
192!
193!-----------------------------------------------------------------------
194! Add biological Source/Sink terms.
195!-----------------------------------------------------------------------
196!
197! Avoid computing source/sink terms if no biological iterations.
198!
199 IF (bioiter(ng).le.0) RETURN
200!
201! Set time-stepping size (days) according to the number of iterations.
202!
203 dtdays=dt(ng)*sec2day/real(bioiter(ng),r8)
204
205#if defined IRON_LIMIT && defined IRON_RELAX
206!
207! Set nudging coefficient for dissolved iron over the shelf.
208!
209 fenudgcoef=dt(ng)/(fenudgtime(ng)*86400.0_r8)
210#endif
211#ifdef IRON_LIMIT
212!
213! Set Fe:N and Fe:C conversion ratio and its inverse.
214!
215 fen2fec=(16.0_r8/106.0_r8)*1.0e3_r8
216 fec2fen=(106.0_r8/16.0_r8)*1.0e-3_r8
217#endif
218!
219! Set vertical sinking indentification vector.
220!
221 idsink(1)=iphyt ! Phytoplankton
222 idsink(2)=isdet ! Small detritus
223!
224! Set vertical sinking velocity vector in the same order as the
225! identification vector, IDSINK.
226!
227 wbio(1)=wphy(ng) ! Phytoplankton
228 wbio(2)=wdet(ng) ! Small detritus
229!
230! Compute inverse thickness to avoid repeated divisions.
231!
232 j_loop : DO j=jstr,jend
233 DO k=1,n(ng)
234 DO i=istr,iend
235 hz_inv(i,k)=1.0_r8/hz(i,j,k)
236 END DO
237 END DO
238 DO k=1,n(ng)-1
239 DO i=istr,iend
240 hz_inv2(i,k)=1.0_r8/(hz(i,j,k)+hz(i,j,k+1))
241 END DO
242 END DO
243 DO k=2,n(ng)-1
244 DO i=istr,iend
245 hz_inv3(i,k)=1.0_r8/(hz(i,j,k-1)+hz(i,j,k)+hz(i,j,k+1))
246 END DO
247 END DO
248!
249! Restrict biological tracer to be positive definite. If a negative
250! concentration is detected, nitrogen is drawn from the most abundant
251! pool to supplement the negative pools to a lower limit of MinVal
252! which is set to 1E-6 above.
253!
254 DO k=1,n(ng)
255 DO i=istr,iend
256!
257! At input, all tracers (index nnew) from predictor step have
258! transport units (m Tunits) since we do not have yet the new
259! values for zeta and Hz. These are known after the 2D barotropic
260! time-stepping.
261!
262 DO itrc=1,nbt
263 ibio=idbio(itrc)
264 biotrc(ibio,nstp)=t(i,j,k,nstp,ibio)
265 biotrc(ibio,nnew)=t(i,j,k,nnew,ibio)*hz_inv(i,k)
266 END DO
267!
268! Impose positive definite concentrations.
269!
270 cff2=0.0_r8
271 DO itime=1,2
272 cff1=0.0_r8
273 itrcmax=idbio(1)
274#ifdef IRON_LIMIT
275 DO itrc=1,nbt-2
276#else
277 DO itrc=1,nbt
278#endif
279 ibio=idbio(itrc)
280 cff1=cff1+max(0.0_r8,minval-biotrc(ibio,itime))
281 IF (biotrc(ibio,itime).gt.biotrc(itrcmax,itime)) THEN
282 itrcmax=ibio
283 END IF
284 biotrc(ibio,itime)=max(minval,biotrc(ibio,itime))
285 END DO
286 IF (biotrc(itrcmax,itime).gt.cff1) THEN
287 biotrc(itrcmax,itime)=biotrc(itrcmax,itime)-cff1
288 END IF
289#ifdef IRON_LIMIT
290 DO itrc=nbt-1,nbt
291 ibio=idbio(itrc)
292 biotrc(ibio,itime)=max(minval,biotrc(ibio,itime))
293 END DO
294#endif
295 END DO
296!
297! Load biological tracers into local arrays.
298!
299 DO itrc=1,nbt
300 ibio=idbio(itrc)
301 bio_old(i,k,ibio)=biotrc(ibio,nstp)
302 bio(i,k,ibio)=biotrc(ibio,nstp)
303 END DO
304
305#if defined IRON_LIMIT && defined IRON_RELAX
306!
307! Relax dissolved iron at coast (h <= FeHim) to a constant value
308! (FeMax) over a time scale (FeNudgTime; days) to simulate sources
309! at the shelf.
310!
311 IF (h(i,j).le.fehmin(ng)) THEN
312 bio(i,k,ifdis)=bio(i,k,ifdis)+ &
313 & fenudgcoef*(femax(ng)-bio(i,k,ifdis))
314 END IF
315#endif
316 END DO
317 END DO
318!
319! Calculate surface Photosynthetically Available Radiation (PAR). The
320! net shortwave radiation is scaled back to Watts/m2 and multiplied by
321! the fraction that is photosynthetically available, PARfrac.
322!
323 DO i=istr,iend
324#ifdef CONST_PAR
325!
326! Specify constant surface irradiance a la Powell and Spitz.
327!
328 parsur(i)=158.075_r8
329#else
330 parsur(i)=parfrac(ng)*srflx(i,j)*rho0*cp
331#endif
332 END DO
333!
334!=======================================================================
335! Start internal iterations to achieve convergence of the nonlinear
336! backward-implicit solution.
337!=======================================================================
338!
339! During the iterative procedure a series of fractional time steps are
340! performed in a chained mode (splitting by different biological
341! conversion processes) in sequence of the main food chain. In all
342! stages the concentration of the component being consumed is treated
343! in a fully implicit manner, so the algorithm guarantees non-negative
344! values, no matter how strong the concentration of active consuming
345! component (Phytoplankton or Zooplankton). The overall algorithm,
346! as well as any stage of it, is formulated in conservative form
347! (except explicit sinking) in sense that the sum of concentration of
348! all components is conserved.
349!
350! In the implicit algorithm, we have for example (N: nutrient,
351! P: phytoplankton),
352!
353! N(new) = N(old) - uptake * P(old) uptake = mu * N / (Kn + N)
354! {Michaelis-Menten}
355! below, we set
356! The N in the numerator of
357! cff = mu * P(old) / (Kn + N(old)) uptake is treated implicitly
358! as N(new)
359!
360! so the time-stepping of the equations becomes:
361!
362! N(new) = N(old) / (1 + cff) (1) when substracting a sink term,
363! consuming, divide by (1 + cff)
364! and
365!
366! P(new) = P(old) + cff * N(new) (2) when adding a source term,
367! growing, add (cff * source)
368!
369! Notice that if you substitute (1) in (2), you will get:
370!
371! P(new) = P(old) + cff * N(old) / (1 + cff) (3)
372!
373! If you add (1) and (3), you get
374!
375! N(new) + P(new) = N(old) + P(old)
376!
377! implying conservation regardless how "cff" is computed. Therefore,
378! this scheme is unconditionally stable regardless of the conversion
379! rate. It does not generate negative values since the constituent
380! to be consumed is always treated implicitly. It is also biased
381! toward damping oscillations.
382!
383! The iterative loop below is to iterate toward an universal Backward-
384! Euler treatment of all terms. So if there are oscillations in the
385! system, they are only physical oscillations. These iterations,
386! however, do not improve the accuaracy of the solution.
387!
388 iter_loop: DO iter=1,bioiter(ng)
389!
390! Compute light attenuation as function of depth.
391!
392 DO i=istr,iend
393 par=parsur(i)
394 IF (parsur(i).gt.0.0_r8) THEN ! day time
395 DO k=n(ng),1,-1
396!
397! Compute average light attenuation for each grid cell. Here, AttSW is
398! the light attenuation due to seawater and AttPhy is the attenuation
399! due to phytoplankton (self-shading coefficient).
400!
401 att=(attsw(ng)+attphy(ng)*bio(i,k,iphyt))* &
402 & (z_w(i,j,k)-z_w(i,j,k-1))
403 expatt=exp(-att)
404 itop=par
405 par=itop*(1.0_r8-expatt)/att ! average at cell center
406 light(i,k)=par
407!
408! Light attenuation at the bottom of the grid cell. It is the starting
409! PAR value for the next (deeper) vertical grid cell.
410!
411 par=itop*expatt
412 END DO
413 ELSE ! night time
414 DO k=1,n(ng)
415 light(i,k)=0.0_r8
416 END DO
417 END IF
418 END DO
419!
420! Phytoplankton photosynthetic growth and nitrate uptake (Vm_NO3 rate).
421! The Michaelis-Menten curve is used to describe the change in uptake
422! rate as a function of nitrate concentration. Here, PhyIS is the
423! initial slope of the P-I curve and K_NO3 is the half saturation of
424! phytoplankton nitrate uptake.
425#ifdef IRON_LIMIT
426!
427! Growth reduction factors due to iron limitation:
428!
429! FNratio current Fe:N ratio [umol-Fe/mmol-N]
430! FCratio current Fe:C ratio [umol-Fe/mol-C]
431! (umol-Fe/mmol-N)*(16 M-N/106 M-C)*(1E3 mmol-C/mol-C)
432! FCratioE empirical Fe:C ratio
433! Flimit Phytoplankton growth reduction factor due to Fe
434! limitation based on Fe:C ratio
435!
436#endif
437!
438 cff1=dtdays*vm_no3(ng)*phyis(ng)
439 cff2=vm_no3(ng)*vm_no3(ng)
440 cff3=phyis(ng)*phyis(ng)
441 DO k=1,n(ng)
442 DO i=istr,iend
443#ifdef IRON_LIMIT
444!
445! Calculate growth reduction factor due to iron limitation.
446!
447 fnratio=bio(i,k,ifphy)/max(minval,bio(i,k,iphyt))
448 fcratio=fnratio*fen2fec
449 fcratioe=b_fe(ng)*bio(i,k,ifdis)**a_fe(ng)
450 flimit=fcratio*fcratio/ &
451 & (fcratio*fcratio+k_fec(ng)*k_fec(ng))
452!
453 nlimit=1.0_r8/(k_no3(ng)+bio(i,k,ino3_))
454 fnlim=min(1.0_r8,flimit/(bio(i,k,ino3_)*nlimit))
455#endif
456 cff4=1.0_r8/sqrt(cff2+cff3*light(i,k)*light(i,k))
457 cff=bio(i,k,iphyt)* &
458#ifdef IRON_LIMIT
459 & cff1*cff4*light(i,k)*fnlim*nlimit
460#else
461 & cff1*cff4*light(i,k)/ &
462 & (k_no3(ng)+bio(i,k,ino3_))
463#endif
464 bio(i,k,ino3_)=bio(i,k,ino3_)/(1.0_r8+cff)
465 bio(i,k,iphyt)=bio(i,k,iphyt)+ &
466 & bio(i,k,ino3_)*cff
467
468#ifdef IRON_LIMIT
469!
470! Iron uptake proportional to growth.
471!
472 fac=cff*bio(i,k,ino3_)*fnratio/max(minval,bio(i,k,ifdis))
473 bio(i,k,ifdis)=bio(i,k,ifdis)/(1.0_r8+fac)
474 bio(i,k,ifphy)=bio(i,k,ifphy)+ &
475 & bio(i,k,ifdis)*fac
476!
477! Iron uptake to reach appropriate Fe:C ratio.
478!
479 cff5=dtdays*(fcratioe-fcratio)/t_fe(ng)
480 cff6=bio(i,k,iphyt)*cff5*fec2fen
481 IF (cff6.ge.0.0_r8) THEN
482 cff=cff6/max(minval,bio(i,k,ifdis))
483 bio(i,k,ifdis)=bio(i,k,ifdis)/(1.0_r8+cff)
484 bio(i,k,ifphy)=bio(i,k,ifphy)+ &
485 & bio(i,k,ifdis)*cff
486 ELSE
487 cff=-cff6/max(minval,bio(i,k,ifphy))
488 bio(i,k,ifphy)=bio(i,k,ifphy)/(1.0_r8+cff)
489 bio(i,k,ifdis)=bio(i,k,ifdis)+ &
490 & bio(i,k,ifphy)*cff
491 END IF
492#endif
493 END DO
494 END DO
495!
496! Grazing on phytoplankton by zooplankton (ZooGR rate) using the Ivlev
497! formulation (Ivlev, 1955) and lost of phytoplankton to the nitrate
498! pool as function of "sloppy feeding" and metabolic processes
499! (ZooEEN and ZooEED fractions).
500#ifdef IRON_LIMIT
501! The lost of phytoplankton to the dissolve iron pool is scale by the
502! remineralization rate (FeRR).
503#endif
504!
505 cff1=dtdays*zoogr(ng)
506 cff2=1.0_r8-zooeen(ng)-zooeed(ng)
507 DO k=1,n(ng)
508 DO i=istr,iend
509 cff=bio(i,k,izoop)* &
510 & cff1*(1.0_r8-exp(-ivlev(ng)*bio(i,k,iphyt)))/ &
511 & bio(i,k,iphyt)
512 bio(i,k,iphyt)=bio(i,k,iphyt)/(1.0_r8+cff)
513 bio(i,k,izoop)=bio(i,k,izoop)+ &
514 & bio(i,k,iphyt)*cff2*cff
515 bio(i,k,ino3_)=bio(i,k,ino3_)+ &
516 & bio(i,k,iphyt)*zooeen(ng)*cff
517 bio(i,k,isdet)=bio(i,k,isdet)+ &
518 & bio(i,k,iphyt)*zooeed(ng)*cff
519#ifdef IRON_LIMIT
520 bio(i,k,ifphy)=bio(i,k,ifphy)/(1.0_r8+cff)
521 bio(i,k,ifdis)=bio(i,k,ifdis)+ &
522 & bio(i,k,ifphy)*cff*ferr(ng)
523#endif
524 END DO
525 END DO
526!
527! Phytoplankton mortality to nutrients (PhyMRNro rate), detritus
528! (PhyMRD rate), and if applicable dissolved iron (FeRR rate).
529!
530 cff3=dtdays*phymrd(ng)
531 cff2=dtdays*phymrn(ng)
532 cff1=1.0_r8/(1.0_r8+cff2+cff3)
533 DO k=1,n(ng)
534 DO i=istr,iend
535 bio(i,k,iphyt)=bio(i,k,iphyt)*cff1
536 bio(i,k,ino3_)=bio(i,k,ino3_)+ &
537 & bio(i,k,iphyt)*cff2
538 bio(i,k,isdet)=bio(i,k,isdet)+ &
539 & bio(i,k,iphyt)*cff3
540#ifdef IRON_LIMIT
541 bio(i,k,ifphy)=bio(i,k,ifphy)*cff1
542 bio(i,k,ifdis)=bio(i,k,ifdis)+ &
543 & bio(i,k,ifphy)*(cff2+cff3)*ferr(ng)
544#endif
545 END DO
546 END DO
547!
548! Zooplankton mortality to nutrients (ZooMRN rate) and Detritus
549! (ZooMRD rate).
550!
551 cff3=dtdays*zoomrd(ng)
552 cff2=dtdays*zoomrn(ng)
553 cff1=1.0_r8/(1.0_r8+cff2+cff3)
554 DO k=1,n(ng)
555 DO i=istr,iend
556 bio(i,k,izoop)=bio(i,k,izoop)*cff1
557 bio(i,k,ino3_)=bio(i,k,ino3_)+ &
558 & bio(i,k,izoop)*cff2
559 bio(i,k,isdet)=bio(i,k,isdet)+ &
560 & bio(i,k,izoop)*cff3
561 END DO
562 END DO
563!
564! Detritus breakdown to nutrients: remineralization (DetRR rate).
565!
566 cff2=dtdays*detrr(ng)
567 cff1=1.0_r8/(1.0_r8+cff2)
568 DO k=1,n(ng)
569 DO i=istr,iend
570 bio(i,k,isdet)=bio(i,k,isdet)*cff1
571 bio(i,k,ino3_)=bio(i,k,ino3_)+ &
572 & bio(i,k,isdet)*cff2
573 END DO
574 END DO
575!
576!-----------------------------------------------------------------------
577! Vertical sinking terms: Phytoplankton and Detritus
578!-----------------------------------------------------------------------
579!
580! Reconstruct vertical profile of selected biological constituents
581! "Bio(:,:,isink)" in terms of a set of parabolic segments within each
582! grid box. Then, compute semi-Lagrangian flux due to sinking.
583!
584 sink_loop: DO isink=1,nsink
585 ibio=idsink(isink)
586!
587! Copy concentration of biological particulates into scratch array
588! "qc" (q-central, restrict it to be positive) which is hereafter
589! interpreted as a set of grid-box averaged values for biogeochemical
590! constituent concentration.
591!
592 DO k=1,n(ng)
593 DO i=istr,iend
594 qc(i,k)=bio(i,k,ibio)
595 END DO
596 END DO
597!
598 DO k=n(ng)-1,1,-1
599 DO i=istr,iend
600 fc(i,k)=(qc(i,k+1)-qc(i,k))*hz_inv2(i,k)
601 END DO
602 END DO
603 DO k=2,n(ng)-1
604 DO i=istr,iend
605 dltr=hz(i,j,k)*fc(i,k)
606 dltl=hz(i,j,k)*fc(i,k-1)
607 cff=hz(i,j,k-1)+2.0_r8*hz(i,j,k)+hz(i,j,k+1)
608 cffr=cff*fc(i,k)
609 cffl=cff*fc(i,k-1)
610!
611! Apply PPM monotonicity constraint to prevent oscillations within the
612! grid box.
613!
614 IF ((dltr*dltl).le.0.0_r8) THEN
615 dltr=0.0_r8
616 dltl=0.0_r8
617 ELSE IF (abs(dltr).gt.abs(cffl)) THEN
618 dltr=cffl
619 ELSE IF (abs(dltl).gt.abs(cffr)) THEN
620 dltl=cffr
621 END IF
622!
623! Compute right and left side values (bR,bL) of parabolic segments
624! within grid box Hz(k); (WR,WL) are measures of quadratic variations.
625!
626! NOTE: Although each parabolic segment is monotonic within its grid
627! box, monotonicity of the whole profile is not guaranteed,
628! because bL(k+1)-bR(k) may still have different sign than
629! qc(i,k+1)-qc(i,k). This possibility is excluded,
630! after bL and bR are reconciled using WENO procedure.
631!
632 cff=(dltr-dltl)*hz_inv3(i,k)
633 dltr=dltr-cff*hz(i,j,k+1)
634 dltl=dltl+cff*hz(i,j,k-1)
635 br(i,k)=qc(i,k)+dltr
636 bl(i,k)=qc(i,k)-dltl
637 wr(i,k)=(2.0_r8*dltr-dltl)**2
638 wl(i,k)=(dltr-2.0_r8*dltl)**2
639 END DO
640 END DO
641 cff=1.0e-14_r8
642 DO k=2,n(ng)-2
643 DO i=istr,iend
644 dltl=max(cff,wl(i,k ))
645 dltr=max(cff,wr(i,k+1))
646 br(i,k)=(dltr*br(i,k)+dltl*bl(i,k+1))/(dltr+dltl)
647 bl(i,k+1)=br(i,k)
648 END DO
649 END DO
650 DO i=istr,iend
651 fc(i,n(ng))=0.0_r8 ! NO-flux boundary condition
652#if defined LINEAR_CONTINUATION
653 bl(i,n(ng))=br(i,n(ng)-1)
654 br(i,n(ng))=2.0_r8*qc(i,n(ng))-bl(i,n(ng))
655#elif defined NEUMANN
656 bl(i,n(ng))=br(i,n(ng)-1)
657 br(i,n(ng))=1.5_r8*qc(i,n(ng))-0.5_r8*bl(i,n(ng))
658#else
659 br(i,n(ng))=qc(i,n(ng)) ! default strictly monotonic
660 bl(i,n(ng))=qc(i,n(ng)) ! conditions
661 br(i,n(ng)-1)=qc(i,n(ng))
662#endif
663#if defined LINEAR_CONTINUATION
664 br(i,1)=bl(i,2)
665 bl(i,1)=2.0_r8*qc(i,1)-br(i,1)
666#elif defined NEUMANN
667 br(i,1)=bl(i,2)
668 bl(i,1)=1.5_r8*qc(i,1)-0.5_r8*br(i,1)
669#else
670 bl(i,2)=qc(i,1) ! bottom grid boxes are
671 br(i,1)=qc(i,1) ! re-assumed to be
672 bl(i,1)=qc(i,1) ! piecewise constant.
673#endif
674 END DO
675!
676! Apply monotonicity constraint again, since the reconciled interfacial
677! values may cause a non-monotonic behavior of the parabolic segments
678! inside the grid box.
679!
680 DO k=1,n(ng)
681 DO i=istr,iend
682 dltr=br(i,k)-qc(i,k)
683 dltl=qc(i,k)-bl(i,k)
684 cffr=2.0_r8*dltr
685 cffl=2.0_r8*dltl
686 IF ((dltr*dltl).lt.0.0_r8) THEN
687 dltr=0.0_r8
688 dltl=0.0_r8
689 ELSE IF (abs(dltr).gt.abs(cffl)) THEN
690 dltr=cffl
691 ELSE IF (abs(dltl).gt.abs(cffr)) THEN
692 dltl=cffr
693 END IF
694 br(i,k)=qc(i,k)+dltr
695 bl(i,k)=qc(i,k)-dltl
696 END DO
697 END DO
698!
699! After this moment reconstruction is considered complete. The next
700! stage is to compute vertical advective fluxes, FC. It is expected
701! that sinking may occurs relatively fast, the algorithm is designed
702! to be free of CFL criterion, which is achieved by allowing
703! integration bounds for semi-Lagrangian advective flux to use as
704! many grid boxes in upstream direction as necessary.
705!
706! In the two code segments below, WL is the z-coordinate of the
707! departure point for grid box interface z_w with the same indices;
708! FC is the finite volume flux; ksource(:,k) is index of vertical
709! grid box which contains the departure point (restricted by N(ng)).
710! During the search: also add in content of whole grid boxes
711! participating in FC.
712!
713 cff=dtdays*abs(wbio(isink))
714 DO k=1,n(ng)
715 DO i=istr,iend
716 fc(i,k-1)=0.0_r8
717 wl(i,k)=z_w(i,j,k-1)+cff
718 wr(i,k)=hz(i,j,k)*qc(i,k)
719 ksource(i,k)=k
720 END DO
721 END DO
722 DO k=1,n(ng)
723 DO ks=k,n(ng)-1
724 DO i=istr,iend
725 IF (wl(i,k).gt.z_w(i,j,ks)) THEN
726 ksource(i,k)=ks+1
727 fc(i,k-1)=fc(i,k-1)+wr(i,ks)
728 END IF
729 END DO
730 END DO
731 END DO
732!
733! Finalize computation of flux: add fractional part.
734!
735 DO k=1,n(ng)
736 DO i=istr,iend
737 ks=ksource(i,k)
738 cu=min(1.0_r8,(wl(i,k)-z_w(i,j,ks-1))*hz_inv(i,ks))
739 fc(i,k-1)=fc(i,k-1)+ &
740 & hz(i,j,ks)*cu* &
741 & (bl(i,ks)+ &
742 & cu*(0.5_r8*(br(i,ks)-bl(i,ks))- &
743 & (1.5_r8-cu)* &
744 & (br(i,ks)+bl(i,ks)- &
745 & 2.0_r8*qc(i,ks))))
746 END DO
747 END DO
748 DO k=1,n(ng)
749 DO i=istr,iend
750 bio(i,k,ibio)=qc(i,k)+(fc(i,k)-fc(i,k-1))*hz_inv(i,k)
751 END DO
752 END DO
753
754 END DO sink_loop
755 END DO iter_loop
756!
757!-----------------------------------------------------------------------
758! Update global tracer variables: Add increment due to BGC processes
759! to tracer array in time index "nnew". Index "nnew" is solution after
760! advection and mixing and has transport units (m Tunits) hence the
761! increment is multiplied by Hz. Notice that we need to subtract
762! original values "Bio_old" at the top of the routine to just account
763! for the concentractions affected by BGC processes. This also takes
764! into account any constraints (non-negative concentrations, carbon
765! concentration range) specified before entering BGC kernel. If "Bio"
766! were unchanged by BGC processes, the increment would be exactly
767! zero. Notice that final tracer values, t(:,:,:,nnew,:) are not
768! bounded >=0 so that we can preserve total inventory of nutrients
769! when advection causes tracer concentration to go negative.
770!-----------------------------------------------------------------------
771!
772 DO itrc=1,nbt
773 ibio=idbio(itrc)
774 DO k=1,n(ng)
775 DO i=istr,iend
776 cff=bio(i,k,ibio)-bio_old(i,k,ibio)
777 t(i,j,k,nnew,ibio)=t(i,j,k,nnew,ibio)+cff*hz(i,j,k)
778 END DO
779 END DO
780 END DO
781
782 END DO j_loop
783!
784 RETURN
785 END SUBROUTINE npzd_iron_tile
786
787 END MODULE biology_mod
subroutine, public biology(ng, tile)
Definition ecosim.h:57
subroutine npzd_iron_tile(ng, tile, lbi, ubi, lbj, ubj, ubk, ubt, imins, imaxs, jmins, jmaxs, nstp, nnew, rmask, h, hz, z_r, z_w, srflx, t)
Definition npzd_iron.h:105
real(r8), dimension(:), allocatable parfrac
Definition fennel_mod.h:139
real(r8), dimension(:), allocatable phymrd
real(r8), dimension(:), allocatable zooeed
integer ifphy
real(r8), dimension(:), allocatable detrr
real(r8), dimension(:), allocatable ferr
real(r8), dimension(:), allocatable wdet
integer, dimension(:), allocatable bioiter
Definition ecosim_mod.h:343
real(r8), dimension(:), allocatable phyis
Definition fennel_mod.h:143
real(r8), dimension(:), allocatable attsw
Definition fennel_mod.h:125
real(r8), dimension(:), allocatable a_fe
integer ino3_
Definition ecosim_mod.h:277
real(r8), dimension(:), allocatable zoogr
Definition fennel_mod.h:160
integer ifdis
real(r8), dimension(:), allocatable k_no3
Definition fennel_mod.h:133
integer iphyt
Definition fennel_mod.h:81
real(r8), dimension(:), allocatable fenudgtime
real(r8), dimension(:), allocatable ivlev
real(r8), dimension(:), allocatable attphy
real(r8), dimension(:), allocatable b_fe
integer, dimension(:), allocatable idbio
Definition ecosim_mod.h:256
real(r8), dimension(:), allocatable wphy
Definition fennel_mod.h:154
real(r8), dimension(:), allocatable vm_no3
real(r8), dimension(:), allocatable fehmin
real(r8), dimension(:), allocatable k_fec
real(r8), dimension(:), allocatable t_fe
real(r8), dimension(:), allocatable zoomrn
real(r8), dimension(:), allocatable femax
real(r8), dimension(:), allocatable phymrn
integer izoop
Definition fennel_mod.h:82
real(r8), dimension(:), allocatable zoomrd
real(r8), dimension(:), allocatable zooeen
type(t_forces), dimension(:), allocatable forces
Definition mod_forces.F:554
type(t_grid), dimension(:), allocatable grid
Definition mod_grid.F:365
type(t_ocean), dimension(:), allocatable ocean
Definition mod_ocean.F:351
integer, parameter inlm
Definition mod_param.F:662
integer, dimension(:), allocatable n
Definition mod_param.F:479
integer nbt
Definition mod_param.F:509
integer, dimension(:), allocatable nt
Definition mod_param.F:489
real(dp), dimension(:), allocatable dt
real(dp) cp
real(dp), parameter sec2day
real(dp) rho0
integer, dimension(:), allocatable nnew
integer, dimension(:), allocatable nstp
recursive subroutine wclock_off(ng, model, region, line, routine)
Definition timers.F:148
recursive subroutine wclock_on(ng, model, region, line, routine)
Definition timers.F:3