!=================================================================== !BOP ! ! !MODULE: ice_prescribed_mod - Prescribed Ice Model ! ! !DESCRIPTION: ! ! The prescribed ice model reads in ice concentration data from a netCDF ! file. Ice thickness, temperature, the ice temperature profile are ! prescribed. Air/ice fluxes are computed to get surface temperature, ! Ice/ocean fluxes are set to zero, and ice dynamics are not calculated. ! Regridding and data cycling capabilities are included. ! ! !REVISION HISTORY: ! SVN:$Id: ice_prescribed_mod.F90 40 2006-12-01 19:09:30Z eclare $ ! ! 2010-May-15 - Tony Craig and Mariana Vertenstein - updated to latest streams ! 2006-Aug-22 - D. Bailey, E. Hunke, modified to fit with CICE ! 2005-May-19 - J. Schramm - first version ! 2005-Apr-19 - B. Kauffman, J. Schramm, M. Vertenstein, NCAR - design ! ! !INTERFACE: ---------------------------------------------------------- module ice_prescribed_mod 3,20 ! !USES: use shr_strdata_mod use shr_dmodel_mod use shr_string_mod use shr_ncread_mod use shr_sys_mod use shr_mct_mod use mct_mod use pio use ice_broadcast use ice_communicate, only : my_task, master_task, MPI_COMM_ICE use ice_kinds_mod use ice_fileunits use ice_exit, only : abort_ice use ice_domain_size, only : nx_global, ny_global, ncat, nilyr, nslyr, max_blocks use ice_constants use ice_blocks, only : nx_block, ny_block use ice_domain, only : nblocks, distrb_info, blocks_ice use ice_grid, only : TLAT,TLON,hm,tmask use ice_calendar, only : idate, sec use ice_itd, only : ilyr1, slyr1, hin_max use ice_read_write implicit none save private ! except ! !PUBLIC TYPES: ! !PUBLIC MEMBER FUNCTIONS: public :: ice_prescribed_init ! initialize input data stream public :: ice_prescribed_run ! get time slices and time interp public :: ice_prescribed_phys ! set prescribed ice state and fluxes ! !PUBLIC DATA MEMBERS: logical(kind=log_kind), public :: prescribed_ice ! true if prescribed ice !EOP logical(kind=log_kind) :: prescribed_ice_fill ! true if data fill required integer(kind=int_kind) :: stream_year_first ! first year in stream to use integer(kind=int_kind) :: stream_year_last ! last year in stream to use integer(kind=int_kind) :: model_year_align ! align stream_year_first ! with this model year character(len=char_len_long) :: stream_fldVarName character(len=char_len_long) :: stream_fldFileName character(len=char_len_long) :: stream_domTvarName character(len=char_len_long) :: stream_domXvarName character(len=char_len_long) :: stream_domYvarName character(len=char_len_long) :: stream_domAreaName character(len=char_len_long) :: stream_domMaskName character(len=char_len_long) :: stream_domFileName type(shr_strdata_type) :: sdat ! prescribed data stream character(len=char_len_long) :: fldList ! list of fields in data stream real(kind=dbl_kind) :: ice_cov(nx_block,ny_block,max_blocks) ! ice cover real (kind=dbl_kind), parameter :: & cp_sno = 0.0_dbl_kind & ! specific heat of snow (J/kg/K) , rLfi = Lfresh*rhoi & ! latent heat of fusion ice (J/m^3) , rLfs = Lfresh*rhos & ! latent heat of fusion snow (J/m^3) , rLvi = Lvap*rhoi & ! latent heat of vapor*rhoice (J/m^3) , rLvs = Lvap*rhos & ! latent heat of vapor*rhosno (J/m^3) , rcpi = cp_ice*rhoi & ! heat capacity of fresh ice (J/m^3) , rcps = cp_sno*rhos & ! heat capacity of snow (J/m^3) , rcpidepressT = rcpi*depressT & ! param for finding T(z) from q (J/m^3) , rLfidepressT = rLfi*depressT ! param for heat capacity (J deg/m^3) ! heat capacity of sea ice, rhoi*C=rcpi+rLfidepressT*salinity/T^2 !======================================================================= contains !=============================================================================== !BOP ! ! !IROUTINE: ice_prescribed_init - prescribed ice initialization ! ! !INTERFACE: subroutine ice_prescribed_init(compid, gsmap, dom) 1,19 ! !DESCRIPTION: ! Prescribed ice initialization - needed to ! work with new shr_strdata module derived type ! ! !REVISION HISTORY: ! 2009-Oct-12 - M. Vertenstein ! ! !INPUT/OUTPUT PARAMETERS: ! implicit none integer(kind=int_kind), intent(in) :: compid type(mct_gsMap) :: gsmap type(mct_gGrid) :: dom !EOP !----- Local ------ integer(kind=int_kind) :: nml_error ! namelist i/o error flag character(len=8) :: fillalgo character(*),parameter :: subName = "('ice_prescribed_init2')" character(*),parameter :: F00 = "('(ice_prescribed_init2) ',4a)" namelist /ice_prescribed_nml/ & prescribed_ice, & prescribed_ice_fill, & stream_year_first , & stream_year_last , & model_year_align, & stream_fldVarName , & stream_fldFileName, & stream_domTvarName, & stream_domXvarName, & stream_domYvarName, & stream_domAreaName, & stream_domMaskName, & stream_domFileName ! default values for namelist prescribed_ice = .false. ! if true, prescribe ice stream_year_first = 1 ! first year in pice stream to use stream_year_last = 1 ! last year in pice stream to use model_year_align = 1 ! align stream_year_first with this model year stream_fldVarName = 'ice_cov' stream_fldFileName = ' ' stream_domTvarName = 'time' stream_domXvarName = 'lon' stream_domYvarName = 'lat' stream_domAreaName = 'area' stream_domMaskName = 'mask' stream_domFileName = ' ' prescribed_ice_fill = .false. ! true if pice data fill required ! read from input file call get_fileunit(nu_nml) if (my_task == master_task) then open (nu_nml, file=nml_filename, status='old',iostat=nml_error) if (nml_error /= 0) then nml_error = -1 else nml_error = 1 endif do while (nml_error > 0) read(nu_nml, nml=ice_prescribed_nml,iostat=nml_error) if (nml_error > 0) read(nu_nml,*) ! for Nagware compiler end do if (nml_error == 0) close(nu_nml) endif call release_fileunit(nu_nml) call broadcast_scalar(nml_error,master_task) if (nml_error /= 0) then call abort_ice ('ice: Namelist read error in ice_prescribed_mod') endif call broadcast_scalar(prescribed_ice,master_task) ! *** If not prescribed ice then return *** if (.not. prescribed_ice) RETURN call broadcast_scalar(prescribed_ice_fill,master_task) call broadcast_scalar(stream_year_first,master_task) call broadcast_scalar(stream_year_last,master_task) call broadcast_scalar(model_year_align,master_task) call broadcast_scalar(stream_fldVarName,master_task) call broadcast_scalar(stream_fldFileName,master_task) call broadcast_scalar(stream_domTvarName,master_task) call broadcast_scalar(stream_domXvarName,master_task) call broadcast_scalar(stream_domYvarName,master_task) call broadcast_scalar(stream_domAreaName,master_task) call broadcast_scalar(stream_domMaskName,master_task) call broadcast_scalar(stream_domFileName,master_task) if (my_task == master_task) then write(nu_diag,*) ' ' write(nu_diag,*) 'This is the prescribed ice coverage option.' write(nu_diag,*) ' stream_year_first = ',stream_year_first write(nu_diag,*) ' stream_year_last = ',stream_year_last write(nu_diag,*) ' model_year_align = ',model_year_align write(nu_diag,*) ' stream_fldVarName = ',trim(stream_fldVarName) write(nu_diag,*) ' stream_fldFileName = ',trim(stream_fldFileName) write(nu_diag,*) ' stream_domTvarName = ',trim(stream_domTvarName) write(nu_diag,*) ' stream_domXvarName = ',trim(stream_domXvarName) write(nu_diag,*) ' stream_domYvarName = ',trim(stream_domYvarName) write(nu_diag,*) ' stream_domFileName = ',trim(stream_domFileName) write(nu_diag,*) ' prescribed_ice_fill= ',prescribed_ice_fill write(nu_diag,*) ' ' endif ! Read shr_strdata_nml namelist if (prescribed_ice_fill) then fillalgo='nn' else fillalgo='none' endif call shr_strdata_create(sdat,name="prescribed_ice", & mpicom=MPI_COMM_ICE, compid=compid, & gsmap=gsmap, ggrid=dom, & nxg=nx_global,nyg=ny_global, & yearFirst=stream_year_first, & yearLast=stream_year_last, & yearAlign=model_year_align, & offset=0, & domFilePath='', & domFileName=trim(stream_domFileName), & domTvarName=stream_domTvarName, & domXvarName=stream_domXvarName, & domYvarName=stream_domYvarName, & domAreaName=stream_domAreaName, & domMaskName=stream_domMaskName, & filePath='', & filename=(/trim(stream_fldFileName)/), & fldListFile=stream_fldVarName, & fldListModel=stream_fldVarName, & fillalgo = trim(fillalgo)) if (my_task == master_task) then call shr_strdata_print(sdat,'SPRESICE data') endif !----------------------------------------------------------------- ! For one ice category, set hin_max(1) to something big !----------------------------------------------------------------- if (ncat == 1) then hin_max(1) = 999._dbl_kind end if end subroutine ice_prescribed_init !======================================================================= !BOP =================================================================== ! ! !IROUTINE: ice_prescribed_run -- Update ice coverage ! ! !DESCRIPTION: ! ! Finds two time slices bounding current model time, remaps if necessary ! ! !REVISION HISTORY: ! 2005-May-19 - J. Schramm - first version ! 2009-Oct-15 - M. Vertenstein - update to new data model changes ! ! !INTERFACE: ----------------------------------------------------------- subroutine ice_prescribed_run(mDateIn, secIn) 1,4 ! !USES: implicit none ! !INPUT/OUTPUT PARAMETERS: integer(kind=int_kind), intent(in) :: mDateIn ! Current model date (yyyymmdd) integer(kind=int_kind), intent(in) :: secIn ! Elapsed seconds on model date !EOP integer(kind=int_kind) :: i,j,n,iblk ! loop indices and counter integer(kind=int_kind) :: ilo,ihi,jlo,jhi ! beginning and end of physical domain type (block) :: this_block real(kind=dbl_kind) :: aice_max ! maximun ice concentration logical, save :: first_time = .true. character(*),parameter :: subName = "('ice_prescribed_run')" character(*),parameter :: F00 = "('(ice_prescribed_run) ',a,2g20.13)" !------------------------------------------------------------------------ ! Interpolate to new ice coverage !------------------------------------------------------------------------ call shr_strdata_advance(sdat,mDateIn,SecIn,MPI_COMM_ICE,'cice_pice') ice_cov(:,:,:) = c0 ! This initializes ghost cells as well n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 ice_cov(i,j,iblk) = sdat%avs(1)%rAttr(1,n) end do end do end do !-------------------------------------------------------------------- ! Check to see that ice concentration is in fraction, not percent !-------------------------------------------------------------------- if (first_time) then aice_max = maxval(ice_cov) if (aice_max > c10) then write(nu_diag,F00) "ERROR: Ice conc data must be in fraction, aice_max= ",& aice_max call abort_ice(subName) end if first_time = .false. end if !----------------------------------------------------------------- ! Set prescribed ice state and fluxes !----------------------------------------------------------------- call ice_prescribed_phys() end subroutine ice_prescribed_run !=============================================================================== !BOP =========================================================================== ! ! !IROUTINE: ice_prescribed_phys -- set prescribed ice state and fluxes ! ! !DESCRIPTION: ! ! Set prescribed ice state using input ice concentration; ! set surface ice temperature to atmospheric value; use ! linear temperature gradient in ice to ocean temperature. ! ! !REVISION HISTORY: ! 2005-May-23 - J. Schramm - Updated with data models ! 2004-July - J. Schramm - Modified to allow variable snow cover ! 2001-May - B. P. Briegleb - Original version ! ! !INTERFACE: ------------------------------------------------------------------ subroutine ice_prescribed_phys 1,7 ! !USES: use ice_flux ! use ice_grid, only : bound use ice_state use ice_itd, only : aggregate use ice_dyn_evp implicit none ! !INPUT/OUTPUT PARAMETERS: !EOP !----- Local ------ integer(kind=int_kind) :: layer ! level index integer(kind=int_kind) :: nc ! ice category index integer(kind=int_kind) :: i,j,k ! longitude, latitude and level indices integer(kind=int_kind) :: iblk real(kind=dbl_kind) :: slope ! diff in underlying ocean tmp and ice surface tmp real(kind=dbl_kind) :: Ti ! ice level temperature real(kind=dbl_kind) :: Tmlt ! ice level melt temperature real(kind=dbl_kind) :: qin_save(nilyr) real(kind=dbl_kind) :: qsn_save(nslyr) real(kind=dbl_kind) :: hi ! ice prescribed (hemispheric) ice thickness real(kind=dbl_kind) :: hs ! snow thickness real(kind=dbl_kind) :: zn ! normalized ice thickness real(kind=dbl_kind) :: salin(nilyr) ! salinity (ppt) real(kind=dbl_kind), parameter :: nsal = 0.407_dbl_kind real(kind=dbl_kind), parameter :: msal = 0.573_dbl_kind real(kind=dbl_kind), parameter :: saltmax = 3.2_dbl_kind ! max salinity at ice base (ppm) !----------------------------------------------------------------- ! Initialize ice state !----------------------------------------------------------------- ! TODO - can we now get rid of the following??? ! aicen(:,:,:,:) = c0 ! vicen(:,:,:,:) = c0 ! eicen(:,:,:,:) = c0 ! do nc=1,ncat ! trcrn(:,:,nt_Tsfc,nc,:) = Tf(:,:,:) ! enddo !----------------------------------------------------------------- ! Set ice cover over land to zero, not sure if this should be ! be done earier, before time/spatial interp?????? !----------------------------------------------------------------- do iblk = 1,nblocks do j = 1,ny_block do i = 1,nx_block if (tmask(i,j,iblk)) then if (ice_cov(i,j,iblk) .lt. eps04) ice_cov(i,j,iblk) = c0 if (ice_cov(i,j,iblk) .gt. c1) ice_cov(i,j,iblk) = c1 else ice_cov(i,j,iblk) = c0 end if enddo enddo enddo do iblk = 1,nblocks do j = 1,ny_block do i = 1,nx_block if (tmask(i,j,iblk)) then ! Over ocean points !-------------------------------------------------------------- ! Place ice where ice concentration > .0001 !-------------------------------------------------------------- if (ice_cov(i,j,iblk) >= eps04) then hi = 0.0_dbl_kind !---------------------------------------------------------- ! Set ice thickness in each hemisphere !---------------------------------------------------------- if(TLAT(i,j,iblk)*rad_to_deg > 40.0_dbl_kind) then hi = 2.0_dbl_kind else if(TLAT(i,j,iblk)*rad_to_deg < -40.0_dbl_kind) then hi = 1.0_dbl_kind end if !---------------------------------------------------------- ! All ice in appropriate thickness category !---------------------------------------------------------- do nc = 1,ncat if(hin_max(nc-1) < hi .and. hi < hin_max(nc)) then if (aicen(i,j,nc,iblk) > c0) then hs = vsnon(i,j,nc,iblk) / aicen(i,j,nc,iblk) else hs = c0 endif qin_save(:) = c0 qsn_save(:) = c0 if (vicen(i,j,nc,iblk) > c0) then do k=1,nilyr qin_save(k) = eicen(i,j,ilyr1(nc)+k-1,iblk) & * real(nilyr,kind=dbl_kind) & / Vicen(i,j,nc,iblk) enddo endif if (vsnon(i,j,nc,iblk) > c0) then do k=1,nslyr qsn_save(k) = esnon(i,j,slyr1(nc)+k-1,iblk) & * real(nslyr,kind=dbl_kind) & / vsnon(i,j,nc,iblk) enddo endif aicen(i,j,nc,iblk) = ice_cov(i,j,iblk) vicen(i,j,nc,iblk) = hi*aicen(i,j,nc,iblk) vsnon(i,j,nc,iblk) = hs*aicen(i,j,nc,iblk) ! remember enthalpy profile to compute energy do k=1,nilyr eicen(i,j,ilyr1(nc)+k-1,iblk) & = qin_save(k) * vicen(i,j,nc,iblk) & / real(nilyr,kind=dbl_kind) enddo do k=1,nslyr esnon(i,j,slyr1(nc)+k-1,iblk) & = qsn_save(k) * vsnon(i,j,nc,iblk) & / real(nslyr,kind=dbl_kind) enddo !--------------------------------------------------------- ! make linear temp profile and compute enthalpy !--------------------------------------------------------- if (abs(eicen(i,j,ilyr1(nc),iblk)) < puny) then if (aice(i,j,iblk) < puny) & trcrn(i,j,nt_Tsfc,nc,iblk) = Tf(i,j,iblk) slope = Tf(i,j,iblk) - trcrn(i,j,nt_Tsfc,nc,iblk) do k = 1, nilyr zn = (real(k,kind=dbl_kind)-p5) / real(nilyr,kind=dbl_kind) Ti = trcrn(i,j,nt_Tsfc,nc,iblk) + slope*zn salin(k) = (saltmax/c2)*(c1-cos(pi*zn**(nsal/(msal+zn)))) Tmlt = -salin(k)*depressT eicen(i,j,ilyr1(nc)+k-1,iblk) = & -(rhoi * (cp_ice*(Tmlt-Ti) & + Lfresh*(c1-Tmlt/Ti) - cp_ocn*Tmlt)) & * vicen(i,j,nc,iblk)/real(nilyr,kind=dbl_kind) enddo do k=1,nslyr esnon(i,j,slyr1(nc)+k-1,iblk) = & -rhos*(Lfresh - cp_ice*trcrn(i,j,nt_Tsfc,nc,iblk)) & *vsnon(i,j,nc,iblk) enddo endif ! aice < puny end if ! hin_max enddo ! ncat else trcrn(i,j,nt_Tsfc,:,iblk) = Tf(i,j,iblk) aicen(i,j,:,iblk) = c0 vicen(i,j,:,iblk) = c0 vsnon(i,j,:,iblk) = c0 esnon(i,j,:,iblk) = c0 eicen(i,j,:,iblk) = c0 end if ! ice_cov >= eps04 end if ! tmask enddo ! i enddo ! j !-------------------------------------------------------------------- ! compute aggregate ice state and open water area !-------------------------------------------------------------------- call aggregate (nx_block, ny_block, & aicen(:,:,:,iblk), trcrn(:,:,:,:,iblk), & vicen(:,:,:,iblk), vsnon(:,:,:,iblk), & eicen(:,:,:,iblk), esnon(:,:,:,iblk), & aice(:,:,iblk), trcr(:,:,:,iblk), & vice(:,:,iblk), vsno(:,:,iblk), & eice(:,:,iblk), esno(:,:,iblk), & aice0(:,:,iblk), tmask(:,:,iblk), & ntrcr, trcr_depend) enddo ! iblk do iblk = 1, nblocks do j = 1, ny_block do i = 1, nx_block aice_init(i,j,iblk) = aice(i,j,iblk) enddo enddo enddo !-------------------------------------------------------------------- ! set non-computed fluxes, ice velocities, ice-ocn stresses to zero !-------------------------------------------------------------------- frzmlt (:,:,:) = c0 uvel (:,:,:) = c0 vvel (:,:,:) = c0 strocnxT (:,:,:) = c0 strocnyT (:,:,:) = c0 !----------------------------------------------------------------- ! other atm and ocn fluxes !----------------------------------------------------------------- call init_flux_atm call init_flux_ocn end subroutine ice_prescribed_phys !============================================================================== end module ice_prescribed_mod !==============================================================================