New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
sbcdcy.F90 in NEMO/branches/2020/dev_r13383_HPC-02_Daley_Tiling/src/OCE/SBC – NEMO

source: NEMO/branches/2020/dev_r13383_HPC-02_Daley_Tiling/src/OCE/SBC/sbcdcy.F90 @ 13553

Last change on this file since 13553 was 13553, checked in by hadcv, 3 years ago

Merge in trunk up to [13550]

  • Property svn:keywords set to Id
File size: 12.5 KB
Line 
1MODULE sbcdcy
2   !!======================================================================
3   !!                    ***  MODULE  sbcdcy  ***
4   !! Ocean forcing:  compute the diurnal cycle
5   !!======================================================================
6   !! History : OPA  !  2005-02  (D. Bernie)  Original code
7   !!   NEMO    2.0  !  2006-02  (S. Masson, G. Madec)  adaptation to NEMO
8   !!           3.1  !  2009-07  (J.M. Molines)  adaptation to v3.1
9   !!           4.*  !  2019-10  (L. Brodeau)  nothing really new, but the routine
10   !!                ! "sbc_dcy_param" has been extracted from old function "sbc_dcy"
11   !!                ! => this allows the warm-layer param of COARE3* to know the time
12   !!                ! of dawn and dusk even if "ln_dm2dc=.false." (rdawn_dcy & rdusk_dcy
13   !!                ! are now public)
14   !!----------------------------------------------------------------------
15
16   !!----------------------------------------------------------------------
17   !!  sbc_dcy : solar flux at kt from daily mean, taking diurnal cycle into account
18   !!----------------------------------------------------------------------
19   USE oce              ! ocean dynamics and tracers
20   USE phycst           ! ocean physics
21   USE dom_oce          ! ocean space and time domain
22   USE sbc_oce          ! Surface boundary condition: ocean fields
23   !
24   USE in_out_manager   ! I/O manager
25   USE lib_mpp          ! MPP library
26
27   IMPLICIT NONE
28   PRIVATE
29
30   INTEGER, PUBLIC ::   nday_qsr   !: day when parameters were computed
31
32   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   raa , rbb  , rcc  , rab     ! diurnal cycle parameters
33   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:) ::   rtmd, rscal   !    -      -       -
34   REAL(wp), ALLOCATABLE, SAVE, DIMENSION(:,:), PUBLIC :: rdawn_dcy, rdusk_dcy   !    -      -       -
35
36   PUBLIC   sbc_dcy        ! routine called by sbc
37   PUBLIC   sbc_dcy_param  ! routine used here and called by warm-layer parameterization (sbcblk_skin_coare*)
38
39   !! * Substitutions
40#  include "do_loop_substitute.h90"
41   !!----------------------------------------------------------------------
42   !! NEMO/OCE 4.0 , NEMO Consortium (2018)
43   !! $Id$
44   !! Software governed by the CeCILL license (see ./LICENSE)
45   !!----------------------------------------------------------------------
46CONTAINS
47
48   INTEGER FUNCTION sbc_dcy_alloc()
49      !!----------------------------------------------------------------------
50      !!                ***  FUNCTION sbc_dcy_alloc  ***
51      !!----------------------------------------------------------------------
52      ALLOCATE( raa (jpi,jpj) , rbb  (jpi,jpj) , rcc  (jpi,jpj) , rab  (jpi,jpj) ,     &
53         &      rtmd(jpi,jpj) , rdawn_dcy(jpi,jpj) , rdusk_dcy(jpi,jpj) , rscal(jpi,jpj) , STAT=sbc_dcy_alloc )
54      !
55      CALL mpp_sum ( 'sbcdcy', sbc_dcy_alloc )
56      IF( sbc_dcy_alloc /= 0 )   CALL ctl_stop( 'STOP', 'sbc_dcy_alloc: failed to allocate arrays' )
57   END FUNCTION sbc_dcy_alloc
58
59
60   FUNCTION sbc_dcy( pqsrin, l_mask ) RESULT( zqsrout )
61      !!----------------------------------------------------------------------
62      !!                  ***  ROUTINE sbc_dcy  ***
63      !!
64      !! ** Purpose : introduce a diurnal cycle of qsr from daily values
65      !!
66      !! ** Method  : see Appendix A of Bernie et al. 2007.
67      !!
68      !! ** Action  : redistribute daily QSR on each time step following the diurnal cycle
69      !!
70      !! reference  : Bernie, DJ, E Guilyardi, G Madec, JM Slingo, and SJ Woolnough, 2007
71      !!              Impact of resolving the diurnal cycle in an ocean--atmosphere GCM.
72      !!              Part 1: a diurnally forced OGCM. Climate Dynamics 29:6, 575-590.
73      !!----------------------------------------------------------------------
74      LOGICAL , OPTIONAL          , INTENT(in) ::   l_mask    ! use the routine for night mask computation
75      REAL(wp), DIMENSION(jpi,jpj), INTENT(in) ::   pqsrin    ! input daily QSR flux
76      REAL(wp), DIMENSION(jpi,jpj)             ::   zqsrout   ! output QSR flux with diurnal cycle
77      !!
78      INTEGER  ::   ji, jj                                       ! dummy loop indices
79      INTEGER, DIMENSION(jpi,jpj) :: imask_night ! night mask
80      REAL(wp) ::   zlo, zup, zlousd, zupusd
81      REAL(wp) ::   ztmp, ztmp1, ztmp2
82      REAL(wp) ::   ztmpm, ztmpm1, ztmpm2
83      !!---------------------------------------------------------------------
84      !
85      ! Initialization
86      ! --------------
87      ! When are we during the day (from 0 to 1)
88      zlo = ( REAL(nsec_day, wp) - 0.5_wp * rn_Dt ) / rday
89      zup = zlo + ( REAL(nn_fsbc, wp)     * rn_Dt ) / rday
90      !
91      IF( nday_qsr == -1 ) THEN       ! first time step only
92         IF(lwp) THEN
93            WRITE(numout,*)
94            WRITE(numout,*) 'sbc_dcy : introduce diurnal cycle from daily mean qsr'
95            WRITE(numout,*) '~~~~~~~'
96            WRITE(numout,*)
97         ENDIF
98      ENDIF
99
100      ! Setting parameters for each new day:
101      CALL sbc_dcy_param()
102
103      !CALL iom_put( "rdusk_dcy", rdusk_dcy(:,:)*tmask(:,:,1) ) !LB
104      !CALL iom_put( "rdawn_dcy", rdawn_dcy(:,:)*tmask(:,:,1) ) !LB
105      !CALL iom_put( "rscal_dcy", rscal(:,:)*tmask(:,:,1) ) !LB
106
107
108      !     3. update qsr with the diurnal cycle
109      !     ------------------------------------
110
111      imask_night(:,:) = 0
112      DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
113         ztmpm = 0._wp
114         IF( ABS(rab(ji,jj)) < 1. ) THEN         ! day duration is less than 24h
115            !
116            IF( rdawn_dcy(ji,jj) < rdusk_dcy(ji,jj) ) THEN       ! day time in one part
117               zlousd = MAX(zlo, rdawn_dcy(ji,jj))
118               zlousd = MIN(zlousd, zup)
119               zupusd = MIN(zup, rdusk_dcy(ji,jj))
120               zupusd = MAX(zupusd, zlo)
121               ztmp = fintegral(zlousd, zupusd, raa(ji,jj), rbb(ji,jj), rcc(ji,jj))
122               zqsrout(ji,jj) = pqsrin(ji,jj) * ztmp * rscal(ji,jj)
123               ztmpm = zupusd - zlousd
124               IF( ztmpm .EQ. 0 ) imask_night(ji,jj) = 1
125               !
126            ELSE                                         ! day time in two parts
127               zlousd = MIN(zlo, rdusk_dcy(ji,jj))
128               zupusd = MIN(zup, rdusk_dcy(ji,jj))
129               ztmp1 = fintegral(zlousd, zupusd, raa(ji,jj), rbb(ji,jj), rcc(ji,jj))
130               ztmpm1=zupusd-zlousd
131               zlousd = MAX(zlo, rdawn_dcy(ji,jj))
132               zupusd = MAX(zup, rdawn_dcy(ji,jj))
133               ztmp2 = fintegral(zlousd, zupusd, raa(ji,jj), rbb(ji,jj), rcc(ji,jj))
134               ztmpm2 =zupusd-zlousd
135               ztmp = ztmp1 + ztmp2
136               ztmpm = ztmpm1 + ztmpm2
137               zqsrout(ji,jj) = pqsrin(ji,jj) * ztmp * rscal(ji,jj)
138               IF(ztmpm .EQ. 0.) imask_night(ji,jj) = 1
139            ENDIF
140         ELSE                                   ! 24h light or 24h night
141            !
142            IF( raa(ji,jj) > rbb(ji,jj) ) THEN           ! 24h day
143               ztmp = fintegral(zlo, zup, raa(ji,jj), rbb(ji,jj), rcc(ji,jj))
144               zqsrout(ji,jj) = pqsrin(ji,jj) * ztmp * rscal(ji,jj)
145               imask_night(ji,jj) = 0
146               !
147            ELSE                                         ! No day
148               zqsrout(ji,jj) = 0.0_wp
149               imask_night(ji,jj) = 1
150            ENDIF
151         ENDIF
152      END_2D
153      !
154      IF( PRESENT(l_mask) .AND. l_mask ) THEN
155         zqsrout(:,:) = float(imask_night(:,:))
156      ENDIF
157      !
158   END FUNCTION sbc_dcy
159
160
161   SUBROUTINE sbc_dcy_param( )
162      !!
163      INTEGER  ::   ji, jj                                       ! dummy loop indices
164      !INTEGER, DIMENSION(jpi,jpj) :: imask_night ! night mask
165      REAL(wp) ::   zdsws, zdecrad, ztx, zsin, zcos
166      REAL(wp) ::   ztmp, ztest
167      !---------------------------statement functions------------------------
168      !
169      IF( nday_qsr == -1 ) THEN       ! first time step only
170         ! allocate sbcdcy arrays
171         IF( sbc_dcy_alloc() /= 0 )   CALL ctl_stop( 'STOP', 'sbc_dcy_alloc : unable to allocate arrays' )
172         ! Compute rcc needed to compute the time integral of the diurnal cycle
173         rcc(:,:) = rad * glamt(:,:) - rpi
174         ! time of midday
175         rtmd(:,:) = 0.5_wp - glamt(:,:) / 360._wp
176         rtmd(:,:) = MOD( (rtmd(:,:) + 1._wp) , 1._wp)
177      ENDIF
178
179      ! If this is a new day, we have to update the dawn, dusk and scaling function
180      !----------------------
181
182      !     2.1 dawn and dusk
183
184      ! nday is the number of days since the beginning of the current month
185      IF( nday_qsr /= nday ) THEN
186         ! save the day of the year and the daily mean of qsr
187         nday_qsr = nday
188         ! number of days since the previous winter solstice (supposed to be always 21 December)
189         zdsws = REAL(11 + nday_year, wp)
190         ! declination of the earths orbit
191         zdecrad = (-23.5_wp * rad) * COS( zdsws * 2._wp*rpi / REAL(nyear_len(1),wp) )
192         ! Compute A and B needed to compute the time integral of the diurnal cycle
193
194         zsin = SIN( zdecrad )   ;   zcos = COS( zdecrad )
195         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
196            ztmp = rad * gphit(ji,jj)
197            raa(ji,jj) = SIN( ztmp ) * zsin
198            rbb(ji,jj) = COS( ztmp ) * zcos
199         END_2D
200         ! Compute the time of dawn and dusk
201
202         ! rab to test if the day time is equal to 0, less than 24h of full day
203         rab(:,:) = -raa(:,:) / rbb(:,:)
204         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
205            IF( ABS(rab(ji,jj)) < 1._wp ) THEN         ! day duration is less than 24h
206               ! When is it night?
207               ztx = 1._wp/(2._wp*rpi) * (ACOS(rab(ji,jj)) - rcc(ji,jj))
208               ztest = -rbb(ji,jj) * SIN( rcc(ji,jj) + 2._wp*rpi * ztx )
209               ! is it dawn or dusk?
210               IF( ztest > 0._wp ) THEN
211                  rdawn_dcy(ji,jj) = ztx
212                  rdusk_dcy(ji,jj) = rtmd(ji,jj) + ( rtmd(ji,jj) - rdawn_dcy(ji,jj) )
213               ELSE
214                  rdusk_dcy(ji,jj) = ztx
215                  rdawn_dcy(ji,jj) = rtmd(ji,jj) - ( rdusk_dcy(ji,jj) - rtmd(ji,jj) )
216               ENDIF
217            ELSE
218               rdawn_dcy(ji,jj) = rtmd(ji,jj) + 0.5_wp
219               rdusk_dcy(ji,jj) = rdawn_dcy(ji,jj)
220            ENDIF
221         END_2D
222         rdawn_dcy(:,:) = MOD( (rdawn_dcy(:,:) + 1._wp), 1._wp )
223         rdusk_dcy(:,:) = MOD( (rdusk_dcy(:,:) + 1._wp), 1._wp )
224         !     2.2 Compute the scaling function:
225         !         S* = the inverse of the time integral of the diurnal cycle from dawn to dusk
226         !         Avoid possible infinite scaling factor, associated with very short daylight
227         !         periods, by ignoring periods less than 1/1000th of a day (ticket #1040)
228         DO_2D( nn_hls, nn_hls, nn_hls, nn_hls )
229            IF( ABS(rab(ji,jj)) < 1._wp ) THEN         ! day duration is less than 24h
230               rscal(ji,jj) = 0.0_wp
231               IF( rdawn_dcy(ji,jj) < rdusk_dcy(ji,jj) ) THEN      ! day time in one part
232                  IF( (rdusk_dcy(ji,jj) - rdawn_dcy(ji,jj) ) .ge. 0.001_wp ) THEN
233                     rscal(ji,jj) = fintegral(rdawn_dcy(ji,jj), rdusk_dcy(ji,jj), raa(ji,jj), rbb(ji,jj), rcc(ji,jj))
234                     rscal(ji,jj) = 1._wp / rscal(ji,jj)
235                  ENDIF
236               ELSE                                         ! day time in two parts
237                  IF( (rdusk_dcy(ji,jj) + (1._wp - rdawn_dcy(ji,jj)) ) .ge. 0.001_wp ) THEN
238                     rscal(ji,jj) = fintegral(0._wp, rdusk_dcy(ji,jj), raa(ji,jj), rbb(ji,jj), rcc(ji,jj))   &
239                        &         + fintegral(rdawn_dcy(ji,jj), 1._wp, raa(ji,jj), rbb(ji,jj), rcc(ji,jj))
240                     rscal(ji,jj) = 1. / rscal(ji,jj)
241                  ENDIF
242               ENDIF
243            ELSE
244               IF( raa(ji,jj) > rbb(ji,jj) ) THEN         ! 24h day
245                  rscal(ji,jj) = fintegral(0._wp, 1._wp, raa(ji,jj), rbb(ji,jj), rcc(ji,jj))
246                  rscal(ji,jj) = 1._wp / rscal(ji,jj)
247               ELSE                                          ! No day
248                  rscal(ji,jj) = 0.0_wp
249               ENDIF
250            ENDIF
251         END_2D
252         !
253         ztmp = rday / ( rn_Dt * REAL(nn_fsbc, wp) )
254         rscal(:,:) = rscal(:,:) * ztmp
255         !
256      ENDIF !IF( nday_qsr /= nday )
257      !
258   END SUBROUTINE sbc_dcy_param
259
260
261   FUNCTION fintegral( pt1, pt2, paaa, pbbb, pccc )
262      REAL(wp), INTENT(in) :: pt1, pt2, paaa, pbbb, pccc
263      REAL(wp) :: fintegral
264      fintegral =   paaa * pt2 + 1._wp/(2._wp*rpi) * pbbb * SIN(pccc + 2._wp*rpi*pt2)   &
265         &        - paaa * pt1 - 1._wp/(2._wp*rpi) * pbbb * SIN(pccc + 2._wp*rpi*pt1)
266   END FUNCTION fintegral
267
268   !!======================================================================
269END MODULE sbcdcy
Note: See TracBrowser for help on using the repository browser.