sbcdcy.F90 12 KB

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