5492 lines
195 KiB
Fortran
5492 lines
195 KiB
Fortran
!$Id: lidort_mod.f,v 1.5 2012/05/09 22:31:56 nicolas Exp $
|
|
MODULE LIDORT_MOD
|
|
!
|
|
!******************************************************************************
|
|
! LIDORT_MOD contains routines for calculating aerosol optical properties
|
|
! and there derivaties. (dkh, 01/17/08)
|
|
!
|
|
! Module Variables:
|
|
! ============================================================================
|
|
! (1 ) (INTEGER) :
|
|
!
|
|
! NOTES
|
|
! (1 ) Updated from GCv6, renamed LIDORT_MOD from AERO_OPTICAL_MOD. (dkh, 05/18/10)
|
|
! (2 ) Updated to LIDORT v3p5 (dkh, 07/29/10)
|
|
!******************************************************************************
|
|
!
|
|
USE ADJ_ARRAYS_MOD, ONLY : NSPAN
|
|
USE ADJ_ARRAYS_MOD, ONLY : INV_NSPAN
|
|
|
|
IMPLICIT NONE
|
|
|
|
! include file for LIDORT Mk 2 threads
|
|
#include "./thread_sourcecode_MkII_F90/LIDORT.PARS_F90"
|
|
|
|
PRIVATE
|
|
PUBLIC :: CALC_RF_FORCE
|
|
|
|
!=================================================================
|
|
! MODULE VARIABLES
|
|
!=================================================================
|
|
! Parameters
|
|
INTEGER, PARAMETER :: IU_AOD = 523
|
|
INTEGER, PARAMETER :: IU_LID = 524
|
|
INTEGER, PARAMETER :: IU_RAD = 525
|
|
LOGICAL, PARAMETER :: L_PRINT = .FALSE.
|
|
|
|
! Indicies for MIE TABLE
|
|
INTEGER, PARAMETER :: NWL_MAX = 5 ! Maximum number of wavelengths
|
|
!fha (6/1/11) added OC
|
|
INTEGER, PARAMETER :: NSP_MAX = 3 ! Maximum number of species
|
|
INTEGER, PARAMETER :: NOP_MAX = 2 ! Maximum number of optical properties
|
|
INTEGER, PARAMETER :: NRA_MAX = 20 ! Maximum number of radii
|
|
!INTEGER, PARAMETER :: NPM_MAX = 40 ! Maximum number of phase moments
|
|
INTEGER, PARAMETER :: NPM_MAX = 20 ! Maximum number of phase moments
|
|
INTEGER, PARAMETER :: NPM_ACT = 5 ! Number of active phase moments
|
|
|
|
|
|
INTEGER, PARAMETER :: NSP_SULF = 1 ! mie species index for sulfate
|
|
INTEGER, PARAMETER :: NSP_BC = 2 ! mie species index for black carbon
|
|
!fha (6/1/11) added OC
|
|
INTEGER, PARAMETER :: NSP_OC = 3 ! mie species index for organic carbon
|
|
INTEGER, PARAMETER :: NOP_BEXT = 1 ! mie property index of extinction coeffs
|
|
INTEGER, PARAMETER :: NOP_SSA = 2 ! mie property index of single scattering albedo
|
|
|
|
REAL*8, PARAMETER :: ABS_FAC = 1.5d0 ! absorption enhancement. See Bond and
|
|
! Bergstrom, 2006; Koch et al., 2009.
|
|
|
|
|
|
! Number of TEMIS LER wavelenths
|
|
INTEGER, PARAMETER :: LLER = 11
|
|
|
|
! Data
|
|
! Table of lambdas considered [nm]
|
|
REAL*8 :: LAMBDA_TABLE(NWL_MAX)
|
|
DATA LAMBDA_TABLE / 315d0, 357d0, 500d0,
|
|
& 833d0, 1667d0 /
|
|
INTEGER, PARAMETER :: NWL_500 = 3
|
|
|
|
! particle size range. updated to GCv8-03-01
|
|
! fha - 6-7-11 added OC range from jv_spec.dat; changed sulfate from 0.25 to 0.23
|
|
REAL*8 :: RMIN(NSP_MAX)
|
|
DATA RMIN / 0.07d0, 0.02D0, 0.06D0 /
|
|
REAL*8 :: RMAX(NSP_MAX)
|
|
DATA RMAX / 0.23d0, 0.04D0, 0.16D0 /
|
|
|
|
! From integrating the Plank function using T=5796 K (for 6.4d7 W/m2
|
|
! emissions from the sun) then assuming a mean distance to earch
|
|
! of 1.5d11 m. This gives a solar constant of 1367 W / m2.
|
|
! note: given the bands here, we're only considering 1254.4 W/m2
|
|
REAL*8 :: SOL_FLUX_TABLE(NWL_MAX)
|
|
DATA SOL_FLUX_TABLE / 9.7635d00, 1.0606d02,
|
|
& 5.0274d02, 4.3814d02,
|
|
& 1.9769d02 /
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: SMALL = 1d-20
|
|
|
|
! Microphyical Data
|
|
! size distribution properties
|
|
REAL*8 :: DRY_DIAM(NSP_MAX)
|
|
! updated to GCv8-03-01
|
|
!DATA DRY_DIAM / 0.1d0, 0.02d0 /
|
|
!fha - 6-7-11 added OC size (2x RMIN above)
|
|
DATA DRY_DIAM / 0.14d0, 0.04d0, 0.12d0 /
|
|
REAL*8 :: SIGMA(NSP_MAX)
|
|
! updated to GCv8-03-01
|
|
!fha - 6-7-11 added OC sigma
|
|
!DATA SIGMA / 2D0, 2D0 /
|
|
DATA SIGMA / 1.6D0, 1.6D0, 1.6D0 /
|
|
|
|
! refractive index. 10^(-7.5) = -3.1622776d-08, 10^(-3.5) = 0.00031622776d0
|
|
! From Martin 2004, Table 1
|
|
REAL*8 :: REFRAC_INDEX(NSP_MAX,NWL_MAX,2)
|
|
DATA REFRAC_INDEX(NSP_SULF,1,:) / 1.46d0, 3.1622776d-08 /
|
|
DATA REFRAC_INDEX(NSP_SULF,2,:) / 1.46d0, 3.1622776d-08 /
|
|
DATA REFRAC_INDEX(NSP_SULF,3,:) / 1.46d0, 3.1622776d-08 /
|
|
DATA REFRAC_INDEX(NSP_SULF,4,:) / 1.40d0, 1.d-07 /
|
|
DATA REFRAC_INDEX(NSP_SULF,5,:) / 1.40d0, 0.00031622776d0 /
|
|
! BC props from ??
|
|
DATA REFRAC_INDEX(NSP_BC, 1,:) / 1.743d0, 0.469d0 /
|
|
DATA REFRAC_INDEX(NSP_BC, 2,:) / 1.750d0, 0.464d0 /
|
|
DATA REFRAC_INDEX(NSP_BC, 3,:) / 1.750d0, 0.450d0 /
|
|
DATA REFRAC_INDEX(NSP_BC, 4,:) / 1.750d0, 0.432d0 /
|
|
DATA REFRAC_INDEX(NSP_BC, 5,:) / 1.783d0, 0.473d0 /
|
|
!fha 5-26-2011
|
|
! OC props from d'Almeida, Koepke, Shettle 1991 Atmospheric Aerosols Global climatology and Radiative Characteristics p. 57
|
|
DATA REFRAC_INDEX(NSP_OC, 1,:) / 1.53d0, -0.007d0 /
|
|
DATA REFRAC_INDEX(NSP_OC, 2,:) / 1.53d0, -0.00504d0 /
|
|
DATA REFRAC_INDEX(NSP_OC, 3,:) / 1.53d0, -0.0058d0 /
|
|
DATA REFRAC_INDEX(NSP_OC, 4,:) / 1.53d0, -0.0105d0 /
|
|
DATA REFRAC_INDEX(NSP_OC, 5,:) / 1.52d0, -0.01916d0 /
|
|
! Ion density from Martin et al., 2004 (ACP).
|
|
!fha 6-1-11 I added a fake 1d0 for OC here
|
|
REAL*8 :: DENSE(NSP_MAX)
|
|
DATA DENSE / 1.75d0, 1d0, 1d0 /
|
|
|
|
! note: need to update to Daumont-Malicet cross sections
|
|
|
|
! Factor used for averaging results from 1 day using 24 1hr time steps
|
|
! NSPAN is now defined in input.gcadj
|
|
!INTEGER, PARAMETER :: NSPAN = 1
|
|
! Now reference this from adj_arrays_mod.f
|
|
!REAL*8, PARAMETER :: INV_NSPAN = 1.d0 / REAL(NSPAN,8)
|
|
|
|
|
|
! Allocatable variables
|
|
REAL*8, ALLOCATABLE :: AOD_SAVE(:,:,:)
|
|
REAL*8, ALLOCATABLE :: AOD_AVE(:,:,:)
|
|
REAL*8, ALLOCATABLE :: LAYER_AOD(:,:,:,:)
|
|
REAL*8, ALLOCATABLE :: LAYER_SSA(:,:,:,:)
|
|
REAL*8, ALLOCATABLE :: LAYER_PHM(:,:,:,:,:)
|
|
REAL*8, ALLOCATABLE :: MASS_ND(:,:)
|
|
REAL*8, ALLOCATABLE :: TEMIS_LER(:,:,:)
|
|
|
|
REAL*8, ALLOCATABLE :: GLOB_FLUX_W(:,:,:)
|
|
REAL*8, ALLOCATABLE :: JAC_GLOB_FLUX_W(:,:,:,:,:)
|
|
REAL*8, ALLOCATABLE :: GLOB_FLUX(:,:)
|
|
REAL*8, ALLOCATABLE :: GLOB_AVE_FORCE(:,:)
|
|
|
|
REAL*8, ALLOCATABLE :: GLOB_FLUX_W_ADJ(:,:,:)
|
|
REAL*8, ALLOCATABLE :: LAYER_AOD_ADJ(:,:,:,:)
|
|
REAL*8, ALLOCATABLE :: LAYER_SSA_ADJ(:,:,:,:)
|
|
REAL*8, ALLOCATABLE :: LAYER_PHM_ADJ(:,:,:,:,:)
|
|
|
|
REAL*8, ALLOCATABLE :: DEBUG_J(:,:)
|
|
|
|
|
|
!================================================================
|
|
! Module variables for LIDORT. These are the arguements of the
|
|
! lidort_inputs_basic_master which we only need to load once per
|
|
! simulation and are independent of the model grid cell.
|
|
!================================================================
|
|
|
|
! All inputs
|
|
! ----------
|
|
|
|
! 1. CONTROL FLAGS
|
|
! ================
|
|
|
|
! Basic top-level control
|
|
! -- Thermal to be reintroduced later 2010
|
|
LOGICAL :: DO_SOLAR_SOURCES
|
|
! LOGICAL :: DO_THERMAL_EMISSION
|
|
|
|
! directional control
|
|
LOGICAL :: DO_UPWELLING
|
|
LOGICAL :: DO_DNWELLING
|
|
|
|
! Flag for Full Radiance calculation
|
|
! If not set, just produce diffuse (Multiple scatter) field
|
|
LOGICAL :: DO_FULLRAD_MODE
|
|
|
|
! stream angle flag. Normally required for post-processing solutions
|
|
! ( Exception : DO_MVOUT_ONLY is set, then only want Flux output)
|
|
LOGICAL :: DO_USER_STREAMS
|
|
|
|
! single scatter corrections. (Includes direct beam reflection)
|
|
! - NADIR : Plane-parallel line-of-sight
|
|
! - OUTGOING : Line-of-sight in curved atmosphere
|
|
LOGICAL :: DO_SSCORR_NADIR ! May be re-set after Checking
|
|
LOGICAL :: DO_SSCORR_OUTGOING ! May be re-set after Checking
|
|
|
|
! Flag for Full-up single scatter calculation. (No MS field)
|
|
! One of the above two SSCORR flags must be set
|
|
LOGICAL :: DO_SSFULL
|
|
|
|
! Flag for performing a complete separate delta-M truncation on the
|
|
! single scatter corrrection calculations. **** Use with CAUTION.
|
|
LOGICAL :: DO_SSCORR_TRUNCATION ! May be re-set after Checking
|
|
|
|
! Beam particular solution, plane parallel flag
|
|
! - Not normally required; pseudo-spherical if not set
|
|
LOGICAL :: DO_PLANE_PARALLEL
|
|
|
|
! Flag for use of BRDF surface
|
|
! - If not set, default to Lambertian surface
|
|
LOGICAL :: DO_BRDF_SURFACE
|
|
|
|
! mean value control (1). If set --> Flux output AS WELL AS Intensities
|
|
LOGICAL :: DO_ADDITIONAL_MVOUT ! May be re-set after Checking
|
|
|
|
! mean value control (2). If set --> only Flux output (No Intensities)
|
|
! - DO_USER_STREAMS should be turned off
|
|
LOGICAL :: DO_MVOUT_ONLY ! May be re-set after Checking
|
|
|
|
! Beam particular solution: Flag for calculating solar beam paths
|
|
! ( Chapman factors = slant/vertical path-length ratios)
|
|
! - This should normally be set.
|
|
LOGICAL :: DO_CHAPMAN_FUNCTION ! May be re-set after Checking
|
|
|
|
! Beam particular solution: Flag for using refraction in solar paths
|
|
! - This should NOT normally be set.
|
|
LOGICAL :: DO_REFRACTIVE_GEOMETRY ! May be re-set after Checking
|
|
|
|
! Flag for Use of Delta-M scaling
|
|
! - Should normally be set
|
|
! - Not required for DO_RAYLEIGH_ONLY or DO_ISOTROPIC_ONLY
|
|
LOGICAL :: DO_DELTAM_SCALING ! May be re-set after Checking
|
|
|
|
! double convergence test flag
|
|
LOGICAL :: DO_DOUBLE_CONVTEST ! May be re-set after Checking
|
|
|
|
! Performance flags
|
|
! -- SOLUTION_SAVING gets rid of unneeded RTE computations
|
|
! -- BVP_TELESCOPING creates reduced Boundary value problems
|
|
! -- These flags should be used with CAUTION
|
|
! -- Best, Rayleigh atmospheres with few contiguous cloud/aerosol layers
|
|
LOGICAL :: DO_SOLUTION_SAVING ! May be re-set after Checking
|
|
LOGICAL :: DO_BVP_TELESCOPING ! May be re-set after Checking
|
|
|
|
! scatterers and phase function control
|
|
! - Rayleigh only, if set, make sure that scattering Law is Rayleigh!
|
|
! - Isotropic only, if set, phase function is 1
|
|
LOGICAL :: DO_RAYLEIGH_ONLY ! May be re-set after Checking
|
|
LOGICAL :: DO_ISOTROPIC_ONLY ! May be re-set after Checking
|
|
|
|
! Debug and testing flags
|
|
! - Normally should not be set
|
|
LOGICAL :: DO_NO_AZIMUTH ! May be re-set after Checking
|
|
LOGICAL :: DO_ALL_FOURIER
|
|
|
|
! Control linearization
|
|
LOGICAL :: DO_PROFILE_LINEARIZATION
|
|
LOGICAL :: DO_SURFACE_LINEARIZATION
|
|
|
|
! 2. CONTROL INTEGERS
|
|
! ===================
|
|
|
|
! Number of discrete ordinate streams
|
|
INTEGER :: NSTREAMS
|
|
|
|
! number of computational layers
|
|
INTEGER :: NLAYERS
|
|
|
|
! Number of fine layers subdividing all computational layers
|
|
! ( Only required for the outgoing single scattering correction )
|
|
INTEGER :: NFINELAYERS
|
|
|
|
! number of Legendre phase function expansion moments
|
|
INTEGER :: NMOMENTS_INPUT ! May be re-set after Checking
|
|
|
|
! number of solar beams to be processed
|
|
INTEGER :: NBEAMS
|
|
|
|
! Number of user-defined relative azimuths
|
|
INTEGER :: N_USER_RELAZMS
|
|
|
|
! Number of User-defined viewing zenith angles (0 to 90 degrees)
|
|
INTEGER :: N_USER_STREAMS
|
|
|
|
! Number of User-defined vertical levels for output
|
|
INTEGER :: N_USER_LEVELS
|
|
|
|
! Linearization control
|
|
! ---------------------
|
|
|
|
! Control for atmospheric linearizations, layer by layer
|
|
LOGICAL :: LAYER_VARY_FLAG (MAXLAYERS)
|
|
INTEGER :: LAYER_VARY_NUMBER(MAXLAYERS)
|
|
|
|
! Total number of Surface Jacobians
|
|
INTEGER :: N_SURFACE_WFS
|
|
|
|
! 3. CONTROL NUMBERS
|
|
! ==================
|
|
|
|
! Flux factor ( should be 1 or pi ). Same for all beams.
|
|
REAL(KIND=8) :: FLUX_FACTOR
|
|
|
|
! accuracy for convergence of Fourier series
|
|
REAL(KIND=8) :: LIDORT_ACCURACY
|
|
|
|
! Zenith tolerance (nearness of output zenith cosine to 1.0 )
|
|
! removed 02 June 2010
|
|
! REAL(KIND=8) :: ZENITH_TOLERANCE
|
|
|
|
! Earth radius (in km) for Chapman function calculation of TAUTHICK_INPUT
|
|
REAL(KIND=8) :: EARTH_RADIUS
|
|
|
|
! Refractive index parameter
|
|
! ( Only required for refractive geometry attenuation of the solar beam)
|
|
REAL(KIND=8) :: RFINDEX_PARAMETER
|
|
|
|
! Surface height [km] at which Input geometry is to be specified.
|
|
! -- Introduced by R. Spurr, RT SOLUTIONS INC., 06 August 2007
|
|
! -- See special note below
|
|
REAL(KIND=8) :: GEOMETRY_SPECHEIGHT
|
|
|
|
! BOA solar zenith angles (degrees)
|
|
REAL(KIND=8) :: BEAM_SZAS ( MAXBEAMS )
|
|
|
|
! user-defined relative azimuths (degrees) (mandatory for Fourier > 0)
|
|
REAL(KIND=8) :: USER_RELAZMS (MAX_USER_RELAZMS)
|
|
|
|
! User-defined viewing zenith angles input (degrees)
|
|
REAL(KIND=8) :: USER_ANGLES_INPUT (MAX_USER_STREAMS)
|
|
|
|
! User-defined vertical levels for output
|
|
! E.g. For 0.1, this means in layer 1, but only 0.1 of way down
|
|
! E.g. For 4.5, this means half way down the 5th layer
|
|
! E.g. For 0.0, this is output at TOA
|
|
REAL(KIND=8) :: USER_LEVELS (MAX_USER_LEVELS)
|
|
|
|
|
|
! Exception handling
|
|
! ------------------
|
|
|
|
! Exception handling for File-read Checking. New code, 18 May 2010
|
|
! Message Length should be at least 120 Characters
|
|
INTEGER :: STATUS_INPUTREAD
|
|
INTEGER :: NREADMESSAGES
|
|
CHARACTER*120 :: READMESSAGES(0:MAX_MESSAGES)
|
|
CHARACTER*120 :: READACTIONS (0:MAX_MESSAGES)
|
|
|
|
|
|
! ============================================================
|
|
! ============================================================
|
|
|
|
! SPECIAL NOTE on variable GEOMETRY_SPECHEIGHT
|
|
|
|
! This is only required when the outgoing sphericity correction is
|
|
! in operation. Otherwise, the regular pseudo-spherical correction
|
|
! (wiht or without an exact single-scatter correction) uses the same
|
|
! set of angles all the up the nadir from the bottom of atmosphere.
|
|
|
|
! This height is normally set equal to the height at the lowest
|
|
! level of the atmosphere: GEOMETRY_SPECHEIGHT = HEIGHT_GRID(NLAYERS)
|
|
! In this case, no adjustment to the geometrical inputs is needed
|
|
! for the outgoing sphericity correction.
|
|
|
|
! If there is a situation GEOMETRY_SPECHEIGHT < HEIGHT_GRID(NLAYERS),
|
|
! then an adjustment to the geometrical inputs is needed for the
|
|
! outgoing sphericity correction. This adjustment is internal and
|
|
! the model output will still be given at the geometrical angles
|
|
! as specified by the user, even though these angles may not be the
|
|
! ones at which the calculations were done. This situation will occur
|
|
! when we are given a BOA geometry but we want to make a calculation
|
|
! for a reflecting surface (such as a cloud-top) which is above the
|
|
! BOA level. In this case, GEOMETRY_SPECHEIGHT = 0.0, and the lowest
|
|
! height HEIGHT_GRID(NLAYERS) = cloud-top.
|
|
|
|
! This height cannot be greater than HEIGHT_GRID(NLAYERS). If this is
|
|
! the case, this height will be set equal to HEIGHT_GRID(NLAYERS), and
|
|
! the calculation will go through without the adjustment. A warning
|
|
! about this incorrect input choice will be sent to LOGFILE.
|
|
|
|
! ============================================================
|
|
! ============================================================
|
|
|
|
!=================================================================
|
|
! MODULE ROUTINES -- follow below the "CONTAINS" statement
|
|
!=================================================================
|
|
CONTAINS
|
|
!------------------------------------------------------------------------------
|
|
|
|
|
|
SUBROUTINE CALC_RF_FORCE( COST_FUNC, N_CALC )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CALC_RF_FORCE caculates contribution to cost function from
|
|
! SW aerosol optical effects.
|
|
!
|
|
! Arguments as Input/Output:
|
|
! ============================================================================
|
|
! (1 ) COST_FUNC (REAL) : Cost funciton
|
|
! (2 ) N_CALC (INTEGER) : Current iteration number
|
|
!
|
|
!
|
|
! NOTES:
|
|
! (1 ) Updated to work with LIDORT 3p5 and GCv8 adjoint (dkh, 07/29/10)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD, NFD
|
|
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
|
|
USE DAO_MOD, ONLY : BXHEIGHT, SUNCOS
|
|
USE ERROR_MOD, ONLY : IT_IS_NAN, ERROR_STOP
|
|
USE GRID_MOD, ONLY : GET_AREA_M2
|
|
USE CHECKPT_MOD, ONLY : RP_OUT, CHK_STT
|
|
USE TIME_MOD, ONLY : GET_TAUe, GET_TAUb, GET_TS_CHEM
|
|
USE TIME_MOD, ONLY : GET_NHMS, GET_NHMSb
|
|
USE TIME_MOD, ONLY : GET_NYMD, GET_NYMDb
|
|
USE TIME_MOD, ONLY : ITS_A_NEW_MONTH
|
|
USE TIME_MOD, ONLY : GET_MONTH
|
|
USE TRACER_MOD, ONLY : STT
|
|
USE TRACERID_MOD, ONLY : IDTSO4, IDTNIT, IDTNH4
|
|
USE TRACERID_MOD, ONLY : IDTBCPI, IDTBCPO
|
|
!fha 6-9-2011 added for debugging output
|
|
USE TRACERID_MOD, ONLY : IDTOCPI, IDTOCPO
|
|
|
|
USE MIE_MOD, ONLY : INIT_MIE_MOD
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN" ! STT
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(INOUT) :: COST_FUNC
|
|
INTEGER,INTENT(IN) :: N_CALC
|
|
|
|
! Local variables
|
|
REAL*8 :: LOCAL_COST(IIPAR,JJPAR,NWL_MAX)
|
|
REAL*8 :: AOD(NWL_MAX)
|
|
REAL*8 :: GLOB_FLUX_INST(IIPAR,JJPAR)
|
|
REAL*8 :: GLOB_FLUX_INST_ADJ(IIPAR,JJPAR)
|
|
INTEGER :: I, J, L, IJLOOP
|
|
INTEGER :: CLOCK_1, CLOCK_2, CLOCK_RATE
|
|
INTEGER :: status_inputread
|
|
LOGICAL, SAVE :: FIRST = .TRUE.
|
|
LOGICAL, SAVE :: NEED_READ_LER = .TRUE.
|
|
!INTEGER, SAVE :: NCOUNT
|
|
INTEGER, SAVE :: NCOUNT = 0
|
|
|
|
integer :: n, nf, na, LEN_STRING
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: EARTHSA = 510705155749195 ! [m2]
|
|
|
|
!=================================================================
|
|
! CALC_RF_FORCE begins here!
|
|
!=================================================================
|
|
|
|
! dkh debug
|
|
!print*, 'ddd loc z ', CHK_STT(IFD,JFD,LFD,NFD)
|
|
!print*, 'ddd loc z check', SUM(CHK_STT(IFD,JFD,:,:))
|
|
! - CHK_STT(IFD,JFD,LFD,NFD)
|
|
|
|
|
|
! This is now handled in CALC_ADJ_FORCE_FOR_SENSE (dkh, 02/15/11)
|
|
!NCOUNT = NCOUNT + 1
|
|
!print*, ' CALC_RF_FORCE: NCOUNT, NSPAN : ', NCOUNT, NSPAN
|
|
!IF ( NCOUNT > NSPAN ) THEN
|
|
! print*, ' NCOUNT > NSPAN '
|
|
! RETURN
|
|
!ENDIF
|
|
! Actually, still need NCOUNT so that we know when to make the
|
|
! aod files (dkh, 03/27/11).
|
|
NCOUNT = NCOUNT + 1
|
|
|
|
|
|
!Initialization
|
|
IF ( FIRST ) THEN
|
|
|
|
! Allocate arrays
|
|
CALL INIT_LIDORT
|
|
|
|
CALL INIT_MIE_MOD
|
|
|
|
CALL lidort_inputs_basic_master
|
|
& ( '3p5T_LIDORT_ReadInput.cfg', ! INPUT
|
|
& DO_SOLAR_SOURCES, ! output
|
|
& DO_UPWELLING, DO_DNWELLING, ! output
|
|
& DO_FULLRAD_MODE, DO_USER_STREAMS, ! output
|
|
& DO_SSCORR_NADIR, DO_SSCORR_OUTGOING, ! output
|
|
& DO_SSFULL, DO_SSCORR_TRUNCATION, ! output
|
|
& DO_PLANE_PARALLEL, DO_BRDF_SURFACE, ! output
|
|
& DO_ADDITIONAL_MVOUT, DO_MVOUT_ONLY, ! output
|
|
& DO_CHAPMAN_FUNCTION, DO_REFRACTIVE_GEOMETRY, ! output
|
|
& DO_DELTAM_SCALING, DO_DOUBLE_CONVTEST, ! output
|
|
& DO_RAYLEIGH_ONLY, DO_ISOTROPIC_ONLY, ! output
|
|
& DO_SOLUTION_SAVING, DO_BVP_TELESCOPING, ! output
|
|
& DO_ALL_FOURIER, DO_NO_AZIMUTH, ! output
|
|
& NSTREAMS, NLAYERS, NFINELAYERS, NMOMENTS_INPUT, ! output
|
|
& NBEAMS, N_USER_STREAMS, N_USER_RELAZMS, N_USER_LEVELS, ! output
|
|
& FLUX_FACTOR, LIDORT_ACCURACY, ! output
|
|
& EARTH_RADIUS, RFINDEX_PARAMETER, GEOMETRY_SPECHEIGHT, ! output
|
|
& BEAM_SZAS, USER_ANGLES_INPUT, USER_RELAZMS, USER_LEVELS, ! output
|
|
& STATUS_INPUTREAD, NREADMESSAGES, READMESSAGES, READACTIONS )
|
|
|
|
! Exception handling
|
|
IF ( status_inputread .ne. lidort_success ) THEN
|
|
open(1,file = '3p5T_LIDORT_ReadInput.log',
|
|
& status = 'unknown')
|
|
WRITE(1,*)
|
|
& ' FATAL: Wrong input from LIDORT input file-read'
|
|
WRITE(1,*)
|
|
& ' ------ Here are the messages and actions '
|
|
write(1,'(A,I3)')
|
|
& ' ** Number of messages = ',NREADMESSAGES
|
|
DO N = 1, NREADMESSAGES
|
|
NF = LEN_STRING(READMESSAGES(N))
|
|
NA = LEN_STRING(READACTIONS(N))
|
|
write(1,'(A,I3,A,A)')
|
|
& 'Message # ',N,' : ',READMESSAGES(N)(1:NF)
|
|
write(1,'(A,I3,A,A)')
|
|
& 'Action # ',N,' : ',READACTIONS(N)(1:NA)
|
|
ENDDO
|
|
close(1)
|
|
STOP
|
|
& 'Read-input fail: Look at file 3p5T_LIDORT_ReadInput.log'
|
|
ENDIF
|
|
|
|
FIRST = .FALSE.
|
|
|
|
ENDIF
|
|
|
|
IF ( NEED_READ_LER ) THEN
|
|
|
|
! Read TEMIS LER (reflectivities)
|
|
CALL READ_LER_FILE( GET_MONTH() )
|
|
|
|
NEED_READ_LER = .FALSE.
|
|
ENDIF
|
|
IF ( ITS_A_NEW_MONTH() ) THEN
|
|
|
|
NEED_READ_LER = .TRUE.
|
|
|
|
ENDIF
|
|
|
|
! ! Clear
|
|
LOCAL_COST = 0d0
|
|
|
|
CALL SYSTEM_CLOCK(COUNT_RATE=CLOCK_RATE)
|
|
CALL SYSTEM_CLOCK(COUNT=CLOCK_1)
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, AOD )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
!DO J = JFD, JFD
|
|
!DO I = IFD, IFD
|
|
|
|
! Calculate aerosol optical depth in current column
|
|
! as well as layer-by-layer optical fields (AOD, SSA, PHM)
|
|
CALL CALC_AOD( I, J, AOD )
|
|
|
|
! Safety
|
|
IF ( IT_IS_NAN( SUM(AOD(:)) ) ) THEN
|
|
WRITE(6,*) ' ERROR: AOD is NAN in ', I, J
|
|
ENDIF
|
|
|
|
! Calculate contribution to cost function. Scale
|
|
! by SCALEF / EARTHSA later.
|
|
LOCAL_COST(I,J,:) = AOD(:) * GET_AREA_M2( J )
|
|
|
|
! Save AOD and contribution to global average AOD
|
|
AOD_SAVE(I,J,:) = AOD_SAVE(I,J,:) + AOD(:) * INV_NSPAN
|
|
AOD_AVE(I,J,:) = AOD_AVE(I,J,:)
|
|
& + LOCAL_COST(I,J,:) * INV_NSPAN
|
|
|
|
! Diagnostic: average sulfate mass scattering efficiency
|
|
MASS_ND(I,J) = MASS_ND(I,J) + INV_NSPAN * (
|
|
& SUM( CHK_STT(I,J,1:LLTROP,IDTSO4) ) )
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
CALL SYSTEM_CLOCK(COUNT=CLOCK_2)
|
|
WRITE(6,*) ' AOD TIME : ', (CLOCK_2 - CLOCK_1)/
|
|
& REAL(CLOCK_RATE)
|
|
|
|
|
|
CALL SYSTEM_CLOCK(COUNT_RATE=CLOCK_RATE)
|
|
CALL SYSTEM_CLOCK(COUNT=CLOCK_1)
|
|
|
|
! Loop over longitude
|
|
DO I = 1, IIPAR
|
|
! DO I = IFD, IFD
|
|
|
|
!Initialize
|
|
GLOB_FLUX_W(:,I,:) = 0D0
|
|
JAC_GLOB_FLUX_W(:,:,:,I,:) = 0D0
|
|
|
|
! Call LIDORT routines to calculate radiative fluxes
|
|
! This routine loops over latitude (in parallel)
|
|
! and wavelength.
|
|
CALL LIDORT_DRIVER( I )
|
|
|
|
ENDDO
|
|
|
|
! Calculate integrated upward radiative flux
|
|
CALL CALC_RADIATIVE_FLUX( GLOB_FLUX_INST )
|
|
|
|
! Calculate integrated upward radiative flux
|
|
CALL CALC_RADIATIVE_FORCE( GLOB_FLUX_INST, COST_FUNC )
|
|
|
|
! dkh debug -- 500 nm diagnostics
|
|
print*, 'SUM flux up = ', SUM(GLOB_FLUX_W(NWL_500,:,:))
|
|
WRITE(6,'(A15,I4,2E14.7)') ('SUM flux up = ', L,
|
|
& SUM(JAC_GLOB_FLUX_W(2,L,NWL_500,:,:)),
|
|
& MAXVAL(JAC_GLOB_FLUX_W(2,L,NWL_500,:,:)), L=1,30)
|
|
|
|
! dkh debug -- 500 nm diagnostics
|
|
IF ( .not. L_PRINT ) THEN
|
|
WRITE(*,'(/a/)')'Integrate fluxes at above levels--->'
|
|
WRITE(*,'(3x,1p4e13.5)')(GLOB_FLUX_W(NWL_500,61,32))
|
|
WRITE(*,'(3x,1p4e13.5)')(GLOB_FLUX_W(NWL_500,IFD,JFD))
|
|
|
|
WRITE(*,'(/a//6x,a)')
|
|
& 'Upwelling Jacobians w.r.t. layer aerosol extinction TAU -->',
|
|
& ' ---------- Analytic Jacobian calculations ------------'
|
|
DO L = 1, LLPAR
|
|
WRITE(*,'(i3,2(1x,1p4e14.5))') L,
|
|
! & JAC_GLOB_FLUX_W(2,L,NWL_500,61,32)
|
|
& JAC_GLOB_FLUX_W(2,L,NWL_500,IFD,JFD)
|
|
ENDDO
|
|
WRITE(*,'(/a//6x,a)')
|
|
& 'Upwelling Jacobians w.r.t. layer aerosol single scattering>',
|
|
& ' ---------- Analytic Jacobian calculations ------------'
|
|
DO L = 1, LLPAR
|
|
WRITE(*,'(i3,2(1x,1p4e14.5))') L,
|
|
!! & JAC_GLOB_FLUX_W(2,L,NWL_500,61,32)
|
|
& JAC_GLOB_FLUX_W(3,L,NWL_500,IFD,JFD)
|
|
ENDDO
|
|
WRITE(*,'(/a//6x,a)')
|
|
& 'Upwelling Jacobians w.r.t. layer aerosol PHM ------------>',
|
|
& ' ---------- Analytic Jacobian calculations ------------'
|
|
DO L = 1, LLPAR
|
|
WRITE(*,'(i3,2(1x,1p4e14.5))') L,
|
|
! & JAC_GLOB_FLUX_W(2,L,NWL_500,61,32)
|
|
& JAC_GLOB_FLUX_W(4,L,NWL_500,IFD,JFD)
|
|
ENDDO
|
|
!---------------------------------------------
|
|
|
|
ENDIF
|
|
|
|
CALL SYSTEM_CLOCK(COUNT=CLOCK_2)
|
|
WRITE(6,*) ' LIDORT TIME : ', (CLOCK_2 - CLOCK_1)/
|
|
& REAL(CLOCK_RATE)
|
|
|
|
|
|
! dkh debug
|
|
print*, MAXLOC(AOD_AVE(:,:,:))
|
|
|
|
! Diagnostic printout, see eqn 4 of Martin et al., 2004 ACP
|
|
print*, 'CURRENT AOD STATS: ', 'AOD_ave, Beta_ave, ',
|
|
& ' M_ave (mg SO4 /m2), SCAL'
|
|
print*, 'CURRENT AOD STATS: ',
|
|
& SUM(AOD_AVE(:,:,NWL_500))/EARTHSA,
|
|
& SUM(AOD_AVE(:,:,NWL_500)) / ( SUM(MASS_ND(:,:)) * 1d03 ),
|
|
& SUM(MASS_ND(:,:)) * 1d06 / EARTHSA
|
|
|
|
print*, ' running BC burden [Tg] = ',
|
|
& (SUM(STT(:,:,:,IDTBCPI)) + SUM(STT(:,:,:,IDTBCPO))) * 1d-9
|
|
|
|
! fha 6-9-2011 added OC total to debug output
|
|
print*, ' running OC burden [Tg] = ',
|
|
& (SUM(STT(:,:,:,IDTOCPI)) + SUM(STT(:,:,:,IDTOCPO))) * 1d-9
|
|
|
|
! dkh debug
|
|
print*, ' MAKE_AOD debug ', GET_NYMD(), GET_NYMDb(), GET_NHMS(),
|
|
& GET_NHMSb()
|
|
|
|
! Write out AOD file on the last time through
|
|
IF ( GET_NYMD() == GET_NYMDb() .and.
|
|
& GET_NHMS() == GET_NHMSb() .or.
|
|
& NCOUNT == NSPAN ) THEN
|
|
CALL MAKE_AOD_FILE( GET_NYMD(), GET_NHMS(), N_CALC )
|
|
ENDIF
|
|
|
|
! fur debugin just forward
|
|
!print*, ' SKIPPING RF ADJOINT CALCULATION *** '
|
|
!print*, ' SKIPPING RF ADJOINT CALCULATION *** '
|
|
!print*, ' SKIPPING RF ADJOINT CALCULATION *** '
|
|
!GOTO 131
|
|
|
|
!---------------------------------------------------------------
|
|
! Adjoint code begins here
|
|
!---------------------------------------------------------------
|
|
|
|
! fwd code:
|
|
!CALL CALC_RADIATIVE_FLUX( GLOB_FLUX_INST )
|
|
!CALL CALC_RADIATIVE_FORCE( GLOB_FLUX_INST, COST_FUNC )
|
|
! adj code:
|
|
! note: here GLOB_FLUX_INST_ADJ is output
|
|
CALL ADJ_CALC_RADIATIVE_FORCE( GLOB_FLUX_INST_ADJ )
|
|
! note: here GLOB_FLUX_INST_ADJ is input
|
|
CALL ADJ_CALC_RADIATIVE_FLUX( GLOB_FLUX_INST_ADJ )
|
|
|
|
121 CONTINUE
|
|
|
|
! dkh debug
|
|
print*, 'ddd loc a ', STT_ADJ(IFD,JFD,LFD,NFD)
|
|
|
|
! adjoint of LIDORT routine
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, IJLOOP )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
!DO J = JFD, JFD
|
|
!DO I = IFD, IFD
|
|
|
|
|
|
! Get 1D array index
|
|
IJLOOP = ( J - 1 ) * IIPAR + I
|
|
|
|
! Only bother to do this if the sun is shining
|
|
! ISCCP definition of sunset/sunrise.
|
|
! Rossow and Duenas, 2004
|
|
! CYCLE statement leads to OpenMP issues (dkh, 03/27/11)
|
|
!IF ( SUNCOS(IJLOOP) < 0.0005d0 ) CYCLE
|
|
IF ( SUNCOS(IJLOOP) >= 0.0005d0 ) THEN
|
|
|
|
! fwd code:
|
|
!CALL LIDORT_DRIVER( I, J )
|
|
! adj code:
|
|
CALL ADJ_LIDORT_DRIVER( I, J )
|
|
|
|
! Reset just to be safe
|
|
! fwd code:
|
|
!!Initialize
|
|
!GLOB_FLUX_W(:,I,J) = 0D0
|
|
!JAC_GLOB_FLUX_W(:,:,:,I,J) = 0D0
|
|
! adj code:
|
|
GLOB_FLUX_W_ADJ(:,I,J) = 0D0
|
|
JAC_GLOB_FLUX_W(:,:,:,I,J) = 0D0
|
|
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! dkh debug
|
|
print*, 'ddd loc b ', STT_ADJ(IFD,JFD,LFD,NFD)
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, IJLOOP )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
!DO J = JFD,JFD
|
|
!DO I = IFD,IFD
|
|
|
|
! Get 1D array index
|
|
IJLOOP = ( J - 1 ) * IIPAR + I
|
|
|
|
! Only bother to do this if the sun is shining
|
|
! ISCCP definition of sunset/sunrise.
|
|
! Rossow and Duenas, 2004
|
|
! CYCLE leads to OpenMP issues (dkh, 03/27/11)
|
|
!IF ( SUNCOS(IJLOOP) < 0.0005d0 ) CYCLE
|
|
IF ( SUNCOS(IJLOOP) >= 0.0005d0 ) THEN
|
|
|
|
! Calculate aerosol optical depth in current column
|
|
CALL ADJ_CALC_AOD( I, J )
|
|
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! dkh debug
|
|
!print*, 'ddd loc c ', STT_ADJ(IFD,JFD,LFD,NFD)
|
|
!print*, 'ddd loc c HACK zero STT_ADJ'
|
|
!print*, 'ddd loc c HACK zero STT_ADJ'
|
|
!print*, 'ddd loc c HACK zero STT_ADJ'
|
|
!STT_ADJ = 0d0
|
|
!STT_ADJ(IFD,JFD,LFD,NFD) = 1d0
|
|
|
|
131 CONTINUE
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CALC_RF_FORCE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CALC_AOD( I, J, AOD )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CALC_AOD calculates the aerosol optical depth in column (AOD)
|
|
! as well as the layer-by-layer value needed for LIDORT input
|
|
! (dkh, 01/21/08, 07/29/10)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) I, J (Integer) : X-Y Grid locations
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) AOD (REAL*8) : Aerosol optical depth [none]
|
|
!
|
|
! Module variables as Output:
|
|
! ============================================================================
|
|
! (1 ) LAYER_AOD (REAL*8) : Aerosol optical thickness of each layer
|
|
! (2 ) LAYER_SSA (REAL*8) : Aerosol single scat albedo of each layer
|
|
! (3 ) LAYER_PHM (REAL*8) : Aerosol phase momemnt of each layer
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE CHECKPT_MOD, ONLY : RP_OUT, CHK_STT
|
|
USE DAO_MOD, ONLY : RH, BXHEIGHT, AIRVOL
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE TRACERID_MOD, ONLY : IDTSO4, IDTNIT, IDTNH4
|
|
USE TRACERID_MOD, ONLY : IDTBCPO, IDTBCPI
|
|
USE TRACERID_MOD, ONLY : IDTOCPO, IDTOCPI
|
|
! ^fha 6-6-2011: added OC
|
|
|
|
|
|
! dkh debug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD
|
|
|
|
# include "CMN_SIZE"
|
|
# include "CMN"
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J
|
|
REAL*8, INTENT(OUT) :: AOD(NWL_MAX)
|
|
|
|
! Local variables
|
|
INTEGER :: L, W
|
|
INTEGER :: NSP
|
|
REAL*8 :: DIAM(NSP_MAX)
|
|
REAL*8 :: WET_DIAM(NSP_MAX)
|
|
REAL*8 :: MASS(NSP_MAX)
|
|
REAL*8 :: NCONC(NSP_MAX)
|
|
REAL*8 :: BEXT, SSA, PHM(NPM_MAX)
|
|
REAL*8 :: RHL
|
|
REAL*8 :: BEXT_TOT
|
|
REAL*8 :: SCAT_TOT
|
|
REAL*8 :: PHM_TOT(NPM_MAX)
|
|
|
|
|
|
|
|
!=================================================================
|
|
! CALC_AOD begins here!
|
|
!=================================================================
|
|
|
|
! note: already in a parallel loop over I,J
|
|
!DO L = 1 , LLTROP
|
|
DO L = 1 , LLPAR
|
|
|
|
! Get local RH
|
|
RHL = MIN(99.D0,RH(I,J,L))
|
|
|
|
|
|
! Loop over aerosol type
|
|
DO NSP = 1, NSP_MAX
|
|
!fha (6/1/11) added OC
|
|
IF ( NSP == NSP_BC ) THEN
|
|
|
|
! Aerosol wet size (um)
|
|
WET_DIAM(NSP) = GET_WET_DIAM( RHL, NSP,
|
|
& DRY_DIAM(NSP)/2d0 )
|
|
|
|
! Aerosol mass [kg/box]
|
|
MASS(NSP) = REAL(CHK_STT(I,J,L,IDTBCPI),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTBCPO),8)
|
|
|
|
! Total effective diam is volume weighted average
|
|
! of wet (BCPI) and dry (BCPO) components. Since
|
|
! BC assumed to have density of 1, then volume ~ mass
|
|
DIAM(NSP) =
|
|
& ( REAL(CHK_STT(I,J,L,IDTBCPI),8) * WET_DIAM(NSP)
|
|
& + REAL(CHK_STT(I,J,L,IDTBCPO),8) * DRY_DIAM(NSP) )
|
|
& / MASS(NSP)
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ddd loc md ', MASS(NSP), DIAM(NSP)
|
|
!ENDIF
|
|
|
|
! Aerosol number concentration.
|
|
NCONC(NSP) = GET_NCONC(
|
|
& MASS(NSP),
|
|
& 0d0,
|
|
!------------------------------------------------------------------
|
|
! BUG FIX: since we don't have mass of water, estimate NCONC based
|
|
! on dry radius (dkh, 01/27/11)
|
|
! & DENSE(NSP), 1.d0, DIAM(NSP),
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
!------------------------------------------------------------------
|
|
& SIGMA(NSP), AIRVOL(I,J,L) )
|
|
|
|
ELSEIF ( NSP == NSP_OC ) THEN
|
|
|
|
! Aerosol wet size (um)
|
|
WET_DIAM(NSP) = GET_WET_DIAM( RHL, NSP,
|
|
& DRY_DIAM(NSP)/2d0 )
|
|
|
|
! Aerosol mass [kg/box]
|
|
MASS(NSP) = REAL(CHK_STT(I,J,L,IDTOCPI),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTOCPO),8)
|
|
|
|
! Total effective diam is volume weighted average
|
|
! of wet (BCPI) and dry (BCPO) components. Since
|
|
! BC assumed to have density of 1, then volume ~ mass
|
|
DIAM(NSP) =
|
|
& ( REAL(CHK_STT(I,J,L,IDTOCPI),8) * WET_DIAM(NSP)
|
|
& + REAL(CHK_STT(I,J,L,IDTOCPO),8) * DRY_DIAM(NSP) )
|
|
& / MASS(NSP)
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ddd loc md ', MASS(NSP), DIAM(NSP)
|
|
!ENDIF
|
|
|
|
! Aerosol number concentration.
|
|
NCONC(NSP) = GET_NCONC(
|
|
& MASS(NSP),
|
|
& 0d0,
|
|
!------------------------------------------------------------------
|
|
! BUG FIX: since we don't have mass of water, estimate NCONC based
|
|
! on dry radius (dkh, 01/27/11)
|
|
! & DENSE(NSP), 1.d0, DIAM(NSP),
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
!------------------------------------------------------------------
|
|
& SIGMA(NSP), AIRVOL(I,J,L) )
|
|
|
|
ELSE
|
|
|
|
! try it this way:
|
|
! specify dry diam
|
|
!DIAM = 0.1
|
|
!DIAM(NSP) = DRY_DIAM(NSP)
|
|
|
|
! Aerosol mass [kg/box]
|
|
MASS(NSP) = REAL(CHK_STT(I,J,L,IDTSO4),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTNIT),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTNH4),8)
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: fwd GET_NCONC sulf ', MASS(NSP),
|
|
! DRY_DIAM(NSP)
|
|
!ENDIF
|
|
|
|
! get NCONC based on dry mass
|
|
NCONC(NSP) = GET_NCONC(
|
|
& MASS(NSP),
|
|
& 0d0,
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
& SIGMA(NSP), AIRVOL(I,J,L) )
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: fwd GET_WETD2 ', MASS(NSP),
|
|
! REAL(RP_OUT(I,J,L,4),8), NCONC(NSP)
|
|
!ENDIF
|
|
|
|
|
|
!! ! get wet diam
|
|
!! DIAM(NSP) = GET_WETD2(
|
|
!! & MASS(NSP),
|
|
!!! & REAL(RP_OUT(I,J,L,4),8),
|
|
!!! HACK: for testing SO4
|
|
!! & 1000d0,
|
|
!! & DENSE(NSP), 1.d0, NCONC(NSP),
|
|
!! & SIGMA(NSP), AIRVOL(I,J,L) )
|
|
|
|
! Aerosol wet size (um)
|
|
DIAM(NSP) = GET_WET_DIAM( RHL, NSP,
|
|
& DRY_DIAM(NSP)/2d0 )
|
|
|
|
! if you feed the above routine zero water, will it
|
|
! give back the dry diam? yes.
|
|
!IF ( L == LFD ) THEN
|
|
! print*, ' DIAM, DRY_DIAM = ', DIAM(NSP), DRY_DIAM(NSP)
|
|
!ENDIF
|
|
|
|
ENDIF
|
|
ENDDO
|
|
|
|
! ! Find total volume (need to convert RP_OUT to kg/box)
|
|
! V_TOT = MASS(NSP_SULF) / DENSE(NSP_SULF)
|
|
! & + MASS(NSP_BC) / DENSE(NSP_BC)
|
|
!! & + REAL(RP_OUT(I,J,L,4),8)
|
|
! & + REAL(RP_OUT(I,J,L,4),8) * 1d-9 * AIRVOL(I,J,L)
|
|
!
|
|
! ! Initialize to zero before summing over species
|
|
! LAYER_AOD(I,J,L,:) = 0d0
|
|
! LAYER_SSA(I,J,L,:) = 0d0
|
|
! LAYER_PHM(I,J,L,:,:) = 0d0
|
|
!
|
|
!! DO NSP = 1, NSP_MAX
|
|
! !DO NSP = 2, 2
|
|
! !DO NSP = 1, 1
|
|
!
|
|
! ! We are going to combine optical properties from different
|
|
! ! aerosoly types according to a volume-weighting factor
|
|
! VW = MASS(NSP) / ( DENSE(NSP) * V_TOT )
|
|
!
|
|
! ! For sulfate, add water contribution
|
|
! IF ( NSP == NSP_SULF ) THEN
|
|
! !VW = VW + REAL(RP_OUT(I,J,L,4),8) / ( 1D0 * V_TOT )
|
|
! VW = VW + REAL(RP_OUT(I,J,L,4),8) * 1d-9
|
|
! & * AIRVOL(I,J,L) / ( 1D0 * V_TOT )
|
|
! ENDIF
|
|
!
|
|
! ! fur debugin
|
|
! VW = 1d0
|
|
!
|
|
!
|
|
! ! dkh debug
|
|
! IF ( I == 1 .and. J == 1 ) THEN
|
|
! print*, ' I, J, L, NSP, NCONC, DIAM, MASS, DENSE, VW,
|
|
! & RH, dz ',
|
|
! & I, J, L, NSP, NCONC(NSP), DIAM(NSP), MASS(NSP),
|
|
! & DENSE(NSP), VW,
|
|
! & RHL,
|
|
! & BXHEIGHT(I,J,L)
|
|
! ENDIF
|
|
|
|
!IF ( L == LFD ) THEN
|
|
! print*, ' HACK ddd loc nd NCONC =', NCONC
|
|
! print*, ' HACK ddd loc nd DIAM = ', DIAM
|
|
! DEBUG_J(I,J) = NCONC(2)
|
|
!ENDIF
|
|
|
|
! Loop over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
BEXT_TOT = 0d0
|
|
SCAT_TOT = 0D0
|
|
PHM_TOT(:) = 0D0
|
|
|
|
DO NSP = 1, NSP_MAX
|
|
|
|
! Lookup aerosol optical properties
|
|
CALL MIE_LOOKUP( NCONC(NSP), DIAM(NSP), W, NSP,
|
|
& BEXT, SSA, PHM, I,J,L )
|
|
|
|
!print*, ' mie done ', I, J, L, NSP, W
|
|
|
|
!IF ( L == LFD .and. W == 3 .and. NSP == 2 ) THEN
|
|
! print*, 'HACK ddd loc bps BEXT = ', BEXT
|
|
! print*, 'HACK ddd loc bps SSA = ', SSA
|
|
! print*, 'HACK ddd loc bps PHM = ', PHM
|
|
! DEBUG_J(I,J) = BEXT
|
|
!ENDIF
|
|
|
|
BEXT_TOT = BEXT_TOT + BEXT
|
|
SCAT_TOT = SCAT_TOT + BEXT * SSA
|
|
PHM_TOT(:) = PHM_TOT(:) + PHM(:) * BEXT * SSA
|
|
|
|
|
|
ENDDO
|
|
|
|
IF ( BEXT_TOT < SMALL .or.
|
|
& SCAT_TOT < SMALL ) THEN
|
|
CALL ERROR_STOP(' Trouble calculating combined opt prop',
|
|
& ' aero_optical_mod.f' )
|
|
ENDIF
|
|
|
|
|
|
! Calculate AOD for this layer. BXHEIGHT is [m] while
|
|
! BEXT is in [1/m]
|
|
LAYER_AOD(I,J,L,W) = BXHEIGHT(I,J,L) * BEXT_TOT
|
|
|
|
! Layer single scatering albedo
|
|
LAYER_SSA(I,J,L,W) = SCAT_TOT / BEXT_TOT !/ NCONC_TOT
|
|
|
|
! Layer phase moments
|
|
LAYER_PHM(I,J,L,:,W) = PHM_TOT(:) / SCAT_TOT
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD .and. L == LFD
|
|
! .and. W == 3 ) THEN
|
|
! print*, 'ddd loc w ', LAYER_AOD(I,J,L,W)
|
|
! print*, 'ddd loc s ', LAYER_SSA(I,J,L,W)
|
|
!
|
|
!ENDIF
|
|
|
|
|
|
ENDDO ! LAMBDA
|
|
|
|
ENDDO ! L
|
|
|
|
|
|
! Total AOD over all vertical levels
|
|
DO W = 1, NWL_MAX
|
|
AOD(W) = SUM( LAYER_AOD(I,J,:,W) )
|
|
ENDDO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CALC_AOD
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_WET_DIAM( RH , NSP, DRY_RADIUS ) RESULT( DIAM )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GET_WET_DIAM calculates mean wet radius of aerosol.
|
|
! Currently based on jv_spec.dat
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) RH (REAL*8) : Relative humidity [%]
|
|
! (2 ) NSP (INTEGER) : Species index
|
|
! (3 ) DRY_RADIUS (REAL*8) : Dry mode radius [um]
|
|
!
|
|
! Output:
|
|
! ============================================================================
|
|
! (1 ) DIAM (REAL*8) : Diameter [um]
|
|
!
|
|
! NOTES:
|
|
! (1 ) Updated growth factors to GCv8-03-1 (dkh, 09/27/10)
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: RH
|
|
INTEGER,INTENT(IN) :: NSP
|
|
REAL*8, INTENT(IN) :: DRY_RADIUS
|
|
|
|
! Value
|
|
REAL*8 :: DIAM
|
|
|
|
! Local variables
|
|
REAL*8 :: RADIUS
|
|
REAL*8 :: GF
|
|
|
|
!=================================================================
|
|
! GET_WET_DIAM begins here!
|
|
!=================================================================
|
|
|
|
SELECT CASE( NSP )
|
|
|
|
! Sulfate
|
|
CASE( 1 )
|
|
|
|
! GF's udated to GCv8-03-01 (dkh, 09/27/10)
|
|
IF ( RH <= 50.d0 ) THEN
|
|
|
|
! GF = 1.d0 + ( 1.36 - 1.0 ) / ( 50 - 0 ) * ( RH - 0 )
|
|
GF = 1.d0 + 0.0073d0 * RH
|
|
|
|
ELSEIF ( RH <= 70.d0 ) THEN
|
|
|
|
! GF = 1.36 + ( 1.52 - 1.36 ) / ( 70 - 50 ) * ( RH - 50 )
|
|
GF = 0.99d0 + 0.0075d0 * RH
|
|
|
|
ELSEIF ( RH <= 80.d0 ) THEN
|
|
|
|
! GF = 1.52 + ( 1.64 - 1.52 ) / ( 80 - 70 ) * ( RH - 70 )
|
|
GF = 0.68d0 + 0.012d0 * RH
|
|
|
|
ELSEIF ( RH <= 90.d0 ) THEN
|
|
|
|
! GF = 1.64 + ( 1.87 - 1.64 ) / ( 90 - 80 ) * ( RH - 80 )
|
|
GF = -0.23d0 + 0.023d0 * RH
|
|
|
|
ELSEIF ( RH <= 95.d0 ) THEN
|
|
|
|
! GF = 1.87 + ( 2.18 - 1.87 ) / ( 95 - 90 ) * ( RH - 90 )
|
|
GF = -3.8d0 + 0.063d0 * RH
|
|
|
|
ELSEIF ( RH <= 100.d0 ) THEN
|
|
|
|
! GF = 2.18 + ( 3.13 - 2.18 ) / ( 99 - 95 ) * ( RH - 95 )
|
|
GF = -20d0 + 0.24d0 * RH
|
|
|
|
ENDIF
|
|
|
|
! BC
|
|
CASE( 2 )
|
|
|
|
! GF's udated to GCv8-03-01 (dkh, 09/27/10)
|
|
IF ( RH < 70.d0 ) THEN
|
|
|
|
GF = 1.d0
|
|
|
|
ELSEIF ( RH <= 80.d0 ) THEN
|
|
|
|
! GF = 1.d0 + ( 1.2 - 1.0 ) / ( 80 - 70 ) * ( RH - 70 )
|
|
GF = -0.4d0 + 0.02d0 * RH
|
|
|
|
ELSEIF ( RH <= 90.d0 ) THEN
|
|
|
|
! GF = 1.2d0 + ( 1.4 - 1.2 ) / ( 90 - 80 ) * ( RH - 80 )
|
|
GF = -0.4d0 + 0.02d0 * RH
|
|
|
|
ELSEIF ( RH <= 95.d0 ) THEN
|
|
|
|
! GF = 1.4d0 + ( 1.5 - 1.4 ) / ( 95 - 90 ) * ( RH - 90 )
|
|
GF = -0.14d0 + 0.017d0 * RH
|
|
|
|
ELSEIF ( RH <= 100.d0 ) THEN
|
|
|
|
! GF = 1.5d0 + ( 1.9 - 1.5 ) / ( 99 - 95 ) * ( RH - 95 )
|
|
GF = -8.0D0 + 0.1d0 * RH
|
|
|
|
ENDIF
|
|
|
|
! OC
|
|
CASE( 3 )
|
|
|
|
! added OC GF's from GCv8-03-01 (fha, 6-1-11)
|
|
! RH r-eff r-eff v r-eff @ RH==0 (GF)
|
|
! 00 .07 1
|
|
! 50 .087 1.24
|
|
! 70 .095 1.36
|
|
! 80 .102 1.46
|
|
! 90 .116 1.66
|
|
! 95 .133 1.9
|
|
! 99 .177 2.53
|
|
IF ( RH <= 50.d0 ) THEN
|
|
|
|
! GF = 1.d0 + ( 1.24 - 1.0 ) / ( 50 - 0 ) * ( RH - 0 )
|
|
GF = 1.d0 + 0.0049d0 * RH
|
|
|
|
ELSEIF ( RH <= 70.d0 ) THEN
|
|
|
|
! GF = 1.24d0 + ( 1.36 - 1.24 ) / ( 70 - 50 ) * ( RH - 0 )
|
|
GF = 0.9571d0 + 0.0057d0 * RH
|
|
|
|
ELSEIF ( RH <= 80.d0 ) THEN
|
|
|
|
! GF = 1.36d0 + ( 1.46 - 1.36 ) / ( 80 - 70 ) * ( RH - 70 )
|
|
GF = 0.6571d0 + 0.01d0 * RH
|
|
|
|
ELSEIF ( RH <= 90.d0 ) THEN
|
|
|
|
! GF = 1.46d0 + ( 1.66 - 1.46 ) / ( 90 - 80 ) * ( RH - 80 )
|
|
GF = -0.1429d0 + 0.02d0 * RH
|
|
|
|
ELSEIF ( RH <= 95.d0 ) THEN
|
|
|
|
! GF = 1.66d0 + ( 1.9 - 1.66 ) / ( 95 - 90 ) * ( RH - 90 )
|
|
GF = -2.714d0 + 0.04857d0 * RH
|
|
|
|
ELSEIF ( RH <= 100.d0 ) THEN
|
|
|
|
! GF = 1.9d0 + ( 2.53 - 1.9 ) / ( 99 - 95 ) * ( RH - 95 )
|
|
GF = -13.029D0 + 0.1571d0 * RH
|
|
|
|
ENDIF
|
|
|
|
CASE DEFAULT
|
|
|
|
CALL ERROR_STOP( 'bad NSP in GET_WET_DIAM',
|
|
& 'aero_optical_mod.f')
|
|
|
|
END SELECT
|
|
|
|
RADIUS = DRY_RADIUS * GF
|
|
|
|
DIAM = 2D0 * RADIUS
|
|
|
|
! dkh debug
|
|
!print*, 'RH, DIAM ', RH, DIAM
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_WET_DIAM
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
FUNCTION GET_NCONC( MASS_DRY_kg, MASS_WET, DENSE_DRY, DENSE_WET,
|
|
& D, SIGMA, BVOL )
|
|
& RESULT( NCONC )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GET_NCONC calculates the number concentration [#/cm3] that
|
|
! corresponds to the lognormally distributed (D,SIGMA) aerosol mass.
|
|
! (dkh, 01/21/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) MASS_DRY_kg (REAL*8) : Aerosol dry mass concentration [kg/box]
|
|
! (2 ) MASS_WET (REAL*8) : Aerosol water concentration [ug/m3]
|
|
! (3 ) DENSE_DRY (REAL*8) : Dry aerosol density [g/cm3]
|
|
! (4 ) DENSE_WET (REAL*8) : Wet aerosol density [g/cm3]
|
|
! (5 ) D (REAL*8) : Assumed aerosol median diameter [um]
|
|
! (6 ) SIGMA (REAL*8) : Assumed aerosol standard deviation [um]
|
|
! (7 ) BVOL (REAL*8) : Box volume [m3]
|
|
!
|
|
! Output:
|
|
! ============================================================================
|
|
! (1 ) NCONC (REAL*8) : Aerosol number concentration [#/cm3]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: MASS_WET
|
|
REAL*8, INTENT(IN) :: MASS_DRY_kg
|
|
REAL*8, INTENT(IN) :: DENSE_DRY
|
|
REAL*8, INTENT(IN) :: DENSE_WET
|
|
REAL*8, INTENT(IN) :: D
|
|
REAL*8, INTENT(IN) :: SIGMA
|
|
REAL*8, INTENT(IN) :: BVOL
|
|
|
|
! Fuction value
|
|
REAL*8 :: NCONC
|
|
|
|
! Local variables
|
|
REAL*8 :: DVM
|
|
REAL*8 :: DENSITY
|
|
REAL*8 :: VOLUME
|
|
REAL*8 :: MASS_TOTAL
|
|
REAL*8 :: MASS_DRY
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: PI = 3.14159265358979324D0
|
|
|
|
!=================================================================
|
|
! GET_NCONC begins here!
|
|
!=================================================================
|
|
|
|
! Convert mass units ( [kg/box] --> [ug/m3] )
|
|
MASS_DRY = MASS_DRY_kg * 1d9 / BVOL
|
|
|
|
! Get total mass
|
|
MASS_TOTAL = MASS_DRY + MASS_WET
|
|
|
|
IF ( MASS_TOTAL < 1d-20 ) THEN
|
|
print*, 'housten, we have a problem'
|
|
NCONC = 0d0 ! <-- this will cause LIDORT to give NANs
|
|
CALL ERROR_STOP( 'Aersol mass too small: 1',
|
|
& 'aero_optical_mod.f')
|
|
ENDIF
|
|
|
|
! Average density
|
|
! Also convert [g/cm3] --> [ug/cm3]
|
|
DENSITY = ( DENSE_DRY * MASS_DRY + DENSE_WET * MASS_WET )
|
|
& / ( MASS_TOTAL ) * 1d6
|
|
|
|
! Total volume [cm3/m3 air]
|
|
VOLUME = MASS_TOTAL / DENSITY
|
|
|
|
! Volume mean diameter can be calculated from the log-normal
|
|
! median diameter and the geometric standard deviation,
|
|
! see exercise 7.7 of S&P, 1998.
|
|
! Also convert units [um] --> [cm]
|
|
DVM = D * EXP( 1.5d0 * ( LOG( SIGMA ) )**2 ) * 1D-04
|
|
|
|
! The total number concentration can be calculated from
|
|
! the total volume and the volume mean volume diameter,
|
|
! see table 7.2 of S&P, 1998.
|
|
! Also convert units [#/m3 air] --> [#/cm3 air]
|
|
NCONC = 6d0 * VOLUME / ( PI * DVM ** 3 ) * 1d-06
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_NCONC
|
|
|
|
!------------------------------------------------------------------------------
|
|
FUNCTION GET_WETD2( MASS_DRY_kg, MASS_WET, DENSE_DRY, DENSE_WET,
|
|
& NCONC, SIGMA, BVOL )
|
|
& RESULT( D )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine GET_WETD2 calculates the log-normal median diameter [um] that
|
|
! corresponds to the lognormally distributed (D,SIGMA) wet aerosol mass
|
|
! with the number concentration calculated from the calculated dry particle
|
|
! mass and assumed size.
|
|
! (dkh, 02/22/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) MASS_DRY_kg (REAL*8) : Aerosol dry mass concentration [kg/box]
|
|
! (2 ) MASS_WET (REAL*8) : Aerosol water concentration [ug/m3]
|
|
! (3 ) DENSE_DRY (REAL*8) : Dry aerosol density [g/cm3]
|
|
! (4 ) DENSE_WET (REAL*8) : Wet aerosol density [g/cm3]
|
|
! (5 ) NCONC (REAL*8) : Number concentration [#/cm3]
|
|
! (6 ) SIGMA (REAL*8) : Assumed aerosol standard deviation [um]
|
|
! (7 ) BVOL (REAL*8) : Box volume [m3]
|
|
!
|
|
! Output:
|
|
! ============================================================================
|
|
! (1 ) D (REAL*8) : Aerosol log-normal median diameter [um]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: MASS_WET
|
|
REAL*8, INTENT(IN) :: MASS_DRY_kg
|
|
REAL*8, INTENT(IN) :: DENSE_DRY
|
|
REAL*8, INTENT(IN) :: DENSE_WET
|
|
REAL*8, INTENT(IN) :: NCONC
|
|
REAL*8, INTENT(IN) :: SIGMA
|
|
REAL*8, INTENT(IN) :: BVOL
|
|
|
|
! Fuction value
|
|
REAL*8 :: D
|
|
|
|
! Local variables
|
|
REAL*8 :: DVM
|
|
REAL*8 :: DENSITY
|
|
REAL*8 :: VOLUME
|
|
REAL*8 :: MASS_TOTAL
|
|
REAL*8 :: MASS_DRY
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: PI = 3.14159265358979324D0
|
|
|
|
!=================================================================
|
|
! GET_WETD2 begins here!
|
|
!=================================================================
|
|
|
|
! Convert mass units ( [kg/box] --> [ug/m3] )
|
|
MASS_DRY = MASS_DRY_kg * 1d9 / BVOL
|
|
|
|
! Get total mass
|
|
MASS_TOTAL = MASS_DRY + MASS_WET
|
|
|
|
IF ( MASS_TOTAL < 1d-20 ) THEN
|
|
print*, 'housten, we have a problem'
|
|
!NCONC = 0d0 ! <-- this will cause LIDORT to give NANs
|
|
CALL ERROR_STOP( 'Aersol mass too small: 2',
|
|
& 'aero_optical_mod.f')
|
|
ENDIF
|
|
|
|
! Average density
|
|
! Also convert [g/cm3] --> [ug/cm3]
|
|
DENSITY = ( DENSE_DRY * MASS_DRY + DENSE_WET * MASS_WET )
|
|
& / ( MASS_TOTAL ) * 1d6
|
|
|
|
! Total volume [cm3/m3 air]
|
|
VOLUME = MASS_TOTAL / DENSITY
|
|
|
|
! The total number concentration can be calculated from
|
|
! the total volume and the volume mean volume diameter,
|
|
! see table 7.2 of S&P, 1998.
|
|
! Also convert units [#/m3 air] --> [#/cm3 air]
|
|
DVM = ( 6d0 * VOLUME / ( PI * NCONC ) * 1d-06 ) ** (1.0/3.0)
|
|
|
|
! Volume mean diameter can be calculated from the log-normal
|
|
! median diameter and the geometric standard deviation,
|
|
! see exercise 7.7 of S&P, 1998.
|
|
! Also convert units [um] --> [cm]
|
|
D = DVM * 1d04 / ( EXP( 1.5d0 * ( LOG( SIGMA ) )**2 ) )
|
|
|
|
|
|
! Return to calling program
|
|
END FUNCTION GET_WETD2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE MIE_LOOKUP( NCONC, DIAM, W, NSP, BEXT, SSA, PHM,I,J,L )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine MIE_LOOKUP
|
|
!
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) ARG (TYPE) : Description [unit]
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) ARG (TYPE) : Description [unit]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE MIE_MOD, ONLY : MIE_TABLE
|
|
USE MIE_MOD, ONLY : MIE_TABLE_PHM
|
|
|
|
! dkh dbug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD
|
|
|
|
!# include "foo"
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: NCONC
|
|
REAL*8, INTENT(IN) :: DIAM
|
|
INTEGER, INTENT(IN) :: W
|
|
INTEGER, INTENT(IN) :: NSP
|
|
REAL*8, INTENT(OUT) :: BEXT
|
|
REAL*8, INTENT(OUT) :: SSA
|
|
REAL*8, INTENT(OUT) :: PHM(NPM_MAX)
|
|
|
|
INTEGER, INTENT(IN) :: L, I, J
|
|
! Local variables
|
|
REAL*8 :: N, BEXTT, RAD
|
|
LOGICAL :: FAIL
|
|
CHARACTER*90 :: MESSAGES(4)
|
|
REAL*8 :: PHM2(0:NPM_MAX)
|
|
REAL*8 :: BEXT0
|
|
REAL*8 :: SSA0
|
|
|
|
|
|
! Parameters
|
|
! BUG FIX: need to calculated this separately for BC and SULF,
|
|
! as they have different size ranges and spacing in the lookup
|
|
! table. (dkh, 09/27/10)
|
|
!REAL*8, PARAMETER :: RNG = LOG(RMAX/RMIN) / REAL(NRA_MAX)
|
|
REAL*8 :: RNG
|
|
|
|
!=================================================================
|
|
! MIE_LOOKUP begins here!
|
|
!=================================================================
|
|
|
|
! BUG FIX: need to calculated this separately for BC and SULF,
|
|
! as they have different size ranges and spacing in the lookup
|
|
! table. (dkh, 09/27/10)
|
|
RNG = LOG(RMAX(NSP)/RMIN(NSP)) / ( REAL(NRA_MAX) - 1d0 )
|
|
|
|
RAD = DIAM / 2D0
|
|
|
|
! Get index in MIE_TABLE that corresponds to current diameter.
|
|
! Diameters are calculated at NRA_MAX - 1 points between Dmin and
|
|
! Dmax with a spacing defined in ln space:
|
|
! d_n = d_min * exp( ( n - 1 ) * ln(d_max/d_min) / npts )
|
|
! The inverse of this formulat gives us the n for any d_n.
|
|
N = LOG(RAD/RMIN(NSP)) / RNG + 1
|
|
|
|
! Enforce bounds on this index
|
|
IF ( N < 1.0 ) N = 1.d0
|
|
IF ( N > REAL(NRA_MAX) ) N = REAL(NRA_MAX)
|
|
|
|
BEXTT = MIE_TABLE(W,NSP,NOP_BEXT,INT(N))
|
|
|
|
! Table values calculated for N = 1 [#/cm3], so scale up to current
|
|
! number concentraiton and convert units to 1/m
|
|
BEXT0 = BEXTT * NCONC * 1d-6
|
|
|
|
IF ( NSP == NSP_SULF ) THEN
|
|
SSA0 = 1d0 ! for sulfate
|
|
ELSE
|
|
SSA0 = MIE_TABLE(W,NSP,NOP_SSA,INT(N))
|
|
ENDIF
|
|
|
|
|
|
! Get phase moment from table
|
|
PHM(1:NPM_MAX) = MIE_TABLE_PHM(W,NSP,INT(N),:)
|
|
|
|
! enhance absorption owing to mixing by factor of
|
|
! ABS_FAC = 1.5 (dkh, 02/01/11)
|
|
IF ( NSP == NSP_BC ) THEN
|
|
BEXT = BEXT0 * ( SSA0 + ABS_FAC * ( 1d0 - SSA0 ) )
|
|
SSA = SSA0 / ( SSA0 + ABS_FAC * ( 1d0 - SSA0 ) )
|
|
ELSE
|
|
BEXT = BEXT0
|
|
SSA = SSA0
|
|
ENDIF
|
|
|
|
|
|
! Now we calculate these online (dkh, 07/29/10) .
|
|
! BUT it is too slow. so go back to lookup table.
|
|
! ! Call MIE code
|
|
! CALL GC_FORWARD_MIE
|
|
! & ( NPM_MAX, NCONC, DIAM, SIGMA(NSP), REFRAC_INDEX(NSP,W,:), ! input
|
|
! & LAMBDA_TABLE(W) * 1d-03, ! input
|
|
! & BEXT, SSA, PHM2, FAIL, MESSAGES ) ! Output
|
|
!
|
|
!
|
|
! ! GC_FORWARD_MIE uses the zero element of PHM; just keep 1:NPM_MAX.
|
|
! PHM(1:NPM_MAX) = PHM2(1:NPM_MAX)
|
|
!
|
|
! ! error checking
|
|
! IF ( FAIL ) THEN
|
|
! WRITE(*,*) MESSAGES(1)
|
|
! WRITE(*,*) MESSAGES(2)
|
|
! WRITE(*,*) MESSAGES(3)
|
|
! WRITE(*,*) MESSAGES(4)
|
|
! ENDIF
|
|
|
|
! ! debug: write results
|
|
! print*, ' !--- MIE DBG ---! '
|
|
! print*, ' NSP, W ', NSP, W
|
|
! print*, ' NCONC, DIAM ', NCONC, DIAM
|
|
! print*, ' RTS: BEXT ', BEXT , BEXT2
|
|
! print*, ' RTS: SSA ', SSA, SSA2
|
|
! DO L = 1, NPM_MAX
|
|
! print*, 'RTS PHM ', PHM(L), PHM2(L)
|
|
! ENDDO
|
|
|
|
! dkh debug
|
|
!IF ( W == 3 .and. L == LFD .and.
|
|
! I == IFD .and. J == JFD .and. NSP == 2 ) THEN
|
|
! print*, ' fwd: BEXTT = ', BEXTT
|
|
! print*, ' fwd: BEXT0 = ', BEXT0
|
|
! print*, ' fwd: NCONC = ', NCONC
|
|
! print*, ' fwd: SSA0 = ', SSA0
|
|
! print*, ' fwd: N = ', N, INT(N)
|
|
!ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE MIE_LOOKUP
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE LIDORT_DRIVER( I )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine LIDORT_DRIVER was a modified version of the jactest_3p3_solar2
|
|
! testing routine. Now it is based on 3p5T_lps_tester.f90. (dkh, 05/18/10)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) I (INTEGER) : Lon index [none]
|
|
! (2 ) J (INTEGER) : Lat index [none]
|
|
!
|
|
! Module variables as Output:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX_W (REAL*8) : Upward reflectance [%]
|
|
! (2 ) JAC_GLOB_FLUX_W (REAL*8) : Sensitivity of upward reflectance []
|
|
!
|
|
! NOTES:
|
|
! (1 ) This is based upon the jactest_3p3_solar2.f driver provided with
|
|
! LIDORT by R. Spurr. Original code is lower case.
|
|
! (2 ) Update for GCv8. Based on 3p5T_lps_tester.f90 (dkh, 05/18/10)
|
|
! (3 ) Additional updates and parallelization (dkh, 07/29/10)
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ADJ_ARRAYS_MOD, ONLY : JFD
|
|
USE DAO_MOD, ONLY : SUNCOS
|
|
|
|
! Include files
|
|
# include 'CMN_SIZE'
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I
|
|
|
|
!---------------------------------------------------------------
|
|
! LIDORT variables that need to be defined locally because
|
|
! they will depend on location
|
|
!---------------------------------------------------------------
|
|
|
|
|
|
! BOA solar zenith angles (degrees)
|
|
REAL(KIND=8) :: BEAM_SZAS ( MAXBEAMS )
|
|
|
|
! Exception handling
|
|
! ------------------
|
|
|
|
! Exception handling for LIDORT Input Checking. New code, 18 May 2010
|
|
! Message Length should be at least 120 Characters
|
|
|
|
INTEGER :: STATUS_INPUTCHECK
|
|
INTEGER :: NCHECKMESSAGES
|
|
CHARACTER*120 :: CHECKMESSAGES(0:MAX_MESSAGES)
|
|
CHARACTER*120 :: CHECKACTIONS (0:MAX_MESSAGES)
|
|
|
|
! Exception handling for LIDORT Model Calculation. New code, 18 May 2010
|
|
INTEGER :: STATUS_CALCULATION
|
|
CHARACTER*120 :: MESSAGE, TRACE_1, TRACE_2, TRACE_3
|
|
|
|
! 4. ATMOSPHERIC INPUTS
|
|
! =====================
|
|
|
|
! PTH inputs
|
|
! ----------
|
|
|
|
! multilayer Height inputs
|
|
! (only required for the Chapman function calculations)
|
|
REAL(KIND=8) :: HEIGHT_GRID ( 0:MAXLAYERS )
|
|
|
|
! multilayer atmospheric inputs (P andT)
|
|
! (only required for the Chapman function calculations, refractive geometry)
|
|
REAL(KIND=8) :: PRESSURE_GRID ( 0:MAXLAYERS )
|
|
REAL(KIND=8) :: TEMPERATURE_GRID ( 0:MAXLAYERS )
|
|
REAL(KIND=8) :: AIRDENS ( 1:MAXLAYERS )
|
|
REAL(KIND=8) :: GAS_PROFILE ( 1:MAXLAYERS )
|
|
|
|
! Number of fine layer gradations
|
|
! (only for Chapman function calculations with refractive geometry)
|
|
INTEGER :: FINEGRID ( MAXLAYERS )
|
|
|
|
! optical property inputs
|
|
! -----------------------
|
|
|
|
! multilayer optical property (bulk) inputs
|
|
REAL(KIND=8) :: OMEGA_TOTAL_INPUT ( MAXLAYERS, MAXTHREADS )
|
|
REAL(KIND=8) :: DELTAU_VERT_INPUT ( MAXLAYERS, MAXTHREADS )
|
|
|
|
! Phase function Legendre-polynomial expansion coefficients
|
|
! Include all that you require for exact single scatter calculations
|
|
REAL(KIND=8) :: PHASMOMS_TOTAL_INPUT
|
|
& ( 0:MAXMOMENTS_INPUT, MAXLAYERS, MAXTHREADS )
|
|
|
|
! Optical property linearizations
|
|
! Layer linearization (bulk property variation) input
|
|
! Layer linearization (phase function variation) input
|
|
REAL(KIND=8)
|
|
& :: L_OMEGA_TOTAL_INPUT(MAX_ATMOSWFS,MAXLAYERS,MAXTHREADS)
|
|
REAL(KIND=8)
|
|
& :: L_DELTAU_VERT_INPUT(MAX_ATMOSWFS,MAXLAYERS,MAXTHREADS)
|
|
REAL(KIND=8)
|
|
& :: L_PHASMOMS_TOTAL_INPUT ( MAX_ATMOSWFS,0:MAXMOMENTS_INPUT,
|
|
& MAXLAYERS,MAXTHREADS)
|
|
|
|
! 5. Surface inputs (New BRDF arrays, 23 March 2010)
|
|
! ==================================================
|
|
|
|
! Lambertian Surface control
|
|
REAL(KIND=8) :: LAMBERTIAN_ALBEDO (MAXTHREADS)
|
|
|
|
! Exact (direct bounce) BRDF (same all threads)
|
|
REAL(KIND=8)
|
|
& :: EXACTDB_BRDFUNC ( MAX_USER_STREAMS, MAX_USER_RELAZMS,
|
|
& MAXBEAMS )
|
|
|
|
! Linearized Exact (direct bounce) BRDF (same all threads)
|
|
REAL(KIND=8) :: LS_EXACTDB_BRDFUNC
|
|
& ( MAX_SURFACEWFS, MAX_USER_STREAMS, MAX_USER_RELAZMS,
|
|
& MAXBEAMS )
|
|
|
|
! Fourier components of BRDF, in the following order (same all threads)
|
|
|
|
! incident solar directions, reflected quadrature streams
|
|
! incident quadrature streams, reflected quadrature streams
|
|
! incident solar directions, reflected user streams
|
|
! incident quadrature streams, reflected user streams
|
|
REAL(KIND=8) :: BRDF_F_0 ( 0:MAXMOMENTS, MAXSTREAMS,
|
|
& MAXBEAMS )
|
|
REAL(KIND=8) :: BRDF_F ( 0:MAXMOMENTS, MAXSTREAMS,
|
|
& MAXSTREAMS )
|
|
REAL(KIND=8) :: USER_BRDF_F_0 ( 0:MAXMOMENTS, MAX_USER_STREAMS,
|
|
& MAXBEAMS )
|
|
REAL(KIND=8) :: USER_BRDF_F ( 0:MAXMOMENTS, MAX_USER_STREAMS,
|
|
& MAXSTREAMS )
|
|
|
|
! Linearized Fourier components of BRDF, in the following order (same all threads)
|
|
|
|
! incident solar directions, reflected quadrature streams
|
|
! incident quadrature streams, reflected quadrature streams
|
|
! incident solar directions, reflected user streams
|
|
! incident quadrature streams, reflected user streams
|
|
REAL(KIND=8) :: LS_BRDF_F_0 ( MAX_SURFACEWFS,
|
|
& 0:MAXMOMENTS, MAXSTREAMS, MAXBEAMS )
|
|
REAL(KIND=8) :: LS_BRDF_F ( MAX_SURFACEWFS,
|
|
& 0:MAXMOMENTS, MAXSTREAMS, MAXSTREAMS )
|
|
REAL(KIND=8) :: LS_USER_BRDF_F_0 ( MAX_SURFACEWFS,
|
|
& 0:MAXMOMENTS, MAX_USER_STREAMS, MAXBEAMS )
|
|
REAL(KIND=8) :: LS_USER_BRDF_F ( MAX_SURFACEWFS,
|
|
& 0:MAXMOMENTS, MAX_USER_STREAMS, MAXSTREAMS )
|
|
|
|
! Subroutine output arguments (Intent(out))
|
|
! +++++++++++++++++++++++++++++++++++++++++
|
|
|
|
! Main results
|
|
! ------------
|
|
|
|
! Intensity Results at all angles and optical depths
|
|
REAL(KIND=8) :: INTENSITY
|
|
& ( MAX_USER_LEVELS, MAX_GEOMETRIES, MAX_DIRECTIONS,
|
|
& MAXTHREADS )
|
|
|
|
! Results for mean-value output
|
|
REAL(KIND=8) :: MEAN_INTENSITY
|
|
& (MAX_USER_LEVELS, MAXBEAMS, MAX_DIRECTIONS, MAXTHREADS)
|
|
REAL(KIND=8) :: FLUX_INTEGRAL
|
|
& (MAX_USER_LEVELS, MAXBEAMS, MAX_DIRECTIONS, MAXTHREADS)
|
|
|
|
! Profile weighting functions
|
|
REAL(kind=8) :: PROFILEWF ( MAX_ATMOSWFS, MAXLAYERS,
|
|
& MAX_USER_LEVELS, MAX_GEOMETRIES, MAX_DIRECTIONS, MAXTHREADS )
|
|
|
|
! mean intensity weighting functions
|
|
REAL(kind=8) :: MINT_PROFILEWF ( MAX_ATMOSWFS, MAXLAYERS,
|
|
& MAX_USER_LEVELS, MAXBEAMS, MAX_DIRECTIONS, MAXTHREADS )
|
|
|
|
! flux weighting functions
|
|
REAL(kind=8) :: FLUX_PROFILEWF ( MAX_ATMOSWFS, MAXLAYERS,
|
|
& MAX_USER_LEVELS, MAXBEAMS, MAX_DIRECTIONS, MAXTHREADS )
|
|
|
|
! Surface weighting functions at user angles
|
|
REAL(kind=8) :: SURFACEWF ( MAX_SURFACEWFS, MAX_USER_LEVELS,
|
|
& MAX_GEOMETRIES, MAX_DIRECTIONS, MAXTHREADS )
|
|
|
|
! Flux and mean intensity surface weighting functions
|
|
REAL(kind=8) :: MINT_SURFACEWF ( MAX_SURFACEWFS,
|
|
& MAX_USER_LEVELS, MAXBEAMS, MAX_DIRECTIONS, MAXTHREADS )
|
|
REAL(kind=8) :: FLUX_SURFACEWF ( MAX_SURFACEWFS,
|
|
& MAX_USER_LEVELS, MAXBEAMS, MAX_DIRECTIONS, MAXTHREADS )
|
|
|
|
! Bookkeeping output
|
|
! ------------------
|
|
|
|
! Fourier numbers used
|
|
INTEGER :: FOURIER_SAVED ( MAXBEAMS, MAXTHREADS )
|
|
|
|
! Number of geometries (bookkeeping output)
|
|
INTEGER :: N_GEOMETRIES
|
|
|
|
|
|
! Thread number
|
|
INTEGER :: THREAD
|
|
|
|
|
|
! Another copy for FD test
|
|
REAL(KIND=8) :: FLUX_INTEGRAL_BASE
|
|
& (MAX_USER_LEVELS, MAXBEAMS, MAX_DIRECTIONS, MAXTHREADS)
|
|
|
|
! (dkh, 02/08/08)
|
|
INTEGER :: V, N
|
|
INTEGER :: W, WF
|
|
|
|
|
|
! Flag for opening error output file
|
|
LOGICAL :: OPENFILEFLAG
|
|
|
|
! Help variables
|
|
|
|
integer :: n6,l,ndum,ldum,t,t1,t2,t3,t4,t5,k3,k4,k5
|
|
integer :: n_totalprofile_wfs,nf,na,LEN_STRING
|
|
integer :: npert, k2
|
|
double precision :: kd, gaer, waer, taer, parcel, raywt, aerwt
|
|
double precision :: aersca, aerext, molabs, molsca, totsca, totext
|
|
double precision :: omega
|
|
double precision :: molomg(maxlayers),molext(maxlayers)
|
|
double precision :: aermoms(0:maxmoments_input), lamb, eps, epsfac
|
|
double precision :: raymoms(0:2,maxlayers), ratio1, ratio2
|
|
|
|
LOGICAL :: STATUS_PHYSICS
|
|
|
|
INTEGER :: J, K, IJLOOP
|
|
|
|
!=================================================================
|
|
! LIDORT_DRIVER begins here!
|
|
!=================================================================
|
|
|
|
! Set LIDORT number of layers and Legendre moments
|
|
nlayers = LLPAR
|
|
nmoments_input = NPM_MAX
|
|
|
|
eps = 0d0
|
|
epsfac = 1.0d0 + eps
|
|
|
|
! Initialize linearized inputs
|
|
DO_PROFILE_LINEARIZATION = .TRUE.
|
|
DO_SURFACE_LINEARIZATION = .TRUE.
|
|
N_TOTALPROFILE_WFS = MAX_ATMOSWFS
|
|
DO_BRDF_SURFACE = .FALSE.
|
|
|
|
! Initialise
|
|
do n = 1, nlayers
|
|
layer_vary_number(n) = MAX_ATMOSWFS
|
|
layer_vary_flag(n) = .true.
|
|
enddo
|
|
|
|
! Surface
|
|
N_SuRFACE_WFS = 1
|
|
|
|
|
|
!!$OMP PARALLEL DO
|
|
!!$OMP+DEFAULT( SHARED )
|
|
!!$OMP+PRIVATE( thread )
|
|
!!$OMP+PRIVATE( status_physics )
|
|
!!$OMP+PRIVATE( STATUS_INPUTCHECK, STATUS_CALCULATION )
|
|
!!$OMP+PRIVATE( CHECKACTIONS)
|
|
!!$OMP+PRIVATE( NCHECKMESSAGES, CHECKMESSAGES )
|
|
!!$OMP+PRIVATE( MESSAGE, TRACE_1, TRACE_2, TRACE_3 )
|
|
!!$OMP+PRIVATE( N_GEOMETRIES )
|
|
!!$OMP+PRIVATE( AIRDENS, GAS_PROFILE ) ! local
|
|
!!$OMP+PRIVATE( FINEGRID, HEIGHT_GRID, PRESSURE_GRID, TEMPERATURE_GRID ) ! local
|
|
!!$OMP+PRIVATE( BEAM_SZAS ) ! local
|
|
!!$OMP+PRIVATE( npert )
|
|
!!$OMP+PRIVATE( J )
|
|
!!$OMP+PRIVATE( IJLOOP )
|
|
!!$OMP+PRIVATE( W, V, N, WF, K )
|
|
DO THREAD = 1, JJPAR
|
|
!DO THREAD = JFD, JFD
|
|
|
|
! Use THREAD to loop over the latitude index J
|
|
J = THREAD
|
|
|
|
! First check to see if it is daytime.
|
|
! Calc 1-D array index
|
|
IJLOOP = ( J - 1 ) * IIPAR + I
|
|
|
|
! Only consider the sunny side
|
|
! CYCLE leads to OpenMP issues
|
|
!IF ( SUNCOS(IJLOOP) < 0.0005d0 ) CYCLE
|
|
IF ( SUNCOS(IJLOOP) >= 0.0005d0 ) THEN
|
|
|
|
! Get LAT / LON / ALT dependent physical properties
|
|
CALL PREPARE_PHYSICS_GC_IJ( I, J, PRESSURE_GRID,
|
|
& TEMPERATURE_GRID, HEIGHT_GRID, AIRDENS, GAS_PROFILE,
|
|
& BEAM_SZAS )
|
|
|
|
IF ( THREAD == 1 ) then
|
|
npert = 1
|
|
t1 = THREAD
|
|
|
|
ELSEIF ( THREAD == 2 ) then
|
|
npert = 21
|
|
t2 = THREAD
|
|
k2 = npert
|
|
|
|
ELSEIF ( THREAD == 3 ) then
|
|
npert = 23
|
|
t3 = THREAD
|
|
k3 = npert
|
|
|
|
ELSEIF ( THREAD == 4 ) then
|
|
npert = 40
|
|
t4 = THREAD
|
|
k4 = npert
|
|
|
|
ELSEIF ( THREAD == 5 ) then
|
|
!npert = 40
|
|
t5 = THREAD
|
|
k5 = npert
|
|
|
|
ENDIF
|
|
|
|
|
|
! Loop over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
! Prepare wavelength dependent physics, abort if failed
|
|
CALL PREPARE_PHYSICS_GC_IJW
|
|
& ( thread, epsfac, npert,
|
|
& status_physics,
|
|
& AIRDENS,
|
|
& GAS_PROFILE,
|
|
& LAMBERTIAN_ALBEDO(THREAD),
|
|
& OMEGA_TOTAL_INPUT(:,THREAD),
|
|
& DELTAU_VERT_INPUT(:,THREAD),
|
|
& PHASMOMS_TOTAL_INPUT(:,:,THREAD),
|
|
& L_OMEGA_TOTAL_INPUT(:,:,THREAD),
|
|
& L_DELTAU_VERT_INPUT(:,:,THREAD),
|
|
& L_PHASMOMS_TOTAL_INPUT(:,:,:,THREAD),
|
|
& I, J, W )
|
|
|
|
IF ( status_physics .EQV. .TRUE. ) STOP'physics_fail---'
|
|
|
|
! Call the actual LIDORT routines
|
|
CALL LIDORT_LPS_MASTER
|
|
& ( THREAD, DO_SOLAR_SOURCES, ! Input
|
|
& DO_UPWELLING, DO_DNWELLING, ! Input
|
|
& DO_FULLRAD_MODE, DO_USER_STREAMS, ! Input/Output
|
|
& DO_SSCORR_NADIR, DO_SSCORR_OUTGOING, ! Input/Output
|
|
& DO_SSFULL, DO_SSCORR_TRUNCATION, ! Input/Output
|
|
& DO_PLANE_PARALLEL, DO_BRDF_SURFACE, ! Input
|
|
& DO_ADDITIONAL_MVOUT, DO_MVOUT_ONLY, ! Input/Output
|
|
& DO_CHAPMAN_FUNCTION, DO_REFRACTIVE_GEOMETRY, ! Input/Output
|
|
& DO_DELTAM_SCALING, DO_DOUBLE_CONVTEST, ! Input/Output
|
|
& DO_RAYLEIGH_ONLY, DO_ISOTROPIC_ONLY, ! Input/Output
|
|
& DO_SOLUTION_SAVING, DO_BVP_TELESCOPING, ! Input/Output
|
|
& DO_ALL_FOURIER, DO_NO_AZIMUTH, ! Input/Output
|
|
& DO_PROFILE_LINEARIZATION, DO_SURFACE_LINEARIZATION, ! Input
|
|
& NSTREAMS, NLAYERS, NFINELAYERS, NMOMENTS_INPUT, ! Input (Nmoment_input re-set)
|
|
& NBEAMS, N_USER_STREAMS, N_USER_RELAZMS, N_USER_LEVELS, ! Input
|
|
& LAYER_VARY_FLAG, LAYER_VARY_NUMBER, N_SURFACE_WFS, ! Input
|
|
& FLUX_FACTOR, LIDORT_ACCURACY, ! Input
|
|
& EARTH_RADIUS, RFINDEX_PARAMETER, GEOMETRY_SPECHEIGHT, ! Input
|
|
& BEAM_SZAS, USER_ANGLES_INPUT, USER_RELAZMS, USER_LEVELS, ! Input
|
|
& FINEGRID, HEIGHT_GRID, PRESSURE_GRID, TEMPERATURE_GRID, ! Input
|
|
& DELTAU_VERT_INPUT, L_DELTAU_VERT_INPUT, ! Input
|
|
& OMEGA_TOTAL_INPUT, L_OMEGA_TOTAL_INPUT, ! Input
|
|
& PHASMOMS_TOTAL_INPUT, L_PHASMOMS_TOTAL_INPUT, ! Input
|
|
& LAMBERTIAN_ALBEDO, EXACTDB_BRDFUNC, LS_EXACTDB_BRDFUNC, ! Input
|
|
& BRDF_F_0, BRDF_F, USER_BRDF_F_0, USER_BRDF_F, ! Input
|
|
& LS_BRDF_F_0, LS_BRDF_F, LS_USER_BRDF_F_0, LS_USER_BRDF_F, ! Input
|
|
& INTENSITY, MEAN_INTENSITY, FLUX_INTEGRAL, ! Output
|
|
& N_GEOMETRIES, FOURIER_SAVED, ! Output
|
|
& PROFILEWF, MINT_PROFILEWF, FLUX_PROFILEWF, ! Output
|
|
& SURFACEWF, MINT_SURFACEWF, FLUX_SURFACEWF, ! Output
|
|
& STATUS_INPUTCHECK, NCHECKMESSAGES, CHECKMESSAGES, ! Check
|
|
& CHECKACTIONS, ! Check
|
|
& STATUS_CALCULATION, MESSAGE, TRACE_1, TRACE_2, TRACE_3 ) ! Check
|
|
|
|
! ! Exception handling, write-up (optional)
|
|
! ! Will generate file only if errors or warnings are encountered
|
|
! ! Unit file number = 35, Filename = '3p5T_LIDORT_Execution.log'
|
|
! CALL LIDORT_STATUS
|
|
! & ( THREAD, '3p5T_LIDORT_Execution.log', 35, OPENFILEFLAG,
|
|
! & STATUS_INPUTCHECK, NCHECKMESSAGES, CHECKMESSAGES,
|
|
! & CHECKACTIONS,
|
|
! & STATUS_CALCULATION, MESSAGE, TRACE_1, TRACE_2, TRACE_3 )
|
|
|
|
|
|
! Save results in global arrays.
|
|
! First loop over beams
|
|
DO V = 1, NBEAMS
|
|
|
|
! only save output at N = 1 (i.e., TOA)
|
|
N = 1
|
|
|
|
! Save flux
|
|
GLOB_FLUX_W(W,I,J) = GLOB_FLUX_W(W,I,J)
|
|
& + FLUX_INTEGRAL(N,V,UPIDX,THREAD)
|
|
|
|
|
|
! Save flux profile weighting functions (derivatives)
|
|
DO WF = 1, MAX_ATMOSWFS
|
|
DO K = 1, NLAYERS
|
|
JAC_GLOB_FLUX_W(WF, K,W,I,J)
|
|
& = JAC_GLOB_FLUX_W(WF,K,W,I,J)
|
|
& + FLUX_PROFILEWF(WF,K,N,V,UPIDX,THREAD)
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
|
|
|
|
ENDDO ! W
|
|
|
|
ENDIF ! SUNCOS
|
|
ENDDO
|
|
!!$OMP END PARALLEL DO
|
|
|
|
|
|
! !------------------------------------------------------------
|
|
! ! Repeat for FD calculation
|
|
! !------------------------------------------------------------
|
|
!
|
|
! ! set perturbation
|
|
! eps = 1.0d-03
|
|
! epsfac = 1.0d0 + eps
|
|
!
|
|
! ! save a copy of baseline calculations
|
|
! flux_integral_base = flux_integral
|
|
!
|
|
!!$OMP PARALLEL DO
|
|
!!$OMP+DEFAULT( SHARED )
|
|
!!$OMP+PRIVATE( thread )
|
|
!!$OMP+PRIVATE( status_physics )
|
|
!!$OMP+PRIVATE( STATUS_INPUTCHECK, STATUS_CALCULATION )
|
|
!!$OMP+PRIVATE( CHECKACTIONS)
|
|
!!$OMP+PRIVATE( NCHECKMESSAGES, CHECKMESSAGES )
|
|
!!$OMP+PRIVATE( MESSAGE, TRACE_1, TRACE_2, TRACE_3 )
|
|
!!$OMP+PRIVATE( N_GEOMETRIES )
|
|
!!$OMP+PRIVATE( AIRDENS, GAS_PROFILE ) ! local
|
|
!!$OMP+PRIVATE( FINEGRID, HEIGHT_GRID, PRESSURE_GRID, TEMPERATURE_GRID ) ! local
|
|
!!$OMP+PRIVATE( BEAM_SZAS ) ! local
|
|
!!$OMP+PRIVATE( npert )
|
|
!!$OMP+PRIVATE( J )
|
|
!!$OMP+PRIVATE( IJLOOP )
|
|
!!$OMP+PRIVATE( W, V, N, WF, K )
|
|
! DO THREAD = 1, 5
|
|
!
|
|
! ! Use THREAD to loop over the latitude index J
|
|
! !J = THREAD
|
|
! J = JFD
|
|
!
|
|
! ! First check to see if it is daytime.
|
|
! ! Calc 1-D array index
|
|
! IJLOOP = ( J - 1 ) * IIPAR + I
|
|
!
|
|
! !! Only consider the sunny side
|
|
! IF ( SUNCOS(IJLOOP) < 0.0005d0 ) CYCLE
|
|
!
|
|
! ! Get LAT / LON / ALT dependent physical properties
|
|
! CALL PREPARE_PHYSICS_GC_IJ( I, J, PRESSURE_GRID,
|
|
! & TEMPERATURE_GRID, HEIGHT_GRID, AIRDENS, GAS_PROFILE,
|
|
! & BEAM_SZAS )
|
|
!
|
|
! IF ( THREAD == 1 ) then
|
|
! npert = 1
|
|
! t1 = THREAD
|
|
!
|
|
! ELSEIF ( THREAD == 2 ) then
|
|
! npert = 21
|
|
! t2 = THREAD
|
|
! k2 = npert
|
|
!
|
|
! ELSEIF ( THREAD == 3 ) then
|
|
! npert = 23
|
|
! t3 = THREAD
|
|
! k3 = npert
|
|
!
|
|
! ELSEIF ( THREAD == 4 ) then
|
|
! npert = 40
|
|
! t4 = THREAD
|
|
! k4 = npert
|
|
!
|
|
! ELSEIF ( THREAD == 5 ) then
|
|
! npert = 1
|
|
! t5 = THREAD
|
|
!
|
|
! ENDIF
|
|
!
|
|
!
|
|
! ! Just check a single wavelength
|
|
! W = 1
|
|
!
|
|
! ! Prepare physics, abort if failed
|
|
! CALL PREPARE_PHYSICS_GC_IJW
|
|
! & ( thread, epsfac, npert,
|
|
! & status_physics,
|
|
! & AIRDENS,
|
|
! & GAS_PROFILE,
|
|
! & LAMBERTIAN_ALBEDO(THREAD),
|
|
! & OMEGA_TOTAL_INPUT(:,THREAD),
|
|
! & DELTAU_VERT_INPUT(:,THREAD),
|
|
! & PHASMOMS_TOTAL_INPUT(:,:,THREAD),
|
|
! & L_OMEGA_TOTAL_INPUT(:,:,THREAD),
|
|
! & L_DELTAU_VERT_INPUT(:,:,THREAD),
|
|
! & L_PHASMOMS_TOTAL_INPUT(:,:,:,THREAD),
|
|
! & I, J, W )
|
|
! IF ( status_physics .EQV. .TRUE. ) STOP'physics_fail---'
|
|
!
|
|
!
|
|
! ! Call the actual LIDORT routines
|
|
! CALL LIDORT_LPS_MASTER
|
|
! & ( THREAD, DO_SOLAR_SOURCES, ! Input
|
|
! & DO_UPWELLING, DO_DNWELLING, ! Input
|
|
! & DO_FULLRAD_MODE, DO_USER_STREAMS, ! Input/Output
|
|
! & DO_SSCORR_NADIR, DO_SSCORR_OUTGOING, ! Input/Output
|
|
! & DO_SSFULL, DO_SSCORR_TRUNCATION, ! Input/Output
|
|
! & DO_PLANE_PARALLEL, DO_BRDF_SURFACE, ! Input
|
|
! & DO_ADDITIONAL_MVOUT, DO_MVOUT_ONLY, ! Input/Output
|
|
! & DO_CHAPMAN_FUNCTION, DO_REFRACTIVE_GEOMETRY, ! Input/Output
|
|
! & DO_DELTAM_SCALING, DO_DOUBLE_CONVTEST, ! Input/Output
|
|
! & DO_RAYLEIGH_ONLY, DO_ISOTROPIC_ONLY, ! Input/Output
|
|
! & DO_SOLUTION_SAVING, DO_BVP_TELESCOPING, ! Input/Output
|
|
! & DO_ALL_FOURIER, DO_NO_AZIMUTH, ! Input/Output
|
|
! & DO_PROFILE_LINEARIZATION, DO_SURFACE_LINEARIZATION, ! Input
|
|
! & NSTREAMS, NLAYERS, NFINELAYERS, NMOMENTS_INPUT, ! Input (Nmoment_input re-set)
|
|
! & NBEAMS, N_USER_STREAMS, N_USER_RELAZMS, N_USER_LEVELS, ! Input
|
|
! & LAYER_VARY_FLAG, LAYER_VARY_NUMBER, N_SURFACE_WFS, ! Input
|
|
! & FLUX_FACTOR, LIDORT_ACCURACY, ! Input
|
|
! & EARTH_RADIUS, RFINDEX_PARAMETER, GEOMETRY_SPECHEIGHT, ! Input
|
|
! & BEAM_SZAS, USER_ANGLES_INPUT, USER_RELAZMS, USER_LEVELS, ! Input
|
|
! & FINEGRID, HEIGHT_GRID, PRESSURE_GRID, TEMPERATURE_GRID, ! Input
|
|
! & DELTAU_VERT_INPUT, L_DELTAU_VERT_INPUT, ! Input
|
|
! & OMEGA_TOTAL_INPUT, L_OMEGA_TOTAL_INPUT, ! Input
|
|
! & PHASMOMS_TOTAL_INPUT, L_PHASMOMS_TOTAL_INPUT, ! Input
|
|
! & LAMBERTIAN_ALBEDO, EXACTDB_BRDFUNC, LS_EXACTDB_BRDFUNC, ! Input
|
|
! & BRDF_F_0, BRDF_F, USER_BRDF_F_0, USER_BRDF_F, ! Input
|
|
! & LS_BRDF_F_0, LS_BRDF_F, LS_USER_BRDF_F_0, LS_USER_BRDF_F, ! Input
|
|
! & INTENSITY, MEAN_INTENSITY, FLUX_INTEGRAL, ! Output
|
|
! & N_GEOMETRIES, FOURIER_SAVED, ! Output
|
|
! & PROFILEWF, MINT_PROFILEWF, FLUX_PROFILEWF, ! Output
|
|
! & SURFACEWF, MINT_SURFACEWF, FLUX_SURFACEWF, ! Output
|
|
! & STATUS_INPUTCHECK, NCHECKMESSAGES, CHECKMESSAGES, ! Check
|
|
! & CHECKACTIONS, ! Check
|
|
! & STATUS_CALCULATION, MESSAGE, TRACE_1, TRACE_2, TRACE_3 ) ! Check
|
|
!
|
|
! ! Exception handling, write-up (optional)
|
|
! ! Will generate file only if errors or warnings are encountered
|
|
! ! Unit file number = 35, Filename = '3p5T_LIDORT_Execution.log'
|
|
!
|
|
! CALL LIDORT_STATUS
|
|
! & ( THREAD, '3p5T_LIDORT_Execution.log', 35, OPENFILEFLAG,
|
|
! & STATUS_INPUTCHECK, NCHECKMESSAGES, CHECKMESSAGES,
|
|
! & CHECKACTIONS,
|
|
! & STATUS_CALCULATION, MESSAGE, TRACE_1, TRACE_2, TRACE_3 )
|
|
!
|
|
! ENDDO
|
|
!!$OMP END PARALLEL DO
|
|
!
|
|
!
|
|
! ! Display FD vs ADJ ouput
|
|
! OPEN(36,file = 'Tester_LPS_MT.all', status = 'unknown')
|
|
! write(36,'(/T32,a/T32,a/)')
|
|
! & 'REGULAR FLUX, 3 PROFILE JACOBIANS, 1 SURFACE JACOBIAN',
|
|
! & '====================================================='
|
|
! write(36,'(a,T32,a,a,a/)')' Sun SZA Level/Output',
|
|
! & 'Regular F1 Profile AJ2 Profile FD2 Profile AJ3',
|
|
! & ' Profile FD3 Profile AJ4 Profifle FD4',
|
|
! & ' Surface AJ5 Surface FD5'
|
|
! do v = 1, nbeams
|
|
!
|
|
! ! upwelling
|
|
! do n = 1, n_user_levels
|
|
! write(36,366)v,'Upwelling @',user_levels(n),
|
|
! & flux_integral_base(n,v,upidx,t1),
|
|
! & flux_profilewf(1,k2,n,v,upidx,t2),
|
|
! & (flux_integral(n,v,upidx,t2)
|
|
! & - flux_integral_base(n,v,upidx,t2))/eps,
|
|
! & flux_profilewf(2,k3,n,v,upidx,t3),
|
|
! & (flux_integral(n,v,upidx,t3)
|
|
! & - flux_integral_base(n,v,upidx,t3))/eps,
|
|
! & flux_profilewf(2,k4,n,v,upidx,t4),
|
|
! & (flux_integral(n,v,upidx,t4)
|
|
! & - flux_integral_base(n,v,upidx,t4))/eps,
|
|
! & LAMBERTIAN_ALBEDO(t5)/epsfac*flux_surfacewf(1,n,v,upidx,t5),
|
|
! & (flux_integral(n,v,upidx,t5)
|
|
! & - flux_integral_base(n,v,upidx,t5))/eps
|
|
! enddo
|
|
!
|
|
!! ! downwelling
|
|
!! do n = 1, n_user_levels
|
|
!! write(36,366)v,'Dnwelling @',user_levels(n),
|
|
!! & flux_integral(n,v,dnidx,t1),
|
|
!! & flux_profilewf(1,k2,n,v,dnidx,t2),
|
|
!! & (flux_integral(n,v,dnidx,t2)
|
|
!! & - flux_integral_base(n,v,dnidx,t2))/eps,
|
|
!! & flux_profilewf(2,k3,n,v,dnidx,t3),
|
|
!! & (flux_integral(n,v,dnidx,t3)
|
|
!! & - flux_integral_base(n,v,dnidx,t3))/eps,
|
|
!! & flux_profilewf(2,k4,n,v,dnidx,t4),
|
|
!! & (flux_integral(n,v,dnidx,t4)
|
|
!! & - flux_integral_base(n,v,dnidx,t4))/eps,
|
|
!! & LAMBERTIAN_ALBEDO(t5)/epsfac*flux_surfacewf(1,n,v,dnidx,t5),
|
|
!! & (flux_integral(n,v,dnidx,t5)
|
|
!! & - flux_integral_base(n,v,dnidx,t5))/eps
|
|
!! enddo
|
|
! write(36,*)' '
|
|
! enddo
|
|
!
|
|
! close(36)
|
|
!366 format(i5,T11,a,f6.2,2x,1pe13.6,4(2x,1p2e14.6))
|
|
|
|
|
|
|
|
! Close error file if it has been opened
|
|
IF ( OPENFILEFLAG ) then
|
|
CLOSE(35)
|
|
IF ( STATUS_INPUTCHECK .eq. LIDORT_WARNING .and.
|
|
& STATUS_CALCULATION .eq. LIDORT_SUCCESS ) then
|
|
write(*,*)'3p5T.exe: program executed with internal '//
|
|
& 'defaults, warnings in "3p5T_LIDORT_Execution.log"'
|
|
ELSE
|
|
write(*,*)'3p5T.exe: program Failed to execute, '//
|
|
& 'Error messages in "3p5T_LIDORT_Execution.log"'
|
|
ENDIF
|
|
ELSE
|
|
!write(*,*)'3p5T.exe: program finished successfully'
|
|
ENDIF
|
|
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE LIDORT_DRIVER
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CALC_RADIATIVE_FLUX( GLOB_FLUX_INST )
|
|
|
|
!******************************************************************************
|
|
! Subroutine CALC_RADIATIVE_FLUX calculates the TOA upward radiative flux
|
|
! [W/m2].
|
|
!
|
|
! Module variables as Input:
|
|
! ============================================================================
|
|
! (1 ) SUNCOS (REAL*8) : Cosine of solar zenith angle [rad]
|
|
! (2 ) GLOB_FLUX_W (REAL*8) : Percent of insolation reflected upward [%]
|
|
!
|
|
! Module variables as Output:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX (REAL*8) : Running total of upward ratiative flux [W/m2/nsteps]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE DAO_MOD, ONLY : SUNCOS
|
|
USE GRID_MOD, ONLY : GET_AREA_M2
|
|
USE TIME_MOD, ONLY : GET_NYMD, GET_NHMS
|
|
|
|
|
|
! dkh debug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD
|
|
# include "CMN_SIZE" ! IIPAR, JJPAR
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(INOUT) :: GLOB_FLUX_INST(IIPAR,JJPAR)
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, W, IJLOOP
|
|
REAL*8 :: TOTAL_FLUX(IIPAR,JJPAR)
|
|
REAL*8 :: GLOB_TEMP(IIPAR,JJPAR)
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: EARTHSA = 510705155749195 ! [m2]
|
|
|
|
|
|
!=================================================================
|
|
! CALC_RADIATIVE_FLUX begins here!
|
|
!=================================================================
|
|
|
|
! Initialize storage arrays
|
|
TOTAL_FLUX(:,:) = 0d0
|
|
GLOB_TEMP(:,:) = 0d0
|
|
GLOB_FLUX_INST(:,:) = 0d0
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, W, IJLOOP )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
!DO J = JFD, JFD
|
|
!DO I = IFD, IFD
|
|
|
|
! Calc 1-D array index
|
|
IJLOOP = ( J - 1 ) * IIPAR + I
|
|
|
|
! Only consider the sunny side
|
|
IF ( SUNCOS(IJLOOP) > 0.0005d0 ) THEN
|
|
|
|
! Integrate over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
! Calculate instantaneous upward flux
|
|
! = (% reflected) * (spectral band insolation)
|
|
! note: zenith angle already accounted for in GLOB_FLUX_W
|
|
GLOB_FLUX_INST(I,J) = GLOB_FLUX_INST(I,J)
|
|
& + GLOB_FLUX_W(W,I,J)
|
|
& * SOL_FLUX_TABLE(W)
|
|
|
|
! Track total incoming ratiation
|
|
GLOB_TEMP(I,J) = GLOB_TEMP(I,J)
|
|
& + SOL_FLUX_TABLE(W) * SUNCOS(IJLOOP)
|
|
|
|
ENDDO
|
|
|
|
! Add current flux to the running total
|
|
GLOB_FLUX(I,J) = GLOB_FLUX(I,J)
|
|
& + GLOB_FLUX_INST(I,J) * INV_NSPAN
|
|
|
|
! Convert from [W/m2] to [W]
|
|
TOTAL_FLUX(I,J) = GLOB_FLUX(I,J) * GET_AREA_M2(J)
|
|
GLOB_TEMP (I,J) = GLOB_TEMP(I,J) * GET_AREA_M2(J)
|
|
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Update count
|
|
!GLOB_FLUX_COUNT = GLOB_FLUX_COUNT + 1
|
|
|
|
! dkh debug
|
|
print*, ' sum of GLOB_FLUX = ', SUM(TOTAL_FLUX(:,:))
|
|
& / EARTHSA, !/ GLOB_FLUX_COUNT,
|
|
& SUM(GLOB_TEMP(:,:))
|
|
& / EARTHSA
|
|
! & GLOB_FLUX_COUNT
|
|
|
|
! Save out instantaneous forcing
|
|
CALL MAKE_RAD_FILE( GET_NYMD(), GET_NHMS(), GLOB_FLUX_INST )
|
|
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CALC_RADIATIVE_FLUX
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE CALC_RADIATIVE_FORCE( GLOB_FLUX_INST, COST_FUNC )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine CALC_RADIATIVE_FORCE calculates the difference in the
|
|
! instantaneous upward radiative flux between the current simulation and data
|
|
! from a previous simulation. (dkh, 03/05/08)
|
|
!
|
|
! Arguments as Input/Output:
|
|
! ============================================================================
|
|
! (1 ) COST_FUNC (REAL*8) : Cost function [none]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE DAO_MOD, ONLY : CLDFRC
|
|
USE ERROR_MOD, ONLY : IT_IS_NAN, ERROR_STOP
|
|
USE GRID_MOD, ONLY : GET_AREA_M2
|
|
USE TIME_MOD, ONLY : GET_NYMD, GET_NHMS
|
|
|
|
! dkh debug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD
|
|
|
|
# include "CMN_SIZE"
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: GLOB_FLUX_INST(IIPAR,JJPAR)
|
|
REAL*8, INTENT(INOUT) :: COST_FUNC
|
|
|
|
! Local variables
|
|
INTEGER :: I, J
|
|
REAL*8 :: FORCE(IIPAR,JJPAR)
|
|
REAL*8 :: GLOB_FLUX_NAT(IIPAR,JJPAR)
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: EARTHSA = 510705155749195 ! [m2]
|
|
|
|
!=================================================================
|
|
! CALC_RADIATIVE_FORCE begins here!
|
|
!=================================================================
|
|
|
|
! Initialize
|
|
FORCE(:,:) = 0d0
|
|
GLOB_FLUX_NAT(:,:) = 0d0
|
|
|
|
! Read radiative flux from previous simulation
|
|
!print*, ' *** SENSITIVITY CALC; USE NAT RAD = 0'
|
|
!print*, ' *** SENSITIVITY CALC; USE NAT RAD = 0'
|
|
!print*, ' *** SENSITIVITY CALC; USE NAT RAD = 0'
|
|
!print*, ' *** SENSITIVITY CALC; USE NAT RAD = 0'
|
|
GLOB_FLUX_NAT(:,:) = 0D0
|
|
!CALL READ_RAD_FILE( GET_NYMD(), GET_NHMS(), GLOB_FLUX_NAT )
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
!DO J = JFD, JFD
|
|
!DO I = IFD, IFD
|
|
|
|
!print*, I, ' ', J
|
|
!print*, I, ' ', J, ' ', GLOB_FLUX_INST(I,J),GLOB_AVE_FORCE(I,J)
|
|
|
|
! Forcing is (downward flux) - (downward natural flux). Since these
|
|
! GLOB_FLUX arrays are actually actualy upward fluxes, subtract
|
|
! GLOB_FLUX from GLOB_FLUX_NAT.
|
|
! Include cloud fraction for clear-sky calculation (dkh, 08/03/11)
|
|
!FORCE(I,J) = GLOB_FLUX_NAT(I,J) - GLOB_FLUX_INST(I,J)
|
|
FORCE(I,J) = ( GLOB_FLUX_NAT(I,J) - GLOB_FLUX_INST(I,J) )
|
|
& * CLDFRC(I,J)
|
|
|
|
! Diagnostic: Track global average forcing [W/m2]
|
|
GLOB_AVE_FORCE(I,J) = GLOB_AVE_FORCE(I,J)
|
|
& + FORCE(I,J) * INV_NSPAN
|
|
|
|
! Weight it according to local area [W]
|
|
FORCE(I,J) = FORCE(I,J) * GET_AREA_M2(J)
|
|
|
|
!print*, I, ' ', J, ' ', GLOB_FLUX_INST(I,J),GLOB_AVE_FORCE(I,J)
|
|
!print*, I, ' ', J
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Update cost function with global average forcing [W/m2]
|
|
COST_FUNC = COST_FUNC + SUM(FORCE(:,:)) / EARTHSA * INV_NSPAN
|
|
|
|
! dkh debug
|
|
!! **** HACK
|
|
!COST_FUNC = COST_FUNC + GLOB_FLUX_INST(IFD,JFD) * INV_NSPAN
|
|
!print*, ' *** COST_FUNC ONLY IN JFD, IFD *** '
|
|
!print*, ' *** COST_FUNC ONLY IN JFD, IFD *** '
|
|
!print*, ' *** COST_FUNC ONLY IN JFD, IFD *** '
|
|
!print*, ' *** COST_FUNC ONLY IN JFD, IFD *** '
|
|
!print*, ' *** COST_FUNC ONLY IN JFD, IFD *** '
|
|
|
|
! Error checking and print out
|
|
IF ( IT_IS_NAN( COST_FUNC ) ) THEN
|
|
CALL ERROR_STOP( 'COST_FUNC is NAN', 'CALC_AOD_FORCE')
|
|
ELSE
|
|
WRITE(6,*) ' CALC_RADIATIVE_FORC: Current COST_FUN = ',
|
|
& COST_FUNC
|
|
ENDIF
|
|
|
|
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CALC_RADIATIVE_FORCE
|
|
|
|
!------------------------------------------------------------------------------
|
|
SUBROUTINE ADJ_CALC_RADIATIVE_FORCE( GLOB_FLUX_INST_ADJ )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine ADJ_CALC_RADIATIVE_FORCE is the adjoint of CALC_RADIATIVE_FORCE.
|
|
! (dkh, 04/03/08)
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX_INST_ADJ (REAL*8) : [none]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE DAO_MOD, ONLY : CLDFRC
|
|
USE GRID_MOD, ONLY : GET_AREA_M2
|
|
|
|
# include "CMN_SIZE"
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(OUT) :: GLOB_FLUX_INST_ADJ(IIPAR,JJPAR)
|
|
|
|
! Local variables
|
|
INTEGER :: J
|
|
INTEGER :: I
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: EARTHSA = 510705155749195 ! [m2]
|
|
|
|
!=================================================================
|
|
! ADJ_CALC_RADIATIVE_FORCE begins here!
|
|
!=================================================================
|
|
|
|
! fwd code:
|
|
!COST_FUNC += SUM( (GLOB_FLUX_NAT(I,J) - GLOB_FLUX_INST(I,J) ) * GET_AREA_M2(J) ) / EARTHSA * INV_NSPAN
|
|
! * CLDFRC(I,J)
|
|
|
|
GLOB_FLUX_INST_ADJ(:,:) = 1D0 / EARTHSA * INV_NSPAN
|
|
|
|
! dkh debug
|
|
!! **** HACK
|
|
!print*, ' *** HACK '
|
|
!print*, ' *** HACK '
|
|
!print*, ' *** HACK '
|
|
!print*, ' *** HACK '
|
|
!print*, ' force localy '
|
|
!GLOB_FLUX_INST_ADJ(:,:) = - 1D0 * INV_NSPAN
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
!
|
|
GLOB_FLUX_INST_ADJ(I,J) = - GLOB_FLUX_INST_ADJ(I,J)
|
|
& * GET_AREA_M2(J)
|
|
& * CLDFRC(I,J)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE ADJ_CALC_RADIATIVE_FORCE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE ADJ_CALC_RADIATIVE_FLUX( GLOB_FLUX_INST_ADJ )
|
|
|
|
!******************************************************************************
|
|
! Subroutine ADJ_CALC_RADIATIVE_FLUX
|
|
! (dkh, 04/03/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX_INST_ADJ (REAL*8) :
|
|
!
|
|
! Module variables as Output:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX_W_ADJ (REAL*8) :
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE DAO_MOD, ONLY : SUNCOS
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD
|
|
|
|
# include "CMN_SIZE" ! IIPAR, JJPAR
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: GLOB_FLUX_INST_ADJ(IIPAR,JJPAR)
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, W, IJLOOP
|
|
|
|
!=================================================================
|
|
! ADJ_CALC_RADIATIVE_FLUX begins here!
|
|
!=================================================================
|
|
|
|
! Initialize arrays
|
|
GLOB_FLUX_W_ADJ(:,:,:) = 0d0
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, W, IJLOOP )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
!DO J = JFD, JFD
|
|
!DO I = IFD, IFD
|
|
|
|
! Calc 1-D array index
|
|
IJLOOP = ( J - 1 ) * IIPAR + I
|
|
|
|
! Only consider the sunny side
|
|
IF ( SUNCOS(IJLOOP) > 0.0005d0 ) THEN
|
|
|
|
! Integrate over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
! fwd code:
|
|
!GLOB_FLUX_INST(I,J) = GLOB_FLUX_INST(I,J)
|
|
! + GLOB_FLUX_W(W,I,J)
|
|
! * SOL_FLUX_TABLE(W)
|
|
! adj code:
|
|
GLOB_FLUX_W_ADJ(W,I,J) = GLOB_FLUX_INST_ADJ(I,J)
|
|
& * SOL_FLUX_TABLE(W)
|
|
|
|
ENDDO
|
|
|
|
ENDIF
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE ADJ_CALC_RADIATIVE_FLUX
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE ADJ_LIDORT_DRIVER( I, J )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine ADJ_LIDORT_DRIVER
|
|
! (dkh, 04/03/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) I (INTEGER) : Lon index [none]
|
|
! (2 ) J (INTEGER) : Lat index [none]
|
|
!
|
|
! Module variables as Input:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX_W_ADJ
|
|
! (2 ) JAC_GLOB_FLUX_W
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : IT_IS_NAN, ERROR_STOP
|
|
USE COMODE_MOD, ONLY : JLOP
|
|
!USE COMODE_MOD, ONLY : ADJ_CSPEC_FORCE
|
|
USE DAO_MOD, ONLY : BXHEIGHT
|
|
USE TRACERID_MOD, ONLY : IDO3
|
|
|
|
! Include files
|
|
# include "CMN_SIZE" ! LLPAR, LLTROP
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J
|
|
|
|
! (dkh, 02/08/08)
|
|
INTEGER :: W, L, UA, K
|
|
INTEGER :: JLOOP
|
|
|
|
REAL*8 :: TAU_GAS
|
|
REAL*8 :: ADJ_GAS_PROFILE
|
|
|
|
REAL*8, PARAMETER :: DU_TO_CM2 = 2.68668d+16
|
|
|
|
!=================================================================
|
|
! ADJ_LIDORT_DRIVER begins here!
|
|
!=================================================================
|
|
|
|
! Loop over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
DO K = 1, NLAYERS
|
|
|
|
L = LLPAR - K + 1
|
|
|
|
! Adjoint of gas absorption. Leave this out for the now
|
|
! TAU_GAS = GAS_PROFILE(K) * DU_TO_CM2 * O3_XSEC_TABLE(W)
|
|
!
|
|
! ! Trace gas absorption [sw only]
|
|
! ADJ_GAS_PROFILE = JAC_GLOB_FLUX_W(1,K,W,I,J)
|
|
! & * GLOB_FLUX_W_ADJ(W,I,J)
|
|
! & / TAU_GAS
|
|
!
|
|
! ! Get 1-D array index for extracting O3 from CSPEC
|
|
! JLOOP = JLOP(I,J,L)
|
|
!
|
|
! ! Get O3 from CSPEC within the troposphere
|
|
! IF ( JLOOP > 0 .and. L <= LLTROP ) THEN
|
|
!
|
|
! ! fwd code:
|
|
! !GAS_PROFILE(N) = CSPEC(JLOOP,IDO3)
|
|
! ! * BXHEIGHT(I,J,L) * 100d0
|
|
! ! * 3.7219d-17
|
|
!
|
|
! ADJ_CSPEC_FORCE(JLOOP,IDO3) = ADJ_CSPEC_FORCE(JLOOP,IDO3)
|
|
! & + ADJ_GAS_PROFILE
|
|
! & * BXHEIGHT(I,J,L) * 100d0
|
|
! & * 3.7219d-17
|
|
! ENDIF
|
|
|
|
|
|
|
|
! Layer aerosol optical depth
|
|
LAYER_AOD_ADJ(I,J,L,W) = JAC_GLOB_FLUX_W(2,K,W,I,J)
|
|
& * GLOB_FLUX_W_ADJ(W,I,J)
|
|
& / LAYER_AOD(I,J,L,W)
|
|
|
|
! Layer aerosol single scatering albedo
|
|
LAYER_SSA_ADJ(I,J,L,W) = JAC_GLOB_FLUX_W(3,K,W,I,J)
|
|
& * GLOB_FLUX_W_ADJ(W,I,J)
|
|
& / LAYER_SSA(I,J,L,W)
|
|
|
|
! Layer aerosol phase momemnts
|
|
LAYER_PHM_ADJ(I,J,L,1,W) = JAC_GLOB_FLUX_W(4,K,W,I,J)
|
|
& * GLOB_FLUX_W_ADJ(W,I,J)
|
|
& / LAYER_PHM(I,J,L,1,W)
|
|
|
|
! Check if we've actually computed jacobians of all these PHMs
|
|
IF ( MAX_ATMOSWFS == 8 ) THEN
|
|
LAYER_PHM_ADJ(I,J,L,2:5,W) = JAC_GLOB_FLUX_W(5:8,K,W,I,J)
|
|
& * GLOB_FLUX_W_ADJ(W,I,J)
|
|
& / LAYER_PHM(I,J,L,2:5,W)
|
|
LAYER_PHM_ADJ(I,J,L,6:NPM_MAX,W) = 0D0
|
|
ELSE
|
|
LAYER_PHM_ADJ(I,J,L,2:NPM_MAX,W) = 0D0
|
|
ENDIF
|
|
|
|
ENDDO
|
|
|
|
ENDDO
|
|
|
|
! ********* HACK works, at least close...
|
|
!LAYER_AOD_ADJ(:,:,:,:) = 0d0
|
|
!LAYER_SSA_ADJ(:,:,:,:) = 0d0
|
|
!LAYER_PHM_ADJ(:,:,:,:,:) = 0d0
|
|
!LAYER_AOD_ADJ(IFD,JFD,6,4) = 1d0
|
|
!LAYER_SSA_ADJ(IFD,JFD,5,4:4) = 1d0
|
|
! LAYER_PHM_ADJ(IFD,JFD,6,1:5,:) = 1d0
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE ADJ_LIDORT_DRIVER
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE ADJ_CALC_AOD( I, J )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine ADJ_CALC_AOD
|
|
! (dkh, 04/06/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) I, J (Integer) : X-Y Grid locations
|
|
!
|
|
! Output:
|
|
! ============================================================================
|
|
! STT_ADJ and ADJ_FORCE
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ADJ_ARRAYS_MOD, ONLY : STT_ADJ
|
|
USE CHECKPT_MOD, ONLY : RP_OUT, CHK_STT
|
|
USE DAO_MOD, ONLY : RH, BXHEIGHT, AIRVOL
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE TRACERID_MOD, ONLY : IDTSO4, IDTNIT, IDTNH4
|
|
USE TRACERID_MOD, ONLY : IDTBCPO, IDTBCPI
|
|
USE TRACERID_MOD, ONLY : IDTOCPO, IDTOCPI
|
|
! fha 6-6-2011 added OC
|
|
! dkh debug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD
|
|
|
|
# include "CMN_SIZE"
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: I, J
|
|
|
|
! Local variables
|
|
INTEGER :: L, W
|
|
INTEGER :: NSP
|
|
REAL*8 :: DIAM(NSP_MAX)
|
|
REAL*8 :: WET_DIAM(NSP_MAX)
|
|
REAL*8 :: MASS(NSP_MAX)
|
|
REAL*8 :: NCONC(NSP_MAX)
|
|
REAL*8 :: BEXT, SSA, PHM(NPM_MAX)
|
|
REAL*8 :: RHL
|
|
REAL*8 :: BEXT_TOT
|
|
REAL*8 :: SCAT_TOT
|
|
REAL*8 :: PHM_TOT(NPM_MAX)
|
|
!REAL*8 :: NCONC_TOT
|
|
|
|
! Local adjoint variables
|
|
REAL*8 :: ADJ_DIAM(NSP_MAX)
|
|
REAL*8 :: ADJ_MASS(NSP_MAX)
|
|
REAL*8 :: ADJ_NCONC(NSP_MAX)
|
|
REAL*8 :: ADJ_BEXT, ADJ_SSA, ADJ_PHM(NPM_MAX)
|
|
REAL*8 :: ADJ_BEXT_TOT
|
|
REAL*8 :: ADJ_SCAT_TOT
|
|
REAL*8 :: ADJ_PHM_TOT(NPM_MAX)
|
|
REAL*8 :: ADJ_MASS_WET
|
|
REAL*8 :: ADJ_MASS_DRY
|
|
!REAL*8 :: ADJ_NCONC_TOT
|
|
REAL*8 :: DUM
|
|
|
|
! for testing MIE derivatives
|
|
!REAL*8 :: DIAM_0, NCONC_0, PERT
|
|
!REAL*8 :: DIAM_P, DIAM_N, NCONC_p, NCONC_n
|
|
!REAL*8 :: BEXT_1p, BEXT_1n, SSA_1p, SSA_1n
|
|
!REAL*8 :: BEXT_2p, BEXT_2n, SSA_2p, SSA_2n
|
|
!REAL*8 :: BEXT_0, SSA_0, PHM_0(NPM_MAX)
|
|
!REAL*8 :: PHM_2p(NPM_MAX), PHM_2n(NPM_MAX)
|
|
!REAL*8 :: ADJ_NCONC_1, ADJ_NCONC_2
|
|
!REAL*8 :: ADJ_DIAM_1, ADJ_DIAM_2
|
|
!REAL*8 :: PHM_1p(NPM_MAX), PHM_1n(NPM_MAX)
|
|
|
|
!=================================================================
|
|
! ADJ_CALC_AOD begins here!
|
|
!=================================================================
|
|
|
|
! dkh debug
|
|
! IF ( I == IFD .and. J == JFD ) THEN
|
|
! print*, 'ddd loc w HACK '
|
|
! print*, 'ddd loc w HACK '
|
|
! print*, 'ddd loc w HACK '
|
|
! print*, 'ddd loc w ', LAYER_AOD_ADJ(I,J,LFD,3)
|
|
! LAYER_AOD_ADJ = 0d0
|
|
! LAYER_SSA_ADJ = 0d0
|
|
! LAYER_PHM_ADJ = 0d0
|
|
! !LAYER_AOD_ADJ(I,J,LFD,3) = 1d0
|
|
! LAYER_SSA_ADJ(I,J,LFD,3) = 1d0
|
|
! ENDIF
|
|
|
|
|
|
! note: already in a parallel loop over I,J
|
|
DO L = 1 , LLPAR
|
|
|
|
|
|
|
|
! Recalculate NCONC, DIAM, MASS
|
|
|
|
! Get local RH, cap at 99%
|
|
RHL = MIN(99.D0,RH(I,J,L))
|
|
|
|
! Loop over aerosol type
|
|
DO NSP = 1, NSP_MAX
|
|
!fha (6/1/11) added OC
|
|
IF ( NSP == NSP_BC ) THEN
|
|
|
|
! Aerosol wet size (um)
|
|
WET_DIAM(NSP) = GET_WET_DIAM( RHL, NSP,
|
|
& DRY_DIAM(NSP)/2d0 )
|
|
|
|
! Aerosol mass [kg/box]
|
|
MASS(NSP) = REAL(CHK_STT(I,J,L,IDTBCPI),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTBCPO),8)
|
|
|
|
! Total effective diam is volume weighted average
|
|
! of wet (BCPI) and dry (BCPO) components. Since
|
|
! BC assumed to have density of 1, then volume ~ mass
|
|
DIAM(NSP) =
|
|
& ( REAL(CHK_STT(I,J,L,IDTBCPI),8) * WET_DIAM(NSP)
|
|
& + REAL(CHK_STT(I,J,L,IDTBCPO),8) * DRY_DIAM(NSP) )
|
|
& / MASS(NSP)
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: rcl GET_NCONC bc ', MASS(NSP),
|
|
! & DIAM(NSP)
|
|
! ENDIF
|
|
!
|
|
! IF ( I == IFD .and. J == JFD .and. L == 6 ) THEN
|
|
! print*, 'rcl JJJ MASS = ', MASS(NSP)
|
|
! print*, 'rcl JJJ DIAM = ', DIAM(NSP)
|
|
! print*, 'rcl JJJ WET_DIAM = ', WET_DIAM(NSP)
|
|
! print*, 'rcl JJJ DRY_DIAM = ', DRY_DIAM(NSP)
|
|
! print*, 'rcl JJJ RHL = ', RHL
|
|
! ENDIF
|
|
|
|
|
|
! Aerosol number concentration.
|
|
NCONC(NSP) = GET_NCONC(
|
|
& MASS(NSP),
|
|
& 0d0,
|
|
!------------------------------------------------------------------
|
|
! BUG FIX: since we don't have mass of water, estimate NCONC based
|
|
! on dry radius (dkh, 01/27/11)
|
|
! & DENSE(NSP), 1.d0, DIAM(NSP),
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
!------------------------------------------------------------------
|
|
& SIGMA(NSP), AIRVOL(I,J,L) )
|
|
ELSEIF ( NSP == NSP_OC ) THEN
|
|
|
|
! Aerosol wet size (um)
|
|
WET_DIAM(NSP) = GET_WET_DIAM( RHL, NSP,
|
|
& DRY_DIAM(NSP)/2d0 )
|
|
|
|
! Aerosol mass [kg/box]
|
|
MASS(NSP) = REAL(CHK_STT(I,J,L,IDTOCPI),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTOCPO),8)
|
|
|
|
! Total effective diam is volume weighted average
|
|
! of wet (BCPI) and dry (BCPO) components. Since
|
|
! BC assumed to have density of 1, then volume ~ mass
|
|
DIAM(NSP) =
|
|
& ( REAL(CHK_STT(I,J,L,IDTOCPI),8) * WET_DIAM(NSP)
|
|
& + REAL(CHK_STT(I,J,L,IDTOCPO),8) * DRY_DIAM(NSP) )
|
|
& / MASS(NSP)
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: rcl GET_NCONC bc ', MASS(NSP),
|
|
! & DIAM(NSP)
|
|
! ENDIF
|
|
!
|
|
! IF ( I == IFD .and. J == JFD .and. L == 6 ) THEN
|
|
! print*, 'rcl JJJ MASS = ', MASS(NSP)
|
|
! print*, 'rcl JJJ DIAM = ', DIAM(NSP)
|
|
! print*, 'rcl JJJ WET_DIAM = ', WET_DIAM(NSP)
|
|
! print*, 'rcl JJJ DRY_DIAM = ', DRY_DIAM(NSP)
|
|
! print*, 'rcl JJJ RHL = ', RHL
|
|
! ENDIF
|
|
|
|
|
|
! Aerosol number concentration.
|
|
NCONC(NSP) = GET_NCONC(
|
|
& MASS(NSP),
|
|
& 0d0,
|
|
!------------------------------------------------------------------
|
|
! BUG FIX: since we don't have mass of water, estimate NCONC based
|
|
! on dry radius (dkh, 01/27/11)
|
|
! & DENSE(NSP), 1.d0, DIAM(NSP),
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
!------------------------------------------------------------------
|
|
& SIGMA(NSP), AIRVOL(I,J,L) )
|
|
ELSE
|
|
! try it this way:
|
|
! specify dry diam
|
|
!DIAM = 0.1
|
|
!DIAM(NSP) = DRY_DIAM(NSP)
|
|
|
|
! Aerosol mass [kg/box]
|
|
MASS(NSP) = REAL(CHK_STT(I,J,L,IDTSO4),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTNIT),8)
|
|
& + REAL(CHK_STT(I,J,L,IDTNH4),8)
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: rcl GET_NCONC sulf ', MASS(NSP),
|
|
! & DRY_DIAM(NSP)
|
|
! ENDIF
|
|
|
|
! get NCONC based on dry mass
|
|
NCONC(NSP) = GET_NCONC(
|
|
& MASS(NSP),
|
|
& 0d0,
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
& SIGMA(NSP), AIRVOL(I,J,L) )
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: rcl GET_WETD2 ', MASS(NSP),
|
|
! & REAL(RP_OUT(I,J,L,4),8), NCONC(NSP)
|
|
! ENDIF
|
|
|
|
!! ! get wet diam
|
|
!! DIAM(NSP) = GET_WETD2(
|
|
!! & MASS(NSP),
|
|
!!! & REAL(RP_OUT(I,J,L,4),8),
|
|
!!! HACK: for testing SO4
|
|
!! & 1000d0,
|
|
!! & DENSE(NSP), 1.d0, NCONC(NSP),
|
|
!! & SIGMA(NSP), AIRVOL(I,J,L) )
|
|
! Aerosol wet size (um)
|
|
DIAM(NSP) = GET_WET_DIAM( RHL, NSP,
|
|
& DRY_DIAM(NSP)/2d0 )
|
|
|
|
|
|
ENDIF
|
|
ENDDO
|
|
|
|
! Initialize these, which are summed over wavelength in ADJ_MIE_LOOKUP
|
|
ADJ_NCONC(:) = 0D0
|
|
ADJ_DIAM(:) = 0D0
|
|
ADJ_MASS(:) = 0D0
|
|
|
|
! Loop over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
BEXT_TOT = 0d0
|
|
SCAT_TOT = 0D0
|
|
PHM_TOT(:) = 0D0
|
|
!NCONC_TOT = 0D0
|
|
|
|
! Recalculate BEXT_TOT, SCAT_TOT, PHM_TOT, NCONC_TOT
|
|
DO NSP = 1, NSP_MAX
|
|
|
|
! Lookup aerosol optical properties
|
|
CALL MIE_LOOKUP( NCONC(NSP), DIAM(NSP), W, NSP,
|
|
& BEXT, SSA, PHM, I,J,L )
|
|
|
|
|
|
BEXT_TOT = BEXT_TOT + BEXT
|
|
SCAT_TOT = SCAT_TOT + BEXT * SSA
|
|
PHM_TOT(:) = PHM_TOT(:) + PHM(:) * BEXT * SSA
|
|
!NCONC_TOT = NCONC_TOT + NCONC(NSP)
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! !print*, ' I, J, L, W, NSP, NCONC, DIAM, MASS, DENSE,
|
|
! !BEXT, SSA in adj',
|
|
! !I, J, L, W, NSP, NCONC(NSP), DIAM(NSP), MASS(NSP),
|
|
! !DENSE(NSP), BEXT, SSA
|
|
! print*, ' ick: rcl I,J,L,W,NSP ', I, J, L, W, NSP
|
|
! print*, ' ick: rcl NCONC ', NCONC(NSP)
|
|
! print*, ' ick: rcl DIAM ', DIAM(NSP)
|
|
! print*, ' ick: rcl MASS ', MASS(NSP)
|
|
! print*, ' ick: rcl DENSE ', DENSE(NSP)
|
|
! print*, ' ick: rcl BEXT ', BEXT
|
|
! print*, ' ick: rcl SSA ', SSA
|
|
!ENDIF
|
|
|
|
ENDDO
|
|
|
|
IF ( BEXT_TOT < SMALL .or.
|
|
& SCAT_TOT < SMALL ) THEN
|
|
CALL ERROR_STOP(' Trouble calculating combined opt prop',
|
|
& ' aero_optical_mod.f' )
|
|
ENDIF
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD ) THEN
|
|
! print*, ' jck: rcl I,J,L,W ', I, J, L, W
|
|
! print*, ' jck: rcl BEXT_TOT ', BEXT_TOT
|
|
! print*, ' jck: rcl SCAT_TOT ', SCAT_TOT
|
|
! print*, ' jck: rcl LAYER_AOD', LAYER_AOD(I,J,L,W)
|
|
! print*, ' jck: rcl LAYER_SSA', LAYER_SSA(I,J,L,W)
|
|
! print*, ' jck: rcl RHL ', RHL
|
|
!ENDIF
|
|
|
|
|
|
! Calculate adjoint of BEXT_TOT, SCAT_TOT, PHM_TOT, NCONC_TOT
|
|
! fwd code:
|
|
!LAYER_AOD(I,J,L,W) = BXHEIGHT(I,J,L) * BEXT_TOT
|
|
!LAYER_SSA(I,J,L,W) = SCAT_TOT / BEXT_TOT ! / NCONC_TOT
|
|
!LAYER_PHM(I,J,L,:,W) = PHM_TOT(:) / SCAT_TOT
|
|
! adj code:
|
|
ADJ_BEXT_TOT = BXHEIGHT(I,J,L)
|
|
& * LAYER_AOD_ADJ(I,J,L,W)
|
|
! & * 1d-6
|
|
& - SCAT_TOT / BEXT_TOT **2 !/ NCONC_TOT
|
|
& * LAYER_SSA_ADJ(I,J,L,W)
|
|
ADJ_SCAT_TOT = 1.0 / BEXT_TOT !/ NCONC_TOT
|
|
& * LAYER_SSA_ADJ(I,J,L,W)
|
|
& - 1 / SCAT_TOT **2
|
|
& * SUM(PHM_TOT(:) * LAYER_PHM_ADJ(I,J,L,:,W) )
|
|
ADJ_PHM_TOT(:) = LAYER_PHM_ADJ(I,J,L,:,W) / SCAT_TOT
|
|
! ADJ_NCONC_TOT = - SCAT_TOT / BEXT_TOT / NCONC_TOT ** 2
|
|
! & * LAYER_SSA_ADJ(I,J,L,W)
|
|
|
|
!**** HACK
|
|
!IF ( L == LFD .and. W == NWL_500 ) THEN
|
|
! ADJ_BEXT_TOT = 0D0
|
|
! ADJ_SCAT_TOT = 1D0
|
|
! ADJ_PHM_TOT(:) = 0D0
|
|
!ELSE
|
|
! ADJ_BEXT_TOT = 0D0
|
|
! ADJ_SCAT_TOT = 0D0
|
|
! ADJ_PHM_TOT(:) = 0D0
|
|
!ENDIF
|
|
|
|
!print*, 'ADJ_BEXT_TOT = ', ADJ_BEXT_TOT
|
|
|
|
DO NSP = 1, NSP_MAX
|
|
|
|
! Recalculate BEXT, SSA, PHM
|
|
! Lookup aerosol optical properties
|
|
CALL MIE_LOOKUP( NCONC(NSP), DIAM(NSP), W, NSP,
|
|
& BEXT, SSA, PHM, I,J,L )
|
|
|
|
! dkh debug
|
|
!IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! !print*, ' I, J, L, W, NSP, NCONC, DIAM, MASS, DENSE,
|
|
! !BEXT, SSA in adj',
|
|
! !I, J, L, W, NSP, NCONC(NSP), DIAM(NSP), MASS(NSP),
|
|
! !DENSE(NSP), BEXT, SSA
|
|
! print*, ' ick: rc2 I,J,L,W,NSP ', I, J, L, W, NSP
|
|
! print*, ' ick: rc2 NCONC ', NCONC(NSP)
|
|
! print*, ' ick: rc2 DIAM ', DIAM(NSP)
|
|
! print*, ' ick: rc2 MASS ', MASS(NSP)
|
|
! print*, ' ick: rc2 DENSE ', DENSE(NSP)
|
|
! print*, ' ick: rc2 BEXT ', BEXT
|
|
! print*, ' ick: rc2 SSA ', SSA
|
|
!ENDIF
|
|
|
|
! Calculate adjoint of BEXT, SSA, PHM, NCONC
|
|
! fwd code:
|
|
!BEXT_TOT = BEXT_TOT + BEXT
|
|
!SCAT_TOT = SCAT_TOT + BEXT * SSA
|
|
!PHM_TOT(:) = PHM_TOT(:) + PHM(:) * BEXT * SSA
|
|
!!NCONC_TOT = NCONC_TOT + NCONC(NSP)
|
|
! adj code:
|
|
!ADJ_NCONC(NSP) = ADJ_NCONC_TOT
|
|
ADJ_PHM(:) = ADJ_PHM_TOT(:) * BEXT * SSA
|
|
ADJ_SSA = ADJ_SCAT_TOT * BEXT
|
|
& + SUM(ADJ_PHM_TOT(:) * PHM(:) ) * BEXT
|
|
ADJ_BEXT = ADJ_BEXT_TOT
|
|
& + ADJ_SCAT_TOT * SSA
|
|
& + SUM(ADJ_PHM_TOT(:) * PHM(:) ) * SSA
|
|
|
|
! dkh debug
|
|
!print*, 'ddd loc bu ', ADJ_SSA, ADJ_BEXT , W, NSP
|
|
!print*, 'ddd loc bu p', ADJ_PHM(:)
|
|
!print*, 'ddd loc bu f1', BEXT, SSA
|
|
!print*, 'ddd loc bu f2', PHM(:)
|
|
!print*, 'ddd loc bu f3', ADJ_PHM_TOT(:)
|
|
|
|
!!**** HACK works
|
|
! IF ( L == LFD .and. W == NWL_500 .and. NSP == 2 ) THEN
|
|
!! print*, ' HACK ddd loc bps '
|
|
! ADJ_BEXT = 1D0
|
|
! ADJ_PHM(:) = 0D0
|
|
! ADJ_SSA = 0D0
|
|
! ADJ_NCONC = 0D0
|
|
! ELSE
|
|
! ADJ_BEXT = 0D0
|
|
! ADJ_PHM(:) = 0D0
|
|
! ADJ_SSA = 0D0
|
|
! ENDIF
|
|
|
|
|
|
! Get ADJ_NCONC, ADJ_DIAM
|
|
CALL ADJ_MIE_LOOKUP( DIAM(NSP), W, NSP,
|
|
& NCONC(NSP),
|
|
& ADJ_NCONC(NSP), ADJ_DIAM(NSP),
|
|
& ADJ_BEXT, ADJ_SSA,
|
|
& ADJ_PHM, I,J,L )
|
|
|
|
!! dkh debug
|
|
!print*, 'ddd loc bv ', ADJ_NCONC(NSP),ADJ_DIAM(NSP), W
|
|
|
|
! Here is some code for testing MIE derivatives. Should disable OMP
|
|
! loop when calling ADJ_CALC_AOD prior to using this. Also, uncomment
|
|
! the block of "testing" variable declarations above (dkh, 03/27/11)
|
|
!----------------------------------------------------------------------
|
|
! IF ( I == IFD .and. L == LFD .and. W == 1
|
|
! & .and. NSP == 2 ) THEN
|
|
! ! FWD
|
|
! DIAM_0 = DIAM(NSP)
|
|
! NCONC_0 = NCONC(NSP)
|
|
! PERT = 0.1d0
|
|
!
|
|
! ! Lookup aerosol optical properties
|
|
! CALL MIE_LOOKUP( NCONC(NSP), DIAM(NSP), W, NSP,
|
|
! & BEXT_0, SSA_0, PHM_0, I,J,L )
|
|
!
|
|
! NCONC_p = NCONC_0 * (1d0 + PERT)
|
|
! NCONC_n = NCONC_0 * (1d0 - PERT)
|
|
!
|
|
! DIAM_p = DIAM_0 * (1d0 + PERT)
|
|
! DIAM_n = DIAM_0 * (1d0 - PERT)
|
|
!
|
|
! CALL MIE_LOOKUP( NCONC_p, DIAM_0 , W, NSP,
|
|
! & BEXT_1p, SSA_1p, PHM_1p, I,J,L )
|
|
!
|
|
! CALL MIE_LOOKUP( NCONC_n, DIAM_0 , W, NSP,
|
|
! & BEXT_1n, SSA_1n, PHM_1n, I,J,L )
|
|
!
|
|
! CALL MIE_LOOKUP( NCONC_0 , DIAM_p, W, NSP,
|
|
! & BEXT_2p, SSA_2p, PHM_2p, I,J,L )
|
|
!
|
|
! CALL MIE_LOOKUP( NCONC_0 , DIAM_n, W, NSP,
|
|
! & BEXT_2n, SSA_2n, PHM_2n, I,J,L )
|
|
!
|
|
!
|
|
! ADJ_BEXT = 1d0
|
|
! ADJ_SSA = 0d0
|
|
! ADJ_PHM = 0d0
|
|
! ADJ_NCONC_1 = 0d0
|
|
! ADJ_DIAM_1 = 0d0
|
|
!
|
|
! ! Get ADJ_NCONC, ADJ_DIAM
|
|
! CALL ADJ_MIE_LOOKUP( DIAM_0, W, NSP,
|
|
! & NCONC_0,
|
|
! & ADJ_NCONC_1, ADJ_DIAM_1,
|
|
! & ADJ_BEXT, ADJ_SSA,
|
|
! & ADJ_PHM, I,J,L )
|
|
!
|
|
! ADJ_BEXT = 0d0
|
|
! ADJ_SSA = 1d0
|
|
! ADJ_PHM = 0d0
|
|
! ADJ_NCONC_2 = 0d0
|
|
! ADJ_DIAM_2 = 0d0
|
|
!
|
|
! ! Get ADJ_NCONC, ADJ_DIAM
|
|
! CALL ADJ_MIE_LOOKUP( DIAM_0, W, NSP,
|
|
! & NCONC_0,
|
|
! & ADJ_NCONC_2, ADJ_DIAM_2,
|
|
! & ADJ_BEXT, ADJ_SSA,
|
|
! & ADJ_PHM, I,J,L )
|
|
!
|
|
! print*,' dBEXT/dNCONC, dSSA/dNCONC, dBEXT/dDIAM, dSSA/dDIAM',
|
|
! & I, J, L, W, NSP
|
|
! WRITE(6,100), ' FD 1st pos: ', ( BEXT_1p - BEXT_0 ) / PERT,
|
|
! & ( SSA_1p - SSA_0 ) / PERT,
|
|
! & ( BEXT_2p - BEXT_0) / PERT,
|
|
! & ( SSA_2p - SSA_0 ) / PERT
|
|
! WRITE(6,100), ' FD 1st neg: ', -( BEXT_1n - BEXT_0 ) / PERT,
|
|
! & -( SSA_1n - SSA_0 ) / PERT,
|
|
! & -( BEXT_2n - BEXT_0) / PERT,
|
|
! & -( SSA_2n - SSA_0 ) / PERT
|
|
! WRITE(6,100), ' FD 2nd : ',
|
|
! & ( BEXT_1p - BEXT_1n ) / ( 2d0 * PERT ),
|
|
! & ( SSA_1p - SSA_1n ) / ( 2d0 * PERT ),
|
|
! & ( BEXT_2p - BEXT_2n ) / ( 2d0 * PERT ),
|
|
! & ( SSA_2p - SSA_2n ) / ( 2d0 * PERT )
|
|
! WRITE(6,100), ' ADJ : ', ADJ_NCONC_1 * NCONC_0,
|
|
! & ADJ_NCONC_2 * NCONC_0,
|
|
! & ADJ_DIAM_1 * DIAM_0,
|
|
! & ADJ_DIAM_2 * DIAM_0
|
|
!
|
|
! 100 FORMAT(A14, 2x, es13.6, 2x, es13.6, 2x, es13.6, 2x, es13.6 )
|
|
!
|
|
! ENDIF
|
|
!----------------------------------------------------------------------
|
|
|
|
|
|
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ADJ_NCONC = ', ADJ_NCONC, NSP
|
|
! print*, 'ADJ_DIAM = ', ADJ_DIAM , NSP
|
|
! ENDIF
|
|
|
|
! Reset
|
|
ADJ_PHM(:) = 0d0
|
|
ADJ_SSA = 0d0
|
|
ADJ_BEXT = 0d0
|
|
|
|
ENDDO
|
|
|
|
! reset some variables here
|
|
! fwd:
|
|
!BEXT_TOT = 0d0
|
|
!SCAT_TOT = 0D0
|
|
!PHM_TOT(:) = 0D0
|
|
!NCONC_TOT = 0D0
|
|
! adj:
|
|
ADJ_BEXT_TOT = 0D0
|
|
ADJ_SCAT_TOT = 0D0
|
|
ADJ_PHM_TOT(:) = 0D0
|
|
!ADJ_NCONC_TOT = 0D0
|
|
|
|
ENDDO ! LAMBDA
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, ' ADJ_DIAM, ADJ_NCONC ' , ADJ_DIAM, ADJ_NCONC
|
|
! ENDIF
|
|
|
|
! ! **** HACK works
|
|
! IF ( L == LFD ) THEN
|
|
! !print*, ' HACK ddd loc nd '
|
|
! ADJ_NCONC(2) = 1D0
|
|
! ADJ_DIAM(2) = 0d0
|
|
! ELSE
|
|
! ADJ_NCONC(2) = 0D0
|
|
! ADJ_DIAM(2) = 0d0
|
|
! ENDIF
|
|
! ADJ_NCONC(1) = 0D0
|
|
! ADJ_DIAM(1) = 0d0
|
|
|
|
|
|
! Calculate adjoint of STT(SO4,NH4,NIT,BC)
|
|
! Loop over aerosol type
|
|
DO NSP = 1, NSP_MAX
|
|
|
|
! dkh debug
|
|
!print*, 'ddd loc b xyz loop NSP ', NSP
|
|
!fha (6/1/11) added OC
|
|
IF ( NSP == NSP_BC ) THEN
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: ADJ_GET_NCONC bc ', MASS(NSP),
|
|
! & DIAM(NSP)
|
|
! ENDIF
|
|
|
|
|
|
! Calculate adjoint of MASS, update adjoint of DIAM
|
|
! fwd:
|
|
!NCONC(NSP) = GET_NCONC(
|
|
! MASS(NSP),
|
|
! 0d0,
|
|
! DENSE(NSP), 1.d0, DIAM(NSP),
|
|
! SIGMA(NSP), AIRVOL(I,J,L) )
|
|
! adj:
|
|
CALL ADJ_GET_NCONC(
|
|
& MASS(NSP), 0d0,
|
|
!----------------------------------------------------------
|
|
! BUG FIX: use dry diam for estimating bc NCONC. Also,
|
|
! DIAM is not an active variable, so pass 0d0 instead of
|
|
! ADJ_DIAM. (dkh, 01/27/11)
|
|
! & DENSE(NSP), 1.d0, DIAM(NSP),
|
|
! & SIGMA(NSP), AIRVOL(I,J,L),
|
|
! & ADJ_DIAM(NSP), ADJ_NCONC(NSP),
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
& SIGMA(NSP), AIRVOL(I,J,L),
|
|
& DUM, ADJ_NCONC(NSP),
|
|
!----------------------------------------------------------
|
|
& ADJ_MASS(NSP) )
|
|
|
|
!! **** HACK works
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD .and. NSP == 2 ) THEN
|
|
! print*, ' force at ddd loc md '
|
|
! ADJ_DIAM(NSP) = 0D0
|
|
! ADJ_MASS(NSP) = 1D0
|
|
! print*, 'adj JJJ MASS = ', MASS(NSP)
|
|
! print*, 'adj JJJ DIAM = ', DIAM(NSP)
|
|
! print*, 'adj JJJ WET_DIAM = ', WET_DIAM(NSP)
|
|
! print*, 'adj JJJ DRY_DIAM = ', DRY_DIAM(NSP)
|
|
! print*, 'adj JJJ RHL = ', RHL
|
|
! ELSE
|
|
! ADJ_DIAM(NSP) = 0D0
|
|
! ADJ_MASS(NSP) = 0D0
|
|
! ENDIF
|
|
|
|
! fwd:
|
|
!DIAM(NSP) =
|
|
! ( REAL(CHK_STT(I,J,L,IDTBCPI),8) * WET_DIAM(NSP)
|
|
! + REAL(CHK_STT(I,J,L,IDTBCPO),8) * DRY_DIAM(NSP) )
|
|
! / MASS(NSP)
|
|
! adj:
|
|
ADJ_MASS(NSP) = - DIAM(NSP) / MASS(NSP)
|
|
& * ADJ_DIAM(NSP) + ADJ_MASS(NSP)
|
|
|
|
! **** HACK
|
|
STT_ADJ(I,J,L,IDTBCPI) = STT_ADJ(I,J,L,IDTBCPI)
|
|
& + WET_DIAM(NSP) / MASS(NSP)
|
|
& * ADJ_DIAM(NSP)
|
|
STT_ADJ(I,J,L,IDTBCPO) = STT_ADJ(I,J,L,IDTBCPO)
|
|
& + DRY_DIAM(NSP) / MASS(NSP)
|
|
& * ADJ_DIAM(NSP)
|
|
|
|
! **** HACK worked
|
|
!IF ( L == 6 ) THEN
|
|
! ADJ_MASS(NSP) = 1d0
|
|
!ELSE
|
|
! ADJ_MASS(NSP) = 0d0
|
|
!ENDIF
|
|
! fwd:
|
|
!MASS(NSP) = REAL(CHK_STT(I,J,L,IDTBCPI),8)
|
|
! + REAL(CHK_STT(I,J,L,IDTBCPO),8)
|
|
! adj:
|
|
! **** HACK
|
|
STT_ADJ(I,J,L,IDTBCPI) = STT_ADJ(I,J,L,IDTBCPI)
|
|
& + ADJ_MASS(NSP)
|
|
STT_ADJ(I,J,L,IDTBCPO) = STT_ADJ(I,J,L,IDTBCPO)
|
|
& + ADJ_MASS(NSP)
|
|
|
|
! fwd:
|
|
!WET_DIAM(NSP) = GET_WET_DIAM( RHL, NSP, DRY_DIAM(NSP)/2d0 )
|
|
! adj: None, since RH not an active variable, but could
|
|
! calculates sensitivity w.r.t. dry diam and RH here.
|
|
|
|
|
|
|
|
ELSEIF ( NSP == NSP_OC ) THEN
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: ADJ_GET_NCONC bc ', MASS(NSP),
|
|
! & DIAM(NSP)
|
|
! ENDIF
|
|
|
|
|
|
! Calculate adjoint of MASS, update adjoint of DIAM
|
|
! fwd:
|
|
!NCONC(NSP) = GET_NCONC(
|
|
! MASS(NSP),
|
|
! 0d0,
|
|
! DENSE(NSP), 1.d0, DIAM(NSP),
|
|
! SIGMA(NSP), AIRVOL(I,J,L) )
|
|
! adj:
|
|
CALL ADJ_GET_NCONC(
|
|
& MASS(NSP), 0d0,
|
|
!----------------------------------------------------------
|
|
! BUG FIX: use dry diam for estimating bc NCONC. Also,
|
|
! DIAM is not an active variable, so pass 0d0 instead of
|
|
! ADJ_DIAM. (dkh, 01/27/11)
|
|
! & DENSE(NSP), 1.d0, DIAM(NSP),
|
|
! & SIGMA(NSP), AIRVOL(I,J,L),
|
|
! & ADJ_DIAM(NSP), ADJ_NCONC(NSP),
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
& SIGMA(NSP), AIRVOL(I,J,L),
|
|
& DUM, ADJ_NCONC(NSP),
|
|
!----------------------------------------------------------
|
|
& ADJ_MASS(NSP) )
|
|
|
|
!! **** HACK works
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD .and. NSP == 2 ) THEN
|
|
! print*, ' force at ddd loc md '
|
|
! ADJ_DIAM(NSP) = 0D0
|
|
! ADJ_MASS(NSP) = 1D0
|
|
! print*, 'adj JJJ MASS = ', MASS(NSP)
|
|
! print*, 'adj JJJ DIAM = ', DIAM(NSP)
|
|
! print*, 'adj JJJ WET_DIAM = ', WET_DIAM(NSP)
|
|
! print*, 'adj JJJ DRY_DIAM = ', DRY_DIAM(NSP)
|
|
! print*, 'adj JJJ RHL = ', RHL
|
|
! ELSE
|
|
! ADJ_DIAM(NSP) = 0D0
|
|
! ADJ_MASS(NSP) = 0D0
|
|
! ENDIF
|
|
|
|
! fwd:
|
|
!DIAM(NSP) =
|
|
! ( REAL(CHK_STT(I,J,L,IDTBCPI),8) * WET_DIAM(NSP)
|
|
! + REAL(CHK_STT(I,J,L,IDTBCPO),8) * DRY_DIAM(NSP) )
|
|
! / MASS(NSP)
|
|
! adj:
|
|
ADJ_MASS(NSP) = - DIAM(NSP) / MASS(NSP)
|
|
& * ADJ_DIAM(NSP) + ADJ_MASS(NSP)
|
|
|
|
! **** HACK
|
|
STT_ADJ(I,J,L,IDTOCPI) = STT_ADJ(I,J,L,IDTOCPI)
|
|
& + WET_DIAM(NSP) / MASS(NSP)
|
|
& * ADJ_DIAM(NSP)
|
|
STT_ADJ(I,J,L,IDTOCPO) = STT_ADJ(I,J,L,IDTOCPO)
|
|
& + DRY_DIAM(NSP) / MASS(NSP)
|
|
& * ADJ_DIAM(NSP)
|
|
|
|
! **** HACK worked
|
|
!IF ( L == 6 ) THEN
|
|
! ADJ_MASS(NSP) = 1d0
|
|
!ELSE
|
|
! ADJ_MASS(NSP) = 0d0
|
|
!ENDIF
|
|
! fwd:
|
|
!MASS(NSP) = REAL(CHK_STT(I,J,L,IDTBCPI),8)
|
|
! + REAL(CHK_STT(I,J,L,IDTBCPO),8)
|
|
! adj:
|
|
! **** HACK
|
|
STT_ADJ(I,J,L,IDTOCPI) = STT_ADJ(I,J,L,IDTOCPI)
|
|
& + ADJ_MASS(NSP)
|
|
STT_ADJ(I,J,L,IDTOCPO) = STT_ADJ(I,J,L,IDTOCPO)
|
|
& + ADJ_MASS(NSP)
|
|
|
|
! fwd:
|
|
!WET_DIAM(NSP) = GET_WET_DIAM( RHL, NSP, DRY_DIAM(NSP)/2d0 )
|
|
! adj: None, since RH not an active variable, but could
|
|
! calculates sensitivity w.r.t. dry diam and RH here.
|
|
|
|
|
|
ELSE
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: ADJ_GET_WETD2 ', MASS(NSP),
|
|
! & REAL(RP_OUT(I,J,L,4),8), NCONC(NSP)
|
|
! ENDIF
|
|
|
|
! dkh debug
|
|
!print*, 'ddd loc bx ', ADJ_NCONC(NSP),
|
|
! & ADJ_DIAM(NSP)
|
|
!print*, 'ddd loc bx f1', MASS(NSP)
|
|
!print*, 'ddd loc bx f2', REAL(RP_OUT(I,J,L,4),8)
|
|
!print*, 'ddd loc bx f3', DENSE(NSP)
|
|
!print*, 'ddd loc bx f4', NCONC(NSP)
|
|
!print*, 'ddd loc bx f5', SIGMA(NSP)
|
|
!print*, 'ddd loc bx f6', AIRVOL(I,J,L)
|
|
|
|
! fwd:
|
|
!DIAM(NSP) = GET_WETD2(
|
|
! MASS(NSP),
|
|
! REAL(RP_OUT(I,J,L,4),8),
|
|
! DENSE(NSP), 1.d0, NCONC(NSP),
|
|
! SIGMA(NSP), AIRVOL(I,J,L) )
|
|
! adj: input is ADJ_NCONC, ADJ_DIAM
|
|
! output is ADJ_MASS_WET, ADJ_MASS_DRY, ADJ_NCONC
|
|
!! CALL ADJ_GET_WETD2(
|
|
!! & MASS(NSP),
|
|
!!! & REAL(RP_OUT(I,J,L,4),8),
|
|
!!! HACK: for testing SO4
|
|
!! & 1000d0,
|
|
!! & DENSE(NSP), 1.d0, NCONC(NSP),
|
|
!! & SIGMA(NSP), AIRVOL(I,J,L),
|
|
!! & ADJ_DIAM(NSP), ADJ_MASS_WET,
|
|
!! & ADJ_MASS_DRY, ADJ_NCONC(NSP) )
|
|
|
|
! **** HACK
|
|
! ADJ_FORCE(I,J,L,IDADJH2O) = ADJ_MASS_WET
|
|
! ADJ_MASS(NSP) = ADJ_MASS_DRY
|
|
|
|
! ! dkh debug
|
|
! IF ( I == IFD .and. J == JFD .and. L == LFD ) THEN
|
|
! print*, 'ichk: ADJ_GET_NCONC sulf ', MASS(NSP),
|
|
! & DRY_DIAM(NSP)
|
|
! ENDIF
|
|
|
|
! **** HACK
|
|
!IF ( L == LFD ) THEN
|
|
! ADJ_NCONC(NSP) = 1D0
|
|
! ADJ_DIAM(NSP) = 0D0
|
|
! ADJ_MASS(NSP) = 0D0
|
|
!ELSE
|
|
! ADJ_NCONC(NSP) = 0D0
|
|
! ADJ_DIAM(NSP) = 0D0
|
|
! ADJ_MASS(NSP) = 0D0
|
|
!ENDIF
|
|
|
|
! dkh debug
|
|
! print*, 'ddd loc by', ADJ_MASS(NSP), ADJ_NCONC(NSP),
|
|
! & ADJ_DIAM(NSP)
|
|
|
|
|
|
! fwd
|
|
!NCONC(NSP) = GET_NCONC(
|
|
! MASS(NSP),
|
|
! 0d0,
|
|
! DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
! SIGMA(NSP), AIRVOL(I,J,L) )
|
|
! adj: input is ADJ_DIAM, ADJ_NCONC, ADJ_MASS
|
|
! output is ADJ_MASS, ADJ_DIAM
|
|
CALL ADJ_GET_NCONC(
|
|
& MASS(NSP), 0d0,
|
|
& DENSE(NSP), 1.d0, DRY_DIAM(NSP),
|
|
& SIGMA(NSP), AIRVOL(I,J,L),
|
|
& ADJ_DIAM(NSP), ADJ_NCONC(NSP),
|
|
& ADJ_MASS(NSP) )
|
|
|
|
! dkh debug
|
|
!print*, 'ddd loc bz', ADJ_MASS(NSP)
|
|
|
|
! **** HACK
|
|
!IF ( L == LFD ) THEN
|
|
! ADJ_MASS(NSP) = 1D0
|
|
!ELSE
|
|
! ADJ_MASS(NSP) = 0D0
|
|
!ENDIF
|
|
|
|
! Aerosol mass [kg/box]
|
|
!MASS(NSP) = REAL(CHK_STT(I,J,L,IDTSO4),8)
|
|
! + REAL(CHK_STT(I,J,L,IDTNIT),8)
|
|
! + REAL(CHK_STT(I,J,L,IDTNH4),8)
|
|
STT_ADJ(I,J,L,IDTSO4) = STT_ADJ(I,J,L,IDTSO4)
|
|
& + ADJ_MASS(NSP)
|
|
STT_ADJ(I,J,L,IDTNIT) = STT_ADJ(I,J,L,IDTNIT)
|
|
& + ADJ_MASS(NSP)
|
|
STT_ADJ(I,J,L,IDTNH4) = STT_ADJ(I,J,L,IDTNH4)
|
|
& + ADJ_MASS(NSP)
|
|
|
|
ENDIF
|
|
ENDDO
|
|
|
|
ENDDO ! L
|
|
|
|
|
|
!print*, ' *** DISABLE ADJOINT H2O FORCING '
|
|
!print*, ' *** DISABLE ADJOINT H2O FORCING '
|
|
!print*, ' *** DISABLE ADJOINT H2O FORCING '
|
|
!print*, ' *** DISABLE ADJOINT H2O FORCING '
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE ADJ_CALC_AOD
|
|
|
|
!------------------------------------------------------------------------------
|
|
!
|
|
SUBROUTINE ADJ_GET_NCONC( MASS_DRY_kg, MASS_WET, DENSE_DRY,
|
|
& DENSE_WET, D, SIGMA, BVOL,
|
|
& ADJ_D, ADJ_NCONC, ADJ_MASS_DRY )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine ADJ_GET_NCONC computes ADJ_MASS_DRY and updates ADJ_D
|
|
! (dkh, 01/21/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) MASS_DRY_kg (REAL*8) : Aerosol dry mass concentration [kg/box]
|
|
! (2 ) MASS_WET (REAL*8) : Aerosol water concentration [ug/m3]
|
|
! (3 ) DENSE_DRY (REAL*8) : Dry aerosol density [g/cm3]
|
|
! (4 ) DENSE_WET (REAL*8) : Wet aerosol density [g/cm3]
|
|
! (5 ) D (REAL*8) : Assumed aerosol median diameter [um]
|
|
! (6 ) SIGMA (REAL*8) : Assumed aerosol standard deviation [um]
|
|
! (7 ) BVOL (REAL*8) : Box volume [m3]
|
|
! (8 ) ADJ_D
|
|
! (9 ) ADJ_NCONC
|
|
! (10) ADJ_MASS_DRY
|
|
!
|
|
! Output:
|
|
! ============================================================================
|
|
! (1 ) ADJ_D (just for diagnostic)
|
|
! (2 ) ADJ_MASS_DRY
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: MASS_WET
|
|
REAL*8, INTENT(IN) :: MASS_DRY_kg
|
|
REAL*8, INTENT(IN) :: DENSE_DRY
|
|
REAL*8, INTENT(IN) :: DENSE_WET
|
|
REAL*8, INTENT(IN) :: D
|
|
REAL*8, INTENT(IN) :: SIGMA
|
|
REAL*8, INTENT(IN) :: BVOL
|
|
|
|
! Adjoint arguments
|
|
REAL*8, INTENT(IN) :: ADJ_NCONC
|
|
REAL*8, INTENT(INOUT) :: ADJ_MASS_DRY
|
|
REAL*8, INTENT(INOUT) :: ADJ_D
|
|
|
|
! Local variables
|
|
REAL*8 :: DVM
|
|
REAL*8 :: DENSITY
|
|
REAL*8 :: VOLUME
|
|
REAL*8 :: MASS_TOTAL
|
|
REAL*8 :: MASS_DRY
|
|
REAL*8 :: NCONC
|
|
|
|
! Adjoint local variables
|
|
REAL*8 :: ADJ_DVM
|
|
REAL*8 :: ADJ_DENSITY
|
|
REAL*8 :: ADJ_VOLUME
|
|
REAL*8 :: ADJ_MASS_TOTAL
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: PI = 3.14159265358979324D0
|
|
|
|
!=================================================================
|
|
! ADJ_GET_NCONC begins here!
|
|
!=================================================================
|
|
|
|
! Recalculate first
|
|
|
|
! Convert mass units ( [kg/box] --> [ug/m3] )
|
|
MASS_DRY = MASS_DRY_kg * 1d9 / BVOL
|
|
|
|
! Get total mass
|
|
MASS_TOTAL = MASS_DRY + MASS_WET
|
|
|
|
IF ( MASS_TOTAL < 1d-20 ) THEN
|
|
print*, 'housten, we have a problem'
|
|
NCONC = 0d0 ! <-- this will cause LIDORT to give NANs
|
|
CALL ERROR_STOP( 'Aersol mass too small: 3',
|
|
& 'aero_optical_mod.f')
|
|
ENDIF
|
|
|
|
! Average density
|
|
! Also convert [g/cm3] --> [ug/cm3]
|
|
DENSITY = ( DENSE_DRY * MASS_DRY + DENSE_WET * MASS_WET )
|
|
& / ( MASS_TOTAL ) * 1d6
|
|
|
|
! Total volume [cm3/m3 air]
|
|
VOLUME = MASS_TOTAL / DENSITY
|
|
|
|
! Volume mean diameter can be calculated from the log-normal
|
|
! median diameter and the geometric standard deviation,
|
|
! see exercise 7.7 of S&P, 1998.
|
|
! Also convert units [um] --> [cm]
|
|
DVM = D * EXP( 1.5d0 * ( LOG( SIGMA ) )**2 ) * 1D-04
|
|
|
|
! fwd:
|
|
!NCONC = 6d0 * VOLUME / ( PI * DVM ** 3 ) * 1d-06
|
|
! adj:
|
|
ADJ_DVM = - 18d0 * VOLUME / ( PI * DVM ** 4 ) * 1d-06
|
|
& * ADJ_NCONC
|
|
ADJ_VOLUME = 6D0 / ( PI * DVM ** 3 ) * 1d-06
|
|
& * ADJ_NCONC
|
|
|
|
! fwd:
|
|
!DVM = D * EXP( 1.5d0 * ( LOG( SIGMA ) )**2 ) * 1D-04
|
|
! adj: (ADJ_D is an input with previous value)
|
|
ADJ_D = ADJ_D
|
|
& + ADJ_DVM * EXP( 1.5d0 * ( LOG( SIGMA ) )**2 ) * 1D-04
|
|
|
|
! fwd:
|
|
!VOLUME = MASS_TOTAL / DENSITY
|
|
! adj:
|
|
ADJ_MASS_TOTAL = ADJ_VOLUME / DENSITY
|
|
ADJ_DENSITY = - ADJ_VOLUME * MASS_TOTAL / DENSITY ** 2
|
|
|
|
! fwd:
|
|
!DENSITY = ( DENSE_DRY * MASS_DRY + DENSE_WET * MASS_WET )
|
|
! / ( MASS_TOTAL ) * 1d6
|
|
! adj: (ADJ_MASS_DRY is an input with previous value)
|
|
ADJ_MASS_DRY = ADJ_MASS_DRY
|
|
& + DENSE_DRY / MASS_TOTAL * 1D6 * ADJ_DENSITY
|
|
ADJ_MASS_TOTAL = ADJ_MASS_TOTAL
|
|
& - DENSITY / MASS_TOTAL * ADJ_DENSITY
|
|
|
|
! fwd:
|
|
!MASS_TOTAL = MASS_DRY + MASS_WET
|
|
! adj:
|
|
ADJ_MASS_DRY = ADJ_MASS_DRY + ADJ_MASS_TOTAL
|
|
|
|
! fwd:
|
|
!MASS_DRY = MASS_DRY_kg * 1d9 / BVOL
|
|
! adj:
|
|
ADJ_MASS_DRY = ADJ_MASS_DRY * 1d9 / BVOL
|
|
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE ADJ_GET_NCONC
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE ADJ_GET_WETD2( MASS_DRY_kg, MASS_WET, DENSE_DRY,
|
|
& DENSE_WET,
|
|
& NCONC, SIGMA, BVOL, ADJ_D,
|
|
& ADJ_MASS_WET, ADJ_MASS_DRY, ADJ_NCONC)
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine ADJ_GET_WETD2 computes ADJ_MASS_DRY, ADJ_MASS_WET and updates
|
|
! ADJ_NCONC
|
|
! (dkh, 02/22/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) MASS_DRY_kg (REAL*8) : Aerosol dry mass concentration [kg/box]
|
|
! (2 ) MASS_WET (REAL*8) : Aerosol water concentration [ug/m3]
|
|
! (3 ) DENSE_DRY (REAL*8) : Dry aerosol density [g/cm3]
|
|
! (4 ) DENSE_WET (REAL*8) : Wet aerosol density [g/cm3]
|
|
! (5 ) NCONC (REAL*8) : Number concentration [#/cm3]
|
|
! (6 ) SIGMA (REAL*8) : Assumed aerosol standard deviation [um]
|
|
! (7 ) BVOL (REAL*8) : Box volume [m3]
|
|
! (8 ) ADJ_D
|
|
! (9 ) ADJ_NCONC
|
|
!
|
|
! Output:
|
|
! ============================================================================
|
|
! (1 ) ADJ_MASS_WET
|
|
! (2 ) ADJ_MASS_WET
|
|
! (3 ) ADJ_NCONC
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: MASS_WET
|
|
REAL*8, INTENT(IN) :: MASS_DRY_kg
|
|
REAL*8, INTENT(IN) :: DENSE_DRY
|
|
REAL*8, INTENT(IN) :: DENSE_WET
|
|
REAL*8, INTENT(IN) :: NCONC
|
|
REAL*8, INTENT(IN) :: SIGMA
|
|
REAL*8, INTENT(IN) :: BVOL
|
|
|
|
! Adjoint arguments
|
|
REAL*8, INTENT(IN) :: ADJ_D
|
|
REAL*8, INTENT(OUT) :: ADJ_MASS_WET
|
|
REAL*8, INTENT(OUT) :: ADJ_MASS_DRY
|
|
REAL*8, INTENT(INOUT) :: ADJ_NCONC
|
|
|
|
! Local variables
|
|
REAL*8 :: D
|
|
REAL*8 :: DVM
|
|
REAL*8 :: DENSITY
|
|
REAL*8 :: VOLUME
|
|
REAL*8 :: MASS_TOTAL
|
|
REAL*8 :: MASS_DRY
|
|
|
|
! Local adjiont variables
|
|
REAL*8 :: ADJ_DVM
|
|
REAL*8 :: ADJ_DENSITY
|
|
REAL*8 :: ADJ_VOLUME
|
|
REAL*8 :: ADJ_MASS_TOTAL
|
|
|
|
! Parameters
|
|
REAL*8, PARAMETER :: PI = 3.14159265358979324D0
|
|
|
|
!=================================================================
|
|
! ADJ_GET_WETD2 begins here!
|
|
!=================================================================
|
|
|
|
! Recalculate VOLUME, MASS_TOTAL, DENSITY
|
|
! Convert mass units ( [kg/box] --> [ug/m3] )
|
|
MASS_DRY = MASS_DRY_kg * 1d9 / BVOL
|
|
|
|
! Get total mass
|
|
MASS_TOTAL = MASS_DRY + MASS_WET
|
|
|
|
IF ( MASS_TOTAL < 1d-20 ) THEN
|
|
print*, 'housten, we have a problem'
|
|
!NCONC = 0d0 ! <-- this will cause LIDORT to give NANs
|
|
CALL ERROR_STOP( 'Aersol mass too small 4',
|
|
& 'aero_optical_mod.f')
|
|
ENDIF
|
|
|
|
! Trap for small NCONC, as we multiply by 1/(NCONC^2) below
|
|
IF ( NCONC < 1d0 ) THEN
|
|
!print*, 'warning: NCONC low '
|
|
ADJ_MASS_WET = 0D0
|
|
ADJ_MASS_DRY = 0D0
|
|
RETURN
|
|
ENDIF
|
|
|
|
! Average density
|
|
! Also convert [g/cm3] --> [ug/cm3]
|
|
DENSITY = ( DENSE_DRY * MASS_DRY + DENSE_WET * MASS_WET )
|
|
& / ( MASS_TOTAL ) * 1d6
|
|
|
|
! Total volume [cm3/m3 air]
|
|
VOLUME = MASS_TOTAL / DENSITY
|
|
|
|
! Don't need to recalc D or DVM for adjoint
|
|
! fwd:
|
|
!D = DVM * 1d04 / ( EXP( 1.5d0 * ( LOG( SIGMA ) )**2 ) )
|
|
! adj:
|
|
ADJ_DVM = ADJ_D * 1d04 / ( EXP( 1.5d0 * ( LOG( SIGMA ) )**2 ) )
|
|
|
|
! fwd:
|
|
!DVM = ( 6d0 * VOLUME / ( PI * NCONC ) * 1d-06 ) ** (1.0/3.0)
|
|
! adj:
|
|
ADJ_VOLUME = 6d0 / ( PI * NCONC ) * 1d-06
|
|
& * 1.d0 / 3d0 * ( 6d0 * VOLUME / ( PI * NCONC ) * 1d-06)
|
|
& ** ( - 2.0/3.0) * ADJ_DVM
|
|
ADJ_NCONC = ( - 6d0 * VOLUME / ( PI * NCONC ** 2 ) * 1d-06 )
|
|
& * 1.d0 / 3d0 * ( 6d0 * VOLUME / ( PI * NCONC ) * 1d-06)
|
|
& ** ( - 2.0/3.0) * ADJ_DVM + ADJ_NCONC
|
|
|
|
! fwd:
|
|
!VOLUME = MASS_TOTAL / DENSITY
|
|
! adj:
|
|
ADJ_MASS_TOTAL = ADJ_VOLUME / DENSITY
|
|
ADJ_DENSITY = - VOLUME / DENSITY * ADJ_VOLUME
|
|
|
|
! fwd:
|
|
!DENSITY = ( DENSE_DRY * MASS_DRY + DENSE_WET * MASS_WET )
|
|
! / ( MASS_TOTAL ) * 1d6
|
|
! adj:
|
|
ADJ_MASS_DRY = DENSE_DRY / MASS_TOTAL * 1D6 * ADJ_DENSITY
|
|
ADJ_MASS_WET = DENSE_WET / MASS_TOTAL * 1D6 * ADJ_DENSITY
|
|
ADJ_MASS_TOTAL = ADJ_MASS_TOTAL
|
|
& - DENSITY / MASS_TOTAL * ADJ_DENSITY
|
|
|
|
! fwd:
|
|
!MASS_TOTAL = MASS_DRY + MASS_WET
|
|
! adj:
|
|
ADJ_MASS_DRY = ADJ_MASS_DRY + ADJ_MASS_TOTAL
|
|
ADJ_MASS_WET = ADJ_MASS_WET + ADJ_MASS_TOTAL
|
|
|
|
! fwd:
|
|
!MASS_DRY = MASS_DRY_kg * 1d9 / BVOL
|
|
! adj:
|
|
ADJ_MASS_DRY = ADJ_MASS_DRY * 1D9 / BVOL
|
|
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE ADJ_GET_WETD2
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE ADJ_MIE_LOOKUP( DIAM, W, NSP,
|
|
& NCONC,
|
|
& ADJ_NCONC, ADJ_DIAM, ADJ_BEXT, ADJ_SSA,
|
|
& ADJ_PHM,I,J,L )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine ADJ_MIE_LOOKUP
|
|
!
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) DIAM
|
|
! (2 ) W
|
|
! (3 ) NSP
|
|
! (4 ) NCONC
|
|
! (5 ) ADJ_BEXT
|
|
! (6 ) ADJ_SSA
|
|
! (7 ) ADJ_PHM
|
|
!
|
|
! Arguments as Input/Output:
|
|
! ============================================================================
|
|
! (1 ) ADJ_NCONC
|
|
! (2 ) ADJ_DIAM
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE MIE_MOD, ONLY : MIE_TABLE
|
|
USE MIE_MOD, ONLY : MIE_TABLE_PHM
|
|
USE MIE_MOD, ONLY : MIE_TABLE_ADJ
|
|
|
|
! dkh debug
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD
|
|
|
|
! Arguments
|
|
REAL*8, INTENT(IN) :: DIAM
|
|
INTEGER, INTENT(IN) :: W
|
|
INTEGER, INTENT(IN) :: NSP
|
|
INTEGER, INTENT(IN) :: L, I, J
|
|
REAL*8, INTENT(IN) :: NCONC
|
|
REAL*8, INTENT(INOUT) :: ADJ_NCONC
|
|
REAL*8, INTENT(INOUT) :: ADJ_DIAM
|
|
REAL*8, INTENT(IN) :: ADJ_BEXT
|
|
REAL*8, INTENT(IN) :: ADJ_SSA
|
|
REAL*8, INTENT(IN) :: ADJ_PHM(NPM_MAX)
|
|
|
|
! Local variables
|
|
REAL*8 :: N, BEXTT, RAD
|
|
REAL*8 :: ADJ_RAD
|
|
REAL*8 :: PHM_1(NPM_ACT), PHM_2(NPM_ACT)
|
|
REAL*8 :: R1, R2
|
|
REAL*8 :: DPHM_DR(NPM_ACT)
|
|
INTEGER :: N1, N2
|
|
REAL*8 :: SSA0
|
|
REAL*8 :: BEXT0
|
|
REAL*8 :: ADJ_BEXT0
|
|
REAL*8 :: ADJ_BEXTT
|
|
REAL*8 :: ADJ_SSA0
|
|
REAL*8 :: TEMP
|
|
|
|
! Parameters
|
|
!REAL*8, PARAMETER :: RNG = LOG(RMAX/RMIN) / REAL(NRA_MAX)
|
|
REAL*8 :: RNG
|
|
|
|
!=================================================================
|
|
! ADJ_MIE_LOOKUP begins here!
|
|
!=================================================================
|
|
|
|
|
|
|
|
! BUG FIX: need to calculated this separately for BC and SULF,
|
|
! as they have different size ranges and spacing in the lookup
|
|
! table. (dkh, 09/27/10)
|
|
RNG = LOG(RMAX(NSP)/RMIN(NSP)) / ( REAL(NRA_MAX) - 1d0 )
|
|
|
|
RAD = DIAM / 2D0
|
|
|
|
! Get index in MIE_TABLE that corresponds to current diameter.
|
|
! Diameters are calculated at NRA_MAX - 1 points between Dmin and
|
|
! Dmax with a spacing defined in ln space:
|
|
! d_n = d_min * exp( ( n - 1 ) * ln(d_max/d_min) / npts )
|
|
! The inverse of this formulat gives us the n for any d_n.
|
|
N = LOG(RAD/RMIN(NSP)) / RNG + 1
|
|
|
|
! Enforce bounds on this index
|
|
IF ( N < 1.0 ) N = 1.d0
|
|
IF ( N > REAL(NRA_MAX) ) N = REAL(NRA_MAX)
|
|
|
|
! recalculate BEXTT and BEXT0
|
|
BEXTT = MIE_TABLE(W,NSP,NOP_BEXT,INT(N))
|
|
BEXT0 = BEXTT * NCONC *1d-6
|
|
|
|
! recalculate SSA
|
|
SSA0 = MIE_TABLE(W,NSP,NOP_SSA,INT(N))
|
|
|
|
! Account for absorption enhancement
|
|
! fwd:
|
|
!IF ( NSP == NSP_BC ) THEN
|
|
! BEXT = BEXT0 * ( SSA + ABS_FAC * ( 1d0 - SSA ) )
|
|
! SSA = SSA0 / ( SSA + ABS_FAC * ( 1d0 - SSA ) )
|
|
!ENDIF
|
|
! adj:
|
|
IF ( NSP == NSP_BC ) THEN
|
|
|
|
! define this term to make equations simple
|
|
TEMP = SSA0 + ABS_FAC * ( 1d0 - SSA0 )
|
|
|
|
! SSA = SSA0 / ( SSA0 + ABS_FAC * ( 1d0 - SSA0 ) )
|
|
ADJ_SSA0 = ADJ_SSA * ABS_FAC / ( TEMP ** 2 )
|
|
|
|
! BEXT = BEXT0 * ( SSA0 + ABS_FAC * ( 1d0 - SSA0 ) )
|
|
ADJ_SSA0 = ADJ_SSA0
|
|
& + BEXT0 * ( 1 - ABS_FAC )
|
|
& * ADJ_BEXT
|
|
ADJ_BEXT0 = ADJ_BEXT * TEMP
|
|
|
|
ELSE
|
|
ADJ_SSA0 = ADJ_SSA
|
|
ADJ_BEXT0 = ADJ_BEXT
|
|
ENDIF
|
|
|
|
! Contribution from ADJ_PHM
|
|
! Use values from table to get the derivative of PHM w.r.t. R
|
|
! using finite differencing.
|
|
IF ( INT(N+1) > NRA_MAX) THEN
|
|
N1 = INT(N-1)
|
|
N2 = INT(N)
|
|
ELSEIF (INT(N-1) < 1 ) THEN
|
|
N1 = INT(N)
|
|
N2 = INT(N+1)
|
|
ELSE
|
|
N1 = INT(N-1)
|
|
N2 = INT(N+1)
|
|
ENDIF
|
|
|
|
PHM_1(1:NPM_ACT) = MIE_TABLE_PHM(W,NSP,N1,1:NPM_ACT)
|
|
PHM_2(1:NPM_ACT) = MIE_TABLE_PHM(W,NSP,N2,1:NPM_ACT)
|
|
R1 = RMIN(NSP) * EXP( RNG ) ** N1
|
|
R2 = RMIN(NSP) * EXP( RNG ) ** N2
|
|
DPHM_DR(:) = ( PHM_2(:) - PHM_1(:) ) / ( R2 - R1 )
|
|
ADJ_RAD = SUM(DPHM_DR(:) * ADJ_PHM(1:NPM_ACT) )
|
|
|
|
! dkh debug
|
|
!print*, ' DIAM, N, BEXTT, BEXT = ', DIAM, N, BEXTT, BEXT
|
|
|
|
! Contribution from ADJ_SSA
|
|
! fwd:
|
|
!IF ( NSP == NSP_SULF ) THEN
|
|
! SSA = 1d0 ! for sulfate
|
|
!ELSE
|
|
! SSA = MIE_TABLE(W,NSP,NOP_SSA,INT(N))
|
|
!ENDIF
|
|
! adj:
|
|
IF ( NSP == NSP_SULF ) THEN
|
|
ADJ_RAD = ADJ_RAD + 0D0
|
|
ELSE
|
|
|
|
!-----------------------------------------------------------------
|
|
! BUG_FIX: use FD sensitivities instead of table. (dkh, 03/27/11)
|
|
! BUG_FIX: use table instead of FD (dkh, 07/01/11)
|
|
ADJ_RAD = ADJ_RAD + MIE_TABLE_ADJ(W,NSP,NOP_SSA,INT(N))
|
|
& * ADJ_SSA0
|
|
! OLD:
|
|
!ADJ_RAD = ADJ_RAD
|
|
! + (MIE_TABLE(W,NSP,NOP_SSA,N2) - MIE_TABLE(W,NSP,NOP_SSA,N1))
|
|
! / ( R2 - R1 ) * ADJ_SSA0
|
|
!-----------------------------------------------------------------
|
|
|
|
ENDIF
|
|
|
|
|
|
! fwd:
|
|
!BEXT0 = BEXTT * NCONC * 1d-6
|
|
! adj:
|
|
ADJ_BEXTT = NCONC * ADJ_BEXT0 * 1d-6
|
|
ADJ_NCONC = ADJ_NCONC + BEXTT * ADJ_BEXT0 * 1d-6
|
|
|
|
! Contribution from ADJ_BEXT
|
|
! fwd:
|
|
! BEXTT = MIE_TABKE(W,NSP,NOP_BEXT,INT(N))
|
|
! adj:
|
|
!-----------------------------------------------------------------
|
|
! BUG_FIX: use FD sensitivities instead of table. (dkh, 03/27/11)
|
|
! BUG_FIX: use table instead of FD. (dkh, 07/01/11)
|
|
ADJ_RAD = ADJ_RAD + MIE_TABLE_ADJ(W,NSP,NOP_BEXT,INT(N))
|
|
& * ADJ_BEXTT
|
|
!ADJ_RAD = ADJ_RAD
|
|
! + (MIE_TABLE(W,NSP,NOP_BEXT,N2) - MIE_TABLE(W,NSP,NOP_BEXT,N1))
|
|
! / ( R2 - R1 ) * ADJ_BEXTT
|
|
!-----------------------------------------------------------------
|
|
|
|
|
|
! fwd:
|
|
!RAD = DIAM / 2D0
|
|
! adj:
|
|
ADJ_DIAM = ADJ_DIAM + ADJ_RAD / 2D0
|
|
|
|
! dkh debug
|
|
!ADJ_DIAM = 0d0
|
|
! this works. somehow there is a connection between ADJ_DIAM and
|
|
! ADJ_STT in this situation, but not a connection between STT and DIAM!
|
|
|
|
! dkh debug
|
|
!IF ( W == 3 .and. L == LFD .and. NSP == 2 .and.
|
|
! I == IFD .and. J == JFD ) THEN
|
|
! print*, ' adj: BEXTT = ', BEXTT
|
|
! print*, ' adj: BEXT0 = ', BEXT0
|
|
! print*, ' adj: NCONC = ', NCONC
|
|
! print*, ' adj: SSA0 = ', SSA0
|
|
! print*, ' adj: N = ', N, INT(N)
|
|
!
|
|
! print*, ' adj: ADJ_BEXT = ', ADJ_BEXT
|
|
! print*, ' adj: ADJ_BEXT0 = ', ADJ_BEXT0
|
|
! print*, ' adj: ADJ_BEXTT = ', ADJ_BEXTT
|
|
!
|
|
! print*, ' adj: ADJ_NCONC = ', ADJ_NCONC
|
|
! print*, ' adj: ADJ_DIAM = ', ADJ_DIAM
|
|
!
|
|
!ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE ADJ_MIE_LOOKUP
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE PREPARE_PHYSICS_GC_IJ( I, J, PRESSURE_GRID,
|
|
& TEMPERATURE_GRID, HEIGHT_GRID, AIRDENS, GAS_PROFILE, BEAM_SZAS )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine PREPARE_PHYSICS_GC_IJ sets lidort inputs that depend only
|
|
! on lat and lon. (dkh, 03/03/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) I (INTEGER) : Lon [unit]
|
|
! (2 ) J (INTEGER) : Lat [unit]
|
|
!
|
|
! Variables as Output:
|
|
! ============================================================================
|
|
! (2 ) PRESSURE_GRID
|
|
! (3 ) AIRDENS
|
|
! (4 ) TEMPERATURE_GRID
|
|
! (5 ) GAS_PROFILE
|
|
! (6 ) NLAYERS
|
|
! (7 ) NMOMENTS_INPUT
|
|
! (8 ) HEIGHT_GRID
|
|
!
|
|
! NOTES:
|
|
! (1 ) This is based upon the jactest_3p3_solar2.f driver provided with
|
|
! LIDORT by R. Spurr. Original code is lower case.
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE ADJ_ARRAYS_MOD, ONLY : O3_PROF_SAV
|
|
USE COMODE_MOD, ONLY : CSPEC, JLOP
|
|
USE DAO_MOD, ONLY : AIRDEN, TS, T
|
|
USE DAO_MOD, ONLY : SUNCOS, BXHEIGHT
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE PRESSURE_MOD, ONLY : GET_PEDGE
|
|
USE TRACERID_MOD, ONLY : IDO3
|
|
|
|
# include "cmn_fj.h" ! FJ sizes, need for jv_cmn, CMN_SIZE
|
|
# include "jv_cmn.h" ! DO3
|
|
# include "CMN_GCTM" ! Rdg0
|
|
|
|
! Arguments
|
|
INTEGER :: I, J
|
|
REAL(KIND=8) :: HEIGHT_GRID ( 0:MAXLAYERS )
|
|
REAL(KIND=8) :: PRESSURE_GRID ( 0:MAXLAYERS )
|
|
REAL(KIND=8) :: TEMPERATURE_GRID ( 0:MAXLAYERS )
|
|
REAL(KIND=8) :: AIRDENS ( 1:MAXLAYERS )
|
|
REAL(KIND=8) :: GAS_PROFILE ( 1:MAXLAYERS )
|
|
REAL(KIND=8) :: BEAM_SZAS ( MAXBEAMS )
|
|
|
|
|
|
! Local variables
|
|
INTEGER :: L, N, JLOOP, IJLOOP
|
|
REAL*8 :: SS_ZLEVELS( 0: LLPAR )
|
|
|
|
! XNUMOL_AIR: (molecules air / kg air)
|
|
REAL*8, PARAMETER :: XNUMOLAIR = 6.022d+23 / 0.02897d0
|
|
|
|
!=================================================================
|
|
! PREPARE_PHYSICS_GC_IJ begins here!
|
|
!=================================================================
|
|
|
|
! Get model top pressure [hPa]. Can't access directly from CMN_SIZE,
|
|
! since we have to use the cmn_fj.h rather than CMN_SIZE.
|
|
PRESSURE_GRID(0) = GET_PEDGE(I,J,LLPAR+1)
|
|
|
|
! Get layer input.
|
|
DO L = 1, LLPAR
|
|
|
|
! N starts with 0=TOA. L = 1 is the ground.
|
|
N = LLPAR - L + 1
|
|
|
|
! pressures [hPa] (not used)
|
|
PRESSURE_GRID(N) = GET_PEDGE(I,J,L)
|
|
|
|
IF ( L == 1 ) THEN
|
|
SS_ZLEVELS(N) = 0d0 !or altitude?
|
|
|
|
! temperature at surface [k]
|
|
TEMPERATURE_GRID(N) = TS(I,J)
|
|
|
|
ELSE
|
|
|
|
! temperature at lower edge [k] ( T is mid-layere temp).
|
|
TEMPERATURE_GRID(N) = 0.5d0 * ( T(I,J,L) + T(I,J,L-1) )
|
|
|
|
! heights of lower layer boundaries [km]
|
|
SS_ZLEVELS(N) = SS_ZLEVELS(N+1)
|
|
& + Rdg0 * 1d-3 * T(I,J,L-1)
|
|
& * LOG( PRESSURE_GRID(N+1)
|
|
& / PRESSURE_GRID(N) )
|
|
ENDIF
|
|
|
|
! air density [molec/cm3], convert from [kg/m3].
|
|
! NOTE: AIRDEN index is (L, I, J), not the usual (I, J, L)
|
|
AIRDENS(N) = AIRDEN(L,I,J) * XNUMOLAIR / 1d6
|
|
|
|
! Gas VMR [DU]
|
|
IF ( L <= LLTROP ) THEN
|
|
|
|
! Get 1-D array index for extracting O3 from CSPEC
|
|
JLOOP = JLOP(I,J,L)
|
|
|
|
! Get O3 from CSPEC within the troposphere
|
|
! and convert from [#/cm3] --> [DU]
|
|
IF ( JLOOP > 0 )
|
|
& GAS_PROFILE(N) = CSPEC(JLOOP,IDO3)
|
|
& * BXHEIGHT(I,J,L) * 100d0
|
|
& * 3.7219d-17
|
|
|
|
! Otherwise get O3 from FAST-J (scaled climatology)
|
|
ELSE
|
|
|
|
! Convert from [#/cm2] --> [DU]
|
|
GAS_PROFILE(N) = O3_PROF_SAV(I,J,L) * 3.7219d-17
|
|
|
|
ENDIF
|
|
|
|
! dkh debug
|
|
IF ( I == 61 .and. J == 32 ) THEN
|
|
print*, 'GAS_PROF = ', GAS_PROFILE(N), L, N
|
|
ENDIF
|
|
|
|
ENDDO
|
|
|
|
! top of atmosphere in [km]
|
|
SS_ZLEVELS(0) = SS_ZLEVELS(1)
|
|
& + Rdg0 * 1d-3 * T(I,J,LLPAR)
|
|
& * LOG( PRESSURE_GRID(1) / GET_PEDGE(I,J,LLPAR+1) )
|
|
|
|
|
|
! Set LIDORT number of layers and Legendre moments
|
|
nlayers = LLPAR
|
|
nmoments_input = NPM_MAX
|
|
|
|
! Set LIDORT height grid for pseudo-spherical treatment
|
|
DO n = 0, nlayers
|
|
height_grid(n) = ss_zlevels(n)
|
|
END DO
|
|
|
|
! note: probably don't need these error checking and
|
|
! calculation of X0 and SX0 -- it's redundant (dkh, 01/19/10)
|
|
! Set solar zenith angle and associated quantities
|
|
! note: this overwrites the values in the lidort input file *.inp
|
|
IJLOOP = ( J - 1 ) * IIPAR + I
|
|
BEAM_SZAS(1) = ACOS( SUNCOS(IJLOOP) )
|
|
! IF ( BEAM_SZAS(1) .LT. ZERO .OR.
|
|
! & BEAM_SZAS(1) .GE. 90.0D0 ) THEN
|
|
! CALL ERROR_STOP('LIDORT: bad input: out-of-range beam',
|
|
! & 'lidort_mod.f' )
|
|
! ENDIF
|
|
! X0(1) = DCOS( BEAM_SZAS(1) )
|
|
! SX0(1) = DSQRT( ONE - X0(1) * X0(1) )
|
|
|
|
! dkh debug
|
|
IF ( L_PRINT ) THEN
|
|
print*, 'test at cell i61, j32 with zenith angle = ',
|
|
& BEAM_SZAS(1)
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE PREPARE_PHYSICS_GC_IJ
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE PREPARE_PHYSICS_GC_IJW
|
|
& ( TR, epsfac, npert,
|
|
& status, AIRDENS, GAS_PROFILE,
|
|
& LAMBERTIAN_ALBEDO, OMEGA_TOTAL_INPUT, DELTAU_VERT_INPUT,
|
|
& PHASMOMS_TOTAL_INPUT, L_OMEGA_TOTAL_INPUT, L_DELTAU_VERT_INPUT,
|
|
& L_PHASMOMS_TOTAL_INPUT, I, J, W )
|
|
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine PREPARE_PHYSICS_GC_IJW sets physics that depends upon lat, lon
|
|
! and wavelength. (dkh, 03/03/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) ARG (TYPE) : Description [unit]
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) ARG (TYPE) : Description [unit]
|
|
!
|
|
! NOTES:
|
|
! (1 ) This is based upon the jactest_3p3_solar2.f driver provided with
|
|
! LIDORT by R. Spurr. Original code is lower case.
|
|
! (2 ) Updated to 3p5 (dkh, 07/29/10)
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE UVALBEDO_MOD, ONLY : UVALBEDO
|
|
USE ADJ_ARRAYS_MOD, ONLY : IFD, JFD, LFD, NFD
|
|
|
|
! --------------------
|
|
! LIDORT Include files
|
|
! --------------------
|
|
# include "CMN_SIZE" ! LLPAR
|
|
|
|
! arguments
|
|
LOGICAL status
|
|
INTEGER :: TR
|
|
INTEGER :: npert
|
|
DOUBLE PRECISION :: epsfac
|
|
REAL(KIND=8) :: AIRDENS ( 1:MAXLAYERS )
|
|
REAL(KIND=8) :: GAS_PROFILE ( 1:MAXLAYERS )
|
|
|
|
! Added for GC implementation
|
|
INTEGER :: I, J, W
|
|
|
|
! -----------------------
|
|
! LIDORT inputs. Local, single threaded version.
|
|
! -----------------------
|
|
REAL(KIND=8) :: OMEGA_TOTAL_INPUT ( MAXLAYERS )
|
|
REAL(KIND=8) :: DELTAU_VERT_INPUT ( MAXLAYERS )
|
|
|
|
! Phase function Legendre-polynomial expansion coefficients
|
|
! Include all that you require for exact single scatter calculations
|
|
REAL(KIND=8) :: PHASMOMS_TOTAL_INPUT
|
|
& ( 0:MAXMOMENTS_INPUT, MAXLAYERS )
|
|
|
|
! Optical property linearizations
|
|
! Layer linearization (bulk property variation) input
|
|
! Layer linearization (phase function variation) input
|
|
REAL(KIND=8)
|
|
& :: L_OMEGA_TOTAL_INPUT(MAX_ATMOSWFS,MAXLAYERS)
|
|
REAL(KIND=8)
|
|
& :: L_DELTAU_VERT_INPUT(MAX_ATMOSWFS,MAXLAYERS)
|
|
REAL(KIND=8)
|
|
& :: L_PHASMOMS_TOTAL_INPUT ( MAX_ATMOSWFS,0:MAXMOMENTS_INPUT,
|
|
& MAXLAYERS)
|
|
|
|
! Lambertian Surface control
|
|
REAL(KIND=8) :: LAMBERTIAN_ALBEDO
|
|
|
|
! Local physics storage
|
|
! ---------------------
|
|
double precision gasvods(NWL_MAX)
|
|
double precision lambdas(NWL_MAX)
|
|
double precision rayleigh_xsec(NWL_MAX)
|
|
double precision rayleigh_depol(NWL_MAX)
|
|
double precision local_albedo(NWL_MAX)
|
|
double precision gas_xsec(NWL_MAX,LLPAR)
|
|
double precision aerosol_deltaus(NWL_MAX,LLPAR)
|
|
double precision aerosol_ssalbs(NWL_MAX,LLPAR)
|
|
double precision
|
|
& aerosol_phasmoms(NWL_MAX,LLPAR,0:NPM_MAX)
|
|
|
|
! other local variables
|
|
INTEGER n, l, nd, ut, uta, k, ll
|
|
double precision aermom,raymom,depol,rayxs,tempdummy,agas,dummy
|
|
double precision scatmom_1, scatmom_2, scatmom_l, deltau, taue_aer
|
|
double precision tg,taua_gas,taue_mol,taus_ray,taus_aer,taus_total
|
|
double precision du_to_cm2, baer, waer, vaer, saer
|
|
|
|
double precision gascc, taua_gas0, taua_gas_eps, nx, sum1, sum0
|
|
|
|
!----------------------------------------------------------------
|
|
! Data
|
|
!----------------------------------------------------------------
|
|
|
|
! MOVE TO MODULE HEADER
|
|
! O3 absorption cross section [unit]
|
|
! Data is take from
|
|
! 315nm: Burrows et al., 1999, Fig 4
|
|
! 357nm: Voigt et al., 2001, Fig 5 (@ 246 K)
|
|
! 500nm: Voigt et al., 2001, Fig 2
|
|
! 833nm: Voigt et al., 2001, Fig 2 (ave)
|
|
! 1667nm: Bogumil et al., 2003, Fig 1
|
|
REAL*8 :: O3_XSEC_TABLE(NWL_MAX)
|
|
DATA O3_XSEC_TABLE / 4d-20, 7d-23,
|
|
& 1d-21, 7d-23,
|
|
& 0d0 /
|
|
|
|
! Rayleigh
|
|
! from Bodhaine et al., 1999, Table 3
|
|
! Linearly interpolate. Values at 1667 nm are just a guess.
|
|
REAL*8 :: RAY_XSEC_TABLE(NWL_MAX)
|
|
DATA RAY_XSEC_TABLE / 4.5830d-26, 2.700d-26,
|
|
& 6.6614d-27, 8.380d-27,
|
|
& 0d0 /
|
|
REAL*8 :: RAY_DEPOL_TABLE(NWL_MAX)
|
|
DATA RAY_DEPOL_TABLE / 1.05521d0, 1.05280d0,
|
|
& 1.04935d0, 1.04750d0,
|
|
& 1d0 /
|
|
|
|
!=================================================================
|
|
! PREPARE_PHYSICS_GC_IJW begins here!
|
|
!=================================================================
|
|
|
|
! Initialise
|
|
taua_gas_eps = 0.0d0
|
|
|
|
! Conversion, Dobson units to mol/cm/cm
|
|
du_to_cm2 = 2.68668d+16
|
|
|
|
! Wavelengths [nm]
|
|
LAMBDAS(W) = LAMBDA_TABLE(W)
|
|
|
|
!NOTE: the three quantities below are wavelength dependent at
|
|
! the very least.
|
|
|
|
! Local albedo
|
|
! from Martin et al., 2004
|
|
! depnds on season. should also depend on location?
|
|
! The GC albedo used for FAST-J depends on season and
|
|
! location, but is for 340-380 nm
|
|
!LOCAL_ALBEDO(W) = UVALBEDO(I,J)
|
|
LOCAL_ALBEDO(W) = TEMIS_LER(I,J,W)
|
|
|
|
! These two also depend slightly on CO2
|
|
! Rayleigh X-section
|
|
RAYLEIGH_XSEC(W) = RAY_XSEC_TABLE(W) ! 6.6614d-27
|
|
|
|
! Rayleigh depolarization ratio
|
|
RAYLEIGH_DEPOL(W) = RAY_DEPOL_TABLE(W) ! 1.04935
|
|
|
|
! Define the following properties:
|
|
! Trace gas absorption cross-section, in cm^2/mol.
|
|
! aerosol extinction optical depth,
|
|
! aerosol single scattering albedo,
|
|
! aerosol phase function Legendre expansion coeffs..
|
|
|
|
! Vertical loop. L is 1 at surface, N is 1 at top.
|
|
DO N = 1 , LLPAR
|
|
|
|
L = LLPAR - N + 1
|
|
|
|
! Trace gas absorption cross-section [cm2/mol]
|
|
GAS_XSEC(W,N) = O3_XSEC_TABLE(W)
|
|
|
|
! Aerosol extinction optical depth
|
|
AEROSOL_DELTAUS(W,N) = LAYER_AOD(I,J,L,W)
|
|
|
|
! Aerosol single scattering albedoes
|
|
AEROSOL_SSALBS(W,N) = LAYER_SSA(I,J,L,W)
|
|
|
|
! Aerosol phase function Legendre expansion coeffs
|
|
AEROSOL_PHASMOMS(W,N,1:NPM_MAX) =
|
|
& LAYER_PHM(I,J,L,1:NPM_MAX,W)
|
|
|
|
|
|
ENDDO
|
|
|
|
! The zeroeth order PHM is always 1.d0
|
|
!note: this is redundant, as the lidort zeroeth order input is hardwired to 1d0
|
|
! below
|
|
AEROSOL_PHASMOMS(:,:,0) = 1d0
|
|
|
|
! dkh debug
|
|
!IF ( I == 61 .AND. J == 32 .and. W == 3 ) THEN
|
|
IF ( I == IFD .AND. J == JFD .and. W == 3 ) THEN
|
|
WRITE(*,'(3i5)'), LLPAR, NPM_MAX, 1
|
|
! WRITE(*,'(1pe15.7)') SS_ZLEVELS(0)
|
|
! WRITE(*,'(1p5e15.7)') (SS_ZLEVELS(N),PRESSURE(N),
|
|
! & TEMPERATURE(N), AIRDENS(N),
|
|
! & GAS_PROFILE(N),N=1,LLPAR)
|
|
WRITE(*,'(2f12.5,1p2e15.6)') LAMBDAS(NWL_500),
|
|
& LOCAL_ALBEDO(NWL_500),
|
|
& RAYLEIGH_XSEC(NWL_500), RAYLEIGH_DEPOL(NWL_500)
|
|
WRITE(*,'(1p24e15.5)') (GAS_XSEC(NWL_500,N),
|
|
& AEROSOL_DELTAUS(NWL_500,N),
|
|
& AEROSOL_SSALBS(NWL_500,N),
|
|
& AEROSOL_PHASMOMS(NWL_500,N,0:NPM_MAX),
|
|
& n=1,LLPAR)
|
|
print*, 'ok done' , NPM_MAX
|
|
ENDIF
|
|
|
|
! Surface albedo. (This may be overwritten)
|
|
! Will only be used if the Lambertian surface flag is set
|
|
lambertian_albedo = local_albedo(w)
|
|
IF ( TR == 5 ) lambertian_albedo = lambertian_albedo * epsfac
|
|
|
|
! Rayleigh: Depolarization ratio and second phase function moment
|
|
depol = rayleigh_depol(w)
|
|
rayxs = rayleigh_xsec(w)
|
|
raymom = ( 1.0d0 - depol ) / ( 2.0d0 + depol )
|
|
|
|
! initialise total atmsopheric optical depth for gas
|
|
gasvods(w) = 0.0
|
|
|
|
! start layer loop
|
|
DO n = 1, LLPAR
|
|
|
|
! optical depth due to Rayleigh scattering
|
|
taus_ray = rayxs * airdens(n)
|
|
|
|
! Trace gas layer column amount
|
|
taua_gas = 0.0d0
|
|
gascc = gas_profile(n)
|
|
|
|
! Trace gas absoprtion optical thickness
|
|
tg = gascc * gas_xsec(w,n)
|
|
tg = du_to_cm2 * tg
|
|
taua_gas = taua_gas + tg
|
|
gasvods(w) = gasvods(w) + tg
|
|
|
|
! Make a finite difference perturbation if flagged
|
|
if ( n == npert .and. TR == 2 ) then
|
|
taua_gas = taua_gas * epsfac
|
|
endif
|
|
|
|
|
|
|
|
! ! debug code (ignore)
|
|
! taua_gas0 = gas_profile(n)*du_to_cm2*gas_xsec(w,n)
|
|
! if (n.eq.npert.and.wq.eq.1)taua_gas_eps = taua_gas - taua_gas0
|
|
|
|
! Trace gas absoprtion + Rayleigh scattering optical depth
|
|
taue_mol = taus_ray + taua_gas
|
|
|
|
! aerosol optical thickness for extinction
|
|
taue_aer = aerosol_deltaus(w,n)
|
|
|
|
! Make a finite difference perturbation if flagged
|
|
if ( n == npert .and. TR == 3 ) taue_aer = taue_aer * epsfac
|
|
if ( n == npert .and. TR == 4 ) taue_aer = taue_aer * epsfac
|
|
|
|
! total optical thickness for layer. Set the LIDORT input
|
|
deltau = taue_aer + taue_mol
|
|
|
|
! if ( n == 21 )print*, 'deltau, taue_aer, taue_mol',
|
|
! & deltau, taue_aer, taue_mol,TR
|
|
|
|
deltau_vert_input(n) = deltau
|
|
|
|
! Derivative factors for computing linearized inputs
|
|
agas = taua_gas / deltau
|
|
vaer = taue_aer / deltau
|
|
|
|
! aerosol scattering optical depth
|
|
taus_aer = aerosol_ssalbs(w,n) * taue_aer
|
|
|
|
! total scattering optical depth
|
|
taus_total = taus_ray + taus_aer
|
|
|
|
! total single scattering albedo. Set the LIDORT input
|
|
omega_total_input(n) = taus_total / deltau
|
|
|
|
! Toggle the SS albedo if near to one
|
|
! (actually not required with this data set)
|
|
IF (omega_total_input(n) .gt. 0.9999 ) THEN
|
|
omega_total_input(n) = 0.9999
|
|
ENDIF
|
|
|
|
! some additional ratios for computing the linearized inputs
|
|
waer = aerosol_ssalbs(w,n) / omega_total_input(n)
|
|
saer = taus_aer / taus_total
|
|
|
|
! phase function: Zeroth moment = 1
|
|
phasmoms_total_input(0,n) = 1.0D0
|
|
|
|
! phase function first moment
|
|
scatmom_1 = taus_aer * aerosol_phasmoms(w,n,1)
|
|
phasmoms_total_input(1,n) = scatmom_1 / taus_total
|
|
|
|
! phase function second moment (include Rayleigh):
|
|
aermom = aerosol_phasmoms(w,n,2)
|
|
scatmom_2 = taus_ray * raymom + taus_aer * aermom
|
|
phasmoms_total_input(2,n) = scatmom_2 / taus_total
|
|
|
|
! phase function moments > 2:
|
|
DO l = 3, NPM_MAX
|
|
aermom = aerosol_phasmoms(w,n,l)
|
|
scatmom_l = taus_aer * aermom
|
|
phasmoms_total_input(l,n) = scatmom_l / taus_total
|
|
ENDDO
|
|
|
|
! Linearization inputs if a Linearization Calculation is required
|
|
!if ( dowf ) then
|
|
layer_vary_flag(n) = .true.
|
|
! (dkh, 04/04/08)
|
|
!layer_vary_number(n) = 2
|
|
layer_vary_number(n) = MAX_ATMOSWFS
|
|
l_deltau_vert_input(1,n) = + agas
|
|
l_omega_total_input(1,n) = - agas
|
|
l_deltau_vert_input(2,n) = + vaer
|
|
l_omega_total_input(2,n) = + vaer * ( waer - one )
|
|
l_phasmoms_total_input(1,0,n) = zero
|
|
l_phasmoms_total_input(2,0,n) = zero
|
|
do l = 1, NPM_MAX
|
|
l_phasmoms_total_input(1,l,n) = zero
|
|
baer = aerosol_phasmoms(w,n,l)/phasmoms_total_input(l,n)
|
|
l_phasmoms_total_input(2,l,n) = saer * ( baer - one )
|
|
enddo
|
|
!endif
|
|
|
|
! (dkh, 04/03/08)
|
|
! w.r.t. aerosol_ssalb
|
|
l_deltau_vert_input(3,n) = zero
|
|
l_omega_total_input(3,n) = + saer
|
|
l_phasmoms_total_input(3,0,n) = zero
|
|
do l = 1, NPM_MAX
|
|
baer = aerosol_phasmoms(w,n,l)/phasmoms_total_input(l,n)
|
|
l_phasmoms_total_input(3,l,n) = saer * ( baer - one )
|
|
enddo
|
|
|
|
! (dkh, 04/04/08)
|
|
! w.r.t. aerosol_phasmoms
|
|
!l_deltau_vert_input(4,n) = zero
|
|
!l_omega_total_input(4,n) = zero
|
|
!l_phasmoms_total_input(4,0,n) = zero
|
|
!do l = 1, NPM_MAX
|
|
! baer = aerosol_phasmoms(w,n,l)/phasmoms_total_input(l,n)
|
|
! l_phasmoms_total_input(4,l,n) = saer * baer
|
|
!enddo
|
|
l_deltau_vert_input(4:MAX_ATMOSWFS,n) = zero
|
|
l_omega_total_input(4:MAX_ATMOSWFS,n) = zero
|
|
l_phasmoms_total_input(4:MAX_ATMOSWFS,:,n) = zero
|
|
do ll = 4, MAX_ATMOSWFS
|
|
l = ll - 3
|
|
baer = aerosol_phasmoms(w,n,l)/phasmoms_total_input(l,n)
|
|
l_phasmoms_total_input(ll,l,n) = saer * baer
|
|
enddo
|
|
|
|
|
|
! ! No linearization required, just zero the inputs
|
|
! if ( .not. dowf ) then
|
|
! layer_vary_flag(n) = .false.
|
|
! layer_vary_number(n) = 0
|
|
! l_deltau_vert_input(1,n,TR) = zero
|
|
! l_omega_total_input(1,n,TR) = zero
|
|
! l_deltau_vert_input(2,n,TR) = zero
|
|
! l_omega_total_input(2,n,TR) = zero
|
|
! ! (dkh, 04/04/08)
|
|
! l_deltau_vert_input(3:MAX_ATMOSWFS,n,TR) = zero
|
|
! l_omega_total_input(3:MAX_ATMOSWFS,n,TR) = zero
|
|
! do l = 0, NPM_MAX
|
|
! l_phasmoms_total_input(1,l,n,TR) = zero
|
|
! l_phasmoms_total_input(2,l,n,TR) = zero
|
|
! ! (dkh, 04/04/08)
|
|
! l_phasmoms_total_input(3:MAX_ATMOSWFS,l,n,TR) = zero
|
|
! enddo
|
|
! endif
|
|
|
|
! End layer loop
|
|
END DO
|
|
|
|
!! thermal BB input.
|
|
!C Read pre-prepared BB functions
|
|
!
|
|
! OPEN(45,file='testbb.dat',status='old')
|
|
! read(45,*)dummy,dummy
|
|
! DO n = 0, nlayers
|
|
! READ(45,'(i2,f9.3,1pe18.8)')nd,tempdummy,thermal_bb_input(n)
|
|
! END DO
|
|
! READ(45,'(2x,f9.3,1pe18.8)')tempdummy,surfbb
|
|
! CLOSE(45)
|
|
|
|
! normal return for this routine
|
|
status = .false.
|
|
RETURN
|
|
|
|
! error return for this routine
|
|
400 CONTINUE
|
|
status = .TRUE.
|
|
RETURN
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE PREPARE_PHYSICS_GC_IJW
|
|
|
|
!----------------------------------------------------------------------
|
|
|
|
SUBROUTINE MAKE_AOD_FILE( YYYYMMDD, HHMMSS, N_CALC )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine MAKE_AOD_FILE saves average AOD (dkh, 01/24/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) YYYYMMDD (INTEGER) : Date of average [unit]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE BPCH2_MOD
|
|
USE DAO_MOD, ONLY : SUNCOS
|
|
USE DIRECTORY_ADJ_MOD, ONLY : DIAGADJ_DIR
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE GRID_MOD, ONLY : GET_XOFFSET, GET_YOFFSET
|
|
USE TIME_MOD, ONLY : GET_TAU, EXPAND_DATE
|
|
|
|
# include "CMN_SIZE" ! Size params
|
|
|
|
! Arguments
|
|
INTEGER :: YYYYMMDD
|
|
INTEGER :: HHMMSS
|
|
INTEGER, INTENT(IN) :: N_CALC
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, I0, J0, L, W
|
|
CHARACTER(LEN=120) :: FILENAME
|
|
REAL*4 :: DAT(IIPAR,JJPAR,LLPAR)
|
|
REAL*4 :: TEMP
|
|
|
|
! For binary punch file, version 2.0
|
|
CHARACTER(LEN=20) :: MODELNAME
|
|
CHARACTER(LEN=40) :: CATEGORY
|
|
CHARACTER(LEN=40) :: UNIT
|
|
CHARACTER(LEN=40) :: RESERVED = ''
|
|
CHARACTER(LEN=80) :: TITLE
|
|
REAL*4 :: LONRES, LATRES
|
|
INTEGER, PARAMETER :: HALFPOLAR = 1
|
|
INTEGER, PARAMETER :: CENTER180 = 1
|
|
|
|
!=================================================================
|
|
! MAKE_AOD_FILE begins here!
|
|
!=================================================================
|
|
DAT(:,:,:) = 0d0
|
|
|
|
FILENAME = TRIM( 'aod.YYYYMMDD.hhmm.NN' )
|
|
|
|
CALL EXPAND_DATE( FILENAME, YYYYMMDD, HHMMSS)
|
|
|
|
! Append the iteration number suffix to the file name
|
|
CALL EXPAND_NAME( FILENAME, N_CALC )
|
|
|
|
! Append data directory prefix
|
|
FILENAME = TRIM( DIAGADJ_DIR ) // TRIM( FILENAME )
|
|
|
|
! Define variables for BINARY PUNCH FILE OUTPUT
|
|
TITLE = 'Average AOD data file '
|
|
CATEGORY = 'IJ-AOD-$'
|
|
LONRES = DISIZE
|
|
LATRES = DJSIZE
|
|
UNIT = 'none'
|
|
|
|
! Call GET_MODELNAME to return the proper model name for
|
|
! the given met data being used (bmy, 6/22/00)
|
|
MODELNAME = GET_MODELNAME()
|
|
|
|
! Get the nested-grid offsets
|
|
I0 = GET_XOFFSET( GLOBAL=.TRUE. )
|
|
J0 = GET_YOFFSET( GLOBAL=.TRUE. )
|
|
|
|
!=================================================================
|
|
! Open the checkpoint file for output -- binary punch format
|
|
!=================================================================
|
|
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - MAKE_AOD_FILE: Writing ', a )
|
|
|
|
! Open checkpoint file for output
|
|
CALL OPEN_BPCH2_FOR_WRITE( IU_AOD, FILENAME, TITLE )
|
|
|
|
!--------------------------------------
|
|
! write AOD
|
|
!--------------------------------------
|
|
|
|
! Loop over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Transfer data to 3D, REAL*4 array
|
|
DAT(I,J,1) = REAL(AOD_SAVE(I,J,W),4)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
CALL BPCH2( IU_AOD, MODELNAME, LONRES, LATRES,
|
|
& HALFPOLAR, CENTER180, CATEGORY, W,
|
|
& UNIT, GET_TAU(), GET_TAU(), RESERVED,
|
|
& IIPAR, JJPAR, 1, I0+1,
|
|
& J0+1, 1, DAT(:,:,1) )
|
|
|
|
ENDDO
|
|
|
|
! Define variables for BINARY PUNCH FILE OUTPUT
|
|
CATEGORY = 'IJ-AOD-$'
|
|
|
|
!--------------------------------------
|
|
! write reflectence
|
|
!--------------------------------------
|
|
UNIT = '%'
|
|
|
|
! Loop over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Transfer data to 3D, REAL*4 array
|
|
DAT(I,J,1) = REAL(GLOB_FLUX_W(W,I,J),4)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
CALL BPCH2( IU_AOD, MODELNAME, LONRES, LATRES,
|
|
& HALFPOLAR, CENTER180, CATEGORY, NWL_MAX+W,
|
|
& UNIT, GET_TAU(), GET_TAU(), RESERVED,
|
|
& IIPAR, JJPAR, 1, I0+1,
|
|
& J0+1, 1, DAT(:,:,1) )
|
|
|
|
|
|
ENDDO
|
|
|
|
!--------------------------------------
|
|
! write reflectance sensitivities
|
|
!--------------------------------------
|
|
UNIT = 'none'
|
|
|
|
! Loop over wavelengths
|
|
DO W = 1, NWL_MAX
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, L)
|
|
DO L = 1, LLPAR
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Transfer data to 3D, REAL*4 array
|
|
DAT(I,J,L) = REAL(JAC_GLOB_FLUX_W(2,L,W,I,J),4)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
CALL BPCH2( IU_AOD, MODELNAME, LONRES, LATRES,
|
|
& HALFPOLAR, CENTER180, CATEGORY, 2*NWL_MAX+W,
|
|
& UNIT, GET_TAU(), GET_TAU(), RESERVED,
|
|
& IIPAR, JJPAR, LLPAR, I0+1,
|
|
& J0+1, 1, DAT )
|
|
|
|
|
|
ENDDO ! W
|
|
|
|
!--------------------------------------
|
|
! write radiative flux
|
|
!--------------------------------------
|
|
UNIT = 'W/m2'
|
|
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, TEMP )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Average
|
|
!IF ( GLOB_FLUX_COUNT > 0 ) THEN
|
|
! TEMP = GLOB_FLUX(I,J) / REAL(GLOB_FLUX_COUNT)
|
|
!ELSE
|
|
! TEMP = 0d0
|
|
!ENDIF
|
|
|
|
! Transfer data to 3D, REAL*4 array
|
|
!DAT(I,J,1) = REAL(TEMP,4)
|
|
DAT(I,J,1) = REAL(GLOB_FLUX(I,J),4)
|
|
|
|
! For debuggin purposes, I'm curious about the following:
|
|
DAT(I,J,2) = REAL(SUNCOS( ( J - 1 ) * IIPAR + I ),4)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
CALL BPCH2( IU_AOD, MODELNAME, LONRES, LATRES,
|
|
& HALFPOLAR, CENTER180, CATEGORY, 3*NWL_MAX+1,
|
|
& UNIT, GET_TAU(), GET_TAU(), RESERVED,
|
|
& IIPAR, JJPAR, 2, I0+1,
|
|
& J0+1, 1, DAT(:,:,1:2) )
|
|
|
|
|
|
!--------------------------------------
|
|
! write average radiative force
|
|
!--------------------------------------
|
|
UNIT = 'W/m2'
|
|
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J, TEMP )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Average
|
|
!IF ( !GLOB_FLUX_COUNT > 0 ) THEN
|
|
! TEMP = GLOB_AVE_FORCE(I,J) / REAL(GLOB_FLUX_COUNT)
|
|
!ELSE
|
|
! TEMP = 0d0
|
|
!ENDIF
|
|
|
|
! Transfer data to 3D, REAL*4 array
|
|
DAT(I,J,1) = REAL(GLOB_AVE_FORCE(I,J),4)
|
|
!DAT(I,J,1) = REAL(DEBUG_J(I,J),4)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
CALL BPCH2( IU_AOD, MODELNAME, LONRES, LATRES,
|
|
& HALFPOLAR, CENTER180, CATEGORY, 3*NWL_MAX+2,
|
|
& UNIT, GET_TAU(), GET_TAU(), RESERVED,
|
|
& IIPAR, JJPAR, 1, I0+1,
|
|
& J0+1, 1, DAT(:,:,1) )
|
|
|
|
|
|
|
|
! Close file
|
|
CLOSE( IU_AOD )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE MAKE_AOD_FILE
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE MAKE_RAD_FILE( YYYYMMDD, HHMMSS, GLOB_FLUX_INST )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine MAKE_RAD_FILE saves save instantaneous upward SW radiative flux.
|
|
! (dkh, 03/05/08)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) YYYYMMDD (INTEGER) : Date of average
|
|
! (2 ) HHMMSS (INTEGER) : Hour-minute-second
|
|
!
|
|
! Arguments as Onput:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX_INST(REAL*8) : Instantaneous upward rad flux [W/m2]
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! Reference to f90 modules
|
|
USE BPCH2_MOD
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
USE GRID_MOD, ONLY : GET_XOFFSET, GET_YOFFSET
|
|
USE TIME_MOD, ONLY : GET_TAU, EXPAND_DATE
|
|
|
|
# include "CMN_SIZE" ! Size params
|
|
|
|
! Arguments
|
|
INTEGER :: YYYYMMDD, HHMMSS
|
|
REAL*8 :: GLOB_FLUX_INST(IIPAR,JJPAR)
|
|
|
|
! Local variables
|
|
INTEGER :: I, J, I0, J0, L
|
|
CHARACTER(LEN=120) :: FILENAME
|
|
REAL*4 :: DAT(IIPAR,JJPAR,1)
|
|
|
|
! For binary punch file, version 2.0
|
|
CHARACTER(LEN=20) :: MODELNAME
|
|
CHARACTER(LEN=40) :: CATEGORY
|
|
CHARACTER(LEN=40) :: UNIT
|
|
CHARACTER(LEN=40) :: RESERVED = ''
|
|
CHARACTER(LEN=80) :: TITLE
|
|
REAL*4 :: LONRES, LATRES
|
|
INTEGER, PARAMETER :: HALFPOLAR = 1
|
|
INTEGER, PARAMETER :: CENTER180 = 1
|
|
|
|
!=================================================================
|
|
! MAKE_RAD_FILE begins here!
|
|
!=================================================================
|
|
DAT(:,:,:) = 0d0
|
|
|
|
FILENAME = TRIM( 'rad.YYYYMMDD.hhmm' )
|
|
|
|
CALL EXPAND_DATE( FILENAME, YYYYMMDD, HHMMSS)
|
|
|
|
! Append data directory prefix
|
|
FILENAME = TRIM( './nat_rad/' ) // TRIM( FILENAME )
|
|
|
|
! Define variables for BINARY PUNCH FILE OUTPUT
|
|
TITLE = 'Inst. rad data file '
|
|
CATEGORY = 'RAD_UPFX'
|
|
LONRES = DISIZE
|
|
LATRES = DJSIZE
|
|
UNIT = 'W/m2'
|
|
|
|
! Call GET_MODELNAME to return the proper model name for
|
|
! the given met data being used (bmy, 6/22/00)
|
|
MODELNAME = GET_MODELNAME()
|
|
|
|
! Get the nested-grid offsets
|
|
I0 = GET_XOFFSET( GLOBAL=.TRUE. )
|
|
J0 = GET_YOFFSET( GLOBAL=.TRUE. )
|
|
|
|
!=================================================================
|
|
! Open the checkpoint file for output -- binary punch format
|
|
!=================================================================
|
|
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - MAKE_RAD_FILE: Writing ', a )
|
|
|
|
! Open checkpoint file for output
|
|
CALL OPEN_BPCH2_FOR_WRITE( IU_RAD, FILENAME, TITLE )
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
|
|
! Transfer data to 3D, REAL*4 array
|
|
DAT(I,J,1) = REAL(GLOB_FLUX_INST(I,J),4)
|
|
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
CALL BPCH2( IU_RAD, MODELNAME, LONRES, LATRES,
|
|
& HALFPOLAR, CENTER180, CATEGORY, 1,
|
|
& UNIT, GET_TAU(), GET_TAU(), RESERVED,
|
|
& IIPAR, JJPAR, 1, I0+1,
|
|
& J0+1, 1, DAT )
|
|
|
|
! Close file
|
|
CLOSE( IU_RAD )
|
|
|
|
! dkh debug
|
|
print*, 'writing GLOB_FLUX_INST = ', SUM(GLOB_FLUX_INST(:,:))
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE MAKE_RAD_FILE
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE READ_RAD_FILE( YYYYMMDD, HHMMSS, GLOB_FLUX_NAT )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_RAD_FILE reads the contents of aod.* files. (dkh, 03/05/08)
|
|
!
|
|
! Arguments as input:
|
|
! ============================================================================
|
|
! (1 ) YYYYMMDD : Year-Month-Day
|
|
! (2 ) HHMMSS : and Hour-Min-Sec for which to read aod file
|
|
!
|
|
! Arguments passed as output:
|
|
! ============================================================================
|
|
! (1 ) GLOB_FLUX_NAT : Natural upward fluxes
|
|
!
|
|
! Notes
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : OPEN_BPCH2_FOR_READ
|
|
USE ERROR_MOD, ONLY : DEBUG_MSG, ERROR_STOP
|
|
USE FILE_MOD, ONLY : IOERROR
|
|
USE TIME_MOD, ONLY : EXPAND_DATE
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: YYYYMMDD, HHMMSS
|
|
REAL*8, INTENT(OUT) :: GLOB_FLUX_NAT(IIPAR,JJPAR)
|
|
|
|
! Local Variables
|
|
INTEGER :: I, IOS, J, L, N, NTL
|
|
REAL*4 :: TRACER(IIPAR,JJPAR,1)
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
|
|
! For binary punch file, version 2.0
|
|
INTEGER :: NI, NJ, NL
|
|
INTEGER :: IFIRST, JFIRST, LFIRST
|
|
INTEGER :: NTRACER, NSKIP
|
|
INTEGER :: HALFPOLAR, CENTER180
|
|
REAL*4 :: LONRES, LATRES
|
|
REAL*8 :: ZTAU0, ZTAU1
|
|
CHARACTER(LEN=20) :: MODELNAME
|
|
CHARACTER(LEN=40) :: CATEGORY
|
|
CHARACTER(LEN=40) :: UNIT
|
|
CHARACTER(LEN=40) :: RESERVED
|
|
|
|
!=================================================================
|
|
! READ_RAD_FILE begins here!
|
|
!=================================================================
|
|
|
|
! Hardwire output file for now
|
|
FILENAME = 'rad.YYYYMMDD.hhmm'
|
|
|
|
! Initialize some variables
|
|
TRACER(:,:,:) = 0e0
|
|
|
|
!=================================================================
|
|
! Open rad file and read top-of-file header
|
|
!=================================================================
|
|
|
|
! Copy input file name to a local variable
|
|
FILENAME = TRIM( FILENAME )
|
|
|
|
! Replace YYYY, MM, DD, HH tokens in FILENAME w/ actual values
|
|
CALL EXPAND_DATE( FILENAME, YYYYMMDD, HHMMSS )
|
|
|
|
! Add ADJ_DIR prefix to name
|
|
FILENAME = TRIM( './nat_rad/' ) // TRIM( FILENAME )
|
|
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( ' - READ_RAD_FILE: Reading ', a )
|
|
|
|
! Open the binary punch file for input
|
|
CALL OPEN_BPCH2_FOR_READ( IU_RAD, FILENAME )
|
|
|
|
!=================================================================
|
|
! Read checkpointed variables
|
|
!=================================================================
|
|
|
|
READ( IU_RAD, IOSTAT=IOS )
|
|
& MODELNAME, LONRES, LATRES, HALFPOLAR, CENTER180
|
|
|
|
! IOS < 0 is end-of-file, so exit
|
|
!IF ( IOS < 0 ) EXIT
|
|
|
|
! IOS > 0 is a real I/O error -- print error message
|
|
IF ( IOS > 0 ) CALL IOERROR( IOS,IU_RAD,'read_rad_file:1' )
|
|
|
|
READ( IU_RAD, IOSTAT=IOS )
|
|
& CATEGORY, NTRACER, UNIT, ZTAU0, ZTAU1, RESERVED,
|
|
& NI, NJ, NL, IFIRST, JFIRST, LFIRST,
|
|
& NSKIP
|
|
|
|
IF ( IOS /= 0 ) CALL IOERROR( IOS,IU_RAD,'read_rad_file:2')
|
|
|
|
READ( IU_RAD, IOSTAT=IOS )
|
|
& ( ( ( TRACER(I,J,L), I=1,NI ), J=1,NJ ), L=1,NL )
|
|
|
|
IF ( IOS /= 0 ) CALL IOERROR( IOS,IU_RAD,'read_rad_file:3')
|
|
|
|
|
|
! Only process rad data (i.e. sw upward flux)
|
|
! Make sure array dimensions are of global size
|
|
IF ( CATEGORY(1:8) == 'RAD_UPFX' .and.
|
|
& NI == IIPAR .and. NJ == JJPAR .and. NL == 1 ) THEN
|
|
|
|
!$OMP PARALLEL DO
|
|
!$OMP+DEFAULT( SHARED )
|
|
!$OMP+PRIVATE( I, J )
|
|
DO J = 1, JJPAR
|
|
DO I = 1, IIPAR
|
|
GLOB_FLUX_NAT(I,J) = TRACER(I,J,1)
|
|
ENDDO
|
|
ENDDO
|
|
!$OMP END PARALLEL DO
|
|
|
|
ELSE
|
|
CALL ERROR_STOP('read_rad_file: did not match criteria',
|
|
& 'aero_optical_modl.f')
|
|
ENDIF
|
|
|
|
! dkh debug
|
|
print*, 'reading GLOB_FLUX_NAT = ', SUM(GLOB_FLUX_NAT(:,:))
|
|
|
|
! Close file
|
|
CLOSE( IU_RAD )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_RAD_FILE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE EXPAND_NAME( FILENAME, N_ITRN )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine EXPAND_DATE replaces "NN" token within
|
|
! a filename string with the actual values. (bmy, 6/27/02, 12/2/03)
|
|
! (dkh, 9/22/04)
|
|
!
|
|
! Arguments as Input:
|
|
! ============================================================================
|
|
! (1 ) FILENAME (CHARACTER) : Filename with tokens to replace
|
|
! (2 ) N_ITRN (INTEGER ) : Current iteration number
|
|
!
|
|
!
|
|
! Arguments as Output:
|
|
! ============================================================================
|
|
! (1 ) FILENAME (CHARACTER) : Modified filename
|
|
!
|
|
! NOTES:
|
|
! (1 ) Based on EXPAND_DATE
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE CHARPAK_MOD, ONLY : STRREPL
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
# include "define.h"
|
|
|
|
! Arguments
|
|
CHARACTER(LEN=*), INTENT(INOUT) :: FILENAME
|
|
INTEGER, INTENT(IN) :: N_ITRN
|
|
|
|
! Local variables
|
|
CHARACTER(LEN=2) :: NN_STR
|
|
|
|
!=================================================================
|
|
! EXPAND_NAME begins here!
|
|
!=================================================================
|
|
|
|
#if defined( LINUX_PGI )
|
|
|
|
! Use ENCODE statement for PGI/Linux (bmy, 9/29/03)
|
|
ENCODE( 2, '(i2.2)', NN_STR ) N_ITRN
|
|
|
|
#else
|
|
|
|
! For other platforms, use an F90 internal write (bmy, 9/29/03)
|
|
WRITE( NN_STR, '(i2.2)' ) N_ITRN
|
|
|
|
#endif
|
|
|
|
! Replace NN token w/ actual value
|
|
CALL STRREPL( FILENAME, 'NN', NN_STR )
|
|
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE EXPAND_NAME
|
|
|
|
!-----------------------------------------------------------------------
|
|
|
|
|
|
SUBROUTINE READ_LER_FILE( MM )
|
|
!
|
|
!******************************************************************************
|
|
! Subroutine READ_LER_FILE reads data file of TEMIS Lambertian Equivalent
|
|
! reflectivities. (dkh, 10/31/08)
|
|
!
|
|
! Arguments as input:
|
|
! ============================================================================
|
|
! (1 ) MM : Month
|
|
!
|
|
! NOTES:
|
|
! (1 ) Based on read_restart.
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
! References to F90 modules
|
|
USE BPCH2_MOD, ONLY : OPEN_BPCH2_FOR_READ
|
|
USE BPCH2_MOD, ONLY : GET_RES_EXT
|
|
USE DAO_MOD, ONLY : AD
|
|
USE DIRECTORY_MOD, ONLY : DATA_DIR
|
|
USE ERROR_MOD, ONLY : DEBUG_MSG
|
|
USE FILE_MOD, ONLY : IU_RST, IOERROR
|
|
USE LOGICAL_MOD, ONLY : LPRT
|
|
USE TIME_MOD, ONLY : EXPAND_DATE
|
|
USE CHARPAK_MOD, ONLY : STRREPL
|
|
|
|
|
|
# include "CMN_SIZE" ! Size parameters
|
|
# include "CMN" ! STT, NSRCX, TCVV, NTRACE, TCMASS, etc..
|
|
# include "CMN_DIAG" ! TRCOFFSET
|
|
|
|
! Arguments
|
|
INTEGER, INTENT(IN) :: MM
|
|
|
|
! Local Variables
|
|
INTEGER :: I, IOS, J, L, N
|
|
INTEGER :: NCOUNT(NNPAR)
|
|
REAL*4 :: TRACER(IIPAR,JJPAR,LLPAR)
|
|
REAL*8 :: SUMTC
|
|
CHARACTER(LEN=255) :: FILENAME
|
|
LOGICAL, SAVE :: FIRST = .TRUE.
|
|
|
|
! For binary punch file, version 2.0
|
|
INTEGER :: NI, NJ, NL
|
|
INTEGER :: IFIRST, JFIRST, LFIRST
|
|
INTEGER :: NTRACER, NSKIP
|
|
INTEGER :: HALFPOLAR, CENTER180
|
|
REAL*4 :: LONRES, LATRES
|
|
REAL*8 :: ZTAU0, ZTAU1
|
|
CHARACTER(LEN=20) :: MODELNAME
|
|
CHARACTER(LEN=40) :: CATEGORY
|
|
CHARACTER(LEN=40) :: UNIT
|
|
CHARACTER(LEN=40) :: RESERVED
|
|
CHARACTER(LEN=2) :: MM_STR
|
|
CHARACTER(LEN=40) :: INPUT_LER_FILE
|
|
|
|
!=================================================================
|
|
! READ_LER_FILE begins here!
|
|
!=================================================================
|
|
|
|
! Hardwire output file for now
|
|
INPUT_LER_FILE = 'temis_ler.MM.bpch'
|
|
|
|
! Initialize some variables
|
|
NCOUNT(:) = 0
|
|
TRACER(:,:,:) = 0e0
|
|
|
|
!=================================================================
|
|
! Open restart file and read top-of-file header
|
|
!=================================================================
|
|
|
|
! Copy input file name to a local variable
|
|
FILENAME = TRIM( INPUT_LER_FILE )
|
|
|
|
WRITE( MM_STR, '(i2.2)' ) MM
|
|
|
|
! Replace YYYY, MM, DD, HH tokens in FILENAME w/ actual values
|
|
CALL STRREPL( FILENAME, 'MM', MM_STR )
|
|
|
|
FILENAME = TRIM( DATA_DIR ) // 'temis_ler_200810/'
|
|
& // TRIM( FILENAME ) // '.' // GET_RES_EXT()
|
|
|
|
! Echo some input to the screen
|
|
WRITE( 6, 100 ) TRIM( FILENAME )
|
|
100 FORMAT( 'READ_LER_FILE: Reading ', a )
|
|
|
|
! Open the binary punch file for input
|
|
CALL OPEN_BPCH2_FOR_READ( IU_RST, FILENAME )
|
|
|
|
|
|
!=================================================================
|
|
! Read concentrations -- store in the TRACER array
|
|
!=================================================================
|
|
READ( IU_RST, IOSTAT=IOS )
|
|
& MODELNAME, LONRES, LATRES, HALFPOLAR, CENTER180
|
|
|
|
! IOS > 0 is a real I/O error -- print error message
|
|
IF ( IOS > 0 .or. IOS < 0 )
|
|
& CALL IOERROR( IOS,IU_RST,'read_ler_file:4' )
|
|
|
|
READ( IU_RST, IOSTAT=IOS )
|
|
& CATEGORY, NTRACER, UNIT, ZTAU0, ZTAU1, RESERVED,
|
|
& NI, NJ, NL, IFIRST, JFIRST, LFIRST,
|
|
& NSKIP
|
|
|
|
IF ( IOS /= 0 ) CALL IOERROR( IOS,IU_RST,'read_ler_file:5')
|
|
|
|
READ( IU_RST, IOSTAT=IOS )
|
|
& ( ( ( TRACER(I,J,L), I=1,NI ), J=1,NJ ), L=1,NL )
|
|
|
|
IF ( IOS /= 0 ) CALL IOERROR( IOS,IU_RST,'read_ler_file:6')
|
|
|
|
!==============================================================
|
|
! Assign data from the TRACER array to the STT array.
|
|
!==============================================================
|
|
|
|
! Save in TEMIS_LER and convert to fraction (data in file is
|
|
! stored as fraction * 1d3).
|
|
|
|
! Use values at 335 for 315
|
|
TEMIS_LER(:,:,1) = TRACER(:,:,1) / 1d3
|
|
|
|
! Interpolate vales at 357 from values at 380 and 335
|
|
TEMIS_LER(:,:,2) = ( TRACER(:,:,2) - TRACER(:,:,1) )
|
|
& / ( 380 - 335 )
|
|
& * ( LAMBDA_TABLE(2) - 335 ) / 1d3
|
|
& + ( TRACER(:,:,1) ) / 1d3
|
|
|
|
! Interpolate values at 500 from values at 494 and 555
|
|
TEMIS_LER(:,:,3) = ( TRACER(:,:,7) - TRACER(:,:,6) )
|
|
& / ( 555 - 494 )
|
|
& * ( LAMBDA_TABLE(3) - 494 ) / 1d3
|
|
& + ( TRACER(:,:,6) ) / 1d3
|
|
|
|
! Use values at 758 for 833 and 1667
|
|
TEMIS_LER(:,:,4) = ( TRACER(:,:,7) - TRACER(:,:,6) )
|
|
& / ( 555 - 494 )
|
|
& * ( LAMBDA_TABLE(3) - 494 ) / 1d3
|
|
& + ( TRACER(:,:,6) ) / 1d3
|
|
TEMIS_LER(:,:,5) = TEMIS_LER(:,:,4)
|
|
|
|
! Close file
|
|
CLOSE( IU_RST )
|
|
|
|
|
|
!### Debug
|
|
IF ( LPRT ) CALL DEBUG_MSG( '### READ_LER_FILE: read file' )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE READ_LER_FILE
|
|
|
|
!------------------------------------------------------------------------------
|
|
|
|
SUBROUTINE INIT_LIDORT
|
|
!
|
|
!*****************************************************************************
|
|
! Subroutine INIT_LIDORT deallocates all module arrays. (dkh, 11/09/07)
|
|
!
|
|
! NOTES:
|
|
! (1 ) Udate to LIDORT 3p5, change name from INIT_AERO_OPTICAL to INIT_LIDORT
|
|
! (dkh, 07/25/10)
|
|
! (2 ) Check to make sure JJPAR matches MAXTHREADS
|
|
!******************************************************************************
|
|
!
|
|
USE ERROR_MOD, ONLY : ALLOC_ERR
|
|
USE ERROR_MOD, ONLY : ERROR_STOP
|
|
|
|
# include "CMN_SIZE" ! IIPAR, JJPAR, etc
|
|
|
|
! include file for LIDORT Mk 2 threads
|
|
#include "./thread_sourcecode_MkII_F90/LIDORT.PARS_F90"
|
|
|
|
|
|
! Local variables
|
|
INTEGER :: AS
|
|
|
|
!=================================================================
|
|
! INIT_LIDORT begins here
|
|
!=================================================================
|
|
|
|
ALLOCATE( AOD_SAVE( IIPAR, JJPAR, NWL_MAX ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'AOD_SAVE' )
|
|
AOD_SAVE = 0d0
|
|
|
|
ALLOCATE( AOD_AVE( IIPAR, JJPAR, NWL_MAX ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'AOD_AVE' )
|
|
AOD_AVE = 0d0
|
|
|
|
ALLOCATE( LAYER_AOD( IIPAR, JJPAR, LLPAR, NWL_MAX ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'LAYER_AOD' )
|
|
LAYER_AOD = 0d0
|
|
|
|
ALLOCATE( LAYER_SSA( IIPAR, JJPAR, LLPAR, NWL_MAX ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'LAYER_SSA' )
|
|
LAYER_SSA = 0d0
|
|
|
|
ALLOCATE( LAYER_PHM( IIPAR, JJPAR, LLPAR, NPM_MAX, NWL_MAX ),
|
|
& STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'LAYER_PHM' )
|
|
LAYER_PHM = 0d0
|
|
|
|
ALLOCATE( LAYER_AOD_ADJ( IIPAR, JJPAR, LLPAR, NWL_MAX ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'LAYER_AOD_ADJ' )
|
|
LAYER_AOD_ADJ = 0d0
|
|
|
|
ALLOCATE( LAYER_SSA_ADJ( IIPAR, JJPAR, LLPAR, NWL_MAX ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'LAYER_SSA_ADJ' )
|
|
LAYER_SSA_ADJ = 0d0
|
|
|
|
ALLOCATE( LAYER_PHM_ADJ( IIPAR, JJPAR, LLPAR, NPM_MAX, NWL_MAX ),
|
|
& STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'LAYER_PHM_ADJ' )
|
|
LAYER_PHM_ADJ = 0d0
|
|
|
|
ALLOCATE( MASS_ND( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'MASS_ND' )
|
|
MASS_ND = 0d0
|
|
|
|
ALLOCATE( GLOB_FLUX_W( NWL_MAX, IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'GLOB_FLUX_W' )
|
|
GLOB_FLUX_W = 0d0
|
|
|
|
ALLOCATE( GLOB_FLUX_W_ADJ( NWL_MAX, IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'GLOB_FLUX_W_ADJ' )
|
|
GLOB_FLUX_W_ADJ = 0d0
|
|
|
|
ALLOCATE( GLOB_FLUX( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'GLOB_FLUX' )
|
|
GLOB_FLUX = 0d0
|
|
|
|
ALLOCATE(
|
|
& JAC_GLOB_FLUX_W( MAX_ATMOSWFS, LLPAR, NWL_MAX, IIPAR, JJPAR ),
|
|
& STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'JAC_GLOB_FLUX_W' )
|
|
JAC_GLOB_FLUX_W = 0d0
|
|
|
|
ALLOCATE( GLOB_AVE_FORCE( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'GLOB_AVE_FORCE' )
|
|
GLOB_AVE_FORCE = 0d0
|
|
|
|
ALLOCATE( TEMIS_LER( IIPAR, JJPAR, LLER ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'TEMIS_LER' )
|
|
TEMIS_LER = 0d0
|
|
|
|
ALLOCATE( DEBUG_J( IIPAR, JJPAR ), STAT=AS )
|
|
IF ( AS /= 0 ) CALL ALLOC_ERR( 'DEBUG_J' )
|
|
DEBUG_J = 0d0
|
|
|
|
! make sure we've set MAXTHREADS in LIDORT.PAR to match
|
|
! the current model resolution
|
|
IF ( MAXTHREADS .ne. JJPAR ) THEN
|
|
CALL ERROR_STOP( 'MAXTHREADS /= JJPAR',
|
|
& 'lidort_mod.f' )
|
|
ENDIF
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE INIT_LIDORT
|
|
|
|
|
|
!------------------------------------------------------------------------------
|
|
SUBROUTINE CLEANUP_LIDORT
|
|
!
|
|
!*****************************************************************************
|
|
! Subroutine CLEANUP_LIDORT deallocates all module arrays. (dkh, 11/09/07)
|
|
!
|
|
! NOTES:
|
|
!
|
|
!******************************************************************************
|
|
!
|
|
IF ( ALLOCATED( AOD_SAVE ) ) DEALLOCATE( AOD_SAVE )
|
|
IF ( ALLOCATED( AOD_AVE ) ) DEALLOCATE( AOD_AVE )
|
|
IF ( ALLOCATED( LAYER_AOD ) ) DEALLOCATE( LAYER_AOD )
|
|
IF ( ALLOCATED( LAYER_SSA ) ) DEALLOCATE( LAYER_SSA )
|
|
IF ( ALLOCATED( LAYER_PHM ) ) DEALLOCATE( LAYER_PHM )
|
|
IF ( ALLOCATED( LAYER_AOD_ADJ ) ) DEALLOCATE( LAYER_AOD_ADJ )
|
|
IF ( ALLOCATED( LAYER_SSA_ADJ ) ) DEALLOCATE( LAYER_SSA_ADJ )
|
|
IF ( ALLOCATED( LAYER_PHM_ADJ ) ) DEALLOCATE( LAYER_PHM_ADJ )
|
|
IF ( ALLOCATED( MASS_ND ) ) DEALLOCATE( MASS_ND )
|
|
IF ( ALLOCATED( GLOB_FLUX_W ) ) DEALLOCATE( GLOB_FLUX_W )
|
|
IF ( ALLOCATED( GLOB_FLUX_W_ADJ ) ) DEALLOCATE( GLOB_FLUX_W_ADJ )
|
|
IF ( ALLOCATED( JAC_GLOB_FLUX_W ) ) DEALLOCATE( JAC_GLOB_FLUX_W )
|
|
IF ( ALLOCATED( GLOB_FLUX ) ) DEALLOCATE( GLOB_FLUX )
|
|
IF ( ALLOCATED( GLOB_AVE_FORCE ) ) DEALLOCATE( GLOB_AVE_FORCE )
|
|
IF ( ALLOCATED( TEMIS_LER ) ) DEALLOCATE( TEMIS_LER )
|
|
|
|
! Return to calling program
|
|
END SUBROUTINE CLEANUP_LIDORT
|
|
!------------------------------------------------------------------------------
|
|
|
|
|
|
END MODULE LIDORT_MOD
|