Files
GEOS-Chem-adjoint-v35-note/code/obs_operators/mls_hno3_obs_mod.f90
2018-08-28 00:40:44 -04:00

596 lines
18 KiB
Fortran

MODULE MLS_HNO3_OBS_MOD
!
!
! Module MLS_HNO3_OBS contains all subroutines and variables needed for MLS HNO3 column data
!
!
! Module Routines:
!
! (1) READ_MLS_HNO3_FILE : Read MLS hdf file
IMPLICIT NONE
#include "CMN_SIZE"
PRIVATE
!PUBLIC READ_OMI_HNO3_FILE
PUBLIC READ_MLS_HNO3_FILE
PUBLIC CALC_MLS_HNO3_FORCE
! Module variables
! MLS data
REAL*8, ALLOCATABLE :: MLS_LON(:)
REAL*8, ALLOCATABLE :: MLS_LAT(:)
REAL*8, ALLOCATABLE :: MLS_TIME(:)
REAL*8, ALLOCATABLE :: MLS_HNO3(:,:)
REAL*8, ALLOCATABLE :: MLS_HNO3_STD(:,:)
REAL*8, ALLOCATABLE :: MLS_CN(:)
REAL*8, ALLOCATABLE :: MLS_CON_QUAL(:)
REAL*8, ALLOCATABLE :: MLS_STA_QUAL(:)
REAL*8, ALLOCATABLE :: MLS_MAIN_QUAL(:)
REAL*8, ALLOCATABLE :: MLS_VIEW_ZENITH(:)
REAL*8, ALLOCATABLE :: MLS_SOLAR_ZENITH(:)
REAL*8, ALLOCATABLE :: MLS_PRESSURE(:)
! MLS grid specification
INTEGER :: N_MLS_OBS
INTEGER :: N_MLS_ALT
CONTAINS
!-----------------------------------------------------------------------------!
SUBROUTINE READ_MLS_HNO3_FILE ( YYYYMMDD, HHMMSS )
USE ERROR_MOD, ONLY : ALLOC_ERR
USE TIME_MOD, ONLY : EXPAND_DATE, GET_MONTH, GET_YEAR
USE HDF5
! Arguments
INTEGER, INTENT(IN) :: YYYYMMDD, HHMMSS
CHARACTER(LEN=255) :: DIR_MLS
CHARACTER(LEN=255) :: DIR_MONTH_MLS
CHARACTER(LEN=255) :: FILENAME_MLS
CHARACTER(LEN=255) :: FILENAME_FULL
CHARACTER(LEN=255) :: DSET_NAME
INTEGER(HID_T) :: file_id, dset_id, dspace_id
INTEGER(HSIZE_T) :: dims(2), maxdims(2), data_dims(2)
INTEGER :: error
CALL CLEANUP_MLS
DIR_MLS = '/users/jk/15/xzhang/MLS_HNO3/'
DIR_MONTH_MLS = '/YYYY/MM/'
FILENAME_MLS = 'MLS-Aura_L2GP-HNO3_v04-22-c01_YYYYdMMDD.he5'
CALL EXPAND_DATE(DIR_MLS, YYYYMMDD, 0)
CALL EXPAND_DATE(DIR_MONTH_MLS, YYYYMMDD, 0)
CALL EXPAND_DATE(FILENAME_MLS, YYYYMMDD, 0)
FILENAME_FULL = TRIM(DIR_MLS) // TRIM(DIR_MONTH_MLS) // TRIM(FILENAME_MLS)
PRINT *,"READING MLS File: ", FILENAME_FULL
! Initialize HDF5 Interface
PRINT *,"INITIALIZE INTERFACE"
CALL h5open_f(error)
! Open HDF5 file
PRINT *,"OPEN FILE"
CALL h5fopen_f (FILENAME_FULL, H5F_ACC_RDONLY_F, file_id, error)
! Read Time array
PRINT *,"READING TIME ARRAY"
DSET_NAME = '/HDFEOS/SWATHS/HNO3/Data Fields/L2gpValue'
PRINT *,"OPENING DATA SET"
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
! open dataspace
CALL h5dget_space_f(dset_id, dspace_id, error)
! read in length of data arrays
CALL h5sget_simple_extent_dims_f(dspace_id, dims, maxdims, error)
! close dataspace
CALL h5sclose_f(dspace_id, error)
N_MLS_ALT = dims(1)
N_MLS_OBS = dims(2)
ALLOCATE(MLS_TIME(N_MLS_OBS))
ALLOCATE(MLS_LON(N_MLS_OBS))
ALLOCATE(MLS_LAT(N_MLS_OBS))
ALLOCATE(MLS_HNO3(N_MLS_ALT,N_MLS_OBS))
ALLOCATE(MLS_CON_QUAL(N_MLS_OBS))
ALLOCATE(MLS_HNO3_STD(N_MLS_ALT,N_MLS_OBS))
ALLOCATE(MLS_MAIN_QUAL(N_MLS_OBS))
ALLOCATE(MLS_STA_QUAL(N_MLS_OBS))
ALLOCATE(MLS_CN(N_MLS_OBS))
ALLOCATE(MLS_VIEW_ZENITH(N_MLS_OBS))
ALLOCATE(MLS_SOLAR_ZENITH(N_MLS_OBS))
ALLOCATE(MLS_PRESSURE(N_MLS_ALT))
PRINT *,"ALLOCATING TIME ARRAY WITH LENGTH: ", N_MLS_OBS
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_HNO3, data_dims, error)
CALL h5dclose_f(dset_id,error)
! Read MLS HNO3 array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Data Fields/L2gpValue'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_HNO3, data_dims, error)
CALL h5dclose_f(dset_id,error)
!PRINT *, "L2gpValue", MLS_HNO3(:,N_MLS_OBS)
! Read Time array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Geolocation Fields/Time'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_TIME, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read Longitude array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Geolocation Fields/Longitude'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_LON, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read Latitude array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Geolocation Fields/Latitude'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_LAT, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read MLS HNO3 Precision array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Data Fields/L2gpPrecision'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_HNO3_STD, data_dims, error)
CALL h5dclose_f(dset_id,error)
! Read Quality array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Data Fields/Quality'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_MAIN_QUAL, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read Status array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Data Fields/Status'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_STA_QUAL, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read ChunkNumber array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Geolocation Fields/ChunkNumber'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_CN, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read LineofSightAngle array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Geolocation Fields/LineOfSightAngle'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_VIEW_ZENITH, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read Solar zenith Angle array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Geolocation Fields/SolarZenithAngle'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_SOLAR_ZENITH, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read Convergence quality array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Data Fields/Convergence'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_CON_QUAL, (/data_dims(2),0/), error)
CALL h5dclose_f(dset_id,error)
! Read Convergence quality array
DSET_NAME= '/HDFEOS/SWATHS/HNO3/Geolocation Fields/Pressure'
CALL h5dopen_f(file_id, DSET_NAME, dset_id, error)
CALL h5dread_f(dset_id, H5T_NATIVE_DOUBLE, MLS_PRESSURE, (/data_dims(1),0/), error)
CALL h5dclose_f(dset_id,error)
! close HDF5 file
CALL h5fclose_f(file_id,error)
! close HDF5 interface
CALL h5close_f(error)
END SUBROUTINE READ_MLS_HNO3_FILE
!-----------------------------------------------------------------------------!
SUBROUTINE CALC_MLS_HNO3_FORCE
!!
!! Subroutine CALC_OMI_HNO3_FORCE computes the HNO3 adjoint forcing from OMI column data
!!
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
USE CHECKPT_MOD, ONLY : CHK_STT
USE COMODE_MOD, ONLY : JLOP
USE COMODE_MOD, ONLY : CSPEC_AFTER_CHEM
USE COMODE_MOD, ONLY : CSPEC_AFTER_CHEM_ADJ
USE DAO_MOD, ONLY : AD
USE DAO_MOD, ONLY : AIRDEN
USE DAO_MOD, ONLY : BXHEIGHT
USE GRID_MOD, ONLY : GET_IJ
USE TIME_MOD, ONLY : GET_HOUR
USE TROPOPAUSE_MOD, ONLY : ITS_IN_THE_TROP
USE ADJ_ARRAYS_MOD, ONLY : ID2C
USE TRACERID_MOD, ONLY : IDHNO3, IDTHNO3
USE ADJ_ARRAYS_MOD, ONLY : COST_FUNC
USE TRACER_MOD, ONLY : XNUMOLAIR
USE TRACER_MOD, ONLY : TCVV
USE PRESSURE_MOD, ONLY : GET_PCENTER, GET_PEDGE
#include "CMN_SIZE" ! size parameters
INTEGER :: I,J,K,L
INTEGER :: I_MLS, J_MLS, JLOOP
INTEGER :: IIJJ(2)
! variables for time unit conversion
REAL*8 :: tai93
INTEGER :: iy,im,id,ih,imin
REAL*8 :: sec
INTEGER :: GC_HOUR
! variables for observation operator and adjoint thereof
REAL*8 :: GC_HNO3(LLPAR)
REAL*8 :: GC_HNO3_COL
REAL*8 :: GC_HNO3_ADJ(IIPAR,JJPAR,LLPAR)
REAL*8 :: CM22DU
REAL*8 :: DIFF
REAL*8 :: OBS_ERROR
LOGICAL :: MLS_MATCH
REAL*8 :: OMI_MLS_DIST
REAl*8 :: OMI_MLS_DIST_LON
REAl*8 :: OMI_MLS_DIST_LAT
REAL*8 :: MLS_HNO3_GC(LLPAR)
REAL*8 :: MLS_HNO3_GC_STD(LLPAR)
REAL*8 :: NCP(LLPAR)
REAL*8 :: COUNT_GRID(IIPAR,JJPAR)
REAL*8 :: COST_CONTRIB(LLPAR)
! arrays needed for superobservations
LOGICAL :: SUPER_OBS = .TRUE. ! do super observations?
REAL*8 :: SOBS_COUNT(IIPAR,JJPAR) ! super observation count
REAL*8 :: SOBS_ADJ_FORCE(IIPAR,JJPAR,LLPAR) ! super observation adjoint forcing
REAL*8 :: GC_ADJ_COUNT(IIPAR,JJPAR,LLPAR)
REAL*8 :: NEW_COST(IIPAR,JJPAR) ! super observation cost function contribution
REAL*8 :: SOBS_GC(IIPAR,JJPAR)
REAL*8 :: SOBS_OMI(IIPAR,JJPAR)
REAL*8 :: SOBS_BIAS(IIPAR,JJPAR)
REAL*8 :: SOBS_CHISQUARED(IIPAR,JJPAR)
! Loop through data to find observations
CM22DU = 2.69E16 ! conversion factor for DU -> #/cm2
GC_HOUR = GET_HOUR()
! initialize needed arrays and variables
COUNT_GRID = 0d0
COST_CONTRIB = 0d0
GC_HNO3 = 0d0
GC_HNO3_ADJ = 0d0
GC_HNO3_COL = 0d0
MLS_HNO3_GC = 0d0
MLS_HNO3_GC_STD = 0d0
NCP = 0d0
SOBS_COUNT = 0d0
SOBS_ADJ_FORCE = 0d0
NEW_COST = 0d0
GC_ADJ_COUNT = 0d0
OMI_MLS_DIST = 10000d0
DO I_MLS = 1, N_MLS_OBS
IF(MLS_TIME(I_MLS)>0) THEN
! There is an observation in the MLS grid box.
! Check if it was made within the current hour.
tai93 = MLS_TIME(I_MLS)
! Convert TAI93 to UTC
CALL TAI2UTC(tai93,iy,im,id,ih,imin,sec)
IF ( ( GC_HOUR .EQ. ih ) .AND. &
( MLS_MAIN_QUAL(I_MLS) > 0.5 ) .AND. &
( MLS_STA_QUAL(I_MLS) < 250 ) .AND. &
( MLS_CON_QUAL(I_MLS) < 1.4 ) ) THEN
! Get model grid coordinate indices that correspond to the observation
IIJJ = GET_IJ(REAL(MLS_LON(I_MLS),4),REAL(MLS_LAT(I_MLS),4))
I = IIJJ(1)
J = IIJJ(2)
! Get GEOS-CHEM HNO3 values
GC_HNO3 = 0d0
GC_HNO3_COL = 0d0
MLS_HNO3_GC = 0d0
MLS_HNO3_GC_STD = 0d0
NCP = 0d0
COST_CONTRIB = 0d0
DO L = 1, LLPAR
JLOOP = JLOP(I,J,L)
IF( ( GET_PCENTER(I,J,L) < 151 ) .AND. ( GET_PCENTER(I,J,L) > 15 ) ) THEN
!IF ( JLOOP > 0 ) THEN
!GC_HNO3(L) = CSPEC_AFTER_CHEM(JLOOP,ID2C(IDHNO3)) * 1d6 / ( AIRDEN(L,I,J) * XNUMOLAIR )
!ELSE
!GC_HNO3(L) = CHK_STT(I,J,L,IDTOX) * TCVV(IDTOX) / AD(I,J,L)
!ENDIF
! CHK_STT is in units of [kg/box] here. Convert to ppb
GC_HNO3(L) = CHK_STT(I,J,L,IDTHNO3) * TCVV(IDTHNO3) / AD(I,J,L)
DO J_MLS = 1, N_MLS_ALT
IF( ( MLS_PRESSURE(J_MLS) >= GET_PEDGE(I,J,L+1) ) .AND. &
( MLS_PRESSURE(J_MLS) < GET_PEDGE(I,J,L) ) .AND. &
( MLS_PRESSURE(J_MLS) < 151 ) .AND. &
( MLS_PRESSURE(J_MLS) > 15 ) .AND. &
( MLS_HNO3(J_MLS,I_MLS) > 0 ) ) THEN
MLS_HNO3_GC(L) = MLS_HNO3_GC(L) + MLS_HNO3(J_MLS,I_MLS)
MLS_HNO3_GC_STD(L) = MLS_HNO3_GC_STD(L) + MLS_HNO3_STD(J_MLS,I_MLS)**2
NCP(L) = NCP(L) + 1
ENDIF
ENDDO
IF (NCP(L)>0) THEN
MLS_HNO3_GC(L) = MLS_HNO3_GC(L)/NCP(L)
MLS_HNO3_GC_STD(L) = (MLS_HNO3_GC_STD(L)**(0.5))/NCP(L)
OBS_ERROR = MLS_HNO3_GC_STD(L)
DIFF = GC_HNO3(L) - MLS_HNO3_GC(L)
COST_CONTRIB(L) = 0.5 * (DIFF/OBS_ERROR)**2
IF ( ( COST_CONTRIB(L) > 0d0) .AND. &
( GET_PCENTER(I,J,L) < 151 ) .AND. &
( GET_PCENTER(I,J,L) > 15 ) ) THEN
IF (SUPER_OBS) THEN
NEW_COST(I,J) = NEW_COST(I,J) + COST_CONTRIB(L)
SOBS_COUNT(I,J) = SOBS_COUNT(I,J) + 1
SOBS_ADJ_FORCE(I,J,L) = SOBS_ADJ_FORCE(I,J,L) + DIFF/(OBS_ERROR**2) * TCVV(IDTHNO3) / AD(I,J,L)
GC_ADJ_COUNT(I,J,L) = GC_ADJ_COUNT(I,J,L) + 1
ENDIF
ENDIF
ENDIF
ENDIF
ENDDO
!PRINT *, "MODELLED HNO3", GC_HNO3
!PRINT *, "OBSERVED HNO3", MLS_HNO3_GC
! Compute stratospheric HNO3 column value [v/v*cm]
!GC_HNO3_COL = SUM(GC_HNO3(:) * BXHEIGHT(I,J,:) * 100d0)
!PRINT *, "GC_HNO3_COL", GC_HNO3_COL
!PRINT *, "MLS_HNO3_COL", MLS_HNO3_COL(I_MLS)
!DIFF = GC_HNO3_COL - MLS_HNO3_COL(I_MLS)
!OBS_ERROR = (MLS_HNO3_COL_STD(I_MLS))**0.5
!DO L = 1, LLPAR
!IF( ( GET_PCENTER(I,J,L) < 151 ) .AND. ( GET_PCENTER(I,J,L) > 15 ) ) THEN
!JLOOP = JLOP(I,J,L)
!IF (SUPER_OBS) THEN
!SOBS_ADJ_FORCE(I,J,L) = SOBS_ADJ_FORCE(I,J,L) + DIFF/(OBS_ERROR**2) * BXHEIGHT(I,J,L) * 100d0 &
!* TCVV(IDTHNO3) / (AD(I,J,L) * 1d6)
!ELSE
!STT_ADJ(I,J,L,IDTHNO3) = STT_ADJ(I,J,L,IDTHNO3) + DIFF/(OBS_ERROR**2) * BXHEIGHT(I,J,L) * 100d0 &
!* TCVV(IDTHNO3) / (AD(I,J,L) * 1d6)
!ENDIF
!ENDIF
!ENDDO
!PRINT *, "SUPER_OBS_FORCE", SOBS_ADJ_FORCE
ENDIF
ENDIF
ENDDO
!PRINT *, "SUPER_OBS_FORCE", SOBS_ADJ_FORCE
IF (SUPER_OBS) THEN
DO J = 1,JJPAR
DO I = 1, IIPAR
IF(SOBS_COUNT(I,J) > 0d0) THEN
DO L = 1,LLPAR
IF( ( GET_PCENTER(I,J,L) < 151 ) .AND. &
( GET_PCENTER(I,J,L) > 15 ) .AND. &
( GC_ADJ_COUNT(I,J,L) > 0 ) ) THEN
!JLOOP = JLOP(I,J,L)
STT_ADJ(I,J,L,IDTHNO3) = STT_ADJ(I,J,L,IDTHNO3) + SOBS_ADJ_FORCE(I,J,L)/GC_ADJ_COUNT(I,J,L)
ENDIF
ENDDO
COST_FUNC = COST_FUNC + NEW_COST(I,J)/SOBS_COUNT(I,J)
ENDIF
ENDDO
ENDDO
ENDIF
PRINT *, "COST FUNCTION OF MLS HNO3", COST_FUNC
END SUBROUTINE CALC_MLS_HNO3_FORCE
!----------------------------------------------------------------------------!
SUBROUTINE CLEANUP_MLS
IF (ALLOCATED( MLS_LON )) DEALLOCATE( MLS_LON )
IF (ALLOCATED( MLS_LAT )) DEALLOCATE( MLS_LAT )
IF (ALLOCATED( MLS_TIME )) DEALLOCATE( MLS_TIME )
IF (ALLOCATED( MLS_HNO3 )) DEALLOCATE( MLS_HNO3 )
IF (ALLOCATED( MLS_HNO3_STD )) DEALLOCATE( MLS_HNO3_STD )
IF (ALLOCATED( MLS_CON_QUAL )) DEALLOCATE( MLS_CON_QUAL )
IF (ALLOCATED( MLS_MAIN_QUAL )) DEALLOCATE( MLS_MAIN_QUAL )
IF (ALLOCATED( MLS_STA_QUAL )) DEALLOCATE( MLS_STA_QUAL )
IF (ALLOCATED( MLS_CN )) DEALLOCATE( MLS_CN )
IF (ALLOCATED( MLS_SOLAR_ZENITH )) DEALLOCATE( MLS_SOLAR_ZENITH )
IF (ALLOCATED( MLS_VIEW_ZENITH )) DEALLOCATE( MLS_VIEW_ZENITH )
IF (ALLOCATED( MLS_PRESSURE )) DEALLOCATE( MLS_PRESSURE )
END SUBROUTINE CLEANUP_MLS
!-----------------------------------------------------------------------------!
SUBROUTINE TAI2UTC(tai93,iy,im,id,ih,imin,sec)
!!
!! SUBROUTINE TAI2UTC converts TAI93 time (seconds since 1.1.1993) to UTC
!!
!! adapted from
!! code.google.com/p/miyoshi/source/browse/trunk/common/common.f90
IMPLICIT NONE
INTEGER,PARAMETER :: n=7 ! number of leap seconds after Jan. 1, 1993
INTEGER,PARAMETER :: leapsec(n) = (/ 15638399, 47174400, 94608001, 141868802, 189302403, 410227204, 504921605/)
REAL*8,INTENT(IN) :: tai93
INTEGER,INTENT(OUT) :: iy,im,id,ih,imin
REAL*8,INTENT(OUT) :: sec
REAL*8,PARAMETER :: mins = 60.0d0
REAL*8,PARAMETER :: hour = 60.0d0*mins
REAL*8,PARAMETER :: day = 24.0d0*hour
REAL*8,PARAMETER :: year = 365.0d0*day
INTEGER,PARAMETER :: mdays(12) = (/31,28,31,30,31,30,31,31,30,31,30,31/)
REAL*8 :: wk,tai
INTEGER :: days,i,leap
tai = tai93
sec = 0.0d0
DO i=1,n
IF(FLOOR(tai93) == leapsec(i)+1) THEN
sec = 60.0d0 + tai93-FLOOR(tai93)
ENDIF
IF(FLOOR(tai93) > leapsec(i)) tai = tai -1.0d0
END DO
iy = 1993 + FLOOR(tai /year)
wk = tai - REAL(iy-1993)*year - FLOOR(REAL(iy-1993)/4.0)*day
IF(wk < 0.0d0) THEN
iy = iy -1
wk = tai - REAL(iy-1993)*year - FLOOR(REAL(iy-1993)/4.0)*day
END IF
days = FLOOR(wk/day)
wk = wk - REAL(days)*day
im = 1
DO i=1,12
leap = 0
IF(im == 2 .AND. MOD(iy,4)==0) leap=1
IF(im == i .AND. days >= mdays(i)+leap) THEN
im = im + 1
days = days - mdays(i)-leap
END IF
END DO
id = days +1
ih = FLOOR(wk/hour)
wk = wk - REAL(ih)*hour
imin = FLOOR(wk/mins)
IF(sec < 60.0d0) sec = wk - REAL(imin)*mins
RETURN
END SUBROUTINE TAI2UTC
END MODULE MLS_HNO3_OBS_MOD