?? time_manager.f90
字號:
#include <misc.h>module time_manager use precision, only: r8 use pmgrid, only: masterproc use esmf_timemgmtmod, only: & esmf_errhandlersettype, esmf_err_return, esmf_errprint, esmf_success, & esmf_time, esmf_timeinit, esmf_timeget, esmf_timegetdays, & esmf_timeincrement, esmf_timedecrement, & esmf_date, esmf_dateinit, esmf_gregorian, esmf_no_leap, esmf_dateget, & esmf_dateincrementsec, esmf_dateincrementday, esmf_datedecrement, & esmf_datediff, esmf_dategetfltdayofyear, & esmf_timemgr, esmf_timemgrinit, esmf_timemgradvance, esmf_timemgrgetnstep, & esmf_timemgrgetstepsize, esmf_timemgrgetstartdate, esmf_timemgrgetbasedate, & esmf_timemgrlaststep, esmf_timemgrgetcurrdate, esmf_timemgrgetprevdate, esmf_dateislater, & esmf_timemgrrestartwrite, esmf_timemgrrestartread use string_utils, only: to_upper use dycore, only: dycore_is#ifdef SPMD use mpishorthand, only: mpicom, mpiint, mpilog#endif implicit none private save! Public methods public ::& timemgr_preset, &! time manager initialization before namelist input timemgr_init, &! time manager initialization advance_timestep, &! increment timestep number get_step_size, &! return step size in seconds get_nstep, &! return timestep number get_curr_date, &! return date components at end of current timestep get_prev_date, &! return date components at beginning of current timestep get_start_date, &! return components of the start date get_ref_date, &! return components of the reference date get_perp_date, &! return components of the perpetual date, and current time of day get_curr_time, &! return components of elapsed time since reference date get_curr_calday, &! return calendar day at end of current timestep is_first_step, &! return true on first step of initial run is_first_restart_step, &! return true on first step of restart or branch run is_end_curr_day, &! return true on last timestep in current day is_end_curr_month, &! return true on last timestep in current month is_last_step, &! return true on last timestep is_perpetual, &! return true if perpetual calendar is in use timemgr_write_restart, &! write info to file needed to restart the time manager timemgr_read_restart, &! read info from file needed to restart the time manager timemgr_restart ! restart the time manager! Public data for namelist input character(len=32), public ::& calendar = 'NO_LEAP' ! Calendar to use in date calculations. ! 'NO_LEAP' or 'GREGORIAN' integer, parameter :: uninit_int = -999999999 integer, public ::& dtime = uninit_int, &! timestep in seconds nestep = uninit_int, &! final timestep (or day if negative) number nelapse = uninit_int, &! number of timesteps (or days if negative) to extend a run start_ymd = uninit_int, &! starting date for run in yearmmdd format start_tod = 0, &! starting time of day for run in seconds stop_ymd = uninit_int, &! stopping date for run in yearmmdd format stop_tod = 0, &! stopping time of day for run in seconds ref_ymd = uninit_int, &! reference date for time coordinate in yearmmdd format ref_tod = 0, &! reference time of day for time coordinate in seconds perpetual_ymd = uninit_int ! date used by perpetual calendar logical, public ::& perpetual_run = .false. ! .true. => use a perpetual calendar! Public data for communicating with modules that don't have 'get' methods. integer, public ::& ic_ymd = uninit_int, &! date of initial conditions in yearmmdd format ic_tod = 0 ! time of day of initial conditions in seconds ! ic_ymd, ic_tod set in control/readinitial.F90 logical, public ::& tm_aqua_planet = .false. ! flag for aqua-planet simulation! Private module data type(esmf_timemgr) :: tm_id ! time manager ID type(esmf_date) :: tm_perp_date ! reference date for perpetual calendar day calc integer ::& ! Data required to restart time manager: rst_type = uninit_int, &! calendar type rst_nstep = uninit_int, &! current step number rst_step_days = uninit_int, &! days component of timestep size rst_step_sec = uninit_int, &! seconds component of timestep size rst_start_ymd = uninit_int, &! start date rst_start_tod = uninit_int, &! start time of day rst_stop_ymd = uninit_int, &! stop date rst_stop_tod = uninit_int, &! stop time of day rst_ref_ymd = uninit_int, &! reference date rst_ref_tod = uninit_int, &! reference time of day rst_curr_ymd = uninit_int, &! current date rst_curr_tod = uninit_int, &! current time of day rst_perp_ymd = uninit_int ! perpetual date logical ::& rst_perp_cal = .false. ! true when using perpetual calendar logical :: tm_first_restart_step = .false. ! true for first step of a restart or branch run logical :: tm_perp_calendar = .false. ! true when using perpetual calendar!=========================================================================================contains!=========================================================================================subroutine timemgr_preset()! Initialize variables before namelist input. implicit none! Local variables character(len=*), parameter :: sub = 'timemgr_preset'!----------------------------------------------------------------------------------------- if ( dtime == uninit_int ) then if (dycore_is ('EUL')) then dtime = 1200 else if (dycore_is ('SLD')) then dtime = 3600 else if (dycore_is ('LR')) then dtime = 3600 else write(6,*)sub,': need valid dycore to set default DTIME' call endrun end if end ifend subroutine timemgr_preset!=========================================================================================subroutine timemgr_init()! Initialize the ESMF time manager.!! NOTE - Assumptions:! 1) The namelist variables have been set before this routine is called. (set in control/parse_namelist.F90)! 2) ic_ymd, ic_tod are set before this routine is called. (set in control/readinitial.F90) implicit none! Local variables character(len=*), parameter :: sub = 'timemgr_init' character(len=len(calendar)) :: cal integer :: rc ! return code integer :: cal_type ! calendar type type(esmf_time) :: step_size ! timestep size type(esmf_date) :: start_date ! start date for run type(esmf_date) :: stop_date ! stop date for run type(esmf_date) :: ref_date ! reference date for time coordinate! Some backwards compatibility stuff: type(esmf_time) :: diff integer :: ntspday, ndays, nsecs logical :: islater!-----------------------------------------------------------------------------------------! Initialize error handling. call esmf_errhandlersettype(esmf_err_return)! Initialize calendar type. cal = to_upper(calendar) if ( trim(cal) == 'NO_LEAP' ) then cal_type = esmf_no_leap else if ( trim(cal) == 'GREGORIAN' ) then cal_type = esmf_gregorian else write(6,*)sub,': unrecognized calendar specified: ',calendar call endrun end if! Initialize timestep size. if ( mod(86400,dtime) /=0 ) then write(6,*)sub,': timestep must divide evenly into 1 day' call endrun end if step_size = esmf_timeinit(0, dtime, rc) call chkrc(rc, sub//': error return from esmf_timeinit: setting step_size')! Initialize start date. if ( start_ymd == uninit_int ) then start_ymd = ic_ymd start_tod = ic_tod end if start_date = esmf_dateinit(cal_type, start_ymd, start_tod, rc) call chkrc(rc, sub//': error return from esmf_dateinit: setting start_date')! Initialize reference date for time coordinate. if ( ref_ymd /= uninit_int ) then ref_date = esmf_dateinit(cal_type, ref_ymd, ref_tod, rc) else ref_date = esmf_dateinit(start_date, rc) end if call chkrc(rc, sub//': error return from esmf_dateinit: setting ref_date')! Initialize stop date. if ( stop_ymd /= uninit_int ) then stop_date = esmf_dateinit(cal_type, stop_ymd, stop_tod, rc) else if ( nestep /= uninit_int ) then if ( nestep >= 0 ) then stop_date = esmf_dateincrementsec(start_date, dtime*nestep, rc) else stop_date = esmf_dateincrementday(start_date, -nestep, rc) end if else if ( nelapse /= uninit_int ) then if ( nelapse >= 0 ) then stop_date = esmf_dateincrementsec(start_date, dtime*nelapse, rc) else stop_date = esmf_dateincrementday(start_date, -nelapse, rc) end if else write(6,*)sub,': Must specify one of stop_ymd, nestep, or nelapse' call endrun end if call chkrc(rc, sub//': error return setting stop_date')! Initialize a time manager. tm_id = esmf_timemgrinit(step_size, start_date, stop_date, ref_date, rc) call chkrc(rc, sub//': error return from esmf_timemgrinit')! Initialize date used for perpetual calendar day calculation. if ( tm_aqua_planet ) then tm_perp_date = esmf_dateinit(cal_type, 321, 0, rc) call chkrc(rc, sub//': error return from esmf_dateinit: setting tm_perp_date') tm_perp_calendar = .true. else if ( perpetual_run ) then if ( perpetual_ymd /= uninit_int ) then tm_perp_date = esmf_dateinit(cal_type, perpetual_ymd, 0, rc) call chkrc(rc, sub//': error return from esmf_dateinit: setting tm_perp_date') tm_perp_calendar = .true. else tm_perp_date = esmf_dateinit(cal_type, ic_ymd, 0, rc) call chkrc(rc, sub//': error return from esmf_dateinit: setting tm_perp_date') tm_perp_calendar = .true. end if end if! Set variables from "comtim.h interface" for backwards compatibility.! Calculation of ending timestep number (nestep) assumes a constant stepsize. ntspday = 86400/dtime diff = esmf_timeinit() call esmf_datediff(start_date, stop_date, diff, islater, rc) call chkrc(rc, sub//': error return from esmf_datediff calculating nestep') call esmf_timeget(diff, ndays, nsecs, rc) call chkrc(rc, sub//': error return from esmf_timeget calculating nestep') nestep = ntspday*ndays + nsecs/dtime if ( mod(nsecs,dtime) /= 0 ) nestep = nestep + 1! Print configuration summary to log file (stdout). if (masterproc) then call timemgr_print() end ifend subroutine timemgr_init!=========================================================================================subroutine timemgr_restart()! Restart the ESMF time manager.!! NOTE - Assumptions:! 1) The namelist variables have been set before this routine is called.! (set in control/parse_namelist.F90)! The stop date is the only thing that can be changed by the user on a restart.! 2) Restart data have been read on the master process before this routine is called.! (timemgr_read_restart called from control/restart.F90::read_restart) implicit none! Local variables character(len=*), parameter :: sub = 'timemgr_restart' integer :: rc ! return code type(esmf_date) :: start_date ! start date for run type(esmf_date) :: stop_date ! stop date for run type(esmf_date) :: curr_date ! date of data in restart file logical :: islater integer :: ymd, tod! Some backwards compatibility stuff: type(esmf_time) :: diff integer :: ntspday, ndays, nsecs!-----------------------------------------------------------------------------------------#if ( defined SPMD ) call mpibcast(rst_type, 1, mpiint, 0, mpicom) call mpibcast(rst_nstep, 1, mpiint, 0, mpicom) call mpibcast(rst_step_days, 1, mpiint, 0, mpicom) call mpibcast(rst_step_sec, 1, mpiint, 0, mpicom) call mpibcast(rst_start_ymd, 1, mpiint, 0, mpicom) call mpibcast(rst_start_tod, 1, mpiint, 0, mpicom) call mpibcast(rst_stop_ymd, 1, mpiint, 0, mpicom) call mpibcast(rst_stop_tod, 1, mpiint, 0, mpicom) call mpibcast(rst_ref_ymd, 1, mpiint, 0, mpicom) call mpibcast(rst_ref_tod, 1, mpiint, 0, mpicom) call mpibcast(rst_curr_ymd, 1, mpiint, 0, mpicom) call mpibcast(rst_curr_tod, 1, mpiint, 0, mpicom) call mpibcast(rst_perp_ymd, 1, mpiint, 0, mpicom) call mpibcast(rst_perp_cal, 1, mpilog, 0, mpicom)#endif! Initialize error handling. call esmf_errhandlersettype(esmf_err_return)! Initialize calendar type. if ( rst_type == esmf_no_leap ) then calendar = 'NO_LEAP' else if ( rst_type == esmf_gregorian ) then calendar = 'GREGORIAN' else write(6,*)sub,': unrecognized calendar type in restart file: ',rst_type call endrun end if! Initialize the timestep. dtime = rst_step_days*86400 + rst_step_sec! Initialize start date.
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -