123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407 |
- MODULE diahsb
- !!======================================================================
- !! *** MODULE diahsb ***
- !! Ocean diagnostics: Heat, salt and volume budgets
- !!======================================================================
- !! History : 3.3 ! 2010-09 (M. Leclair) Original code
- !! ! 2012-10 (C. Rousset) add iom_put
- !!----------------------------------------------------------------------
- !!----------------------------------------------------------------------
- !! dia_hsb : Diagnose the conservation of ocean heat and salt contents, and volume
- !! dia_hsb_rst : Read or write DIA file in restart file
- !! dia_hsb_init : Initialization of the conservation diagnostic
- !!----------------------------------------------------------------------
- USE oce ! ocean dynamics and tracers
- USE dom_oce ! ocean space and time domain
- USE phycst ! physical constants
- USE sbc_oce ! surface thermohaline fluxes
- USE sbcrnf ! river runoff
- USE sbcisf ! ice shelves
- USE domvvl ! vertical scale factors
- USE traqsr ! penetrative solar radiation
- USE trabbc ! bottom boundary condition
- USE trabbc ! bottom boundary condition
- USE bdy_par ! (for lk_bdy)
- USE restart ! ocean restart
- !
- USE iom ! I/O manager
- USE in_out_manager ! I/O manager
- USE lib_fortran ! glob_sum
- USE lib_mpp ! distributed memory computing library
- USE timing ! preformance summary
- USE wrk_nemo ! work arrays
- IMPLICIT NONE
- PRIVATE
- PUBLIC dia_hsb ! routine called by step.F90
- PUBLIC dia_hsb_init ! routine called by nemogcm.F90
- LOGICAL, PUBLIC :: ln_diahsb !: check the heat and salt budgets
- REAL(wp) :: surf_tot ! ocean surface
- REAL(wp) :: frc_t, frc_s, frc_v ! global forcing trends
- REAL(wp) :: frc_wn_t, frc_wn_s ! global forcing trends
- !
- REAL(wp), DIMENSION(:,:) , ALLOCATABLE :: surf , ssh_ini !
- REAL(wp), DIMENSION(:,:) , ALLOCATABLE :: ssh_hc_loc_ini, ssh_sc_loc_ini !
- REAL(wp), DIMENSION(:,:,:), ALLOCATABLE :: hc_loc_ini, sc_loc_ini, e3t_ini !
- !! * Substitutions
- # include "domzgr_substitute.h90"
- # include "vectopt_loop_substitute.h90"
- !!----------------------------------------------------------------------
- !! NEMO/OPA 3.3 , NEMO Consortium (2010)
- !! $Id: diahsb.F90 5628 2015-07-22 20:26:35Z mathiot $
- !! Software governed by the CeCILL licence (NEMOGCM/NEMO_CeCILL.txt)
- !!----------------------------------------------------------------------
- CONTAINS
- SUBROUTINE dia_hsb( kt )
- !!---------------------------------------------------------------------------
- !! *** ROUTINE dia_hsb ***
- !!
- !! ** Purpose: Compute the ocean global heat content, salt content and volume conservation
- !!
- !! ** Method : - Compute the deviation of heat content, salt content and volume
- !! at the current time step from their values at nit000
- !! - Compute the contribution of forcing and remove it from these deviations
- !!
- !!---------------------------------------------------------------------------
- INTEGER, INTENT(in) :: kt ! ocean time-step index
- !
- INTEGER :: ji, jj, jk ! dummy loop indice
- REAL(wp) :: zdiff_hc , zdiff_sc ! heat and salt content variations
- REAL(wp) :: zdiff_hc1 , zdiff_sc1 ! - - - -
- REAL(wp) :: zdiff_v1 , zdiff_v2 ! volume variation
- REAL(wp) :: zerr_hc1 , zerr_sc1 ! heat and salt content misfit
- REAL(wp) :: zvol_tot ! volume
- REAL(wp) :: z_frc_trd_t , z_frc_trd_s ! - -
- REAL(wp) :: z_frc_trd_v ! - -
- REAL(wp) :: z_wn_trd_t , z_wn_trd_s ! - -
- REAL(wp) :: z_ssh_hc , z_ssh_sc ! - -
- REAL(wp), DIMENSION(:,:), POINTER :: z2d0, z2d1
- !!---------------------------------------------------------------------------
- IF( nn_timing == 1 ) CALL timing_start('dia_hsb')
- !
- CALL wrk_alloc( jpi,jpj, z2d0, z2d1 )
- !
- tsn(:,:,:,1) = tsn(:,:,:,1) * tmask(:,:,:) ; tsb(:,:,:,1) = tsb(:,:,:,1) * tmask(:,:,:) ;
- tsn(:,:,:,2) = tsn(:,:,:,2) * tmask(:,:,:) ; tsb(:,:,:,2) = tsb(:,:,:,2) * tmask(:,:,:) ;
- ! ------------------------- !
- ! 1 - Trends due to forcing !
- ! ------------------------- !
- z_frc_trd_v = r1_rau0 * glob_sum( - ( emp(:,:) - rnf(:,:) + fwfisf(:,:) ) * surf(:,:) ) ! volume fluxes
- z_frc_trd_t = glob_sum( sbc_tsc(:,:,jp_tem) * surf(:,:) ) ! heat fluxes
- z_frc_trd_s = glob_sum( sbc_tsc(:,:,jp_sal) * surf(:,:) ) ! salt fluxes
- ! Add runoff heat & salt input
- IF( ln_rnf ) z_frc_trd_t = z_frc_trd_t + glob_sum( rnf_tsc(:,:,jp_tem) * surf(:,:) )
- IF( ln_rnf_sal) z_frc_trd_s = z_frc_trd_s + glob_sum( rnf_tsc(:,:,jp_sal) * surf(:,:) )
- ! Add ice shelf heat & salt input
- IF( nn_isf .GE. 1 ) THEN
- z_frc_trd_t = z_frc_trd_t + glob_sum( risf_tsc(:,:,jp_tem) * surf(:,:) )
- z_frc_trd_s = z_frc_trd_s + glob_sum( risf_tsc(:,:,jp_sal) * surf(:,:) )
- ENDIF
- ! Add penetrative solar radiation
- IF( ln_traqsr ) z_frc_trd_t = z_frc_trd_t + r1_rau0_rcp * glob_sum( qsr (:,:) * surf(:,:) )
- ! Add geothermal heat flux
- IF( ln_trabbc ) z_frc_trd_t = z_frc_trd_t + glob_sum( qgh_trd0(:,:) * surf(:,:) )
- !
- IF( .NOT. lk_vvl ) THEN
- IF ( ln_isfcav ) THEN
- DO ji=1,jpi
- DO jj=1,jpj
- z2d0(ji,jj) = surf(ji,jj) * wn(ji,jj,mikt(ji,jj)) * tsb(ji,jj,mikt(ji,jj),jp_tem)
- z2d1(ji,jj) = surf(ji,jj) * wn(ji,jj,mikt(ji,jj)) * tsb(ji,jj,mikt(ji,jj),jp_sal)
- ENDDO
- ENDDO
- ELSE
- z2d0(:,:) = surf(:,:) * wn(:,:,1) * tsb(:,:,1,jp_tem)
- z2d1(:,:) = surf(:,:) * wn(:,:,1) * tsb(:,:,1,jp_sal)
- END IF
- z_wn_trd_t = - glob_sum( z2d0 )
- z_wn_trd_s = - glob_sum( z2d1 )
- ENDIF
- frc_v = frc_v + z_frc_trd_v * rdt
- frc_t = frc_t + z_frc_trd_t * rdt
- frc_s = frc_s + z_frc_trd_s * rdt
- ! ! Advection flux through fixed surface (z=0)
- IF( .NOT. lk_vvl ) THEN
- frc_wn_t = frc_wn_t + z_wn_trd_t * rdt
- frc_wn_s = frc_wn_s + z_wn_trd_s * rdt
- ENDIF
- ! ------------------------ !
- ! 2 - Content variations !
- ! ------------------------ !
- zdiff_v2 = 0._wp
- zdiff_hc = 0._wp
- zdiff_sc = 0._wp
- ! volume variation (calculated with ssh)
- zdiff_v1 = glob_sum( surf(:,:) * ( sshn(:,:) - ssh_ini(:,:) ) )
- ! heat & salt content variation (associated with ssh)
- IF( .NOT. lk_vvl ) THEN
- IF ( ln_isfcav ) THEN
- DO ji = 1, jpi
- DO jj = 1, jpj
- z2d0(ji,jj) = surf(ji,jj) * ( tsn(ji,jj,mikt(ji,jj),jp_tem) * sshn(ji,jj) - ssh_hc_loc_ini(ji,jj) )
- z2d1(ji,jj) = surf(ji,jj) * ( tsn(ji,jj,mikt(ji,jj),jp_sal) * sshn(ji,jj) - ssh_sc_loc_ini(ji,jj) )
- END DO
- END DO
- ELSE
- z2d0(:,:) = surf(:,:) * ( tsn(:,:,1,jp_tem) * sshn(:,:) - ssh_hc_loc_ini(:,:) )
- z2d1(:,:) = surf(:,:) * ( tsn(:,:,1,jp_sal) * sshn(:,:) - ssh_sc_loc_ini(:,:) )
- END IF
- z_ssh_hc = glob_sum( z2d0 )
- z_ssh_sc = glob_sum( z2d1 )
- ENDIF
- DO jk = 1, jpkm1
- ! volume variation (calculated with scale factors)
- zdiff_v2 = zdiff_v2 + glob_sum( surf(:,:) * tmask(:,:,jk) &
- & * ( fse3t_n(:,:,jk) - e3t_ini(:,:,jk) ) )
- ! heat content variation
- zdiff_hc = zdiff_hc + glob_sum( surf(:,:) * tmask(:,:,jk) &
- & * ( fse3t_n(:,:,jk) * tsn(:,:,jk,jp_tem) - hc_loc_ini(:,:,jk) ) )
- ! salt content variation
- zdiff_sc = zdiff_sc + glob_sum( surf(:,:) * tmask(:,:,jk) &
- & * ( fse3t_n(:,:,jk) * tsn(:,:,jk,jp_sal) - sc_loc_ini(:,:,jk) ) )
- ENDDO
- ! ------------------------ !
- ! 3 - Drifts !
- ! ------------------------ !
- zdiff_v1 = zdiff_v1 - frc_v
- IF( lk_vvl ) zdiff_v2 = zdiff_v2 - frc_v
- zdiff_hc = zdiff_hc - frc_t
- zdiff_sc = zdiff_sc - frc_s
- IF( .NOT. lk_vvl ) THEN
- zdiff_hc1 = zdiff_hc + z_ssh_hc
- zdiff_sc1 = zdiff_sc + z_ssh_sc
- zerr_hc1 = z_ssh_hc - frc_wn_t
- zerr_sc1 = z_ssh_sc - frc_wn_s
- ENDIF
- ! ----------------------- !
- ! 4 - Diagnostics writing !
- ! ----------------------- !
- zvol_tot = 0._wp ! total ocean volume (calculated with scale factors)
- DO jk = 1, jpkm1
- zvol_tot = zvol_tot + glob_sum( surf(:,:) * tmask(:,:,jk) * fse3t_n(:,:,jk) )
- END DO
- !!gm to be added ?
- ! IF( .NOT. lk_vvl ) THEN ! fixed volume, add the ssh contribution
- ! zvol_tot = zvol_tot + glob_sum( surf(:,:) * sshn(:,:) )
- ! ENDIF
- !!gm end
- CALL iom_put( 'bgfrcvol' , frc_v * 1.e-9 ) ! vol - surface forcing (km3)
- CALL iom_put( 'bgfrctem' , frc_t * rau0 * rcp * 1.e-20 ) ! hc - surface forcing (1.e20 J)
- CALL iom_put( 'bgfrchfx' , frc_t * rau0 * rcp / & ! hc - surface forcing (W/m2)
- & ( surf_tot * kt * rdt ) )
- CALL iom_put( 'bgfrcsal' , frc_s * 1.e-9 ) ! sc - surface forcing (psu*km3)
- IF( lk_vvl ) THEN
- CALL iom_put( 'bgtemper' , zdiff_hc / zvol_tot ) ! Temperature drift (C)
- CALL iom_put( 'bgsaline' , zdiff_sc / zvol_tot ) ! Salinity drift (pss)
- CALL iom_put( 'bgheatco' , zdiff_hc * 1.e-20 * rau0 * rcp ) ! Heat content drift (1.e20 J)
- CALL iom_put( 'bgheatfx' , zdiff_hc * rau0 * rcp / & ! Heat flux drift (W/m2)
- & ( surf_tot * kt * rdt ) )
- CALL iom_put( 'bgsaltco' , zdiff_sc * 1.e-9 ) ! Salt content drift (psu*km3)
- CALL iom_put( 'bgvolssh' , zdiff_v1 * 1.e-9 ) ! volume ssh drift (km3)
- CALL iom_put( 'bgvole3t' , zdiff_v2 * 1.e-9 ) ! volume e3t drift (km3)
- ELSE
- CALL iom_put( 'bgtemper' , zdiff_hc1 / zvol_tot) ! Heat content drift (C)
- CALL iom_put( 'bgsaline' , zdiff_sc1 / zvol_tot) ! Salt content drift (pss)
- CALL iom_put( 'bgheatco' , zdiff_hc1 * 1.e-20 * rau0 * rcp ) ! Heat content drift (1.e20 J)
- CALL iom_put( 'bgheatfx' , zdiff_hc1 * rau0 * rcp / & ! Heat flux drift (W/m2)
- & ( surf_tot * kt * rdt ) )
- CALL iom_put( 'bgsaltco' , zdiff_sc1 * 1.e-9 ) ! Salt content drift (psu*km3)
- CALL iom_put( 'bgvolssh' , zdiff_v1 * 1.e-9 ) ! volume ssh drift (km3)
- CALL iom_put( 'bgmistem' , zerr_hc1 / zvol_tot ) ! hc - error due to free surface (C)
- CALL iom_put( 'bgmissal' , zerr_sc1 / zvol_tot ) ! sc - error due to free surface (psu)
- ENDIF
- !
- IF( lrst_oce ) CALL dia_hsb_rst( kt, 'WRITE' )
- CALL wrk_dealloc( jpi,jpj, z2d0, z2d1 )
- IF( nn_timing == 1 ) CALL timing_stop('dia_hsb')
- !
- END SUBROUTINE dia_hsb
- SUBROUTINE dia_hsb_rst( kt, cdrw )
- !!---------------------------------------------------------------------
- !! *** ROUTINE limdia_rst ***
- !!
- !! ** Purpose : Read or write DIA file in restart file
- !!
- !! ** Method : use of IOM library
- !!----------------------------------------------------------------------
- INTEGER , INTENT(in) :: kt ! ocean time-step
- CHARACTER(len=*), INTENT(in) :: cdrw ! "READ"/"WRITE" flag
- !
- INTEGER :: ji, jj, jk ! dummy loop indices
- !!----------------------------------------------------------------------
- !
- IF( TRIM(cdrw) == 'READ' ) THEN ! Read/initialise
- IF( ln_rstart ) THEN !* Read the restart file
- !
- IF(lwp) WRITE(numout,*) '~~~~~~~'
- IF(lwp) WRITE(numout,*) ' dia_hsb_rst at it= ', kt,' date= ', ndastp
- IF(lwp) WRITE(numout,*) '~~~~~~~'
- CALL iom_get( numror, 'frc_v', frc_v )
- CALL iom_get( numror, 'frc_t', frc_t )
- CALL iom_get( numror, 'frc_s', frc_s )
- IF( .NOT. lk_vvl ) THEN
- CALL iom_get( numror, 'frc_wn_t', frc_wn_t )
- CALL iom_get( numror, 'frc_wn_s', frc_wn_s )
- ENDIF
- CALL iom_get( numror, jpdom_autoglo, 'ssh_ini', ssh_ini(:,:) )
- CALL iom_get( numror, jpdom_autoglo, 'e3t_ini', e3t_ini(:,:,:) )
- CALL iom_get( numror, jpdom_autoglo, 'hc_loc_ini', hc_loc_ini(:,:,:) )
- CALL iom_get( numror, jpdom_autoglo, 'sc_loc_ini', sc_loc_ini(:,:,:) )
- IF( .NOT. lk_vvl ) THEN
- CALL iom_get( numror, jpdom_autoglo, 'ssh_hc_loc_ini', ssh_hc_loc_ini(:,:) )
- CALL iom_get( numror, jpdom_autoglo, 'ssh_sc_loc_ini', ssh_sc_loc_ini(:,:) )
- ENDIF
- ELSE
- IF(lwp) WRITE(numout,*) '~~~~~~~'
- IF(lwp) WRITE(numout,*) ' dia_hsb at initial state '
- IF(lwp) WRITE(numout,*) '~~~~~~~'
- ssh_ini(:,:) = sshn(:,:) ! initial ssh
- DO jk = 1, jpk
- e3t_ini (:,:,jk) = fse3t_n(:,:,jk) ! initial vertical scale factors
- hc_loc_ini(:,:,jk) = tsn(:,:,jk,jp_tem) * fse3t_n(:,:,jk) ! initial heat content
- sc_loc_ini(:,:,jk) = tsn(:,:,jk,jp_sal) * fse3t_n(:,:,jk) ! initial salt content
- END DO
- frc_v = 0._wp ! volume trend due to forcing
- frc_t = 0._wp ! heat content - - - -
- frc_s = 0._wp ! salt content - - - -
- IF( .NOT. lk_vvl ) THEN
- IF ( ln_isfcav ) THEN
- DO ji=1,jpi
- DO jj=1,jpj
- ssh_hc_loc_ini(ji,jj) = tsn(ji,jj,mikt(ji,jj),jp_tem) * sshn(ji,jj) ! initial heat content in ssh
- ssh_sc_loc_ini(ji,jj) = tsn(ji,jj,mikt(ji,jj),jp_sal) * sshn(ji,jj) ! initial salt content in ssh
- ENDDO
- ENDDO
- ELSE
- ssh_hc_loc_ini(:,:) = tsn(:,:,1,jp_tem) * sshn(:,:) ! initial heat content in ssh
- ssh_sc_loc_ini(:,:) = tsn(:,:,1,jp_sal) * sshn(:,:) ! initial salt content in ssh
- END IF
- frc_wn_t = 0._wp ! initial heat content misfit due to free surface
- frc_wn_s = 0._wp ! initial salt content misfit due to free surface
- ENDIF
- ENDIF
- ELSEIF( TRIM(cdrw) == 'WRITE' ) THEN ! Create restart file
- ! ! -------------------
- IF(lwp) WRITE(numout,*) '~~~~~~~'
- IF(lwp) WRITE(numout,*) ' dia_hsb_rst at it= ', kt,' date= ', ndastp
- IF(lwp) WRITE(numout,*) '~~~~~~~'
- CALL iom_rstput( kt, nitrst, numrow, 'frc_v' , frc_v )
- CALL iom_rstput( kt, nitrst, numrow, 'frc_t' , frc_t )
- CALL iom_rstput( kt, nitrst, numrow, 'frc_s' , frc_s )
- IF( .NOT. lk_vvl ) THEN
- CALL iom_rstput( kt, nitrst, numrow, 'frc_wn_t', frc_wn_t )
- CALL iom_rstput( kt, nitrst, numrow, 'frc_wn_s', frc_wn_s )
- ENDIF
- CALL iom_rstput( kt, nitrst, numrow, 'ssh_ini', ssh_ini(:,:) )
- CALL iom_rstput( kt, nitrst, numrow, 'e3t_ini', e3t_ini(:,:,:) )
- CALL iom_rstput( kt, nitrst, numrow, 'hc_loc_ini', hc_loc_ini(:,:,:) )
- CALL iom_rstput( kt, nitrst, numrow, 'sc_loc_ini', sc_loc_ini(:,:,:) )
- IF( .NOT. lk_vvl ) THEN
- CALL iom_rstput( kt, nitrst, numrow, 'ssh_hc_loc_ini', ssh_hc_loc_ini(:,:) )
- CALL iom_rstput( kt, nitrst, numrow, 'ssh_sc_loc_ini', ssh_sc_loc_ini(:,:) )
- ENDIF
- !
- ENDIF
- !
- END SUBROUTINE dia_hsb_rst
- SUBROUTINE dia_hsb_init
- !!---------------------------------------------------------------------------
- !! *** ROUTINE dia_hsb ***
- !!
- !! ** Purpose: Initialization for the heat salt volume budgets
- !!
- !! ** Method : Compute initial heat content, salt content and volume
- !!
- !! ** Action : - Compute initial heat content, salt content and volume
- !! - Initialize forcing trends
- !! - Compute coefficients for conversion
- !!---------------------------------------------------------------------------
- INTEGER :: ierror ! local integer
- INTEGER :: ios
- !
- NAMELIST/namhsb/ ln_diahsb
- !!----------------------------------------------------------------------
- REWIND( numnam_ref ) ! Namelist namhsb in reference namelist
- READ ( numnam_ref, namhsb, IOSTAT = ios, ERR = 901)
- 901 IF( ios /= 0 ) CALL ctl_nam ( ios , 'namhsb in reference namelist', lwp )
- REWIND( numnam_cfg ) ! Namelist namhsb in configuration namelist
- READ ( numnam_cfg, namhsb, IOSTAT = ios, ERR = 902 )
- 902 IF( ios /= 0 ) CALL ctl_nam ( ios , 'namhsb in configuration namelist', lwp )
- IF(lwm) WRITE ( numond, namhsb )
- IF(lwp) THEN
- WRITE(numout,*)
- WRITE(numout,*) 'dia_hsb_init'
- WRITE(numout,*) '~~~~~~~~ '
- WRITE(numout,*) ' check the heat and salt budgets (T) or not (F) ln_diahsb = ', ln_diahsb
- ENDIF
- !
- IF( .NOT. ln_diahsb ) RETURN
- ! IF( .NOT. lk_mpp_rep ) &
- ! CALL ctl_stop (' Your global mpp_sum if performed in single precision - 64 bits -', &
- ! & ' whereas the global sum to be precise must be done in double precision ',&
- ! & ' please add key_mpp_rep')
- ! ------------------- !
- ! 1 - Allocate memory !
- ! ------------------- !
- ALLOCATE( hc_loc_ini(jpi,jpj,jpk), sc_loc_ini(jpi,jpj,jpk), &
- & e3t_ini(jpi,jpj,jpk), surf(jpi,jpj), ssh_ini(jpi,jpj), STAT=ierror )
- IF( ierror > 0 ) THEN
- CALL ctl_stop( 'dia_hsb: unable to allocate hc_loc_ini' )
- RETURN
- ENDIF
- IF( .NOT. lk_vvl ) THEN
- ALLOCATE( ssh_hc_loc_ini(jpi,jpj), ssh_sc_loc_ini(jpi,jpj), STAT=ierror )
- IF( ierror > 0 ) THEN
- CALL ctl_stop( 'dia_hsb: unable to allocate hc_loc_ini' )
- RETURN
- ENDIF
- ENDIF
- ! ----------------------------------------------- !
- ! 2 - Time independant variables and file opening !
- ! ----------------------------------------------- !
- surf(:,:) = e1t(:,:) * e2t(:,:) * tmask_i(:,:) ! masked surface grid cell area
- surf_tot = glob_sum( surf(:,:) ) ! total ocean surface area
- IF( lk_bdy ) CALL ctl_warn( 'dia_hsb does not take open boundary fluxes into account' )
- !
- ! ---------------------------------- !
- ! 4 - initial conservation variables !
- ! ---------------------------------- !
- CALL dia_hsb_rst( nit000, 'READ' ) !* read or initialize all required files
- !
- END SUBROUTINE dia_hsb_init
- !!======================================================================
- END MODULE diahsb
|