4401 lines
155 KiB
Fortran
4401 lines
155 KiB
Fortran
! $Id: time_mod.f,v 1.6 2012/03/01 22:00:27 daven Exp $
|
|
MODULE TIME_MOD
|
|
!
|
|
!******************************************************************************
|
|
! TIME_MOD contains GEOS-CHEM date and time variables and timesteps, and
|
|
! routines for accessing them. (bmy, 6/21/00, 2/2/07)
|
|
!
|
|
! Module Variables:
|
|
! ============================================================================
|
|
! (1 ) NYMDb (INTEGER) : YYYYMMDD at beginning of GEOS-CHEM run
|
|
! (2 ) NHMSb (INTEGER) : HHMMSS at beginning of GEOS-CHEM run
|
|
! (3 ) NYMDe (INTEGER) : YYYYMMDD at end of GEOS-CHEM run
|
|
! (4 ) NHMSe (INTEGER) : HHMMSS at end of GEOS-CHEM run
|
|
! (5 ) NYMD (INTEGER) : YYYYMMDD at current timestep
|
|
! (6 ) NHMS (INTEGER) : HHMMSS at current timestep
|
|
! (7 ) MONTH (INTEGER) : Current month value (1-12)
|
|
! (8 ) DAY (INTEGER) : Current day of the month (1-31)
|
|
! (9 ) YEAR (INTEGER) : Current year (YYYY format)
|
|
! (10) HOUR (INTEGER) : Current hour of the day (0-23)
|
|
! (11) MINUTE (INTEGER) : Current minute of the hour (0-59)
|
|
! (12) SECOND (INTEGER) : Current second of the minute (0-59)
|
|
! (13) NSEASON (INTEGER) : Season flag (1=DJF, 2=MAM, 3=JJA, 4=SON)
|
|
! (14) DAY_OF_YEAR (INTEGER) : Current day of year (0-365 or 0-366)
|
|
! (15) ELAPSED_MIN (INTEGER) : Elapsed minutes since the end of the run
|
|
! (16) TAU (REAL*8 ) : Current TAU value (hours since 0 GMT 1/1/1985)
|
|
! (17) TAUb (REAL*8 ) : TAU value at beginning of GEOS-CHEM run
|
|
! (18) TAUe (REAL*8 ) : TAU value at end of GEOS-CHEM run
|
|
! (19) DIAGb (REAL*8 ) : TAU value at beginning of diagnostic interval
|
|
! (20) DIAGe (REAL*8 ) : TAU value at end of diagnostic interval
|
|
! (21) GMT (REAL*8 ) : Current Greenwich Mean Time (0.0 - 23.999 hrs)
|
|
! (22) TS_CHEM (INTEGER) : Chemistry timestep in minutes
|
|
! (23) TS_CONV (INTEGER) : Convection timestep in minutes
|
|
! (24) TS_DIAG (INTEGER) : Diagnostic timestep in minutes
|
|
! (25) TS_DYN (INTEGER) : Dynamic timestep in minutes
|
|
! (26) TS_EMIS (INTEGER) : Emission timestep in minutes
|
|
! (27) TS_UNIT (INTEGER) : Unit conversion timestep in minutes
|
|
! (28) CT_CHEM (INTEGER) : Number of chemistry timesteps executed so far
|
|
! (29) CT_CONV (INTEGER) : Number of convection timesteps executed so far
|
|
! (30) CT_DYN (INTEGER) : Number of dynamic timesteps executed so far
|
|
! (31) CT_EMIS (INTEGER) : Number of emission timesteps executed so far
|
|
! (32) JD85 (REAL*8 ) : Astronomical Julian Day at 0 GMT 1/1/1985
|
|
! (33) NDIAGTIME (INTEGER) : Time of day (HHMMSS) to write bpch file
|
|
!
|
|
! Module Routines:
|
|
! ============================================================================
|
|
! (1 ) SET_CURRENT_TIME : Updates time variables for current timestep
|
|
! (2 ) SET_BEGIN_TIME : Initializes NYMDb, NHMSb, TAUb variables
|
|
! (3 ) SET_END_TIME : Initializes NYMDe, NHMSe, TAUe variables
|
|
! (4 ) SET_NDIAGTIME : Initializes NDIAGTIME (time to write bpch file)
|
|
! (5 ) SET_DIAGb : Updates DIAGb and DIAGe diagnostic interval times
|
|
! (6 ) SET_DIAGe : Updates DIAGb and DIAGe diagnostic interval times
|
|
! (7 ) SET_TIMESTEPS : Updates the elapsed minutes since the start of run
|
|
! (8 ) SET_CT_CHEM : Increments/resets the chemistry timestep counter
|
|
! (9 ) SET_CT_CONV : Increments/resets the convection timestep counter
|
|
! (10) SET_CT_DYN : Increments/resets the dynamic timestep counter
|
|
! (11) SET_CT_EMIS : Increments/resets the emissions timestep counter
|
|
! (12) SET_CT_A3 : Increments/resets the A-3 fields timestep counter
|
|
! (13) SET_CT_A6 : Increments/resets the A-6 fields timestep counte
|
|
! (14) SET_CT_I6 : Increments/resets the I-6 fields timestep counter
|
|
! (15) SET_CT_XTRA : Increments/resets the I-6 fields timestep counter
|
|
! (16) SET_ELAPSED_MIN : Updates the elapsed minutes since the start of run
|
|
! (17) GET_JD : Returns Astronomical Julian Date for NYMD, NHMS
|
|
! (18) GET_ELAPSED_MIN : Returns the elapsed minutes since the start of run
|
|
! (19) GET_ELAPSED_SEC : Returns the elapsed seconds since the start of run
|
|
! (20) GET_NYMDb : Returns the YYYYMMDD at the beginning of the run
|
|
! (21) GET_NHMSb : Returns the HHMMSS at the beginning of the run
|
|
! (22) GET_NYMDe : Returns the YYYYMMDD at the end of the run
|
|
! (23) GET_NHMSe : Returns the HHMMSS at the end of the run
|
|
! (24) GET_NYMD : Returns the YYYYMMDD at the current time
|
|
! (25) GET_NHMS : Returns the HHMMSS at the current time
|
|
! (26) GET_NDIAGTIME : Returns NDIAGTIME (time of day to write bpch file)
|
|
! (27) GET_TIME_AHEAD : Returns the YYYYMMDD, HHMMSS for N_MINS from now
|
|
! (28) GET_MONTH : Returns the current month (1-12)
|
|
! (29) GET_DAY : Returns the current day of month (1-31)
|
|
! (30) GET_YEAR : Returns the current year (YYYY)
|
|
! (31) GET_HOUR : Returns the current hour (0-23)
|
|
! (32) GET_MINUTE : Returns the current minute (0-59)
|
|
! (33) GET_SECOND : Returns the current second (0-59)
|
|
! (34) GET_DAY_OF_YEAR : Returns the current day of the year (0-366)
|
|
! (35) GET_DAY_OF_WEEK : Returns the current day of the week (0-6)
|
|
! (36) GET_GMT : Returns the current GMT (0.0 - 23.999)
|
|
! (37) GET_TAU : Returns the current TAU value (hrs since 1/1/1985)
|
|
! (38) GET_TAUb : Returns TAU value at beginning of GEOS-CHEM run
|
|
! (39) GET_TAUe : Returns TAU value at end of GEOS-CHEM run
|
|
! (40) GET_DIAGb : Returns TAU value at start of diagnostic interval
|
|
! (41) GET_DIAGe : Returns TAU value at end of diagnostic interval
|
|
! (42) GET_LOCALTIME : Returns local time for a grid box (0.0 - 23.999)
|
|
! (43) GET_SEASON : Returns season flag (1=DJF, 2=MAM, 3=JJA, 4=SON)
|
|
! (44) GET_TS_CHEM : Returns chemistry timestep in minutes
|
|
! (45) GET_TS_CONV : Returns convection timestep in minutes
|
|
! (46) GET_TS_DIAG : Returns diagnostic timestep in minutes
|
|
! (47) GET_TS_DYN : Returns dynamic timestep in minutes
|
|
! (48) GET_TS_EMIS : Returns emissions timestep in minutes
|
|
! (49) GET_TS_UNIT : Returns unit conversion timestep in minutes
|
|
! (50) GET_CT_CHEM : Returns # of chemistry timesteps already executed
|
|
! (51) GET_CT_CONV : Returns # of convection timesteps already executed
|
|
! (52) GET_CT_DYN : Returns # of dynamic timesteps already executed
|
|
! (53) GET_CT_EMIS : Returns # of emission timesteps already executed
|
|
! (54) GET_CT_A3 : Returns # of times A-3 fields have been read in
|
|
! (55) GET_CT_A6 : Returns # of times A-6 fields have been read in
|
|
! (56) GET_CT_I6 : Returns # of times I-6 fields have been read in
|
|
! (57) GET_CT_XTRA : Returns # of times I-6 fields have been read in
|
|
! (58) GET_A3_TIME : Returns YYYYMMDD and HHMMSS for the A-3 fields
|
|
! (59) GET_A6_TIME : Returns YYYYMMDD and HHMMSS for the A-6 fields
|
|
! (60) GET_I6_TIME : Returns YYYYMMDD and HHMMSS for the I-6 fields
|
|
! (61) GET_FIRST_A3_TIME : Returns YYYYMMDD and HHMMSS for the first A-3 read
|
|
! (62) GET_FIRST_A3_TIME : Returns YYYYMMDD and HHMMSS for the first A-6 read
|
|
! (63) ITS_TIME_FOR_CHEM : Returns TRUE if it is time to do chemistry
|
|
! (64) ITS_TIME_FOR_CONV : Returns TRUE if it is time to do convection
|
|
! (65) ITS_TIME_FOR_DYN : Returns TRUE if it is time to do dynamics
|
|
! (66) ITS_TIME_FOR_EMIS : Returns TRUE if it is time to do emissions
|
|
! (67) ITS_TIME_FOR_UNIT : Returns TRUE if it is time to do unit conversions
|
|
! (68) ITS_TIME_FOR_DIAG : Returns TRUE if it is time to write diagnostics
|
|
! (69) ITS_TIME_FOR_A3 : Returns TRUE if it is time to read in A-3 fields
|
|
! (71) ITS_TIME_FOR_A6 : Returns TRUE if it is time to read in A-6 fields
|
|
! (72) ITS_TIME_FOR_I6 : Returns TRUE if it is time to read in I-6 fields
|
|
! (73) ITS_TIME_FOR_UNZIP: Returns TRUE if it is the end of the run
|
|
! (74) ITS_TIME_FOR_DEL : Returns TRUE if it is time to delete temp files
|
|
! (75) ITS_TIME_FOR_EXIT : Returns TRUE if it is the end of the run
|
|
! (76) ITS_TIME_FOR_BPCH : Returns TRUE if it's time to write bpch output
|
|
! (77) ITS_A_LEAPYEAR : Returns TRUE if the current year is a leapyear
|
|
! (78) ITS_A_NEW_YEAR : Returns TRUE if it's a new year
|
|
! (79) ITS_A_NEW_MONTH : Returns TRUE if it's a new month
|
|
! (80) ITS_MIDMONTH : Returns TRUE if it's 0 GMT on the 16th of the month
|
|
! (81) ITS_A_NEW_DAY : Returns TRUE if it's a new day
|
|
! (82) ITS_A_NEW_SEASON : Returns TRUE if it's a new season
|
|
! (83) TIMESTAMP_STRING : Returns a string "YYYY/MM/DD HH:MM:SS"
|
|
! (84) PRINT_CURRENT_TIME: Prints date time in YYYY/MM/DD, HH:MM:SS format
|
|
! (85) YMD_EXTRACT : Extracts YYYY, MM, DD from a YYYYMMDD format number
|
|
! (86) EXPAND_DATE : Replaces date/time tokens w/ actual values
|
|
! (87) SYSTEM_DATE_TIME : Returns the system date and time
|
|
! (88) SYSTEM_TIMESTAMP : Returns a string with the system date and time
|
|
! (89) CALC_RUN_DAYS : Returns the number of days of the run
|
|
! adj_group: add the following routines (dkh, 01/23/10)
|
|
! (90) ITS_TIME_FOR_EXIT_ADJ
|
|
! (91) ITS_A_NEW_DAY_ADJ
|
|
! (92) ITS_TIME_FOR_I6_ADJ
|
|
! (93) GET_I6_TIME_ADJ
|
|
! (94) ITS_TIME_FOR_A6_ADJ
|
|
! (95) GET_A6_TIME_ADJ
|
|
! (96) ITS_TIME_FOR_A3_ADJ
|
|
! (97) GET_A3_TIME_ADJ
|
|
! (98) GET_TIME_BEHIND_ADJ
|
|
! (99) ITS_TIME_TO_CHK_T_15_AVG
|
|
! (100) ITS_TIME_TO_GET_T_15_AVG
|
|
! (101) ITS_TIME_TO_GET_T_DAY
|
|
!
|
|
! GEOS-CHEM modules referenced by time_mod.f
|
|
! ============================================================================
|
|
! (1 ) charpak_mod.f : Module containing string handling routines
|
|
! (2 ) error_mod.f : Module containing NaN and other error check routines
|
|
! (3 ) grid_mod.f : Module containing horizontal grid information
|
|
! (4 ) julday_mod.f : Module containing astronomical Julian date routines
|
|
!
|
|
! NOTES:
|
|
! (1 ) Updated comments (bmy, 9/4/01)
|
|
! (2 ) Added routine YMD_EXTRACT. Also rewrote TIMECHECK using astronomical
|
|
! Julian day routines from "julday_mod.f". (bmy, 11/21/01)
|
|
! (3 ) Eliminated obsolete code (bmy, 2/27/02)
|
|
! (4 ) Updated comments (bmy, 5/28/02)
|
|
! (5 ) Added routine "expand_date". Also now reference "charpak_mod.f".
|
|
! (bmy, 6/27/02)
|
|
! (6 ) Now references "error_mod.f". Also added function GET_SEASON, which
|
|
! returns the current season number. (bmy, 10/22/02)
|
|
! (7 ) Now added module variables and various GET_ and SET_ routines to
|
|
! access them. Now minutes are the smallest timing unit. (bmy, 3/21/03)
|
|
! (8 ) Bug fix in DATE_STRING (bmy, 5/15/03)
|
|
! (9 ) Added GET_FIRST_A3_TIME and GET_FIRST_A6_TIME. Also added changes for
|
|
! reading fvDAS fields. (bmy, 6/26/03)
|
|
! (10) Now allow ITS_A_LEAPYEAR to take an optional argument. Bug fix for
|
|
! Linux: must use ENCODE to convert numbers to strings (bmy, 9/29/03)
|
|
! (11) Bug fix in EXPAND_DATE. Also add optional arguments to function
|
|
! TIMESTAMP_STRNIG. (bmy, 10/28/03)
|
|
! (12) Changed the name of some cpp switches in "define.h" (bmy, 12/2/03)
|
|
! (13) Modified ITS_TIME_FOR_A6 and GET_FIRST_A6_TIME for both GEOS-4
|
|
! "a_llk_03" and "a_llk_04" data versions. (bmy, 3/22/04)
|
|
! (14) Added routines ITS_A_NEW_MONTH, ITS_A_NEW_YEAR, ITS_A_NEW_DAY.
|
|
! (bmy, 4/1/04)
|
|
! (15) Added routines ITS_A_NEW_SEASON, GET_NDIAGTIME, SET_NDIAGTIME, and
|
|
! variable NDIAGTIME. (bmy, 7/20/04)
|
|
! (17) Added routine GET_DAY_OF_WEEK (bmy, 11/5/04)
|
|
! (18) Removed obsolete FIRST variable in GET_A3_TIME (bmy, 12/10/04)
|
|
! (19) Added routines SYSTEM_DATE_TIME and SYSTEM_TIMESTAMP. Also modified
|
|
! for GCAP and GEOS-5 met fields. (swu, bmy, 5/3/05)
|
|
! (20) GCAP/GISS met fields don't have leap years (swu, bmy, 8/29/05)
|
|
! (21) Added counter variable & routines for XTRA fields (tmf, bmy, 10/20/05)
|
|
! (22) Bug fix in ITS_A_NEW_YEAR (bmy, 11/1/05)
|
|
! (23) Added function ITS_MIDMONTH. Also removed obsolete functions
|
|
! NYMD_Y2K, NYMD6_2_NYMD8, NYMD_STRING, DATE_STRING.
|
|
! (sas, cdh, bmy, 12/15/05)
|
|
! (24) GCAP bug fix: There are no leapyears, so transition from 2/28 to 3/1,
|
|
! skipping 2/29 for all years. (swu, bmy, 4/24/06)
|
|
! (25) Remove support for GEOS-1 and GEOS-STRAT met fields (bmy, 8/4/06)
|
|
! (26) Further bug fix to skip over Feb 29th in GCAP (phs, bmy, 10/3/06)
|
|
! (27) Moved ITS_TIME_FOR_BPCH here from "main.f" (bmy, 2/2/07)
|
|
! (28) Added CALC_RUN_DAYS for adjoint purposes (mak, 6/07/09)
|
|
!******************************************************************************
|
|
!
|
|
IMPLICIT NONE
|
|
|
|
!=================================================================
|
|
! MODULE PRIVATE DECLARATIONS -- keep certain internal variables
|
|
! and routines from being seen outside "time_mod.f"
|
|
!=================================================================
|
|
|
|
! Make everything PUBLIC ...
|
|
PUBLIC
|
|
|
|
! ... except these variables
|
|
! comment out for calculation of NSPAN (fp)
|
|
!PRIVATE :: NYMDb, NHMSb
|
|
!PRIVATE :: NYMDe, NHMSe
|
|
PRIVATE :: NYMD, NHMS
|
|
PRIVATE :: MONTH, DAY, YEAR
|
|
PRIVATE :: HOUR, MINUTE, SECOND
|
|
PRIVATE :: NSEASON, DAY_OF_YEAR, ELAPSED_MIN
|
|
PRIVATE :: TAU, TAUb, TAUe
|
|
PRIVATE :: DIAGb, DIAGe, GMT
|
|
PRIVATE :: TS_CHEM, TS_CONV, TS_DIAG
|
|
PRIVATE :: TS_DYN, TS_EMIS, TS_UNIT
|
|
PRIVATE :: CT_CHEM, CT_CONV, CT_DYN
|
|
PRIVATE :: CT_EMIS, CT_A3, CT_A6
|
|
PRIVATE :: CT_I6, CT_XTRA, JD85
|
|
PRIVATE :: NDIAGTIME, DAY_OF_WEEK
|
|
|
|
! geos_fp (lzh, 04/10/2014)
|
|
PRIVATE :: CT_A1, CT_I3
|
|
|
|
! adj_group
|
|
PRIVATE :: DIRECTION
|
|
|
|
!=================================================================
|
|
! MODULE VARIABLES
|
|
!=================================================================
|
|
|
|
! Date and time variables
|
|
INTEGER :: NYMDb, NHMSb, NYMDe
|
|
INTEGER :: NHMSe, NYMD, NHMS
|
|
INTEGER :: MONTH, DAY, YEAR
|
|
INTEGER :: HOUR, MINUTE, SECOND
|
|
INTEGER :: NSEASON, DAY_OF_YEAR, ELAPSED_MIN
|
|
INTEGER :: DAY_OF_WEEK ! Day of week (0=Sun,1=Mon,.., 6=Sat)
|
|
INTEGER :: NDIAGTIME
|
|
REAL*8 :: TAU, TAUb, TAUe
|
|
REAL*8 :: GMT, DIAGb, DIAGe
|
|
|
|
! Timesteps
|
|
INTEGER :: TS_CHEM, TS_CONV, TS_DIAG
|
|
INTEGER :: TS_DYN, TS_EMIS, TS_UNIT
|
|
|
|
! Timestep counters
|
|
INTEGER :: CT_CHEM, CT_CONV, CT_DYN
|
|
INTEGER :: CT_EMIS, CT_A3, CT_A6
|
|
INTEGER :: CT_I6, CT_XTRA
|
|
|
|
! geos_fp (lzh, 04/10/2014)
|
|
INTEGER :: CT_A1, CT_I3
|
|
|
|
! Astronomical Julian Date at 0 GMT, 1 Jan 1985
|
|
REAL*8, PARAMETER :: JD85 = 2446066.5d0
|
|
|
|
! adj_group
|
|
INTEGER :: DIRECTION
|
|
|
|
!=================================================================
|
|
! MODULE ROUTINES -- follow below the "CONTAINS" statement
|
|
!=================================================================
|
|
CONTAINS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CURRENT_TIME
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CURRENT_TIME takes in the elapsed time in minutes since the
|
|
! start of a GEOS-CHEM simulation and sets the GEOS-CHEM time variables
|
|
! accordingly. (bmy, 2/5/03, 10/3/06)
|
|
!
|
|
! NOTES:
|
|
! (1 ) GCAP/GISS fields don't have leap years, so if JULDAY says it's
|
|
! Feb 29th, reset MONTH, DAY, JD1 to Mar 1st. (swu, bmy, 8/29/05)
|
|
! (2 ) Now references "define.h". Now add special handling to skip from
|
|
! Feb 28th to Mar 1st for GCAP model. (swu, bmy, 4/24/06)
|
|
! (3 ) Fix bug in case of GCAP fields for runs that start during leap year
|
|
! and after February 29 (phs, 9/27/06)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE JULDAY_MOD, ONLY : JULDAY, CALDATE
|
|
|
|
# include "define.h"
|
|
|
|
! Local variables
|
|
LOGICAL :: IS_LEAPYEAR
|
|
REAL*4 :: TMP
|
|
REAL*8 :: JD0, JD1, JD_JAN_1
|
|
|
|
!=================================================================
|
|
! SET_CURRENT_TIME begins here!
|
|
!=================================================================
|
|
|
|
! JD0: Astronomical Julian Date at start of GEOS-CHEM run
|
|
JD0 = GET_JD( NYMDb, NHMSb )
|
|
|
|
! JD1: Astronomical Julian Date at current time
|
|
JD1 = JD0 + ( DBLE( ELAPSED_MIN ) / 1440d0 )
|
|
|
|
! Call CALDATE to compute the current YYYYMMDD and HHMMSS
|
|
CALL CALDATE( JD1, NYMD, NHMS )
|
|
|
|
! Extract current year, month, day from NYMD
|
|
CALL YMD_EXTRACT( NYMD, YEAR, MONTH, DAY )
|
|
|
|
#if defined( GCAP )
|
|
|
|
!-------------------------------
|
|
! GCAP met fields: no leapyears
|
|
!-------------------------------
|
|
|
|
! Special handling for leap years
|
|
IF ( ITS_A_LEAPYEAR( YEAR, FORCE=.TRUE. ) ) THEN
|
|
|
|
! Get Astronomical Julian Date on Jan 0th of this year
|
|
JD_JAN_1 = GET_JD( YEAR*10000 + 0101, 000000 )
|
|
|
|
! Skip directly from Feb 28 to Mar 1st
|
|
IF ( ( JD1 - JD_JAN_1 >= 59d0 ) .and.
|
|
& ( JD0 - JD_JAN_1 <= 59d0 ) ) THEN
|
|
JD1 = JD1 + 1d0
|
|
ENDIF
|
|
|
|
! Call CALDATE to recompute YYYYMMDD and HHMMSS
|
|
CALL CALDATE( JD1, NYMD, NHMS )
|
|
|
|
! Extract current year, month, day from NYMD
|
|
CALL YMD_EXTRACT( NYMD, YEAR, MONTH, DAY )
|
|
ENDIF
|
|
|
|
#endif
|
|
|
|
! Extract current hour, minute, second from NHMS
|
|
CALL YMD_EXTRACT( NHMS, HOUR, MINUTE, SECOND )
|
|
|
|
! Fix minutes & seconds for display purposes (esp. for 1x1)
|
|
IF ( SECOND == 59 ) SECOND = 0
|
|
IF ( MOD( MINUTE+1, 10 ) == 0 ) MINUTE = MINUTE + 1
|
|
|
|
!=================================================================
|
|
! Compute other GEOS-CHEM timing variables
|
|
!=================================================================
|
|
|
|
! Current Greenwich Mean Time
|
|
GMT = ( DBLE( HOUR ) ) +
|
|
& ( DBLE( MINUTE ) / 60d0 ) +
|
|
& ( DBLE( SECOND ) / 3600d0 )
|
|
|
|
! Days elapsed in this year (0-366)
|
|
DAY_OF_YEAR = JD1 - JULDAY( YEAR, 1, 0d0 )
|
|
|
|
! TAU value (# of hours since 1 Jan 1985)
|
|
! NOTE: TMP is REAL*4 to prevent precision problems
|
|
TMP = ( JD1 - JD85 ) * 24e0
|
|
TAU = DBLE( TMP )
|
|
|
|
! Season index (1=DJF, 2=MAM, 3=JJA, 4=SON)
|
|
SELECT CASE ( MONTH )
|
|
CASE ( 12, 1, 2 )
|
|
NSEASON = 1
|
|
CASE ( 3, 4, 5 )
|
|
NSEASON = 2
|
|
CASE ( 6, 7, 8 )
|
|
NSEASON = 3
|
|
CASE ( 9, 10, 11 )
|
|
NSEASON = 4
|
|
END SELECT
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CURRENT_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_BEGIN_TIME( THISNYMDb, THISNHMSb )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_BEGIN_TIME initializes NYMDb, NHMSb, and TAUb, which are the
|
|
! YYYYMMDD, HHMMSS, and hours since 1/1/1985 corresponding to the beginning
|
|
! date and time of a GEOS-CHEM run. (bmy, 2/5/03, 7/20/04)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISNYMDb (INTEGER) : YYYYMMDD at beginning of GEOS-CHEM run
|
|
! (2 ) THISNHMSb (INTEGER) : HHMMSS at beginning of GEOS-CHEM run
|
|
!
|
|
! NOTES:
|
|
! (1 ) Added error check for THISNHMSb (bmy, 7/20/04)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISNYMDb, THISNHMSb
|
|
|
|
! Local variables
|
|
REAL*4 :: TMP
|
|
|
|
!=================================================================
|
|
! SET_BEGIN_TIME begins here!
|
|
!=================================================================
|
|
|
|
! Make sure NHMSb is valid
|
|
IF ( THISNHMSb > 235959 ) THEN
|
|
CALL ERROR_STOP( 'NHMSb cannot be greater than 23:59:59!',
|
|
& 'SET_BEGIN_TIME (time_mod.f)' )
|
|
ENDIF
|
|
|
|
! Make sure THISNYMDb uses 4 digits for the year
|
|
! and is not less than 1985/01/01
|
|
IF ( THISNYMDb < 19850101 ) THEN
|
|
CALL ERROR_STOP( 'NYMDb must be in the format YYYYMMDD!',
|
|
& 'SET_BEGIN_TIME (time_mod.f)' )
|
|
|
|
ENDIF
|
|
|
|
! Initialize NYMDb, NHMSb
|
|
NYMDb = THISNYMDb
|
|
NHMSb = THISNHMSb
|
|
|
|
! TAUb value (TMP is REAL*4 to prevent precision problems)
|
|
TMP = ( GET_JD( NYMDb, NHMSb ) - JD85 ) * 24e0
|
|
TAUb = DBLE( TMP )
|
|
|
|
! Also initialize ELAPSED_MIN
|
|
ELAPSED_MIN = 0
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_BEGIN_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_END_TIME( THISNYMDe, THISNHMSe )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_END_TIME initializes NYMDe, NHMSe, and TAUe, which are the
|
|
! YYYYMMDD, HHMMSS, and hours since 1/1/1985 corresponding to the ending
|
|
! date and time of a GEOS-CHEM run. (bmy, 2/5/03, 7/20/04)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISNYMDe (INTEGER) : YYYYMMDD at end of GEOS-CHEM run
|
|
! (2 ) THISNHMSe (INTEGER) : HHMMSS at end of GEOS-CHEM run
|
|
!
|
|
! NOTES:
|
|
! (1 ) Added error check for THISNHMSb (bmy, 7/20/04)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISNYMDe, THISNHMSe
|
|
|
|
! Local variables
|
|
REAL*4 :: TMP
|
|
|
|
!=================================================================
|
|
! SET_END_TIME begins here!
|
|
!=================================================================
|
|
|
|
! Error check to make sure
|
|
IF ( THISNHMSe > 235959 ) THEN
|
|
CALL ERROR_STOP( 'NHMSe cannot be greater than 23:59:59!',
|
|
& 'SET_END_TIME (time_mod.f)' )
|
|
ENDIF
|
|
|
|
! Make sure THISNYMDb uses 4 digits for the year
|
|
! and is not less than 1985/01/01
|
|
IF ( THISNYMDe < 19850101 ) THEN
|
|
CALL ERROR_STOP( 'NYMDe must be in the format YYYYMMDD!',
|
|
& 'SET_END_TIME (time_mod.f)' )
|
|
|
|
ENDIF
|
|
|
|
! Initialize NYMDe, NHMSe
|
|
NYMDe = THISNYMDe
|
|
NHMSe = THISNHMSe
|
|
|
|
! TAUe value (TMP is REAL*4 to prevent precision problems)
|
|
TMP = ( GET_JD( NYMDe, NHMSe ) - JD85 ) * 24e0
|
|
TAUe = DBLE( TMP )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_END_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_NDIAGTIME( THIS_NDIAGTIME )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_NDIAGTIME initializes NDIAGTIME, the time of day at which
|
|
! the binary punch file will be written out to disk. (bmy, 7/20/04)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THIS_NDIAGTIME
|
|
|
|
!=================================================================
|
|
! SET_NDIAGTIME begins here!
|
|
!=================================================================
|
|
NDIAGTIME = THIS_NDIAGTIME
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_NDIAGTIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_DIAGb( THISDIAGb )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_DIAGb initializes DIAGb, the TAU value at the beginning
|
|
! of the diagnostic averaging interval. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISDIAGb (INTEGER) : TAU value at beginning of diagnostic interval
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: THISDIAGb
|
|
|
|
!=================================================================
|
|
! SET_DIAGb begins here!
|
|
!=================================================================
|
|
DIAGb = THISDIAGb
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_DIAGb
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_DIAGe( THISDIAGe )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_DIAGe initializes DIAGe, the TAU value at the end
|
|
! of the diagnostic averaging interval. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISDIAGe (INTEGER) : TAU value at end of diagnostic interval
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: THISDIAGe
|
|
|
|
!=================================================================
|
|
! SET_DIAGe begins here!
|
|
!=================================================================
|
|
DIAGe = THISDIAGe
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_DIAGe
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_TIMESTEPS( CHEMISTRY, CONVECTION,
|
|
& DYNAMICS, EMISSION, UNIT_CONV )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_TIMESTEPS initializes the timesteps for dynamics, convection,
|
|
! chemistry, and emissions. Counters are also zeroed. (bmy, 3/21/03,10/20/05)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) CHEMISTRY (INTEGER) : Chemistry timestep [minutes]
|
|
! (2 ) CONVECTION (INTEGER) : Convective timestep [minutes]
|
|
! (3 ) DYNAMICS (INTEGER) : Dynamic timestep [minutes]
|
|
! (4 ) EMISSION (INTEGER) : Emissions timestep [minutes]
|
|
! (4 ) UNIT_CONV (INTEGER) : Unit conversion timestep [minutes]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Suppress some output lines (bmy, 7/20/04)
|
|
! (2 ) Also zero CT_XTRA (tmf, bmy, 10/20/05)
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: CHEMISTRY, CONVECTION, DYNAMICS
|
|
INTEGER, INTENT(IN) :: EMISSION, UNIT_CONV
|
|
|
|
!=================================================================
|
|
! SET_TIMESTEPS begins here!
|
|
!=================================================================
|
|
|
|
! Initialize timesteps
|
|
TS_CHEM = CHEMISTRY
|
|
TS_CONV = CONVECTION
|
|
TS_DYN = DYNAMICS
|
|
TS_EMIS = EMISSION
|
|
TS_UNIT = UNIT_CONV
|
|
|
|
! Zero timestep counters
|
|
CT_CHEM = 0
|
|
CT_CONV = 0
|
|
CT_DYN = 0
|
|
CT_EMIS = 0
|
|
CT_A3 = 0
|
|
CT_A6 = 0
|
|
CT_I6 = 0
|
|
CT_XTRA = 0
|
|
|
|
! (lzh, 04/10/2014)
|
|
CT_A1 = 0
|
|
CT_I3 = 0
|
|
|
|
! Echo to stdout
|
|
WRITE( 6, '(/,a)' ) 'SET_TIMESTEPS: setting GEOS-CHEM timesteps!'
|
|
WRITE( 6, '( a)' ) '-------------------------------------------'
|
|
WRITE( 6, '(''Chemistry Timestep [min] : '', i4 )' ) TS_CHEM
|
|
WRITE( 6, '(''Convection Timestep [min] : '', i4 )' ) TS_CONV
|
|
WRITE( 6, '(''Dynamics Timestep [min] : '', i4 )' ) TS_DYN
|
|
WRITE( 6, '(''Emission Timestep [min] : '', i4 )' ) TS_EMIS
|
|
WRITE( 6, '(''Unit Conv Timestep [min] : '', i4 )' ) TS_UNIT
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_TIMESTEPS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_CHEM( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_CHEM increments CT_CHEM, the counter of chemistry
|
|
! timesteps executed thus far. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If specified, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If specified, then will reset counter to zero
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_CHEM begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_CHEM = CT_CHEM + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_CHEM = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_CHEM
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_CONV( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_CONV increments CT_CONV, the counter of convection
|
|
! timesteps executed thus far. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_CONV begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_CONV = CT_CONV + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_CONV = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_CONV
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_DYN( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_DYN increments CT_DYN, the counter of dynamic
|
|
! timesteps executed thus far. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_DYN begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_DYN = CT_DYN + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_DYN = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_DYN
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_EMIS( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_EMIS increments CT_EMIS, the counter of emission
|
|
! timesteps executed thus far. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_EMIS begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_EMIS = CT_EMIS + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_EMIS = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_EMIS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_A3( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_A3 increments CT_A3, the counter of the number of times
|
|
! we have read in A-3 fields. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_A3 begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_A3 = CT_A3 + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_A3 = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_A3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_A6( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_A6 increments CT_A6, the counter of the number of times
|
|
! we have read in A-6 fields. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_A3 begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_A6 = CT_A6 + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_A6 = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_A6
|
|
|
|
!!! (lzh, 04/10/2014)
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_A1( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_A3 increments CT_A3, the counter of the number of times
|
|
! we have read in A-3 fields. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_A3 begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_A1 = CT_A1 + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_A1 = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_A1
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_I3( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_A3 increments CT_A3, the counter of the number of times
|
|
! we have read in A-3 fields. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_A3 begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_I3 = CT_I3 + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_I3 = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_I3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_I6( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_I6 increments CT_I6, the counter of the number of times
|
|
! we have read in I-6 fields. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_I6 begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_I6 = CT_I6 + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_I6 = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_I6
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_CT_XTRA( INCREMENT, RESET )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_CT_XTRA increments CT_XTRA, the counter of the number of
|
|
! times we have read in GEOS-3 XTRA fields. (tmf, bmy, 10/20/05)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) INCREMENT (LOGICAL) : If T, then will increment counter
|
|
! (2 ) RESET (LOGICAL) : If T, then will reset counter to zero!
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL, INTENT(IN), OPTIONAL :: INCREMENT, RESET
|
|
|
|
!=================================================================
|
|
! SET_CT_I6 begins here!
|
|
!=================================================================
|
|
IF ( PRESENT( INCREMENT ) ) THEN
|
|
CT_XTRA = CT_XTRA + 1
|
|
ELSE IF ( PRESENT( RESET ) ) THEN
|
|
CT_XTRA = 0
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_CT_XTRA
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_ELAPSED_MIN
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_ELAPSED_MIN increments the number of elapsed minutes by
|
|
! the dynamic timestep TS_DYN. (bmy, 3/21/03)
|
|
!******************************************************************************
|
|
!
|
|
!=================================================================
|
|
! SET_ELAPSED_MIN begins here!
|
|
!=================================================================
|
|
ELAPSED_MIN = ELAPSED_MIN + TS_DYN
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_ELAPSED_MIN
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_JD( THISNYMD, THISNHMS ) RESULT( THISJD )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_JD is a wrapper for the JULDAY routine. Given the current
|
|
! NYMD and NHMS values, GET_JD will return the current astronomical Julian
|
|
! date. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISNYMD (INTEGER) : YYYYMMDD value
|
|
! (2 ) THISNHMS (INTEGER) : HHMMSS value
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 m odules
|
|
USE JULDAY_MOD, ONLY : JULDAY
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: THISNYMD, THISNHMS
|
|
|
|
! Local variables
|
|
INTEGER :: Y, M, D, H, MI, S
|
|
REAL*8 :: DAY
|
|
|
|
! Function variable
|
|
REAL*8 :: THISJD
|
|
|
|
!=================================================================
|
|
! GET_JD begins here!
|
|
!=================================================================
|
|
|
|
! Extract year, month, day from NYMDb
|
|
CALL YMD_EXTRACT( THISNYMD, Y, M, D )
|
|
|
|
! Extract hour, minute, second from NHMSb
|
|
CALL YMD_EXTRACT( THISNHMS, H, MI, S )
|
|
|
|
! Decimal day (including fractional part)
|
|
DAY = DBLE( D ) + ( DBLE( H ) / 24d0 ) +
|
|
& ( DBLE( MI ) / 1440d0 ) +
|
|
& ( DBLE( S ) / 86400d0 )
|
|
|
|
! Compute astronomical Julian day at start of run
|
|
THISJD = JULDAY( Y, M, DAY )
|
|
|
|
! Return to the calling program
|
|
END FUNCTION GET_JD
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_ELAPSED_MIN() RESULT( THIS_ELAPSED_MIN )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_ELAPSED_MIN returns the elapsed minutes since the start of
|
|
! a GEOS_CHEM run to the calling program (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_ELAPSED_MIN
|
|
|
|
!=================================================================
|
|
! GET_ELAPSED_MIN begins here!
|
|
!=================================================================
|
|
THIS_ELAPSED_MIN = ELAPSED_MIN
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_ELAPSED_MIN
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_ELAPSED_SEC() RESULT( THIS_ELAPSED_SEC )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_ELAPSED_SEC returns the elapsed minutss since the start of
|
|
! a GEOS_CHEM run to the calling program (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_ELAPSED_SEC
|
|
|
|
!=================================================================
|
|
! GET_ELAPSED_SEC begins here!
|
|
!=================================================================
|
|
THIS_ELAPSED_SEC = ELAPSED_MIN * 60
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_ELAPSED_SEC
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NYMDb() RESULT( THISNYMDb )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_NYMDb returns the NYMDb value (YYYYMMDD at the beginning of
|
|
! the run) to the calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISNYMDb
|
|
|
|
!=================================================================
|
|
! GET_NYMDb begins here!
|
|
!=================================================================
|
|
THISNYMDb = NYMDb
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NYMDb
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NHMSb() RESULT( THISNHMSb )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_NHMSb returns the NHMSb value (HHMMSS at the beginning
|
|
! of the run) to the calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISNHMSb
|
|
|
|
!=================================================================
|
|
! GET_NHMSb begins here!
|
|
!=================================================================
|
|
THISNHMSb = NHMSb
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NHMSb
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NYMDe() RESULT( THISNYMDe )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_NYMDe returns the NYMDe value (YYYYMMDD at the end of
|
|
! the run) to the calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISNYMDe
|
|
|
|
!=================================================================
|
|
! GET_NYMDe begins here!
|
|
!=================================================================
|
|
THISNYMDe = NYMDe
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NYMDe
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NHMSe() RESULT( THISNHMSe )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_NHMSe returns the NHMSe value (HHMMSS at the end
|
|
! of the run) to the calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISNHMSe
|
|
|
|
!=================================================================
|
|
! GET_NHMSe begins here!
|
|
!=================================================================
|
|
THISNHMSe = NHMSe
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NHMSe
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NYMD() RESULT( THISNYMD )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_NYMD returns the current NYMD value (YYYYMMDD) to the
|
|
! calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISNYMD
|
|
|
|
!=================================================================
|
|
! GET_NYMD begins here!
|
|
!=================================================================
|
|
THISNYMD = NYMD
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NYMD
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NHMS() RESULT( THISNHMS )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_NHMS returns the current NHMS value (HHMMSS) to the
|
|
! calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISNHMS
|
|
|
|
!=================================================================
|
|
! GET_NHMS begins here!
|
|
!=================================================================
|
|
THISNHMS = NHMS
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NHMS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NDIAGTIME() RESULT( THIS_NDIAGTIME )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GET_NDIAGTIME returns to the calling program NDIAGTIME, the
|
|
! time of day at which the binary punch file will be written out to disk.
|
|
! (bmy, 7/20/04)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Local variables
|
|
INTEGER :: THIS_NDIAGTIME
|
|
|
|
!=================================================================
|
|
! GET_NDIAGTIME begins here!
|
|
!=================================================================
|
|
THIS_NDIAGTIME = NDIAGTIME
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NDIAGTIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TIME_AHEAD( N_MINS ) RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_3h_AHEAD returns to the calling program a 2-element vector
|
|
! containing the YYYYMMDD and HHMMSS values at the current time plus N_MINS
|
|
! minutes. (bmy, 3/21/03, 12/8/06)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) N_MINS (INTEGER) : Minutes ahead of time to compute YYYYMMDD,HHMMSS
|
|
!
|
|
! NOTES:
|
|
! (1 ) Bug fix for GCAP leap year case (phs, bmy, 12/8/06)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE JULDAY_MOD, ONLY : CALDATE
|
|
|
|
# include "define.h" ! C-preprocessor flags
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: N_MINS
|
|
|
|
! Local variables
|
|
INTEGER :: DATE(2), THISYEAR, THISMONTH, THISDAY
|
|
REAL*8 :: JD
|
|
|
|
!=================================================================
|
|
! GET_TIME_AHEAD begins here!
|
|
!=================================================================
|
|
|
|
! Astronomical Julian Date at current time + N_MINS
|
|
JD = GET_JD( NYMD, NHMS ) + ( N_MINS / 1440d0 )
|
|
|
|
! Call CALDATE to compute the current YYYYMMDD and HHMMSS
|
|
CALL CALDATE( JD, DATE(1), DATE(2) )
|
|
|
|
#if defined( GCAP )
|
|
|
|
!-------------------------------
|
|
! GCAP met fields: no leapyears
|
|
!-------------------------------
|
|
|
|
! Extract current year, month, day from DATE(1)
|
|
CALL YMD_EXTRACT( DATE(1), THISYEAR, THISMONTH, THISDAY )
|
|
|
|
! Special handling for leap years
|
|
IF ( ITS_A_LEAPYEAR( THISYEAR, FORCE=.TRUE. ) .AND.
|
|
& THISMONTH == 2 .AND.
|
|
& THISDAY == 29 ) THEN
|
|
DATE(1) = ( THISYEAR * 10000 ) + 0301
|
|
ENDIF
|
|
|
|
#endif
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TIME_AHEAD
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_MONTH() RESULT( THISMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_MONTH returns the current month to the calling program.
|
|
! (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISMONTH
|
|
|
|
!=================================================================
|
|
! GET_MONTH begins here!
|
|
!=================================================================
|
|
THISMONTH = MONTH
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_MONTH
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_DAY() RESULT( THISDAY )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_DAY returns the current day to the calling program.
|
|
! (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISDAY
|
|
|
|
!=================================================================
|
|
! GET_DAY begins here!
|
|
!=================================================================
|
|
THISDAY = DAY
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_DAY
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_YEAR() RESULT( THISYEAR )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_YEAR returns the current year to the calling program.
|
|
! (bmy, 2/5/03)
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISYEAR
|
|
|
|
!=================================================================
|
|
! GET_YEAR begins here!
|
|
!=================================================================
|
|
THISYEAR = YEAR
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_YEAR
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_HOUR() RESULT( THISHOUR )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_HOUR returns the current hour to the calling program.
|
|
! (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISHOUR
|
|
|
|
!=================================================================
|
|
! GET_HOUR begins here!
|
|
!=================================================================
|
|
THISHOUR = HOUR
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_HOUR
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_MINUTE() RESULT( THISMINUTE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_MINUTE returns the current minute to the calling program
|
|
! (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISMINUTE
|
|
|
|
!=================================================================
|
|
! GET_MINUTE begins here!
|
|
!=================================================================
|
|
THISMINUTE = MINUTE
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_MINUTE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_SECOND() RESULT( THISSECOND )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_SECOND returns the current seconds to the calling program.
|
|
! (bmy, 2/5/03)
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISSECOND
|
|
|
|
!=================================================================
|
|
! GET_SECOND begins here!
|
|
!=================================================================
|
|
THISSECOND = SECOND
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_SECOND
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_DAY_OF_YEAR() RESULT( THISDAYOFYEAR )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_DAY_OF_YEAR returns the current day of the year (0-365 or
|
|
! 0-366 for leap years) to the calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISDAYOFYEAR
|
|
|
|
!=================================================================
|
|
! GET_DAY_OF_YEAR begins here!
|
|
!=================================================================
|
|
THISDAYOFYEAR = DAY_OF_YEAR
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_DAY_OF_YEAR
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_DAY_OF_WEEK() RESULT( DAY_NUM )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_DAY_OF_WEEK returns the day of the week as a number:
|
|
! Sun=0, Mon=1, Tue=2, Wed=3, Thu=4, Fri=5, Sat=6. (bmy, 11/5/04)
|
|
!
|
|
! Reference:
|
|
! ============================================================================
|
|
! "Practical Astronomy with Your Calculator", 3rd Ed. Peter Duffett-Smith,
|
|
! Cambridge UP, 1992, p9.
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE JULDAY_MOD, ONLY : JULDAY
|
|
|
|
! Return value
|
|
INTEGER :: DAY_NUM
|
|
|
|
! Local variables
|
|
REAL*8 :: A, B, JD, THISDAY
|
|
|
|
!=================================================================
|
|
! GET_DAY_OF_WEEK begins here!
|
|
!=================================================================
|
|
|
|
! Get fractional day
|
|
THISDAY = DAY + ( HOUR / 24d0 ) +
|
|
& ( MINUTE / 1440d0 ) + ( SECOND / 86400d0 )
|
|
|
|
! Get current Julian date
|
|
JD = JULDAY( YEAR, MONTH, THISDAY )
|
|
|
|
! Add 1.5 to JD and divide by 7
|
|
A = ( JD + 1.5d0 ) / 7d0
|
|
|
|
! Take fractional part and multiply by 7
|
|
B = ( A - INT( A ) ) * 7d0
|
|
|
|
! Round to nearest integer -- this is the day number!
|
|
DAY_NUM = INT( B + 0.5d0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_DAY_OF_WEEK
|
|
|
|
!------------------------------------------------------------------------------
|
|
! Harvard University Atmospheric Chemistry Modeling Group !
|
|
!------------------------------------------------------------------------------
|
|
!BOP
|
|
!
|
|
! !IROUTINE: get_day_of_week_lt
|
|
!
|
|
! !DESCRIPTION: Function GET\_DAY\_OF\_WEEK\_LT returns the day of the week
|
|
! (with repect to the SOLAR LOCAL TIME AT GRID BOX [I,J,L]) as a number:
|
|
! Sun=0, Mon=1, Tue=2, Wed=3, Thu=4, Fri=5, Sat=6.
|
|
!\\
|
|
!\\
|
|
! !INTERFACE:
|
|
!
|
|
FUNCTION GET_DAY_OF_WEEK_LT( I, J, L ) RESULT( DAY_NUM )
|
|
!
|
|
! !USES:
|
|
!
|
|
USE GRID_MOD, ONLY : GET_XMID
|
|
!
|
|
! !INPUT PARAMETERS:
|
|
!
|
|
INTEGER, INTENT(IN) :: I ! Grid box lon index
|
|
INTEGER, INTENT(IN) :: J ! Grid box lat index
|
|
INTEGER, INTENT(IN) :: L ! Grid box level index
|
|
!
|
|
! !RETURN VALUE:
|
|
!
|
|
INTEGER :: DAY_NUM ! Day of week, w/r/t local time
|
|
!
|
|
! !REMARKS:
|
|
! This routine is used by various emissions routines, in order to determine
|
|
! whether weekday or weekend emissions need to be applied.
|
|
!
|
|
! !REVISION HISTORY:
|
|
! 13 Jun 2013 - R. Yantosca - Initial version
|
|
!EOP
|
|
!------------------------------------------------------------------------------
|
|
!BOC
|
|
!
|
|
! !LOCAL VARIABLES:
|
|
!
|
|
REAL*8 :: DOW_LOCAL, LOCAL_TIME
|
|
|
|
!=================================================================
|
|
! GET_DAY_OF_WEEK begins here!
|
|
!=================================================================
|
|
|
|
! Get the local time [hrs] at grid box (I,J,L),
|
|
! but do not force it into the range of [0..24] hours.
|
|
LOCAL_TIME = GMT + ( GET_XMID( I ) / 15d0 )
|
|
|
|
! Add the local fraction of day elapsed to the day of week
|
|
! obtained w/r/t the GREENWICH MEAN TIME. This accounts for
|
|
! the distance of grid box (I,J,L) from the Greenwich meridian.
|
|
DOW_LOCAL = DBLE( DAY_OF_WEEK ) + ( LOCAL_TIME / 24d0 )
|
|
|
|
! If DOW_LOCAL is negative, then we need to add 7.
|
|
! This means that the day of week w/r/t GMT is Sunday
|
|
! but that it is still Saturday at grid box (I,J,L).
|
|
IF ( DOW_LOCAL < 0d0 ) THEN
|
|
DOW_LOCAL = DOW_LOCAL + 7d0
|
|
ENDIF
|
|
|
|
! Force the day of week w/r/t LOCAL TIME to fall
|
|
! within the range 0 (Sunday) thru 6 (Saturday).
|
|
DOW_LOCAL = MOD( DOW_LOCAL, 7d0 )
|
|
|
|
! Cast to integer and return result
|
|
DAY_NUM = INT( DOW_LOCAL )
|
|
|
|
END FUNCTION GET_DAY_OF_WEEK_LT
|
|
!EOC
|
|
!------------------------------------------------------------------------------
|
|
! Harvard University Atmospheric Chemistry Modeling Group !
|
|
!------------------------------------------------------------------------------
|
|
!BOP
|
|
!
|
|
! !IROUTINE: get_gmt
|
|
!
|
|
! !DESCRIPTION: Function GET\_GMT returns the current Greenwich Mean Time
|
|
! to the calling program.
|
|
!\\
|
|
!\\
|
|
! !INTERFACE:
|
|
!
|
|
FUNCTION GET_GMT() RESULT( THISGMT )
|
|
!
|
|
! !RETURN VALUE:
|
|
!
|
|
REAL*8 :: THISGMT ! Greenwich mean time [hrs]
|
|
!
|
|
! !REVISION HISTORY:
|
|
! 05 Feb 2003 - R. Yantosca - Initial Version
|
|
! 15 Jan 2010 - R. Yantosca - Added ProTeX headers
|
|
!EOP
|
|
!------------------------------------------------------------------------------
|
|
!BOC
|
|
!
|
|
THISGMT = GMT
|
|
|
|
END FUNCTION GET_GMT
|
|
!EOC
|
|
|
|
FUNCTION GET_TAU() RESULT( THISTAU )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TAU returns the current TAU (# of hours since 1 Jan 1985)
|
|
! value to the calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
REAL*8 :: THISTAU
|
|
|
|
!=================================================================
|
|
! GET_TAUb begins here!
|
|
!=================================================================
|
|
THISTAU = TAU
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TAU
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TAUb() RESULT( THISTAUb )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TAUb returns TAUb (# of hours since 1 Jan 1985 at the
|
|
! start of a GEOS-CHEM run) to the calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
REAL*8 :: THISTAUb
|
|
|
|
!=================================================================
|
|
! GET_TAUb begins here!
|
|
!=================================================================
|
|
THISTAUb = TAUb
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TAUb
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TAUe() RESULT( THISTAUe )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TAUe returns TAUe (# of hours since 1 Jan 1985 at the
|
|
! end of a GEOS-CHEM run) to the calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
REAL*8 :: THISTAUe
|
|
|
|
!=================================================================
|
|
! GET_TAUe begins here!
|
|
!=================================================================
|
|
THISTAUe = TAUe
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TAUe
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_DIAGb() RESULT( THISDIAGb )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_DIAGb returns DIAGb (# of hours since 1 Jan 1985 at the
|
|
! start of a diagnostic interval) to the calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
REAL*8 :: THISDIAGb
|
|
|
|
!=================================================================
|
|
! GET_DIAGb begins here!
|
|
!=================================================================
|
|
THISDIAGb = DIAGb
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_DIAGb
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_DIAGe() RESULT( THISDIAGe )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_DIAGb returns DIAGe (# of hours since 1 Jan 1985 at the
|
|
! end of a diagnostic interval) to the calling program. (bmy, 2/5/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISDIAGe
|
|
|
|
!=================================================================
|
|
! GET_DIAGe begins here!
|
|
!=================================================================
|
|
THISDIAGe = DIAGe
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_DIAGe
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_LOCALTIME( I ) RESULT( THISLOCALTIME )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_LOCALTIME returns the local time of a grid box to the
|
|
! calling program. (bmy, 2/5/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) I (INTEGER) : Grid box longitude index
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE GRID_MOD, ONLY : GET_XMID
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I
|
|
|
|
! Function value
|
|
REAL*8 :: THISLOCALTIME
|
|
|
|
!=================================================================
|
|
! GET_LOCALTIME begins here!
|
|
!=================================================================
|
|
|
|
! Local Time = GMT + ( longitude / 15 ) since each hour of time
|
|
! corresponds to 15 degrees of longitude on the globe
|
|
THISLOCALTIME = GET_GMT() + ( GET_XMID( I ) / 15d0 )
|
|
|
|
! Make sure that THISLOCALTIME is in the range 0-24 hours
|
|
IF ( THISLOCALTIME > 24 ) THISLOCALTIME = THISLOCALTIME - 24d0
|
|
IF ( THISLOCALTIME < 0 ) THISLOCALTIME = THISLOCALTIME + 24d0
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_LOCALTIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_SEASON() RESULT( THISSEASON )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_SEASON returns the climatological season number
|
|
! (1=DJF, 2=MAM, 3=JJA, 4=SON) to the calling program. (bmy, 3/21/03)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) THISMONTH (INTEGER) : Current month (1-12)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THISSEASON
|
|
|
|
!=================================================================
|
|
! GET_SEASON begins here!
|
|
!=================================================================
|
|
THISSEASON = NSEASON
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_SEASON
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TS_CHEM() RESULT( THIS_TS_CHEM )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TS_CHEM returns the chemistry timestep in minutes to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_TS_CHEM
|
|
|
|
!=================================================================
|
|
! GET_TS_CHEM begins here!
|
|
!=================================================================
|
|
THIS_TS_CHEM = TS_CHEM
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TS_CHEM
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TS_CONV() RESULT( THIS_TS_CONV )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TS_CONV returns the convection timestep in minutes to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_TS_CONV
|
|
|
|
!=================================================================
|
|
! GET_TS_CONV begins here!
|
|
!=================================================================
|
|
THIS_TS_CONV = TS_CONV
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TS_CONV
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TS_DIAG() RESULT( THIS_TS_DIAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TS_DIAG returns the diagnostic timestep in minutes to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_TS_DIAG
|
|
|
|
!=================================================================
|
|
! GET_TS_DIAG begins here!
|
|
!=================================================================
|
|
THIS_TS_DIAG = TS_DIAG
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TS_DIAG
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TS_DYN() RESULT( THIS_TS_DYN )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TS_DIAG returns the diagnostic timestep in minutes to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_TS_DYN
|
|
|
|
!=================================================================
|
|
! GET_TS_DYN begins here!
|
|
!=================================================================
|
|
THIS_TS_DYN = TS_DYN
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TS_DYN
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TS_EMIS() RESULT( THIS_TS_EMIS )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TS_EMIS returns the emission timestep in minutes to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_TS_EMIS
|
|
|
|
!=================================================================
|
|
! GET_TS_EMIS begins here!
|
|
!=================================================================
|
|
THIS_TS_EMIS = TS_EMIS
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TS_EMIS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TS_UNIT() RESULT( THIS_TS_UNIT )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TS_EMIS returns the emission timestep in minutes to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_TS_UNIT
|
|
|
|
!=================================================================
|
|
! GET_TS_UNIT begins here!
|
|
!=================================================================
|
|
THIS_TS_UNIT = TS_UNIT
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TS_UNIT
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_CHEM() RESULT( THIS_CT_CHEM )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_CHEM returns the chemistry timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_CHEM
|
|
|
|
!=================================================================
|
|
! GET_CT_CHEM begins here!
|
|
!=================================================================
|
|
THIS_CT_CHEM = CT_CHEM
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_CHEM
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_CONV() RESULT( THIS_CT_CONV )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_CONV returns the convection timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_CONV
|
|
|
|
!=================================================================
|
|
! GET_CT_CONV begins here!
|
|
!=================================================================
|
|
THIS_CT_CONV = CT_CONV
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_CONV
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_DYN() RESULT( THIS_CT_DYN )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_CHEM returns the dynamic timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_DYN
|
|
|
|
!=================================================================
|
|
! GET_CT_DYN begins here!
|
|
!=================================================================
|
|
THIS_CT_DYN = CT_DYN
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_DYN
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_EMIS() RESULT( THIS_CT_EMIS )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_CHEM returns the emission timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_EMIS
|
|
|
|
!=================================================================
|
|
! GET_CT_EMIS begins here!
|
|
!=================================================================
|
|
THIS_CT_EMIS = CT_EMIS
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_EMIS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_A3() RESULT( THIS_CT_A3 )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_CHEM returns the A-3 fields timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_A3
|
|
|
|
!=================================================================
|
|
! GET_CT_A3 begins here!
|
|
!=================================================================
|
|
THIS_CT_A3 = CT_A3
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_A3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_A6() RESULT( THIS_CT_A6 )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_A6 returns the A-6 fields timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_A6
|
|
|
|
!=================================================================
|
|
! GET_CT_A6 begins here!
|
|
!=================================================================
|
|
THIS_CT_A6 = CT_A6
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_A6
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_I6() RESULT( THIS_CT_I6 )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_I6 returns the I-6 fields timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_I6
|
|
|
|
!=================================================================
|
|
! GET_CT_I6 begins here!
|
|
!=================================================================
|
|
THIS_CT_I6 = CT_I6
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_I6
|
|
|
|
!!! (lzh, 04/10/2014)
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_A1() RESULT( THIS_CT_A1 )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_CHEM returns the A-3 fields timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_A1
|
|
|
|
!=================================================================
|
|
! GET_CT_A3 begins here!
|
|
!=================================================================
|
|
THIS_CT_A1 = CT_A1
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_A1
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_I3() RESULT( THIS_CT_I3 )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_CHEM returns the A-3 fields timestep counter to the
|
|
! calling program. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_I3
|
|
|
|
!=================================================================
|
|
! GET_CT_A3 begins here!
|
|
!=================================================================
|
|
THIS_CT_I3 = CT_I3
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_I3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_CT_XTRA() RESULT( THIS_CT_XTRA )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_CT_XTRA returns the XTRA fields timestep counter to the
|
|
! calling program. (tmf, bmy, 10/20/05)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: THIS_CT_XTRA
|
|
|
|
!=================================================================
|
|
! GET_CT_I6 begins here!
|
|
!=================================================================
|
|
THIS_CT_XTRA = CT_XTRA
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_CT_XTRA
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_A1_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! (lzh, 04/09/2014)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Function value
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_A3_TIME begins here!
|
|
!=================================================================
|
|
|
|
#if defined( GEOS_FP )
|
|
|
|
! For GEOS-1, GEOS-STRAT, GEOS-3, the A-3 fields are timestamped
|
|
! by ending time. Therefore, the difference between the actual time
|
|
! when the fields are read and the A-3 timestamp time is 180 minutes.
|
|
DATE = GET_TIME_AHEAD( 30 )
|
|
|
|
#else
|
|
|
|
! For GEOS-4, GEOS-5, or GCAP data: The A-3 fields are timestamped
|
|
! by center time. Therefore, the difference between the actual time
|
|
! when the fields are read and the A-3 timestamp time is 90 minutes.
|
|
DATE = GET_TIME_AHEAD( 0 )
|
|
|
|
#endif
|
|
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_A1_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_A3_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_A3_TIME returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the next average 3-hour (A-3) fields.
|
|
! (bmy, 3/21/03, 8/4/06)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now return proper time for GEOS-4/fvDAS fields (bmy, 6/19/03)
|
|
! (2 ) Remove reference to FIRST variable (bmy, 12/10/04)
|
|
! (3 ) Now modified for GCAP and GEOS-5 met fields (swu, bmy, 5/24/05)
|
|
! (4 ) Remove support for GEOS-1 and GEOS-STRAT met fields (bmy, 8/4/06)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Function value
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_A3_TIME begins here!
|
|
!=================================================================
|
|
|
|
#if defined( GEOS_3 )
|
|
|
|
! For GEOS-1, GEOS-STRAT, GEOS-3, the A-3 fields are timestamped
|
|
! by ending time. Therefore, the difference between the actual time
|
|
! when the fields are read and the A-3 timestamp time is 180 minutes.
|
|
DATE = GET_TIME_AHEAD( 180 )
|
|
|
|
#else
|
|
|
|
! For GEOS-4, GEOS-5, or GCAP data: The A-3 fields are timestamped
|
|
! by center time. Therefore, the difference between the actual time
|
|
! when the fields are read and the A-3 timestamp time is 90 minutes.
|
|
DATE = GET_TIME_AHEAD( 90 )
|
|
|
|
#endif
|
|
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_A3_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_A6_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_A6_TIME returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the next average 6-hour (A-6) fields.
|
|
! (bmy, 3/21/03, 6/26/03)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Updated comments (bmy, 6/26/03)
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_A6_TIME begins here!
|
|
!=================================================================
|
|
|
|
! Return the time 3h (180m) from now, since there is a 3-hour
|
|
! offset between the actual time when the A-6 fields are read
|
|
! and the time that the A-6 fields are stamped with.
|
|
DATE = GET_TIME_AHEAD( 180 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_A6_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_I3_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! (lzh, 04/09/2014)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Function value
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_A3_TIME begins here!
|
|
!=================================================================
|
|
LOGICAL, SAVE :: FIRST = .TRUE.
|
|
INTEGER :: HH, MM, SS, MINS, OFFSET
|
|
|
|
!=================================================================
|
|
! ALL MET FIELDS:
|
|
!=================================================================
|
|
|
|
IF ( FIRST ) THEN
|
|
|
|
!--------------------------------------------------------------
|
|
! FIRST-TIME ONLY! Get the proper # of hours until the next
|
|
! I6 time. Also works for start times other than 0 GMT.
|
|
!--------------------------------------------------------------
|
|
|
|
! Split NHMS into hours, mins, seconds
|
|
CALL YMD_EXTRACT( NHMS, HH, MM, SS )
|
|
|
|
! Compute minutes elapsed in the 6-hour interval
|
|
MINS = MOD( HH, 3 )*60 + MM
|
|
|
|
! Compute offset to next I-3 time
|
|
OFFSET = 180 - MINS
|
|
|
|
! Get YYYY/MM/DD and hh:mm:ss to next I-6 time
|
|
DATE = GET_TIME_AHEAD( OFFSET )
|
|
|
|
! Reset first-time flag
|
|
FIRST = .FALSE.
|
|
|
|
ELSE
|
|
|
|
!--------------------------------------------------------------
|
|
! Other than the 1st time: Search 360 mins ahead
|
|
!--------------------------------------------------------------
|
|
|
|
! We need to read in the I-6 fields 6h (180 mins) ahead of time
|
|
DATE = GET_TIME_AHEAD( 180 )
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_I3_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_I6_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_I6_TIME returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the next instantaneous 6-hour (I-6) fields.
|
|
! (bmy, 3/21/03, 4/24/06)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Bug fix for GCAP: skip over Feb 29th (no leapyears). (bmy, 4/24/06)
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_I6_TIME begins here!
|
|
!=================================================================
|
|
|
|
#if defined( GCAP )
|
|
|
|
!-------------------------------
|
|
! GCAP met fields: no leapyears
|
|
!-------------------------------
|
|
|
|
! If 18 GMT on Feb 28th, the next I-6 time is 0 GMT on Mar 1st
|
|
IF ( MONTH == 2 .and. DAY == 28 .and. HOUR == 18 ) THEN
|
|
DATE = (/ ( YEAR * 10000 ) + 0301, 000000 /)
|
|
RETURN
|
|
ENDIF
|
|
|
|
#endif
|
|
|
|
!-------------------------------
|
|
! GEOS met fields: w/ leapyears
|
|
!-------------------------------
|
|
|
|
! We need to read in the I-6 fields 6h (360 mins) ahead of time
|
|
DATE = GET_TIME_AHEAD( 360 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_I6_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_FIRST_A1_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! (lzh, 04/09/2014)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Arguments
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_FIRST_A1_TIME begins here!
|
|
!=================================================================
|
|
DATE = GET_A1_TIME()
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_FIRST_A1_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_FIRST_A3_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_FIRST_A3_TIME returns the correct YYYYMMDD and HHMMSS
|
|
! values the first time that A-3 fields are read in from disk.
|
|
! (bmy, 6/26/03, 8/4/06)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now modified for GCAP and GEOS-5 data (swu, bmy, 5/24/05)
|
|
! (2 ) Remove support for GEOS-1 and GEOS-STRAT met fields (bmy, 8/4/06)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Arguments
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_FIRST_A3_TIME begins here!
|
|
!=================================================================
|
|
#if defined( GEOS_3 )
|
|
|
|
! For GEOS-1, GEOS-STRAT, GEOS-3: Return the current date/time
|
|
DATE = (/ NYMD, NHMS /)
|
|
|
|
#else
|
|
|
|
! For GEOS-4, GEOS-5, and GCAP: Call GET_A3_TIME to return
|
|
! the date/time under which the A-3 fields are timestamped
|
|
DATE = GET_A3_TIME()
|
|
|
|
#endif
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_FIRST_A3_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_FIRST_A6_TIME() RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_FIRST_A6_TIME returns the correct YYYYMMDD & HHMMSS values the
|
|
! first time that A-6 fields are read in from disk. (bmy, 6/26/03, 5/24/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now modified for GEOS-4 "a_llk_03" and "a_llk_04" fields (bmy, 3/22/04)
|
|
! (2 ) Modified for GCAP and GEOS-5 met fields (swu, bmy, 5/24/05)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Arguments
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_FIRST_A6_TIME begins here!
|
|
!=================================================================
|
|
|
|
#if defined( GCAP )
|
|
|
|
! For GCAP data: Call GET_A6_TIME to return date/time
|
|
! under which the A-6 fields are timestamped
|
|
DATE = GET_A6_TIME()
|
|
|
|
#else
|
|
|
|
! For GEOS data: Return the current date/time
|
|
DATE = (/ NYMD, NHMS /)
|
|
|
|
#endif
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_FIRST_A6_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_FIRST_I3_TIME() RESULT( DATE )
|
|
!
|
|
!!! (lzh, 04/10/2014)
|
|
!******************************************************************************
|
|
! Function GET_FIRST_A6_TIME returns the correct YYYYMMDD & HHMMSS values the
|
|
! first time that A-6 fields are read in from disk. (bmy, 6/26/03, 5/24/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now modified for GEOS-4 "a_llk_03" and "a_llk_04" fields (bmy, 3/22/04)
|
|
! (2 ) Modified for GCAP and GEOS-5 met fields (swu, bmy, 5/24/05)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Arguments
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_FIRST_A6_TIME begins here!
|
|
!=================================================================
|
|
! !LOCAL VARIABLES:
|
|
!
|
|
INTEGER :: HH, MM, SS, MINS, OFFSET
|
|
|
|
!==================================================================
|
|
! Compute first I-6 time for all met field types
|
|
!==================================================================
|
|
|
|
! Split NYMS into hours, mins, seconds
|
|
CALL YMD_EXTRACT( NHMS, HH, MM, SS )
|
|
|
|
! Compute minutes elapsed in the 3-hour interval
|
|
MINS = MOD( HH, 3 )*60 + MM
|
|
|
|
! Compute offset to nearest I-6 time
|
|
OFFSET = -MINS
|
|
|
|
! Get YYYY/MM/DD and hh:mm:ss to nearest I-6 time
|
|
DATE = GET_TIME_AHEAD( OFFSET )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_FIRST_I3_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_CHEM() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_CHEM returns TRUE if it is time to do chemistry
|
|
! and false otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_CHEM begins here!
|
|
!=================================================================
|
|
FLAG = ( MOD( ELAPSED_MIN, TS_CHEM ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_CHEM
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_CONV() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_CONV returns TRUE if it is time to do chemistry
|
|
! and false otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_CONV begins here!
|
|
!=================================================================
|
|
FLAG = ( MOD( ELAPSED_MIN, TS_CONV ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_CONV
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_DYN() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_DYN returns TRUE if it is time to do chemistry
|
|
! and false otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_DYN begins here!
|
|
!=================================================================
|
|
FLAG = ( MOD( ELAPSED_MIN, TS_DYN ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_DYN
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_EMIS() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_EMIS returns TRUE if it is time to do emissions
|
|
! and false otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_EMIS begins here!
|
|
!=================================================================
|
|
FLAG = ( MOD( ELAPSED_MIN, TS_EMIS ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_EMIS
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_UNIT() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_UNIT returns TRUE if it is time to do unit conversion
|
|
! and false otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_UNIT begins here!
|
|
!=================================================================
|
|
FLAG = ( MOD( ELAPSED_MIN, TS_DYN ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_UNIT
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_DIAG() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_DIAG returns TRUE if it is time to archive
|
|
! certain diagnostics false otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_DIAG begins here!
|
|
!=================================================================
|
|
FLAG = ( MOD( ELAPSED_MIN, 60 ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_DIAG
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_A1() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_A3 returns TRUE if it is time to read in A-3
|
|
! (average 3-h fields) and FALSE otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!!! for geos-fp (lzh, 04/10/2014)
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_A3 begins here!
|
|
!=================================================================
|
|
|
|
! We read A-3 fields every 3 hours
|
|
FLAG = ( MOD( NHMS, 010000 ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_A1
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_A3() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_A3 returns TRUE if it is time to read in A-3
|
|
! (average 3-h fields) and FALSE otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_A3 begins here!
|
|
!=================================================================
|
|
|
|
! We read A-3 fields every 3 hours
|
|
FLAG = ( MOD( NHMS, 030000 ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_A3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_A6() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_A6 returns TRUE if it is time to read in A-6
|
|
! (average 6-h fields) and FALSE otherwise. (bmy, 3/21/03, 5/24/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now compute when it's time to read in GEOS-4 A-6 fields. (bmy, 6/26/03)
|
|
! (2 ) Now modified for GEOS-4 "a_llk_03" and "a_llk_04" fields (bmy, 3/22/04)
|
|
! (3 ) Now modified for GCAP and GEOS-5 met fields (swu, bmy, 5/24/05)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Local variables
|
|
INTEGER :: DATE(2)
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_A6 begins here!
|
|
!=================================================================
|
|
|
|
#if defined( GCAP )
|
|
|
|
! For GCAP data: We need to read A-6 fields when it 00, 06,
|
|
! 12, 18 GMT. DATE is the current time -- test below.
|
|
DATE = GET_TIME_AHEAD( 0 )
|
|
|
|
#else
|
|
|
|
! For all GEOS data: We need to read A-6 fields when it is 03,
|
|
! 09, 15, 21 GMT. DATE is the time 3 hours from now -- test below.
|
|
DATE = GET_TIME_AHEAD( 180 )
|
|
|
|
#endif
|
|
|
|
! Test if DATE corresponds to 00, 06, 12, 18 GMT.
|
|
! If so, then it is time to read A-6 fields from disk.
|
|
FLAG = ( MOD( DATE(2), 060000 ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_A6
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_I3() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_I6 returns TRUE if it is time to read in I-6
|
|
! (instantaneous 6-h fields) and FALSE otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!!! for geos-fp (lzh, 04/10/2014)
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_I6 begins here!
|
|
!=================================================================
|
|
LOGICAL, SAVE :: FIRST = .TRUE.
|
|
|
|
! We read in I-6 fields at 00, 03, 06, 09, 12, 15, 18, 21 GMT
|
|
FLAG = ( ( MOD( NHMS, 030000 ) == 0 ) .or. FIRST )
|
|
|
|
FIRST = .FALSE.
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_I3
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_I6() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_I6 returns TRUE if it is time to read in I-6
|
|
! (instantaneous 6-h fields) and FALSE otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_I6 begins here!
|
|
!=================================================================
|
|
|
|
! We read in I-6 fields at 00, 06, 12, 18 GMT
|
|
FLAG = ( MOD( NHMS, 060000 ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_I6
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_UNZIP() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_UNZIP Treturns TRUE if it is time to unzip
|
|
! the next day's met field files (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Local variables
|
|
INTEGER :: DATE(2)
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_UNZIP begins here!
|
|
!=================================================================
|
|
|
|
! Get YYYYMMDD and HHMMSS 12 hours (720 mins) from now
|
|
DATE = GET_TIME_AHEAD( 720 )
|
|
|
|
! If HHMMSS = 0 then it's time to unzip!
|
|
FLAG = ( DATE(2) == 000000 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_UNZIP
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_DEL() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_DEL returns TRUE if it is time to delete the previous
|
|
! day's met field files in the temporary directory. (bmy, 3/21/03, 6/19/03)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now delete files at 23 GMT each day, since the last fvDAS A-3 field is
|
|
! 22:30 GMT and the last fvDAS A-6 field is 21 GMT. (bmy, 6/19/03)
|
|
!******************************************************************************
|
|
!
|
|
! Local variables
|
|
INTEGER :: DATE(2)
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_DEL begins here!
|
|
!=================================================================
|
|
|
|
! Delete files when it's 23 GMT
|
|
FLAG = ( NHMS == 230000 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_DEL
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_EXIT() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_EXIT returns TRUE if it is the end of the run
|
|
! (i.e. TAU >= TAUe) and false otherwise. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_FOR_EXIT begins here!
|
|
!=================================================================
|
|
FLAG = ( TAU >= TAUe )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_EXIT
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_BPCH() RESULT( DO_BPCH )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_BPCH returns true if it's time to write output
|
|
! to the bpch file. (bmy, 2/2/07)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN_DIAG" ! NJDAY
|
|
|
|
! Local variables
|
|
INTEGER :: DOY, THIS_NJDAY
|
|
LOGICAL :: DO_BPCH
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_BPCH begins here!
|
|
!=================================================================
|
|
|
|
! Return FALSE if it's the first timestep
|
|
IF ( TAU == TAUb ) THEN
|
|
DO_BPCH = .FALSE.
|
|
RETURN
|
|
ENDIF
|
|
|
|
! Day of year (0..365 or 0..366 leapyears)
|
|
DOY = DAY_OF_YEAR
|
|
|
|
! Look up appropriate value of NJDAY array. We may need to add a
|
|
! day to skip past the Feb 29 element of NJDAY for non-leap-years.
|
|
IF ( .not. ITS_A_LEAPYEAR( FORCE=.TRUE. ) .and. DOY > 59 ) THEN
|
|
THIS_NJDAY = NJDAY( DOY + 1 )
|
|
ELSE
|
|
THIS_NJDAY = NJDAY( DOY )
|
|
ENDIF
|
|
|
|
! Test if this is the day & time to write to the BPCH file!
|
|
IF ( ( THIS_NJDAY > 0 ) .and. NHMS == NDIAGTIME ) THEN
|
|
DO_BPCH = .TRUE.
|
|
ELSE
|
|
DO_BPCH = .FALSE.
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_BPCH
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_A_LEAPYEAR( YEAR_IN, FORCE ) RESULT( IS_LEAPYEAR )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_A_LEAPYEAR tests to see if a year is really a leapyear.
|
|
! (bmy, 3/17/99, 4/24/06)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) YEAR_IN (INTEGER) : (OPTIONAL) Specify a year to test for leapyear
|
|
! (2 ) FORCE (LOGICAL) : (OPTIONAL) Do not exit if using GCAP met fields
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now remove YEAR from ARG list; use the module variable (bmy, 3/21/03)
|
|
! (2 ) Now add YEAR_IN as an optional argument. If YEAR_IN is not passed,
|
|
! then test if the current year is a leapyear (bmy, 9/25/03)
|
|
! (3 ) Now always return FALSE for GCAP (swu, bmy, 8/29/05)
|
|
! (4 ) Now add FORCE argument to force ITS_A_LEAPYEAR to return a value
|
|
! instead of just returning with FALSE for the GCAP met fields.
|
|
! (swu, bmy, 4/24/06)
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER, INTENT(IN), OPTIONAL :: YEAR_IN
|
|
LOGICAL, INTENT(IN), OPTIONAL :: FORCE
|
|
|
|
! Local variables
|
|
INTEGER :: THISYEAR
|
|
LOGICAL :: THISFORCE
|
|
|
|
! Function value
|
|
LOGICAL :: IS_LEAPYEAR
|
|
|
|
!=================================================================
|
|
! LEAPYEAR begins here!
|
|
!=================================================================
|
|
|
|
! If YEAR_IN is passed, use that value; otherwise use the value
|
|
! of the current year as stored in module variable YEAR.
|
|
IF ( PRESENT( YEAR_IN ) ) THEN
|
|
THISYEAR = YEAR_IN
|
|
ELSE
|
|
THISYEAR = YEAR
|
|
ENDIF
|
|
|
|
! If FORCE is passed, use that value, otherwise default to .FALSE.
|
|
IF ( PRESENT( FORCE ) ) THEN
|
|
THISFORCE = FORCE
|
|
ELSE
|
|
THISFORCE = .FALSE.
|
|
ENDIF
|
|
|
|
!=================================================================
|
|
! A leap year is:
|
|
! (1) evenly divisible by 4 (if not a century year)
|
|
! (2) evenly divisible by 4, 100, and 400 (if a century year)
|
|
!
|
|
! EXAMPLES:
|
|
! (a) 1992 is a leap year since it is evenly divisible by 4,
|
|
! and is not a century year (i.e. it doesn't end in '00').
|
|
!
|
|
! (b) 1900 is NOT a leap year, since while being evenly divisible
|
|
! by 4 and 100, it is NOT divisible by 400.
|
|
!
|
|
! (c) 2000 is a leap year, since it is divisible by
|
|
! 4, 100, and 400.
|
|
!=================================================================
|
|
IS_LEAPYEAR = .FALSE.
|
|
|
|
#if defined( GCAP )
|
|
! For GCAP met fields, there are no leap years. However, sometimes
|
|
! we need to test to see if it would be a leap year so that we can
|
|
! tell the GEOS-Chem timing functions to skip past Feb 29th. If
|
|
! argument FORCE=T, then return the value of IS_LEAPYEAR to the
|
|
! calling program (bmy, 4/24/06)
|
|
IF ( .not. THISFORCE ) RETURN
|
|
#endif
|
|
|
|
IF ( MOD( THISYEAR, 4 ) == 0 ) THEN
|
|
IF ( MOD( THISYEAR, 100 ) == 0 ) THEN
|
|
IF ( MOD( THISYEAR, 400 ) == 0 ) THEN
|
|
IS_LEAPYEAR = .TRUE.
|
|
ENDIF
|
|
ELSE
|
|
IS_LEAPYEAR = .TRUE.
|
|
ENDIF
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_A_LEAPYEAR
|
|
|
|
!------------------------------------------------------------------------------
|
|
!******************************************************************************
|
|
|
|
|
|
FUNCTION ITS_A_NEW_HOUR( ) RESULT( IS_NEW_HOUR )
|
|
!
|
|
! !RETURN VALUE:
|
|
!
|
|
LOGICAL :: IS_NEW_HOUR
|
|
!
|
|
! !REVISION HISTORY:
|
|
! 19 Feb 2013 - K. Travis - Initial version
|
|
!EOP
|
|
!------------------------------------------------------------------------------
|
|
!BOC
|
|
!
|
|
! !LOCAL VARIABLES:
|
|
!
|
|
INTEGER, SAVE :: LAST_HOUR = -1
|
|
|
|
IF ( HOUR /= LAST_HOUR ) THEN
|
|
IS_NEW_HOUR = .TRUE.
|
|
LAST_HOUR = HOUR
|
|
ELSE
|
|
IS_NEW_HOUR = .FALSE.
|
|
ENDIF
|
|
|
|
END FUNCTION ITS_A_NEW_HOUR
|
|
|
|
|
|
!******************************************************************************
|
|
|
|
|
|
FUNCTION ITS_A_NEW_YEAR() RESULT( IS_NEW_YEAR )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_A_NEW_YEAR returns TRUE if it's the first of a new month
|
|
! (it also returns TRUE on the first timestep of the run). This is useful
|
|
! for setting flags for reading in data. (bmy, 4/1/04)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Bug fix: Need month & day to be 1 (bmy, 11/1/05)
|
|
! (2 ) adj_group: update for adjoint (dkh, 04/28/10)
|
|
! (3 ) Updated to work better with CO assimilation (zj, dkh, 01/08/12, adj32_017)
|
|
!******************************************************************************
|
|
!
|
|
! Function value)
|
|
LOGICAL :: IS_NEW_YEAR
|
|
|
|
! adj_group: local variables
|
|
INTEGER :: DATE_FWD(2), YY_FWD, MM_FWD, DD_FWD
|
|
! (zj, dkh, 01/08/12, adj32_017)
|
|
INTEGER :: YY_END, MM_END, DD_END
|
|
|
|
|
|
!=================================================================
|
|
! ITS_A_NEW_YEAR begins here!
|
|
!=================================================================
|
|
IF ( MONTH == 1 .and. DAY == 1 .and. NHMS == 000000 ) THEN
|
|
|
|
! A new year is Jan 1 at 0 GMT
|
|
IS_NEW_YEAR = .TRUE.
|
|
|
|
ELSE IF ( NYMD == NYMDb .and. NHMS == NHMSb ) THEN
|
|
|
|
! Also return TRUE if it's the start of the run
|
|
! (since files will need to be read in from disk)
|
|
IS_NEW_YEAR = .TRUE.
|
|
|
|
ELSE
|
|
|
|
! Otherwise, it's not a new year
|
|
IS_NEW_YEAR = .FALSE.
|
|
|
|
ENDIF
|
|
|
|
! adj_group: during reverse integration, return true when it
|
|
! is the last hour of a month
|
|
IF ( DIRECTION < 0 ) THEN
|
|
|
|
|
|
! check if we are in the last hour of a day
|
|
IF ( NHMS >= 230000 ) THEN
|
|
|
|
! get the year of the time 60 minutes in the future
|
|
DATE_FWD = GET_TIME_AHEAD( 60 )
|
|
CALL YMD_EXTRACT( DATE_FWD(1), YY_FWD, MM_FWD, DD_FWD )
|
|
|
|
!----------------------------------------------------------
|
|
! BUG FIX: (dkh, 01/08/12, adj32_017)
|
|
! OLD CODE:
|
|
!! if future year not the same as present...
|
|
!IF ( YY_FWD /= YEAR ) THEN
|
|
! ! then we must be in the last hour of a month
|
|
! IS_NEW_YEAR = .TRUE.
|
|
!
|
|
!ENDIF
|
|
! NEW CODE:
|
|
CALL YMD_EXTRACT( NYMDe, YY_END, MM_END, DD_END )
|
|
|
|
! if future year not the same as present...
|
|
IF ( YY_FWD /= YEAR .OR.( DD_FWD .EQ. DD_END .and.
|
|
& MM_FWD == MM_END ) ) THEN
|
|
|
|
|
|
! then we must be in the last hour of a month
|
|
IS_NEW_YEAR = .TRUE.
|
|
|
|
ENDIF
|
|
!----------------------------------------------------------
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
! Return to calling program
|
|
END FUNCTION ITS_A_NEW_YEAR
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_A_NEW_MONTH() RESULT( IS_NEW_MONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_A_NEW_MONTH returns TRUE if it's the first of a new month
|
|
! (it also returns TRUE on the first timestep of the run). This is useful
|
|
! for setting flags for reading in data. (bmy, 4/1/04)
|
|
!
|
|
! NOTES:
|
|
! (1 ) adj_group: Updated to run in adjoint (dkh, 04/28/10)
|
|
! (2 ) make sure ITS_A_NEW_MONTH is true only once per month during adjoint
|
|
! (dbm, dkh, 02/10/11)
|
|
! (3 ) update to work better with CO assimilation (zj, dkh, 01/08/12, adj32_017)
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: IS_NEW_MONTH
|
|
|
|
! adj_group: local variables
|
|
INTEGER :: DATE_FWD(2), YY_FWD, MM_FWD, DD_FWD
|
|
! (zj, dkh, 01/08/12, ad33_009)
|
|
INTEGER :: YY_END, MM_END, DD_END
|
|
|
|
|
|
!=================================================================
|
|
! ITS_A_NEW_MONTH begins here!
|
|
!=================================================================
|
|
IF ( DAY == 1 .and. NHMS == 000000 ) THEN
|
|
|
|
! Test for the 1st of the month at 0 GMT
|
|
IS_NEW_MONTH = .TRUE.
|
|
|
|
ELSE IF ( NYMD == NYMDb .and. NHMS == NHMSb ) THEN
|
|
|
|
! Also return TRUE if it's the start of the run
|
|
! (since files will need to be read in from disk)
|
|
IS_NEW_MONTH = .TRUE.
|
|
|
|
ELSE
|
|
|
|
! Otherwise, it's not a new year
|
|
IS_NEW_MONTH = .FALSE.
|
|
|
|
ENDIF
|
|
|
|
|
|
! adj_group: during reverse integration, return true when it
|
|
! is the last hour of a month
|
|
IF ( DIRECTION < 0 ) THEN
|
|
|
|
IF ( (GET_NYMDe() - GET_NYMD()) < 31 ) THEN
|
|
|
|
IS_NEW_MONTH = .FALSE.
|
|
RETURN
|
|
|
|
ENDIF
|
|
|
|
! check if we are in the last hour of a day
|
|
IF ( NHMS >= 230000 ) THEN
|
|
|
|
! get the month of the time 60 minutes in the future
|
|
DATE_FWD = GET_TIME_AHEAD( 60 )
|
|
CALL YMD_EXTRACT( DATE_FWD(1), YY_FWD, MM_FWD, DD_FWD )
|
|
|
|
! if future month not the same as present...
|
|
!----------------------------------------------------------
|
|
! BUG_FIX: (zj, dkh, 01/08/12, adj32_017)
|
|
! OLD CODE:
|
|
!IF ( MM_FWD /= MONTH ) THEN
|
|
! ! then we must be in the last hour of a month
|
|
! IS_NEW_MONTH = .TRUE.
|
|
! NEW CODE:
|
|
CALL YMD_EXTRACT( NYMDe, YY_END, MM_END, DD_END )
|
|
|
|
IF ( MM_FWD /= MONTH .OR. ( DD_FWD .EQ. DD_END .and.
|
|
& MM_FWD == MM_END ) ) THEN
|
|
|
|
! then we must be in the last hour of a month
|
|
IS_NEW_MONTH = .TRUE.
|
|
!----------------------------------------------------------
|
|
|
|
! Make sure to set it to FALSE here (dbm, dkh, 02/10/11)
|
|
ELSE
|
|
|
|
IS_NEW_MONTH = .FALSE.
|
|
|
|
ENDIF
|
|
|
|
ELSE
|
|
|
|
! Make sure to set it to FALSE here (dbm, dkh, 02/10/11)
|
|
IS_NEW_MONTH = .FALSE.
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_A_NEW_MONTH
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_MIDMONTH() RESULT( IS_MIDMONTH )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_MIDMONTH returns TRUE if it's the middle of a month
|
|
! -sas 10/10/05
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: IS_MIDMONTH
|
|
|
|
!=================================================================
|
|
! ITS_MIDMONTH begins here!
|
|
!=================================================================
|
|
|
|
! Test for the 16th of the month at 0 GMT
|
|
IS_MIDMONTH = ( DAY == 16 .and. NHMS == 000000 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_MIDMONTH
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_A_NEW_DAY( ) RESULT( IS_NEW_DAY )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_A_NEW_DAY returns TRUE if it's the first timestep of a new
|
|
! day (it also returns TRUE on the first timestep of the run). This is
|
|
! useful for setting flags for reading in data. (bmy, 4/1/04)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL :: IS_NEW_DAY
|
|
|
|
!=================================================================
|
|
! ITS_A_NEW_DAY begins here!
|
|
!=================================================================
|
|
IF ( DIRECTION > 0 ) THEN
|
|
|
|
IF ( NHMS == 000000 ) THEN
|
|
|
|
! Test if it's 0 GMT
|
|
IS_NEW_DAY = .TRUE.
|
|
|
|
ELSE IF ( NYMD == NYMDb .and. NHMS == NHMSb ) THEN
|
|
|
|
! Also return TRUE if it's the start of the run
|
|
! (since files will need to be read in from disk)
|
|
IS_NEW_DAY = .TRUE.
|
|
|
|
ELSE
|
|
|
|
! Otherwise, it's not a new year
|
|
IS_NEW_DAY = .FALSE.
|
|
|
|
ENDIF
|
|
|
|
! add support for adjoint (adj_group, 10/31/12)
|
|
ELSE
|
|
|
|
IF ( NHMS == ( 236000 - GET_TS_EMIS() * 100 ) ) THEN
|
|
|
|
! Test if it's the first emission time step starting a new day
|
|
! during the adjoint calculation
|
|
IS_NEW_DAY = .TRUE.
|
|
|
|
ELSE
|
|
|
|
! Otherwise, it's not a new year
|
|
IS_NEW_DAY = .FALSE.
|
|
|
|
ENDIF
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_A_NEW_DAY
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_A_NEW_SEASON( ) RESULT( IS_NEW_SEASON )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_A_NEW_SEASON returns TRUE if it's a new season or FALSE
|
|
! if it's not a new season. Seasons are (1=DJF, 2=MAM, 3=JJA, 4=SON).
|
|
! (bmy, 7/20/04)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: IS_NEW_SEASON
|
|
|
|
! Local variables
|
|
INTEGER, SAVE :: LAST_SEASON = -1
|
|
|
|
!=================================================================
|
|
! ITS_A_NEW_SEASON begins here!
|
|
!=================================================================
|
|
IF ( NSEASON /= LAST_SEASON ) THEN
|
|
IS_NEW_SEASON = .TRUE.
|
|
LAST_SEASON = NSEASON
|
|
ELSE
|
|
IS_NEW_SEASON = .FALSE.
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_A_NEW_SEASON
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE PRINT_CURRENT_TIME
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine PRINT_CURRENT_TIME prints the date, GMT time, and elapsed
|
|
! hours of a GEOS-CHEM simulation. (bmy, 3/21/03)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Local variables
|
|
REAL*4 :: E_HOURS
|
|
|
|
!=================================================================
|
|
! PRINT_CURRENT_TIME begins here!
|
|
!=================================================================
|
|
|
|
! Hours since start of run
|
|
E_HOURS = REAL( ELAPSED_MIN ) / 60e0
|
|
|
|
! Write quantities
|
|
WRITE( 6, 100 ) YEAR, MONTH, DAY, HOUR, MINUTE, E_HOURS
|
|
|
|
! Format string
|
|
100 FORMAT( '---> DATE: ', i4.4, '/', i2.2, '/', i2.2,
|
|
& ' GMT: ', i2.2, ':', i2.2, ' X-HRS: ', f11.3 )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE PRINT_CURRENT_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION TIMESTAMP_STRING( YYYYMMDD, HHMMSS ) RESULT( TIME_STR )
|
|
!
|
|
!******************************************************************************
|
|
! TIMESTAMP_STRING returns a formatted string "YYYY/MM/DD HH:MM" for the a
|
|
! date and time specified by YYYYMMDD and HHMMSS. If YYYYMMDD and HHMMSS are
|
|
! omitted, then TIMESTAMP_STRING will create a formatted string for the
|
|
! current date and time. (bmy, 3/21/03, 12/2/03)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Now use ENCODE statement for PGI/F90 on Linux (bmy, 9/29/03)
|
|
! (2 ) Now add optional arguments YYYYMMDD and HHMMSS (bmy, 10/27/03)
|
|
! (3 ) Renamed LINUX to LINUX_PGI (bmy, 12/2/03)
|
|
!******************************************************************************
|
|
!
|
|
# include "define.h"
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN), OPTIONAL :: YYYYMMDD, HHMMSS
|
|
|
|
! Local variables
|
|
INTEGER :: THISYEAR, THISMONTH, THISDAY
|
|
INTEGER :: THISHOUR, THISMINUTE, THISSECOND
|
|
|
|
! Function value
|
|
CHARACTER(LEN=16) :: TIME_STR
|
|
|
|
!=================================================================
|
|
! TIMESTAMP_STRING begins here!
|
|
!=================================================================
|
|
|
|
! If YYYYMMDD is passed, then use that date. Otherwise use the
|
|
! current date stored in global variables YEAR, MONTH, DAY.
|
|
IF ( PRESENT( YYYYMMDD ) ) THEN
|
|
CALL YMD_EXTRACT( YYYYMMDD, THISYEAR, THISMONTH, THISDAY )
|
|
ELSE
|
|
THISYEAR = YEAR
|
|
THISMONTH = MONTH
|
|
THISDAY = DAY
|
|
ENDIF
|
|
|
|
! If HHMMSS is passed, then use that time. Otherwise use the
|
|
! current time stored in global variables HOUR and MINUTE.
|
|
IF ( PRESENT( HHMMSS ) ) THEN
|
|
CALL YMD_EXTRACT( HHMMSS, THISHOUR, THISMINUTE, THISSECOND )
|
|
ELSE
|
|
THISHOUR = HOUR
|
|
THISMINUTE = MINUTE
|
|
ENDIF
|
|
|
|
#if defined( LINUX_PGI )
|
|
|
|
! For PGI/F90 Linux, we must use the ENCODE command
|
|
! to convert from numeric to string format (bmy, 9/29/03)
|
|
ENCODE( 16, 100, TIME_STR ) THISYEAR, THISMONTH,
|
|
& THISDAY, THISHOUR, THISMINUTE
|
|
|
|
#else
|
|
|
|
! For other platforms, we can just use a FORTRAN internal write
|
|
WRITE( TIME_STR, 100 ) THISYEAR, THISMONTH,
|
|
& THISDAY, THISHOUR, THISMINUTE
|
|
|
|
#endif
|
|
|
|
! Format statement
|
|
100 FORMAT( i4.4, '/', i2.2, '/', i2.2, ' ', i2.2, ':', i2.2 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION TIMESTAMP_STRING
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE YMD_EXTRACT( NYMD, Y, M, D )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine YMD_EXTRACT extracts the year, month, and date from an integer
|
|
! variable in YYYYMMDD format. It can also extract the hours, minutes, and
|
|
! seconds from a variable in HHMMSS format. (bmy, 11/21/01)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) NYMD (INTEGER) : Variable in YYYYMMDD (or HHMMSS) format
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (2 ) Y (INTEGER) : Variable that returns YYYY (or HH - hours )
|
|
! (3 ) M (INTEGER) : Variable that returns MM (or MM - minutes)
|
|
! (4 ) D (INTEGER) : Variable that returns DD (or SS - seconds)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: NYMD
|
|
INTEGER, INTENT(OUT) :: Y, M, D
|
|
|
|
! Local variables
|
|
REAL*8 :: REM
|
|
|
|
!=================================================================
|
|
! YMD_EXTRACT begins here!
|
|
!=================================================================
|
|
|
|
! Extract YYYY from YYYYMMDD
|
|
Y = INT( DBLE( NYMD ) / 1d4 )
|
|
|
|
! Extract MM from YYYYMMDD
|
|
REM = DBLE( NYMD ) - ( DBLE( Y ) * 1d4 )
|
|
M = INT( REM / 1d2 )
|
|
|
|
! Extract DD from YYYYMMDD
|
|
REM = REM - ( DBLE( M ) * 1d2 )
|
|
D = INT( REM )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE YMD_EXTRACT
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE EXPAND_DATE( FILENAME, YYYYMMDD, HHMMSS )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine EXPAND_DATE replaces "YYYYMMDD" and "hhmmss" tokens within
|
|
! a filename string with the actual values. (bmy, 6/27/02, 7/20/04)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) FILENAME (CHARACTER) : Filename with tokens to replace
|
|
! (2 ) YYYYMMDD (INTEGER ) : Current Year-Month-Day (must have 8 digits!)
|
|
! (3 ) HHMMSS (INTEGER ) : Current Hour-Minute-Seconds
|
|
!
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) FILENAME (CHARACTER) : Modified filename
|
|
!
|
|
! NOTES:
|
|
! (1 ) Bug fix for Linux: use ENCODE statement to convert number to string
|
|
! instead of F90 internal read. (bmy, 9/29/03)
|
|
! (2 ) Now replace 2 and 4 digit year strings for all models (bmy, 10/23/03)
|
|
! (3 ) Renamed LINUX to LINUX_PGI (bmy, 12/2/03)
|
|
! (4 ) Now do not replace "ss" with seconds, as the smallest GEOS-CHEM
|
|
! timestep is in minutes. (bmy, 7/20/04)
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE CHARPAK_MOD, ONLY : STRREPL
|
|
|
|
# include "define.h"
|
|
|
|
! Arguments
|
|
CHARACTER(LEN=*), INTENT(INOUT) :: FILENAME
|
|
INTEGER, INTENT(IN) :: YYYYMMDD, HHMMSS
|
|
|
|
! Local variables
|
|
INTEGER :: YYYY, YY, MM, DD, HH, II, SS
|
|
CHARACTER(LEN=2) :: MM_STR, DD_STR
|
|
CHARACTER(LEN=2) :: HH_STR, II_STR, SS_STR
|
|
CHARACTER(LEN=2) :: YY_STR
|
|
CHARACTER(LEN=4) :: YYYY_STR
|
|
|
|
!=================================================================
|
|
! EXPAND_DATE begins here!
|
|
!=================================================================
|
|
|
|
! Extract today's date into year, month, and day sections
|
|
CALL YMD_EXTRACT( YYYYMMDD, YYYY, MM, DD )
|
|
|
|
! Extract today's time into HH, MM, and SS sections
|
|
! (rename minutes to II so as not to overwrite MM)
|
|
CALL YMD_EXTRACT( HHMMSS, HH, II, SS )
|
|
|
|
! 2-digit year number (e.g. "97" instead of "1997")
|
|
YY = YYYY - 1900
|
|
IF ( YY >= 100 ) YY = YY - 100
|
|
|
|
#if defined( LINUX_PGI )
|
|
|
|
! Use ENCODE statement for PGI/Linux (bmy, 9/29/03)
|
|
ENCODE( 4, '(i4.4)', YYYY_STR ) YYYY
|
|
ENCODE( 2, '(i2.2)', YY_STR ) YY
|
|
ENCODE( 2, '(i2.2)', MM_STR ) MM
|
|
ENCODE( 2, '(i2.2)', DD_STR ) DD
|
|
ENCODE( 2, '(i2.2)', HH_STR ) HH
|
|
ENCODE( 2, '(i2.2)', II_STR ) II
|
|
|
|
#else
|
|
|
|
! For other platforms, use an F90 internal write (bmy, 9/29/03)
|
|
WRITE( YYYY_STR, '(i4.4)' ) YYYY
|
|
WRITE( YY_STR, '(i2.2)' ) YY
|
|
WRITE( MM_STR, '(i2.2)' ) MM
|
|
WRITE( DD_STR, '(i2.2)' ) DD
|
|
WRITE( HH_STR, '(i2.2)' ) HH
|
|
WRITE( II_STR, '(i2.2)' ) II
|
|
|
|
#endif
|
|
|
|
! Replace YYYY, MM, DD, HH tokens w/ actual values
|
|
CALL STRREPL( FILENAME, 'YYYY', YYYY_STR )
|
|
CALL STRREPL( FILENAME, 'YY', YY_STR )
|
|
CALL STRREPL( FILENAME, 'MM', MM_STR )
|
|
CALL STRREPL( FILENAME, 'DD', DD_STR )
|
|
CALL STRREPL( FILENAME, 'hh', HH_STR )
|
|
CALL STRREPL( FILENAME, 'mm', II_STR )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE EXPAND_DATE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SYSTEM_DATE_TIME( SYS_NYMD, SYS_NHMS )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SYSTEM_DATE_TIME returns the actual local date and time
|
|
! (as opposed to the model date and time). (bmy, 5/2/05)
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) SYS_NYMD (INTEGER) : System date (local time) in YYYYMMDD format
|
|
! (2 ) SYS_NHMS (INTEGER) : System time (local time) in HHMMSS format
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER, INTENT(OUT) :: SYS_NYMD
|
|
INTEGER, INTENT(OUT) :: SYS_NHMS
|
|
|
|
! Local variables
|
|
INTEGER :: V(8)
|
|
CHARACTER(LEN=8) :: D
|
|
CHARACTER(LEN=10) :: T
|
|
|
|
!=================================================================
|
|
! SYSTEM_DATE_TIME begins here!
|
|
!=================================================================
|
|
|
|
! Initialize
|
|
D = 'ccyymmdd'
|
|
T = 'hhmmss.sss'
|
|
|
|
! Call the F90 intrinsic routine DATE_AND_TIME
|
|
! Return values are (/YYYY, MM, DD, GMT_MIN, HH, MM, SS, MSEC/)
|
|
CALL DATE_AND_TIME( DATE=D, TIME=T, VALUES=V )
|
|
|
|
! Save to YYYYMMDD and HHMMSS format
|
|
SYS_NYMD = ( V(1) * 10000 ) + ( V(2) * 100 ) + V(3)
|
|
SYS_NHMS = ( V(5) * 10000 ) + ( V(6) * 100 ) + V(7)
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SYSTEM_DATE_TIME
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION SYSTEM_TIMESTAMP() RESULT( STAMP )
|
|
!
|
|
!******************************************************************************
|
|
! Function SYSTEM_TIMESTAMP returns a 16 character string with the system
|
|
! date and time in YYYY/MM/DD HH:MM format. (bmy, 5/3/05)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Local variables
|
|
INTEGER :: SYS_NYMD, SYS_NHMS
|
|
CHARACTER(LEN=16) :: STAMP
|
|
|
|
!=================================================================
|
|
! SYSTEM_TIMESTAMP begins here!
|
|
!=================================================================
|
|
|
|
! Get system date and time
|
|
CALL SYSTEM_DATE_TIME( SYS_NYMD, SYS_NHMS )
|
|
|
|
! Create a string w/ system date & time
|
|
STAMP = TIMESTAMP_STRING( SYS_NYMD, SYS_NHMS )
|
|
|
|
! Return to calling program
|
|
END FUNCTION SYSTEM_TIMESTAMP
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION CALC_RUN_DAYS() RESULT( DAYS )
|
|
|
|
!******************************************************************************
|
|
! Function CALC_RUN_DAYS computes the number of days in the simulation.
|
|
! This is useful as some arrays in the adjoint code (eg. EMS_orig) are
|
|
! allocated according to the number of days/time steps. To compute this
|
|
! we convert the start and end date from input.geos into julian time, and
|
|
! subtract. Casted to an integer, variable DAYS is output, (mak, 3/16/06)
|
|
! (1 ) NYMDb (INTEGER) : YYYYMMDD at beginning of GEOS-CHEM run
|
|
! (3 ) NYMDe (INTEGER) : YYYYMMDD at end of GEOS-CHEM run
|
|
!
|
|
! Notes:
|
|
! (1 ) Force DAYS to be at least 1 to allow simulations shorter tha
|
|
! one day (dkh, 02/22/11)
|
|
!******************************************************************************
|
|
|
|
INTEGER DAYS
|
|
REAL*8 :: JD0, JD1
|
|
|
|
! JD0: Astronomical Julian Date at start of GEOS-CHEM run
|
|
JD0 = GET_JD( NYMDb, NHMSb )
|
|
! JD1: Astronomical Julian Date at the end of GEOS-CHEM run
|
|
JD1 = GET_JD( NYMDe, NHMSe )
|
|
|
|
! BUG FIX: (dkh, 02/22/11)
|
|
!IF ( DAYS < 1 ) DAYS = 1
|
|
|
|
DAYS = JD1 - JD0
|
|
PRINT*, 'Number of days in the simulation is:', DAYS
|
|
|
|
END FUNCTION CALC_RUN_DAYS
|
|
!------------------------------------------------------------------------------
|
|
!=============----------------=====================--------------------===========
|
|
! ***************************ADJOINT SUBROUTINES****************************
|
|
!=============----------------=====================--------------------===========
|
|
|
|
SUBROUTINE SET_ELAPSED_MIN_ADJ
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_ELAPSED_MIN_ADJ decrements the number of elapsed minutes by
|
|
! the dynamic timestep TS_DYN. (Kumaresh, 01/24/08)
|
|
!******************************************************************************
|
|
!
|
|
!=================================================================
|
|
! SET_ELAPSED_MIN begins here!
|
|
!=================================================================
|
|
ELAPSED_MIN = ELAPSED_MIN - TS_DYN
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_ELAPSED_MIN_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_EXIT_ADJ() RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_EXIT_ADJ returns TRUE if it is the end of the adjoint
|
|
! run (i.e. Elapsed time <= 0) and false otherwise. (Kumaresh, 01/24/08)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
!=================================================================
|
|
! ITS_FOR_EXIT begins here!
|
|
!=================================================================
|
|
FLAG = ( ELAPSED_MIN <= 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_EXIT_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_A_NEW_DAY_ADJ( ) RESULT( IS_NEW_DAY )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_A_NEW_DAY returns TRUE if it's the first timestep of a new
|
|
! day (it also returns TRUE on the first timestep of the run). (dkh, 01/23/10)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL :: IS_NEW_DAY
|
|
|
|
! Local variables
|
|
LOGICAL, SAVE :: FIRST = .TRUE.
|
|
|
|
!=================================================================
|
|
! ITS_A_NEW_DAY_ADJ begins here!
|
|
!=================================================================
|
|
IS_NEW_DAY = .FALSE.
|
|
|
|
! adjoint equivalent of ITS_A_NEW_DAY
|
|
IF ( ( GET_NHMS() == 236000 - ( GET_TS_DYN() * 100d0 ) )
|
|
& .AND. ( .not. FIRST ) ) THEN
|
|
|
|
IS_NEW_DAY = .TRUE.
|
|
|
|
ENDIF
|
|
|
|
! Reset first-time flag
|
|
IF ( FIRST ) FIRST = .FALSE.
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_A_NEW_DAY_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_I6_ADJ( ) RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_I6_ADJ returns TRUE if it is time to read in I-6
|
|
! (instantaneous 6-h fields) and FALSE otherwise. This happens when TIME_ADJ is
|
|
! at a 6h interval, which is equivalent to when ELAPSED_TIME+TS_DYN is at a
|
|
! 6h interval. (dkh, 8/25/04)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Don't read in i6 fields when we are still within the last 6 h interval
|
|
! from the forward simulation, in which case just use the i6 fields that
|
|
! are already loaded. (dkh, 9/30/04)
|
|
! (2 ) FIXED BUG: Use EXTRA so that NHMS + (TS_DYN) is divisible by 6 h
|
|
! (3 ) Now always read in files if it's time. (dkh, 01/25/10)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
! Local variable
|
|
INTEGER :: EXTRA
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_I6_ADJ begins here!
|
|
!=================================================================
|
|
|
|
!-----------------------------------------------------------------------
|
|
! OLD CODE: now always read in files, it's just simpler (dkh, 01/25/10)
|
|
! IF ( GET_ELAPSED_SEC() >= NSECb ) THEN
|
|
!
|
|
! ! We can use I6 fields still loaded from forward run
|
|
! FLAG = .FALSE.
|
|
!
|
|
! ! Echo this fact to the screen
|
|
! WRITE(6,*) ' -- USE I6 FIELDS FROM FORWARD RUN '
|
|
!
|
|
! ELSE
|
|
!-----------------------------------------------------------------------
|
|
|
|
! EXTRA set so that current NHMS + 1 dynamic time step is
|
|
! divisible by 060000
|
|
! Original, hardwired to 30 min dynamic time step
|
|
!EXTRA = 7000
|
|
! Qinbin's formula, assumes TS_DYN <= 60 min
|
|
EXTRA = 4000 + GET_TS_DYN()*100
|
|
|
|
IF ( GET_TS_DYN() > 60 ) CALL ERROR_STOP( 'Invalid EXTRA!',
|
|
& 'ITS_TIME_FOR_I6_ADJ (adjoint.f)' )
|
|
|
|
! We read in I-6 fields at 00, 06, 12, 18 GMT
|
|
FLAG = ( MOD( GET_NHMS() + EXTRA, 060000 ) == 0 )
|
|
|
|
! ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_I6_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_I6_TIME_ADJ( ) RESULT( BEHIND_DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_I6_TIME_ADJ returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the previous instantaneous 6-hour (I-6) fields.
|
|
! (dkh, 8/25/04)
|
|
!
|
|
! NOTES:
|
|
! This is only called if ITS_TIME_FOR_I6_ADJ is true
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER :: BEHIND_DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_I6_TIME_ADJ begins here!
|
|
!=================================================================
|
|
|
|
! We need to read in the I-6 fields 6h (360 mins) behind of TIME_ADJ
|
|
! which is the same as 360 - TS_DYN behind ELAPSED_TIME
|
|
BEHIND_DATE = GET_TIME_BEHIND_ADJ( 360 - GET_TS_DYN() )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_I6_TIME_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_I3_ADJ( ) RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_I6_ADJ returns TRUE if it is time to read in I-6
|
|
! (instantaneous 6-h fields) and FALSE otherwise. This happens when TIME_ADJ is
|
|
! at a 6h interval, which is equivalent to when ELAPSED_TIME+TS_DYN is at a
|
|
! 6h interval. (dkh, 8/25/04)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Don't read in i6 fields when we are still within the last 6 h interval
|
|
! from the forward simulation, in which case just use the i6 fields that
|
|
! are already loaded. (dkh, 9/30/04)
|
|
! (2 ) FIXED BUG: Use EXTRA so that NHMS + (TS_DYN) is divisible by 6 h
|
|
! (3 ) Now always read in files if it's time. (dkh, 01/25/10)
|
|
!******************************************************************************
|
|
!!! geos-fp (lzh, 04/10/2014)
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
! Local variable
|
|
INTEGER :: EXTRA
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_I6_ADJ begins here!
|
|
!=================================================================
|
|
|
|
!-----------------------------------------------------------------------
|
|
! OLD CODE: now always read in files, it's just simpler (dkh, 01/25/10)
|
|
! IF ( GET_ELAPSED_SEC() >= NSECb ) THEN
|
|
!
|
|
! ! We can use I6 fields still loaded from forward run
|
|
! FLAG = .FALSE.
|
|
!
|
|
! ! Echo this fact to the screen
|
|
! WRITE(6,*) ' -- USE I6 FIELDS FROM FORWARD RUN '
|
|
!
|
|
! ELSE
|
|
!-----------------------------------------------------------------------
|
|
|
|
! EXTRA set so that current NHMS + 1 dynamic time step is
|
|
! divisible by 060000
|
|
! Original, hardwired to 30 min dynamic time step
|
|
!EXTRA = 7000
|
|
! Qinbin's formula, assumes TS_DYN <= 60 min
|
|
EXTRA = 4000 + GET_TS_DYN()*100
|
|
|
|
IF ( GET_TS_DYN() > 60 ) CALL ERROR_STOP( 'Invalid EXTRA!',
|
|
& 'ITS_TIME_FOR_I3_ADJ (adjoint.f)' )
|
|
|
|
! We read in I-6 fields at 00, 06, 12, 18 GMT
|
|
FLAG = ( MOD( GET_NHMS() + EXTRA, 030000 ) == 0 )
|
|
|
|
! ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_I3_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_I3_TIME_ADJ( ) RESULT( BEHIND_DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_I6_TIME_ADJ returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the previous instantaneous 6-hour (I-6) fields.
|
|
! (dkh, 8/25/04)
|
|
!
|
|
! NOTES:
|
|
! This is only called if ITS_TIME_FOR_I6_ADJ is true
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER :: BEHIND_DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_I6_TIME_ADJ begins here!
|
|
!=================================================================
|
|
|
|
! We need to read in the I-6 fields 6h (360 mins) behind of TIME_ADJ
|
|
! which is the same as 360 - TS_DYN behind ELAPSED_TIME
|
|
BEHIND_DATE = GET_TIME_BEHIND_ADJ( 180 - GET_TS_DYN() )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_I3_TIME_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_A6_ADJ( ) RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_A6_ADJ returns TRUE if it is time to read in I-A
|
|
! (average 6-h fields) and FALSE otherwise. This happens when TIME_ADJ is
|
|
! at a 6h interval (03, 09, 15,21), which is equivalent to when
|
|
! ELAPSED_TIME+TS_DYN is at a 6h interval. (dkh, 03/04/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Don't read in A6 fields when we are still within the last 6 h interval
|
|
! from the forward simulation, in which case just use the A6 fields that
|
|
! are already loaded. NSECb is the total elapsed seconds at the last fwd
|
|
! I6 interval, so if we are more than 3 hr past this, can use A6 fields
|
|
! from forward run. (dkh, 03/04/05)
|
|
! (2 ) Now always read in files if it's time. (dkh, 01/25/10)
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
! Local variable
|
|
INTEGER :: EXTRA
|
|
INTEGER :: DATE(2)
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_A6_ADJ begins here!
|
|
!=================================================================
|
|
|
|
|
|
!-------------------------------------------------------------------------
|
|
! OLD CODE: now we read them every time, it's just simpler (dkh, 01/25/10)
|
|
! IF ( GET_ELAPSED_SEC() >= NSECb + 3 * 3600 ) THEN
|
|
!
|
|
! ! We can use A6 fields still loaded from forward run
|
|
! FLAG = .FALSE.
|
|
!
|
|
! ! Echo this fact to the screen
|
|
! WRITE(6,*) ' -- USE A6 FIELDS FROM FORWARD RUN '
|
|
!
|
|
! ELSE
|
|
!-------------------------------------------------------------------------
|
|
|
|
#if defined( GEOS_4 ) && defined( A_LLK_03 ) || defined ( GCAP )
|
|
|
|
! For GEOS-4 "a_llk_03" data, we need to read A-6 fields when it
|
|
! is 00, 06, 12, 18 GMT. DATE is the current time -- test below.
|
|
DATE = GET_TIME_AHEAD( 0 )
|
|
|
|
#else
|
|
|
|
! For GEOS-1, GEOS-S, GEOS-3, and GEOS-4 "a_llk_04" data,
|
|
! we need to read A-6 fields when it is 03, 09, 15, 21 GMT.
|
|
! DATE is the time 3 before now -- test below.
|
|
DATE = GET_TIME_BEHIND_ADJ( 180 )
|
|
|
|
#endif
|
|
! EXTRA set so that current NHMS + 1 dynamic time step is
|
|
! divisible by 060000
|
|
! Original formula, assumes dynamic time step is 30 min
|
|
! EXTRA = 7000
|
|
! Qinbin's formula, assumes dynamic time step <= 60
|
|
EXTRA = 4000 + GET_TS_DYN() * 100
|
|
|
|
IF ( GET_TS_DYN() > 60 ) CALL ERROR_STOP( 'Invalid EXTRA!',
|
|
& 'ITS_TIME_FOR_A6_ADJ (adjoint.f)' )
|
|
|
|
! We read in A-6 fields at 03, 09, 15, 21 GMT
|
|
FLAG = ( MOD( DATE(2) + EXTRA, 060000 ) == 0 )
|
|
|
|
! ENDIF
|
|
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_A6_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_A6_TIME_ADJ( ) RESULT( BEHIND_DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_A6_TIME_ADJ returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the previous average 6-hour (A-6) fields.
|
|
! (dkh, 03/04/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) This is only called if ITS_TIME_FOR_A6_ADJ is true
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
INTEGER :: BEHIND_DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_A6_TIME_ADJ begins here!
|
|
!=================================================================
|
|
|
|
! Return the time 3h (180m) before now, since there is a 3-hour
|
|
! offset between the actual time when the A-6 fields are read
|
|
! and the time that the A-6 fields are stamped with. Also apply
|
|
! offset of TS_DYN.
|
|
BEHIND_DATE = GET_TIME_BEHIND_ADJ( 180 - GET_TS_DYN() )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_A6_TIME_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_A3_ADJ( ) RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_A3_ADJ returns TRUE if it is time to read in A-3
|
|
! (average 3-h fields) and FALSE otherwise. This happens when TIME_ADJ is
|
|
! at a 3h interval, which is equivalent to when
|
|
! ELAPSED_TIME+TS_DYN is at a 3h interval. (dkh, 03/04/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Don't read in 3 fields when we are still within the last 3 h interval
|
|
! from the forward simulation, in which case just use the A3 fields that
|
|
! are already loaded. NSECb is the total elapsed seconds at the last fwd
|
|
! I6 interval, so if we are more than 3 hr past this, can use A3 fields
|
|
! from forward run. (dkh, 03/04/05)
|
|
! (2 ) Now always read in files if it's time. (dkh, 01/25/10)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
! Local variable
|
|
INTEGER :: EXTRA
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_A3_ADJ begins here!
|
|
!=================================================================
|
|
|
|
!-------------------------------------------------------------------------
|
|
! OLD CODE: now skip this option just to make this simpler (dkh, 01/25/10)
|
|
! IF ( GET_ELAPSED_SEC() >= NSECb + 3 * 3600 ) THEN
|
|
! !IF ( GET_ELAPSED_SEC() >= NSECb + 3 * 3600 + 30*60 ) THEN
|
|
!
|
|
! ! We can use A3 fields still loaded from forward run
|
|
! FLAG = .FALSE.
|
|
!
|
|
! ! Echo this fact to the screen
|
|
! WRITE(6,*) ' -- USE A3 FIELDS FROM FORWARD RUN '
|
|
!
|
|
! ELSE
|
|
!-------------------------------------------------------------------------
|
|
|
|
! EXTRA set so that current NHMS + 1 dynamic time step is
|
|
! divisible by 030000
|
|
! Original formula, assumes dynamic time step is 30 min
|
|
!EXTRA = 7000
|
|
! Qinbin's formula, assumes dynamic time step <= 60 min
|
|
EXTRA = 4000 + GET_TS_DYN() * 100
|
|
|
|
IF ( GET_TS_DYN() > 30 ) CALL ERROR_STOP( 'Invalid EXTRA!',
|
|
& 'ITS_TIME_FOR_A3_ADJ (adjoint.f)' )
|
|
|
|
! We read in A-3 every 3 hours
|
|
FLAG = ( MOD( GET_NHMS() + EXTRA, 030000 ) == 0 )
|
|
|
|
! ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_A3_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_A3_TIME_ADJ( ) RESULT( BEHIND_DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_A3_TIME_ADJ returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the previous average 3-hour (A-3) fields.
|
|
! (dkh, 03/04/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) This is only called if ITS_TIME_FOR_A3_ADJ is true
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
|
|
! Arguments
|
|
INTEGER :: BEHIND_DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_A3_TIME_ADJ begins here!
|
|
!=================================================================
|
|
|
|
!#if defined( GEOS_4 )
|
|
#if defined( GEOS_4 ) || defined ( GEOS_5 ) || defined( GEOS_FP )
|
|
|
|
! For GEOS-4/fvDAS, the A-3 fields are timestamped by center time.
|
|
! Therefore, the difference between the actual time when the fields
|
|
! are read and the A-3 timestamp time is 90 minutes.
|
|
BEHIND_DATE = GET_TIME_BEHIND_ADJ( 90 - GET_TS_DYN() )
|
|
|
|
#else
|
|
|
|
! For GEOS-1, GEOS-STRAT, GEOS-3, the A-3 fields are timestamped
|
|
! by ending time. Therefore, the difference between the actual time
|
|
! when the fields are read and the A-3 timestamp time is 180 minutes.
|
|
!BEHIND_DATE = GET_TIME_BEHIND_ADJ( 180 - TS_DYN )
|
|
BEHIND_DATE = GET_TIME_BEHIND_ADJ( - GET_TS_DYN() )
|
|
|
|
#endif
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_A3_TIME_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_FOR_A1_ADJ( ) RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_FOR_A3_ADJ returns TRUE if it is time to read in A-3
|
|
! (average 3-h fields) and FALSE otherwise. This happens when TIME_ADJ is
|
|
! at a 3h interval, which is equivalent to when
|
|
! ELAPSED_TIME+TS_DYN is at a 3h interval. (dkh, 03/04/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Don't read in 3 fields when we are still within the last 3 h interval
|
|
! from the forward simulation, in which case just use the A3 fields that
|
|
! are already loaded. NSECb is the total elapsed seconds at the last fwd
|
|
! I6 interval, so if we are more than 3 hr past this, can use A3 fields
|
|
! from forward run. (dkh, 03/04/05)
|
|
! (2 ) Now always read in files if it's time. (dkh, 01/25/10)
|
|
!******************************************************************************
|
|
!!! geos-fp (lzh, 04/10/2014)
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
! Local variable
|
|
INTEGER :: EXTRA
|
|
|
|
!=================================================================
|
|
! ITS_TIME_FOR_A3_ADJ begins here!
|
|
!=================================================================
|
|
! EXTRA set so that current NHMS + 1 dynamic time step is
|
|
! divisible by 030000
|
|
! Original formula, assumes dynamic time step is 30 min
|
|
!EXTRA = 7000
|
|
! Qinbin's formula, assumes dynamic time step <= 60 min
|
|
EXTRA = 4000 + GET_TS_DYN() * 100
|
|
|
|
IF ( GET_TS_DYN() > 30 ) CALL ERROR_STOP( 'Invalid EXTRA!',
|
|
& 'ITS_TIME_FOR_A1_ADJ (adjoint.f)' )
|
|
|
|
! We read in A-3 every 1 hours
|
|
FLAG = ( MOD( GET_NHMS() + EXTRA, 010000 ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_FOR_A1_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_A1_TIME_ADJ( ) RESULT( BEHIND_DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_A3_TIME_ADJ returns the correct YYYYMMDD and HHMMSS values
|
|
! that are needed to read in the previous average 3-hour (A-3) fields.
|
|
! (dkh, 03/04/05)
|
|
!
|
|
! NOTES:
|
|
! (1 ) This is only called if ITS_TIME_FOR_A3_ADJ is true
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
|
|
! Arguments
|
|
INTEGER :: BEHIND_DATE(2)
|
|
|
|
!=================================================================
|
|
! GET_A3_TIME_ADJ begins here!
|
|
!=================================================================
|
|
#if defined( GEOS_4 ) || defined ( GEOS_5 ) || defined( GEOS_FP )
|
|
|
|
! For GEOS-4/fvDAS, the A-3 fields are timestamped by center time.
|
|
! Therefore, the difference between the actual time when the fields
|
|
! are read and the A-3 timestamp time is 90 minutes.
|
|
BEHIND_DATE = GET_TIME_BEHIND_ADJ( 30 - GET_TS_DYN() )
|
|
|
|
#else
|
|
|
|
! For GEOS-1, GEOS-STRAT, GEOS-3, the A-3 fields are timestamped
|
|
! by ending time. Therefore, the difference between the actual time
|
|
! when the fields are read and the A-3 timestamp time is 180 minutes.
|
|
!BEHIND_DATE = GET_TIME_BEHIND_ADJ( 180 - TS_DYN )
|
|
BEHIND_DATE = GET_TIME_BEHIND_ADJ( - GET_TS_DYN() )
|
|
|
|
#endif
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_A1_TIME_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_TIME_BEHIND_ADJ( N_MINS ) RESULT( DATE )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_TIME_BEHIND_ADJ returns to the calling program a 2-element vector
|
|
! containing the YYYYMMDD and HHMMSS values at the current time minus N_MINS
|
|
! minutes. (dkh, 8/25/04)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) N_MINS (INTEGER) : Minutes ahead of time to compute YYYYMMDD,HHMMSS
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE JULDAY_MOD, ONLY : CALDATE
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: N_MINS
|
|
|
|
! Local variables
|
|
INTEGER :: DATE(2)
|
|
REAL*8 :: JD
|
|
|
|
!=================================================================
|
|
! GET_TIME_BEHIND_ADJ begins here!
|
|
!=================================================================
|
|
|
|
! Astronomical Julian Date at current time - N_MINS
|
|
JD = GET_JD( GET_NYMD(), GET_NHMS() ) - ( N_MINS / 1440d0 )
|
|
|
|
! Call CALDATE to compute the current YYYYMMDD and HHMMSS
|
|
CALL CALDATE( JD, DATE(1), DATE(2) )
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_TIME_BEHIND_ADJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_TO_CHK_T_15_AVG( ) RESULT( IS_TIME )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_TO_CHK_T_15_AVG returns TRUE if it's the last timestep
|
|
! of the day. (dkh, 01/23/10)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL :: IS_TIME
|
|
|
|
!=================================================================
|
|
! ITS_TIME_TO_CHK_T_15_AVG begins here!
|
|
!=================================================================
|
|
IS_TIME = .FALSE.
|
|
|
|
! adjoint equivalent of ITS_A_NEW_DAY
|
|
IF ( GET_NHMS() == ( 236000 - ( GET_TS_DYN() * 100d0 ) ) ) THEN
|
|
|
|
IS_TIME = .TRUE.
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_TO_CHK_T_15_AVG
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_TO_GET_T_15_AVG( ) RESULT( IS_TIME )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_TO_GET_T_15_AVG returns TRUE if it's the last timestep
|
|
! of the day. (dkh, 01/23/10)
|
|
!
|
|
! NOTES:
|
|
!******************************************************************************
|
|
!
|
|
! Arguments
|
|
LOGICAL :: IS_TIME
|
|
|
|
!=================================================================
|
|
! ITS_TIME_TO_GET_T_15_AVG begins here!
|
|
!=================================================================
|
|
IS_TIME = .FALSE.
|
|
|
|
! adjoint equivalent of ITS_A_NEW_DAY
|
|
IF ( GET_NHMS() == ( 236000 - ( GET_TS_DYN() * 100d0 ) ) ) THEN
|
|
|
|
IS_TIME = .TRUE.
|
|
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_TO_GET_T_15_AVG
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION ITS_TIME_TO_GET_T_DAY( ) RESULT( FLAG )
|
|
!
|
|
!******************************************************************************
|
|
! Function ITS_TIME_TO_GET_T_DAY returns TRUE if it is time to read in
|
|
! checkpointed values of T_DAY. (dkh, 01/23/10)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Based on ITS_TIME_FOR_A3_ADJ.
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Function value
|
|
LOGICAL :: FLAG
|
|
|
|
! Local variable
|
|
INTEGER :: EXTRA
|
|
LOGICAL, SAVE :: FIRST = .TRUE.
|
|
|
|
!=================================================================
|
|
! ITS_TIME_TO_GET_T_DAY begins here!
|
|
!=================================================================
|
|
|
|
! EXTRA set so that current NHMS + 1 dynamic time step is
|
|
! divisible by 030000
|
|
! Original formula, assumes dynamic time step is 30 min
|
|
!EXTRA = 7000
|
|
! Qinbin's formula, assumes dynamic time step <= 60 min
|
|
EXTRA = 4000 + GET_TS_DYN() * 100
|
|
|
|
IF ( GET_TS_DYN() > 30 ) CALL ERROR_STOP( 'Invalid EXTRA!',
|
|
& 'ITS_TIME_FOR_A3_ADJ (adjoint.f)' )
|
|
|
|
! We read in A-3 every 3 hours
|
|
FLAG = ( MOD( GET_NHMS() + EXTRA, 030000 ) == 0 )
|
|
|
|
! Return to calling program
|
|
END FUNCTION ITS_TIME_TO_GET_T_DAY
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_DIRECTION( ) RESULT ( D )
|
|
!
|
|
!******************************************************************************
|
|
! Function GET_DIRECTION returns the value of DIRECTION (dkh, 11/08/09)
|
|
!
|
|
! Output:
|
|
! ============================================================================
|
|
! (1 ) D (INTEGER) : 1 = forward, -1 = adjoint
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: D
|
|
|
|
!=================================================================
|
|
! GET_DIRECTION begins here!
|
|
!=================================================================
|
|
|
|
D = DIRECTION
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_DIRECTION
|
|
|
|
!-----------------------------------------------------------------------------
|
|
|
|
SUBROUTINE SET_DIRECTION( D )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine SET_DIRECTION is used to set the value of DIRECTION (dkh, 11/08/09)
|
|
!
|
|
! Input:
|
|
! ============================================================================
|
|
! (1 ) D (INTEGER) : 1 = forward, -1 = adjoint
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Function value
|
|
INTEGER :: D
|
|
|
|
!=================================================================
|
|
! SET_DIRECTION begins here!
|
|
!=================================================================
|
|
|
|
DIRECTION = D
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE SET_DIRECTION
|
|
|
|
!-----------------------------------------------------------------------------
|
|
|
|
|
|
|
|
END MODULE TIME_MOD
|
|
|
|
|
|
|
|
|