!=======================================================================
!
!BOP
!
! !MODULE: ice_forcing - reads and interpolates input forcing data
!
! !DESCRIPTION:
!
! Reads and interpolates forcing data for atmosphere and ocean quantities.
!
! !REVISION HISTORY:
! SVN:$Id: ice_forcing.F90 140 2008-07-25 20:15:53Z eclare $
!
! authors: Elizabeth C. Hunke and William H. Lipscomb, LANL
!
! 2004 WHL: Block structure added
! 2005 WHL: ECMWF option added
! 2006 ECH: LY option added
! 2006 WHL: Module name changed from ice_flux_in
! 2006 ECH: Fixed bugs, rearranged routines, edited comments, etc.
! Added NCAR ocean forcing file
! Converted to free source form (F90)
! 2007: netcdf version of read_data added by Alison McLaren, Met Office
!
! !INTERFACE:
!
module ice_forcing 3,10
!
! !USES:
!
use ice_kinds_mod
use ice_blocks
, only: nx_block, ny_block
use ice_domain_size
use ice_communicate
, only: my_task, master_task
use ice_constants
use ice_calendar
, only: istep, istep1, time, time_forc, year_init, &
sec, mday, month, nyr, yday, daycal, dayyr, &
daymo, days_per_year
use ice_fileunits
use ice_atmo
, only: calc_strair
use ice_exit
use ice_timers
!
!EOP
!
implicit none
save
integer (kind=int_kind) :: &
ycycle , & ! number of years in forcing cycle
fyear_init , & ! first year of data in forcing cycle
fyear , & ! current year in forcing cycle
fyear_final ! last year in cycle
character (char_len_long) :: & ! input data file names
height_file, &
uwind_file, &
vwind_file, &
wind_file, &
strax_file, &
stray_file, &
potT_file, &
tair_file, &
humid_file, &
rhoa_file, &
fsw_file, &
flw_file, &
rain_file, &
sst_file, &
sss_file, &
pslv_file, &
sublim_file, &
snow_file
character (char_len_long), dimension(ncat) :: & ! input data file names
topmelt_file, &
botmelt_file
real (kind=dbl_kind) :: &
c1intp, c2intp , & ! interpolation coefficients
ftime ! forcing time (for restart)
integer (kind=int_kind) :: &
oldrecnum = 0 , & ! old record number (save between steps)
oldrecslot = 1 ! old record slot (save between steps)
real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks) :: &
cldf ! cloud fraction
real (kind=dbl_kind), dimension(nx_block,ny_block,2,max_blocks) :: &
fsw_data, & ! field values at 2 temporal data points
cldf_data, &
fsnow_data, &
Tair_data, &
uatm_data, &
vatm_data, &
wind_data, &
strax_data, &
stray_data, &
Qa_data, &
rhoa_data, &
potT_data, &
zlvl_data, &
flw_data, &
sst_data, &
sss_data, &
uocn_data, &
vocn_data, &
sublim_data, &
frain_data
real (kind=dbl_kind), &
dimension(nx_block,ny_block,2,max_blocks,ncat) :: &
topmelt_data, &
botmelt_data
character(char_len) :: &
atm_data_format, & ! 'bin'=binary or 'nc'=netcdf
ocn_data_format, & ! 'bin'=binary or 'nc'=netcdf
atm_data_type, & ! 'default', 'monthly', 'ncar', 'ecmwf',
! 'LYq' or 'hadgem'
sss_data_type, & ! 'default', 'clim', or 'ncar'
sst_data_type, & ! 'default', 'clim', 'ncar',
! 'hadgem_sst' or 'hadgem_sst_uvocn'
precip_units ! 'mm_per_month', 'mm_per_sec', 'mks'
character(char_len_long) :: &
atm_data_dir , & ! top directory for atmospheric data
ocn_data_dir , & ! top directory for ocean data
oceanmixed_file ! file name for ocean forcing data
integer (kind=int_kind), parameter :: &
nfld = 8 ! number of fields to search for in forcing file
! as in the dummy atm (latm)
real (kind=dbl_kind), parameter :: &
frcvdr = 0.28_dbl_kind, & ! frac of incoming sw in vis direct band
frcvdf = 0.24_dbl_kind, & ! frac of incoming sw in vis diffuse band
frcidr = 0.31_dbl_kind, & ! frac of incoming sw in near IR direct band
frcidf = 0.17_dbl_kind ! frac of incoming sw in near IR diffuse band
real (kind=dbl_kind), &
dimension (nx_block,ny_block,max_blocks,nfld,12) :: &
ocn_frc_m ! ocn data for 12 months
logical (kind=log_kind) :: &
restore_sst ! restore sst if true
integer (kind=int_kind) :: &
trestore ! restoring time scale (days)
real (kind=dbl_kind) :: &
trest ! restoring time scale (sec)
logical (kind=log_kind) :: &
dbug ! prints debugging output if true
!=======================================================================
contains
!=======================================================================
!
!BOP
!
! !IROUTINE: init_forcing_atmo - initialize atmospheric forcing
!
! !INTERFACE:
!
subroutine init_forcing_atmo,5
!
! !DESCRIPTION:
!
! Determine the current and final year of the forcing cycle based on
! namelist input; initialize the forcing data filenames.
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
! !INPUT/OUTPUT PARAMETERS:
!
!EOP
!
fyear = fyear_init + mod(nyr-1,ycycle) ! current year
fyear_final = fyear_init + ycycle - 1 ! last year in forcing cycle
if (trim(atm_data_type) /= 'default' .and. &
my_task == master_task) then
write (nu_diag,*) ' Initial forcing data year = ',fyear_init
write (nu_diag,*) ' Final forcing data year = ',fyear_final
endif
!-------------------------------------------------------------------
! Get filenames for input forcing data
!-------------------------------------------------------------------
! default forcing values from init_flux_atm
if (trim(atm_data_type) == 'ncar') then
call NCAR_files
(fyear)
elseif (trim(atm_data_type) == 'ecmwf') then
call ecmwf_files
(fyear)
elseif (trim(atm_data_type) == 'LYq') then
call LY_files
(fyear)
elseif (trim(atm_data_type) == 'hadgem') then
call hadgem_files
(fyear)
elseif (trim(atm_data_type) == 'monthly') then
call monthly_files
(fyear)
endif
end subroutine init_forcing_atmo
!=======================================================================
!BOP
!
! !IROUTINE: init_forcing_ocn - initialize sss and sst
!
! !INTERFACE:
!
subroutine init_forcing_ocn(dt),13
!
! !DESCRIPTION:
!
! Set sea surface salinity and freezing temperature to annual mean value
! using a 12-month climatology.
! Read sst data for current month, and adjust sst based on freezing
! temperature. No interpolation in time.
! Note: SST is subsequently prognosed if CICE is run with a mixed layer
! ocean (oceanmixed\_ice = T), and can be restored to data
! (restore\_sst = T). SSS is not prognosed by CICE.
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_domain
, only: nblocks
use ice_flux
, only: sss, sst, Tf, Tfrzpt
use ice_work
, only: work1
use ice_read_write
use ice_therm_vertical
, only: ustar_scale
!
! !INPUT/OUTPUT PARAMETERS:
!
real (kind=dbl_kind), intent(in) :: &
dt ! time step
!
!EOP
!
integer (kind=int_kind) :: &
i, j, iblk , & ! horizontal indices
k , & ! month index
fid , & ! file id for netCDF file
nbits
logical (kind=log_kind) :: diag
character (char_len) :: &
fieldname ! field name in netcdf file
nbits = 64 ! double precision data
!-------------------------------------------------------------------
! Sea surface salinity (SSS)
! initialize to annual climatology created from monthly data
!-------------------------------------------------------------------
if (trim(sss_data_type) == 'clim') then
! sss_file = trim(ocn_data_dir)//'sss_Lev.mm'
sss_file = trim(ocn_data_dir)//'sss.mm.100x116.da' ! gx3 only
!!! sss_file = trim(ocn_data_dir)//'sss_12.r'
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'SSS climatology computed from:'
write (nu_diag,*) trim(sss_file)
endif
if (my_task == master_task) &
call ice_open
(nu_forcing, sss_file, nbits)
sss(:,:,:) = c0
do k = 1,12 ! loop over 12 months
call ice_read
(nu_forcing, k, work1, 'rda8', dbug, &
field_loc_center, field_type_scalar)
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
sss(i,j,iblk) = sss(i,j,iblk) + work1(i,j,iblk)
enddo
enddo
enddo
enddo ! k
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
sss(i,j,iblk) = sss(i,j,iblk) / c12 ! annual average
sss(i,j,iblk) = max(sss(i,j,iblk),c0)
if (trim(Tfrzpt) == 'constant') then
Tf (i,j,iblk) = -1.8_dbl_kind ! deg C
else ! default: Tfrzpt = 'linear_S'
Tf (i,j,iblk) = -depressT * sss(i,j,iblk) ! deg C
endif
enddo
enddo
enddo
! close file
if (my_task == master_task) close(nu_forcing)
endif ! sss_data_type
!-------------------------------------------------------------------
! Sea surface temperature (SST)
! initialize to data for current month
!-------------------------------------------------------------------
if (restore_sst) then
if (trestore == 0) then
trest = dt ! use data instantaneously
else
trest = real(trestore,kind=dbl_kind) * secday ! seconds
endif
endif
if (trim(sst_data_type) == 'clim') then
if (nx_global == 320) then ! gx1
sst_file = trim(ocn_data_dir)//'sst_clim_hurrell.dat'
else ! gx3
! sst_file = trim(ocn_data_dir)//'sst_Lev.mm'
sst_file = trim(ocn_data_dir)//'sst.mm.100x116.da'
!!! sst_file = trim(ocn_data_dir)//'sst_12.r'
endif
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'Initial SST file:', trim(sst_file)
endif
if (my_task == master_task) &
call ice_open
(nu_forcing, sst_file, nbits)
call ice_read
(nu_forcing, month, sst, 'rda8', dbug, &
field_loc_center, field_type_scalar)
if (my_task == master_task) close(nu_forcing)
! Make sure sst is not less than freezing temperature Tf
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
sst(i,j,iblk) = max(sst(i,j,iblk),Tf(i,j,iblk))
enddo
enddo
enddo
endif ! init_sst_data
if (trim(sst_data_type) == 'hadgem_sst' .or. &
trim(sst_data_type) == 'hadgem_sst_uvocn') then
diag = .true. ! write diagnostic information
sst_file = trim (ocn_data_dir)//'MONTHLY/sst.1997.nc'
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'Initial SST file:', trim(sst_file)
call ice_open_nc
(sst_file,fid)
endif
fieldname='sst'
call ice_read_nc
(fid,month,fieldname,sst,diag)
if (my_task == master_task) call ice_close_nc
(fid)
! Make sure sst is not less than freezing temperature Tf
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
sst(i,j,iblk) = max(sst(i,j,iblk),Tf(i,j,iblk))
enddo
enddo
enddo
endif ! sst_data_type
if (trim(sst_data_type) == 'ncar' .or. &
trim(sss_data_type) == 'ncar') then
call ocn_data_ncar_init
endif
! set ustar_scale for case of zero currents
! default value of c1 (for nonzero currents) set in init_thermo_vertical
if (trim(sst_data_type) /= 'ncar' .or. &
trim(sss_data_type) /= 'ncar' .or. &
trim(sst_data_type) /= 'hadgem_sst_uvocn') then
ustar_scale = c10 ! for zero currents
endif
end subroutine init_forcing_ocn
!=======================================================================
!BOP
!
! !IROUTINE: get_forcing_atmo - Get atmospheric forcing data and interpolate
!
! !INTERFACE:
!
subroutine get_forcing_atmo,19
!
! !DESCRIPTION:
!
! Get atmospheric forcing data and interpolate as necessary
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_boundary
, only: ice_HaloUpdate
use ice_domain
use ice_blocks
use ice_flux
use ice_state
use ice_grid
, only: ANGLET, hm
!
!EOP
!
integer (kind=int_kind) :: &
iblk, & ! block index
ilo,ihi,jlo,jhi ! beginning and end of physical domain
type (block) :: &
this_block ! block information for current block
fyear = fyear_init + mod(nyr-1,ycycle) ! current year
if (trim(atm_data_type) /= 'default' .and. istep <= 1 &
.and. my_task == master_task) then
write (nu_diag,*) ' Current forcing data year = ',fyear
endif
ftime = time ! forcing time
time_forc = ftime ! for restarting
!-------------------------------------------------------------------
! Read and interpolate atmospheric data
!-------------------------------------------------------------------
if (trim(atm_data_type) == 'ncar') then
call ncar_data
elseif (trim(atm_data_type) == 'ecmwf') then
call ecmwf_data
elseif (trim(atm_data_type) == 'LYq') then
call LY_data
elseif (trim(atm_data_type) == 'hadgem') then
call hadgem_data
elseif (trim(atm_data_type) == 'monthly') then
call monthly_data
else ! default values set in init_flux
return
endif
!-------------------------------------------------------------------
! Convert forcing data to fields needed by ice model
!-------------------------------------------------------------------
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
call prepare_forcing
(nx_block, ny_block, &
ilo, ihi, jlo, jhi, &
hm (:,:,iblk), &
Tair (:,:,iblk), &
fsw (:,:,iblk), &
cldf (:,:,iblk), &
flw (:,:,iblk), &
frain (:,:,iblk), &
fsnow (:,:,iblk), &
Qa (:,:,iblk), &
rhoa (:,:,iblk), &
uatm (:,:,iblk), &
vatm (:,:,iblk), &
strax (:,:,iblk), &
stray (:,:,iblk), &
zlvl (:,:,iblk), &
wind (:,:,iblk), &
swvdr (:,:,iblk), &
swvdf (:,:,iblk), &
swidr (:,:,iblk), &
swidf (:,:,iblk), &
potT (:,:,iblk), &
ANGLET(:,:,iblk), &
trcr (:,:,nt_Tsfc,iblk), &
sst (:,:,iblk), &
aice (:,:,iblk) )
enddo ! iblk
call ice_timer_start
(timer_bound)
call ice_HaloUpdate
(swvdr, halo_info, &
field_loc_center, field_type_scalar)
call ice_HaloUpdate
(swvdf, halo_info, &
field_loc_center, field_type_scalar)
call ice_HaloUpdate
(swidr, halo_info, &
field_loc_center, field_type_scalar)
call ice_HaloUpdate
(swidf, halo_info, &
field_loc_center, field_type_scalar)
call ice_timer_stop
(timer_bound)
end subroutine get_forcing_atmo
!=======================================================================
!BOP
!
! !IROUTINE: get_forcing_ocn - interpolate sss, sst; restore sst
!
! !INTERFACE:
!
subroutine get_forcing_ocn (dt),5
!
! !DESCRIPTION:
!
! Read and interpolate annual climatologies of SSS and SST.
! Restore model SST to data if desired.
! Interpolate ocean fields to U grid if necessary.
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke, LANL
!
! !USES:
!
use ice_domain
, only: nblocks
use ice_ocean
!
! !INPUT/OUTPUT PARAMETERS:
!
real (kind=dbl_kind), intent(in) :: &
dt ! time step
!
!EOP
!
if (trim(sst_data_type) == 'clim' .or. &
trim(sss_data_type) == 'clim') then
call ocn_data_clim
(dt)
elseif (trim(sst_data_type) == 'ncar' .or. &
trim(sss_data_type) == 'ncar') then
call ocn_data_ncar
(dt)
elseif (trim(sst_data_type) == 'hadgem_sst' .or. &
trim(sst_data_type) == 'hadgem_sst_uvocn') then
call ocn_data_hadgem
(dt)
endif
end subroutine get_forcing_ocn
!=======================================================================
!
!BOP
!
! !IROUTINE: read_data - Read data needed for interpolation
!
! !INTERFACE:
!
subroutine read_data (flag, recd, yr, ixm, ixx, ixp, & 18,16
maxrec, data_file, field_data, &
field_loc, field_type)
!
! !DESCRIPTION:
!
! If data is at the beginning of a one-year record, get data from
! the previous year.
! If data is at the end of a one-year record, get data from the
! following year.
! If no earlier data exists (beginning of fyear_init), then
! (1) For monthly data, get data from the end of fyear_final.
! (2) For more frequent data, let the ixm value equal the
! first value of the year.
! If no later data exists (end of fyear_final), then
! (1) For monthly data, get data from the beginning of fyear_init.
! (2) For more frequent data, let the ipx value
! equal the last value of the year.
! In other words, we assume persistence when daily or 6-hourly
! data is missing, and we assume periodicity when monthly data
! is missing.
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_read_write
use ice_diagnostics
, only: check_step
!
! !INPUT/OUTPUT PARAMETERS:
!
logical (kind=log_kind), intent(in) :: flag
integer (kind=int_kind), intent(in) :: &
recd , & ! baseline record number
yr , & ! year of forcing data
ixm, ixx, ixp , & ! record numbers of 3 data values
! relative to recd
maxrec ! maximum record value
real (kind=dbl_kind), dimension(nx_block,ny_block,2,max_blocks), &
intent(out) :: &
field_data ! 2 values needed for interpolation
integer (kind=int_kind), intent(in) :: &
field_loc, & ! location of field on staggered grid
field_type ! type of field (scalar, vector, angle)
!
!EOP
!
character (char_len_long) :: &
data_file ! data file to be read
integer (kind=int_kind) :: &
nbits , & ! = 32 for single precision, 64 for double
nrec , & ! record number to read
n2, n4 , & ! like ixm and ixp, but
! adjusted at beginning and end of data
arg ! value of time argument in field_data
call ice_timer_start
(timer_readwrite) ! reading/writing
nbits = 64 ! double precision data
if (istep1 > check_step) dbug = .true. !! debugging
if (my_task==master_task .and. (dbug)) then
write(nu_diag,*) ' ', trim(data_file)
endif
if (flag) then
!-----------------------------------------------------------------
! Initialize record counters
! (n2, n4 will change only at the very beginning or end of
! a forcing cycle.)
!-----------------------------------------------------------------
n2 = ixm
n4 = ixp
arg = 0
!-----------------------------------------------------------------
! read data
!-----------------------------------------------------------------
if (ixm /= 99) then
! currently in first half of data interval
if (ixx <= 1) then
if (yr > fyear_init) then ! get data from previous year
call file_year
(data_file, yr-1)
else ! yr = fyear_init, no prior data exists
if (maxrec > 12) then ! extrapolate from first record
if (ixx == 1) n2 = ixx
else ! go to end of fyear_final
call file_year
(data_file, fyear_final)
endif
endif ! yr > fyear_init
endif ! ixx <= 1
call ice_open
(nu_forcing, data_file, nbits)
arg = 1
nrec = recd + n2
call ice_read
(nu_forcing, nrec, field_data(:,:,arg,:), &
'rda8', dbug, field_loc, field_type)
if (ixx==1 .and. my_task == master_task) close(nu_forcing)
endif ! ixm ne 99
! always read ixx data from data file for current year
call file_year
(data_file, yr)
call ice_open
(nu_forcing, data_file, nbits)
arg = arg + 1
nrec = recd + ixx
call ice_read
(nu_forcing, nrec, field_data(:,:,arg,:), &
'rda8', dbug, field_loc, field_type)
if (ixp /= 99) then
! currently in latter half of data interval
if (ixx==maxrec) then
if (yr < fyear_final) then ! get data from following year
if (my_task == master_task) close(nu_forcing)
call file_year
(data_file, yr+1)
call ice_open
(nu_forcing, data_file, nbits)
else ! yr = fyear_final, no more data exists
if (maxrec > 12) then ! extrapolate from ixx
n4 = ixx
else ! go to beginning of fyear_init
if (my_task == master_task) close(nu_forcing)
call file_year
(data_file, fyear_init)
call ice_open
(nu_forcing, data_file, nbits)
endif
endif ! yr < fyear_final
endif ! ixx = maxrec
arg = arg + 1
nrec = recd + n4
call ice_read
(nu_forcing, nrec, field_data(:,:,arg,:), &
'rda8', dbug, field_loc, field_type)
endif ! ixp /= 99
if (my_task == master_task) close(nu_forcing)
endif ! flag
call ice_timer_stop
(timer_readwrite) ! reading/writing
end subroutine read_data
!=======================================================================
!
!BOP
!
! !IROUTINE: read_data_nc - Read netcdf data needed for interpolation
!
! !INTERFACE:
!
subroutine read_data_nc (flag, recd, yr, ixm, ixx, ixp, & 18,20
maxrec, data_file, fieldname, field_data, &
field_loc, field_type)
!
! !DESCRIPTION:
!
! If data is at the beginning of a one-year record, get data from
! the previous year.
! If data is at the end of a one-year record, get data from the
! following year.
! If no earlier data exists (beginning of fyear_init), then
! (1) For monthly data, get data from the end of fyear_final.
! (2) For more frequent data, let the ixm value equal the
! first value of the year.
! If no later data exists (end of fyear_final), then
! (1) For monthly data, get data from the beginning of fyear_init.
! (2) For more frequent data, let the ipx value
! equal the last value of the year.
! In other words, we assume persistence when daily or 6-hourly
! data is missing, and we assume periodicity when monthly data
! is missing.
!
! !REVISION HISTORY:
!
! Adapted by Alison McLaren, Met Office from read_data
!
! !USES:
!
use ice_read_write
use ice_diagnostics
, only: check_step
!
! !INPUT/OUTPUT PARAMETERS:
!
logical (kind=log_kind), intent(in) :: flag
integer (kind=int_kind), intent(in) :: &
recd , & ! baseline record number
yr , & ! year of forcing data
ixm, ixx, ixp , & ! record numbers of 3 data values
! relative to recd
maxrec ! maximum record value
character (char_len_long) :: &
data_file ! data file to be read
character (char_len), intent(in) :: &
fieldname ! field name in netCDF file
integer (kind=int_kind), intent(in) :: &
field_loc, & ! location of field on staggered grid
field_type ! type of field (scalar, vector, angle)
real (kind=dbl_kind), dimension(nx_block,ny_block,2,max_blocks), &
intent(out) :: &
field_data ! 2 values needed for interpolation
!
!EOP
!
#ifdef ncdf
integer (kind=int_kind) :: &
nrec , & ! record number to read
n2, n4 , & ! like ixm and ixp, but
! adjusted at beginning and end of data
arg , & ! value of time argument in field_data
fid ! file id for netCDF routines
call ice_timer_start
(timer_readwrite) ! reading/writing
if (istep1 > check_step) dbug = .true. !! debugging
if (my_task==master_task .and. (dbug)) then
write(nu_diag,*) ' ', trim(data_file)
endif
if (flag) then
!-----------------------------------------------------------------
! Initialize record counters
! (n2, n4 will change only at the very beginning or end of
! a forcing cycle.)
!-----------------------------------------------------------------
n2 = ixm
n4 = ixp
arg = 0
!-----------------------------------------------------------------
! read data
!-----------------------------------------------------------------
if (ixm /= 99) then
! currently in first half of data interval
if (ixx <= 1) then
if (yr > fyear_init) then ! get data from previous year
call file_year
(data_file, yr-1)
else ! yr = fyear_init, no prior data exists
if (maxrec > 12) then ! extrapolate from first record
if (ixx == 1) n2 = ixx
else ! go to end of fyear_final
call file_year
(data_file, fyear_final)
endif
endif ! yr > fyear_init
endif ! ixx <= 1
call ice_open_nc
(data_file, fid)
arg = 1
nrec = recd + n2
call ice_read_nc
&
(fid, nrec, fieldname, field_data(:,:,arg,:), dbug, &
field_loc, field_type)
if (ixx==1) call ice_close_nc
(fid)
endif ! ixm ne 99
! always read ixx data from data file for current year
call file_year
(data_file, yr)
call ice_open_nc
(data_file, fid)
arg = arg + 1
nrec = recd + ixx
call ice_read_nc
&
(fid, nrec, fieldname, field_data(:,:,arg,:), dbug, &
field_loc, field_type)
if (ixp /= 99) then
! currently in latter half of data interval
if (ixx==maxrec) then
if (yr < fyear_final) then ! get data from following year
call ice_close_nc
(fid)
call file_year
(data_file, yr+1)
call ice_open_nc
(data_file, fid)
else ! yr = fyear_final, no more data exists
if (maxrec > 12) then ! extrapolate from ixx
n4 = ixx
else ! go to beginning of fyear_init
call ice_close_nc
(fid)
call file_year
(data_file, fyear_init)
call ice_open_nc
(data_file, fid)
endif
endif ! yr < fyear_final
endif ! ixx = maxrec
arg = arg + 1
nrec = recd + n4
call ice_read_nc
&
(fid, nrec, fieldname, field_data(:,:,arg,:), dbug, &
field_loc, field_type)
endif ! ixp /= 99
call ice_close_nc
(fid)
endif ! flag
call ice_timer_stop
(timer_readwrite) ! reading/writing
#else
field_data = c0 ! to satisfy intent(out) attribute
#endif
end subroutine read_data_nc
!=======================================================================
!
!BOP
!
! !IROUTINE: read_clim_data - read annual climatological data
!
! !INTERFACE:
!
subroutine read_clim_data (readflag, recd, ixm, ixx, ixp, & 13,8
data_file, field_data, &
field_loc, field_type)
!
! !DESCRIPTION:
!
! Read data needed for interpolation, as in read_data.
! Assume a one-year cycle of climatological data, so that there is
! no need to get data from other years or to extrapolate data beyond
! the forcing time period.
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_read_write
use ice_diagnostics
, only: check_step
!
! !INPUT/OUTPUT PARAMETERS:
!
logical (kind=log_kind),intent(in) :: readflag
integer (kind=int_kind), intent(in) :: &
recd , & ! baseline record number
ixm,ixx,ixp ! record numbers of 3 data values
! relative to recd
character (char_len_long), intent(in) :: data_file
integer (kind=int_kind), intent(in) :: &
field_loc, & ! location of field on staggered grid
field_type ! type of field (scalar, vector, angle)
real (kind=dbl_kind), dimension(nx_block,ny_block,2,max_blocks), &
intent(out) :: &
field_data ! 2 values needed for interpolation
!
!EOP
!
integer (kind=int_kind) :: &
nbits , & ! = 32 for single precision, 64 for double
nrec , & ! record number to read
arg ! value of time argument in field_data
call ice_timer_start
(timer_readwrite) ! reading/writing
nbits = 64 ! double precision data
if (istep1 > check_step) dbug = .true. !! debugging
if (my_task==master_task .and. (dbug)) &
write(nu_diag,*) ' ', trim(data_file)
if (readflag) then
!-----------------------------------------------------------------
! read data
!-----------------------------------------------------------------
call ice_open
(nu_forcing, data_file, nbits)
arg = 0
if (ixm /= 99) then
arg = 1
nrec = recd + ixm
call ice_read
(nu_forcing, nrec, field_data(:,:,arg,:), &
'rda8', dbug, field_loc, field_type)
endif
arg = arg + 1
nrec = recd + ixx
call ice_read
(nu_forcing, nrec, field_data(:,:,arg,:), &
'rda8', dbug, field_loc, field_type)
if (ixp /= 99) then
arg = arg + 1
nrec = recd + ixp
call ice_read
(nu_forcing, nrec, field_data(:,:,arg,:), &
'rda8', dbug, field_loc, field_type)
endif
if (my_task == master_task) close (nu_forcing)
endif ! readflag
call ice_timer_stop
(timer_readwrite) ! reading/writing
end subroutine read_clim_data
!=======================================================================
!
!BOP
!
! !IROUTINE: interp_coeff_monthly - Compute monthly data interpolation coefficients
!
! !INTERFACE:
!
subroutine interp_coeff_monthly (recslot) 8
!
! !DESCRIPTION:
!
! Compute coefficients for interpolating monthly data to current time step.
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
! !INPUT/OUTPUT PARAMETERS:
!
integer (kind=int_kind), intent(in) :: &
recslot ! slot (1 or 2) for current record
!
!EOP
!
real (kind=dbl_kind) :: &
tt , & ! seconds elapsed in current year
t1, t2 ! seconds elapsed at month midpoint
real (kind=dbl_kind) :: &
daymid(0:13) ! month mid-points
daymid(1:13) = 14._dbl_kind ! time frame ends 0 sec into day 15
daymid(0) = 14._dbl_kind - daymo(12) ! Dec 15, 0 sec
! make time cyclic
tt = mod(ftime/secday,dayyr)
! Find neighboring times
if (recslot==2) then ! first half of month
t2 = daycal(month) + daymid(month) ! midpoint, current month
if (month == 1) then
t1 = daymid(0) ! Dec 15 (0 sec)
else
t1 = daycal(month-1) + daymid(month-1) ! midpoint, previous month
endif
else ! second half of month
t1 = daycal(month) + daymid(month) ! midpoint, current month
t2 = daycal(month+1) + daymid(month+1)! day 15 of next month (0 sec)
endif
! Compute coefficients
c1intp = (t2 - tt) / (t2 - t1)
c2intp = c1 - c1intp
end subroutine interp_coeff_monthly
!=======================================================================
!
!BOP
!
! !IROUTINE: interp_coeff
!
! !INTERFACE:
!
subroutine interp_coeff (recnum, recslot, secint, dataloc) 3
!
! !DESCRIPTION:
!
! Compute coefficients for interpolating data to current time step.
! Works for any data interval that divides evenly into a
! year (daily, 6-hourly, etc.)
! Use interp_coef_monthly for monthly data.
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
integer (kind=int_kind), intent(in) :: &
recnum , & ! record number for current data value
recslot , & ! spline slot for current record
dataloc ! = 1 for data located in middle of time interval
! = 2 for date located at end of time interval
real (kind=dbl_kind), intent(in) :: &
secint ! seconds in data interval
!
! !INPUT/OUTPUT PARAMETERS:
!
!EOP
!
real (kind=dbl_kind) :: &
secyr ! seconds in a year
real (kind=dbl_kind) :: &
tt , & ! seconds elapsed in current year
t1, t2 , & ! seconds elapsed at data points
rcnum ! recnum => dbl_kind
secyr = dayyr * secday ! seconds in a year
tt = mod(ftime,secyr)
! Find neighboring times
rcnum = real(recnum,kind=dbl_kind)
if (recslot==2) then ! current record goes in slot 2
if (dataloc==1) then ! data located at middle of interval
t2 = (rcnum-p5)*secint
else ! data located at end of interval
t2 = rcnum*secint
endif
t1 = t2 - secint ! - 1 interval
else ! recslot = 1
if (dataloc==1) then ! data located at middle of interval
t1 = (rcnum-p5)*secint
else
t1 = rcnum*secint ! data located at end of interval
endif
t2 = t1 + secint ! + 1 interval
endif
! Compute coefficients
c1intp = abs((t2 - tt) / (t2 - t1))
c2intp = c1 - c1intp
end subroutine interp_coeff
!=======================================================================
!BOP
!
! !IROUTINE: interpolate_data
!
! !INTERFACE:
!
subroutine interpolate_data (field_data, field) 63,11
!
! !DESCRIPTION:
!
! Linear interpolation
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke, LANL
!
! !USES:
!
use ice_domain
, only: nblocks
!
! !INPUT/OUTPUT PARAMETERS:
!
real (kind=dbl_kind), dimension(nx_block,ny_block,2,max_blocks), &
intent(in) :: &
field_data ! 2 values used for interpolation
real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks), &
intent(out) :: &
field ! interpolated field
!
!EOP
!
integer (kind=int_kind) :: i,j, iblk
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
field(i,j,iblk) = c1intp * field_data(i,j,1,iblk) &
+ c2intp * field_data(i,j,2,iblk)
enddo
enddo
enddo
end subroutine interpolate_data
!=======================================================================
!
!BOP
!
! !IROUTINE: file_year - construct name of atmospheric data file
!
! !INTERFACE:
!
subroutine file_year (data_file, yr) 48
!
! !DESCRIPTION:
!
! Construct the correct name of the atmospheric data file
! to be read, given the year and assuming the naming convention
! that filenames end with 'yyyy.dat' or 'yyyy.r' or 'yyyy.nc'.
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke, LANL
!
! !USES:
!
!
! !INPUT/OUTPUT PARAMETERS:
!
character (char_len_long), intent(inout) :: data_file
!
!EOP
!
integer (kind=int_kind), intent(in) :: yr
character (char_len_long) :: tmpname
integer (kind=int_kind) :: i
if (trim(atm_data_type) == 'ecmwf') then ! NPS/ECMWF naming convention
i = index(data_file,'.r') - 5
tmpname = data_file
write(data_file,'(a,i4.4,a)') tmpname(1:i), yr, '.r'
elseif (trim(atm_data_type) == 'hadgem') then ! netcdf
i = index(data_file,'.nc') - 5
tmpname = data_file
write(data_file,'(a,i4.4,a)') tmpname(1:i), yr, '.nc'
else ! LANL/NCAR naming convention
i = index(data_file,'.dat') - 5
tmpname = data_file
write(data_file,'(a,i4.4,a)') tmpname(1:i), yr, '.dat'
endif
end subroutine file_year
!=======================================================================
!
!BOP
!
! !IROUTINE: prepare_forcing - finish manipulating forcing
!
! !INTERFACE:
!
subroutine prepare_forcing (nx_block, ny_block, & 1
ilo, ihi, jlo, jhi, &
hm, &
Tair, fsw, &
cldf, flw, &
frain, fsnow, &
Qa, rhoa, &
uatm, vatm, &
strax, stray, &
zlvl, wind, &
swvdr, swvdf, &
swidr, swidf, &
potT, ANGLET, &
Tsfc, sst, &
aice)
!
! !DESCRIPTION:
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
! !INPUT/OUTPUT PARAMETERS:
!
integer (kind=int_kind), intent(in) :: &
nx_block, ny_block, & ! block dimensions
ilo,ihi,jlo,jhi ! beginning and end of physical domain
real (kind=dbl_kind), dimension(nx_block,ny_block), intent(in) :: &
Tair , & ! air temperature (K)
ANGLET , & ! ANGLE converted to T-cells
Tsfc , & ! ice skin temperature
sst , & ! sea surface temperature
aice , & ! ice area fraction
hm ! land mask
real (kind=dbl_kind), dimension(nx_block,ny_block), &
intent(inout) :: &
fsw , & ! incoming shortwave radiation (W/m^2)
cldf , & ! cloud fraction
frain , & ! rainfall rate (kg/m^2 s)
fsnow , & ! snowfall rate (kg/m^2 s)
Qa , & ! specific humidity (kg/kg)
rhoa , & ! air density (kg/m^3)
uatm , & ! wind velocity components (m/s)
vatm , &
strax , & ! wind stress components (N/m^2)
stray , &
zlvl , & ! atm level height (m)
wind , & ! wind speed (m/s)
flw , & ! incoming longwave radiation (W/m^2)
swvdr , & ! sw down, visible, direct (W/m^2)
swvdf , & ! sw down, visible, diffuse (W/m^2)
swidr , & ! sw down, near IR, direct (W/m^2)
swidf , & ! sw down, near IR, diffuse (W/m^2)
potT ! air potential temperature (K)
!
!EOP
!
integer (kind=int_kind) :: &
i, j
real (kind=dbl_kind) :: workx, worky, &
fcc, sstk, rtea, ptem, qlwm, precip_factor
do j = jlo, jhi
do i = ilo, ihi
!-----------------------------------------------------------------
! make sure interpolated values are physically realistic
!-----------------------------------------------------------------
cldf (i,j) = max(min(cldf(i,j),c1),c0)
fsw (i,j) = max(fsw(i,j),c0)
fsnow(i,j) = max(fsnow(i,j),c0)
rhoa (i,j) = max(rhoa(i,j),c0)
Qa (i,j) = max(Qa(i,j),c0)
enddo ! i
enddo ! j
!-----------------------------------------------------------------
! calculations specific to datasets
!-----------------------------------------------------------------
if (trim(atm_data_type) == 'ncar') then
do j = jlo, jhi
do i = ilo, ihi
!-----------------------------------------------------------------
! correct known biases in NCAR data (as in CCSM latm)
!-----------------------------------------------------------------
Qa (i,j) = Qa (i,j) * 0.94_dbl_kind
fsw(i,j) = fsw(i,j) * 0.92_dbl_kind
!-----------------------------------------------------------------
! compute downward longwave as in Parkinson and Washington (1979)
! (for now)
!-----------------------------------------------------------------
flw(i,j) = stefan_boltzmann*Tair(i,j)**4 &
* (c1 - 0.261_dbl_kind &
*exp(-7.77e-4_dbl_kind*(Tffresh - Tair(i,j))**2)) &
* (c1 + 0.275_dbl_kind*cldf(i,j))
! precip is in mm/month; converted to mks below
enddo
enddo
elseif (trim(atm_data_type) == 'ecmwf') then
do j = jlo, jhi
do i = ilo, ihi
!-----------------------------------------------------------------
! The following assumes that the input Qa is really dew point temp
! (deg K) and need to be converted to specific humidity (kg/kg).
! Cf. ice_atmo module.
!-----------------------------------------------------------------
Qa (i,j) = (qqqocn/rhoa(i,j)) * exp(-TTTocn/Qa(i,j))
Qa (i,j) = max(Qa(i,j),c0)
!-----------------------------------------------------------------
! compute downward longwave as in Parkinson and Washington (1979)
! (for now)
!-----------------------------------------------------------------
flw(i,j) = stefan_boltzmann*Tair(i,j)**4 &
* (c1 - 0.261_dbl_kind &
*exp(-7.77e-4_dbl_kind*(Tffresh - Tair(i,j))**2)) &
* (c1 + 0.275_dbl_kind*cldf(i,j))
! precip is in mm/month; converted to mks below
enddo
enddo
elseif (trim(atm_data_type) == 'LYq') then
!-----------------------------------------------------------------
! longwave, Rosati and Miyakoda, JPO 18, p. 1607 (1988) - sort of
!-----------------------------------------------------------------
do j = jlo, jhi
do i = ilo, ihi
fcc = c1 - 0.8_dbl_kind * cldf(i,j)
sstk = (Tsfc(i,j) * aice(i,j) &
+ sst(i,j) * (c1 - aice(i,j))) + Tffresh
rtea = sqrt(c1000*Qa(i,j) / &
(0.622_dbl_kind+0.378_dbl_kind*Qa(i,j)))
ptem = Tair(i,j) ! get this from stability?
qlwm = ptem * ptem * ptem &
* ( ptem*(0.39_dbl_kind-0.05_dbl_kind*rtea)*fcc &
+ c4*(sstk-ptem) )
flw(i,j) = emissivity*stefan_boltzmann * ( sstk**4 - qlwm )
flw(i,j) = flw(i,j) * hm(i,j) ! land mask
enddo
enddo
endif ! atm_data_type
!-----------------------------------------------------------------
! Compute other fields needed by model
!-----------------------------------------------------------------
! convert precipitation units to kg/m^2 s
if (trim(precip_units) == 'mm_per_month') then
precip_factor = c12/(secday*days_per_year)
elseif (trim(precip_units) == 'mm_per_day') then
precip_factor = c1/secday
elseif (trim(precip_units) == 'mm_per_sec' .or. &
trim(precip_units) == 'mks') then
precip_factor = c1 ! mm/sec = kg/m^2 s
endif
do j = jlo, jhi
do i = ilo, ihi
zlvl(i,j) = c10
potT(i,j) = Tair(i,j)
! divide shortwave into spectral bands
swvdr(i,j) = fsw(i,j)*frcvdr ! visible direct
swvdf(i,j) = fsw(i,j)*frcvdf ! visible diffuse
swidr(i,j) = fsw(i,j)*frcidr ! near IR direct
swidf(i,j) = fsw(i,j)*frcidf ! near IR diffuse
! convert precipitation units to kg/m^2 s
fsnow(i,j) = fsnow(i,j) * precip_factor
enddo ! i
enddo ! j
! determine whether precip is rain or snow
! HadGEM forcing provides separate snowfall and rainfall rather
! than total precipitation
if (trim(atm_data_type) /= 'hadgem') then
do j = jlo, jhi
do i = ilo, ihi
frain(i,j) = c0
if (Tair(i,j) >= Tffresh) then
frain(i,j) = fsnow(i,j)
fsnow(i,j) = c0
endif
enddo ! i
enddo ! j
endif
if (calc_strair) then
do j = jlo, jhi
do i = ilo, ihi
wind(i,j) = sqrt(uatm(i,j)**2 + vatm(i,j)**2)
!-----------------------------------------------------------------
! Rotate zonal/meridional vectors to local coordinates.
! Velocity comes in on T grid, but is oriented geographically ---
! need to rotate to pop-grid FIRST using ANGLET
! then interpolate to the U-cell centers (otherwise we
! interpolate across the pole).
! Use ANGLET which is on the T grid !
! Atmo variables are needed in T cell centers in subroutine
! atmo_boundary_layer, and are interpolated to the U grid later as
! necessary.
!-----------------------------------------------------------------
workx = uatm(i,j) ! wind velocity, m/s
worky = vatm(i,j)
uatm (i,j) = workx*cos(ANGLET(i,j)) & ! convert to POP grid
+ worky*sin(ANGLET(i,j)) ! note uatm, vatm, wind
vatm (i,j) = worky*cos(ANGLET(i,j)) & ! are on the T-grid here
- workx*sin(ANGLET(i,j))
enddo ! i
enddo ! j
else ! strax, stray, wind are read from files
do j = jlo, jhi
do i = ilo, ihi
workx = strax(i,j) ! wind stress
worky = stray(i,j)
strax(i,j) = workx*cos(ANGLET(i,j)) & ! convert to POP grid
+ worky*sin(ANGLET(i,j)) ! note strax, stray, wind
stray(i,j) = worky*cos(ANGLET(i,j)) & ! are on the T-grid here
- workx*sin(ANGLET(i,j))
enddo ! i
enddo ! j
endif ! calc_strair
end subroutine prepare_forcing
!=======================================================================
! NCAR atmospheric forcing
!=======================================================================
!
!BOP
!
! !IROUTINE: ncar_files - construct filenames for NCAR bulk atmospheric data
!
! !INTERFACE:
!
subroutine ncar_files (yr) 1,8
!
! !DESCRIPTION:
!
! Construct filenames based on the LANL naming conventions for NCAR data.
! Edit for other directory structures or filenames.
! Note: The year number in these filenames does not matter, because
! subroutine file\_year will insert the correct year.
!
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke, LANL
!
! !USES:
!
! !INPUT/OUTPUT PARAMETERS:
!
integer (kind=int_kind), intent(in) :: &
yr ! current forcing year
!
!EOP
!
fsw_file = &
trim(atm_data_dir)//'ISCCPM/MONTHLY/RADFLX/swdn.1996.dat'
call file_year
(fsw_file,yr)
flw_file = &
trim(atm_data_dir)//'ISCCPM/MONTHLY/RADFLX/cldf.1996.dat'
call file_year
(flw_file,yr)
rain_file = &
trim(atm_data_dir)//'MXA/MONTHLY/PRECIP/prec.1996.dat'
call file_year
(rain_file,yr)
uwind_file = &
trim(atm_data_dir)//'NCEP/4XDAILY/STATES/u_10.1996.dat'
call file_year
(uwind_file,yr)
vwind_file = &
trim(atm_data_dir)//'NCEP/4XDAILY/STATES/v_10.1996.dat'
call file_year
(vwind_file,yr)
tair_file = &
trim(atm_data_dir)//'NCEP/4XDAILY/STATES/t_10.1996.dat'
call file_year
(tair_file,yr)
humid_file = &
trim(atm_data_dir)//'NCEP/4XDAILY/STATES/q_10.1996.dat'
call file_year
(humid_file,yr)
rhoa_file = &
trim(atm_data_dir)//'NCEP/4XDAILY/STATES/dn10.1996.dat'
call file_year
(rhoa_file,yr)
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'Forcing data year =', fyear
write (nu_diag,*) 'Atmospheric data files:'
write (nu_diag,*) trim(fsw_file)
write (nu_diag,*) trim(flw_file)
write (nu_diag,*) trim(rain_file)
write (nu_diag,*) trim(uwind_file)
write (nu_diag,*) trim(vwind_file)
write (nu_diag,*) trim(tair_file)
write (nu_diag,*) trim(humid_file)
write (nu_diag,*) trim(rhoa_file)
endif ! master_task
end subroutine ncar_files
!=======================================================================
!
!BOP
!
! !IROUTINE: ncar_data - read NCAR bulk atmospheric data
!
! !INTERFACE:
!
subroutine ncar_data 1,21
!
! !DESCRIPTION:
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_flux
!
! !INPUT/OUTPUT PARAMETERS:
!
!
!EOP
!
integer (kind=int_kind) :: &
i, j , &
ixm,ixx,ixp , & ! record numbers for neighboring months
recnum , & ! record number
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
dataloc , & ! = 1 for data located in middle of time interval
! = 2 for date located at end of time interval
midmonth ! middle day of month
real (kind=dbl_kind) :: &
sec6hr ! number of seconds in 6 hours
logical (kind=log_kind) :: readm, read6
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
midmonth = 15 ! data is given on 15th of every month
! midmonth = fix(p5 * real(daymo(month))) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
ixm = mod(month+maxrec-2,maxrec) + 1
ixp = mod(month, maxrec) + 1
if (mday >= midmonth) ixm = 99 ! other two points will be used
if (mday < midmonth) ixp = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
! Read 2 monthly values
readm = .false.
if (istep==1 .or. (mday==midmonth .and. sec==0)) readm = .true.
if (trim(atm_data_format) == 'bin') then
call read_data
(readm, 0, fyear, ixm, month, ixp, &
maxrec, fsw_file, fsw_data, &
field_loc_center, field_type_scalar)
call read_data
(readm, 0, fyear, ixm, month, ixp, &
maxrec, flw_file, cldf_data, &
field_loc_center, field_type_scalar)
call read_data
(readm, 0, fyear, ixm, month, ixp, &
maxrec, rain_file, fsnow_data, &
field_loc_center, field_type_scalar)
else
call abort_ice
('nonbinary atm_data_format unavailable')
! The routine exists, for example:
! call read_data_nc (readm, 0, fyear, ixm, month, ixp, &
! maxrec, fsw_file, 'fsw', fsw_data, &
! field_loc_center, field_type_scalar)
! call read_data_nc (readm, 0, fyear, ixm, month, ixp, &
! maxrec, flw_file, 'cldf',cldf_data, &
! field_loc_center, field_type_scalar)
! call read_data_nc (readm, 0, fyear, ixm, month, ixp, &
! maxrec, rain_file,'prec',fsnow_data, &
! field_loc_center, field_type_scalar)
endif
! Interpolate to current time step
call interpolate_data
(fsw_data, fsw)
call interpolate_data
(cldf_data, cldf)
call interpolate_data
(fsnow_data, fsnow)
!-------------------------------------------------------------------
! 6-hourly data
!
! Assume that the 6-hourly value is located at the end of the
! 6-hour period. This is the convention for NCEP reanalysis data.
! E.g. record 1 gives conditions at 6 am GMT on 1 January.
!-------------------------------------------------------------------
dataloc = 2 ! data located at end of interval
sec6hr = secday/c4 ! seconds in 6 hours
maxrec = 1460 ! 365*4
! current record number
recnum = 4*int(yday) - 3 + int(real(sec,kind=dbl_kind)/sec6hr)
! Compute record numbers for surrounding data
ixm = mod(recnum+maxrec-2,maxrec) + 1
ixx = mod(recnum-1, maxrec) + 1
! ixp = mod(recnum, maxrec) + 1
! Compute interpolation coefficients
! If data is located at the end of the time interval, then the
! data value for the current record always goes in slot 2.
recslot = 2
ixp = 99
call interp_coeff
(recnum, recslot, sec6hr, dataloc)
! Read
read6 = .false.
if (istep==1 .or. oldrecnum /= recnum) read6 = .true.
if (trim(atm_data_format) == 'bin') then
call read_data
(read6, 0, fyear, ixm, ixx, ixp, &
maxrec, tair_file, Tair_data, &
field_loc_center, field_type_scalar)
call read_data
(read6, 0, fyear, ixm, ixx, ixp, &
maxrec, uwind_file, uatm_data, &
field_loc_center, field_type_scalar)
call read_data
(read6, 0, fyear, ixm, ixx, ixp, &
maxrec, vwind_file, vatm_data, &
field_loc_center, field_type_scalar)
call read_data
(read6, 0, fyear, ixm, ixx, ixp, &
maxrec, rhoa_file, rhoa_data, &
field_loc_center, field_type_scalar)
call read_data
(read6, 0, fyear, ixm, ixx, ixp, &
maxrec, humid_file, Qa_data, &
field_loc_center, field_type_scalar)
else
call abort_ice
('nonbinary atm_data_format unavailable')
endif
! Interpolate
call interpolate_data
(Tair_data, Tair)
call interpolate_data
(uatm_data, uatm)
call interpolate_data
(vatm_data, vatm)
call interpolate_data
(rhoa_data, rhoa)
call interpolate_data
(Qa_data, Qa)
! Save record number for next time step
oldrecnum = recnum
end subroutine ncar_data
!=======================================================================
! ECMWF atmospheric forcing
!=======================================================================
!BOP
!
! !IROUTINE: ecmwf_files - construct filenames for ECMWF atmospheric data
!
! !INTERFACE:
!
subroutine ecmwf_files (yr) 1,6
!
! !DESCRIPTION:
!
! Construct filenames based on naming conventions used by Wieslaw Maslowski
! for reading (mostly) ECMWF atmospheric data.
! Edit for other directory structures or filenames.
! Note: The year number in these filenames does not matter, because
! subroutine file\_year will insert the correct year.
!
!
! !REVISION HISTORY:
!
! authors: William H. Lipscomb, LANL (based on ncar_files)
!
! !USES:
!
!
! !INPUT/OUTPUT PARAMETERS:
!
integer (kind=int_kind), intent(in) :: &
yr ! current forcing year
!
!EOP
!
fsw_file = &
trim(atm_data_dir)//'sol_2002.r'
call file_year
(fsw_file,yr)
flw_file = &
trim(atm_data_dir)//'flo_2002.r'
call file_year
(flw_file,yr)
rain_file = &
trim(atm_data_dir)//'prec_lanl_12.r'
! Comment out the file_year call if rain file is from climatology
!!! call file_year(rain_file,yr)
uwind_file = &
trim(atm_data_dir)//'ucmp_2002.r'
call file_year
(uwind_file,yr)
vwind_file = &
trim(atm_data_dir)//'vcmp_2002.r'
call file_year
(vwind_file,yr)
tair_file = &
trim(atm_data_dir)//'tair_2002.r'
call file_year
(tair_file,yr)
humid_file = &
trim(atm_data_dir)//'qa_2002.r'
call file_year
(humid_file,yr)
rhoa_file = &
trim(atm_data_dir)//'rhoa_ncar85-88_12.r'
! Comment out the file_year call if rhoa file is from climatology
!!! call file_year(rhoa_file,yr)
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'Forcing data year = ', fyear
write (nu_diag,*) 'Atmospheric data files:'
write (nu_diag,*) trim(fsw_file)
write (nu_diag,*) trim(flw_file)
write (nu_diag,*) trim(rain_file)
write (nu_diag,*) trim(uwind_file)
write (nu_diag,*) trim(vwind_file)
write (nu_diag,*) trim(tair_file)
write (nu_diag,*) trim(humid_file)
write (nu_diag,*) trim(rhoa_file)
endif ! master_task
end subroutine ecmwf_files
!=======================================================================
!BOP
!
! !IROUTINE: ecmwf_data - read ECMWF atmospheric data
!
! !INTERFACE:
!
subroutine ECMWF_data 1,21
!
! !DESCRIPTION:
!
! Read ECMWF atmospheric data.
!
! !REVISION HISTORY:
!
! authors: William H. Lipscomb, LANL
! Wieslaw Maslowski, NPS
! Based on ncar_data
!
! !USES:
!
use ice_flux
!
! !INPUT/OUTPUT PARAMETERS:
!
!
!EOP
!
integer (kind=int_kind) :: &
ixm,ixx,ixp , & ! record numbers for neighboring months
recnum , & ! record number
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
dataloc , & ! = 1 for data located in middle of time interval
! = 2 for date located at end of time interval
midmonth ! middle day of month
logical (kind=log_kind) :: readm, readd
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
midmonth = 15 ! data is given on 15th of every month
! midmonth = fix(p5 * real(daymo(month))) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
ixm = mod(month+maxrec-2,maxrec) + 1
ixp = mod(month, maxrec) + 1
if (mday >= midmonth) ixm = 99 ! other two points will be used
if (mday < midmonth) ixp = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
! Read 2 monthly values
readm = .false.
if (istep==1 .or. (mday==midmonth .and. sec==0)) readm = .true.
if (trim(atm_data_format) == 'bin') then
call read_clim_data
(readm, 0, ixm, month, ixp, &
rhoa_file, rhoa_data, field_loc_center, field_type_scalar)
call read_clim_data
(readm, 0, ixm, month, ixp, &
rain_file, fsnow_data, field_loc_center, field_type_scalar)
else
call abort_ice
('nonbinary atm_data_format unavailable')
endif
! Interpolate to current time step
call interpolate_data
(fsnow_data, fsnow)
call interpolate_data
(rhoa_data, rhoa)
!-------------------------------------------------------------------
! Daily data
!
! Assume that the daily value is located in the middle of the
! 24-hour period.
!-------------------------------------------------------------------
dataloc = 1 ! data located in middle of interval
maxrec = 365 ! days in a year (no leap years)
! current record number
recnum = int(yday) ! current record number
! Compute record numbers for surrounding data
ixm = mod(recnum+maxrec-2,maxrec) + 1
ixx = mod(recnum-1, maxrec) + 1
ixp = mod(recnum, maxrec) + 1
! Compute interpolation coefficients
! If data is located at the end of the time interval, then the
! data value for the current record goes in slot 2
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
if (real(sec,kind=dbl_kind) < p5*secday-puny) then ! first half of day
recslot = 2
ixp = 99
else ! second half of day
recslot = 1
ixm = 99
endif
call interp_coeff
(recnum, recslot, secday, dataloc)
! Read new data at midpoint of day
readd = .false.
if (istep==1 .or. (recslot==1 .and. oldrecslot==2)) &
readd = .true.
if (trim(atm_data_format) == 'bin') then
call read_data
(readd, 0, fyear, ixm, ixx, ixp, maxrec, &
tair_file, Tair_data, &
field_loc_center, field_type_scalar)
call read_data
(readd, 0, fyear, ixm, ixx, ixp, maxrec, &
uwind_file, uatm_data, &
field_loc_center, field_type_scalar)
call read_data
(readd, 0, fyear, ixm, ixx, ixp, maxrec, &
vwind_file, vatm_data, &
field_loc_center, field_type_scalar)
call read_data
(readd, 0, fyear, ixm, ixx, ixp, maxrec, &
fsw_file, fsw_data, &
field_loc_center, field_type_scalar)
call read_data
(readd, 0, fyear, ixm, ixx, ixp, maxrec, &
flw_file, flw_data, &
field_loc_center, field_type_scalar)
call read_data
(readd, 0, fyear, ixm, ixx, ixp, maxrec, &
humid_file, Qa_data, &
field_loc_center, field_type_scalar)
else
call abort_ice
('nonbinary atm_data_format unavailable')
endif
! Interpolate
call interpolate_data
(Tair_data, Tair)
call interpolate_data
(uatm_data, uatm)
call interpolate_data
(vatm_data, vatm)
call interpolate_data
( fsw_data, fsw)
call interpolate_data
( flw_data, flw)
call interpolate_data
( Qa_data, Qa)
! Save recslot for next time step
oldrecslot = recslot
end subroutine ecmwf_data
!=======================================================================
! Large and Yeager forcing (AOMIP style)
!=======================================================================
!
!BOP
!
! !IROUTINE: LY_files - construct filenames for Large and Yeager data
! note: includes AOMIP (OMIP) cldf climatology
!
! !INTERFACE:
!
subroutine LY_files (yr) 1,4
!
! !DESCRIPTION:
!
! Construct filenames based on the LANL naming conventions for NCAR data.
! Edit for other directory structures or filenames.
! Note: The year number in these filenames does not matter, because
! subroutine file_year will insert the correct year.
!
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke, LANL
!
! !USES:
!
!
! !INPUT/OUTPUT PARAMETERS:
!
integer (kind=int_kind), intent(in) :: &
yr ! current forcing year
!
!EOP
!
flw_file = &
trim(atm_data_dir)//'MONTHLY/cldf.omip.dat'
rain_file = &
trim(atm_data_dir)//'MONTHLY/prec.nmyr.dat'
uwind_file = &
trim(atm_data_dir)//'4XDAILY/u_10.1996.dat'
call file_year
(uwind_file,yr)
vwind_file = &
trim(atm_data_dir)//'4XDAILY/v_10.1996.dat'
call file_year
(vwind_file,yr)
tair_file = &
trim(atm_data_dir)//'4XDAILY/t_10.1996.dat'
call file_year
(tair_file,yr)
humid_file = &
trim(atm_data_dir)//'4XDAILY/q_10.1996.dat'
call file_year
(humid_file,yr)
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'Forcing data year = ', fyear
write (nu_diag,*) 'Atmospheric data files:'
write (nu_diag,*) trim(flw_file)
write (nu_diag,*) trim(rain_file)
write (nu_diag,*) trim(uwind_file)
write (nu_diag,*) trim(vwind_file)
write (nu_diag,*) trim(tair_file)
write (nu_diag,*) trim(humid_file)
endif ! master_task
end subroutine LY_files
!=======================================================================
!
!BOP
!
! !IROUTINE: LY_data - read Large and Yeager atmospheric data
! note: also uses AOMIP protocol, in part
!
! !INTERFACE:
!
subroutine LY_data 1,22
!
! !DESCRIPTION:
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_global_reductions
use ice_domain
, only: nblocks, distrb_info, blocks_ice
use ice_flux
use ice_grid
, only: hm, tlon, tlat, tmask, umask
!
! !INPUT/OUTPUT PARAMETERS:
!
!EOP
!
integer (kind=int_kind) :: &
i, j , &
imx,ixx,ipx , & ! record numbers for neighboring months
recnum , & ! record number
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
midmonth , & ! middle day of month
dataloc , & ! = 1 for data located in middle of time interval
! = 2 for date located at end of time interval
iblk , & ! block index
ilo,ihi,jlo,jhi ! beginning and end of physical domain
real (kind=dbl_kind) :: &
sec6hr , & ! number of seconds in 6 hours
vmin, vmax
logical (kind=log_kind) :: readm, read6
type (block) :: &
this_block ! block information for current block
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
midmonth = 15 ! data is given on 15th of every month
! midmonth = fix(p5 * real(daymo(month))) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
imx = mod(month+maxrec-2,maxrec) + 1
ipx = mod(month, maxrec) + 1
if (mday >= midmonth) imx = 99 ! other two points will be used
if (mday < midmonth) ipx = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
! Read 2 monthly values
readm = .false.
if (istep==1 .or. (mday==midmonth .and. sec==0)) readm = .true.
call read_clim_data
(readm, 0, imx, month, ipx, &
flw_file, cldf_data, field_loc_center, field_type_scalar)
call read_clim_data
(readm, 0, imx, month, ipx, &
rain_file, fsnow_data, field_loc_center, field_type_scalar)
call interpolate_data
(cldf_data, cldf)
call interpolate_data
(fsnow_data, fsnow) ! units mm/s = kg/m^2/s
!-------------------------------------------------------------------
! 6-hourly data
!
! Assume that the 6-hourly value is located at the end of the
! 6-hour period. This is the convention for NCEP reanalysis data.
! E.g. record 1 gives conditions at 6 am GMT on 1 January.
!-------------------------------------------------------------------
dataloc = 2 ! data located at end of interval
sec6hr = secday/c4 ! seconds in 6 hours
maxrec = 1460 ! 365*4
! current record number
recnum = 4*int(yday) - 3 + int(real(sec,kind=dbl_kind)/sec6hr)
! Compute record numbers for surrounding data (2 on each side)
imx = mod(recnum+maxrec-2,maxrec) + 1
ixx = mod(recnum-1, maxrec) + 1
! ipx = mod(recnum, maxrec) + 1
! Compute interpolation coefficients
! If data is located at the end of the time interval, then the
! data value for the current record goes in slot 2
recslot = 2
ipx = 99
call interp_coeff
(recnum, recslot, sec6hr, dataloc)
! Read
read6 = .false.
if (istep==1 .or. oldrecnum .ne. recnum) read6 = .true.
if (trim(atm_data_format) == 'bin') then
call read_data
(read6, 0, fyear, imx, ixx, ipx, maxrec, &
tair_file, Tair_data, &
field_loc_center, field_type_scalar)
call read_data
(read6, 0, fyear, imx, ixx, ipx, maxrec, &
uwind_file, uatm_data, &
field_loc_center, field_type_scalar)
call read_data
(read6, 0, fyear, imx, ixx, ipx, maxrec, &
vwind_file, vatm_data, &
field_loc_center, field_type_scalar)
call read_data
(read6, 0, fyear, imx, ixx, ipx, maxrec, &
humid_file, Qa_data, &
field_loc_center, field_type_scalar)
else
call abort_ice
('nonbinary atm_data_format unavailable')
endif
! Interpolate
call interpolate_data
(Tair_data, Tair)
call interpolate_data
(uatm_data, uatm)
call interpolate_data
(vatm_data, vatm)
call interpolate_data
(Qa_data, Qa)
do iblk = 1, nblocks
call Qa_fixLY
(nx_block, ny_block, &
Tair (:,:,iblk), &
Qa (:,:,iblk))
do j = 1, ny_block
do i = 1, nx_block
Qa (i,j,iblk) = Qa (i,j,iblk) * hm(i,j,iblk)
Tair(i,j,iblk) = Tair(i,j,iblk) * hm(i,j,iblk)
uatm(i,j,iblk) = uatm(i,j,iblk) * hm(i,j,iblk)
vatm(i,j,iblk) = vatm(i,j,iblk) * hm(i,j,iblk)
enddo
enddo
! AOMIP
this_block = get_block
(blocks_ice(iblk),iblk)
ilo = this_block%ilo
ihi = this_block%ihi
jlo = this_block%jlo
jhi = this_block%jhi
call compute_shortwave
(nx_block, ny_block, &
ilo, ihi, jlo, jhi, &
TLON (:,:,iblk), &
TLAT (:,:,iblk), &
hm (:,:,iblk), &
Qa (:,:,iblk), &
cldf (:,:,iblk), &
fsw (:,:,iblk))
enddo ! iblk
! Save record number
oldrecnum = recnum
if (dbug) then
if (my_task == master_task) write (nu_diag,*) 'LY_bulk_data'
vmin = global_minval(fsw,distrb_info,tmask)
vmax = global_maxval(fsw,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'fsw',vmin,vmax
vmin = global_minval(cldf,distrb_info,tmask)
vmax = global_maxval(cldf,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'cldf',vmin,vmax
vmin =global_minval(fsnow,distrb_info,tmask)
vmax =global_maxval(fsnow,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'fsnow',vmin,vmax
vmin = global_minval(Tair,distrb_info,tmask)
vmax = global_maxval(Tair,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'Tair',vmin,vmax
vmin = global_minval(uatm,distrb_info,umask)
vmax = global_maxval(uatm,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'uatm',vmin,vmax
vmin = global_minval(vatm,distrb_info,umask)
vmax = global_maxval(vatm,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'vatm',vmin,vmax
vmin = global_minval(Qa,distrb_info,tmask)
vmax = global_maxval(Qa,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'Qa',vmin,vmax
endif ! dbug
end subroutine LY_data
!=======================================================================
subroutine compute_shortwave(nx_block, ny_block, & 2
ilo, ihi, jlo, jhi, &
TLON, TLAT, hm, Qa, cldf, fsw)
!---!-------------------------------------------------------------------
!---! AOMIP shortwave forcing
!---!-------------------------------------------------------------------
integer (kind=int_kind), intent(in) :: &
nx_block, ny_block, & ! block dimensions
ilo,ihi,jlo,jhi ! beginning and end of physical domain
real (kind=dbl_kind), dimension(nx_block,ny_block), intent(in) :: &
TLON, TLAT , & ! longitude, latitude
Qa , & ! specific humidity
cldf , & ! cloud fraction
hm ! land mask
real (kind=dbl_kind), dimension(nx_block,ny_block), &
intent(inout) :: &
fsw ! shortwave
real (kind=dbl_kind) :: &
hour_angle, &
solar_time, &
declin , &
cosZ , &
e, d , &
sw0 , &
deg2rad
integer (kind=int_kind) :: &
i, j
do j=jlo,jhi
do i=ilo,ihi
deg2rad = pi/c180
solar_time = mod(real(sec,kind=dbl_kind),secday)/c3600 &
+ c12*sin(p5*TLON(i,j))
hour_angle = (c12 - solar_time)*pi/c12
declin = 23.44_dbl_kind*cos((172._dbl_kind-yday) &
* c2*pi/c365)*deg2rad ! use dayyr instead of c365???
cosZ = sin(TLAT(i,j))*sin(declin) &
+ cos(TLAT(i,j))*cos(declin)*cos(hour_angle)
cosZ = max(cosZ,c0)
e = 1.e5*Qa(i,j)/(0.622_dbl_kind + 0.378_dbl_kind*Qa(i,j))
d = (cosZ+2.7_dbl_kind)*e*1.e-5_dbl_kind+1.085_dbl_kind*cosZ+p1
sw0 = 1353._dbl_kind*cosZ**2/d
sw0 = max(sw0,c0)
! total downward shortwave for cice
Fsw(i,j) = sw0*(c1-p6*cldf(i,j)**3)
Fsw(i,j) = Fsw(i,j)*hm(i,j)
enddo
enddo
end subroutine compute_shortwave
!=======================================================================
subroutine Qa_fixLY(nx_block, ny_block, Tair, Qa) 2,1
use ice_work
, only: worka
integer (kind=int_kind), intent(in) :: &
nx_block, ny_block ! block dimensions
real (kind=dbl_kind), dimension(nx_block,ny_block), intent(in) :: &
Tair ! air temperature
real (kind=dbl_kind), dimension(nx_block,ny_block), &
intent(inout) :: &
Qa ! specific humidity
worka = Tair - Tffresh
worka = c2 + (0.7859_dbl_kind + 0.03477_dbl_kind*worka) &
/(c1 + 0.00412_dbl_kind*worka) & ! 2+ converts ea mb -> Pa
+ 0.00422_dbl_kind*worka ! for ice
! vapor pressure
worka = (c10**worka) ! saturated
worka = max(worka,puny) ! puny over land to prevent division by zero
! specific humidity
worka = 0.622_dbl_kind*worka/(1.e5_dbl_kind-0.378_dbl_kind*worka)
Qa = min(Qa, worka)
end subroutine Qa_fixLY
!=======================================================================
! HadGEM or HadGAM atmospheric forcing
!=======================================================================
!
!BOP
!
! !IROUTINE: hadgem_files - construct filenames for HadGEM or HadGAM files
!
! !INTERFACE:
!
subroutine hadgem_files (yr) 1,17
!
! !DESCRIPTION:
!
! Construct filenames based on selected model options
!
! Note: The year number in these filenames does not matter, because
! subroutine file\_year will insert the correct year.
!
! !REVISION HISTORY:
!
! author: Alison McLaren, Met Office
!
! !USES:
!
use ice_therm_vertical
, only: calc_Tsfc
use ice_ocean
, only: oceanmixed_ice
!
! !INPUT/OUTPUT PARAMETERS:
!
integer (kind=int_kind), intent(in) :: &
yr ! current forcing year
!
!EOP
!
integer (kind=int_kind) :: &
n ! thickness category index
! -----------------------------------------------------------
! Rainfall and snowfall
! -----------------------------------------------------------
snow_file = &
trim(atm_data_dir)//'MONTHLY/snowfall.1996.nc'
call file_year
(snow_file,yr)
rain_file = &
trim(atm_data_dir)//'MONTHLY/rainfall.1996.nc'
call file_year
(rain_file,yr)
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'Atmospheric data files:'
write (nu_diag,*) trim(rain_file)
write (nu_diag,*) trim(snow_file)
endif
if (calc_strair) then
! --------------------------------------------------------
! Wind velocity
! --------------------------------------------------------
uwind_file = &
trim(atm_data_dir)//'MONTHLY/u_10.1996.nc'
call file_year
(uwind_file,yr)
vwind_file = &
trim(atm_data_dir)//'MONTHLY/v_10.1996.nc'
call file_year
(vwind_file,yr)
if (my_task == master_task) then
write (nu_diag,*) trim(uwind_file)
write (nu_diag,*) trim(vwind_file)
endif
else
! --------------------------------------------------------
! Wind stress
! --------------------------------------------------------
strax_file = &
trim(atm_data_dir)//'MONTHLY/taux.1996.nc'
call file_year
(strax_file,yr)
stray_file = &
trim(atm_data_dir)//'MONTHLY/tauy.1996.nc'
call file_year
(stray_file,yr)
if (my_task == master_task) then
write (nu_diag,*) trim(strax_file)
write (nu_diag,*) trim(stray_file)
endif
if (calc_Tsfc .or. oceanmixed_ice) then
! --------------------------------------------------
! Wind speed
! --------------------------------------------------
wind_file = &
trim(atm_data_dir)//'MONTHLY/wind_10.1996.nc'
call file_year
(wind_file,yr)
if (my_task == master_task) then
write (nu_diag,*) trim(wind_file)
endif
endif ! calc_Tsfc or oceanmixed_ice
endif ! calc_strair
! --------------------------------------------------------------
! Atmosphere properties. Even if these fields are not
! being used to force the ice (i.e. calc_Tsfc=.false.), they
! are still needed to generate forcing for mixed layer model or
! to calculate wind stress
! --------------------------------------------------------------
if (calc_Tsfc .or. oceanmixed_ice .or. calc_strair) then
fsw_file = &
trim(atm_data_dir)//'MONTHLY/SW_incoming.1996.nc'
call file_year
(fsw_file,yr)
flw_file = &
trim(atm_data_dir)//'MONTHLY/LW_incoming.1996.nc'
call file_year
(flw_file,yr)
tair_file = &
trim(atm_data_dir)//'MONTHLY/t_10.1996.nc'
call file_year
(tair_file,yr)
humid_file = &
trim(atm_data_dir)//'MONTHLY/q_10.1996.nc'
call file_year
(humid_file,yr)
rhoa_file = &
trim(atm_data_dir)//'MONTHLY/rho_10.1996.nc'
call file_year
(rhoa_file,yr)
if (my_task == master_task) then
write (nu_diag,*) trim(fsw_file)
write (nu_diag,*) trim(flw_file)
write (nu_diag,*) trim(tair_file)
write (nu_diag,*) trim(humid_file)
write (nu_diag,*) trim(rhoa_file)
endif ! master_task
endif ! calc_Tsfc or oceanmixed_ice or calc_strair
if (.not. calc_Tsfc) then
! ------------------------------------------------------
! Sublimation, topmelt and botmelt
! ------------------------------------------------------
do n = 1, ncat
! 'topmelt' = fsurf - fcondtop.
write(topmelt_file(n), '(a,i1,a)') &
trim(atm_data_dir)//'MONTHLY/topmeltn',n,'.1996.nc'
call file_year
(topmelt_file(n),yr)
! 'botmelt' = fcondtop.
write(botmelt_file(n), '(a,i1,a)') &
trim(atm_data_dir)//'MONTHLY/botmeltn',n,'.1996.nc'
call file_year
(botmelt_file(n),yr)
enddo
! 'sublim' = - flat / Lsub.
sublim_file = &
trim(atm_data_dir)//'MONTHLY/sublim.1996.nc'
call file_year
(sublim_file,yr)
if (my_task == master_task) then
do n = 1, ncat
write (nu_diag,*) trim(topmelt_file(n))
write (nu_diag,*) trim(botmelt_file(n))
enddo
write (nu_diag,*) trim(sublim_file)
endif
endif ! .not. calc_Tsfc
end subroutine hadgem_files
!=======================================================================
!
!BOP
!
! !IROUTINE: hadgem_data - read HadGEM or HadGAM atmospheric data
!
! !INTERFACE:
!
subroutine hadgem_data 1,36
!
! !DESCRIPTION:
!
! !REVISION HISTORY:
!
! authors: Alison McLaren, Met Office
!
! !USES:
!
use ice_domain
, only: nblocks
use ice_flux
use ice_state
, only: aice,aicen
use ice_ocean
, only: oceanmixed_ice
use ice_therm_vertical
, only: calc_Tsfc
!
! !INPUT/OUTPUT PARAMETERS:
!
!
!EOP
!
integer (kind=int_kind) :: &
i, j , & ! horizontal indices
n , & ! thickness category index
iblk , & ! block index
ixm,ixx,ixp , & ! record numbers for neighboring months
recnum , & ! record number
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
dataloc , & ! = 1 for data located in middle of time interval
! = 2 for date located at end of time interval
midmonth ! middle day of month
logical (kind=log_kind) :: readm
real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks) :: &
topmelt, & ! temporary fields
botmelt, &
sublim
character (char_len) :: &
fieldname ! field name in netcdf file
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
midmonth = 15 ! data is given on 15th of every month
! midmonth = fix(p5 * real(daymo(month))) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
ixm = mod(month+maxrec-2,maxrec) + 1
ixp = mod(month, maxrec) + 1
if (mday >= midmonth) ixm = 99 ! other two points will be used
if (mday < midmonth) ixp = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
! Read 2 monthly values
readm = .false.
if (istep==1 .or. (mday==midmonth .and. sec==0)) readm = .true.
! -----------------------------------------------------------
! Rainfall and snowfall
! -----------------------------------------------------------
fieldname='rainfall'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, rain_file, fieldname, frain_data, &
field_loc_center, field_type_scalar)
fieldname='snowfall'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, snow_file, fieldname, fsnow_data, &
field_loc_center, field_type_scalar)
! Interpolate to current time step
call interpolate_data
(fsnow_data, fsnow)
call interpolate_data
(frain_data, frain)
if (calc_strair) then
! --------------------------------------------------------
! Wind velocity
! --------------------------------------------------------
fieldname='u_10'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, uwind_file, fieldname, uatm_data, &
field_loc_center, field_type_vector)
fieldname='v_10'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, vwind_file, fieldname, vatm_data, &
field_loc_center, field_type_vector)
! Interpolate to current time step
call interpolate_data
(uatm_data, uatm)
call interpolate_data
(vatm_data, vatm)
else
! --------------------------------------------------------
! Wind stress
! --------------------------------------------------------
fieldname='taux'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, strax_file, fieldname, strax_data, &
field_loc_center, field_type_vector)
fieldname='tauy'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, stray_file, fieldname, stray_data, &
field_loc_center, field_type_vector)
! Interpolate to current time step
call interpolate_data
(strax_data, strax)
call interpolate_data
(stray_data, stray)
if (calc_Tsfc .or. oceanmixed_ice) then
! --------------------------------------------------
! Wind speed
! --------------------------------------------------
fieldname='wind_10'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, wind_file, fieldname, wind_data, &
field_loc_center, field_type_scalar)
! Interpolate to current time step
call interpolate_data
(wind_data, wind)
endif ! calc_Tsfc or oceanmixed_ice
endif ! calc_strair
! -----------------------------------------------------------
! SW incoming, LW incoming, air temperature, density and
! humidity at 10m.
!
! Even if these fields are not being used to force the ice
! (i.e. calc_Tsfc=.false.), they are still needed to generate
! forcing for mixed layer model or to calculate wind stress
! -----------------------------------------------------------
if (calc_Tsfc .or. oceanmixed_ice .or. calc_strair) then
fieldname='SW_incoming'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, fsw_file, fieldname, fsw_data, &
field_loc_center, field_type_scalar)
fieldname='LW_incoming'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, flw_file, fieldname, flw_data, &
field_loc_center, field_type_scalar)
fieldname='t_10'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, tair_file, fieldname, Tair_data, &
field_loc_center, field_type_scalar)
fieldname='rho_10'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, rhoa_file, fieldname, rhoa_data, &
field_loc_center, field_type_scalar)
fieldname='q_10'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, humid_file, fieldname, Qa_data, &
field_loc_center, field_type_scalar)
! Interpolate onto current timestep
call interpolate_data
(fsw_data, fsw)
call interpolate_data
(flw_data, flw)
call interpolate_data
(Tair_data, Tair)
call interpolate_data
(rhoa_data, rhoa)
call interpolate_data
(Qa_data, Qa)
endif ! calc_Tsfc or oceanmixed_ice or calc_strair
if (.not. calc_Tsfc) then
! ------------------------------------------------------
! Sublimation, topmelt and botmelt
! ------------------------------------------------------
fieldname='sublim'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, sublim_file, fieldname, sublim_data, &
field_loc_center, field_type_scalar)
! Interpolate to current time step
call interpolate_data
(sublim_data, sublim)
do n = 1, ncat
write(fieldname, '(a,i1)') 'topmeltn',n
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, topmelt_file(n), fieldname, topmelt_data(:,:,:,:,n), &
field_loc_center, field_type_scalar)
write(fieldname, '(a,i1)') 'botmeltn',n
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, botmelt_file(n), fieldname, botmelt_data(:,:,:,:,n), &
field_loc_center, field_type_scalar)
call interpolate_data
(topmelt_data(:,:,:,:,n), topmelt)
call interpolate_data
(botmelt_data(:,:,:,:,n), botmelt)
!--------------------------------------------------------
! Convert from UM variables to CICE variables
! topmelt = fsurf - fcondtop
! botmelt = fcondtop (as zero layer)
!
! Convert UM sublimation data into CICE LH flux
! (sublim = - flatn / Lsub) and have same value for all
! categories
!--------------------------------------------------------
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
fcondtopn_f(i,j,n,iblk) = botmelt(i,j,iblk)
fsurfn_f(i,j,n,iblk) = topmelt(i,j,iblk) &
+ botmelt(i,j,iblk)
flatn_f(i,j,n,iblk) = - sublim(i,j,iblk)*Lsub
enddo
enddo
enddo
enddo ! ncat
endif ! .not. calc_Tsfc
end subroutine hadgem_data
!=======================================================================
! monthly forcing
!=======================================================================
!
!BOP
!
! !IROUTINE: monthly_files - construct filenames for monthly data
!
! !INTERFACE:
!
subroutine monthly_files (yr) 1,5
!
! !DESCRIPTION:
!
! Construct filenames based on the LANL naming conventions for NCAR data.
! Edit for other directory structures or filenames.
! Note: The year number in these filenames does not matter, because
! subroutine file_year will insert the correct year.
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke, LANL
!
! !USES:
!
!
! !INPUT/OUTPUT PARAMETERS:
!
integer (kind=int_kind), intent(in) :: &
yr ! current forcing year
!
!EOP
!
flw_file = &
trim(atm_data_dir)//'MONTHLY/cldf.omip.dat'
rain_file = &
trim(atm_data_dir)//'MONTHLY/prec.nmyr.dat'
tair_file = &
trim(atm_data_dir)//'MONTHLY/t_10.1996.dat'
call file_year
(tair_file,yr)
humid_file = &
trim(atm_data_dir)//'MONTHLY/q_10.1996.dat'
call file_year
(humid_file,yr)
! stress/speed is used instead of wind components
strax_file = &
trim(atm_data_dir)//'MONTHLY/strx.1996.dat'
call file_year
(strax_file,yr)
stray_file = &
trim(atm_data_dir)//'MONTHLY/stry.1996.dat'
call file_year
(stray_file,yr)
wind_file = &
trim(atm_data_dir)//'MONTHLY/wind.1996.dat'
call file_year
(wind_file,yr)
if (my_task == master_task) then
write (nu_diag,*) ' '
write (nu_diag,*) 'Forcing data year = ', fyear
write (nu_diag,*) 'Atmospheric data files:'
write (nu_diag,*) trim(flw_file)
write (nu_diag,*) trim(rain_file)
write (nu_diag,*) trim(tair_file)
write (nu_diag,*) trim(humid_file)
write (nu_diag,*) trim(uwind_file)
write (nu_diag,*) trim(vwind_file)
endif ! master_task
end subroutine monthly_files
!=======================================================================
!
!BOP
!
! !IROUTINE: monthly_data - read monthly atmospheric data
!
! !INTERFACE:
!
subroutine monthly_data 1,22
!
! !DESCRIPTION:
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_global_reductions
use ice_domain
, only: nblocks, distrb_info, blocks_ice
use ice_flux
use ice_grid
, only: hm, tlon, tlat, tmask, umask
!
! !INPUT/OUTPUT PARAMETERS:
!
!EOP
!
integer (kind=int_kind) :: &
i, j , &
imx,ipx , & ! record numbers for neighboring months
recnum , & ! record number
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
midmonth , & ! middle day of month
iblk , & ! block index
ilo,ihi,jlo,jhi ! beginning and end of physical domain
real (kind=dbl_kind) :: &
vmin, vmax
logical (kind=log_kind) :: readm
type (block) :: &
this_block ! block information for current block
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
midmonth = 15 ! data is given on 15th of every month
! midmonth = fix(p5 * real(daymo(month))) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
imx = mod(month+maxrec-2,maxrec) + 1
ipx = mod(month, maxrec) + 1
if (mday >= midmonth) imx = 99 ! other two points will be used
if (mday < midmonth) ipx = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
! Read 2 monthly values
readm = .false.
if (istep==1 .or. (mday==midmonth .and. sec==0)) readm = .true.
call read_clim_data
(readm, 0, imx, month, ipx, &
flw_file, cldf_data, &
field_loc_center, field_type_scalar)
call read_clim_data
(readm, 0, imx, month, ipx, &
rain_file, fsnow_data, &
field_loc_center, field_type_scalar)
call read_clim_data
(readm, 0, imx, month, ipx, &
tair_file, Tair_data, &
field_loc_center, field_type_scalar)
call read_clim_data
(readm, 0, imx, month, ipx, &
humid_file, Qa_data, &
field_loc_center, field_type_scalar)
call read_clim_data
(readm, 0, imx, month, ipx, &
wind_file, wind_data, &
field_loc_center, field_type_scalar)
call read_clim_data
(readm, 0, imx, month, ipx, &
strax_file, strax_data, &
field_loc_center, field_type_vector)
call read_clim_data
(readm, 0, imx, month, ipx, &
stray_file, stray_data, &
field_loc_center, field_type_vector)
call interpolate_data
(cldf_data, cldf)
call interpolate_data
(fsnow_data, fsnow) ! units mm/s = kg/m^2/s
call interpolate_data
(Tair_data, Tair)
call interpolate_data
(Qa_data, Qa)
call interpolate_data
(wind_data, wind)
call interpolate_data
(strax_data, strax)
call interpolate_data
(stray_data, stray)
do iblk = 1, nblocks
call Qa_fixLY
(nx_block, ny_block, &
Tair (:,:,iblk), &
Qa (:,:,iblk))
do j = 1, ny_block
do i = 1, nx_block
Qa (i,j,iblk) = Qa (i,j,iblk) * hm(i,j,iblk)
Tair (i,j,iblk) = Tair (i,j,iblk) * hm(i,j,iblk)
wind (i,j,iblk) = wind (i,j,iblk) * hm(i,j,iblk)
strax(i,j,iblk) = strax(i,j,iblk) * hm(i,j,iblk)
stray(i,j,iblk) = stray(i,j,iblk) * hm(i,j,iblk)
enddo
enddo
! AOMIP
this_block = get_block
(blocks_ice(iblk),iblk)
ilo = this_block%ilo
ihi = this_block%ihi
jlo = this_block%jlo
jhi = this_block%jhi
call compute_shortwave
(nx_block, ny_block, &
ilo, ihi, jlo, jhi, &
TLON (:,:,iblk), &
TLAT (:,:,iblk), &
hm (:,:,iblk), &
Qa (:,:,iblk), &
cldf (:,:,iblk), &
fsw (:,:,iblk))
enddo ! iblk
! Save record number
oldrecnum = recnum
if (dbug) then
if (my_task == master_task) write (nu_diag,*) 'LY_bulk_data'
vmin = global_minval(fsw,distrb_info,tmask)
vmax = global_maxval(fsw,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'fsw',vmin,vmax
vmin = global_minval(cldf,distrb_info,tmask)
vmax = global_maxval(cldf,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'cldf',vmin,vmax
vmin =global_minval(fsnow,distrb_info,tmask)
vmax =global_maxval(fsnow,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'fsnow',vmin,vmax
vmin = global_minval(Tair,distrb_info,tmask)
vmax = global_maxval(Tair,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'Tair',vmin,vmax
vmin = global_minval(wind,distrb_info,umask)
vmax = global_maxval(wind,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'wind',vmin,vmax
vmin = global_minval(strax,distrb_info,umask)
vmax = global_maxval(strax,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'strax',vmin,vmax
vmin = global_minval(stray,distrb_info,umask)
vmax = global_maxval(stray,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'stray',vmin,vmax
vmin = global_minval(Qa,distrb_info,tmask)
vmax = global_maxval(Qa,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'Qa',vmin,vmax
endif ! dbug
end subroutine monthly_data
!=======================================================================
! Climatological ocean forcing
!=======================================================================
!BOP
!
! !IROUTINE: ocn_data_clim - interpolate sss, sst; restore sst
!
! !INTERFACE:
!
subroutine ocn_data_clim (dt) 1,9
!
! !DESCRIPTION:
!
! Interpolate monthly sss, sst data to timestep.
! Restore prognostic sst to data.
! Interpolate fields from U grid to T grid if necessary.
!
! !REVISION HISTORY:
!
! author: Elizabeth C. Hunke and William H. Lipscomb, LANL
!
! !USES:
!
use ice_domain
, only: nblocks
use ice_ocean
use ice_flux
, only: Tf, sss, sst, uocn, vocn, ss_tltx, ss_tlty, Tfrzpt
use ice_grid
, only: t2ugrid_vector
!
! !INPUT/OUTPUT PARAMETERS:
!
real (kind=dbl_kind), intent(in) :: &
dt ! time step
!
!EOP
!
integer (kind=int_kind) :: &
i, j, iblk , & ! horizontal indices
ixm,ixp , & ! record numbers for neighboring months
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
midmonth ! middle day of month
real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks) :: &
sstdat ! data value toward which SST is restored
logical (kind=log_kind) :: readm
if (my_task == master_task .and. istep == 1) then
if (trim(sss_data_type)=='clim') then
write (nu_diag,*) ' '
write (nu_diag,*) 'SSS data interpolated to timestep:'
write (nu_diag,*) trim(sss_file)
endif
if (trim(sst_data_type)=='clim') then
write (nu_diag,*) ' '
write (nu_diag,*) 'SST data interpolated to timestep:'
write (nu_diag,*) trim(sst_file)
if (restore_sst) write (nu_diag,*) &
'SST restoring timescale (days) =', trestore
endif
endif ! my_task, istep
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
if (trim(sss_data_type)=='clim' .or. &
trim(sst_data_type)=='clim') then
midmonth = 15 ! data is given on 15th of every month
!!! midmonth = fix(p5 * real(daymo(month))) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
ixm = mod(month+maxrec-2,maxrec) + 1
ixp = mod(month, maxrec) + 1
if (mday >= midmonth) ixm = 99 ! other two points will be used
if (mday < midmonth) ixp = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
readm = .false.
if (istep==1 .or. (mday==midmonth .and. sec==0)) readm = .true.
endif ! sss/sst_data_type
!-------------------------------------------------------------------
! Read two monthly SSS values and interpolate.
! Note: SSS is restored instantaneously to data.
!-------------------------------------------------------------------
if (trim(sss_data_type)=='clim') then
call read_clim_data
(readm, 0, ixm, month, ixp, &
sss_file, sss_data, &
field_loc_center, field_type_scalar)
call interpolate_data
(sss_data, sss)
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
sss(i,j,iblk) = max(sss(i,j,iblk), c0)
if (trim(Tfrzpt) == 'constant') then
Tf (i,j,iblk) = -1.8_dbl_kind ! deg C
else ! default: Tfrzpt = 'linear_S'
Tf (i,j,iblk) = -depressT * sss(i,j,iblk) ! deg C
endif
enddo
enddo
enddo
endif
!-------------------------------------------------------------------
! Read two monthly SST values and interpolate.
! Restore toward interpolated value.
!-------------------------------------------------------------------
if (trim(sst_data_type)=='clim') then
call read_clim_data
(readm, 0, ixm, month, ixp, &
sst_file, sst_data, &
field_loc_center, field_type_scalar)
call interpolate_data
(sst_data, sstdat)
if (restore_sst) then
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
sst(i,j,iblk) = sst(i,j,iblk) &
+ (sstdat(i,j,iblk)-sst(i,j,iblk))*dt/trest
enddo
enddo
enddo
endif
endif
end subroutine ocn_data_clim
!=======================================================================
! NCAR CCSM M-configuration (AIO) ocean forcing
!=======================================================================
!
!BOP
!
! !IROUTINE: ocn_data_ncar_init - reads data set
!
! !INTERFACE:
!
subroutine ocn_data_ncar_init 1,13
!
! !DESCRIPTION:
!
! Reads NCAR pop ocean forcing data set 'pop_frc_gx1v3_010815.nc'
!
! List of ocean forcing fields: Note that order is important!
! (order is determined by field list in vname).
!
! For ocean mixed layer-----------------------------units
!
! 1 sst------temperature---------------------------(C) \\
! 2 sss------salinity------------------------------(ppt) \\
! 3 hbl------depth---------------------------------(m) \\
! 4 u--------surface u current---------------------(m/s) \\
! 5 v--------surface v current---------------------(m/s) \\
! 6 dhdx-----surface tilt x direction--------------(m/m) \\
! 7 dhdy-----surface tilt y direction--------------(m/m) \\
! 8 qdp------ocean sub-mixed layer heat flux-------(W/m2)\\
!
! Fields 4, 5, 6, 7 are on the U-grid; 1, 2, 3, and 8 are
! on the T-grid.
!
! !REVISION HISTORY:
!
! authors: Bruce Briegleb, NCAR
! Elizabeth Hunke, LANL
!
! !USES:
!
use ice_domain
, only: nblocks, distrb_info
use ice_gather_scatter
use ice_exit
use ice_work
, only: work1
use ice_read_write
#ifdef ncdf
use netcdf
#endif
!
! !INPUT/OUTPUT PARAMETERS:
!
!EOP
!
integer (kind=int_kind) :: &
n , & ! field index
m , & ! month index
nrec, & ! record number for direct access
nbits
character(char_len) :: &
vname(nfld) ! variable names to search for in file
data vname / &
'T', 'S', 'hblt', 'U', 'V', &
'dhdx', 'dhdy', 'qdp' /
integer (kind=int_kind) :: &
fid , & ! file id
dimid ! dimension id
integer (kind=int_kind) :: &
status , & ! status flag
nlat , & ! number of longitudes of data
nlon ! number of latitudes of data
if (my_task == master_task) then
write (nu_diag,*) 'WARNING: evp_prep calculates surface tilt'
write (nu_diag,*) 'WARNING: stress from geostrophic currents,'
write (nu_diag,*) 'WARNING: not data from ocean forcing file.'
write (nu_diag,*) 'WARNING: Alter ice_dyn_evp.F if desired.'
if (restore_sst) write (nu_diag,*) &
'SST restoring timescale = ',trestore,' days'
sst_file = trim(ocn_data_dir)//oceanmixed_file ! not just sst
!---------------------------------------------------------------
! Read in ocean forcing data from an existing file
!---------------------------------------------------------------
write (nu_diag,*) 'ocean mixed layer forcing data file = ', &
sst_file
endif ! master_task
if (trim(ocn_data_format) == 'nc') then
#ifdef ncdf
if (my_task == master_task) then
call ice_open_nc
(sst_file, fid)
! status = nf90_inq_dimid(fid,'nlon',dimid)
status = nf90_inq_dimid(fid,'ni',dimid)
status = nf90_inquire_dimension(fid,dimid,len=nlon)
! status = nf90_inq_dimid(fid,'nlat',dimid)
status = nf90_inq_dimid(fid,'nj',dimid)
status = nf90_inquire_dimension(fid,dimid,len=nlat)
if( nlon .ne. nx_global ) then
call abort_ice
('ice: ocn frc file nlon ne nx_global')
endif
if( nlat .ne. ny_global ) then
call abort_ice
('ice: ocn frc file nlat ne ny_global')
endif
endif ! master_task
! Read in ocean forcing data for all 12 months
do n=1,nfld
do m=1,12
! Note: netCDF does single to double conversion if necessary
if (n >= 4 .and. n <= 7) then
call ice_read_nc
(fid, m, vname(n), work1, dbug, &
field_loc_NEcorner, field_type_vector)
else
call ice_read_nc
(fid, m, vname(n), work1, dbug, &
field_loc_center, field_type_scalar)
endif
ocn_frc_m(:,:,:,n,m) = work1(:,:,:)
enddo ! month loop
enddo ! field loop
if (my_task == master_task) status = nf90_close(fid)
#endif
else ! binary format
nbits = 64
call ice_open
(nu_forcing, sst_file, nbits)
nrec = 0
do n=1,nfld
do m=1,12
nrec = nrec + 1
if (n >= 4 .and. n <= 7) then
call ice_read
(nu_forcing, nrec, work1, 'rda8', dbug, &
field_loc_NEcorner, field_type_vector)
else
call ice_read
(nu_forcing, nrec, work1, 'rda8', dbug, &
field_loc_center, field_type_scalar)
endif
ocn_frc_m(:,:,:,n,m) = work1(:,:,:)
enddo ! month loop
enddo ! field loop
close (nu_forcing)
endif
!echmod - currents cause Fram outflow to be too large
ocn_frc_m(:,:,:,4,:) = c0
ocn_frc_m(:,:,:,5,:) = c0
!echmod
end subroutine ocn_data_ncar_init
!=======================================================================
!
!BOP
!
! !IROUTINE: ocn_data_ncar - interpolates data to timestep
!
! !INTERFACE:
!
subroutine ocn_data_ncar(dt) 1,11
!
! !DESCRIPTION:
!
! Interpolate monthly ocean data to timestep.
! Restore sst if desired. sst is updated with surface fluxes in ice_ocean.F.
!
! !REVISION HISTORY:
!
! authors: same as module
!
! !USES:
!
use ice_global_reductions
use ice_domain
, only: nblocks, distrb_info
use ice_gather_scatter
use ice_exit
use ice_work
, only: work_g1, work1
use ice_flux
, only: sss, sst, Tf, uocn, vocn, ss_tltx, ss_tlty, &
qdp, hmix, Tfrzpt
! use ice_ocean
use ice_restart
, only: restart
use ice_grid
, only: hm, tmask, umask
!
!
! !INPUT/OUTPUT PARAMETERS:
!
real (kind=dbl_kind), intent(in) :: &
dt ! time step
!
!EOP
!
integer (kind=int_kind) :: &
i, j, n, iblk , &
imx,ipx , & ! record numbers for neighboring months
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
midmonth ! middle day of month
real (kind=dbl_kind) :: &
vmin, vmax
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
midmonth = 15 ! data is given on 15th of every month
! midmonth = fix(p5 * real(daymo(month),kind=dbl_kind)) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
imx = mod(month+maxrec-2,maxrec) + 1
ipx = mod(month, maxrec) + 1
if (mday >= midmonth) imx = 99 ! other two points will be used
if (mday < midmonth) ipx = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
do n = nfld, 1, -1
do iblk = 1, nblocks
! use sst_data arrays as temporary work space until n=1
if (imx /= 99) then ! first half of month
sst_data(:,:,1,iblk) = ocn_frc_m(:,:,iblk,n,imx)
sst_data(:,:,2,iblk) = ocn_frc_m(:,:,iblk,n,month)
else ! second half of month
sst_data(:,:,1,iblk) = ocn_frc_m(:,:,iblk,n,month)
sst_data(:,:,2,iblk) = ocn_frc_m(:,:,iblk,n,ipx)
endif
enddo
call interpolate_data
(sst_data,work1)
! masking by hm is necessary due to NaNs in the data file
do j = 1, ny_block
do i = 1, nx_block
if (n == 2) sss (i,j,:) = c0
if (n == 3) hmix (i,j,:) = c0
if (n == 4) uocn (i,j,:) = c0
if (n == 5) vocn (i,j,:) = c0
if (n == 6) ss_tltx(i,j,:) = c0
if (n == 7) ss_tlty(i,j,:) = c0
if (n == 8) qdp (i,j,:) = c0
do iblk = 1, nblocks
if (hm(i,j,iblk) == c1) then
if (n == 2) sss (i,j,iblk) = work1(i,j,iblk)
if (n == 3) hmix (i,j,iblk) = work1(i,j,iblk)
if (n == 4) uocn (i,j,iblk) = work1(i,j,iblk)
if (n == 5) vocn (i,j,iblk) = work1(i,j,iblk)
if (n == 6) ss_tltx(i,j,iblk) = work1(i,j,iblk)
if (n == 7) ss_tlty(i,j,iblk) = work1(i,j,iblk)
if (n == 8) qdp (i,j,iblk) = work1(i,j,iblk)
endif
enddo
enddo
enddo
enddo
do j = 1, ny_block
do i = 1, nx_block
sss (i,j,:) = max (sss(i,j,:), c0)
if (trim(Tfrzpt) == 'constant') then
Tf (i,j,:) = -1.8_dbl_kind ! deg C
else ! default: Tfrzpt = 'linear_S'
Tf (i,j,:) = -depressT * sss(i,j,:) ! deg C
endif
hmix(i,j,:) = max(hmix(i,j,:), c0)
enddo
enddo
if (restore_sst) then
do j = 1, ny_block
do i = 1, nx_block
sst(i,j,:) = sst(i,j,:) + (work1(i,j,:)-sst(i,j,:))*dt/trest
enddo
enddo
! else sst is only updated in ice_ocean.F
endif
! initialize sst properly on first step
if (istep1 <= 1 .and. .not. (restart)) then
call interpolate_data
(sst_data,sst)
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
if (hm(i,j,iblk) == c1) then
sst(i,j,iblk) = max (sst(i,j,iblk), Tf(i,j,iblk))
else
sst(i,j,iblk) = c0
endif
enddo
enddo
enddo
endif
if (dbug) then
if (my_task == master_task) &
write (nu_diag,*) 'ocn_data_ncar'
vmin = global_minval(Tf,distrb_info,tmask)
vmax = global_maxval(Tf,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'Tf',vmin,vmax
vmin = global_minval(sst,distrb_info,tmask)
vmax = global_maxval(sst,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'sst',vmin,vmax
vmin = global_minval(sss,distrb_info,tmask)
vmax = global_maxval(sss,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'sss',vmin,vmax
vmin = global_minval(hmix,distrb_info,tmask)
vmax = global_maxval(hmix,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'hmix',vmin,vmax
vmin = global_minval(uocn,distrb_info,umask)
vmax = global_maxval(uocn,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'uocn',vmin,vmax
vmin = global_minval(vocn,distrb_info,umask)
vmax = global_maxval(vocn,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'vocn',vmin,vmax
vmin = global_minval(ss_tltx,distrb_info,umask)
vmax = global_maxval(ss_tltx,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'ss_tltx',vmin,vmax
vmin = global_minval(ss_tlty,distrb_info,umask)
vmax = global_maxval(ss_tlty,distrb_info,umask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'ss_tlty',vmin,vmax
vmin = global_minval(qdp,distrb_info,tmask)
vmax = global_maxval(qdp,distrb_info,tmask)
if (my_task.eq.master_task) &
write (nu_diag,*) 'qdp',vmin,vmax
endif
end subroutine ocn_data_ncar
!=======================================================================
!
!BOP
!
! !IROUTINE: ocn_data_hadgem - read HadGEM ocean data
!
! !INTERFACE:
!
subroutine ocn_data_hadgem(dt) 1,12
!
! !DESCRIPTION:
! Reads in HadGEM ocean forcing data as required from netCDF files
! Current options (selected by sst_data_type)
! hadgem_sst: read in sst only
! hadgem_sst_uvocn: read in sst plus uocn and vocn
!
!
! !REVISION HISTORY:
!
! authors: Ann Keen, Met Office
!
! !USES:
!
use ice_domain
, only: nblocks
use ice_flux
, only: sst, uocn, vocn
use ice_grid
, only: t2ugrid_vector, ANGLET
!
! !INPUT/OUTPUT PARAMETERS:
!
!
!EOP
!
real (kind=dbl_kind), intent(in) :: &
dt ! time step
integer (kind=int_kind) :: &
i, j , & ! horizontal indices
n , & ! thickness category index
iblk , & ! block index
ixm,ixx,ixp , & ! record numbers for neighboring months
recnum , & ! record number
maxrec , & ! maximum record number
recslot , & ! spline slot for current record
dataloc , & ! = 1 for data located in middle of time interval
! = 2 for date located at end of time interval
midmonth ! middle day of month
real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks) :: &
sstdat ! data value toward which SST is restored
real (kind=dbl_kind) :: workx, worky
logical (kind=log_kind) :: readm
character (char_len) :: &
fieldname ! field name in netcdf file
character (char_len_long) :: &
filename ! name of netCDF file
!-------------------------------------------------------------------
! monthly data
!
! Assume that monthly data values are located in the middle of the
! month.
!-------------------------------------------------------------------
midmonth = 15 ! data is given on 15th of every month
! midmonth = fix(p5 * real(daymo(month))) ! exact middle
! Compute record numbers for surrounding months
maxrec = 12
ixm = mod(month+maxrec-2,maxrec) + 1
ixp = mod(month, maxrec) + 1
if (mday >= midmonth) ixm = 99 ! other two points will be used
if (mday < midmonth) ixp = 99
! Determine whether interpolation will use values 1:2 or 2:3
! recslot = 2 means we use values 1:2, with the current value (2)
! in the second slot
! recslot = 1 means we use values 2:3, with the current value (2)
! in the first slot
recslot = 1 ! latter half of month
if (mday < midmonth) recslot = 2 ! first half of month
! Find interpolation coefficients
call interp_coeff_monthly
(recslot)
! Read 2 monthly values
readm = .false.
if (istep==1 .or. (mday==midmonth .and. sec==0)) readm = .true.
if (my_task == master_task .and. istep == 1) then
write (nu_diag,*) ' '
write (nu_diag,*) 'SST data interpolated to timestep:'
write (nu_diag,*) trim(ocn_data_dir)//'MONTHLY/sst.1997.nc'
if (restore_sst) write (nu_diag,*) &
'SST restoring timescale (days) =', trestore
if (trim(sst_data_type)=='hadgem_sst_uvocn') then
write (nu_diag,*) ' '
write (nu_diag,*) 'uocn and vocn interpolated to timestep:'
write (nu_diag,*) trim(ocn_data_dir)//'MONTHLY/uocn.1997.nc'
write (nu_diag,*) trim(ocn_data_dir)//'MONTHLY/vocn.1997.nc'
endif
endif ! my_task, istep
! -----------------------------------------------------------
! SST
! -----------------------------------------------------------
sst_file = trim(ocn_data_dir)//'MONTHLY/sst.1997.nc'
fieldname='sst'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, sst_file, fieldname, sst_data, &
field_loc_center, field_type_scalar)
! Interpolate to current time step
call interpolate_data
(sst_data, sstdat)
! Restore SSTs if required
if (restore_sst) then
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
sst(i,j,iblk) = sst(i,j,iblk) &
+ (sstdat(i,j,iblk)-sst(i,j,iblk))*dt/trest
enddo
enddo
enddo
endif
! -----------------------------------------------------------
! Ocean currents
! --------------
! Values read in are on T grid and oriented geographically, hence
! vectors need to be rotated to model grid and then interpolated
! to U grid.
! Also need to be converted from cm s-1 (UM) to m s-1 (CICE)
! -----------------------------------------------------------
if (trim(sst_data_type)=='hadgem_sst_uvocn') then
filename = trim(ocn_data_dir)//'MONTHLY/uocn.1997.nc'
fieldname='uocn'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, filename, fieldname, uocn_data, &
field_loc_center, field_type_vector)
! Interpolate to current time step
call interpolate_data
(uocn_data, uocn)
filename = trim(ocn_data_dir)//'MONTHLY/vocn.1997.nc'
fieldname='vocn'
call read_data_nc
(readm, 0, fyear, ixm, month, ixp, &
maxrec, filename, fieldname, vocn_data, &
field_loc_center, field_type_vector)
! Interpolate to current time step
call interpolate_data
(vocn_data, vocn)
!-----------------------------------------------------------------
! Rotate zonal/meridional vectors to local coordinates,
! and change units
!-----------------------------------------------------------------
do iblk = 1, nblocks
do j = 1, ny_block
do i = 1, nx_block
workx = uocn(i,j,iblk)
worky = vocn(i,j,iblk)
uocn(i,j,iblk) = workx*cos(ANGLET(i,j,iblk)) &
+ worky*sin(ANGLET(i,j,iblk))
vocn(i,j,iblk) = worky*cos(ANGLET(i,j,iblk)) &
- workx*sin(ANGLET(i,j,iblk))
uocn(i,j,iblk) = uocn(i,j,iblk) * cm_to_m
vocn(i,j,iblk) = vocn(i,j,iblk) * cm_to_m
enddo ! i
enddo ! j
enddo ! nblocks
!-----------------------------------------------------------------
! Interpolate to U grid
!-----------------------------------------------------------------
call t2ugrid_vector
(uocn)
call t2ugrid_vector
(vocn)
endif ! sst_data_type = hadgem_sst_uvocn
end subroutine ocn_data_hadgem
!=======================================================================
end module ice_forcing
!=======================================================================