diff --git a/src/chemistry_mod.f90 b/src/chemistry_mod.f90
index 45e08927129bca3ca1191b72a2507a03b65ff925..4994cd1ea994f3ef9ad70398851bae3d52f88d29 100644
--- a/src/chemistry_mod.f90
+++ b/src/chemistry_mod.f90
@@ -31,8 +31,9 @@ module chemistry_mod
   real, allocatable, dimension(:,:,:,:)   :: clfield_cur        ! chemical loss fields current hour
   integer, dimension(2)                   :: memCLtime          ! time of fields in memory (sec)  
   integer                                 :: curCLhour          ! current hour since start of simulation
+  real(kind=dp)                           :: memCLday           ! current day of simulation
   real(kind=dp), dimension(2)             :: CL_time            ! julian date of fields in memory
-  real, allocatable, dimension(:,:,:)     :: jrate_average      ! monthly average actinic flux 
+  real, allocatable, dimension(:,:)       :: jrate_average      ! daily average actinic flux 
   real, allocatable, dimension(:)         :: lonjr, latjr
 
   private :: zenithangle, photo_O1D
@@ -219,25 +220,6 @@ module chemistry_mod
           error stop
         endif
 
-        if (reag_hourly(nr).gt.0) then
-
-          ! Read average jrates and store in 2nd position
-          !**********************************************
-
-          write(jr_name,'(A)') trim(reag_path(nr))//'jrate_average.nc'
-          inquire(file=jr_name,exist=lexist)
-          if (lexist) then
-            write(*,*) 'Reading jrate field: ',jr_name
-            call readjrate(jr_name, memid, mm)
-          else
-            write(*,*) '#### FLEXPART ERROR                ####'
-            write(*,*) '#### JRATE_AVERAGE NOT FOUND       ####'
-            write(*,*) '#### '//trim(jr_name)//' ####'
-            error stop
-          endif
-
-        endif
-
       end do ! nreagent
 
     else
@@ -278,8 +260,6 @@ module chemistry_mod
               CL_time(memid)=jdmid
             endif
           endif
-          !! testing
-          print*, 'getchemfield: memid, jd, jdmid, CL_time = ',memid,jd,jdmid,CL_time(1)
         else
           call caldate(jd, jjjjmmdd, hhmmss)
           eomday=calceomday(jjjjmmdd/100)
@@ -314,24 +294,6 @@ module chemistry_mod
             error stop
           endif
  
-          ! Read average jrates
-          !********************
-
-          if (reag_hourly(nr).gt.0) then
-            ! Read average jrates into memory 
-            write(jr_name,'(A)') trim(reag_path(nr))//'jrate_average.nc'
-            inquire(file=jr_name,exist=lexist)
-            if (lexist) then
-              write(*,*) 'Reading jrate field: ',jr_name
-              call readjrate(jr_name, memid, mm)
-            else
-              write(*,*) '#### FLEXPART ERROR                ####'
-              write(*,*) '#### JRATE_AVERAGE NOT FOUND       ####'
-              write(*,*) '#### '//trim(jr_name)//' ####'
-              error stop
-            endif
-          endif ! reag_hourly
-
         end do ! nreagent
 
       end do ! memid
@@ -452,44 +414,85 @@ module chemistry_mod
 
     integer            :: itime, curhour, interp_time
     integer            :: nr, kz, ix, jy, ixm, jym, ixp, jyp, indz, indzm, ii
-    real               :: dt1, dt2, dtt, sza, jrate, jrate_cur, r
+    real               :: dt1, dt2, dtt, sza, jrate, r
     real, dimension(2) :: r1
     real               :: dz1, dz2, dz, ddx, ddy, rddx, rddy, p1, p2, p3, p4
-    integer            :: jjjjmmdd, hhmmss
-    integer            :: jrx, jry
-    real(kind=dp)      :: jul
+    integer            :: jjjjmmdd, hhmmss, hh
+    real(kind=dp)      :: jul, curday
     real, parameter    :: avog = 6.02214e23 ! Avogadro constant (1/mol)
     !! testing
-!    character(len=4) :: atime
-!    character(len=20) :: frmt
-!    real, dimension(nxjr,nyjr) :: jscalar, sza_grid
-    
+    character(len=4) :: atime
+    real, dimension(nxCL(1),nyCL(1)) :: jscalar
+    character(len=20) :: frmt
+
     !! testing
-!    jscalar(:,:)=1.
-!    sza_grid(:,:)=0.
+    jscalar(:,:)=0.
 
     ! current hour of simulation
     curhour=itime/3600
     write(*,*) 'getchemhourly: curhour, curCLhour = ',curhour, curCLhour
 
-    jul=bdate+real(itime,kind=dp)/86400._dp
-    call caldate(jul,jjjjmmdd,hhmmss)
-
     if ((ldirect*curCLhour.eq.ldirect*curhour).and.(ldirect*itime.gt.0)) then
       ! chemical field is for current hour -> don't do anything
       return
     else
+
+      ! interpolate chemical field
+      !*****************************
+
+      jul=bdate+real(itime,kind=dp)/86400._dp
+      call caldate(jul,jjjjmmdd,hhmmss)
       ! interpolate to middle of hour
       curCLhour=curhour
       interp_time=curhour*3600+1800
       dt1=float(interp_time-memCLtime(1))
       dt2=float(memCLtime(2)-interp_time)
       dtt=1./(dt1+dt2)
-      !! testing
-      print*, 'getchemhourly: dt1, dt2, dtt = ',dt1,dt2,dtt 
+
+      if (any(reag_hourly.gt.0)) then
+        ! interpolate using rate of O3 + hv -> O1D 
+        ! check if daily mean rate exists for current day
+        ! note: assume that all chemical fields using hourly interpolation
+        ! are on the same grid
+        do nr=1,nreagent
+          if (reag_hourly(nr).gt.0) exit
+        end do
+        curday=bdate+real(itime,kind=dp)/86400._dp
+        curday=floor(curday)
+        write(*,*) 'getchemhourly: curday, memCLday = ',curday, memCLday
+        if (memCLday.ne.curday) then
+          if (.not.allocated(jrate_average)) then
+            allocate(jrate_average(nxCL(1),nyCL(1)))
+          endif
+          memCLday=curday
+          jrate_average(:,:)=0.
+!$OMP PARALLEL &
+!$OMP PRIVATE(jy,ix,hh,sza,jrate) &
+!$OMP REDUCTION(+:jrate_average)
+!$OMP DO
+          do jy=1,nyCL(nr)
+            do ix = 1,nxCL(nr)
+              do hh=0,23
+                sza=zenithangle(latCL(jy,nr),lonCL(ix,nr),jjjjmmdd,hh*10000)
+                jrate=photo_O1D(sza)
+                jrate_average(ix,jy)=jrate_average(ix,jy)+jrate
+              end do
+            end do
+          end do
+!$OMP END DO
+!$OMP END PARALLEL
+          jrate_average=jrate_average/24.
+        end if
+        !! testing
+!        print*, 'getchemhourly: range(jrate_average) = ',minval(jrate_average),maxval(jrate_average)
+      endif
+
+      ! loop over reagents
       do nr=1,nreagent
+
         write(*,*) 'Interpolating fields for reagent: ',reagents(nr)
         clfield_cur(:,:,:,nr)=(dt2*CL_field(:,:,:,nr,1) + dt1*CL_field(:,:,:,nr,2))*dtt
+
         if (reag_unit(nr).eq.'mol/mol') then
           ! convert to molecule/cm3
 !$OMP PARALLEL &
@@ -522,11 +525,6 @@ module chemistry_mod
                 p2=ddx*rddy
                 p3=rddx*ddy
                 p4=ddx*ddy
-                !! testing
-!                if ((ix.lt.5).and.(jy.gt.10.and.jy.lt.20).and.kz.eq.1) then
-!                  print*, 'getchemhourly: lonCL, xlon, latCL, ylat = ',lonCL(ix,nr), xlon0+ixm*dx, latCL(jy,nr), ylat0+jyp*dy
-!                  print*, 'getchemhourly: altCL, height = ',altCL(kz,nr), (dz2*height(indzm)+dz1*height(indzm+1))*dz
-!                endif
                 ! take density from first field (accurate enough)
                 do ii=1,2
                   indz=indzm+ii-1
@@ -545,38 +543,24 @@ module chemistry_mod
 !$OMP END DO
 !$OMP END PARALLEL
         endif
+
         if (reag_hourly(nr).gt.0) then
-          ! use actinic flux (jrate) for interpolation
+          ! interpolate using rate of O3 + hv -> O1D 
 !$OMP PARALLEL &
-!$OMP PRIVATE(kz,jy,jry,ix,jrx,sza,jrate,jrate_cur) 
+!$OMP PRIVATE(kz,jy,ix,sza,jrate) 
 !$OMP DO
           do kz=1,nzCL(nr)
             do jy=1,nyCL(nr)
-              ! jrate_average dimensions given as grid midpoints
-              jry=int((latCL(jy,nr)-(latjr(1)-0.5*dyjr))/dyjr)+1
-              jry=min(jry,nyCL(nr))
-              !! testing
-!              if (kz.eq.1.and.jy.lt.10) print*, 'latCL, latjr = ',latCL(jy), latjr(jry)
               do ix=1,nxCL(nr)
-                ! jrate_average dimensions given as grid midpoints
-                jrx=int((lonCL(ix,nr)-(lonjr(1)-0.5*dxjr))/dxjr)+1
-                jrx=min(jrx,nxCL(nr))
-                !! testing
-!                if (kz.eq.1.and.jy.lt.10.and.ix.lt.10) print*, 'lonCL, lonjr = ',lonCL(ix), lonjr(jrx)
                 ! solar zenith angle
-                sza=zenithangle(latjr(jry),lonjr(jrx),jjjjmmdd,hhmmss)
+                sza=zenithangle(latCL(jy,nr),lonCL(ix,nr),jjjjmmdd,hhmmss)
                 ! calculate J(O1D) (jrate)
                 jrate=photo_O1D(sza)
-                jrate_cur=(dt2*jrate_average(jrx,jry,1) + &
-                           dt1*jrate_average(jrx,jry,2))*dtt
-                ! apply hourly correction to chem field
-                if(jrate_cur.gt.0.) then
-                  clfield_cur(ix,jy,kz,nr)=clfield_cur(ix,jy,kz,nr)*jrate/jrate_cur
+                ! hourly correction
+                if (jrate_average(ix,jy).ne.0) then
+                  clfield_cur(ix,jy,kz,nr)=clfield_cur(ix,jy,kz,nr)*jrate/jrate_average(ix,jy)
                   !! testing
-!                  if (kz.eq.1) then
-!                    jscalar(ix,jy)=jrate/jrate_cur
-!                    sza_grid(ix,jy)=sza
-!                  endif
+!                  jscalar(ix,jy)=jrate/jrate_average(ix,jy)
                 endif
               end do
             end do
@@ -588,30 +572,18 @@ module chemistry_mod
     endif ! curhour
 
     !! testing
-!    write(frmt,fmt='(A,I4,A)') '(',nxCL,'(E14.6))'
 !    write(atime,fmt='(I4.4)') curhour
-!    open(600,file=path(2)(1:length(2))//'clfield_'//atime//'.txt',action='write',status='replace')
-!    do kz=1,nzCL
-!      do jy=1,nyCL
-!        write(600,fmt=frmt) clfield_cur(:,jy,kz,1)
-!      end do
-!    end do
-!    close(600)
-!    write(frmt,fmt='(A,I4,A)') '(',nxjr,'(E14.6))'
+!    write(frmt,fmt='(A,I4,A)') '(',nxCL(1),'(E14.6))'
 !    open(600,file=path(2)(1:length(2))//'jscalar_'//atime//'.txt',action='write',status='replace')
-!    do jy=1,nyjr
+!    do jy=1,nyCL(1)
 !      write(600,fmt=frmt) jscalar(:,jy)
 !    end do
 !    close(600)
-!    write(frmt,fmt='(A,I4,A)') '(',nxjr,'(E14.6))'
-!    open(600,file=path(2)(1:length(2))//'sza_'//atime//'.txt',action='write',status='replace')
-!    do jy=1,nyjr
-!      write(600,fmt=frmt) sza_grid(:,jy)
-!    end do
-!    close(600)
+    !!
 
   end subroutine getchemhourly
 
+
   subroutine chemreaction(itime)
 
   !*****************************************************************************
@@ -817,73 +789,13 @@ module chemistry_mod
   end subroutine chemreaction
 
 
-  subroutine readjrate(jr_name,memid,mm)
-
-  !*****************************************************************************
-  !                                                                            *
-  !    Reads the average actinic flux rates into memory                        *
-  !                                                                            *
-  !    Author: Rona Thompson, Sep 2023                                         *
-  !                                                                            *
-  !*****************************************************************************
-  !                                                                            *
-  ! Variables:                                                                 *
-  !                                                                            *
-  ! jr_name           name of the file                                         *
-  ! memid             time index to chemical field variable                    *
-  ! mm                month to read                                            *
-  !                                                                            * 
-  !*****************************************************************************
-
-    implicit none
-
-    character(len=256) :: jr_name
-    integer            :: memid,mm
-    integer            :: ncid,dimid,varid
-
-    ! Read netcdf file
-    !******************
-
-    ! open file
-    call nf90_err( nf90_open(trim(jr_name),nf90_NOWRITE,ncid) )
-
-    ! longitude
-    call nf90_err( nf90_inq_dimid(ncid,'longitude',dimid) )
-    call nf90_err( nf90_inquire_dimension(ncid,dimid,len=nxjr) )
-    if (.not.allocated(lonjr)) allocate(lonjr(nxjr))
-    call nf90_err( nf90_inq_varid(ncid,'longitude',varid) )
-    call nf90_err( nf90_get_var(ncid,varid,lonjr) )
-    dxjr=abs(lonjr(2)-lonjr(1))
-
-    ! latitude
-    call nf90_err( nf90_inq_dimid(ncid,'latitude',dimid) )
-    call nf90_err( nf90_inquire_dimension(ncid,dimid,len=nyjr) )
-    if (.not.allocated(latjr)) allocate(latjr(nyjr))
-    call nf90_err( nf90_inq_varid(ncid,'latitude',varid) )
-    call nf90_err( nf90_get_var(ncid,varid,latjr) )
-    dyjr=abs(latjr(2)-latjr(1))
-
-    ! jrate field
-    call nf90_err( nf90_inq_varid(ncid,'jrate',varid) )
-    if (.not.allocated(jrate_average)) then
-      allocate(jrate_average(nxjr,nyjr,2))
-    endif
-    call nf90_err( nf90_get_var(ncid,varid,jrate_average(:,:,memid),start=(/1,1,mm/),count=(/nxjr,nyjr,1/)) )
-
-    ! close file
-    call nf90_err( nf90_close(ncid) )
-
-    return
-
-  end subroutine readjrate
-
   function photo_O1D(sza) result(jrate)
 
   !*****************************************************************************
   !                                                                            *
   !    Calculates J(O1D) photolysis rate based on solar zenith angle           *
   !                                                                            *
-  !    Author: A. Stohl, Nov 2014                                              *
+  !    Ref: Hamer, P. D., et al. Atmos. Chem. Phys. 2015
   !                                                                            *
   !*****************************************************************************
   !                                                                            *
@@ -898,38 +810,18 @@ module chemistry_mod
     implicit none
 
     real, intent(in)  :: sza
-    real :: jrate
-    integer :: iz,ik
-    real :: z1,z2,zg,f1,f2,dummy
-    real :: photo_NO2
-    integer, parameter :: nzenith=11
+    real :: sun, jrate
     real, parameter :: pi=3.1415927
-    real, dimension(nzenith) :: zangle,fact_photo
-
-    ! zangle: zenith angles for which fact_photo is tabulated
-    ! fact_photo: conversion of photolysis rate of NO2 to photolysis 
-    !     rate of O3 into O1D as a function of solar zenith angle
-
-    zangle=(/0.,10.,20.,30.,40.,50.,60.,70.,78.,86.,90.0001/)
-    fact_photo=(/0.4616E-02,0.4478E-02,0.4131E-02,0.3583E-02,0.2867E-02,&
-      &0.2081E-02,0.1235E-02,0.5392E-03,0.2200E-03,0.1302E-03,0.0902E-03/)
 
-    if (sza.lt.90.) then
-      do iz=1,nzenith-1
-        if(sza.ge.zangle(iz)) ik=iz
-      end do
-      z1=1./cos(zangle(ik)*pi/180.)
-      z2=1./cos(zangle(ik+1)*pi/180.)
-      zg=1./cos(sza*pi/180.)
-      dummy=(zg-z1)/(z2-z1)
-      f1=alog(fact_photo(ik))
-      f2=alog(fact_photo(ik+1))
-      photo_NO2=1.45e-2*exp(-0.4/cos(sza*pi/180.))
-      jrate=photo_NO2*exp(f1+(f2-f1)*dummy)
+    sun=sza*pi/180.
+    if (sun.le.(pi/2.)) then
+      sun=cos(sun)
     else
-      jrate=0.
+      sun=0.
     endif
 
+    jrate=(8.978e-5*(sun**1.436)*exp(-0.936/sun))
+
   end function photo_O1D