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 branches/UKMO/r6232_tracer_advection/NEMOGCM/NEMO/OPA_SRC/SBC – NEMO

source: branches/UKMO/r6232_tracer_advection/NEMOGCM/NEMO/OPA_SRC/SBC/sbcdcy.F90 @ 9295

Last change on this file since 9295 was 9295, checked in by jcastill, 6 years ago

Remove svn keywords

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