diff --git a/README b/README
index 8b13789..d65db6d 100644
--- a/README
+++ b/README
@@ -1 +1,2 @@
-
+Modified branch to account for in-canopy effects on composition/weather
+Export 5 2D canopy data fields and 3 2D photolysis diagnostics (I. Ivanova, 02/14/2024)
diff --git a/aqm_files.cmake b/aqm_files.cmake
index 527cf3d..6727dc8 100644
--- a/aqm_files.cmake
+++ b/aqm_files.cmake
@@ -187,7 +187,6 @@ list(APPEND aqm_CCTM_files
 	${PHOT}/CSQY_DATA.F
 	${PHOT}/OMI_1979_to_2015.dat
 	${PHOT}/opphot.F
-	${PHOT}/phot.F
 	${PHOT}/PHOT_MET_DATA.F
 	${PHOT}/PHOT_MOD.F
 	${PHOT}/PHOTOLYSIS_ALBEDO.F
@@ -243,4 +242,6 @@ list(APPEND aqm_CCTM_files
 	${localCCTM}/ASX_DATA_MOD.F
 	${localCCTM}/DUST_EMIS.F
 	${localCCTM}/AERO_PHOTDATA.F
+	${localCCTM}/phot.F
+	${localCCTM}/centralized_io_util_module.F
 )
diff --git a/examples/aqm.rc b/examples/aqm.rc
index 13246de..70240c0 100644
--- a/examples/aqm.rc
+++ b/examples/aqm.rc
@@ -34,6 +34,31 @@ omi_data:    /scratch1/NCEPDEV/nems/Raffaele.Montuoro/dev/aqm/epa/data/omi_cmaq_
 # - set to true for cold start
 init_concentrations: true
 
+#
+# Inline Canopy Effects
+#
+canopy_yn: true
+
+canopy_type: canopy
+
+canopy_format: netcdf
+
+canopy_file: /scratch2/NAGAPE/arl/Patrick.C.Campbell/canopy_geofiles/gfs.t12z.geo.08.canopy_regrid.nc
+
+canopy_frequency: static
+
+canopy_species::
+    FCH        1.00000   FCH      m
+    FRT        1.00000   FRT      1
+    CLU        1.00000   CLU      1
+    POPU       1.00000   POPU     10000_people/10km2
+    LAIE       1.00000   LAIE     1
+    C1R        1.00000   C1R      1
+    C2R        1.00000   C2R      1
+    C3R        1.00000   C3R      1
+    C4R        1.00000   C4R      1
+::
+
 #
 # Run options:
 #
@@ -83,7 +108,7 @@ ctm_stdout: all
 emission_sources: myemis
 
 #
-#  Emission type: anthropogenic, biogenic, gbbepx, fengsha
+#  Emission type: anthropogenic, biogenic, gbbepx, fengsha, canopy
 #
 myemis_type: anthropogenic
 
diff --git a/src/aqm_cap.F90 b/src/aqm_cap.F90
index 15a3231..98c30a0 100644
--- a/src/aqm_cap.F90
+++ b/src/aqm_cap.F90
@@ -9,7 +9,7 @@ module AQM
 
   use aqm_comp_mod
   use aqm_const_mod, only: rad_to_deg
-  
+
   implicit none
 
   ! -- import fields
@@ -54,28 +54,36 @@ module AQM
       "temperature_of_soil_layer                "  &
     /)
   ! -- export fields
-  integer, parameter :: exportFieldCount = 2
+  integer, parameter :: exportFieldCount = 2 + 5 + 3   !IVAI: add 5 canopy data fields add 3 photdiag arrays
   character(len=*), dimension(exportFieldCount), parameter :: &
     exportFieldNames = (/ &
       "inst_tracer_mass_frac                ", &
-      "inst_tracer_diag_aod                 "  &
+      "inst_tracer_diag_aod                 ", &
+      "inst_tracer_diag_coszens             ", & !IVAI: photdiag
+      "inst_tracer_diag_jo3o1d              ", & !IVAI: photdiag
+      "inst_tracer_diag_jno2                ", & !IVAI: photdiag
+      "inst_tracer_diag_claie               ", & !IVAI: canopy via aqm_emis_read
+      "inst_tracer_diag_cfch                ", & !IVAI: canopy via aqm_emis_read
+      "inst_tracer_diag_cfrt                ", & !IVAI: canopy via aqm_emis_read
+      "inst_tracer_diag_cclu                ", & !IVAI: canopy via aqm_emis_read
+      "inst_tracer_diag_cpopu               "  & !IVAI: canopy via aqm_emis_read
     /)
 
   private
 
   public SetServices
-  
+
   !-----------------------------------------------------------------------------
   contains
   !-----------------------------------------------------------------------------
-  
+
   subroutine SetServices(model, rc)
     type(ESMF_GridComp)  :: model
     integer, intent(out) :: rc
 
     ! begin
     rc = ESMF_SUCCESS
-    
+
     ! the NUOPC model component will register the generic methods
     call NUOPC_CompDerive(model, inheritModel, rc=rc)
     if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
@@ -120,7 +128,7 @@ subroutine SetServices(model, rc)
       return  ! bail out
 
   end subroutine
-  
+
   !-----------------------------------------------------------------------------
 
   subroutine InitializeP0(model, importState, exportState, clock, rc)
@@ -128,7 +136,7 @@ subroutine InitializeP0(model, importState, exportState, clock, rc)
     type(ESMF_State)     :: importState, exportState
     type(ESMF_Clock)     :: clock
     integer, intent(out) :: rc
-    
+
     ! local variables
     integer                    :: verbosity
     character(len=ESMF_MAXSTR) :: msgString, name, rcFile
@@ -195,16 +203,16 @@ subroutine InitializeP0(model, importState, exportState, clock, rc)
       line=__LINE__, &
       file=__FILE__)) &
       return  ! bail out
-    
+
   end subroutine
-  
+
   !-----------------------------------------------------------------------------
   subroutine InitializeP1(model, importState, exportState, clock, rc)
     type(ESMF_GridComp)  :: model
     type(ESMF_State)     :: importState, exportState
     type(ESMF_Clock)     :: clock
     integer, intent(out) :: rc
-    
+
     ! begin
     rc = ESMF_SUCCESS
 
@@ -285,7 +293,7 @@ subroutine DataInitialize(model, rc)
       return  ! bail out
 
     ! -- check if import fields are defined
-    if (importFieldCount < 1) then 
+    if (importFieldCount < 1) then
       call ESMF_LogSetError(ESMF_RC_NOT_IMPL, &
         msg="This component requires import fields to be defined.", &
         line=__LINE__, file=__FILE__, &
@@ -294,7 +302,7 @@ subroutine DataInitialize(model, rc)
     end if
 
     ! -- check if export fields are defined
-    if (exportFieldCount < 1) then 
+    if (exportFieldCount < 1) then
       call ESMF_LogSetError(ESMF_RC_NOT_IMPL, &
         msg="This component requires export fields to be defined.", &
         line=__LINE__, file=__FILE__, &
@@ -417,7 +425,7 @@ subroutine DataInitialize(model, rc)
             line=__LINE__, &
             file=__FILE__)) &
             return  ! bail out
-         
+
         do item = 1, 2
           call ESMF_GridGetCoord(grid, coordDim=item, staggerloc=ESMF_STAGGERLOC_CENTER, &
             localDE=localDe, farrayPtr=coord, rc=rc)
@@ -534,7 +542,7 @@ end subroutine DataInitialize
   subroutine ModelAdvance(model, rc)
     type(ESMF_GridComp)  :: model
     integer, intent(out) :: rc
-    
+
     ! local variables
     type(ESMF_Clock)              :: clock
     type(ESMF_State)              :: importState, exportState
@@ -548,7 +556,7 @@ subroutine ModelAdvance(model, rc)
 
     ! begin
     rc = ESMF_SUCCESS
-    
+
     ! get component's information
     call NUOPC_CompGet(model, name=name, diagnostic=diagnostic, rc=rc)
     if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
diff --git a/src/aqm_comp_mod.F90 b/src/aqm_comp_mod.F90
index c255316..7433755 100644
--- a/src/aqm_comp_mod.F90
+++ b/src/aqm_comp_mod.F90
@@ -325,6 +325,57 @@ subroutine aqm_comp_export(state, fieldNames, rc)
               line=__LINE__, &
               file=__FILE__)) &
               return  ! bail
+!IVAI: photdiag CTM_RJ_1 fields
+          case ("inst_tracer_diag_coszens")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % coszens, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+          case ("inst_tracer_diag_jo3o1d")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % jo3o1d, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+          case ("inst_tracer_diag_jno2")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % jno2, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+!IVAI: canopy fields read in via 'aqm_emiss_read'
+          case ("inst_tracer_diag_claie")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % claie, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+          case ("inst_tracer_diag_cfch")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % cfch, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+          case ("inst_tracer_diag_cfrt")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % cfrt, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+          case ("inst_tracer_diag_cclu")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % cclu, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+          case ("inst_tracer_diag_cpopu")
+            call ESMF_FieldGet(field, localDe=localDe, farrayPtr=stateOut % cpopu, rc=rc)
+            if (ESMF_LogFoundError(rcToCheck=rc, msg=ESMF_LOGERR_PASSTHRU, &
+              line=__LINE__, &
+              file=__FILE__)) &
+              return  ! bail
+!IVAI
           case default
             ! -- unused field
         end select
diff --git a/src/model/Makefile.am b/src/model/Makefile.am
index cff3967..00d4ae9 100644
--- a/src/model/Makefile.am
+++ b/src/model/Makefile.am
@@ -168,7 +168,6 @@ libCCTM_a_SOURCES += \
 	$(PHOT)/CSQY_DATA.F \
 	$(PHOT)/OMI_1979_to_2015.dat \
 	$(PHOT)/opphot.F \
-	$(PHOT)/phot.F \
 	$(PHOT)/PHOT_MET_DATA.F \
 	$(PHOT)/PHOT_MOD.F \
 	$(PHOT)/PHOTOLYSIS_ALBEDO.F \
@@ -219,7 +218,6 @@ libCCTM_a_SOURCES += \
 	$(UTIL)/bmatvec.F \
 	$(UTIL)/findex.f \
 	$(UTIL)/get_envlist.f \
-	$(UTIL)/setup_logdev.F \
 	$(UTIL)/subhdomain.F \
 	$(UTIL)/UTILIO_DEFN.F
 
@@ -250,11 +248,11 @@ libCCTM_a_SOURCES += \
 	${localCCTM}/PT3D_DEFN.F \
 	${localCCTM}/PT3D_FIRE_DEFN.F \
 	${localCCTM}/PT3D_STKS_DEFN.F \
+	$(localCCTM)/phot.F \
 	${localCCTM}/ASX_DATA_MOD.F \
+	$(localCCTM)/centralized_io_util_module.F \
 	${localCCTM}/DUST_EMIS.F \
 	${localCCTM}/AERO_PHOTDATA.F
-
-
 libCCTM_a_CPPFLAGS  = -DSUBST_FILES_ID=\"FILES_CTM.EXT\"
 libCCTM_a_CPPFLAGS += -DSUBST_CONST=\"CONST.EXT\"
 libCCTM_a_CPPFLAGS += -DSUBST_EMISPRM=\"EMISPRM.EXT\"
@@ -432,6 +430,10 @@ $(libEMIS)BIOG_EMIS.$(OBJEXT) : \
 	$(libUTIL)UTILIO_DEFN.$(OBJEXT)
 $(libEMIS)cropcal.$(OBJEXT) : \
 	$(libGRID)HGRD_DEFN.$(OBJEXT) $(libUTIL)UTILIO_DEFN.$(OBJEXT)
+$(libEMIS)DUST_EMIS.$(OBJEXT) : $(ICL)/const/CONST.EXT $(ICL)/filenames/FILES_CTM.EXT \
+	$(libAERO)AERO_DATA.$(OBJEXT) $(liblocalCCTM)ASX_DATA_MOD.$(OBJEXT) \
+	$(libGRID)GRID_CONF.$(OBJEXT) $(libGRID)HGRD_DEFN.$(OBJEXT) \
+	$(libEMIS)LUS_DEFN.$(OBJEXT) $(libUTIL)UTILIO_DEFN.$(OBJEXT)
 $(libEMIS)EMIS_DEFN.$(OBJEXT) : $(ICL)/const/CONST.EXT $(ICL)/filenames/FILES_CTM.EXT \
 	$(libAERO)AERO_DATA.$(OBJEXT) $(libAERO)AERO_EMIS.$(OBJEXT) \
 	$(liblocalCCTM)ASX_DATA_MOD.$(OBJEXT) $(libEMIS)BEIS_DEFN.$(OBJEXT) \
diff --git a/src/model/Makefile.in b/src/model/Makefile.in
index 078af39..a787fbd 100644
--- a/src/model/Makefile.in
+++ b/src/model/Makefile.in
@@ -186,7 +186,6 @@ am_libCCTM_a_OBJECTS = $(AERO)/libCCTM_a-AERO_DATA.$(OBJEXT) \
 	$(PHOT)/libCCTM_a-complex_number_module.$(OBJEXT) \
 	$(PHOT)/libCCTM_a-CSQY_DATA.$(OBJEXT) \
 	$(PHOT)/libCCTM_a-opphot.$(OBJEXT) \
-	$(PHOT)/libCCTM_a-phot.$(OBJEXT) \
 	$(PHOT)/libCCTM_a-PHOT_MET_DATA.$(OBJEXT) \
 	$(PHOT)/libCCTM_a-PHOT_MOD.$(OBJEXT) \
 	$(PHOT)/libCCTM_a-PHOTOLYSIS_ALBEDO.$(OBJEXT) \
@@ -238,7 +237,9 @@ am_libCCTM_a_OBJECTS = $(AERO)/libCCTM_a-AERO_DATA.$(OBJEXT) \
 	${localCCTM}/libCCTM_a-PT3D_DEFN.$(OBJEXT) \
 	${localCCTM}/libCCTM_a-PT3D_FIRE_DEFN.$(OBJEXT) \
 	${localCCTM}/libCCTM_a-PT3D_STKS_DEFN.$(OBJEXT) \
+	$(localCCTM)/libCCTM_a-phot.$(OBJEXT) \
 	${localCCTM}/libCCTM_a-ASX_DATA_MOD.$(OBJEXT) \
+	$(localCCTM)/libCCTM_a-centralized_io_util_module.$(OBJEXT) \
 	${localCCTM}/libCCTM_a-DUST_EMIS.$(OBJEXT) \
 	${localCCTM}/libCCTM_a-AERO_PHOTDATA.$(OBJEXT)
 libCCTM_a_OBJECTS = $(am_libCCTM_a_OBJECTS)
@@ -516,6 +517,7 @@ libCCTM_a_SOURCES = $(AERO)/AERO_DATA.F $(AERO)/aero_depv.F \
 	${localCCTM}/PT3D_DATA_MOD.F ${localCCTM}/PT3D_DEFN.F \
 	${localCCTM}/PT3D_FIRE_DEFN.F ${localCCTM}/PT3D_STKS_DEFN.F \
 	${localCCTM}/ASX_DATA_MOD.F ${localCCTM}/DUST_EMIS.F \
+	$(localCCTM)/phot.F $(localCCTM)/centralized_io_util_module.F \
 	${localCCTM}/AERO_PHOTDATA.F
 
 # local version of CCTM source files
@@ -886,8 +888,6 @@ $(PHOT)/libCCTM_a-CSQY_DATA.$(OBJEXT): $(PHOT)/$(am__dirstamp) \
 	$(PHOT)/$(DEPDIR)/$(am__dirstamp)
 $(PHOT)/libCCTM_a-opphot.$(OBJEXT): $(PHOT)/$(am__dirstamp) \
 	$(PHOT)/$(DEPDIR)/$(am__dirstamp)
-$(PHOT)/libCCTM_a-phot.$(OBJEXT): $(PHOT)/$(am__dirstamp) \
-	$(PHOT)/$(DEPDIR)/$(am__dirstamp)
 $(PHOT)/libCCTM_a-PHOT_MET_DATA.$(OBJEXT): $(PHOT)/$(am__dirstamp) \
 	$(PHOT)/$(DEPDIR)/$(am__dirstamp)
 $(PHOT)/libCCTM_a-PHOT_MOD.$(OBJEXT): $(PHOT)/$(am__dirstamp) \
@@ -1024,6 +1024,9 @@ ${localCCTM}/libCCTM_a-PT3D_DATA_MOD.$(OBJEXT):  \
 	${localCCTM}/$(am__dirstamp) \
 	${localCCTM}/$(DEPDIR)/$(am__dirstamp)
 ${localCCTM}/libCCTM_a-PT3D_DEFN.$(OBJEXT):  \
+	$(localCCTM)/$(am__dirstamp) \
+	$(localCCTM)/$(DEPDIR)/$(am__dirstamp)
+$(localCCTM)/libCCTM_a-phot.$(OBJEXT):  \
 	${localCCTM}/$(am__dirstamp) \
 	${localCCTM}/$(DEPDIR)/$(am__dirstamp)
 ${localCCTM}/libCCTM_a-PT3D_FIRE_DEFN.$(OBJEXT):  \
@@ -1033,6 +1036,9 @@ ${localCCTM}/libCCTM_a-PT3D_STKS_DEFN.$(OBJEXT):  \
 	${localCCTM}/$(am__dirstamp) \
 	${localCCTM}/$(DEPDIR)/$(am__dirstamp)
 ${localCCTM}/libCCTM_a-ASX_DATA_MOD.$(OBJEXT):  \
+	$(localCCTM)/$(am__dirstamp) \
+	$(localCCTM)/$(DEPDIR)/$(am__dirstamp)
+$(localCCTM)/libCCTM_a-centralized_io_util_module.$(OBJEXT):  \
 	${localCCTM}/$(am__dirstamp) \
 	${localCCTM}/$(DEPDIR)/$(am__dirstamp)
 ${localCCTM}/libCCTM_a-DUST_EMIS.$(OBJEXT):  \
@@ -1532,11 +1538,17 @@ $(PHOT)/libCCTM_a-opphot.o: $(PHOT)/opphot.F
 $(PHOT)/libCCTM_a-opphot.obj: $(PHOT)/opphot.F
 	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(PHOT)/libCCTM_a-opphot.obj `if test -f '$(PHOT)/opphot.F'; then $(CYGPATH_W) '$(PHOT)/opphot.F'; else $(CYGPATH_W) '$(srcdir)/$(PHOT)/opphot.F'; fi`
 
-$(PHOT)/libCCTM_a-phot.o: $(PHOT)/phot.F
-	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(PHOT)/libCCTM_a-phot.o `test -f '$(PHOT)/phot.F' || echo '$(srcdir)/'`$(PHOT)/phot.F
+$(localCCTM)/libCCTM_a-phot.o: $(localCCTM)/phot.F
+	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(localCCTM)/libCCTM_a-phot.o `test -f '$(localCCTM)/phot.F' || echo '$(srcdir)/'`$(localCCTM)/phot.F
+
+$(localCCTM)/libCCTM_a-phot.obj: $(localCCTM)/phot.F
+	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(localCCTM)/libCCTM_a-phot.obj `if test -f '$(localCCTM)/phot.F'; then $(CYGPATH_W) '$(localCCTM)/phot.F'; else $(CYGPATH_W) '$(srcdir)/$(localCCTM)/phot.F'; fi`
+
+$(localCCTM)/libCCTM_a-centralized_io_util_module.o: $(localCCTM)/centralized_io_util_module.F
+	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(localCCTM)/libCCTM_a-centralized_io_util_module.o `test -f '$(localCCTM)/centralized_io_util_module.F' || echo '$(srcdir)/'`$(localCCTM)/centralized_io_util_module.F
 
-$(PHOT)/libCCTM_a-phot.obj: $(PHOT)/phot.F
-	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(PHOT)/libCCTM_a-phot.obj `if test -f '$(PHOT)/phot.F'; then $(CYGPATH_W) '$(PHOT)/phot.F'; else $(CYGPATH_W) '$(srcdir)/$(PHOT)/phot.F'; fi`
+$(localCCTM)/libCCTM_a-centralized_io_util_module.obj: $(localCCTM)/centralized_io_util_module.F
+	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(localCCTM)/libCCTM_a-centralized_io_util_module.obj `if test -f '$(localCCTM)/centralized_io_util_module.F'; then $(CYGPATH_W) '$(localCCTM)/centralized_io_util_module.F'; else $(CYGPATH_W) '$(srcdir)/$(localCCTM)/centralized_io_util_module.F'; fi`
 
 $(PHOT)/libCCTM_a-PHOT_MET_DATA.o: $(PHOT)/PHOT_MET_DATA.F
 	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(PHOT)/libCCTM_a-PHOT_MET_DATA.o `test -f '$(PHOT)/PHOT_MET_DATA.F' || echo '$(srcdir)/'`$(PHOT)/PHOT_MET_DATA.F
@@ -1622,6 +1634,12 @@ $(VDIFF)/libCCTM_a-aero_sedv.o: $(VDIFF)/aero_sedv.F
 $(VDIFF)/libCCTM_a-aero_sedv.obj: $(VDIFF)/aero_sedv.F
 	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(VDIFF)/libCCTM_a-aero_sedv.obj `if test -f '$(VDIFF)/aero_sedv.F'; then $(CYGPATH_W) '$(VDIFF)/aero_sedv.F'; else $(CYGPATH_W) '$(srcdir)/$(VDIFF)/aero_sedv.F'; fi`
 
+$(localCCTM)/libCCTM_a-ASX_DATA_MOD.o: $(localCCTM)/ASX_DATA_MOD.F
+	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(localCCTM)/libCCTM_a-ASX_DATA_MOD.o `test -f '$(localCCTM)/ASX_DATA_MOD.F' || echo '$(srcdir)/'`$(localCCTM)/ASX_DATA_MOD.F
+
+$(localCCTM)/libCCTM_a-ASX_DATA_MOD.obj: $(localCCTM)/ASX_DATA_MOD.F
+	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(localCCTM)/libCCTM_a-ASX_DATA_MOD.obj `if test -f '$(localCCTM)/ASX_DATA_MOD.F'; then $(CYGPATH_W) '$(localCCTM)/ASX_DATA_MOD.F'; else $(CYGPATH_W) '$(srcdir)/$(localCCTM)/ASX_DATA_MOD.F'; fi`
+
 $(VDIFF)/libCCTM_a-conv_cgrid.o: $(VDIFF)/conv_cgrid.F
 	$(AM_V_PPF77)$(F77) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libCCTM_a_CPPFLAGS) $(CPPFLAGS) $(libCCTM_a_FFLAGS) $(FFLAGS) -c -o $(VDIFF)/libCCTM_a-conv_cgrid.o `test -f '$(VDIFF)/conv_cgrid.F' || echo '$(srcdir)/'`$(VDIFF)/conv_cgrid.F
 
diff --git a/src/model/src/ASX_DATA_MOD.F b/src/model/src/ASX_DATA_MOD.F
old mode 100755
new mode 100644
index 16b3095..48d9258
--- a/src/model/src/ASX_DATA_MOD.F
+++ b/src/model/src/ASX_DATA_MOD.F
@@ -121,6 +121,17 @@ Module ASX_DATA_MOD
          Real,    Allocatable :: PBL      ( :,: )  ! pbl height (m)
          Real,    Allocatable :: NACL_EMIS( :,: )  ! NACL mass emission rate of particles with d <10 um (g/m2/s)
 
+!> Inline Canopy Processes
+         Real,    Allocatable :: FCH      ( :,: )  ! Forest Canopy Height (m)
+         Real,    Allocatable :: FRT      ( :,: )  ! Forest Fraction
+         Real,    Allocatable :: CLU      ( :,: )  ! Clumping Index
+         Real,    Allocatable :: POPU     ( :,: )  ! Population Density (people/10km2)
+         Real,    Allocatable :: LAIE     ( :,: )  ! ECCC BELD3 Derived LAI (m2/m2)
+         Real,    Allocatable :: C1R      ( :,: )  ! cumulative LAI fraction hc to 0.75 * hc
+         Real,    Allocatable :: C2R      ( :,: )  ! cumulative LAI fraction hc to 0.50 * hc
+         Real,    Allocatable :: C3R      ( :,: )  ! cumulative LAI fraction hc to 0.35 * hc
+         Real,    Allocatable :: C4R      ( :,: )  ! cumulative LAI fraction hc to 0.20 * hc
+
 !> FENGSHA option
          Real,    Allocatable :: CLAYF    ( :,: )  ! Fractional Clay Content 
          Real,    Allocatable :: SANDF    ( :,: )  ! Fractional Sand Content 
@@ -285,6 +296,10 @@ Module ASX_DATA_MOD
       Real, Pointer, Private :: BUFF2D( :,: )   ! 2D temp var
       Real, Pointer, Private :: BUFF3D( :,:,: ) ! 3D temp var
 
+! Canopy option control
+      CHARACTER( 20 ), SAVE :: CTM_CANOPY_SHADE = 'CTM_CANOPY_SHADE    '! env var for in-line
+      LOGICAL,         PUBLIC, SAVE :: CANOPY_SHADE     ! flag in-lining canopy shading
+
 ! FENGSHA option control
       CHARACTER( 18 ),         SAVE :: CTM_WBDUST_FENGSHA = 'CTM_WBDUST_FENGSHA' ! env var for in-line
       LOGICAL,         PUBLIC, SAVE :: FENGSHA                     ! flag for fengsha option
@@ -630,6 +645,32 @@ Subroutine INIT_MET ( JDATE, JTIME, MOSAIC, ABFLUX, HGBIDI )
             ChemMos_Data%SubName = subname
          End If
 
+!> ccccccccccccccccccccc canopy shade option!ccccccccccccccccccccc
+         CANOPY_SHADE = ENVYN( 'CTM_CANOPY_SHADE',
+     &                   'Flag for in-line canopy shading',
+     &                   .FALSE., IOSX )
+
+!         IF ( CANOPY_SHADE ) THEN
+!            XMSG = 'Using in-line canopy shading option'
+!            CALL M3MSG2( XMSG )
+!         END IF
+         If ( CANOPY_SHADE  ) Then
+            ALLOCATE( Met_Data%FCH    ( NCOLS,NROWS ),
+     &                Met_Data%FRT    ( NCOLS,NROWS ),
+     &                Met_Data%CLU    ( NCOLS,NROWS ),
+     &                Met_Data%POPU   ( NCOLS,NROWS ),
+     &                Met_Data%LAIE   ( NCOLS,NROWS ),
+     &                Met_Data%C1R    ( NCOLS,NROWS ),
+     &                Met_Data%C2R    ( NCOLS,NROWS ),
+     &                Met_Data%C3R    ( NCOLS,NROWS ),
+     &                Met_Data%C4R    ( NCOLS,NROWS ),
+     &                STAT = ALLOCSTAT )
+            If ( ALLOCSTAT .Ne. 0 ) Then
+               XMSG = 'Failure allocating Canopy Shade variables'
+               Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            End If
+         End If
+
 !> ccccccccccccccccccccc Fengsha option!ccccccccccccccccccccc
          FENGSHA = ENVYN( CTM_WBDUST_FENGSHA,
      &                   'Flag for in-line fengsha ',
@@ -1090,6 +1131,80 @@ Subroutine GET_MET ( JDATE, JTIME, TSTEP, MOSAIC, ABFLUX, HGBIDI )
             XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
             Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
          End If
+
+C Canopy vars
+       If ( CANOPY_SHADE ) Then
+        VNAME = 'FCH'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2, STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%FCH ) ) Then
+            XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'FRT'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%FRT ) ) Then
+            XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'CLU'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%CLU ) ) Then
+            XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'POPU'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%POPU ) ) Then
+            XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'LAIE'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%LAIE ) ) Then
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'C1R'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%C1R ) ) Then
+            XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'C2R'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%C2R ) ) Then
+            XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'C3R'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%C3R ) ) Then
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+
+        VNAME = 'C4R'
+         If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
+     &                       STRTCOLMC2,ENDCOLMC2,STRTROWMC2,ENDROWMC2,1,1,
+     &                       JDATE, JTIME, Met_Data%C4R ) ) Then
+            XMSG = MSG1 // TRIM( VNAME ) // ' from ' // MET_CRO_2D
+            Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         End If
+       End If
+
 C FENGSHA vars
        If ( FENGSHA ) Then
         VNAME = 'CLAYF'
@@ -1124,6 +1239,7 @@ Subroutine GET_MET ( JDATE, JTIME, TSTEP, MOSAIC, ABFLUX, HGBIDI )
             Call M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
          End If
       End If
+
 C Soil vars
          VNAME = 'SOIM1'
          If ( .Not. INTERPX( MET_CRO_2D, VNAME, PNAME,
diff --git a/src/model/src/centralized_io_util_module.F b/src/model/src/centralized_io_util_module.F
new file mode 100644
index 0000000..f5b0653
--- /dev/null
+++ b/src/model/src/centralized_io_util_module.F
@@ -0,0 +1,282 @@
+
+!------------------------------------------------------------------------!
+!  The Community Multiscale Air Quality (CMAQ) system software is in     !
+!  continuous development by various groups and is based on information  !
+!  from these groups: Federal Government employees, contractors working  !
+!  within a United States Government contract, and non-Federal sources   !
+!  including research institutions.  These groups give the Government    !
+!  permission to use, prepare derivative works of, and distribute copies !
+!  of their work in the CMAQ system to the public and to permit others   !
+!  to do so.  The United States Environmental Protection Agency          !
+!  therefore grants similar permission to use the CMAQ system software,  !
+!  but users are requested to provide copies of derivative works or      !
+!  products designed to operate in the CMAQ system to the United States  !
+!  Government without restrictions as to use by others.  Software        !
+!  that is used with the CMAQ system but distributed under the GNU       !
+!  General Public License or the GNU Lesser General Public License is    !
+!  subject to their copyright restrictions.                              !
+!------------------------------------------------------------------------!
+
+!------------------------------------------------------------------------!
+! This module contains utility functions to support centralized I/O 
+! implementation
+
+! Revision History:
+!  02/01/19, D. Wong: initial implementation
+!  08/01/19, D. Wong: modified code to work with two-way model
+!  11/20/19, F. Sidi: Modified time to sec to handle negative numbers
+!------------------------------------------------------------------------!
+
+      module centralized_io_util_module
+
+        implicit none
+
+        interface quicksort
+          module procedure quicksort1d,
+     &                     quicksort2d
+        end interface
+
+        contains
+
+! -------------------------------------------------------------------------
+        recursive subroutine quicksort1d (name, begin, end)
+
+          character (*), intent(out) :: name(:)
+          integer, intent(in)         :: begin, end
+
+          integer        :: i, j
+          character (50) :: str1, str2
+          logical        :: done
+
+          str1 = name( (begin + end) / 2 )
+          i = begin
+          j = end
+          done = .false.
+          do while (.not. done)
+             do while (name(i) < str1)
+                i = i + 1
+             end do
+             do while (str1 < name(j))
+                j = j - 1
+             end do
+             if (i .ge. j) then
+                done = .true.
+             else
+                str2 = name(i)  
+                name(i) = name(j)
+                name(j) = str2
+                i = i + 1
+                j = j - 1
+             end if
+          end do
+          if (begin < i-1) call quicksort(name, begin, i-1)
+          if (j+1 < end)   call quicksort(name, j+1, end)
+
+        end subroutine quicksort1d
+
+! -------------------------------------------------------------------------
+        recursive subroutine quicksort2d (name, begin, end)
+
+          character (*), intent(out) :: name(:,:)
+          integer, intent(in)         :: begin, end
+
+          integer        :: i, j, dsize
+          character (50) :: str1, str2(3)
+          logical        :: done
+
+          dsize = size(name,2)
+          str1 = name( (begin + end) / 2, 1 )
+          i = begin
+          j = end
+          done = .false.
+          do while (.not. done)
+             do while (name(i,1) < str1)
+                i = i + 1
+             end do
+             do while (str1 < name(j, 1))
+                j = j - 1
+             end do
+             if (i .ge. j) then
+                done = .true.
+             else
+                str2(1:dsize) = name(i,:)  
+                name(i,:) = name(j,:)
+                name(j,:) = str2(1:dsize)
+                i = i + 1
+                j = j - 1
+             end if
+          end do
+          if (begin < i-1) call quicksort(name, begin, i-1)
+          if (j+1 < end)   call quicksort(name, j+1, end)
+
+        end subroutine quicksort2d
+
+! -------------------------------------------------------------------------
+        function binary_search (name, list, n) result (loc)
+
+          character (*), intent(in) :: name, list(:)
+          integer, intent(in)        :: n
+          integer :: loc
+
+          logical :: found
+          integer :: mid_loc, start_loc, end_loc
+
+          start_loc = 1
+          end_loc   = n
+          found = .false.
+          do while ((start_loc .le. end_loc) .and. (.not. found))
+             mid_loc = start_loc + (end_loc - start_loc) / 2
+             if (name .lt. list(mid_loc)) then
+                end_loc = mid_loc - 1
+             else if (name .gt. list(mid_loc)) then
+                start_loc = mid_loc + 1
+             else
+                found = .true.
+             end if
+          end do
+
+          if (found) then
+             loc = mid_loc
+          else
+             loc = -1
+          end if
+
+        end function binary_search
+
+! -------------------------------------------------------------------------
+        function search (name, list, n) result (loc)
+
+          character (*), intent(in) :: name, list(:)
+          integer, intent(in)        :: n
+          integer :: loc
+
+          logical :: found
+          integer :: lloc
+
+          lloc = 0
+          found = .false.
+          do while ((lloc .le. n) .and. (.not. found))
+             lloc = lloc + 1
+             if (name .eq. list(lloc)) then
+                found = .true.
+             end if
+          end do
+
+          if (found) then
+             loc = lloc
+          else
+             loc = -1
+          end if
+
+        end function search
+
+! -------------------------------------------------------------------------
+        integer function time_to_sec (time)
+
+          integer, intent(in) :: time
+          integer :: neg_time
+          integer :: time_in_sec, hr, min, sec
+
+          if (time .gt. 0) then
+             hr = time / 10000
+             min = mod(time/100, 100)
+             sec = mod(time, 100)
+             time_to_sec = hr * 3600 + min * 60 + sec
+          else
+             neg_time = abs(time)
+             hr = neg_time / 10000
+             min = mod(neg_time/100, 100)
+             sec = mod(neg_time, 100)
+             time_to_sec = -1*(hr * 3600 + min * 60 + sec)
+          end if
+          
+        end function time_to_sec
+
+! -------------------------------------------------------------------------
+        integer function time_diff (time1, time2)
+
+          integer, intent(in) :: time1, time2
+
+          time_diff = time_to_sec(time1) - time_to_sec(time2)
+
+        end function time_diff
+
+!--------------------------------------------------------------------------
+       integer function next_day (jday)
+
+! This function determermins the next day for time interpolation 
+          implicit none
+          
+          integer, intent(in) :: jday 
+          integer year, day
+
+          day  = MOD(jday,1000)
+          year = INT(jday/1000)
+
+          If( day .LT. 365 ) Then
+             next_day = jday+1
+          Else
+             If( MOD(year,4) .Eq. 0 .And. MOD(year,100) .Ne. 0 ) Then
+! Leap Year        
+                If( day .Eq. 365 ) Then
+                   next_day = jday + 1
+                Else
+                   next_day = (INT(jday/1000)+1)*1000+1
+                End If
+             Else If(MOD(year,400) .Eq. 0 ) Then
+! also a leap year, e.g. 2000 but not 2100
+                If( day .Eq. 365 ) Then
+                   next_day = jday + 1
+                Else
+                   next_day = (INT(jday/1000)+1)*1000+1
+                End If
+             Else
+! not a leap year
+                next_day = (INT(jday/1000)+1)*1000+1
+             End If
+          End If
+
+       end function next_day
+
+!--------------------------------------------------------------------------
+
+       function IntegrateTrapezoid(x, y)
+           !! Calculates the integral of an array y with respect to x using the trapezoid
+           !! approximation. Note that the mesh spacing of x does not have to be uniform.
+           real, intent(in)  :: x(:)                !! Variable x
+           real, intent(in)  :: y(size(x))          !! Function y(x)
+           real              :: IntegrateTrapezoid  !! Integral ∫y(x)·dx
+       ! Integrate using the trapezoidal rule
+           associate(n => size(x))
+             IntegrateTrapezoid = sum((y(1+1:n-0) + y(1+0:n-1))*(x(1+1:n-0) - x(1+0:n-1)))/2
+           end associate
+       end function
+
+! ---------------------------------------------------------------------------
+
+      function interp_linear1_internal(x,y,xout) result(yout)
+        !! Interpolates for the y value at the desired x value,
+        !! given x and y values around the desired point.
+
+        implicit none
+
+        real, intent(IN)  :: x(2), y(2), xout
+        real :: yout
+        real :: alph
+
+        if ( xout .lt. x(1) .or. xout .gt. x(2) ) then
+            write(*,*) "interp1: xout < x0 or xout > x1 !"
+            write(*,*) "xout = ",xout
+            write(*,*) "x0   = ",x(1)
+            write(*,*) "x1   = ",x(2)
+            stop
+        end if
+
+        alph = (xout - x(1)) / (x(2) - x(1))
+        yout = y(1) + alph*(y(2) - y(1))
+
+        return
+
+      end function interp_linear1_internal 
+
+      end module centralized_io_util_module
diff --git a/src/model/src/phot.F b/src/model/src/phot.F
new file mode 100644
index 0000000..1b8fd87
--- /dev/null
+++ b/src/model/src/phot.F
@@ -0,0 +1,1441 @@
+
+!------------------------------------------------------------------------!
+!  The Community Multiscale Air Quality (CMAQ) system software is in     !
+!  continuous development by various groups and is based on information  !
+!  from these groups: Federal Government employees, contractors working  !
+!  within a United States Government contract, and non-Federal sources   !
+!  including research institutions.  These groups give the Government    !
+!  permission to use, prepare derivative works of, and distribute copies !
+!  of their work in the CMAQ system to the public and to permit others   !
+!  to do so.  The United States Environmental Protection Agency          !
+!  therefore grants similar permission to use the CMAQ system software,  !
+!  but users are requested to provide copies of derivative works or      !
+!  products designed to operate in the CMAQ system to the United States  !
+!  Government without restrictions as to use by others.  Software        !
+!  that is used with the CMAQ system but distributed under the GNU       !
+!  General Public License or the GNU Lesser General Public License is    !
+!  subject to their copyright restrictions.                              !
+!------------------------------------------------------------------------!
+
+
+! RCS file, release, date & time of last delta, author, state, [and locker]
+! $Header: /project/yoj/arc/CCTM/src/phot/phot_inline/phot.F,v 1.7 2011/10/21 16:11:28 yoj Exp $
+
+! what(1) key, module and SID; SCCS file; date and time of last delta:
+! %W% %P% %G% %U%
+
+!:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
+      SUBROUTINE PHOT ( MDATE, MTIME, JDATE, JTIME, DTSTEP, RJ )
+
+!-----------------------------------------------------------------------
+!
+! Function:  Calculates the photolysis rate constant to be used by the
+!     chemical solver.  It calculates these rates at each gridcell using
+!     codes adapted from JPROC.  Cloud correction now called within the
+!     loops over MY-ROW & MY_COLS
+!
+! Preconditions: HGRD_INIT() called from PAR_INIT, which is called from
+!     DRIVER
+!
+! Subroutines/Functions called: INIT3, M3EXIT, SUBHFILE, CGRID_MAP,
+!     OPPHOT, LOAD_CSQY_DATA, LOAD_OPTICS_DATA, INITIALIZE_ALBEDO, 
+!     GET_PHOT_MET, UPDATE_SUN, GET_ALBEDO, GET_DROPLET_OPTICS, 
+!     GET_ICE_OPTICS, GET_AGGREGATE_OPTICS, CLEAR_HYDROMETEOR_OPTICS, 
+!     GET_AERO_DATA, O3TOTCOL, and NEW_OPTICS
+!
+! Revision History.
+!     Started 10/08/2004 with existing PHOT and JPROC coded by
+!         Dr. Francis S. Binkowski
+!         Carolina Environmental Program
+!         University of North Carolina at Chapel Hill
+!         email: frank_binkowski@unc.edu
+!     August 2005, Sarav Arunachalam, CEP, UNC-CH
+!       - Minor revisions while integrating with CMAQ
+!       - Error check for NPHOTS added (this version works only for SAPRC-99)
+!       - Added creation of new file CTM_RJ_1 to write out RJ values
+!         for O3 and NO2 (both clear sky and cloud effects), and
+!         ETOT_SFC, TAU_AERO, TAU_TOT and TAUO3_TOP values for 7 wavelengths
+!     June 2007, David Wong
+!       -- inline with CMAQ
+!       - declare RJ as assumed shape array to match with the caller routine
+!       - allow PE 0 only to open the output file
+!       - output species: NO2_CLOUD and O3_CLOUD with AMISS value when all cells
+!         are dark and JTIME_CHK = 0
+!       - output species: NO2_CLOUD and O3_CLOUD with AMISS value when CLDATT is
+!         0 and JTIME_CHK = 0
+!     December 2007, Francis Binkowski
+!         code has been modified to call the new on-line version that
+!         has the cloud effects built in.  new photolysis routine to
+!         replace PHOT in CMAQ
+!     January 2008, Shawn Roselle
+!       - reformatted for inclusion in CMAQ
+!       - added additional 3-d photolysis rate diagnostic file
+!       - moved code for opening the diagnostic files to a separate subroutine
+!       - moved aerosol pointer evaluation to a FORTRAN module
+!       - simplified code for writing the diagnostic file
+!       - changed code to call NEW_OPTICS twice, once for clear sky and
+!         another time for the cloudy fraction of the grid cell.  RJ's are
+!         computed based on the cloud fraction weighting.
+!      March 2011, Bill Hutzell
+!       - enable wavelength dependent arrays to have an allocatable number
+!         of wavelength bins
+!       - added data structure and algorithm to compute a surface albedo that
+!         depends on time and landuse catagory based on work by John Striecher
+!         (AMAD/USEPA)
+!       - revised writing to RJ1 file to include surface albedo
+!       - moved photolysis and opacity data from CSQY module to an ASCII input
+!         file
+!       - added routine called LOAD_REF_DATA (inside the PHOT_MOD module) that i
+!         reads this input file
+!       - added call to a routine called AERO_PHOTDATA that returns opacity data
+!         on the aerosol distribution
+!       - revised NEW_OPTICS' arguments based on  aerosol redesign in CMAQ
+!         version 5.0
+!     March 29, 2011 S.Roselle
+!       - Replaced I/O API include files with UTILIO_DEFN
+!     07 Jul 14 B.Hutzell: replaced mechanism include file(s) with fortran module
+!     26 Sep 14 B.Hutzell: 1) moved calculation of surface albedo to its own
+!                             fortran module
+!                          2) changed loading procedure for loading optical data;
+!                             two files now used
+!                          3) reading and calculation of met and geo data
+!                             now acomplished by a fortran module
+!                          4) changed description and accounting of cloud effects
+!                             from 2D liquid water clouds to 3D resolved and subgrid 
+!                             clouds with multi-phases of water
+!                          5) inserted calculation of aerosol optical properites via
+!                             fortran module to improve efficiency in radiative
+!                             transfer solution
+!                          6) moved the O3TOTCOL routine from the PHOT_MOD to simplify
+!                             the NEW_OPTICS routine
+!                          7) Several miscellaneous changes attempting to improve efficiency
+!     June 10 15 J.Young: Modified diagnostic output timestamp to fix for other than one
+!                         hour time steps.
+!     Aug 12, 15 D. Wong: Replaced MYPE with IO_PE_INCLUSIVE for parallel I/O implementation
+
+!----------------------------------------------------------------------
+
+C...modules
+
+      USE RXNS_DATA            ! chemistry varaibles and data
+      USE CGRID_SPCS           ! CGRID species number and offsets
+      USE PCGRID_DEFN          ! get cgrid
+      USE UTILIO_DEFN
+      USE AERO_DATA            ! describes aerosol distribution
+      USE PHOT_MOD             ! photolysis in-line module - inherits CSQY_DATA module
+      USE AERO_PHOTDATA        ! arrays and routines for aerosol dimensions and refractive indices
+      USE PHOTOLYSIS_ALBEDO    ! surface albedo data and routines
+      USE PHOT_MET_DATA        ! Met and Grid data
+      USE CLOUD_OPTICS         ! data and routines for optics of cloud hydrometeors
+!      USE STRATOS_O3_MINFRACS  ! annual minimum fraction of ozone column density above Pressure TOP
+!      USE SEAS_STRAT_O3_FRACS  ! monthly minimum fraction of ozone column density above Pressure TOP
+      USE SEAS_STRAT_O3_MIN    ! monthly minimum fraction of ozone column density above Pressure TOP
+!Used for canopy shade calculation
+      USE ASX_DATA_MOD, ONLY : MET_DATA     !uses met data
+      USE centralized_io_util_module, ONLY: IntegrateTrapezoid, interp_linear1_internal !basic utilities
+
+#ifdef parallel
+      USE SE_MODULES           ! stenex (using SE_UTIL_MODULE)
+#else
+      USE NOOP_MODULES         ! stenex (using NOOP_UTIL_MODULE)
+#endif
+
+      IMPLICIT NONE
+
+!...include files
+
+      INCLUDE SUBST_FILES_ID   ! file name parameters
+!     INCLUDE SUBST_CONST      ! physical constants--moved to PHOT_MOD.
+
+!...arguments
+
+      INTEGER, INTENT( IN ) :: MDATE         ! "centered" Julian date (YYYYDDD)
+      INTEGER, INTENT( IN ) :: MTIME         ! "centered" time (HHMMSS)
+      INTEGER, INTENT( IN ) :: JDATE         ! current Julian date (YYYYDDD)
+      INTEGER, INTENT( IN ) :: JTIME         ! current time (HHMMSS)
+      INTEGER, INTENT( IN ) :: DTSTEP( : )   ! time step vector (HHMMSS)
+
+!     REAL RJ( NCOLS,NROWS,NLAYS, NPHOTAB )
+      REAL,    INTENT( OUT ) :: RJ( :,:,:,: )  ! gridded J-values  (1/min units)
+
+!     REAL CGRID( NCOLS,NROWS,NLAYS, * )  ! Conc array
+      REAL, SAVE, POINTER :: CGRID( :,:,:,: ) ! species concentrations
+
+!...parameters
+
+      LOGICAL, PARAMETER :: CLDATT = .TRUE.   ! include cloud attenuation
+
+      REAL, PARAMETER :: DENS_CONV = ( 1.0E+03 * AVO / MWAIR ) * 1.0E-06  ! convert from kg/m**3 to #/cc
+      REAL, PARAMETER :: PPM_MCM3  = 1.0E-06  ! convert from ppm to molecules / cc mol_Spec/mol_Air = ppm * 1E-06
+      REAL, PARAMETER :: PRES_CONV = 1.0 / STDATMPA ! conversion factor Pa to atm
+      REAL, PARAMETER :: ZTOA      = 50.0E3   ! height of top of atmosphere [ m ] (=50km)
+                                              ! based a 2005 WRF model Documentation
+                                                 
+      REAL, PARAMETER   :: EPSLON  = 1.0E-30  ! Small number
+
+!...external functions: none
+
+!...local variables
+
+      LOGICAL, SAVE :: FIRSTIME = .TRUE.  ! Flag for first call to PHOT
+      LOGICAL, SAVE :: PHOTDIAG           ! Flag for PHOTDIAG file
+
+      LOGICAL, SAVE :: CALL_INIT_ALBEDO = .TRUE.
+      LOGICAL, SAVE :: CALL_GET_ALBEDO  = .TRUE.
+      
+      LOGICAL       :: ZERO_ICE
+
+      CHARACTER(   3 ), ALLOCATABLE, SAVE :: WLTXT( : )
+      CHARACTER(  16 )                    :: VARNM
+      CHARACTER(  16 ), SAVE              :: PNAME = 'PHOT'
+      CHARACTER(  16 ), SAVE              :: CTM_PHOTDIAG = 'CTM_PHOTDIAG'
+
+      CHARACTER(  80 ) :: VARDESC  ! environment variable description
+      CHARACTER( 240 ) :: XMSG = ' '
+
+      INTEGER,    SAVE :: LOGDEV
+      INTEGER,    SAVE :: LGC_O3   ! pointer to O3 in CGRID
+      INTEGER,    SAVE :: LGC_NO2  ! pointer to NO2 in CGRID
+      INTEGER,    SAVE :: TSTEP    ! output timestep in sec
+
+      INTEGER ESTAT                ! status from environment var check
+      INTEGER IPHOT                ! photolysis rate loop index
+      INTEGER ROW
+      INTEGER COL
+      INTEGER LEV
+      INTEGER SPC
+      INTEGER IWL
+      INTEGER L
+      INTEGER V, N, MODE
+      LOGICAL JTIME_CHK            ! To check for JTIME to write RJ values
+      INTEGER ODATE                ! output date
+      INTEGER OTIME                ! output time 
+
+      INTEGER ALLOCSTAT
+
+      INTEGER, SAVE :: TDATE
+      INTEGER, SAVE :: GXOFF, GYOFF        ! global origin offset from file
+      INTEGER, SAVE :: PECOL_OFFSET        ! Local Column Offset for processor
+      INTEGER, SAVE :: PEROW_OFFSET        ! Local Column Offset for processor
+      INTEGER, SAVE :: TSTEP_COUNT         ! counter between calls to write diagnostics
+
+! for INTERPX
+      INTEGER, SAVE :: STRTCOLGC2, ENDCOLGC2, STRTROWGC2, ENDROWGC2
+      INTEGER, SAVE :: STRTCOLMC2, ENDCOLMC2, STRTROWMC2, ENDROWMC2
+      INTEGER, SAVE :: STRTCOLMC3, ENDCOLMC3, STRTROWMC3, ENDROWMC3
+
+      REAL CURRHR          ! current GMT hour
+      REAL JULIAN_DAY      ! time of year [days]
+      REAL CURRHR_LST      ! local standard time at each grid cell
+      REAL CTOP            ! cloud top in single dimension
+      REAL CBASE           ! cloud base in single dimension
+      REAL ZLEV            ! height in single dimension
+      REAL ZEN             ! cosine of zenith angle
+      REAL SINLAT          ! sine of latitude
+      REAL COSLAT          ! cosine of latitude
+      REAL RSQD            ! square of soldist
+      REAL ZSFC            ! surface height (msl) [ m ]
+      REAL EQT             ! equation of time
+      REAL SOLDIST         ! solar distance [ au ]
+      REAL SINDEC          ! sine of the solar declination
+      REAL COSDEC          ! cosine of the solar declination
+      REAL COSZEN          ! working cosine of the solar zenith angle
+      REAL SINZEN          ! working sine of the solar zenith angle
+      REAL LATCR           ! local latitude
+      REAL LONCR           ! local longitude
+      REAL OWATER_FRAC     ! Open water fraction
+      REAL SNOW_FRAC       ! Snow fractional coverage
+      REAL SEAICE_FRAC     ! Sea Ice fraction
+      REAL RES_SKY_REFLECT ! reflection coefficient based on resolved sky
+      REAL RES_SKY_TRANS   ! diffuse transmission coefficient based on resolved sky
+      REAL RES_SKY_TRANSD  ! direct transmission coefficient based on resolved sky
+
+      REAL                    :: TOTAL_O3_COLUMN ! total ozone column density, DU
+      
+      REAL,              SAVE :: JYEAR          = 0.0 ! year
+      REAL,              SAVE :: JD_STRAT_O3MIN = 0.0 ! Julian day (YYYYDDD) of min fraction for stratos ozone
+
+      INTEGER, PARAMETER  :: DAYS( 12 ) = (/ 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 /)
+      INTEGER, SAVE       :: IMONTH = 0
+
+      REAL, ALLOCATABLE, SAVE :: ETOT_SFC ( : )    ! total downward irradiance at sfc [ Watts / m**2  ]
+      REAL, ALLOCATABLE, SAVE :: TAUO3_TOP( : )    ! optical depth of ozone above model domain
+      REAL, ALLOCATABLE, SAVE :: TAU_RAY  ( : )    ! Rayleigh optical depth above model domain
+      REAL, ALLOCATABLE, SAVE :: TAUC_AERO( :,: )  ! aerosol optical depth at layer bottom
+      REAL, ALLOCATABLE, SAVE :: TAU_TOT  ( :,: )  ! total optical depth at layer bottom
+      REAL, ALLOCATABLE, SAVE :: TAU_CLOUD( :,: )  ! cloud optical depth at layer bottom
+
+      REAL, ALLOCATABLE, SAVE :: SSA      ( : ) ! aerosol single scattering albedo, column average
+
+      REAL MSCALE          ! combined factor to scale ppm to Molecules / cm**3
+                           ! and correct for ambient temperaure and pressure
+
+! FSB new arrays for new on-line cloud version
+
+      REAL, ALLOCATABLE, SAVE :: LWC    ( : )      ! cloud liquid water content [ g/m**3 ]
+      REAL, ALLOCATABLE, SAVE :: RWC    ( : )      ! rain water content [ g/m**3 ]
+      REAL, ALLOCATABLE, SAVE :: IWC    ( : )      ! ice liquid water content [ g/m**3 ]
+      REAL, ALLOCATABLE, SAVE :: SWC    ( : )      ! snow content [ g/m**3 ]
+      REAL, ALLOCATABLE, SAVE :: GWC    ( : )      ! graupel content [ g/m**3 ]
+      REAL, ALLOCATABLE, SAVE :: CLDFRAC( : )      ! fractional cloud cover
+      REAL, ALLOCATABLE, SAVE :: BLKPRS ( : )      ! Air pressure in [ Pa ]
+      REAL, ALLOCATABLE, SAVE :: BLKTA  ( : )      ! Air temperature [ K ]
+      REAL, ALLOCATABLE, SAVE :: BLKDENS( : )      ! Air density  [ molecules / m**3 ]
+      REAL, ALLOCATABLE, SAVE :: BLKZH  ( : )      ! layer half-height [ m ]
+      REAL, ALLOCATABLE, SAVE :: BLKO3  ( : )      ! O3 concentration [ molecules/cm**3 ]
+      REAL, ALLOCATABLE, SAVE :: BLKNO2 ( : )      ! NO2 concentration [ molecules/cm**3 ]
+      REAL, ALLOCATABLE, SAVE :: BLKZF  ( : )      ! layer full-height [ m ]
+
+      REAL, ALLOCATABLE, SAVE :: BLKRJ_RES( :, : ) ! photolysis rates
+      REAL, ALLOCATABLE, SAVE :: BLKRJ_ACM( :, : ) ! photolysis rates
+      
+      LOGICAL, ALLOCATABLE, SAVE :: CLOUDS( : )    ! Does layer have clouds?
+      LOGICAL                    :: NEW_PROFILE    ! Has atmospheric temperature and density profile changed?
+      LOGICAL                    :: DARK           ! Are this processor's cells in darkness?
+
+! Canopy in-line control
+      CHARACTER( 20 ), SAVE :: CTM_CANOPY_SHADE = 'CTM_CANOPY_SHADE    ' ! env var for in-line
+      LOGICAL,         SAVE :: CANOPY_SHADE   ! flag in-lining canopy shading
+
+! Canopy arrays
+      REAL, ALLOCATABLE, SAVE  :: RJ_CORR_C1R ( :, :)    ! canopy shading correction to J-values (hc to 0.75*hc)
+      REAL, ALLOCATABLE, SAVE  :: RJ_CORR_C2R ( :, :)    ! canopy shading correction to J-values (hc to 0.50*hc)
+      REAL, ALLOCATABLE, SAVE  :: RJ_CORR_C3R ( :, :)    ! canopy shading correction to J-values (hc to 0.35*hc)
+      REAL, ALLOCATABLE, SAVE  :: RJ_CORR_C4R ( :, :)    ! canopy shading correction to J-values (hc to 0.20*hc)
+      REAL, ALLOCATABLE, SAVE  :: RJ_CORR_BOT ( :, :)    ! canopy shading correction to J-values (0.20*hc to bottom)
+      REAL, ALLOCATABLE, SAVE  :: RJ_CORR ( :, :)        ! total/integrated canopy shading correction to J-values
+      REAL, ALLOCATABLE, SAVE  :: ZCANX    ( : )        ! canopy heights[m]
+      REAL, ALLOCATABLE, SAVE  :: RJ_CORRX ( : )        ! canopy height dependent photolysis attenuation factor
+      REAL                    :: XCAN     ( 2 )        ! canopy height interpolation bounds
+      REAL                    :: YCAN     ( 2 )        ! photolysisattenuation interpolation bounds
+      REAL ZFL, ZCAN, XCANOUT, BOTCAN                  ! local canopy variables
+      INTEGER                 :: COUNTCAN, KCAN
+      INTEGER, PARAMETER      :: MAXCAN = 1000         ! Declare local maximum canopy layers
+
+!...Variables for diagnostic outputs
+
+      REAL, ALLOCATABLE, SAVE :: N_EXCEED_TROPO3( :,: )  ! Number of adjustments tropospheric ozone optical depth
+
+      REAL, ALLOCATABLE, SAVE :: TOTAL_OC( :,: )         ! total ozone column [DU]
+      REAL, ALLOCATABLE, SAVE :: TROPO_OC( :,: )         ! tropospheric ozone column [DU]
+      REAL, ALLOCATABLE, SAVE :: TROPO_O3_EXCEED( :,: )   ! Factor used to adjust tropospheric ozone optical depth
+      REAL, ALLOCATABLE, SAVE :: TRANSMIS_DIFFUSE( :,: ) ! diffuse transmission coefficient at surface
+      REAL, ALLOCATABLE, SAVE :: TRANSMIS_DIRECT( :,: )  ! direct transmission coefficient at surface
+      REAL, ALLOCATABLE, SAVE :: REFLECT_COEFF( :,: )    ! reflection coefficient at top of atmosphere
+      REAL, ALLOCATABLE, SAVE :: ETOT_SFC_WL ( :,:,: )   ! total downward irradiance at sfc [ Watts / m**2  ]
+      REAL, ALLOCATABLE, SAVE :: TAU_AERO_WL ( :,:,: )   ! total aerosol optical depth
+      REAL, ALLOCATABLE, SAVE :: TAU_CLOUD_WL( :,:,: )   ! total cloud optical depth
+      REAL, ALLOCATABLE, SAVE :: CLR_TRANSMISSION( :,: ) ! diffuse transmission coefficient of clouds
+      REAL, ALLOCATABLE, SAVE :: CLR_REFLECTION  ( :,: ) ! reflection coefficient of cloud
+      REAL, ALLOCATABLE, SAVE :: CLR_TRANS_DIRECT( :,: ) ! direct transmission coefficient of clouds
+#ifdef phot_debug      
+      REAL, ALLOCATABLE, SAVE :: ASY_CLOUD_WL( :,:,: ) ! columm average of cloud asymmetry factor
+      REAL, ALLOCATABLE, SAVE :: SSA_CLOUD_WL( :,:,: ) ! columm average of cloud single scattering albedo
+#endif      
+      REAL, ALLOCATABLE, SAVE :: TAU_TOT_WL  ( :,:,: ) ! total optical depth
+      REAL, ALLOCATABLE, SAVE :: TAUO3_TOP_WL( :,:,: ) ! optical depth of ozone above model domain
+
+      REAL, ALLOCATABLE, SAVE :: AERO_SSA  ( :,:,:,: ) ! aerosol single scattering albedo
+      REAL, ALLOCATABLE, SAVE :: AERO_ASYM ( :,:,:,: ) ! aerosol asymmetry factor
+      REAL, ALLOCATABLE, SAVE :: TAU       ( :,:,:,: ) ! optical depth
+      REAL, ALLOCATABLE, SAVE :: TAU_AERO  ( :,:,:,: ) ! aerosol optical depth
+      REAL, ALLOCATABLE, SAVE :: ACTINIC_FX( :,:,:,: ) ! net actinic flux [watts/m**2]
+
+      INTEGER          IOSX            ! i/o and allocate memory status
+
+      INTERFACE
+         SUBROUTINE O3TOTCOL ( LATITUDE, LONGITUDE, JDATE, OZONE )
+            INTEGER, INTENT( IN )    :: JDATE      ! Julian day of the year (yyyyddd)
+            REAL,    INTENT( IN )    :: LATITUDE   ! latitude of point on earth's surface
+            REAL,    INTENT( IN )    :: LONGITUDE  ! longitude of point on earth's surface
+            REAL,    INTENT( INOUT ) :: OZONE      ! total column ozone [DU]
+         END SUBROUTINE O3TOTCOL
+      END INTERFACE
+
+! ----------------------------------------------------------------------
+
+      IF ( FIRSTIME ) THEN
+
+C In-line canopy shading option? (default = false)
+
+         CANOPY_SHADE = ENVYN( 'CTM_CANOPY_SHADE',
+     &                   'Flag for in-line canopy shading',
+     &                   .FALSE., IOSX )
+
+         IF ( CANOPY_SHADE ) THEN
+            XMSG = 'Using in-line canopy shading option'
+            CALL M3MSG2( XMSG )
+         END IF
+
+         FIRSTIME = .FALSE.
+         LOGDEV   = INIT3()
+
+         TSTEP  = TIME2SEC( DTSTEP( 1 ) ) ! output timestep for phot diagnostic files
+
+         CGRID => PCGRID( 1:MY_NCOLS,1:MY_NROWS,:,: )
+
+!...Get photolysis rate diagnostic file flag
+
+         PHOTDIAG = .FALSE.         ! default
+         VARDESC= 'Flag for writing the photolysis rate diagnostic file'
+         PHOTDIAG = ENVYN( CTM_PHOTDIAG, VARDESC, PHOTDIAG, ESTAT )
+         IF ( ESTAT .NE. 0 ) WRITE( LOGDEV, '(5X, A)' ) VARDESC
+         IF ( ESTAT .EQ. 1 ) THEN
+            XMSG = 'Environment variable improperly formatted'
+            CALL M3EXIT( PNAME, JDATE, JTIME, XMSG, XSTAT2 )
+         ELSE IF ( ESTAT .EQ. -1 ) THEN
+            XMSG =
+     &          'Environment variable set, but empty ... Using default:'
+            WRITE( LOGDEV, '(5X, A, I9)' ) XMSG, JTIME
+         ELSE IF ( ESTAT .EQ. -2 ) THEN
+            XMSG = 'Environment variable not set ... Using default:'
+            WRITE( LOGDEV, '(5X, A, I9)' ) XMSG, JTIME
+         END IF
+
+!...Get met file offsets
+
+         CALL SUBHFILE ( GRID_CRO_2D, GXOFF, GYOFF,
+     &                   STRTCOLGC2, ENDCOLGC2, STRTROWGC2, ENDROWGC2 )
+         CALL SUBHFILE ( MET_CRO_2D, GXOFF, GYOFF,
+     &                   STRTCOLMC2, ENDCOLMC2, STRTROWMC2, ENDROWMC2 )
+         CALL SUBHFILE ( MET_CRO_3D, GXOFF, GYOFF,
+     &                   STRTCOLMC3, ENDCOLMC3, STRTROWMC3, ENDROWMC3 )
+ 
+         PECOL_OFFSET = COLSD_PE( 1, MYPE+1 ) - 1
+         PEROW_OFFSET = ROWSD_PE( 1, MYPE+1 ) - 1
+
+         CALL LOAD_CSQY_DATA( )
+
+         CALL LOAD_OPTICS_DATA( )         
+ 
+!...Allocate array needed to calculation aerosol and cloud optical properties
+
+         CALL INIT_AERO_DATA(  )
+         
+         CALL INIT_CLOUD_OPTICS(  )
+
+!...Allocate and initialize new canopy arrays
+        IF ( CANOPY_SHADE ) THEN
+           ALLOCATE( RJ_CORRX     ( MAXCAN ) )
+           ALLOCATE( ZCANX        ( MAXCAN ) )
+
+           ALLOCATE( RJ_CORR_C1R  ( NCOLS, NROWS ),
+     &            RJ_CORR_C2R  ( NCOLS, NROWS ),
+     &            RJ_CORR_C3R  ( NCOLS, NROWS ),
+     &            RJ_CORR_C4R  ( NCOLS, NROWS ),
+     &            RJ_CORR_BOT  ( NCOLS, NROWS ),
+     &            RJ_CORR      ( NCOLS, NROWS ), STAT = ALLOCSTAT )
+           IF ( ALLOCSTAT .NE. 0 ) THEN
+              XMSG = 'Failure allocating canopy photolysis rate correction arrays'
+              CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+           END IF
+
+           RJ_CORRX=0.0
+           ZCANX=0.0
+           RJ_CORR_C1R=0.0
+           RJ_CORR_C2R=0.0
+           RJ_CORR_C3R=0.0
+           RJ_CORR_C4R=0.0
+           RJ_CORR_BOT=0.0
+           RJ_CORR=0.0
+        END IF
+
+!...Initialize Surface albedo method
+
+         IF ( .NOT. INITIALIZE_ALBEDO( JDATE, JTIME, LOGDEV ) ) THEN
+              XMSG = 'Failure initializing photolysis surface albedo algorithm'
+              CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         ALLOCATE( ETOT_SFC ( NWL ) )
+
+         ALLOCATE( LWC    ( NLAYS ) ) 
+         ALLOCATE( RWC    ( NLAYS ) ) 
+         ALLOCATE( IWC    ( NLAYS ) ) 
+         ALLOCATE( SWC    ( NLAYS ) ) 
+         ALLOCATE( GWC    ( NLAYS ) ) 
+         ALLOCATE( BLKPRS ( NLAYS ) ) 
+         ALLOCATE( BLKTA  ( NLAYS ) ) 
+         ALLOCATE( BLKDENS( NLAYS ) ) 
+         ALLOCATE( BLKZH  ( NLAYS ) ) 
+         ALLOCATE( BLKO3  ( NLAYS ) ) 
+         ALLOCATE( BLKNO2 ( NLAYS ) ) 
+         ALLOCATE( BLKZF  ( NLAYS+1 ) )
+         ALLOCATE( CLOUDS ( NLAYS ) ) 
+         ALLOCATE( CLDFRAC( NLAYS ) ) 
+
+         ALLOCATE( BLKRJ_RES( NLAYS,NPHOTAB ) )
+         ALLOCATE( BLKRJ_ACM( NLAYS,NPHOTAB ) )
+
+         ALLOCATE( TAUO3_TOP( NWL ) )
+         ALLOCATE( TAU_RAY  ( NWL ) )
+         ALLOCATE( SSA      ( NWL ) )
+
+         ALLOCATE( TAU_CLOUD( NLAYS,NWL ) )
+         ALLOCATE( TAUC_AERO( NLAYS,NWL ) )
+         ALLOCATE( TAU_TOT  ( NLAYS,NWL ) )
+
+         ALLOCATE( TOTAL_OC ( NCOLS,NROWS ) )
+
+         IF ( PHOTDIAG ) THEN
+            ALLOCATE( TROPO_OC ( NCOLS,NROWS ) )
+            ALLOCATE( TROPO_O3_EXCEED( NCOLS,NROWS ) )
+            ALLOCATE( N_EXCEED_TROPO3( NCOLS,NROWS ) )
+            ALLOCATE( TRANSMIS_DIFFUSE( NCOLS,NROWS ) )
+            ALLOCATE( TRANSMIS_DIRECT ( NCOLS,NROWS ) )
+            ALLOCATE( REFLECT_COEFF   ( NCOLS,NROWS ) )
+            ALLOCATE( CLR_TRANSMISSION( NCOLS,NROWS ) )
+            ALLOCATE( CLR_TRANS_DIRECT( NCOLS,NROWS ) )
+            ALLOCATE( CLR_REFLECTION  ( NCOLS,NROWS ) )
+            ALLOCATE( ETOT_SFC_WL     ( NCOLS,NROWS,NWL ) )
+            ALLOCATE( TAU_AERO_WL     ( NCOLS,NROWS,NWL ) )
+            ALLOCATE( TAU_CLOUD_WL    ( NCOLS,NROWS,NWL ) )
+#ifdef phot_debug            
+            ALLOCATE( SSA_CLOUD_WL( NCOLS,NROWS,NWL ) )
+            ALLOCATE( ASY_CLOUD_WL( NCOLS,NROWS,NWL ) )
+#endif            
+            ALLOCATE( TAU_TOT_WL  ( NCOLS,NROWS,NWL ) )
+            ALLOCATE( TAUO3_TOP_WL( NCOLS,NROWS,NWL ) )
+ 
+            N_EXCEED_TROPO3 = 0.0
+            TROPO_O3_EXCEED = 0.0
+            TSTEP_COUNT     = 0
+
+            DIAG_WVL( 1 )    = 1
+            DIAG_WVL( N_DIAG_WVL ) = NWL
+
+            ALLOCATE ( AERO_ASYM( NCOLS,NROWS,NLAYS,N_DIAG_WVL ), STAT = ALLOCSTAT )
+            IF ( ALLOCSTAT .NE. 0 ) THEN
+               XMSG = 'Failure allocating 3D AERO_ASYM'
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            ALLOCATE ( AERO_SSA( NCOLS,NROWS,NLAYS,N_DIAG_WVL ), STAT = ALLOCSTAT )
+            IF ( ALLOCSTAT .NE. 0 ) THEN
+               XMSG = 'Failure allocating 3D AERO_SSA'
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            ALLOCATE ( TAU_AERO( NCOLS,NROWS,NLAYS,N_DIAG_WVL ), STAT = ALLOCSTAT )
+            IF ( ALLOCSTAT .NE. 0 ) THEN
+               XMSG = 'Failure allocating 3D TAU_AERO'
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            ALLOCATE ( TAU( NCOLS,NROWS,NLAYS,N_DIAG_WVL ), STAT = ALLOCSTAT )
+            IF ( ALLOCSTAT .NE. 0 ) THEN
+               XMSG = 'Failure allocating 3D TAU'
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            ALLOCATE ( ACTINIC_FX( NCOLS,NROWS,NLAYS,NWL ), STAT = ALLOCSTAT )
+            IF ( ALLOCSTAT .NE. 0 ) THEN
+               XMSG = 'Failure allocating ACTINIC_FX'
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+!...write wavelength data to a character array
+
+            ALLOCATE ( WLTXT( NWL ) )
+
+            DO IWL = 1, NWL
+               WRITE( WLTXT( IWL ),'(I3.3)' ) INT( WAVELENGTH( IWL ) )
+            END DO
+
+!...open the photolysis rate diagnostic files
+
+            ODATE = JDATE; OTIME = JTIME
+#ifndef phot_extra_tstep
+            CALL NEXTIME ( ODATE, OTIME, DTSTEP( 1 ) )  ! output timestamp ending time
+#endif
+            IF ( IO_PE_INCLUSIVE ) CALL OPPHOT ( ODATE, OTIME, DTSTEP( 1 ) )
+
+            CALL SUBST_BARRIER
+
+         END IF  ! photdiag
+
+!...set pointers to species O3 and NO2 in CGRID
+
+         VARNM = 'O3'
+         LGC_O3 = INDEX1( VARNM, N_GC_SPC, GC_SPC )
+         IF ( LGC_O3 .LE. 0 ) THEN
+            XMSG = 'Could not find ' // VARNM // 'in species table'
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT3 )
+         END IF
+
+         VARNM = 'NO2'
+         LGC_NO2 = INDEX1( VARNM, N_GC_SPC, GC_SPC )
+         IF ( LGC_NO2 .LE. 0 ) THEN
+            XMSG = 'Could not find ' // VARNM // 'in species table'
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT3 )
+         END IF
+
+#ifdef phot_extra_tstep
+      ELSE
+         IF ( PHOTDIAG ) THEN
+            ODATE = JDATE; OTIME = JTIME
+            CALL NEXTIME ( ODATE, OTIME, DTSTEP( 2 ) )  ! sync time step
+         END IF
+#endif
+      END IF  ! firstime
+
+      IF ( JD_STRAT_O3MIN .NE. JDATE ) THEN
+!...set minimum fraction of ozone column above PTOP
+
+         CALL SEASONAL_STRAT_O3( JDATE, JTIME )
+         MIN_STRATO3_FRAC = MONTH_STRAT_03_FRAC
+         MAX_TROPOO3_FRAC = MAX( 1.0 - MONTH_STRAT_03_FRAC, 0.0 )
+         WRITE( LOGDEV,*)'PHOT: MIN_STRATO3_FRAC = ',MIN_STRATO3_FRAC 
+         
+         JD_STRAT_O3MIN = REAL( JDATE, 4)
+      END IF
+!...initialize variables tracking whether stratosphere ozone column satisfies
+!...climatological averages.
+
+      O3_TOGGLE_AVE     = 0.0
+      O3_TOGGLE_MIN     = 1.0
+      N_TROPO_O3_TOGGLE = 0
+      TSTEP_COUNT       = TSTEP_COUNT + 1
+
+      CALL GET_PHOT_MET( JDATE, JTIME, MDATE, MTIME )
+
+!...Get cosine of solar parameters and set DARK
+
+      CALL UPDATE_SUN( JDATE, JTIME, MDATE, MTIME )
+      
+      RSQD = DIST_TO_SUN * DIST_TO_SUN
+
+      IF ( MAXVAL( COSINE_ZENITH ) .LE. 0.0 ) THEN
+         DARK = .TRUE.
+      ELSE
+         DARK = .FALSE.
+      END IF
+
+!...set surface albedos
+
+      CALL GET_ALBEDO( MDATE, MTIME, LOGDEV, COSINE_ZENITH, LAT, LON )
+
+!...SA  Write COSINE_ZENITH array at the end of each output tstep
+
+      IF ( PHOTDIAG ) THEN
+#ifndef phot_extra_tstep
+         ODATE = JDATE; OTIME = JTIME
+         CALL NEXTIME ( ODATE, OTIME, DTSTEP( 2 ) )  ! sync time step
+#endif
+         JTIME_CHK = ( MOD( TIME2SEC( OTIME ), TSTEP ) .EQ. 0 ) 
+#ifdef parallel_io
+         IF ( .NOT. IO_PE_INCLUSIVE ) THEN
+            IF ( .NOT. OPEN3( CTM_RJ_1, FSREAD3, PNAME ) ) THEN
+               XMSG = 'Could not open ' // TRIM(CTM_RJ_1)
+               CALL M3EXIT( PNAME, ODATE, OTIME, XMSG, XSTAT1 )
+            END IF
+            IF ( .NOT. OPEN3( CTM_RJ_2, FSREAD3, PNAME ) ) THEN
+               XMSG = 'Could not open ' // TRIM(CTM_RJ_2)
+               CALL M3EXIT( PNAME, ODATE, OTIME, XMSG, XSTAT1 )
+            END IF
+         END IF
+#endif
+      ELSE     
+         JTIME_CHK = .FALSE.
+      END IF 
+
+      
+!...If sun below horizon at all cells, zero photolysis rates & exit
+!...  (assumes sun below horizon at *all* levels!)
+
+      IF ( DARK ) THEN
+
+         RJ = 0.0
+
+!...write to the log file, CTM_RJ_1 file and return
+
+         WRITE( LOGDEV, 1003 ) MYPE, JDATE, JTIME
+
+!...Initialize ETOT_SFC, TAU_AERO, TAU_TOT, TAUO3_TOP to 0.0
+
+!...Write data to output diagnostic file
+
+         TOTAL_OC = 0.0
+
+         IF ( JTIME_CHK ) THEN
+
+            TROPO_OC     = 0.0
+            ETOT_SFC_WL  = 0.0
+            TAUO3_TOP_WL = 0.0
+            TAU_AERO_WL  = 0.0
+            TAU_CLOUD_WL = 0.0
+#ifdef phot_debug                   
+            SSA_CLOUD_WL = 0.0
+            ASY_CLOUD_WL = 0.0
+#endif                   
+            TAU_TOT_WL   = 0.0
+            TAU          = 0.0
+            TAU_AERO     = 0.0
+            AERO_SSA     = 0.0
+            AERO_ASYM    = 0.0
+            ACTINIC_FX   = 0.0
+
+!           TROPO_O3_EXCEED   = 0.0
+            TRANSMIS_DIFFUSE  = 0.0
+            TRANSMIS_DIRECT   = 0.0
+            REFLECT_COEFF     = 0.0
+            CLR_TRANSMISSION  = 0.0
+            CLR_TRANS_DIRECT  = 0.0
+            CLR_REFLECTION    = 0.0 
+
+         END IF  ! if JTIME_CHK
+
+      ELSE  ! all cells not dark
+
+!...MAIN loop over all rows and columns
+         LOOP_ROWS: DO ROW = 1, MY_NROWS
+            LOOP_COLS: DO COL = 1, MY_NCOLS
+         
+               PHOT_COL = COL + PECOL_OFFSET
+               PHOT_ROW = ROW + PEROW_OFFSET
+
+               COSZEN = COSINE_ZENITH( COL,ROW ) ! local cosine of solar zenith angle
+
+               IF ( COSZEN .LE. 0.0 ) THEN
+!...the cell is dark: set variables to zero and cycle
+                  RJ( COL,ROW, :,: ) = 0.0
+   
+                  IF ( JTIME_CHK ) THEN
+                     TOTAL_OC( COL,ROW )        = 0.0                            
+                     TROPO_OC( COL,ROW )        = 0.0                            
+                     ETOT_SFC_WL ( COL,ROW, : ) = 0.0
+                     TAUO3_TOP_WL( COL,ROW, : ) = 0.0
+                     TAU_AERO_WL ( COL,ROW, : ) = 0.0
+                     TAU_CLOUD_WL( COL,ROW, : ) = 0.0
+#ifdef phot_debug                   
+                     SSA_CLOUD_WL( COL,ROW, : ) = 0.0
+                     ASY_CLOUD_WL( COL,ROW, : ) = 0.0
+#endif                   
+                     TAU_TOT_WL( COL,ROW, : )   = 0.0
+                     TAU       ( COL,ROW, :,: ) = 0.0
+                     TAU_AERO  ( COL,ROW, :,: ) = 0.0
+                     AERO_SSA  ( COL,ROW, :,: ) = 0.0
+                     AERO_ASYM ( COL,ROW, :,: ) = 0.0
+                     ACTINIC_FX( COL,ROW, :,: ) = 0.0
+                   
+!                     TROPO_O3_EXCEED( COL,ROW )  = 0.0
+                     TRANSMIS_DIFFUSE( COL,ROW ) = 0.0
+                     TRANSMIS_DIRECT ( COL,ROW ) = 0.0
+                     REFLECT_COEFF   ( COL,ROW ) = 0.0
+                     CLR_TRANSMISSION( COL,ROW ) = 0.0
+                     CLR_TRANS_DIRECT( COL,ROW ) = 0.0
+                     CLR_REFLECTION  ( COL,ROW ) = 0.0 
+                  END IF
+
+                  CYCLE LOOP_COLS
+
+               END IF
+
+!...initialize BLKRJ using F90 array operations.
+
+               BLKRJ_RES = 0.0
+               BLKRJ_ACM = 0.0
+
+!...Set height of lowest level to zero
+
+               BLKZF( 1 ) = 0.0
+
+               ZSFC   = HT( COL,ROW ) ! surface height [m]
+               SINZEN = SQRT( 1.0 - COSZEN * COSZEN ) ! sine of zenith angle
+
+!...local latitude and longitude
+
+!               LATCR = LAT( COL,ROW )
+!               LONCR = LON( COL,ROW )
+
+!...get total ozone column based on OMI observations
+               CALL O3TOTCOL ( LAT( COL,ROW ), LON( COL,ROW ), JDATE, TOTAL_O3_COLUMN )
+            
+               IF ( USE_ACM_CLOUD .OR. CLDATT ) THEN
+                  OWATER_FRAC = MAX( ( 1.0 - SEAICE( COL,ROW ) ), 0.0 )
+     &                        * WATER_FRACTION( COL,ROW )
+                  SEAICE_FRAC = SEAICE( COL,ROW ) * WATER_FRACTION( COL,ROW )
+                  SNOW_FRAC   = SNOCOV( COL,ROW )
+                  COL_CLOUD   = PHOT_COL 
+                  ROW_CLOUD   = PHOT_ROW
+               END IF
+
+!...loop over vertical layers ambient air conditions and gas concentration
+               DO L = 1, NLAYS
+!...Fetch the grid cell ambient data at each layer.
+
+                  BLKTA  ( L )   = TA   ( COL,ROW,L ) ! temperature [K]
+                  BLKPRS ( L )   = PRES ( COL,ROW,L ) / STDATMPA  ! [atmospheres]
+                  BLKDENS( L )   = DENS ( COL,ROW,L ) * DENS_CONV ! [molecules / cm**3]
+                  BLKZH  ( L )   = ZM   ( COL,ROW,L ) ! mid layer height [m]
+                  BLKZF  ( L+1 ) = ZFULL( COL,ROW,L ) ! full layer height [m]
+
+!...set scale factor for [ppm] -> [molecule / cm**3]
+!...  To go from ppm to molecule/cc:
+!...  molecule/cc = ppm *  1.0E-06 * DENS (given in molecule/cc)
+
+                  MSCALE = BLKDENS( L ) * PPM_MCM3
+
+!...fetch ozone and no2 and convert to [ molecules / cm **3 ]
+!...  and adjust the volume for ambient temperature and pressure.
+
+                  BLKO3 ( L ) = CGRID( COL,ROW,L,LGC_O3  ) * MSCALE
+                  BLKNO2( L ) = CGRID( COL,ROW,L,LGC_NO2 ) * MSCALE
+                  ZLEV = BLKZF( L )
+               END DO ! loop on layers ambient conditions and gases
+
+               IF ( CLDATT .AND. CFRAC_2D( COL,ROW ) .GT. 0.0 ) THEN
+                  DO L = 1, NLAYS
+                 
+                     IF ( CFRAC_3D( COL,ROW,L ) .GT. 0.0 ) THEN
+                        CLOUDS ( L )        = .TRUE.
+                        CLOUD_LAYERING( L ) = .TRUE.
+                        CLDFRAC( L )        = CFRAC_3D( COL,ROW,L )
+!... set hydrometeor concentrations for resolved cloud
+                        MSCALE   = 1.0E+3 * DENS ( COL,ROW,L )
+                        IWC( L ) = MSCALE * QI( COL,ROW,L )
+                        GWC( L ) = MSCALE * QG( COL,ROW,L )
+                        SWC( L ) = MSCALE * QS( COL,ROW,L )    
+                        LWC( L ) = MSCALE * QC( COL,ROW,L )
+                        RWC( L ) = MSCALE * QR( COL,ROW,L )
+                     ELSE
+                        CLOUDS ( L )        = .FALSE.
+                        CLOUD_LAYERING( L ) = .FALSE.
+                        CLDFRAC( L )        = 0.0
+                        IWC( L ) = 0.0
+                        GWC( L ) = 0.0
+                        SWC( L ) = 0.0    
+                        LWC( L ) = 0.0
+                        RWC( L ) = 0.0
+                     END IF
+                  END DO ! loop on layers clouds
+! get optical properties of resolved cloud hydrometeors
+                  CALL GET_DROPLET_OPTICS( NLAYS, BLKTA, OWATER_FRAC, SEAICE_FRAC, SNOW_FRAC, LWC )     
+                  CALL GET_ICE_OPTICS( NLAYS, BLKTA, IWC )
+                  CALL GET_AGGREGATE_OPTICS( NLAYS, RWC, SWC, GWC )     
+               ELSE
+                  CLOUDS         = .FALSE.
+                  CLOUD_LAYERING = .FALSE.
+                  CLDFRAC        = 0.0
+!  hydrometeor concentrations
+                  LWC = 0.0
+                  IWC = 0.0
+                  RWC = 0.0
+                  SWC = 0.0
+                  RWC = 0.0
+                  CALL CLEAR_HYDROMETEOR_OPTICS()
+               END IF
+            
+!..calculate needed aerosol properties in column
+
+!              IF ( CORE_SHELL ) THEN
+                  CALL GET_AERO_DATA ( COL,ROW, NLAYS, CGRID )
+!              ELSE
+!                 CALL AERO_OPTICS_INTERNAL( COL,ROW, NLAYS, CGRID )
+!              END IF
+
+! set surface albedo
+
+               FORALL ( IWL = 1:NWL )
+                  ALB( IWL ) = SURFACE_ALBEDO( IWL, COL,ROW )
+               END FORALL
+!set min/max fractions of ozone column in stratosphere and troposphere
+!              MIN_STRATO3_FRAC = MIN_STRAT_03_FRAC( COL, ROW )
+!              MAX_TROPOO3_FRAC = MAX( 1.0 - MIN_STRAT_03_FRAC( COL, ROW ), 0.0 )
+!                MIN_STRATO3_FRAC = MONTH_STRAT_03_FRAC( COL, ROW )
+!                MAX_TROPOO3_FRAC = MAX( 1.0 - MONTH_STRAT_03_FRAC( COL, ROW ), 0.0 )
+!...calculate resolved-sky photolysis rates at all layers:
+
+               NEW_PROFILE    = .TRUE. 
+               ONLY_SOLVE_RAD = .FALSE. 
+                             
+               CALL NEW_OPTICS ( JDATE, JTIME, NLAYS, 
+     &                           BLKTA, BLKPRS, BLKDENS, BLKZH, BLKZF,
+     &                           BLKO3, BLKNO2,
+     &                           ZSFC, COSZEN, SINZEN, RSQD,
+     &                           NEW_PROFILE, CLOUDS, CLDFRAC,
+     &                           BLKRJ_RES, TAUC_AERO, TAU_TOT, TAUO3_TOP,
+     &                           TAU_RAY, SSA, TAU_CLOUD, TOTAL_O3_COLUMN )
+
+!...load diagnostic file arrays
+               IF ( PHOTDIAG .AND. .NOT. STRATO3_MINS_MET ) THEN
+                    N_EXCEED_TROPO3( COL,ROW ) =  N_EXCEED_TROPO3( COL,ROW ) + 1.0
+                    TROPO_O3_EXCEED( COL,ROW ) = TROPO_O3_COLUMN/(MAX_TROPOO3_FRAC*TOTAL_O3_COLUMN) - 1.0
+!     &                                         + 1.0 / TROPO_O3_TOGGLE - 1.0
+     &                                         + TROPO_O3_EXCEED( COL,ROW )
+!               ELSE IF(  PHOTDIAG ) THEN
+!                     TROPO_O3_EXCEED( COL,ROW ) = 0.0
+               END IF 
+
+               IF ( JTIME_CHK  ) THEN
+                  TOTAL_OC( COL,ROW )         = REAL( TOTAL_O3_COLUMN )
+                  TROPO_OC( COL,ROW )         = REAL( TROPO_O3_COLUMN )
+                  TRANSMIS_DIFFUSE( COL,ROW ) = TRANSMISSION
+                  TRANSMIS_DIRECT( COL,ROW )  = TRANS_DIRECT
+                  REFLECT_COEFF( COL,ROW )    = REFLECTION
+
+
+                  FORALL( IWL = 1:NWL )
+                     ETOT_SFC_WL ( COL,ROW,IWL ) = IRRADIANCE( 1,IWL )
+                     TAUO3_TOP_WL( COL,ROW,IWL ) = TAUO3_TOP( IWL )
+                     TAU_AERO_WL ( COL,ROW,IWL ) = TAUC_AERO( 1,IWL )
+                     TAU_TOT_WL  ( COL,ROW,IWL ) = TAU_TOT  ( 1,IWL )
+                     TAU_CLOUD_WL( COL,ROW,IWL ) = TAU_CLOUD( 1,IWL )
+#ifdef phot_debug                      
+                     SSA_CLOUD_WL( COL,ROW,IWL ) = AVE_SSA_CLD  ( IWL )
+                     ASY_CLOUD_WL( COL,ROW,IWL ) = AVE_ASYMM_CLD( IWL )
+#endif                      
+                  END FORALL
+                  FORALL ( LEV = 1:NLAYS, IWL = 1:NWL  )
+                     ACTINIC_FX( COL,ROW,LEV,IWL ) = ACTINIC_FLUX( LEV,IWL )
+                  END FORALL
+                  
+                  DO L = 1, N_DIAG_WVL
+                     IWL = DIAG_WVL( L )
+                     FORALL ( LEV = 1:NLAYS )
+                        TAU     ( COL,ROW,LEV,L ) = TAU_TOT  ( LEV,IWL )
+                        TAU_AERO( COL,ROW,LEV,L ) = TAUC_AERO( LEV,IWL )
+                     END FORALL
+                     FORALL ( LEV = 1:NLAYS, AERO_EXTI_COEF( LEV,IWL ) .GT. EPSLON )
+                        AERO_SSA ( COL,ROW,LEV,L ) = AERO_SCAT_COEF( LEV,IWL )
+     &                                             / AERO_EXTI_COEF( LEV,IWL )
+                        AERO_ASYM( COL,ROW,LEV,L ) = AERO_ASYM_FAC( LEV,IWL )
+                     END FORALL
+                     FORALL ( LEV = 1:NLAYS, AERO_EXTI_COEF( LEV,IWL ) .LE. EPSLON )
+                        AERO_SSA ( COL,ROW,LEV,L ) = 1.0
+                        AERO_ASYM( COL,ROW,LEV,L ) = 0.0
+                     END FORALL
+                  END DO
+               END IF
+
+!Set Photolysis rates to resolved sky values
+               FORALL ( L = 1:NLAYS, IPHOT = 1:NPHOTAB )
+                  RJ( COL,ROW, L,IPHOT ) = 60.0 * BLKRJ_RES( L,IPHOT ) 
+               END FORALL  ! Loop on layers and NPHOTAB
+
+               IF ( USE_ACM_CLOUD ) THEN
+                  IF ( ACM_CLOUDS( COL,ROW ) .GT. 0.0 ) THEN
+! save resolved sky reflection and transmission coefficients for possible latter use
+                     RES_SKY_REFLECT = REFLECTION
+                     RES_SKY_TRANS   = TRANSMISSION
+                     RES_SKY_TRANSD  = TRANS_DIRECT
+!...find the highest layer of the sub-grid (convective) cloud
+                     DO LEV = NLAYS, 1, -1
+                        IF ( ACM_CFRAC( LEV, COL,ROW ) .GT. 0.0 ) EXIT
+                     END DO
+!...replace the lower layers with sub-grid cloud properties
+                     DO L = 1, LEV
+                        SWC( L ) = 0.0
+                        IF ( ACM_CFRAC( L,COL,ROW ) .GT. 0.0 ) THEN
+                           CLOUDS ( L ) = .TRUE.
+                           CLDFRAC( L ) = 1.0
+                           MSCALE = 1.0E+3 * DENS ( COL,ROW, L )
+                           LWC( L ) = MSCALE * ACM_QC( L,COL,ROW )
+                           IWC( L ) = MSCALE * ACM_QI( L,COL,ROW )
+                           RWC( L ) = MSCALE * ACM_QR( L,COL,ROW )
+                           GWC( L ) = MSCALE * ACM_QG( L,COL,ROW )
+                        ELSE
+                           CLOUDS( L )  = .FALSE.
+                           CLDFRAC( L ) = 0.0
+                           LWC( L )     = 0.0
+                           IWC( L )     = 0.0
+                           RWC( L )     = 0.0
+                           GWC( L )     = 0.0
+                        END IF
+                        CLOUD_LAYERING( L ) = .FALSE.
+                     END DO
+!                    write(logdev,*)'ACM cloud present fraction, cloud lwc(lev),iwc(lev),rwc(1),gwc(1) = ',
+!     &              ACM_CLOUDS( COL,ROW ),lwc(lev),iwc(lev),rwc(1),gwc(1)
+                 
+! get optical properties of of subgrid cloud hydrometeors
+                     CALL GET_DROPLET_OPTICS( LEV, BLKTA, OWATER_FRAC, SEAICE_FRAC, SNOW_FRAC, LWC )     
+                     CALL GET_ICE_OPTICS( LEV, BLKTA, IWC )     
+                     CALL GET_AGGREGATE_OPTICS( LEV, RWC, SWC, GWC )     
+
+!...calculate the acm-cloud photolysis rates for all layers:
+                     NEW_PROFILE = .FALSE.   
+                     CALL NEW_OPTICS ( JDATE, JTIME, NLAYS,
+     &                                 BLKTA, BLKPRS, BLKDENS, BLKZH, BLKZF,
+     &                                 BLKO3, BLKNO2,
+     &                                 ZSFC, COSZEN, SINZEN, RSQD,
+     &                                 NEW_PROFILE, CLOUDS, CLDFRAC,
+     &                                 BLKRJ_ACM, TAUC_AERO, TAU_TOT, TAUO3_TOP,
+     &                                 TAU_RAY, SSA, TAU_CLOUD, TOTAL_O3_COLUMN )
+
+!...load diagnostic file arrays
+!...compute a cloud-fraction weighted average of ETOT_SFC and TAU_TOT
+!...  note that both TAUC_AERO and TAUO3_TOP are the same for clear and
+!...  cloudy regions
+                     MSCALE = MAX( 1.0 - ACM_CLOUDS( COL,ROW ), 0.0 )
+
+                     IF ( JTIME_CHK ) THEN
+
+                        TRANSMIS_DIRECT( COL,ROW )  = MSCALE * TRANSMIS_DIRECT( COL,ROW )
+     &                                              + ACM_CLOUDS( COL,ROW ) * TRANS_DIRECT
+                        TRANSMIS_DIFFUSE( COL,ROW ) = MSCALE * TRANSMIS_DIFFUSE( COL,ROW )
+     &                                              + ACM_CLOUDS( COL,ROW ) * TRANSMISSION
+                        REFLECT_COEFF( COL,ROW )    = MSCALE * REFLECT_COEFF( COL,ROW )
+     &                                              + ACM_CLOUDS( COL,ROW ) * REFLECTION
+                        FORALL ( IWL = 1:NWL )
+                           ETOT_SFC_WL ( COL,ROW,IWL ) = MSCALE * ETOT_SFC_WL( COL,ROW,IWL )
+     &                                                 + ACM_CLOUDS( COL,ROW ) * IRRADIANCE( 1,IWL )
+                           TAU_TOT_WL  ( COL,ROW,IWL ) = MSCALE * TAU_TOT_WL( COL,ROW,IWL )
+     &                                                 + ACM_CLOUDS( COL,ROW ) * TAU_TOT( 1,IWL )
+                           TAU_CLOUD_WL( COL,ROW,IWL ) = MSCALE * TAU_CLOUD_WL( COL,ROW,IWL )
+     &                                                 + ACM_CLOUDS( COL,ROW ) * TAU_CLOUD( 1,IWL )
+#ifdef phot_debug
+                           SSA_CLOUD_WL( COL,ROW,IWL ) = MSCALE * SSA_CLOUD_WL( COL,ROW,IWL )
+     &                                                 + ACM_CLOUDS( COL,ROW ) * AVE_SSA_CLD ( IWL )
+                           ASY_CLOUD_WL( COL,ROW,IWL ) = MSCALE * ASY_CLOUD_WL( COL,ROW,IWL )
+     &                                                 + ACM_CLOUDS( COL,ROW ) * AVE_ASYMM_CLD( IWL )
+#endif
+                        END FORALL   ! iwl
+                        FORALL ( LEV = 1:NLAYS, IWL = 1:NWL )
+                           ACTINIC_FX( COL,ROW,LEV,IWL ) = MSCALE * ACTINIC_FX( COL,ROW,LEV,IWL )
+     &                                                   + ACM_CLOUDS( COL,ROW ) * ACTINIC_FLUX( LEV,IWL )
+                        END FORALL ! lev and iwl
+
+                        DO L = 1, N_DIAG_WVL
+                           IWL = DIAG_WVL( L )
+                           FORALL ( LEV = 1:NLAYS)
+                              TAU( COL,ROW,LEV,L ) = MSCALE * TAU( COL,ROW,LEV,L )
+     &                                             + ACM_CLOUDS( COL,ROW ) * TAU_TOT( LEV,IWL )
+                           END FORALL
+                        END DO
+                     END IF  ! photdiag
+!Photolysis rates become a weighted average of the values from resolved and ACM skies
+                     FORALL ( L = 1:NLAYS, IPHOT = 1:NPHOTAB )
+                         RJ( COL,ROW, L, IPHOT ) = 60.0 * ACM_CLOUDS( COL,ROW ) * BLKRJ_ACM( L,IPHOT )
+     &                                           + MSCALE * RJ( COL,ROW,L,IPHOT )
+                     END FORALL  ! Loop on layers and PHOT
+                  END IF
+               END IF ! not USE_ACM_CLOUD and  ACM_CLOUDS > 0
+
+!------------------------CANOPY PHOTOLYSIS CORRECTION/REDUCTION Section NOAA-ARL-------------------------------------------
+!Conditions to reduce weighted average of photolysis rates (RJ) due to canopy shading (if user-defined=true); P. C. Campbell
+!Following is based on work of ECCC in GEM-MACHv2.1:  Makar et al. (2017)
+!Makar, P., Staebler, R., Akingunola, A. et al. The effects of forest canopy shading and turbulence on boundary layer ozone.
+!Nat Commun 8, 15243 (2017). https://doi.org/10.1038/ncomms15243
+
+                      IF ( CANOPY_SHADE ) THEN ! compute canopy shade reduction factor (RJ_CORR)
+
+                        DO LEV = 1, NLAYS !loop through model layers
+
+                          IF (LEV .EQ. 1) THEN !first model layer
+                            KCAN = 1
+                          ELSE               !check subsequent model layers
+                            IF (  Met_Data%FCH( COL,ROW ) .GT. Met_Data%ZF( COL,ROW,LEV-1 )
+     &                      .AND. Met_Data%FCH( COL,ROW ) .LE. Met_Data%ZF( COL,ROW,LEV ) ) THEN
+                              KCAN = 1
+                            ELSE
+                              KCAN = 0
+                            END IF
+                          END IF
+
+                          IF (KCAN .EQ. 1) THEN !canopy could be inside model layer
+                            !check for otherconditions for grid cells that do NOT have
+                            !a continuos forest canopy
+                            IF ( Met_Data%LAIE( COL,ROW ) .LT. 0.1
+     &                         .OR. Met_Data%FCH( COL,ROW ) .LT. 0.5
+!    &                         .OR. MAX(0.0, 1.0 - Met_Data%FRT( COL,ROW)) .GT. 0.5  !IVAI: old canopy data
+     &                         .OR. MAX(0.0, 1.0 - Met_Data%FRT( COL,ROW)) .GT.  0.75  !IVAI: new canopy data
+     &                         .OR. Met_Data%POPU( COL,ROW ) .GT.10000.0
+     &                         .OR. (EXP(-0.5*Met_Data%LAIE( COL,ROW)*Met_Data%CLU( COL,ROW )) .GT. 0.45
+     &                                               .AND. Met_Data%FCH(COL,ROW ) .LT. 18.0 )) THEN
+                                 RJ( COL,ROW, LEV, : ) = RJ( COL,ROW, LEV, :)
+                            ELSE ! There is a contiguous forest canopy,apply correctoin
+                            !RJ_CORR effectly represents the beam attenuation and reduces photolysis.
+                            !Nilson, T. A theoretical analysis of the frequency of gaps in plant stands. Agric.
+                            !Meterol. 8, 25⚌~Z~L~@~S38 (1971).
+
+!Calculate attenuation at different set cumulative LAI fractions downward through canopy (C1R, C2R, C3R, C4R data from ECCC)
+                                RJ_CORR_C1R( COL,ROW ) = MAX(1.0E-10, EXP(-1.0*(0.5*(Met_Data%LAIE( COL,ROW )
+     &                                         *Met_Data%C1R( COL,ROW ))*Met_Data%CLU( COL,ROW ))/MAX(0.05, COSZEN)))
+                                RJ_CORR_C2R( COL,ROW ) = MAX(1.0E-10, EXP(-1.0*(0.5*(Met_Data%LAIE( COL,ROW )
+     &                                         *Met_Data%C2R( COL,ROW ))*Met_Data%CLU( COL,ROW ))/MAX(0.05, COSZEN)))
+                                RJ_CORR_C3R( COL,ROW ) = MAX(1.0E-10, EXP(-1.0*(0.5*(Met_Data%LAIE( COL,ROW )
+     &                                         *Met_Data%C3R( COL,ROW ))*Met_Data%CLU( COL,ROW ))/MAX(0.05, COSZEN)))
+                                RJ_CORR_C4R( COL,ROW ) = MAX(1.0E-10, EXP(-1.0*(0.5*(Met_Data%LAIE( COL,ROW )
+     &                                         *Met_Data%C4R( COL,ROW ))*Met_Data%CLU( COL,ROW ))/MAX(0.05, COSZEN)))
+                                RJ_CORR_BOT( COL,ROW ) = MAX(1.0E-10, EXP(-1.0*(0.5*Met_Data%LAIE( COL,ROW )
+     &                                         *Met_Data%CLU( COL,ROW ))/MAX(0.05, COSZEN)))
+
+!Interpolate to get attenuation profile below canopy inside respective model layer 
+                                ZFL = Met_Data%ZF( COL,ROW,LEV )
+                                ZCAN = ZFL    ! Initialize top (m) = Bottom of model layer
+                                COUNTCAN = 0  ! Initialize canopy layers
+
+                                IF (LEV .EQ. 1) THEN  !Find bottom in each model layer
+                                    BOTCAN = 0.5
+                                ELSE
+                                    BOTCAN = Met_Data%ZF( COL,ROW,LEV-1 )
+                                END IF
+
+                                DO WHILE (ZCAN.GE.BOTCAN)
+                                   IF ( ZCAN .GT. Met_Data%FCH( COL,ROW ) ) THEN
+                                     COUNTCAN = COUNTCAN + 1
+                                     ZCANX(COUNTCAN) = ZCAN
+                                     RJ_CORRX (COUNTCAN) = 1.0
+                                   ELSE IF  ( ZCAN .LE. Met_Data%FCH( COL,ROW )   .AND.
+     &                                        ZCAN .GT. Met_Data%FCH( COL,ROW )*0.75 ) THEN
+                                     COUNTCAN = COUNTCAN + 1
+                                     XCAN(2) = Met_Data%FCH( COL,ROW )
+                                     YCAN(2) = 1.0
+                                     XCAN(1) = Met_Data%FCH( COL,ROW )*0.75
+                                     YCAN(1) = RJ_CORR_C1R( COL,ROW )
+                                     XCANOUT = ZCAN
+                                     ZCANX(COUNTCAN) = ZCAN
+                                     RJ_CORRX (COUNTCAN) = interp_linear1_internal(XCAN,YCAN,XCANOUT)
+                                   ELSE IF ( ZCAN .LE. Met_Data%FCH( COL,ROW )*0.75   .AND.
+     &                                       ZCAN .GT. Met_Data%FCH( COL,ROW )*0.50 ) THEN
+                                     COUNTCAN = COUNTCAN + 1
+                                     XCAN(2) = Met_Data%FCH( COL,ROW )*0.75
+                                     YCAN(2) = RJ_CORR_C1R( COL,ROW )
+                                     XCAN(1) = Met_Data%FCH( COL,ROW )*0.50
+                                     YCAN(1) = RJ_CORR_C2R( COL,ROW )
+                                     XCANOUT = ZCAN
+                                     ZCANX(COUNTCAN) = ZCAN
+                                     RJ_CORRX (COUNTCAN) = interp_linear1_internal(XCAN,YCAN,XCANOUT)
+                                   ELSE IF ( ZCAN .LE. Met_Data%FCH( COL,ROW )*0.50   .AND.
+     &                                       ZCAN .GT. Met_Data%FCH( COL,ROW )*0.35 ) THEN
+                                     COUNTCAN = COUNTCAN + 1
+                                     XCAN(2) = Met_Data%FCH( COL,ROW )*0.50
+                                     YCAN(2) = RJ_CORR_C2R( COL,ROW )
+                                     XCAN(1) = Met_Data%FCH( COL,ROW )*0.35
+                                     YCAN(1) = RJ_CORR_C3R( COL,ROW )
+                                     XCANOUT = ZCAN
+                                     ZCANX(COUNTCAN) = ZCAN
+                                     RJ_CORRX (COUNTCAN) = interp_linear1_internal(XCAN,YCAN,XCANOUT)
+                                   ELSE IF ( ZCAN .LE. Met_Data%FCH( COL,ROW )*0.35  .AND.
+     &                                       ZCAN .GT. Met_Data%FCH( COL,ROW )*0.20 ) THEN
+                                     COUNTCAN = COUNTCAN + 1
+                                     XCAN(2) = Met_Data%FCH( COL,ROW )*0.35
+                                     YCAN(2) = RJ_CORR_C3R( COL,ROW )
+                                     XCAN(1) = Met_Data%FCH( COL,ROW )*0.20
+                                     YCAN(1) = RJ_CORR_C4R( COL,ROW )
+                                     XCANOUT = ZCAN
+                                     ZCANX(COUNTCAN) = ZCAN
+                                     RJ_CORRX (COUNTCAN) = interp_linear1_internal(XCAN,YCAN,XCANOUT)
+                                   ELSE IF ( ZCAN .LE. Met_Data%FCH( COL,ROW )*0.20 ) THEN
+                                     COUNTCAN = COUNTCAN + 1
+                                     XCAN(2) = Met_Data%FCH( COL,ROW )*0.20
+                                     YCAN(2) = RJ_CORR_C4R( COL,ROW )
+                                     XCAN(1) = 0.5
+                                     YCAN(1) = RJ_CORR_BOT( COL,ROW )
+                                     XCANOUT = ZCAN
+                                     ZCANX(COUNTCAN) = ZCAN
+                                     RJ_CORRX (COUNTCAN) = interp_linear1_internal(XCAN,YCAN,XCANOUT)
+                                   END IF
+                                   ZCAN = ZCAN-0.5  !step down in-canopy resolution of 0.5 m
+                                END DO !end loop on canopy layers
+
+!Integrate to get best attenuation value to use within canopy
+                                RJ_CORR( COL,ROW ) = IntegrateTrapezoid(ZCANX(COUNTCAN:1:-1),RJ_CORRX(COUNTCAN:1:-1)) /
+     &                                               ZFL
+!Apply attenuation factors above and below canopy
+                                RJ( COL,ROW, LEV, : ) = RJ( COL,ROW, LEV, : )*RJ_CORR( COL,ROW )
+!Apply attenuation value within canopy and take average above and within canopy values
+                            END IF  !other contiguous canopy conditions
+                          END IF  !canopy height could be inside model layer
+                        END DO  !end loop on model layers
+                      END IF  !canopy shade 
+
+               IF ( JTIME_CHK ) THEN ! compute clear sky reflection and transmission coefficients
+                  IF ( ANY( CLOUDS ) ) THEN
+                     IF ( CFRAC_2D( COL,ROW ) .GT. 0.0 ) THEN ! resolved and subgrid clouds exist
+                        CLOUDS         = .FALSE.
+                        NEW_PROFILE    = .FALSE.
+                        ONLY_SOLVE_RAD = .TRUE.
+                        CALL NEW_OPTICS ( JDATE, JTIME, NLAYS, 
+     &                                    BLKTA, BLKPRS, BLKDENS, BLKZH, BLKZF,
+     &                                    BLKO3, BLKNO2,
+     &                                    ZSFC, COSZEN, SINZEN, RSQD,
+     &                                    NEW_PROFILE, CLOUDS, CLDFRAC,
+     &                                    BLKRJ_RES, TAUC_AERO, TAU_TOT, TAUO3_TOP,
+     &                                    TAU_RAY, SSA, TAU_CLOUD, TOTAL_O3_COLUMN)
+                        CLR_REFLECTION  ( COL,ROW ) = REFLECTION
+                        CLR_TRANSMISSION( COL,ROW ) = TRANSMISSION
+                        CLR_TRANS_DIRECT( COL,ROW ) = TRANS_DIRECT
+                     ELSE ! only subgrid clouds exist
+                        CLR_REFLECTION  ( COL,ROW ) = RES_SKY_REFLECT
+                        CLR_TRANSMISSION( COL,ROW ) = RES_SKY_TRANS
+                        CLR_TRANS_DIRECT( COL,ROW ) = RES_SKY_TRANSD
+                     END IF
+                  ELSE ! no cloud in vertical column
+                     CLR_REFLECTION  ( COL,ROW ) = REFLECTION
+                     CLR_TRANSMISSION( COL,ROW ) = TRANSMISSION
+                     CLR_TRANS_DIRECT( COL,ROW ) = TRANS_DIRECT
+                  END IF
+               END IF
+
+            END DO LOOP_COLS
+         END DO LOOP_ROWS
+
+      END IF
+
+!...report on whether stratospheric ozone column satisfies climatological minimums
+      IF( N_TROPO_O3_TOGGLE .GT. 0 )THEN
+         O3_TOGGLE_AVE = O3_TOGGLE_AVE / REAL( N_TROPO_O3_TOGGLE )
+         WRITE( LOGDEV, 9500 )'PHOT: Exceedance of tropospheric ozone column ',
+     &   'or below top of model domains based on stratospheric column minimum ',
+     &   'at date and time; ', JDATE, JTIME, N_TROPO_O3_TOGGLE, (1.0/O3_TOGGLE_AVE - 1.0),
+     &    (1.0/O3_TOGGLE_MIN - 1.0)
+      END IF
+
+!...write diagnostic data to output file at the end of every output tstep
+
+      IF ( JTIME_CHK ) THEN
+
+         VARNM = 'COSZENS'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME,
+     &                     COSINE_ZENITH ) ) THEN
+             XMSG = 'Error writing variable ' // VARNM
+             CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'OZONE_COLUMN'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, TOTAL_OC ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'TROPO_O3_COLUMN'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, TROPO_OC ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         IMONTH = IMONTH + 1
+         IF( IMONTH .GT. 12 )THEN
+             IMONTH = 1
+             TDATE = 2011001
+         END IF
+         TDATE = TDATE + DAYS( IMONTH )
+!         CALL SEASONAL_STRAT_O3(TDATE, JTIME )
+
+
+!         VARNM = 'MIN_FRAC_STRATO3'
+!         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, MONTH_STRAT_03_FRAC ) ) THEN
+!            XMSG = 'Error writing variable ' // VARNM
+!            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+!         END IF
+
+
+         VARNM = 'TRANS_DIFFUSE'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, TRANSMIS_DIFFUSE ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'TRANS_DIRECT'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, TRANSMIS_DIRECT ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'REFLECTION'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, REFLECT_COEFF ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'CLR_TRANS_DIF'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, CLR_TRANSMISSION ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'CLR_TRANS_DIR'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, CLR_TRANS_DIRECT ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'CLR_REFLECTION'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, CLR_REFLECTION ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'TROPO_O3_EXCEED'
+         TROPO_O3_EXCEED = TROPO_O3_EXCEED / REAL( MAX(1, TSTEP_COUNT) )
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, TROPO_O3_EXCEED ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+         TROPO_O3_EXCEED = 0.0 ! reset sum and counter
+         TSTEP_COUNT     = 0
+
+         VARNM = 'N_EXCEED_TROPO3'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, N_EXCEED_TROPO3 ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+         N_EXCEED_TROPO3 = 0.0 ! reset counter
+
+         VARNM = 'JNO2'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, RJ( :,:,1, LNO2 ) ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'JO3O1D'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, RJ( :,:,1,LO3O1D ) ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'RESOLVED_CFRAC'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, CFRAC_2D ) ) THEN
+            XMSG = 'Error writing variable ' // VARNM
+            CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         VARNM = 'RESOLVED_WBAR'
+         IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, AVE_HYDROMETEORS ) ) THEN
+             XMSG = 'Error writing variable ' // VARNM
+             CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+
+         IF ( USE_ACM_CLOUD ) THEN
+             VARNM = 'SUBGRID_CFRAC'
+             IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, ACM_CLOUDS ) ) THEN
+                XMSG = 'Error writing variable ' // VARNM
+                CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+             END IF
+             VARNM = 'SUBGRID_WBAR'
+             IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME, ACM_AVE_H2O ) ) THEN
+                XMSG = 'Error writing variable ' // VARNM
+                CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+             END IF
+         END IF
+
+         DO IWL = 1, NWL
+
+            VARNM = 'ETOT_SFC_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE,
+     &                         OTIME, ETOT_SFC_WL( :,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, ODATE, OTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'TAU_AERO_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE,
+     &                         OTIME, TAU_AERO_WL( :,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'TAU_CLOUD_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE,
+     &                         OTIME, TAU_CLOUD_WL( :,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+#ifdef phot_debug
+            VARNM = 'SSA_CLOUD_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE,
+     &                         OTIME, SSA_CLOUD_WL( :,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'ASY_CLOUD_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE,
+     &                         OTIME, ASY_CLOUD_WL( :,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+#endif
+
+            VARNM = 'TAU_TOT_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE,
+     &                         OTIME, TAU_TOT_WL( :,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'TAUO3_TOP_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE,
+     &                         OTIME, TAUO3_TOP_WL( :,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'ALBEDO_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_1, VARNM, ODATE, OTIME,
+     &                         SURFACE_ALBEDO( IWL,:,: ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+         END DO  ! iwl
+
+         WRITE( LOGDEV, '( /5X, 3( A, :, 1X ), I8, ":", I6.6 )' )
+     &          'RJ Values written to', CTM_RJ_1,
+     &          'for date and time', ODATE, OTIME
+
+         DO IPHOT = 1, NPHOTAB
+            IF ( .NOT. WRITE3( CTM_RJ_2, PHOTAB( IPHOT ), ODATE,
+     &                         OTIME, RJ( :,:,:,IPHOT ) ) ) THEN
+               XMSG = 'Could not write ' // CTM_RJ_2 // ' file'
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+         END DO
+
+         VARNM = 'CFRAC_3D'
+         IF ( .NOT. WRITE3( CTM_RJ_2, VARNM, ODATE, OTIME, CFRAC_3D ) ) THEN
+              XMSG = 'Could not write ' // TRIM( VARNM ) // ' to ' // CTM_RJ_2 // ' file'
+              CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+         END IF
+         
+         DO IWL = 1, NWL
+            VARNM = 'ACTINIC_FX_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_2, VARNM, ODATE, OTIME, ACTINIC_FX( :,:,:,IWL ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+         END DO
+
+         DO L = 1, N_DIAG_WVL
+            IWL = DIAG_WVL( L )
+
+            VARNM = 'AERO_SSA_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_2, VARNM, ODATE, OTIME, AERO_SSA( :,:,:,L ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'AERO_ASYM_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_2, VARNM, ODATE, OTIME, AERO_ASYM( :,:,:,L ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'TAU_AERO_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_2, VARNM, ODATE, OTIME, TAU_AERO( :,:,:,L ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+
+            VARNM = 'TAU_W' // WLTXT( IWL )
+            IF ( .NOT. WRITE3( CTM_RJ_2, VARNM, ODATE, OTIME, TAU( :,:,:,L ) ) ) THEN
+               XMSG = 'Error writing variable ' // VARNM
+               CALL M3EXIT ( PNAME, JDATE, JTIME, XMSG, XSTAT1 )
+            END IF
+         END DO
+
+         WRITE( LOGDEV, '( /5X, 3( A, :, 1X ), I8, ":", I6.6 )' )
+     &          'RJ and Optical Data written to', CTM_RJ_2,
+     &          'for date and time', ODATE, OTIME
+
+      END IF   ! if JTIME_CHK 
+
+1003  FORMAT( 8X, 'Processor ',I4.4,' is in darkness at ', I8.7, ':', I6.6,
+     &        1X, 'GMT - no photolysis')
+9500  FORMAT(3(/ A), I7, 1X, I6.6, 1X, / "Total Number: ", I9, ";Mean Value: ", F9.6,
+     &       "; Max Value: ",F9.6 /)
+
+      RETURN
+      END SUBROUTINE PHOT
diff --git a/src/shr/aqm_config_mod.F90 b/src/shr/aqm_config_mod.F90
index 01aaeae..b5c9d96 100644
--- a/src/shr/aqm_config_mod.F90
+++ b/src/shr/aqm_config_mod.F90
@@ -34,7 +34,7 @@ module aqm_config_mod
     logical                   :: biosw_yn      = .false.
     logical                   :: ctm_aod       = .false.
     logical                   :: ctm_depvfile  = .false.
-    logical                   :: ctm_photodiag = .false.
+    logical                   :: ctm_photdiag  = .false.  !IVAI
     logical                   :: ctm_pmdiag    = .false.
     logical                   :: ctm_wb_dust   = .false.
     logical                   :: mie_optics    = .false.
@@ -42,6 +42,7 @@ module aqm_config_mod
     logical                   :: run_aero      = .false.
     logical                   :: run_rescld    = .false.
     logical                   :: verbose       = .false.
+    logical                   :: canopy_yn     = .false.
     type(aqm_species_type), pointer :: species => null()
   end type aqm_config_type
 
@@ -182,6 +183,17 @@ subroutine aqm_config_read(model, config, rc)
       rcToReturn=rc)) &
       return  ! bail out
 
+!IVAI
+    ! -- read diagnostic settings
+    call ESMF_ConfigGetAttribute(cf, config % ctm_photdiag, &
+      label="ctm_photdiag:", default=.false., rc=localrc)
+    if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
+      line=__LINE__,  &
+      file=__FILE__,  &
+      rcToReturn=rc)) &
+      return  ! bail out
+!IVAI
+
     call ESMF_ConfigGetAttribute(cf, config % ctm_pmdiag, &
       label="ctm_pmdiag:", default=.false., rc=localrc)
     if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
@@ -197,7 +209,16 @@ subroutine aqm_config_read(model, config, rc)
       file=__FILE__,  &
       rcToReturn=rc)) &
       return  ! bail out
-    
+
+    ! Canopy Options
+    call ESMF_ConfigGetAttribute(cf, config % canopy_yn, &
+      label="canopy_yn:", default=.false., rc=localrc)
+    if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
+      line=__LINE__,  &
+      file=__FILE__,  &
+      rcToReturn=rc)) &
+      return  ! bail out
+
     call ESMF_ConfigGetAttribute(cf, value, &
       label="ctm_stdout:", default="all", rc=localrc)
     if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
@@ -232,7 +253,6 @@ subroutine aqm_config_read(model, config, rc)
 
     ! -- set other default values
     config % ctm_depvfile  = .false.
-    config % ctm_photodiag = .false.
 
   end subroutine aqm_config_read
 
@@ -545,6 +565,25 @@ subroutine aqm_config_log(config, name, rc)
         rcToReturn=rc)) &
         return  ! bail out
     end if
+!IVAI
+    if (config % ctm_photdiag) then
+      call ESMF_LogWrite(trim(name) // ": config: read: ctm_photdiag: true", &
+        ESMF_LOGMSG_INFO, rc=localrc)
+      if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
+        line=__LINE__,  &
+        file=__FILE__,  &
+        rcToReturn=rc)) &
+        return  ! bail out
+    else
+      call ESMF_LogWrite(trim(name) // ": config: read: ctm_photdiag: false", &
+        ESMF_LOGMSG_INFO, rc=localrc)
+      if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
+        line=__LINE__,  &
+        file=__FILE__,  &
+        rcToReturn=rc)) &
+        return  ! bail out
+    end if
+!IVAI
     if (config % ctm_wb_dust) then
       call ESMF_LogWrite(trim(name) // ": config: read: ctm_wb_dust: true", &
         ESMF_LOGMSG_INFO, rc=localrc)
@@ -562,6 +601,23 @@ subroutine aqm_config_log(config, name, rc)
         rcToReturn=rc)) &
         return  ! bail out
     end if
+    if (config % canopy_yn) then
+      call ESMF_LogWrite(trim(name) // ": config: read: canopy_yn: true", &
+        ESMF_LOGMSG_INFO, rc=localrc)
+      if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
+        line=__LINE__,  &
+        file=__FILE__,  &
+        rcToReturn=rc)) &
+        return  ! bail out
+    else
+      call ESMF_LogWrite(trim(name) // ": config: read: canopy_yn: false", &
+        ESMF_LOGMSG_INFO, rc=localrc)
+      if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
+        line=__LINE__,  &
+        file=__FILE__,  &
+        rcToReturn=rc)) &
+        return  ! bail out
+    end if
     call ESMF_LogWrite(trim(name) // ": config: read: ctm_stdout: " &
       // config % ctm_stdout, ESMF_LOGMSG_INFO, rc=localrc)
     if (ESMF_LogFoundError(rcToCheck=localrc, msg=ESMF_LOGERR_PASSTHRU, &
diff --git a/src/shr/aqm_emis_mod.F90 b/src/shr/aqm_emis_mod.F90
index e432577..711264d 100644
--- a/src/shr/aqm_emis_mod.F90
+++ b/src/shr/aqm_emis_mod.F90
@@ -1600,6 +1600,12 @@ subroutine aqm_emis_grd_read(em, spcname, buffer, localDe, rc)
           return  ! bail out
         end if
 
+        if (trim(em % type) == "canopy") then
+           ! -- ensure canopy variables are not normalized by area like
+           ! -- emissions conversions below
+           em % dens_flag(item) = 1
+        end if
+
         select case (em % dens_flag(item))
           case (:-1)
             ! -- this case indicates that input emissions are provided as totals/cell
diff --git a/src/shr/aqm_methods.F90 b/src/shr/aqm_methods.F90
index 8501c2f..0733d16 100644
--- a/src/shr/aqm_methods.F90
+++ b/src/shr/aqm_methods.F90
@@ -88,7 +88,7 @@ LOGICAL FUNCTION DESC3( FNAME )
   CHARACTER(LEN=*), INTENT(IN) :: FNAME
 
   INCLUDE SUBST_FILES_ID
- 
+
   integer :: localrc
   integer :: is, ie, js, je
   integer :: EMLAYS
@@ -162,7 +162,7 @@ LOGICAL FUNCTION DESC3( FNAME )
 
   ELSE IF ( TRIM( FNAME ) .EQ. TRIM( MET_CRO_2D ) ) THEN
 
-    NVARS3D = 35
+    NVARS3D = 44
     VNAME3D( 1:NVARS3D ) = &
     (/ 'PRSFC           ', 'USTAR           ',            &
        'WSTAR           ', 'PBL             ',            &
@@ -180,6 +180,11 @@ LOGICAL FUNCTION DESC3( FNAME )
        'SEAICE          ', 'SOIM1           ',            &
        'SOIM2           ', 'SOIT1           ',            &
        'SOIT2           ', 'LH              ',            &
+       'FCH             ', 'FRT             ',            &
+       'CLU             ', 'POPU            ',            &
+       'LAIE            ', 'C1R             ',            &
+       'C2R             ', 'C3R             ',            &
+       'C4R             ',                                &
        'CLAYF           ', 'SANDF           ',            &
        'DRAG            ', 'UTHR            ' /)
     UNITS3D( 1:NVARS3D ) = &
@@ -199,6 +204,11 @@ LOGICAL FUNCTION DESC3( FNAME )
        'FRACTION        ', 'M**3/M**3       ',            &
        'M**3/M**3       ', 'K               ',            &
        'K               ', 'WATTS/M**2      ',            &
+       'M               ', 'NO UNIT         ',            &
+       'NO UNIT         ', 'PEOPLE/KM**2    ',            &
+       'NO UNIT         ', 'NO UNIT         ',            &
+       'NO UNIT         ', 'NO UNIT         ',            &
+       'NO UNIT         ',                                &
        '1               ', '1               ',            &
        '1               ', 'M/S             ' /)
 
@@ -362,13 +372,15 @@ logical function envyn(name, description, defaultval, status)
       envyn = config % ctm_depvfile
     case ('CTM_PMDIAG')
       envyn = config % ctm_pmdiag
-    case ('CTM_PHOTODIAG')
-      envyn = config % ctm_photodiag
+    case ('CTM_PHOTDIAG')
+      envyn = config % ctm_photdiag
     case ('CTM_PT3DEMIS')
       envyn = aqm_emis_ispresent("gbbepx") .or. &
               aqm_emis_ispresent("point-source")
     case ('CTM_GRAV_SETL')
       envyn = .false.
+    case ('CTM_CANOPY_SHADE')
+      envyn = config % canopy_yn
     case ('CTM_WBDUST_FENGSHA')
       envyn = aqm_emis_ispresent("fengsha")
     case ('CTM_WB_DUST')
@@ -539,7 +551,6 @@ INTEGER FUNCTION PROMPTFFILE( PROMPT, RDONLY, FMTTED, DEFAULT, CALLER )
 
 END FUNCTION PROMPTFFILE
 
-
 subroutine nameval(name, eqname)
 
   use aqm_emis_mod,  only : aqm_internal_emis_type, aqm_emis_get
@@ -588,7 +599,7 @@ subroutine nameval(name, eqname)
     case default
       ! -- nothing to do
   end select
-  
+
 end subroutine nameval
 
 
@@ -623,6 +634,7 @@ logical function interpx( fname, vname, pname, &
   real(AQM_KIND_R8), dimension(:,:,:), pointer     :: p3d
   type(aqm_config_type),               pointer     :: config
   type(aqm_state_type),                pointer     :: stateIn
+  type(aqm_state_type),                pointer     :: stateOut   !IVAI
 
   ! -- constants
   include SUBST_FILES_ID
@@ -639,6 +651,7 @@ logical function interpx( fname, vname, pname, &
   nullify(p3d)
   nullify(config)
   nullify(stateIn)
+  nullify(stateOut)  !IVAI
   set_non_neg = .false.
 
   if (trim(fname) == trim(GRID_CRO_2D)) then
@@ -703,7 +716,7 @@ logical function interpx( fname, vname, pname, &
     call aqm_model_get(stateIn=stateIn, rc=localrc)
     if (aqm_rc_check(localrc, msg="Failure to retrieve model input state", &
       file=__FILE__, line=__LINE__)) return
-    
+
     call aqm_model_get(config=config, stateIn=stateIn, rc=localrc)
     if (aqm_rc_check(localrc, msg="Failure to retrieve model input state", &
       file=__FILE__, line=__LINE__)) return
@@ -804,15 +817,132 @@ logical function interpx( fname, vname, pname, &
          end do
         end do
       case ("CLAYF","DRAG","SANDF","UTHR")
-        ! -- read in fengsha variables
+        ! -- fengsha variables
         call aqm_emis_read("fengsha", vname, buffer, rc=localrc)
         if (aqm_rc_test((localrc /= 0), &
           msg="Failure to read fengsha input for " // vname, &
           file=__FILE__, line=__LINE__)) return
+      case ("FCH","FRT","CLU","POPU","LAIE","C1R","C2R","C3R","C4R")
+        ! -- canopy variables
+        if (config % canopy_yn) then
+          call aqm_emis_read("canopy", vname, buffer, rc=localrc)
+          if (aqm_rc_test((localrc /= 0), &
+            msg="Failure to read canopy input for " // vname, &
+            file=__FILE__, line=__LINE__)) return
+        else
+          buffer(1:lbuf) = 0.
+        end if
       case default
     !   return
     end select
 
+!IVAI
+    print*, 'AQM_METHODS: FNAME= ', FNAME, VNAME   !IVAI : MET_CRO_2D
+
+    IF ( TRIM( VNAME ) .EQ. TRIM('LAIE') ) THEN
+
+      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: LAIE
+!      print*, 'AQM_METHODS: LAIE = ', buffer(1:lbuf)
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      k = 0
+      do r = row0, row1
+        do c = col0, col1
+           k = k + 1
+
+           stateOut % CLAIE (c,r) = buffer(k)
+        end do
+      end do
+
+
+    END IF
+    IF ( TRIM( VNAME ) .EQ. TRIM('FCH') ) THEN
+
+      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: FCH
+!      print*, 'AQM_METHODS: FCH = ', buffer(1:lbuf)
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      k = 0
+      do r = row0, row1
+        do c = col0, col1
+           k = k + 1
+
+           stateOut % CFCH (c,r) = buffer(k)
+        end do
+      end do
+
+    END IF
+    IF ( TRIM( VNAME ) .EQ. TRIM('FRT') ) THEN
+
+      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: FRT
+!      print*, 'AQM_METHODS: FRT = ', buffer(1:lbuf)
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      k = 0
+      do r = row0, row1
+        do c = col0, col1
+           k = k + 1
+
+           stateOut % CFRT(c,r) = buffer(k)
+        end do
+      end do
+
+    END IF
+    IF ( TRIM( VNAME ) .EQ. TRIM('CLU') ) THEN
+
+      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: CLU
+!      print*, 'AQM_METHODS: CLU = ', buffer(1:lbuf)
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      k = 0
+      do r = row0, row1
+        do c = col0, col1
+           k = k + 1
+
+           stateOut % CCLU(c,r) = buffer(k)
+        end do
+      end do
+
+    END IF
+    IF ( TRIM( VNAME ) .EQ. TRIM('POPU') ) THEN
+
+      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: POPU
+!      print*, 'AQM_METHODS: POPU= ', buffer(1:lbuf)
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      k = 0
+      do r = row0, row1
+        do c = col0, col1
+           k = k + 1
+
+           stateOut % CPOPU(c,r) = buffer(k)
+        end do
+      end do
+
+    END IF
+
+!IVAI
+
   else if (trim(fname) == trim(OCEAN_1)) then
 
     select case (trim(vname))
@@ -1210,8 +1340,12 @@ LOGICAL FUNCTION WRITE3_REAL2D( FNAME, VNAME, JDATE, JTIME, BUFFER )
 
     WRITE3_REAL2D = .FALSE.
 
+!    print*, 'AQM_METHODS: FNAME, VNAME= ', FNAME, VNAME !IVAI: CTM_AOD_1 ALL
+
     IF ( TRIM( VNAME ) .EQ. TRIM( ALLVAR3 ) ) THEN
 
+!      print*, 'AQM_METHODS: VNAME= ', VNAME         !IVAI: ADO
+
       nullify(stateOut)
       call aqm_model_get(stateOut=stateOut, rc=localrc)
       if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
@@ -1219,12 +1353,78 @@ LOGICAL FUNCTION WRITE3_REAL2D( FNAME, VNAME, JDATE, JTIME, BUFFER )
 
       stateOut % aod = BUFFER
 
+!      print*, 'AQM_METHODS: AOD  pointer = ', aod   !IVAI
+!      print*, 'AQM_METHODS: AOD = ', stateOut % aod !IVAI
+
     END IF
 
     WRITE3_REAL2D = .TRUE.
 
   END IF
 
+!IVAI
+  WRITE3_REAL2D = .TRUE.
+
+  IF ( TRIM( FNAME ) .EQ. TRIM( CTM_RJ_1 ) ) THEN
+
+    WRITE3_REAL2D = .FALSE.
+
+    print*, 'AQM_METHODS: FNAME= ', FNAME, VNAME   !IVAI: JO3O1D JNO2 ... (list of 15 vars)
+
+    IF ( TRIM( VNAME ) .EQ. TRIM('COSZENS') ) THEN
+
+!      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: COSZENS
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      stateOut % coszens = BUFFER
+
+!      print*, 'AQM_METHODS: COSZENS pointer = ', coszens
+!      print*, 'AQM_METHODS: COSZENS = ',  BUFFER
+
+    END IF
+
+    IF ( TRIM( VNAME ) .EQ. TRIM('JO3O1D') ) THEN
+
+!      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: JO3O1D
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      stateOut % JO3O1D = BUFFER
+
+!      print*, 'AQM_METHODS: JO3O1D pointer = ', JO3O1D
+!      print*, 'AQM_METHODS: JO3O1D = ', BUFFER
+
+    END IF
+
+    IF ( TRIM( VNAME ) .EQ. TRIM('JNO2') ) THEN
+
+!      print*, 'AQM_METHODS: VNAME= ', VNAME             !IVAI: JNO2
+
+      nullify(stateOut)
+      call aqm_model_get(stateOut=stateOut, rc=localrc)
+      if (aqm_rc_check(localrc, msg="Failure to retrieve model output state", &
+        file=__FILE__, line=__LINE__)) return
+
+      stateOut % JNO2 = BUFFER
+
+!      print*, 'AQM_METHODS: JNO2 pointer = ', JNO2
+!      print*, 'AQM_METHODS: JNO2 = ', BUFFER
+
+    END IF
+
+    WRITE3_REAL2D = .TRUE.
+
+  END IF ! CTM_RJ_1
+
+!IVAI
+
 END FUNCTION WRITE3_REAL2D
 
 LOGICAL FUNCTION WRITE3_REAL4D( FNAME, VNAME, JDATE, JTIME, BUFFER )
diff --git a/src/shr/aqm_state_mod.F90 b/src/shr/aqm_state_mod.F90
index 9dc762f..fe243f8 100644
--- a/src/shr/aqm_state_mod.F90
+++ b/src/shr/aqm_state_mod.F90
@@ -46,11 +46,25 @@ module aqm_state_mod
 
     real(AQM_KIND_R8), dimension(:,:,:,:), pointer :: tr       => null()
 
+!IVAI
+    ! -- canopy variables
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: cfch     => null()
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: cfrt     => null()
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: cclu     => null()
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: cpopu    => null()
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: claie    => null()
+!IVAI
+
     ! -- diagnostics
     real(AQM_KIND_R8), dimension(:,:),     pointer :: aod      => null()
+!IVAI:
+    ! -- photolysis diagnostics
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: coszens  => null()
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: jo3o1d   => null()
+    real(AQM_KIND_R8), dimension(:,:),     pointer :: jno2     => null()
+!IVAI
 
   end type aqm_state_type
 
   public
-
 end module aqm_state_mod