module ice_comp_mct 2,32 !--------------------------------------------------------------------------- !BOP ! ! !MODULE: ice_comp_mct ! ! !DESCRIPTION: ! CICE interface routine for the ccsm cpl7 mct system ! ! !USES: use shr_kind_mod, only : r8 => shr_kind_r8 use shr_sys_mod, only : shr_sys_abort, shr_sys_flush ! use shr_mem_mod, only : shr_get_memusage, shr_init_memusage use shr_file_mod, only : shr_file_getlogunit, shr_file_getloglevel, & shr_file_setloglevel, shr_file_setlogunit use mct_mod #ifdef USE_ESMF_LIB use esmf_mod #else use esmf_mod, only: ESMF_clock #endif use seq_flds_mod use seq_flds_indices use seq_cdata_mod, only : seq_cdata, seq_cdata_setptrs use seq_infodata_mod,only : seq_infodata_type, seq_infodata_getdata, & seq_infodata_putdata, seq_infodata_start_type_cont, & seq_infodata_start_type_brnch, seq_infodata_start_type_start use seq_timemgr_mod, only : seq_timemgr_eclockgetdata, & seq_timemgr_restartalarmison, & seq_timemgr_eclockdateinsync, & seq_timemgr_stopalarmison use perf_mod, only : t_startf, t_stopf use ice_flux, only : strairxt, strairyt, strocnxt, strocnyt, & alvdr, alidr, alvdf, alidf, tref, qref, flat, & fsens, flwout, evap, fswabs, fhocn, fswthru, & fresh, fsalt, zlvl, uatm, vatm, potT, Tair, Qa, & rhoa, swvdr, swvdf, swidr, swidf, flw, frain, & fsnow, uocn, vocn, sst, ss_tltx, ss_tlty, frzmlt,& sss, tf, wind, fsw, init_flux_atm, init_flux_ocn,& faero use ice_state, only : vice, vsno, aice, trcr, filename_aero, filename_iage, & filename_volpn, filename_FY, filename_lvl, & tr_aero, tr_iage, tr_FY, tr_pond, tr_lvl use ice_domain_size, only : nx_global, ny_global, block_size_x, block_size_y, max_blocks use ice_domain, only : nblocks, blocks_ice, halo_info, distrb_info, profile_barrier use ice_blocks, only : block, get_block, nx_block, ny_block use ice_grid, only : tlon, tlat, tarea, tmask, anglet, hm, ocn_gridcell_frac, & grid_type, t2ugrid_vector use ice_constants, only : c0, c1, puny, tffresh, spval_dbl, rad_to_deg, radius, & field_loc_center, field_type_scalar, field_type_vector, c100 use ice_communicate, only : my_task, master_task, lprint_stats, MPI_COMM_ICE use ice_calendar, only : idate, mday, time, month, daycal, secday, & sec, dt, dt_dyn, xndt_dyn, calendar, & calendar_type, nextsw_cday, days_per_year,& get_daycal, leap_year_count use ice_timers use ice_probability, only : init_numIceCells, print_numIceCells, & write_numIceCells, accum_numIceCells2 use ice_kinds_mod, only : int_kind, dbl_kind, char_len_long, log_kind ! use ice_init use ice_boundary, only : ice_HaloUpdate use ice_scam, only : scmlat, scmlon, single_column use ice_fileunits, only : nu_diag use ice_dyn_evp, only : kdyn use ice_prescribed_mod use ice_step_mod use CICE_RunMod use ice_global_reductions use ice_broadcast ! !PUBLIC MEMBER FUNCTIONS: implicit none public :: ice_init_mct public :: ice_run_mct public :: ice_final_mct SAVE private ! By default make data private ! ! ! PUBLIC DATA: ! ! !REVISION HISTORY: ! Author: Jacob Sewall, Mariana Vertenstein ! !EOP ! !PRIVATE MEMBER FUNCTIONS: private :: ice_export_mct private :: ice_import_mct private :: ice_SetGSMap_mct private :: ice_domain_mct ! ! !PRIVATE VARIABLES integer (kind=int_kind) :: ICEID logical (kind=log_kind) :: atm_aero !======================================================================= contains !======================================================================= !BOP ! ! !IROUTINE: ice_init_mct ! ! !INTERFACE: subroutine ice_init_mct( EClock, cdata_i, x2i_i, i2x_i, NLFilename ) 1,30 ! ! !DESCRIPTION: ! Initialize thermodynamic ice model and obtain relevant atmospheric model ! arrays back from driver ! ! !USES: use CICE_InitMod use ice_restart, only: runid, runtype, restart_dir, restart_format use ice_history, only: history_dir, history_file ! ! !ARGUMENTS: type(ESMF_Clock) , intent(in) :: EClock type(seq_cdata) , intent(inout) :: cdata_i type(mct_aVect) , intent(inout) :: x2i_i, i2x_i character(len=*), optional , intent(in) :: NLFilename ! Namelist filename ! ! !LOCAL VARIABLES: ! type(mct_gsMap) , pointer :: gsMap_ice type(mct_gGrid) , pointer :: dom_i type(seq_infodata_type) , pointer :: infodata ! Input init object integer :: lsize character(len=256) :: drvarchdir ! driver archive directory character(len=32) :: starttype ! infodata start type integer :: start_ymd ! Start date (YYYYMMDD) integer :: start_tod ! start time of day (s) integer :: ref_ymd ! Reference date (YYYYMMDD) integer :: ref_tod ! reference time of day (s) integer :: iyear ! yyyy integer :: dtime ! time step integer :: shrlogunit,shrloglev ! old values integer :: iam,ierr integer :: lbnum integer :: daycal(13) !number of cumulative days per month integer :: nleaps ! number of leap days before current year integer :: mpicom_loc ! temporary mpicom real(r8) :: mrss, mrss0,msize,msize0 ! !REVISION HISTORY: ! Author: Mariana Vertenstein !EOP !----------------------------------------------------------------------- !--------------------------------------------------------------------------- ! Set cdata pointers !--------------------------------------------------------------------------- call seq_cdata_setptrs(cdata_i, ID=ICEID, mpicom=mpicom_loc, & gsMap=gsMap_ice, dom=dom_i, infodata=infodata) ! Determine time of next atmospheric shortwave calculation call seq_infodata_GetData(infodata, nextsw_cday=nextsw_cday ) ! Determine if aerosols are coming from the coupler call seq_infodata_GetData(infodata, atm_aero=atm_aero ) ! call shr_init_memusage() !--------------------------------------------------------------------------- ! use infodata to determine type of run !--------------------------------------------------------------------------- ! Preset single column values single_column = .false. scmlat = -999. scmlon = -999. call seq_infodata_GetData( infodata, case_name=runid , & single_column=single_column ,scmlat=scmlat,scmlon=scmlon) call seq_infodata_GetData( infodata, start_type=starttype) if ( trim(starttype) == trim(seq_infodata_start_type_start)) then runtype = "initial" else if (trim(starttype) == trim(seq_infodata_start_type_cont) ) then runtype = "continue" else if (trim(starttype) == trim(seq_infodata_start_type_brnch)) then runtype = "branch" else write(nu_diag,*) 'ice_comp_mct ERROR: unknown starttype' call shr_sys_abort() end if ! Set nextsw_cday to -1 for continue and branch runs. if (trim(runtype) /= 'initial') nextsw_cday = -1 !============================================================= ! Set ice dtime to ice coupling frequency !============================================================= call seq_timemgr_EClockGetData(EClock, dtime=dtime, calendar=calendar_type) dt = real(dtime) !============================================================= ! Initialize cice because grid information is needed for ! creation of GSMap_ice. cice_init also sets time manager info !============================================================= call t_startf ('cice_init') call cice_init( mpicom_loc ) call t_stopf ('cice_init') call init_numIceCells !--------------------------------------------------------------------------- ! Reset shr logging to my log file !--------------------------------------------------------------------------- call shr_file_getLogUnit (shrlogunit) call shr_file_getLogLevel(shrloglev) call shr_file_setLogUnit (nu_diag) !--------------------------------------------------------------------------- ! use EClock to reset calendar information on initial start !--------------------------------------------------------------------------- ! - the following logic duplicates the logic for the concurrent system - ! cice_init is called then init_cpl is called where the start date is received ! from the flux coupler ! - in the following calculation for the variable time, iyear is used ! rather than (iyear-1) (as in init_cpl) since the sequential system permits you ! to start with year "0" not year "1" ! - on restart run ! - istep0, time and time_forc are read from restart file ! - istep1 is set to istep0 ! - idate is determined from time via the call to calendar (see below) ! - on initial run ! - iyear, month and mday obtained from sync clock ! - time determined from iyear, month and mday ! - istep0 and istep1 are set to 0 if (runtype == 'initial') then call seq_timemgr_EClockGetData(EClock, & start_ymd=start_ymd, start_tod=start_tod, & ref_ymd=ref_ymd, ref_tod=ref_tod) if (ref_ymd /= start_ymd .or. ref_tod /= start_tod) then if (my_task == master_task) then write(nu_diag,*) 'ice_comp_mct: ref_ymd ',ref_ymd, & ' must equal start_ymd ',start_ymd write(nu_diag,*) 'ice_comp_mct: ref_ymd ',ref_tod, & ' must equal start_ymd ',start_tod end if call shr_sys_abort() end if if (my_task == master_task) then write(nu_diag,*) '(ice_init_mct) idate from sync clock = ', & start_ymd write(nu_diag,*) '(ice_init_mct) tod from sync clock = ', & start_tod write(nu_diag,*) & '(ice_init_mct) resetting idate to match sync clock' end if idate = start_ymd iyear = (idate/10000) ! integer year of basedate month = (idate-iyear*10000)/100 ! integer month of basedate mday = idate-iyear*10000-month*100-1 ! day of month of basedate ! (starts at 0) call get_daycal(year=iyear,days_per_year_in=days_per_year, & daycal_out=daycal) nleaps = leap_year_count(iyear) ! this sets nleaps in ice_calendar time = (((iyear)*days_per_year + nleaps + daycal(month)+mday)*secday) & + start_tod call shr_sys_flush(nu_diag) end if call calendar(time) ! update calendar info !--------------------------------------------------------------------------- ! Initialize MCT attribute vectors and indices !--------------------------------------------------------------------------- call t_startf ('cice_mct_init') ! Initialize ice gsMap call ice_SetGSMap_mct( MPI_COMM_ICE, ICEID, GSMap_ice ) lsize = mct_gsMap_lsize(gsMap_ice, MPI_COMM_ICE) ! Initialize mct ice domain (needs ice initialization info) call ice_domain_mct( lsize, gsMap_ice, dom_i ) ! Inialize mct attribute vectors call mct_aVect_init(x2i_i, rList=seq_flds_x2i_fields, lsize=lsize) call mct_aVect_zero(x2i_i) call mct_aVect_init(i2x_i, rList=seq_flds_i2x_fields, lsize=lsize) call mct_aVect_zero(i2x_i) !----------------------------------------------------------------- ! Prescribed ice initialization !----------------------------------------------------------------- call ice_prescribed_init(ICEID, gsmap_ice, dom_i) !----------------------------------------------------------------- ! Get ready for coupling !----------------------------------------------------------------- call coupling_prep !--------------------------------------------------------------------------- ! Fill in export state for driver !--------------------------------------------------------------------------- call ice_export_mct (i2x_i) !Send initial state to driver call seq_infodata_PutData( infodata, ice_prognostic=.true., & ice_nx = nx_global, ice_ny = ny_global ) call t_stopf ('cice_mct_init') !--------------------------------------------------------------------------- ! Reset shr logging to original values !--------------------------------------------------------------------------- call shr_file_setLogUnit (shrlogunit) call shr_file_setLogLevel(shrloglev) call ice_timer_stop(timer_total) ! time entire run ! call shr_get_memusage(msize,mrss) ! call shr_mpi_max(mrss, mrss0, MPI_COMM_ICE,'ice_init_mct mrss0') ! call shr_mpi_max(msize,msize0,MPI_COMM_ICE,'ice_init_mct msize0') ! if(my_task == 0) then ! write(shrlogunit,105) 'ice_init_mct: memory_write: model date = ',start_ymd,start_tod, & ! ' memory = ',msize0,' MB (highwater) ',mrss0,' MB (usage)' ! endif 105 format( A, 2i8, A, f10.2, A, f10.2, A) end subroutine ice_init_mct !--------------------------------------------------------------------------- !BOP ! ! !IROUTINE: ice_run_mct ! ! !INTERFACE: subroutine ice_run_mct( EClock, cdata_i, x2i_i, i2x_i ) 1,69 ! ! !DESCRIPTION: ! Run thermodynamic CICE ! ! !USES: use ice_history use ice_restart use ice_diagnostics use ice_aerosol, only: write_restart_aero use ice_age, only: write_restart_age use ice_meltpond, only: write_restart_pond use ice_FY, only: write_restart_FY use ice_lvl, only: write_restart_lvl use ice_restoring, only: restore_ice, ice_HaloRestore use ice_shortwave, only: init_shortwave ! !ARGUMENTS: type(ESMF_Clock),intent(in) :: EClock type(seq_cdata), intent(inout) :: cdata_i type(mct_aVect), intent(inout) :: x2i_i type(mct_aVect), intent(inout) :: i2x_i ! !LOCAL VARIABLES: integer :: k ! index logical :: rstwr ! .true. ==> write a restart file logical :: stop_now ! .true. ==> stop at the end of this run phase integer :: ymd ! Current date (YYYYMMDD) integer :: tod ! Current time of day (sec) integer :: yr_sync ! Sync current year integer :: mon_sync ! Sync current month integer :: day_sync ! Sync current day integer :: tod_sync ! Sync current time of day (sec) integer :: ymd_sync ! Current year of sync clock integer :: shrlogunit,shrloglev ! old values integer :: lbnum integer :: n type(mct_gGrid) , pointer :: dom_i type(seq_infodata_type), pointer :: infodata type(mct_gsMap) , pointer :: gsMap_i character(len=char_len_long) :: fname character(len=char_len_long) :: string1, string2 character(len=*), parameter :: SubName = "ice_run_mct" real(r8) :: mrss, mrss0,msize,msize0 logical, save :: first_time = .true. ! ! !REVISION HISTORY: ! Author: Jacob Sewall, Mariana Vertenstein ! !EOP !--------------------------------------------------------------------------- call ice_timer_start(timer_total) ! time entire run !--------------------------------------------------------------------------- ! Reset shr logging to my log file !--------------------------------------------------------------------------- call shr_file_getLogUnit (shrlogunit) call shr_file_getLogLevel(shrloglev) call shr_file_setLogUnit (nu_diag) ! Determine time of next atmospheric shortwave calculation call seq_cdata_setptrs(cdata_i, infodata=infodata, dom=dom_i, & gsMap=gsMap_i) call seq_infodata_GetData(infodata, nextsw_cday=nextsw_cday ) !------------------------------------------------------------------- ! get import state !------------------------------------------------------------------- call t_startf ('cice_import') call ice_timer_start(timer_cplrecv) call ice_import_mct( x2i_i ) call ice_timer_stop(timer_cplrecv) call t_stopf ('cice_import') !-------------------------------------------------------------------- ! timestep update !-------------------------------------------------------------------- call ice_timer_start(timer_step) istep = istep + 1 ! update time step counters istep1 = istep1 + 1 time = time + dt ! determine the time and date call calendar(time) ! at the end of the timestep if (resttype == 'old' .and. istep == 1) & call init_shortwave ! initialize radiative transfer using current swdn !----------------------------------------------------------------- ! restoring on grid boundaries !----------------------------------------------------------------- if (restore_ice) call ice_HaloRestore call t_startf ('cice_initmd') call init_mass_diags ! diagnostics per timestep call t_stopf ('cice_initmd') if(prescribed_ice) then ! read prescribed ice call t_startf ('cice_presc') call ice_prescribed_run(idate, sec) call t_stopf ('cice_presc') endif call init_flux_atm ! initialize atmosphere fluxes sent to coupler call init_flux_ocn ! initialize ocean fluxes sent to coupler !----------------------------------------------------------------- ! Scale radiation fields !----------------------------------------------------------------- call t_startf ('cice_prep_radiation') call ice_timer_start(timer_sw) call prep_radiation(dt) call ice_timer_stop(timer_sw) call t_stopf ('cice_prep_radiation') !----------------------------------------------------------------- ! thermodynamics1 !----------------------------------------------------------------- call t_startf ('cice_therm1') call step_therm1(dt) call t_stopf ('cice_therm1') !----------------------------------------------------------------- ! thermodynamics2 !----------------------------------------------------------------- if (.not.prescribed_ice) then call t_startf ('cice_therm2') call step_therm2 (dt) ! post-coupler thermodynamics call t_stopf ('cice_therm2') end if !----------------------------------------------------------------- ! dynamics, transport, ridging !----------------------------------------------------------------- if (.not.prescribed_ice .and. kdyn>0) then if (xndt_dyn > c1) then call t_startf ('cice_dyn') do k = 1, nint(xndt_dyn) call step_dynamics(dt_dyn,dt) ! dynamics, transport, ridging enddo call t_stopf ('cice_dyn') else if (mod(time, dt_dyn) == c0) then call t_startf ('cice_dyn') call step_dynamics(dt_dyn,dt) ! dynamics, transport, ridging call t_stopf ('cice_dyn') endif endif endif ! not prescribed_ice !----------------------------------------------------------------- ! radiation !----------------------------------------------------------------- call t_startf ('cice_radiation') call ice_timer_start(timer_sw) call step_radiation(dt) call ice_timer_stop(timer_sw) call t_stopf ('cice_radiation') !----------------------------------------------------------------- ! get ready for coupling !----------------------------------------------------------------- call coupling_prep call ice_timer_stop(timer_step) !----------------------------------------------------------------- ! write data !----------------------------------------------------------------- call t_startf ('cice_diag') call ice_timer_start(timer_diags) if (mod(istep,diagfreq) == 0) call runtime_diags(dt) ! log file call ice_timer_stop(timer_diags) call t_stopf ('cice_diag') call t_startf ('cice_hist') call ice_timer_start(timer_hist) #if (defined _NOIO) ! Not enought memory on BGL to write a history file yet! ! call ice_write_hist (dt) ! history file #else call ice_write_hist (dt) ! history file #endif call ice_timer_stop(timer_hist) call t_stopf ('cice_hist') !-------------------------------------------- ! Accumualate the number of active ice cells !-------------------------------------------- call accum_numIceCells2(aice) rstwr = seq_timemgr_RestartAlarmIsOn(EClock) if (rstwr) then call seq_timemgr_EClockGetData(EClock, curr_ymd=ymd_sync, curr_tod=tod_sync, & curr_yr=yr_sync,curr_mon=mon_sync,curr_day=day_sync) fname = restart_filename(yr_sync, mon_sync, day_sync, tod_sync) if (my_task == master_task) then write(nu_diag,*) & 'ice_comp_mct: calling dumpfile for restart filename= ', fname endif if (restart_format /= 'nc') then if (tr_pond) then n = index(fname,'cice.r') + 6 string1 = trim(fname(1:n-1)) string2 = trim(fname(n:lenstr(fname))) write(filename_volpn,'(a,a,a,a)') & string1(1:lenstr(string1)),'.volpn', & string2(1:lenstr(string2)) endif if (tr_aero) then n = index(fname,'cice.r') + 6 string1 = trim(fname(1:n-1)) string2 = trim(fname(n:lenstr(fname))) write(filename_aero,'(a,a,a,a)') & string1(1:lenstr(string1)),'.aero', & string2(1:lenstr(string2)) endif if (tr_iage) then n = index(fname,'cice.r') + 6 string1 = trim(fname(1:n-1)) string2 = trim(fname(n:lenstr(fname))) write(filename_iage,'(a,a,a,a)') & string1(1:lenstr(string1)),'.age', & string2(1:lenstr(string2)) endif if (tr_FY) then n = index(fname,'cice.r') + 6 string1 = trim(fname(1:n-1)) string2 = trim(fname(n:lenstr(fname))) write(filename_FY,'(a,a,a,a)') & string1(1:lenstr(string1)),'.FY', & string2(1:lenstr(string2)) endif if (tr_lvl) then n = index(fname,'cice.r') + 6 string1 = trim(fname(1:n-1)) string2 = trim(fname(n:lenstr(fname))) write(filename_lvl,'(a,a,a,a)') & string1(1:lenstr(string1)),'.lvl', & string2(1:lenstr(string2)) endif endif ! restart_format #if (defined _NOIO) ! Not enought memory on BGL to call dumpfile file yet! ! call dumpfile(fname) #else call ice_timer_start(timer_readwrite) call dumpfile(fname) if (restart_format /= 'nc') then if (tr_aero) call write_restart_aero(filename_aero) if (tr_iage) call write_restart_age(filename_iage) if (tr_FY) call write_restart_FY(filename_FY) if (tr_lvl) call write_restart_lvl(filename_lvl) if (tr_pond) call write_restart_pond(filename_volpn) endif call ice_timer_stop(timer_readwrite) #endif end if !----------------------------------------------------------------- ! send export state to driver !----------------------------------------------------------------- call t_startf ('cice_export') call ice_timer_start(timer_cplsend) call ice_export_mct ( i2x_i ) call ice_timer_stop(timer_cplsend) call t_stopf ('cice_export') !-------------------------------------------------------------------- ! check that internal clock is in sync with master clock !-------------------------------------------------------------------- tod = sec ymd = idate if (.not. seq_timemgr_EClockDateInSync( EClock, ymd, tod )) then call seq_timemgr_EClockGetData( EClock, curr_ymd=ymd_sync, & curr_tod=tod_sync ) write(nu_diag,*)' cice ymd=',ymd ,' cice tod= ',tod write(nu_diag,*)' sync ymd=',ymd_sync,' sync tod= ',tod_sync call shr_sys_abort( SubName// & ":: Internal sea-ice clock not in sync with Sync Clock") end if ! reset shr logging to my original values call shr_file_setLogUnit (shrlogunit) call shr_file_setLogLevel(shrloglev) !------------------------------------------------------------------- ! stop timers and print timer info !------------------------------------------------------------------- ! Need to have this logic here instead of in ice_final_mct since ! the ice_final_mct.F90 will still be called even in aqua-planet mode ! Could put this logic in the driver - but it seems easier here ! Need to stop this at the end of every run phase in a coupled run. call ice_timer_stop(timer_total) ! stop timing stop_now = seq_timemgr_StopAlarmIsOn( EClock ) if (stop_now) then call ice_timer_print_all(stats=.true.) ! print timing information if(lprint_stats) then call write_numIceCells() endif call release_all_fileunits end if ! if(tod == 0) then ! call shr_get_memusage(msize,mrss) ! call shr_mpi_max(mrss, mrss0, MPI_COMM_ICE,'ice_run_mct mrss0') ! call shr_mpi_max(msize,msize0,MPI_COMM_ICE,'ice_run_mct msize0') ! if(my_task == 0 ) then ! write(shrlogunit,105) 'ice_run_mct: memory_write: model date = ',ymd,tod, & ! ' memory = ',msize0,' MB (highwater) ',mrss0,' MB (usage)' ! endif ! endif 105 format( A, 2i8, A, f10.2, A, f10.2, A) end subroutine ice_run_mct !--------------------------------------------------------------------------- !BOP ! ! !IROUTINE: ice_final_mct ! ! !INTERFACE: subroutine ice_final_mct( ) 1 ! ! !DESCRIPTION: ! Finalize CICE ! ! !USES: ! !------------------------------------------------------------------------------ !BOP ! ! !ARGUMENTS: ! ! !REVISION HISTORY: ! !EOP !--------------------------------------------------------------------------- end subroutine ice_final_mct !=============================================================================== subroutine ice_SetGSMap_mct( mpicom, ID, gsMap_ice ) 1,2 !------------------------------------------------------------------- ! ! Arguments ! implicit none integer , intent(in) :: mpicom integer , intent(in) :: ID type(mct_gsMap), intent(inout) :: gsMap_ice ! ! Local variables ! integer,allocatable :: gindex(:) integer :: lat integer :: lon integer :: i, j, iblk, n, gi integer :: lsize,gsize integer :: ier integer :: ilo, ihi, jlo, jhi ! beginning and end of physical domain type(block) :: this_block ! block information for current block !------------------------------------------------------------------- ! Build the CICE grid numbering for MCT ! NOTE: Numbering scheme is: West to East and South to North ! starting at south pole. Should be the same as what's used ! in SCRIP ! number the local grid n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 enddo !i enddo !j enddo !iblk lsize = n ! not valid for padded decomps ! lsize = block_size_x*block_size_y*nblocks gsize = nx_global*ny_global allocate(gindex(lsize),stat=ier) n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 lon = this_block%i_glob(i) lat = this_block%j_glob(j) gi = (lat-1)*nx_global + lon gindex(n) = gi enddo !i enddo !j enddo !iblk call mct_gsMap_init( gsMap_ice, gindex, mpicom, ID, lsize, gsize ) deallocate(gindex) end subroutine ice_SetGSMap_mct !=============================================================================== subroutine ice_export_mct( i2x_i ) 2,2 !----------------------------------------------------- type(mct_aVect) , intent(inout) :: i2x_i integer :: i, j, iblk, n, ij integer :: ilo, ihi, jlo, jhi !beginning and end of physical domain integer (kind=int_kind) :: icells ! number of ocean/ice cells integer (kind=int_kind), dimension (nx_block*ny_block) :: indxi ! compressed indices in i integer (kind=int_kind), dimension (nx_block*ny_block) :: indxj ! compressed indices in i real (kind=dbl_kind), dimension(nx_block,ny_block,max_blocks) :: & Tsrf & ! surface temperature , tauxa & ! atmo/ice stress , tauya & , tauxo & ! ice/ocean stress , tauyo & , sicthk & ! needed for cam/som only , ailohi ! fractional ice area real (kind=dbl_kind) :: & workx, worky ! tmps for converting grid type(block) :: this_block ! block information for current block logical :: flag !----------------------------------------------------- flag=.false. !calculate ice thickness from aice and vice. Also !create Tsrf from the first tracer (trcr) in ice_state.F !$OMP PARALLEL DO PRIVATE(iblk,i,j,workx,worky) do iblk = 1, nblocks do j = 1, ny_block do i = 1, nx_block ! sea-ice thickness needed for cam-som only sicthk(i,j,iblk) = vice(i,j,iblk)/(aice(i,j,iblk)+puny) ! ice fraction ailohi(i,j,iblk) = min(aice(i,j,iblk), c1) ! surface temperature Tsrf(i,j,iblk) = Tffresh + trcr(i,j,1,iblk) !Kelvin (original ???) ! wind stress (on POP T-grid: convert to lat-lon) workx = strairxT(i,j,iblk) ! N/m^2 worky = strairyT(i,j,iblk) ! N/m^2 tauxa(i,j,iblk) = workx*cos(ANGLET(i,j,iblk)) & - worky*sin(ANGLET(i,j,iblk)) tauya(i,j,iblk) = worky*cos(ANGLET(i,j,iblk)) & + workx*sin(ANGLET(i,j,iblk)) ! ice/ocean stress (on POP T-grid: convert to lat-lon) workx = -strocnxT(i,j,iblk) ! N/m^2 worky = -strocnyT(i,j,iblk) ! N/m^2 tauxo(i,j,iblk) = workx*cos(ANGLET(i,j,iblk)) & - worky*sin(ANGLET(i,j,iblk)) tauyo(i,j,iblk) = worky*cos(ANGLET(i,j,iblk)) & + workx*sin(ANGLET(i,j,iblk)) enddo enddo enddo !$OMP END PARALLEL DO do iblk = 1, nblocks do j = 1, ny_block do i = 1, nx_block if (tmask(i,j,iblk) .and. ailohi(i,j,iblk) < c0 ) then flag = .true. endif end do end do end do if (flag) then do iblk = 1, nblocks do j = 1, ny_block do i = 1, nx_block if (tmask(i,j,iblk) .and. ailohi(i,j,iblk) < c0 ) then write(nu_diag,*) & ' (ice) send: ERROR ailohi < 0.0 ',i,j,ailohi(i,j,iblk) call shr_sys_flush(nu_diag) endif end do end do end do endif ! Fill export state i2x_i i2x_i%rAttr(:,:) = spval_dbl n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 !-------states-------------------- i2x_i%rAttr(index_i2x_Si_sicthk,n) = sicthk(i,j,iblk) ! (needed by CAM/SOM only) i2x_i%rAttr(index_i2x_Si_ifrac ,n) = ailohi(i,j,iblk) if ( tmask(i,j,iblk) .and. ailohi(i,j,iblk) > c0 ) then !-------states-------------------- i2x_i%rAttr(index_i2x_Si_t ,n) = Tsrf(i,j,iblk) i2x_i%rAttr(index_i2x_Si_avsdr ,n) = alvdr(i,j,iblk) i2x_i%rAttr(index_i2x_Si_anidr ,n) = alidr(i,j,iblk) i2x_i%rAttr(index_i2x_Si_avsdf ,n) = alvdf(i,j,iblk) i2x_i%rAttr(index_i2x_Si_anidf ,n) = alidf(i,j,iblk) i2x_i%rAttr(index_i2x_Si_tref ,n) = Tref(i,j,iblk) i2x_i%rAttr(index_i2x_Si_qref ,n) = Qref(i,j,iblk) i2x_i%rAttr(index_i2x_Si_snowh ,n) = vsno(i,j,iblk) & / ailohi(i,j,iblk) !--- a/i fluxes computed by ice i2x_i%rAttr(index_i2x_Faii_taux ,n) = tauxa(i,j,iblk) i2x_i%rAttr(index_i2x_Faii_tauy ,n) = tauya(i,j,iblk) i2x_i%rAttr(index_i2x_Faii_lat ,n) = flat(i,j,iblk) i2x_i%rAttr(index_i2x_Faii_sen ,n) = fsens(i,j,iblk) i2x_i%rAttr(index_i2x_Faii_lwup ,n) = flwout(i,j,iblk) i2x_i%rAttr(index_i2x_Faii_evap ,n) = evap(i,j,iblk) i2x_i%rAttr(index_i2x_Faii_swnet,n) = fswabs(i,j,iblk) !--- i/o fluxes computed by ice i2x_i%rAttr(index_i2x_Fioi_melth,n) = fhocn(i,j,iblk) i2x_i%rAttr(index_i2x_Fioi_swpen,n) = fswthru(i,j,iblk) ! hf from melting i2x_i%rAttr(index_i2x_Fioi_meltw,n) = fresh(i,j,iblk) ! h2o flux from melting ??? i2x_i%rAttr(index_i2x_Fioi_salt ,n) = fsalt(i,j,iblk) ! salt flux from melting ??? i2x_i%rAttr(index_i2x_Fioi_taux ,n) = tauxo(i,j,iblk) ! stress : i/o zonal ??? i2x_i%rAttr(index_i2x_Fioi_tauy ,n) = tauyo(i,j,iblk) ! stress : i/o meridional ??? end if enddo !i enddo !j enddo !iblk end subroutine ice_export_mct !============================================================================== subroutine ice_import_mct( x2i_i ) 1,10 !----------------------------------------------------- implicit none type(mct_aVect) , intent(inout) :: x2i_i integer :: i, j, iblk, n integer :: ilo, ihi, jlo, jhi !beginning and end of physical domain type(block) :: this_block ! block information for current block integer,parameter :: nflds=15,nfldv=6 real (kind=dbl_kind),allocatable :: aflds(:,:,:,:) real (kind=dbl_kind) :: & workx, worky logical (kind=log_kind) :: & first_call = .true. logical (kind=log_kind) :: & prescribed_aero_tmp !----------------------------------------------------- ! Note that the precipitation fluxes received from the coupler ! are in units of kg/s/m^2 which is what CICE requires. ! Note also that the read in below includes only values needed ! by the thermodynamic component of CICE. Variables uocn, vocn, ! ss_tltx, and ss_tlty are excluded. Also, because the SOM and ! DOM don't compute SSS. SSS is not read in and is left at ! the initilized value (see ice_flux.F init_coupler_flux) of ! 34 ppt ! Use aflds to gather the halo updates of multiple fields ! Need to separate the scalar from the vector halo updates allocate(aflds(nx_block,ny_block,nflds,nblocks)) aflds = c0 n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 aflds(i,j, 1,iblk) = x2i_i%rAttr(index_x2i_So_t,n) aflds(i,j, 2,iblk) = x2i_i%rAttr(index_x2i_So_s,n) aflds(i,j, 3,iblk) = x2i_i%rAttr(index_x2i_Sa_z,n) aflds(i,j, 4,iblk) = x2i_i%rAttr(index_x2i_Sa_ptem,n) aflds(i,j, 5,iblk) = x2i_i%rAttr(index_x2i_Sa_tbot,n) aflds(i,j, 6,iblk) = x2i_i%rAttr(index_x2i_Sa_shum,n) aflds(i,j, 7,iblk) = x2i_i%rAttr(index_x2i_Sa_dens,n) aflds(i,j, 8,iblk) = x2i_i%rAttr(index_x2i_Fioo_q,n) aflds(i,j, 9,iblk) = x2i_i%rAttr(index_x2i_Faxa_swvdr,n) aflds(i,j,10,iblk) = x2i_i%rAttr(index_x2i_Faxa_swndr,n) aflds(i,j,11,iblk) = x2i_i%rAttr(index_x2i_Faxa_swvdf,n) aflds(i,j,12,iblk) = x2i_i%rAttr(index_x2i_Faxa_swndf,n) aflds(i,j,13,iblk) = x2i_i%rAttr(index_x2i_Faxa_lwdn,n) aflds(i,j,14,iblk) = x2i_i%rAttr(index_x2i_Faxa_rain,n) aflds(i,j,15,iblk) = x2i_i%rAttr(index_x2i_Faxa_snow,n) enddo !i enddo !j enddo !iblk if (.not.prescribed_ice) then call t_startf ('cice_imp_halo') call ice_HaloUpdate(aflds, halo_info, field_loc_center, & field_type_scalar) call t_stopf ('cice_imp_halo') endif !$OMP PARALLEL DO PRIVATE(iblk,i,j) do iblk = 1, nblocks do j = 1,ny_block do i = 1,nx_block sst (i,j,iblk) = aflds(i,j, 1,iblk) sss (i,j,iblk) = aflds(i,j, 2,iblk) zlvl (i,j,iblk) = aflds(i,j, 3,iblk) potT (i,j,iblk) = aflds(i,j, 4,iblk) Tair (i,j,iblk) = aflds(i,j, 5,iblk) Qa (i,j,iblk) = aflds(i,j, 6,iblk) rhoa (i,j,iblk) = aflds(i,j, 7,iblk) frzmlt (i,j,iblk) = aflds(i,j, 8,iblk) swvdr(i,j,iblk) = aflds(i,j, 9,iblk) swidr(i,j,iblk) = aflds(i,j,10,iblk) swvdf(i,j,iblk) = aflds(i,j,11,iblk) swidf(i,j,iblk) = aflds(i,j,12,iblk) flw (i,j,iblk) = aflds(i,j,13,iblk) frain(i,j,iblk) = aflds(i,j,14,iblk) fsnow(i,j,iblk) = aflds(i,j,15,iblk) enddo !i enddo !j enddo !iblk !$OMP END PARALLEL DO deallocate(aflds) allocate(aflds(nx_block,ny_block,nfldv,nblocks)) aflds = c0 n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 aflds(i,j, 1,iblk) = x2i_i%rAttr(index_x2i_So_u,n) aflds(i,j, 2,iblk) = x2i_i%rAttr(index_x2i_So_v,n) aflds(i,j, 3,iblk) = x2i_i%rAttr(index_x2i_Sa_u,n) aflds(i,j, 4,iblk) = x2i_i%rAttr(index_x2i_Sa_v,n) aflds(i,j, 5,iblk) = x2i_i%rAttr(index_x2i_So_dhdx,n) aflds(i,j, 6,iblk) = x2i_i%rAttr(index_x2i_So_dhdy,n) enddo enddo enddo if (.not.prescribed_ice) then call t_startf ('cice_imp_halo') call ice_HaloUpdate(aflds, halo_info, field_loc_center, & field_type_vector) call t_stopf ('cice_imp_halo') endif !$OMP PARALLEL DO PRIVATE(iblk,i,j) do iblk = 1, nblocks do j = 1,ny_block do i = 1,nx_block uocn (i,j,iblk) = aflds(i,j, 1,iblk) vocn (i,j,iblk) = aflds(i,j, 2,iblk) uatm (i,j,iblk) = aflds(i,j, 3,iblk) vatm (i,j,iblk) = aflds(i,j, 4,iblk) ss_tltx(i,j,iblk) = aflds(i,j, 5,iblk) ss_tlty(i,j,iblk) = aflds(i,j, 6,iblk) enddo !i enddo !j enddo !iblk !$OMP END PARALLEL DO deallocate(aflds) !------------------------------------------------------- ! Set aerosols from coupler !------------------------------------------------------- if (first_call) then if (tr_aero .and. .not. atm_aero) then write(nu_diag,*) 'ice_comp_mct ERROR: atm_aero must be set for tr_aero' call shr_sys_abort() end if first_call = .false. end if n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 faero(i,j,1,iblk) = x2i_i%rAttr(index_x2i_Faxa_bcphodry,n) faero(i,j,2,iblk) = x2i_i%rAttr(index_x2i_Faxa_bcphidry,n) & + x2i_i%rAttr(index_x2i_Faxa_bcphiwet,n) ! Combine all of the dust into one category faero(i,j,3,iblk) = x2i_i%rAttr(index_x2i_Faxa_dstwet1,n) & + x2i_i%rAttr(index_x2i_Faxa_dstdry1,n) & + x2i_i%rAttr(index_x2i_Faxa_dstwet2,n) & + x2i_i%rAttr(index_x2i_Faxa_dstdry2,n) & + x2i_i%rAttr(index_x2i_Faxa_dstwet3,n) & + x2i_i%rAttr(index_x2i_Faxa_dstdry3,n) & + x2i_i%rAttr(index_x2i_Faxa_dstwet4,n) & + x2i_i%rAttr(index_x2i_Faxa_dstdry4,n) enddo !i enddo !j enddo !iblk !----------------------------------------------------------------- ! rotate zonal/meridional vectors to local coordinates ! compute data derived quantities !----------------------------------------------------------------- ! Vector fields come in on T grid, but are 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 ! call t_startf ('cice_imp_ocn') !$OMP PARALLEL DO PRIVATE(iblk,i,j,workx,worky) do iblk = 1, nblocks do j = 1,ny_block do i = 1,nx_block ! ocean workx = uocn (i,j,iblk) ! currents, m/s worky = vocn (i,j,iblk) uocn(i,j,iblk) = workx*cos(ANGLET(i,j,iblk)) & ! convert to POP grid + worky*sin(ANGLET(i,j,iblk)) vocn(i,j,iblk) = worky*cos(ANGLET(i,j,iblk)) & - workx*sin(ANGLET(i,j,iblk)) workx = ss_tltx (i,j,iblk) ! sea sfc tilt, m/m worky = ss_tlty (i,j,iblk) ss_tltx(i,j,iblk) = workx*cos(ANGLET(i,j,iblk)) & ! convert to POP grid + worky*sin(ANGLET(i,j,iblk)) ss_tlty(i,j,iblk) = worky*cos(ANGLET(i,j,iblk)) & - workx*sin(ANGLET(i,j,iblk)) sst(i,j,iblk) = sst(i,j,iblk) - Tffresh ! sea sfc temp (C) Tf (i,j,iblk) = -1.8_dbl_kind ! hardwired for NCOM ! Tf (i,j,iblk) = -depressT*sss(i,j,iblk) ! freezing temp (C) ! Tf (i,j,iblk) = -depressT*max(sss(i,j,iblk),ice_ref_salinity) enddo enddo enddo !$OMP END PARALLEL DO call t_stopf ('cice_imp_ocn') ! Interpolate ocean dynamics variables from T-cell centers to ! U-cell centers. if (.not.prescribed_ice) then call t_startf ('cice_imp_t2u') call t2ugrid_vector(uocn) call t2ugrid_vector(vocn) call t2ugrid_vector(ss_tltx) call t2ugrid_vector(ss_tlty) call t_stopf ('cice_imp_t2u') end if ! Atmosphere variables are needed in T cell centers in ! subroutine stability and are interpolated to the U grid ! later as necessary. call t_startf ('cice_imp_atm') !$OMP PARALLEL DO PRIVATE(iblk,i,j,workx,worky) do iblk = 1, nblocks do j = 1, ny_block do i = 1, nx_block ! atmosphere workx = uatm(i,j,iblk) ! wind velocity, m/s worky = vatm(i,j,iblk) uatm (i,j,iblk) = workx*cos(ANGLET(i,j,iblk)) & ! convert to POP grid + worky*sin(ANGLET(i,j,iblk)) ! note uatm, vatm, wind vatm (i,j,iblk) = worky*cos(ANGLET(i,j,iblk)) & ! are on the T-grid here - workx*sin(ANGLET(i,j,iblk)) wind (i,j,iblk) = sqrt(uatm(i,j,iblk)**2 + vatm(i,j,iblk)**2) fsw (i,j,iblk) = swvdr(i,j,iblk) + swvdf(i,j,iblk) & + swidr(i,j,iblk) + swidf(i,j,iblk) enddo enddo enddo !$OMP END PARALLEL DO call t_stopf ('cice_imp_atm') end subroutine ice_import_mct !======================================================================= subroutine ice_domain_mct( lsize, gsMap_i, dom_i ) 1,5 !------------------------------------------------------------------- ! ! Arguments ! integer , intent(in) :: lsize type(mct_gsMap), intent(in) :: gsMap_i type(mct_ggrid), intent(inout) :: dom_i ! ! Local Variables ! integer :: i, j, iblk, n, gi ! indices integer :: ilo, ihi, jlo, jhi ! beginning and end of physical domain real(dbl_kind), pointer :: work_dom(:) ! temporary real(dbl_kind), pointer :: data(:) ! temporary integer , pointer :: idata(:) ! temporary type(block) :: this_block ! block information for current block !------------------------------------------------------------------- ! ! Initialize mct domain type ! lat/lon in degrees, area in radians^2, mask is 1 (ocean), 0 (non-ocean) ! call mct_gGrid_init( GGrid=dom_i, CoordChars=trim(seq_flds_dom_coord), & OtherChars=trim(seq_flds_dom_other), lsize=lsize ) call mct_aVect_zero(dom_i%data) ! allocate(data(lsize)) ! ! Determine global gridpoint number attribute, GlobGridNum, which is set automatically by MCT ! call mct_gsMap_orderedPoints(gsMap_i, my_task, idata) call mct_gGrid_importIAttr(dom_i,'GlobGridNum',idata,lsize) ! ! Determine domain (numbering scheme is: West to East and South to North to South pole) ! Initialize attribute vector with special value ! data(:) = -9999.0_R8 call mct_gGrid_importRAttr(dom_i,"lat" ,data,lsize) call mct_gGrid_importRAttr(dom_i,"lon" ,data,lsize) call mct_gGrid_importRAttr(dom_i,"area" ,data,lsize) call mct_gGrid_importRAttr(dom_i,"aream",data,lsize) data(:) = 0.0_R8 call mct_gGrid_importRAttr(dom_i,"mask",data,lsize) call mct_gGrid_importRAttr(dom_i,"frac",data,lsize) ! ! Fill in correct values for domain components ! allocate(work_dom(lsize)) work_dom(:) = 0.0_dbl_kind n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 data(n) = TLON(i,j,iblk)*rad_to_deg enddo !i enddo !j enddo !iblk call mct_gGrid_importRattr(dom_i,"lon",data,lsize) n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 data(n) = TLAT(i,j,iblk)*rad_to_deg enddo !i enddo !j enddo !iblk call mct_gGrid_importRattr(dom_i,"lat",data,lsize) n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 data(n) = tarea(i,j,iblk)/(radius*radius) enddo !i enddo !j enddo !iblk call mct_gGrid_importRattr(dom_i,"area",data,lsize) n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 data(n) = real(nint(hm(i,j,iblk)),kind=dbl_kind) enddo !i enddo !j enddo !iblk call mct_gGrid_importRattr(dom_i,"mask",data,lsize) n=0 do iblk = 1, nblocks this_block = get_block(blocks_ice(iblk),iblk) ilo = this_block%ilo ihi = this_block%ihi jlo = this_block%jlo jhi = this_block%jhi do j = jlo, jhi do i = ilo, ihi n = n+1 if (trim(grid_type) == 'latlon') then data(n) = ocn_gridcell_frac(i,j,iblk) else data(n) = real(nint(hm(i,j,iblk)),kind=dbl_kind) end if enddo !i enddo !j enddo !iblk call mct_gGrid_importRattr(dom_i,"frac",data,lsize) deallocate(data) deallocate(idata) deallocate(work_dom) end subroutine ice_domain_mct !======================================================================= ! BOP ! ! !ROUTINE: restart_filename ! ! !INTERFACE: character(len=char_len_long) function restart_filename( yr_spec, mon_spec, day_spec, sec_spec ) 1,6 ! ! !DESCRIPTION: Create a filename from a filename specifyer. Interpret filename specifyer ! string with: ! %c for case, ! %t for optional number argument sent into function ! %y for year ! %m for month ! %d for day ! %s for second ! %% for the "%" character ! If the filename specifyer has spaces " ", they will be trimmed out ! of the resulting filename. ! ! !USES: use ice_restart, only: runid ! ! !INPUT/OUTPUT PARAMETERS: integer , intent(in) :: yr_spec ! Simulation year integer , intent(in) :: mon_spec ! Simulation month integer , intent(in) :: day_spec ! Simulation day integer , intent(in) :: sec_spec ! Seconds into current simulation day ! ! EOP ! integer :: i, n ! Loop variables integer :: year ! Simulation year integer :: month ! Simulation month integer :: day ! Simulation day integer :: ncsec ! Seconds into current simulation day character(len=char_len_long) :: string ! Temporary character string character(len=char_len_long) :: format ! Format character string character(len=char_len_long) :: filename_spec = '%c.cice.r.%y-%m-%d-%s' ! ice restarts !----------------------------------------------------------------- ! Determine year, month, day and sec to put in filename !----------------------------------------------------------------- if ( len_trim(filename_spec) == 0 )then call shr_sys_abort ('restart_filename: filename specifier is empty') end if if ( index(trim(filename_spec)," ") /= 0 )then call shr_sys_abort ('restart_filename: filename specifier can not contain a space:'//trim(filename_spec)) end if year = yr_spec month = mon_spec day = day_spec ncsec = sec_spec ! Go through each character in the filename specifyer and interpret if special string i = 1 restart_filename = '' do while ( i <= len_trim(filename_spec) ) if ( filename_spec(i:i) == "%" )then i = i + 1 select case( filename_spec(i:i) ) case( 'c' ) ! runid string = trim(runid) case( 'y' ) ! year if ( year > 99999 ) then format = '(i6.6)' else if ( year > 9999 ) then format = '(i5.5)' else format = '(i4.4)' end if write(string,format) year case( 'm' ) ! month write(string,'(i2.2)') month case( 'd' ) ! day write(string,'(i2.2)') day case( 's' ) ! second write(string,'(i5.5)') ncsec case( '%' ) ! percent character string = "%" case default call shr_sys_abort ('restart_filename: Invalid expansion character: '//filename_spec(i:i)) end select else n = index( filename_spec(i:), "%" ) if ( n == 0 ) n = len_trim( filename_spec(i:) ) + 1 if ( n == 0 ) exit string = filename_spec(i:n+i-2) i = n + i - 2 end if if ( len_trim(restart_filename) == 0 )then restart_filename = trim(string) else if ( (len_trim(restart_filename)+len_trim(string)) >= char_len_long )then call shr_sys_abort ('restart_filename Resultant filename too long') end if restart_filename = trim(restart_filename) // trim(string) end if i = i + 1 end do if ( len_trim(restart_filename) == 0 )then call shr_sys_abort ('restart_filename: Resulting filename is empty') end if end function restart_filename end module ice_comp_mct