From c1c9fd9e6eb55d1d614f30b599b49d7b08fdd4ae Mon Sep 17 00:00:00 2001
From: ronesy <rlt@nilu.no>
Date: Mon, 24 Apr 2023 17:35:58 +0200
Subject: [PATCH] Updated calculation of initial mixing ratios and harmonized
 reading of initial mixing ratio fields

---
 source/get_initconc.f90    | 409 +++++++++++++++++++++++++++++++------
 source/init_cini.f90       | 186 ++++++++---------
 source/init_cini_month.f90 | 346 +++++++++++++++++++++++++++++++
 source/init_co2.f90        |   8 +-
 source/init_ghg.f90        |  26 +--
 source/initialize.f90      |  17 +-
 source/interpz.f90         | 108 +++++++---
 source/main.f90            |   3 +
 source/makefile            |   8 +-
 source/mod_perturb.f90     |   1 -
 source/mod_save.f90        |  66 +++---
 source/mod_settings.f90    |  50 ++++-
 source/mod_var.f90         |  12 +-
 source/read_orog.f90       | 109 ++++++++++
 source/simulate.f90        |  10 +-
 15 files changed, 1071 insertions(+), 288 deletions(-)
 create mode 100644 source/init_cini_month.f90
 create mode 100644 source/read_orog.f90

diff --git a/source/get_initconc.f90 b/source/get_initconc.f90
index 9bc7ab1..d06ac3e 100644
--- a/source/get_initconc.f90
+++ b/source/get_initconc.f90
@@ -25,8 +25,10 @@
 !! Interface:
 !!
 !!    Inputs
+!!             files     -  file data structure
+!!             config    -  configuration settings data structure
 !!             filename  -  name of 4D concentration file
-!!             varname   -  variable name
+!!             ntime     -  time dimension of concentration field 
 !!             concini   -  concentrations on flexpart grid (zero array on input)
 !! 
 !!    Externals
@@ -34,34 +36,46 @@
 !!             interpz
 !!             check
 !!             
+!! To do:
+!!
+!!    Add temperature to EGG4 and CAMS-N2O files for more accurate geopotential
+!!    heights
+!!
 !---------------------------------------------------------------------------------------
 
-subroutine get_initconc(filename, varname, concini)
+subroutine get_initconc(files, config, filename, ntime, concini)
 
   use mod_var
+  use mod_settings
+  use mod_tools,   only : sort
   use mod_save,    only : check
   use netcdf
   
   implicit none
 
-  character(len=max_path_len),           intent(in)     :: filename
-  character(len=max_name_len),           intent(in)     :: varname
-  real, dimension(nxgrid,nygrid,nzgrid), intent(in out) :: concini
-
-  character(len=*), parameter                           :: lonname='longitude'
-  character(len=*), parameter                           :: latname='latitude'
-  character(len=*), parameter                           :: prsname='pressure'
-  character(len=*), parameter                           :: timename='time'
-  integer                                               :: ncid, xid, yid, zid, tid, varid
-  integer                                               :: kz
-  integer                                               :: nx, ny, nz, nt 
-  integer                                               :: nx_out, ny_out
-  logical                                               :: midpoints
-  real, dimension(:), allocatable                       :: lon, lat, prs, geoh
-  real, dimension(nxgrid)                               :: lon_out
-  real, dimension(nygrid)                               :: lat_out
-  real, dimension(:,:,:), allocatable                   :: work, workout, concout
-  real, dimension(:,:,:,:), allocatable                 :: conc  
+  type (files_t),                              intent(in)     :: files
+  type (config_t),                             intent(in)     :: config
+  character(len=max_path_len),                 intent(in)     :: filename
+  integer,                                     intent(in)     :: ntime
+  real, dimension(nxgrid,nygrid,nzgrid,ntime), intent(in out) :: concini
+
+  character(len=max_name_len)                                 :: lonname, latname, varname, prsname, timename
+  logical                                                     :: midpoints
+  integer                                                     :: ncid, xid, yid, zid, tid, varid
+  integer                                                     :: n, kz, status, iproduct, zkind
+  integer                                                     :: nx, ny, nz, nt  
+  integer                                                     :: nx_out, ny_out
+  real, dimension(:), allocatable                             :: lon, lat
+  real(kind=8), dimension(:), allocatable                     :: lono, lato, alto
+  real, dimension(:), allocatable                             :: ap, bp, mpres
+  integer, dimension(:), allocatable                          :: indx, indy, indz
+  real, dimension(nxgrid)                                     :: lon_out
+  real, dimension(nygrid)                                     :: lat_out
+  real, dimension(:,:), allocatable                           :: rpres, scalh
+  real, dimension(:,:,:), allocatable                         :: work1, work2, work3, work4
+  real, dimension(:,:,:), allocatable                         :: geoh, geoho, pres, surfp, pw
+  real, dimension(:,:,:,:), allocatable                       :: conc, conco, humid, temp
+  real                                                        :: sclfact, offset
 
   ! initialize
   ! ----------
@@ -72,6 +86,56 @@ subroutine get_initconc(filename, varname, concini)
   nx_out = nxgrid
   ny_out = nygrid
 
+  ! which initial concentration field product
+  ! 1 = CAMS CH4, 2 = EGG4, 3 = CAMS N2O, 4 = FP-CTM, 5 = NOAA interpolated, 6 = FP-CTM (monthly)
+  iproduct = int(files%init_type)
+  varname = files%varname_init
+
+  select case ( iproduct)
+    case (1)
+    ! CAMS CH4
+      lonname = 'longitude'
+      latname = 'latitude'
+      timename = 'time'
+      prsname = 'level'
+    case (2)
+    ! EGG4
+      lonname = 'longitude'
+      latname = 'latitude'
+      timename = 'time'
+      prsname = 'level'
+    case (3)
+    ! CAMS N2O
+      lonname = 'longitude'
+      latname = 'latitude'
+      timename = 'time'
+      prsname = 'level'
+    case (4)
+    ! FP-CTM
+      lonname = 'longitude'
+      latname = 'latitude'
+      timename = 'Date'
+      prsname = 'lev'
+    case (5)
+    ! NOAA
+      lonname = 'longitude'
+      latname = 'latitude'
+      timename = 'time'
+      prsname = 'pressure'     
+    case (6)
+    ! FP-CTM (monthly)
+      lonname = 'longitude'
+      latname = 'latitude'
+      timename = 'none'
+      prsname = 'lev'
+  end select
+  
+  ! from here on FP-CTM daily and monthly treated the same
+  if ( iproduct.eq.6 ) iproduct = 4
+
+  print*, 'get_initconc: lonname, latname, prsname =',lonname,latname,prsname
+
+
   ! read netcdf file
   ! ----------------
 
@@ -79,70 +143,285 @@ subroutine get_initconc(filename, varname, concini)
 
   ! read dimensions
   call check( nf90_open(trim(filename),nf90_NOWRITE,ncid) )
-  call check( nf90_inq_dimid(ncid,lonname,xid) )
-  call check( nf90_inq_dimid(ncid,latname,yid) )
-  call check( nf90_inq_dimid(ncid,prsname,zid) )
-  call check( nf90_inq_dimid(ncid,timename,tid) )
+  call check( nf90_inq_dimid(ncid,trim(lonname),xid) )
   call check( nf90_inquire_dimension(ncid,xid,len=nx) )
+  call check( nf90_inq_dimid(ncid,trim(latname),yid) )
   call check( nf90_inquire_dimension(ncid,yid,len=ny) )
+  call check( nf90_inq_dimid(ncid,trim(prsname),zid) )
   call check( nf90_inquire_dimension(ncid,zid,len=nz) )
-  call check( nf90_inquire_dimension(ncid,tid,len=nt) )
-
-  ! mean so time dimension should be 1 
-  if( nt.ne.1 ) then
-     write(logid,*) 'ERROR get_initconc: time dimension should have length of 1 in '//trim(filename)
-     stop
+  if ( trim(timename).ne.'none' ) then
+    call check( nf90_inq_dimid(ncid,trim(timename),tid) )
+    call check( nf90_inquire_dimension(ncid,tid,len=nt) )
+  else
+    nt = 1
   endif
+  if ( ntime.ne.nt ) write(logid,*) 'ERROR get_initconc: inconsistent time dimension'
 
+  ! read dimension variables
   allocate( lon(nx) )
   allocate( lat(ny) )
-  allocate( prs(nz) )
+  call check( nf90_inq_varid(ncid,trim(lonname),varid) )
+  call check( nf90_get_var(ncid,varid,lon) )
+  call check( nf90_inq_varid(ncid,trim(latname),varid) )
+  call check( nf90_get_var(ncid,varid,lat) )
+
+  ! read supporting variables
+  select case (iproduct)
+    case (1)  
+    ! CAMS CH4
+      ! hybrid pressure coordinates
+      allocate( ap(nz) )
+      allocate( bp(nz) )
+      call check( nf90_inq_varid(ncid,'hyam',varid) )
+      call check( nf90_get_var(ncid,varid,ap) )
+      call check( nf90_inq_varid(ncid,'hybm',varid) )
+      call check( nf90_get_var(ncid,varid,bp) ) 
+      ! read temperature
+      allocate( temp(nx,ny,nz,nt) )
+      call check( nf90_inq_varid(ncid,'T',varid) )
+      call check( nf90_get_var(ncid,varid,temp) )
+      call check( nf90_get_att(ncid, varid, 'scale_factor', sclfact) )
+      call check( nf90_get_att(ncid, varid, 'add_offset', offset) )
+      temp = temp*sclfact + offset
+      ! read surface pressure
+      allocate( surfp(nx,ny,nt) )
+      call check( nf90_inq_varid(ncid,'ps',varid) )
+      call check( nf90_get_var(ncid,varid,surfp) )
+      call check( nf90_get_att(ncid, varid, 'scale_factor', sclfact) )
+      call check( nf90_get_att(ncid, varid, 'add_offset', offset) )
+      surfp = surfp*sclfact + offset
+      ! mixing ratio is in humid air -> read specific humidity
+      allocate( humid(nx,ny,nz,nt) )
+      call check( nf90_inq_varid(ncid,'Q',varid) )
+      call check( nf90_get_var(ncid,varid,humid) )
+      call check( nf90_get_att(ncid, varid, 'scale_factor', sclfact) )
+      call check( nf90_get_att(ncid, varid, 'add_offset', offset) )
+      humid = humid*sclfact + offset
+    case (2)  
+    ! EGG4
+      ! vertical coordinate is pressure
+      allocate( mpres(nz) )
+      call check( nf90_inq_varid(ncid,trim(prsname),varid) )
+      call check( nf90_get_var(ncid,varid,mpres) )
+      ! convert to unit of Pa
+      mpres = mpres*100.
+    case (3) 
+    ! CAMS N2O
+      ! vertical coordinate is pressure
+      allocate( mpres(nz) )
+      call check( nf90_inq_varid(ncid,trim(prsname),varid) )
+      call check( nf90_get_var(ncid,varid,mpres) )
+    case (4)
+    ! FP-CTM
+      allocate( mpres(nz) )
+      call check( nf90_inq_varid(ncid,trim(prsname),varid) )
+      call check( nf90_get_var(ncid,varid,mpres) )
+    case (5)
+    ! NOAA
+      allocate( mpres(nz) )
+      call check( nf90_inq_varid(ncid,trim(prsname),varid) )
+      call check( nf90_get_var(ncid,varid,mpres) )
+  end select
+
+  ! read mixing ratio
   allocate( conc(nx,ny,nz,nt) )
-  allocate( work(nx,ny,1) )
-  allocate( workout(nxgrid,nygrid,1) ) 
-  allocate( concout(nxgrid,nygrid,nz) )
-  allocate( geoh(nz) )
-
-  ! read variables
-  call check( nf90_inq_varid(ncid,lonname,xid) )
-  call check( nf90_get_var(ncid,xid,lon) )
-  call check( nf90_inq_varid(ncid,latname,yid) )
-  call check( nf90_get_var(ncid,yid,lat) )
-  call check( nf90_inq_varid(ncid,prsname,zid) )
-  call check( nf90_get_var(ncid,zid,prs) )
   call check( nf90_inq_varid(ncid,trim(varname),varid) )
   call check( nf90_get_var(ncid,varid,conc(:,:,:,:)) )
-
+  ! check if file contains scalar and offset
+  status = nf90_inquire_attribute(ncid,varid,'scale_factor')
+  if ( status.eq.nf90_noerr ) then
+    call check( nf90_get_att(ncid, varid, 'scale_factor', sclfact) )
+    call check( nf90_get_att(ncid, varid, 'add_offset', offset) )
+    conc = conc*sclfact + offset
+  endif
   call check( nf90_close(ncid) )
 
-  ! calculate geopotential height for each layer
-  do kz = 1, nz
-    geoh(kz) = (gasc*ts/gc/mmol)*log(psurf/prs(kz))
-  enddo
+  ! adjust mixing ratios
+  ! --------------------
 
-  ! interpolate to flexpart grid
-  ! ----------------------------
-  
-  ! interpolate horizontally
-  midpoints = .false.
-  do kz = 1, nz
-    work(:,:,1) = conc(:,:,kz,1)
-    ! gbl_lon and gbl_lat are lon and lat of global flexpart domain
-    call convertgrid(midpoints, nx, ny, lon, lat, work, nx_out, ny_out, lon_out, lat_out, workout)
-    concout(:,:,kz) = workout(:,:,1)
-  end do
+  select case ( iproduct )
+    case (1)
+    ! CAMS CH4
+      ! mole fraction of humid air -> convert to dry air
+      ! calculate mid layer pressure (mean over nt steps)
+      allocate( pres(nx,ny,nz) )
+      allocate( pw(nx,ny,nz) )
+      do n = 1, nz
+        pres(:,:,n) = ap(n) + bp(n)*sum(surfp(:,:,:),dim=3)/real(nt)
+      end do
+      ! partial pressure water from specific humidity
+      pw = sum(humid,dim=4)*pres/real(nt)/(0.622 + 0.378*(sum(humid,dim=4)/real(nt)))
+      do n = 1, nt
+        conc(:,:,:,n) = conc(:,:,:,n)*pres/(pres - pw)    
+      end do
+      print*, 'pres = ',pres(nx/2,ny/2,:)
+      print*, 'range corr dry air = ',minval(pres/(pres-pw)),maxval(pres/(pres-pw))
+      deallocate( humid )
+      deallocate( pw )
+    case (2)
+    ! EGG4
+      ! adjust units from mass mixing ratio to mole fraction
+      conc = conc*1.e9*mmair/config%molarmass
+  end select
+
+  ! calculate geopotential height
+  ! -----------------------------
+
+  allocate( geoh(nx,ny,nz) )
+
+  select case (iproduct)
+    case (1)
+    ! CAMS CH4
+      allocate( rpres(nx,ny) )
+      allocate( scalh(nx,ny) )
+      do n = 1, nz
+        rpres = sum(surfp(:,:,:),dim=3)/real(nt)/pres(:,:,n)
+        scalh = gasc*sum(temp(:,:,n,:),dim=3)/real(nt)/mmol/gc
+        geoh(:,:,n) = scalh*log(rpres)
+        print*, 'range(scalh) = ',minval(scalh), maxval(scalh)
+      end do
+      deallocate( rpres )
+      deallocate( scalh )
+      deallocate( surfp )
+      zkind = 0
+    case (2)
+    ! EGG4
+      do n = 1, nz
+        !  at present temp not included so use estimate
+        geoh(:,:,n) = (gasc*ts/gc/mmol)*log(psurf/mpres(n))
+      end do
+      zkind = 0
+    case (3)
+    ! CAMS N2O
+      do n = 1, nz
+        ! at present temp not included so use estimate
+        geoh(:,:,n) = (gasc*ts/gc/mmol)*log(psurf/mpres(n))
+      end do
+      zkind = 0
+    case (4)
+    ! FP-CTM
+      ! vertical coordinate is meters above ground 
+      do n = 1, nz
+        geoh(:,:,n) = mpres(n)
+      end do
+      zkind = 1
+    case (5)
+    ! NOAA
+      do n = 1, nz
+        ! at present temp not included so use estimate
+        geoh(:,:,n) = (gasc*ts/gc/mmol)*log(psurf/mpres(n))
+      end do
+      zkind = 0
+  end select
+
+  if ( allocated(mpres) ) deallocate( mpres )
+  if ( allocated(pres) )  deallocate( pres )
+  if ( allocated(temp) )  deallocate( temp )
+
+  ! adjust lat, lon and alt of grid
+  ! -------------------------------
 
-  ! interpolate vertically
-  call interpz(nz, geoh, concout, concini)
+  select case ( iproduct )
+    case (1)
+    ! CAMS CH4
+      midpoints = .true.
+    case (2)
+    ! EGG4
+      ! adjust longitude to be -180 to 180
+      where( lon.gt.180. ) lon(:) = lon(:) - 360.
+      ! longitude given as eastern boundary
+      lon(:) = lon(:) - 0.5*(lon(2) - lon(1))
+      ! file contains extra latitude
+      ! latitude given from 90 to -90
+      do n = 1, ny
+        lat(n) = 90. - real(n-1)*(180./real(ny-1)) - 0.5*180./real(ny-1)
+      end do
+      ny = ny - 1
+      midpoints = .true.
+    case (3)
+    ! CAMS N2O
+      ! file contains extra longitude
+      nx = nx - 1
+      ! latitude given from 90 to -90
+      do n = 1, ny
+        lat(n) = 90. - real(n)*(180./real(ny))
+      end do
+      midpoints = .false.
+    case (4)
+    ! FP-CTM 
+      ! file contains extra longitude
+      nx = nx - 1
+      print*, 'get_initconc: nx = ',nx
+      lon(:) = lon(:) + 0.5*(lon(2) - lon(1))
+      midpoints = .true.
+    case (5)
+    ! NOAA
+      midpoints = .false.
+  end select
 
+  ! sort from south to north and west to east
+  print*, 'get_initconc: lon = ',lon
+  print*, 'get_iniconc: lat = ',lat
+  allocate( indy(ny) )
+  allocate( indx(nx) )
+  allocate( lato(ny) )
+  allocate( lono(nx) )
+  allocate( conco(nx,ny,nz,nt) )
+  allocate( geoho(nx,ny,nz) )
+  lato = dble(lat(1:ny))
+  lono = dble(lon(1:nx))
+  call sort(ny, lato, indy)
+  call sort(nx, lono, indx)
+  ! sort from lowest to highest level
+  allocate( indz(nz) )
+  allocate( alto(nz) )
+  alto = dble(geoh(nx/2,ny/2,:))
+  call sort(nz, alto, indz)
+  print*, 'get_initconc: geoh = ',geoh(nx/2,ny/2,:)
+  print*, 'get_initconc: indx = ',indx
+  print*, 'get_initconc: indy = ',indy
+  print*, 'get_initconc: lono = ',lono
+  print*, 'get_initconc: lato = ',lato
+  print*, 'get_initconc: indz = ',indz
+  conco = conc(indx,indy,indz,:)
+  geoho = geoh(indx,indy,indz)
+  deallocate( indx )
+  deallocate( indy )
   deallocate( lon )
   deallocate( lat )
-  deallocate( prs )
+
+  ! interpolate to flexpart grid
+  ! ----------------------------
+
+  allocate( work1(nx,ny,nz) )
+  allocate( work2(nx,ny,nzgrid) )
+  allocate( work3(nx,ny,1) )
+  allocate( work4(nxgrid,nygrid,1) )
+
+  do n = 1, nt
+    work1(:,:,:) = conco(:,:,:,n)
+    ! interpolate vertically
+    call interpz(nx, ny, nz, zkind, midpoints, sngl(lono), sngl(lato), geoho, work1, work2)
+    ! interpolate horizontally
+    do kz = 1, nzgrid
+      work3(:,:,1) = work2(:,:,kz)
+      ! lon_out and lat_out are for global flexpart domain
+      call convertgrid(midpoints, nx, ny, sngl(lono), sngl(lato), work3, nx_out, ny_out, lon_out, lat_out, work4)
+      concini(:,:,kz,n) = work4(:,:,1)
+    end do
+  end do
+
+  deallocate( lono )  
+  deallocate( lato )
+  deallocate( alto )
   deallocate( conc )
-  deallocate( work )
-  deallocate( workout )
-  deallocate( concout )
   deallocate( geoh )
+  deallocate( conco )
+  deallocate( geoho )
+  deallocate( work1 )
+  deallocate( work2 )
+  deallocate( work3 )
+  deallocate( work4 )
 
 end subroutine get_initconc
 
diff --git a/source/init_cini.f90 b/source/init_cini.f90
index 93088e6..19a493d 100644
--- a/source/init_cini.f90
+++ b/source/init_cini.f90
@@ -52,37 +52,55 @@ subroutine init_cini(files, config, obs)
   type (config_t),       intent (in)     :: config
   type (obs_t),          intent (in out) :: obs
 
-  character(max_path_len)                :: path_flexrec, filename
-  character(max_name_len)                :: varname
+  character(max_path_len)                :: path_flexrec, pathname, filename
   character(len=8)                       :: adate, areldate, areltime
+  character(len=6)                       :: ayrmon
+  character(len=4)                       :: ayear
+  character(len=2)                       :: amonth
   logical                                :: lexist
-  integer                                :: lastjjjjmm, prejjjjmm, projjjjmm
-  integer                                :: jjjjmm, jjjjmmdd, hhmiss, mm, eomday
-  integer                                :: ix, jy, kz, i, n
+
+  integer                                :: hfreq 
+  integer                                :: jjjjmm, jjjjmmdd, hhmiss, eomday
+  integer                                :: lasttime, startmonth
   integer                                :: month, prevmonth
-  real                                   :: conc
-  real(kind=8)                           :: jdmid, jdpre, jdlast
+  integer                                :: ix, jy, kz, i, n, nt, nz, nhours, ntime, ierr
+  real(kind=8)                           :: jdi
   real(kind=8), dimension(nobs)          :: jdates
   real, dimension(nobs,ncini)            :: cini
   integer, dimension(nobs)               :: ind
   real, dimension(nxgrid,nygrid,nzgrid)  :: gridini, gridini_tmp
-  real, dimension(nxgrid,nygrid,nzgrid)  :: concini, preconcini, proconcini
+  real, dimension(:,:,:,:), allocatable  :: concini
 
   real                                   :: bndx, bndy, delx, dely
   integer                                :: numx, numy, xshift
   integer                                :: numpoint, release_nr, nr_init
   integer                                :: ibdate, ibtime
   real(kind=8), dimension(maxpoint,2)    :: releases
+  integer                                :: nretr
+  character(len=recname_len)             :: anretr
+
+
+  ! initialize
+  ! ----------
 
+  ! which initial concentration field product
+  ! 1 = CAMS CH4, 2 = EGG4, 3 = CAMS N2O, 4 = FP-CTM (daily)
+  select case ( files%init_type )
+    case (1)
+      hfreq = 24
+    case (2)
+      hfreq = 6
+    case (3)
+      hfreq = 3
+    case (4)
+      hfreq = 24
+  end select
 
   ! loop over observations
   ! ----------------------
 
-  lastjjjjmm = 0
-  concini(:,:,:) = 0.
-  preconcini(:,:,:) = 0.
-  proconcini(:,:,:) = 0.
   cini(:,:) = 0.
+  lasttime = 0
   prevmonth = 0
 
   ! sort obs chronologically for efficiency
@@ -95,9 +113,12 @@ subroutine init_cini(files, config, obs)
     gridini(:,:,:) = 0.
     nr_init = 0
 
+    print*, 'obs%recs(i) = ',obs%recs(ind(i))
+
     ! check month of observation
     call caldate(jdates(i), jjjjmmdd, hhmiss)
     write(adate,'(I6.6)') jjjjmmdd/100
+    write(areldate,'(I8.8)') jjjjmmdd
     month = jjjjmmdd/100
     path_flexrec = trim(files%path_flexpart)//trim(obs%recs(ind(i)))//'/'//trim(adate)//'/'
 
@@ -131,7 +152,6 @@ subroutine init_cini(files, config, obs)
       write(areldate,'(I8.8)') jjjjmmdd
       write(areltime,'(I6.6)') hhmiss
       filename = trim(path_flexrec)//'grid_initial_'//trim(areldate)//trim(areltime)//'_001'
-!      print*, 'init_cini: filename = ',filename
       ! read first flexpart grid_init files
       inquire ( file=trim(filename), exist=lexist )
       if ( lexist ) then
@@ -148,7 +168,6 @@ subroutine init_cini(files, config, obs)
           write(areltime,'(I6.6)') hhmiss
           path_flexrec = trim(files%path_flexpart)//trim(obs%recs(ind(i)))//'/'//trim(adate)//'/'
           filename = trim(path_flexrec)//'grid_initial_'//trim(areldate)//trim(areltime)//'_001'
-!          print*, 'init_cini: filename next = ',filename
           ! sum the grid with previous initial grids
           call read_init(filename, gridini_tmp)
           gridini = gridini + gridini_tmp
@@ -187,114 +206,73 @@ subroutine init_cini(files, config, obs)
     endif 
 
     ! calculate termination time of trajectory
-    call caldate(jdates(i) - trajdays, jjjjmmdd, hhmiss)
+    jdi = jdates(i) - trajdays
+    call caldate(jdi, jjjjmmdd, hhmiss)
     jjjjmm = jjjjmmdd/100
-   
-    ! preceding and proceding months
-    mm = jjjjmm - (jjjjmm/100)*100
-    if( mm.gt.1 ) then
-      prejjjjmm = jjjjmm - 1
-    else
-      prejjjjmm = (jjjjmm/100 - 1)*100 + 12
-    endif
-    if( mm.lt.12 ) then
-      projjjjmm = jjjjmm + 1
-    else
-      projjjjmm = (jjjjmm/100 + 1)*100 + 1
-    endif
 
-    jdmid = juldate(jjjjmm*100+14, 0)
-    jdpre = juldate(prejjjjmm*100+14, 0)
-    jdlast = juldate(lastjjjjmm*100+14, 0) 
-    eomday = calceomday(prejjjjmm)
-
-    ! get new concentrations if not same month as previous observation 
-    if( jjjjmm.ne.lastjjjjmm ) then
-      if( (lastjjjjmm.ne.0).and.(jdmid.eq.(jdlast+dble(eomday))) ) then
-        ! this is proceeding month
-        preconcini = concini
-        concini = proconcini
-        ! get proceeding concentration field
-        write(adate,'(I6.6)') projjjjmm
-        filename = str_replace(files%file_initconc, 'YYYYMM', adate)  
-        filename = trim(files%path_initconc)//trim(filename)
-        inquire(file=trim(filename),exist=lexist)
-        if(lexist) then
-          varname = files%varname_init
-          call get_initconc(filename, varname, proconcini)
-        else
-          write(logid,*) 'WARNING: cannot find ',filename
-          write(logid,*) 'WARNING: next background file missing, copy present into next to avoid 0 value'
-          proconcini = concini
-        endif
-      else 
-        ! get current concentration field
-        write(adate,'(I6.6)') jjjjmm
-        filename = str_replace(files%file_initconc, 'YYYYMM', adate)
-        filename = trim(files%path_initconc)//trim(filename)
-        inquire(file=trim(filename),exist=lexist)
-        if(lexist) then
-          varname = files%varname_init
-          call get_initconc(filename, varname, concini)
-        else
-          write(logid,*) 'WARNING: cannot find ',filename
-          go to 10
-        endif
-        ! get previous concentration field
-        write(adate,'(I6.6)') prejjjjmm
-        filename = str_replace(files%file_initconc, 'YYYYMM', adate)  
-        filename = trim(files%path_initconc)//trim(filename)
-        inquire(file=trim(filename),exist=lexist)
-        if(lexist) then
-          varname = files%varname_init
-          call get_initconc(filename, varname, preconcini)
-        else
-          write(logid,*) 'WARNING: cannot find ',filename
-          go to 10
-        endif
-        ! get next concentration field
-        write(adate,'(I6.6)') projjjjmm
-        filename = str_replace(files%file_initconc, 'YYYYMM', adate)  
-        filename = trim(files%path_initconc)//trim(filename)
-        inquire(file=trim(filename),exist=lexist)
-        if(lexist) then
-          varname = files%varname_init
-          call get_initconc(filename, varname, proconcini)
-        else
-          write(logid,*) 'WARNING: cannot find ',filename
-          write(logid,*) 'WARNING: next background file missing, copy present into next to avoid 0 value'
-          proconcini = concini
-        endif
-      endif   
+    ! read concentration field only if not already in memory
+    if ( jjjjmm.ne.lasttime ) then
+      ! allocate concini knowing data freq (from hfreq)
+      if (allocated( concini ) ) deallocate( concini )
+      eomday = calceomday(jjjjmm)
+      ntime = eomday*24/hfreq
+      allocate( concini(nxgrid,nygrid,nzgrid,ntime), stat = ierr )
+      if ( ierr.ne.0 ) then
+        write(logid,*) 'ERROR init_cini: not enough memory'
+        stop
+      endif
+      concini(:,:,:,:) = 0.
+      ! read new concentration field
+      write(ayear,'(I4.4)') jjjjmm/100
+      write(ayrmon,'(I6.6)') jjjjmm
+      write(amonth,'(I2.2)') jjjjmm-(jjjjmm/100)*100
+      if ( index(files%path_initconc, 'YYYY').ne.0 ) then
+        pathname = str_replace(files%path_initconc, 'YYYY', ayear)
+      else
+        pathname = files%path_initconc
+      endif
+      filename = str_replace(files%file_initconc, 'YYYY', ayear)
+      filename = str_replace(filename, 'MM', amonth)
+      filename = trim(pathname)//trim(filename)
+      print*, 'init_cini: filename = ',filename
+      inquire(file=trim(filename),exist=lexist)
+      if(lexist) then
+        call get_initconc(files, config, filename, ntime, concini)
+      else
+        write(logid,*) 'ERROR init_cini: cannot find file ',filename
+        stop
+      endif
     endif
 
     ! calculate contribution of initial concentration to receptor
+    ! index time dimension of concini
+    startmonth = (jjjjmmdd/100)*100 + 1
+    nhours = int((jdi - juldate(startmonth, 0))*24d0)
+    nt = nhours/hfreq + 1
+    print*, 'init_cini: startmonth = ',startmonth
+    print*, 'init_cini: nhours = ',nhours
+    print*, 'init_cini: nt = ',nt
     do kz = 1, nzgrid
+      nz = 0
+      do while(.true.)
+        nz = nz + 1
+        if ( outheight(kz).lt.cini_alt(nz) ) exit
+      end do
       do jy = 1, nygrid
         n = 0
         do while(.true.)
           n = n + 1
           if ( gbl_lat(jy).lt.cini_lat(n) ) exit
         end do
-!        print*, 'init_cini: gbl_lat(jy), n = ',gbl_lat(jy), n
         do ix = 1, nxgrid
-          ! interpolate between concentrations
-          if( (jdates(i) - trajdays).lt.jdmid ) then
-            conc = preconcini(ix,jy,kz) + (concini(ix,jy,kz) - preconcini(ix,jy,kz)) * &
-                     real((jdates(i) - trajdays) - jdpre, kind=4)/30.
-          else
-            conc = concini(ix,jy,kz) + (proconcini(ix,jy,kz) - concini(ix,jy,kz)) * &
-                     real((jdates(i) - trajdays) - jdmid, kind=4)/30.
-          endif
-          cini(i,n) = cini(i,n) + gridini(ix,jy,kz)*conc
+          cini(i,(nz-1)*nycini+n) = cini(i,(nz-1)*nycini+n) + gridini(ix,jy,kz)*concini(ix,jy,kz,nt)
         end do
       end do
     end do
 
 10  continue
 
-    lastjjjjmm = jjjjmm
-    prevmonth = month
+    lasttime = jjjjmm
 
   end do
 
@@ -303,6 +281,8 @@ subroutine init_cini(files, config, obs)
     obs%cini(ind(i),:) = cini(i,:)
   end do
 
+  if (allocated( concini )) deallocate( concini )
+
 end subroutine init_cini
 
 
diff --git a/source/init_cini_month.f90 b/source/init_cini_month.f90
new file mode 100644
index 0000000..d709da6
--- /dev/null
+++ b/source/init_cini_month.f90
@@ -0,0 +1,346 @@
+!---------------------------------------------------------------------------------------
+! FLEXINVERT: init_cini_month
+!---------------------------------------------------------------------------------------
+!  FLEXINVERT is free software: you can redistribute it and/or modify
+!  it under the terms of the GNU General Public License as published by
+!  the Free Software Foundation, either version 3 of the License, or
+!  (at your option) any later version.
+!
+!  FLEXINVERT is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU General Public License for more details.
+!
+!  You should have received a copy of the GNU General Public License
+!  along with FLEXINVERT.  If not, see <http://www.gnu.org/licenses/>.
+!
+!  Copyright 2017, Rona Thompson
+!---------------------------------------------------------------------------------------
+!
+!> init_cini_month
+!!
+!! Purpose:    Calculates the initial concentration for each observation using the
+!!             4D initial concentration fields and the flexpart grid_initial files.
+!!
+!! Interface:
+!!
+!!    Inputs
+!!             files   -  file data structure
+!!             config  -  configuration settings data structure
+!!             obs     -  observation data structure 
+!!
+!!    Externals
+!!             caldate
+!!             read_init              
+!!             get_initconc
+!!
+!---------------------------------------------------------------------------------------
+
+subroutine init_cini_month(files, config, obs)
+
+  use mod_flexpart
+  use mod_settings
+  use mod_strings
+  use mod_var
+  use mod_dates
+  use mod_obs
+  use mod_tools
+
+  implicit none
+
+  type (files_t),        intent (in)     :: files
+  type (config_t),       intent (in)     :: config
+  type (obs_t),          intent (in out) :: obs
+
+  character(max_path_len)                :: path_flexrec, filename, pathname
+  character(max_name_len)                :: varname
+  character(len=8)                       :: adate, areldate, areltime
+  character(len=6)                       :: ayear
+  logical                                :: lexist
+  integer                                :: lastjjjjmm, prejjjjmm, projjjjmm
+  integer                                :: jjjjmm, jjjjmmdd, hhmiss, mm, eomday
+  integer                                :: ix, jy, kz, i, n, nz, ntime
+  integer                                :: month, prevmonth
+  real                                   :: conc
+  real(kind=8)                           :: jdmid, jdpre, jdlast
+  real(kind=8), dimension(nobs)          :: jdates
+  real, dimension(nobs,ncini)            :: cini
+  integer, dimension(nobs)               :: ind
+  real, dimension(nxgrid,nygrid,nzgrid)  :: gridini, gridini_tmp
+  real, dimension(nxgrid,nygrid,nzgrid,1):: concini, preconcini, proconcini
+
+  real                                   :: bndx, bndy, delx, dely
+  integer                                :: numx, numy, xshift
+  integer                                :: numpoint, release_nr, nr_init
+  integer                                :: ibdate, ibtime
+  real(kind=8), dimension(maxpoint,2)    :: releases
+  integer                                :: nretr, ierr
+  character(len=6)                       :: anretr
+
+  ! loop over observations
+  ! ----------------------
+
+  lastjjjjmm = 0
+  concini(:,:,:,:) = 0.
+  preconcini(:,:,:,:) = 0.
+  proconcini(:,:,:,:) = 0.
+  cini(:,:) = 0.
+  prevmonth = 0
+  ntime = 1
+
+  ! sort obs chronologically for efficiency
+  jdates = obs%jdate(:)
+  call sort(nobs,jdates,ind)
+
+  do i = 1, nobs
+
+    ! reset values
+    gridini(:,:,:) = 0.
+    nr_init = 0
+
+    ! check month of observation
+    call caldate(jdates(i), jjjjmmdd, hhmiss)
+    write(adate,'(I6.6)') jjjjmmdd/100
+    write(areldate,'(I8.8)') jjjjmmdd
+    month = jjjjmmdd/100
+    path_flexrec = trim(files%path_flexpart)//trim(obs%recs(ind(i)))//'/'//trim(adate)//'/'
+
+    if ( config%average_fp ) then
+
+      ! match and, if needed, average grid_initial files to observation timestamp
+
+      ! get header and release information related to current observation location 
+      ! (if not already read and same for previous observation)
+      filename = trim(path_flexrec)//'header'
+      if ( i.eq.1 .or. month.ne.prevmonth ) then
+        write(logid,*) 'Get header:', i, ' '//trim(path_flexrec)//'header'
+        call read_header(filename, numpoint, ibdate, ibtime, releases, &
+                           numx, numy, bndx, bndy, delx, dely, xshift)
+      else
+        if(trim(obs%recs(ind(i))).ne.trim(obs%recs(ind(i-1))))then
+          write(logid,*) 'Get header:', i, ' '//trim(path_flexrec)//'header'
+          call read_header(filename, numpoint, ibdate, ibtime, releases, &
+                             numx, numy, bndx, bndy, delx, dely, xshift)
+        endif
+      endif
+      ! find the first release number corresponding to the current observation
+      release_nr=1
+      do while ( int(releases(release_nr,1)*1.e4,kind=8).lt.int(jdates(i)*1.e4,kind=8) .and. release_nr.lt.numpoint )
+        release_nr = release_nr+1
+      end do
+      ! define first filename
+      call caldate(releases(release_nr,1), jjjjmmdd, hhmiss)
+      ! round seconds
+      hhmiss = (hhmiss/100)*100
+      write(areldate,'(I8.8)') jjjjmmdd
+      write(areltime,'(I6.6)') hhmiss
+      filename = trim(path_flexrec)//'grid_initial_'//trim(areldate)//trim(areltime)//'_001'
+      ! read first flexpart grid_init files
+      inquire ( file=trim(filename), exist=lexist )
+      if ( lexist ) then
+        call read_init(filename, gridini_tmp)
+        gridini = gridini + gridini_tmp
+        nr_init = 1
+        ! current release_nr was already read, start with next
+        release_nr = release_nr + 1
+        do while ( int(releases(release_nr,2)*1.e4,kind=8).le.int((jdates(i)+obs%avetime(ind(i)))*1.e4,kind=8) .and. release_nr.lt.numpoint )
+          call caldate(releases(release_nr,1), jjjjmmdd, hhmiss)
+          write(adate,'(I6.6)') jjjjmmdd/100
+          write(areldate,'(I8.8)') jjjjmmdd
+          hhmiss=int(hhmiss/100)*100
+          write(areltime,'(I6.6)') hhmiss
+          path_flexrec = trim(files%path_flexpart)//trim(obs%recs(ind(i)))//'/'//trim(adate)//'/'
+          filename = trim(path_flexrec)//'grid_initial_'//trim(areldate)//trim(areltime)//'_001'
+          ! sum the grid with previous initial grids
+          call read_init(filename, gridini_tmp)
+          gridini = gridini + gridini_tmp
+          release_nr = release_nr+1
+          nr_init = nr_init + 1
+        end do ! finished summing grid_initial
+        ! convert from ppt to fraction of one
+        gridini = gridini*1.e-12
+        gridini = gridini/real(nr_init)
+      else
+        ! filename not found 
+        write(logid,*) 'WARNING: cannot find '//trim(filename)
+        go to 10
+      endif
+
+    else
+
+      ! timestamps of grid_init files match observations
+
+      ! define file name
+      write(areldate,'(I8.8)') jjjjmmdd
+      write(areltime,'(I6.6)') hhmiss
+      filename = trim(path_flexrec)//'grid_initial_'//trim(areldate)//trim(areltime)//'_001'
+      print*, 'init_cini_month: filename = ',filename
+      ! read flexpart grid_init file
+      inquire(file=trim(filename),exist=lexist)
+      if(lexist) then
+        call read_init(filename, gridini)
+        ! convert from ppt to fraction of one
+        gridini = gridini*1.e-12
+      else
+        write(logid,*) 'WARNING: cannot find ',filename
+        go to 10
+      endif
+
+    endif 
+
+    ! calculate termination time of trajectory
+    call caldate(jdates(i) - trajdays, jjjjmmdd, hhmiss)
+    jjjjmm = jjjjmmdd/100
+   
+    ! preceding and proceding months
+    mm = jjjjmm - (jjjjmm/100)*100
+    if( mm.gt.1 ) then
+      prejjjjmm = jjjjmm - 1
+    else
+      prejjjjmm = (jjjjmm/100 - 1)*100 + 12
+    endif
+    if( mm.lt.12 ) then
+      projjjjmm = jjjjmm + 1
+    else
+      projjjjmm = (jjjjmm/100 + 1)*100 + 1
+    endif
+
+    jdmid = juldate(jjjjmm*100+14, 0)
+    jdpre = juldate(prejjjjmm*100+14, 0)
+    jdlast = juldate(lastjjjjmm*100+14, 0) 
+    eomday = calceomday(prejjjjmm)
+
+    ! get new concentrations if not same month as previous observation 
+    if( jjjjmm.ne.lastjjjjmm ) then
+      if( (lastjjjjmm.ne.0).and.(jdmid.eq.(jdlast+dble(eomday))) ) then
+        ! this is proceeding month
+        preconcini = concini
+        concini = proconcini
+        ! get proceeding concentration field
+        write(adate,'(I6.6)') projjjjmm
+        write(ayear,'(I4.4)') projjjjmm/100
+        select case ( files%init_type )
+          case (4)
+            pathname = str_replace(files%path_initconc, 'YYYY', ayear)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)
+            filename = trim(pathname)//trim(filename)
+          case (5)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)  
+            filename = trim(files%path_initconc)//trim(filename)
+        end select
+        inquire(file=trim(filename),exist=lexist)
+        if(lexist) then
+          varname = files%varname_init
+          call get_initconc(files, config, filename, ntime, proconcini)
+        else
+          write(logid,*) 'WARNING: cannot find ',filename
+          write(logid,*) 'WARNING: next background file missing, copy present into next to avoid 0 value'
+          proconcini = concini
+        endif
+      else 
+        ! get current concentration field
+        write(adate,'(I6.6)') jjjjmm
+        write(ayear,'(I4.4)') jjjjmm/100
+        select case ( files%init_type )
+          case (4)
+            pathname = str_replace(files%path_initconc, 'YYYY', ayear)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)
+            filename = trim(pathname)//trim(filename)
+          case (5)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)
+            filename = trim(files%path_initconc)//trim(filename)
+        end select
+        inquire(file=trim(filename),exist=lexist)
+        if(lexist) then
+          varname = files%varname_init
+          call get_initconc(files, config, filename, ntime, concini)
+        else
+          write(logid,*) 'WARNING: cannot find ',filename
+          go to 10
+        endif
+        ! get previous concentration field
+        write(adate,'(I6.6)') prejjjjmm
+        write(ayear,'(I4.4)') prejjjjmm/100
+        select case ( files%init_type )
+          case (4)
+            pathname = str_replace(files%path_initconc, 'YYYY', ayear)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)
+            filename = trim(pathname)//trim(filename)
+          case (5)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)
+            filename = trim(files%path_initconc)//trim(filename)
+        end select
+        inquire(file=trim(filename),exist=lexist)
+        if(lexist) then
+          varname = files%varname_init
+          call get_initconc(files, config, filename, ntime, preconcini)
+        else
+          write(logid,*) 'WARNING: cannot find ',filename
+          go to 10
+        endif
+        ! get next concentration field
+        write(adate,'(I6.6)') projjjjmm
+        write(ayear,'(I4.4)') projjjjmm/100
+        select case ( files%init_type )
+          case (4)
+            pathname = str_replace(files%path_initconc, 'YYYY', ayear)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)
+            filename = trim(pathname)//trim(filename)
+          case (5)
+            filename = str_replace(files%file_initconc, 'YYYYMM', adate)
+            filename = trim(files%path_initconc)//trim(filename)
+        end select
+        inquire(file=trim(filename),exist=lexist)
+        if(lexist) then
+          varname = files%varname_init
+          call get_initconc(files, config, filename, ntime, proconcini)
+        else
+          write(logid,*) 'WARNING: cannot find ',filename
+          write(logid,*) 'WARNING: next background file missing, copy present into next to avoid 0 value'
+          proconcini = concini
+        endif
+      endif   
+    endif
+
+    ! calculate contribution of initial concentration to receptor
+    do kz = 1, nzgrid
+      nz = 0
+      do while(.true.)
+        nz = nz + 1
+        if ( outheight(kz).lt.cini_alt(nz) ) exit
+      end do
+      do jy = 1, nygrid
+        n = 0
+        do while(.true.)
+          n = n + 1
+          if ( gbl_lat(jy).lt.cini_lat(n) ) exit
+        end do
+        do ix = 1, nxgrid
+          ! interpolate between concentrations
+          if( (jdates(i) - trajdays).lt.jdmid ) then
+            conc = preconcini(ix,jy,kz,1) + (concini(ix,jy,kz,1) - preconcini(ix,jy,kz,1)) * &
+                     real((jdates(i) - trajdays) - jdpre, kind=4)/30.
+          else
+            conc = concini(ix,jy,kz,1) + (proconcini(ix,jy,kz,1) - concini(ix,jy,kz,1)) * &
+                     real((jdates(i) - trajdays) - jdmid, kind=4)/30.
+          endif
+          cini(i,(nz-1)*nycini+n) = cini(i,(nz-1)*nycini+n) + gridini(ix,jy,kz)*conc
+        end do
+      end do
+    end do
+
+10  continue
+
+    lastjjjjmm = jjjjmm
+    prevmonth = month
+
+  end do
+
+  ! reorder cini for observations
+  do i = 1, nobs
+    obs%cini(ind(i),:) = cini(i,:)
+  end do
+
+end subroutine init_cini_month
+
+
diff --git a/source/init_co2.f90 b/source/init_co2.f90
index 34aa406..987645b 100644
--- a/source/init_co2.f90
+++ b/source/init_co2.f90
@@ -686,9 +686,11 @@ subroutine init_co2(files, config, fluxes, obs, states, covar)
   ! initial concentrations from termination of trajectories
   ! only do for a fresh run
   if ( config%restart.eq.0 ) then
-    call init_cini(files, config, obs)
-!    call init_cams(files, config, obs)
-!    call init_fpctm_hour(files, config, obs)
+    if ( files%init_type.lt.5 ) then
+      call init_cini(files, config, obs)
+    else
+      call init_cini_month(files, config, obs)
+    endif
   endif
     
   ! add random perturbation for MC
diff --git a/source/init_ghg.f90 b/source/init_ghg.f90
index 7071bde..c652bbb 100644
--- a/source/init_ghg.f90
+++ b/source/init_ghg.f90
@@ -101,6 +101,7 @@ subroutine init_ghg(files, config, fluxes, obs, states, covar)
 
   call alloc_fluxes(config, fluxes)
   fluxes%flx(:,:,:) = 0.
+  fluxes%flxocn(:,:,:) = 0.
 
   ! loop over prior flux files
 
@@ -303,11 +304,6 @@ subroutine init_ghg(files, config, fluxes, obs, states, covar)
 
   if ( config%lognormal ) then
     ! lognormal distribution 
-!    ! replace values <= 0 with smallnum since need to transform to log
-!    do n = 1, ntstate
-!      where( flx_box(:,n).lt.smallnum ) flx_box(:,n) = smallnum
-!      states%px0((n-1)*nbox+1:n*nbox) = flx_box(:,n)
-!    end do
     ! optimize scalar z = ln(x/xb) 
     ! prior state vector z is zero
     states%px0(1:npvar) = 0.
@@ -320,18 +316,12 @@ subroutine init_ghg(files, config, fluxes, obs, states, covar)
   ! assign prior initial mixing ratio scalars
   if ( config%opt_cini ) then
     if ( config%lognormal ) then
-!      states%px0(npvar+1:nvar) = 1.
       states%px0(npvar+1:nvar) = 0.
     else
       states%px0(npvar+1:nvar) = 1.
     endif
   endif
 
-  ! lognormal transform to log
-!  if ( config%lognormal ) then
-!    states%px0(:) = log(states%px0)
-!  endif
-
   ! time stamp of flux variables
   states%xtime(:) = fluxes%time
 
@@ -343,10 +333,6 @@ subroutine init_ghg(files, config, fluxes, obs, states, covar)
 
   if ( config%lognormal ) then
     ! lognormal 
-!    ! errors are for log transformed state variables 
-!    xerr = sum(flx_box(:,:),dim=2)/real(ntstate)
-!    xerr = log(xerr)
-!    xerr = config%flxerr*xerr
     ! uncertainty of a scalar of fluxes -> use constant uncertainty
     xerr(:) = config%flxerr
   else
@@ -410,9 +396,13 @@ subroutine init_ghg(files, config, fluxes, obs, states, covar)
   ! initial concentrations from termination of trajectories
   ! only do for a fresh run
   if ( config%restart.eq.0 ) then
-!    call init_cams(files, config, obs)
-    call init_cini(files, config, obs)
-!    call init_fpctm(files, config, obs)
+    if ( files%init_type.lt.5 ) then
+      ! daily or higher frequency
+      call init_cini(files, config, obs)
+    else
+      ! monthly frequency
+      call init_cini_month(files, config, obs)
+    endif
   endif
 
   ! add random perturbation for MC
diff --git a/source/initialize.f90 b/source/initialize.f90
index 5f682a5..39e640d 100644
--- a/source/initialize.f90
+++ b/source/initialize.f90
@@ -212,31 +212,20 @@ subroutine initialize(files, config)
     ! statres is time interval over which state variables are averaged
     ! statres_hr is the sub-daily time interval for state variables
     ! ndt is number of time steps per 24h in prior NEE
-    ! flxtres is temporal resolution of low frequency fluxes (biomass burning and ocean)
     ! ntflx is number of time steps of low frequency fluxes
     ! ntstate is number of averaged time invervals for state variables
     statres = config%statres
     statres_hr = config%statres_hr
     ndt = int(24./statres_hr)
-!    flxtres = aint(365./real(config%nt_flx))
-!    ntflx =  nint(real(nday)/flxtres)
-!    ntstate = nint(real(nday)/statres)
     ntstate = int(floor(real(nday)/statres))
   else
     ! statres is time resolution of state variables
-    ! flxtres is temporal resolution of fluxes (same as state variables for non-CO2 tracers)
     ! ntflx is number of state time invervals
     ! ntstate is also number of state time invervals 
     statres = config%statres
-!    flxtres = config%statres
-!    ntflx = nint(real(nday)/statres)
     ntstate = nint(real(nday)/statres)
     ndt = 1
   endif
-!  if ( ntflx.lt.1 ) then
-!    write(logid,*) 'ERROR initialize: number flux time steps < 1 -> increase time interval'
-!    stop
-!  endif
   if ( ntstate.lt.1 ) then
     write(logid,*) 'ERROR initialize: state time steps < 1 -> increase time interval'
     stop
@@ -323,12 +312,14 @@ subroutine initialize(files, config)
   ! -----------------------
 
   maxiter = config%maxiter
+  ncini = nycini*nzcini
+
+  ! write info to log file
+  ! ----------------------
 
   write(logid,*) 'nday: ',nday
   write(logid,*) 'statres: ',statres
-!  write(logid,*) 'flxtres: ',flxtres
   write(logid,*) 'ntstate: ',ntstate
-!  write(logid,*) 'ntflx: ',ntflx
   if ( trim(config%spec).eq.'co2' ) then
     write(logid,*) 'nd_nee: ',nd_nee
     write(logid,*) 'ndt: ',ndt
diff --git a/source/interpz.f90 b/source/interpz.f90
index cbb7add..52bdfb2 100644
--- a/source/interpz.f90
+++ b/source/interpz.f90
@@ -24,50 +24,106 @@
 !! Interface:
 !!
 !!    Inputs
+!!             nx      -  number of grid cells longitude
+!!             ny      -  number of grid cells latitude
 !!             nz      -  number of vertical layers in input
-!!             geoh    -  geopotential heights of layers in input
+!!             zkind   -  indicator of height reference (0 = sea level, 1 = ground level) 
+!!             geoh    -  geopotential height mid-layer in input (metres above sea level)
 !!             gridin  -  input data
 !!             gridout -  output data (zero array on input)
 !!
+!!    Note:    outheight is for top of layers in metres above surface so need to adjust
+!!             to metres above sea level using orography
+!!
 !---------------------------------------------------------------------------------------
 
-subroutine interpz(nz, geoh, gridin, gridout)
+subroutine interpz(nx, ny, nz, zkind, midpoints, lon, lat, geoh, gridin, gridout)
 
   use mod_var
 
   implicit none
 
-  integer,                               intent(in)     :: nz
-  real, dimension(nz),                   intent(in)     :: geoh
-  real, dimension(nxgrid,nygrid,nz),     intent(in)     :: gridin
-  real, dimension(nxgrid,nygrid,nzgrid), intent(in out) :: gridout
+  integer,                       intent(in)     :: nx, ny, nz, zkind
+  logical,                       intent(in)     :: midpoints
+  real, dimension(nx),           intent(in)     :: lon
+  real, dimension(ny),           intent(in)     :: lat
+  real, dimension(nx,ny,nz),     intent(in)     :: geoh
+  real, dimension(nx,ny,nz),     intent(in)     :: gridin
+  real, dimension(nx,ny,nzgrid), intent(in out) :: gridout
+
+  integer                                       :: ix, jy, kz
+  integer                                       :: nn, ii, jj
+  real                                          :: hadj, dz1, dz2, ddx, ddy
+  real, dimension(nzgrid)                       :: halfh
+  !*** TESTING
+!  real, dimension(nx,ny,nzgrid)                 :: htest
 
-  integer                                               :: ix, jy, kz
-  integer                                               :: z, z1, z2
-  real                                                  :: ht
+  do nn = 1, nzgrid
+    if ( nn.eq.1 ) then
+      halfh(nn) = 0.5*outheight(nn)
+    else 
+      halfh(nn) = 0.5*(outheight(nn-1) + outheight(nn))
+    endif
+  end do
+!  print*, 'outheight = ',outheight
+!  print*, 'halfh = ',halfh
 
-  do kz = 1, nzgrid
-    do jy = 1, nygrid
-      do ix = 1, nxgrid     
-        ht = outheight(kz)
-        z = minloc(abs(geoh(:)-ht),dim=1,mask=abs(geoh(:)-ht).eq.minval(abs(geoh(:)-ht)))
-        if( geoh(z).lt.ht ) then
-          z1 = z
-          z2 = min(z+1,nz)
+  ! flexpart coordinates are western and southern boundary
+  if ( midpoints ) then
+    ddy = dy/2.
+    ddx = dx/2.
+  else 
+    ddy = 0.
+    ddx = 0.
+  endif
+!  print*, 'ddx, ddy = ',ddx,ddy
+     
+  do jy = 1, ny
+    jj = minloc(gbl_lat,dim=1,mask=abs(gbl_lat+ddy-lat(jy)).eq.minval(abs(gbl_lat+ddy-lat(jy))))
+    do ix = 1, nx     
+      ii = minloc(gbl_lon,dim=1,mask=abs(gbl_lon+ddx-lon(ix)).eq.minval(abs(gbl_lon+ddx-lon(ix))))
+      if ( zkind.eq.0 ) then
+        ! input is relative to sea level
+        hadj = max(orog(ii,jj),0.)
+      else
+        ! input is relative to ground level
+        hadj = 0.
+      endif
+!      if (jy.eq.ny/2.and.ix.eq.nx/2) print*, 'gbl_lat, lat, gbl_lon, lon = ',gbl_lat(jj), lat(jy), gbl_lon(ii), lon(ix)
+!      if (jy.eq.ny/2.and.ix.eq.nx/2) print*, 'hadj = ',hadj
+      do nn = 1, nzgrid
+        !*** TESTING 
+ !       htest(ix,jy,nn) = halfh(nn)+hadj
+        do kz = 1, nz
+          if ( geoh(ix,jy,kz).gt.(halfh(nn)+hadj) ) exit
+        end do
+!        if(jy.eq.ny/2.and.ix.eq.nx/2) print*, 'kz, halfh(nn)+hadj, geoh(kz) = ',kz, halfh(nn)+hadj, geoh(ix,jy,kz)
+        if ( kz.gt.nz ) then
+          gridout(ix,jy,nn) = gridin(ix,jy,nz)  
+        else if ( kz.gt.1 ) then
+          dz1 = (halfh(nn) + hadj) - geoh(ix,jy,kz-1) 
+          dz2 = geoh(ix,jy,kz) - (halfh(nn) + hadj)
+          gridout(ix,jy,nn) = (gridin(ix,jy,kz-1)*dz2+gridin(ix,jy,kz)*dz1)/(dz1+dz2)
+ !         if (jy.eq.ny/2.and.ix.eq.nx/2) print*, 'w1, w2 = ',dz1/(dz1+dz2), dz2/(dz1+dz2)
         else
-          z1 = max(z-1,1)
-          z2 = z  
-        endif
-        if( z1.eq.z2 ) then
-          gridout(ix,jy,kz) = gridin(ix,jy,z)
-        else  
-          gridout(ix,jy,kz) = gridin(ix,jy,z1)+(gridin(ix,jy,z2)-gridin(ix,jy,z1)) * &
-                              (ht-geoh(z1))/(geoh(z2)-geoh(z1))
-        endif
+          gridout(ix,jy,nn) = gridin(ix,jy,kz)
+        endif 
       end do
     end do
   end do
 
+  !*** TESTING
+!  open(200,file='conc_profile_in.txt',action='write',status='replace')
+!  do nn = 1, nz
+!    write(200,fmt='(F8.2,1X,F8.2)') geoh(ix/2,jy/2,nn), gridin(ix/2,jy/2,nn)
+!  end do
+!  close(200)
+!  open(200,file='conc_profile_out.txt',action='write',status='replace')
+!  do nn = 1, nzgrid
+!    write(200,fmt='(F8.2,1X,F8.2)') htest(ix/2,jy/2,nn), gridout(ix/2,jy/2,nn)
+!  end do
+!  close(200)
+
 end subroutine interpz
 
 
diff --git a/source/main.f90 b/source/main.f90
index 640bd6c..232cca8 100644
--- a/source/main.f90
+++ b/source/main.f90
@@ -75,6 +75,9 @@ program main
   ! initialize parameters
   call initialize(files, config)
 
+  ! read orography
+  call read_orog(files)
+
   ! read land-sea mask 
   call read_lsm(files)
 
diff --git a/source/makefile b/source/makefile
index 103ee50..9e9e29f 100644
--- a/source/makefile
+++ b/source/makefile
@@ -32,17 +32,13 @@ SRCS =    mod_var.f90 \
           correl.f90 \
           error_cov.f90 \
           read_lsm.f90 \
+          read_orog.f90 \
           mod_regions.f90 \
           interpz.f90 \
           convertgrid.f90 \
           get_initconc.f90 \
-          get_initfpctm.f90 \
-          get_initfpctm_hour.f90 \
-          get_initcams.f90 \
           init_cini.f90 \
-          init_fpctm.f90 \
-          init_fpctm_hour.f90 \
-          init_cams.f90 \
+          init_cini_month.f90 \
           init_co2.f90 \
           init_ghg.f90 \
           calc_conc.f90 \
diff --git a/source/mod_perturb.f90 b/source/mod_perturb.f90
index 23beee3..f454b27 100644
--- a/source/mod_perturb.f90
+++ b/source/mod_perturb.f90
@@ -98,7 +98,6 @@ module mod_perturb
     ! add perturbation to state vector 
     if ( config%lognormal ) then
       ! lognormal
-!      states%px0(:) = states%px0(:) * exp(real(perturb(:),kind=4))
       states%px0(:) = exp(real(perturb(:),kind=4))
     else
       ! normal
diff --git a/source/mod_save.f90 b/source/mod_save.f90
index f905a85..f2298c1 100644
--- a/source/mod_save.f90
+++ b/source/mod_save.f90
@@ -465,56 +465,44 @@ module mod_save
           endif
           ! if inc_ocean is true state vector includes all fluxes, if false need to add ocean fluxes
           if ( nbox_xy(ix,jy).gt.0 ) then
-            ! regrid flux increments according to prior flux distribution and add prior flux
-            if ( fluxes%flx_box(nbox_xy(ix,jy),n,1).gt.smallnum ) then
-              if ( config%nested ) then
-                if ( config%lognormal ) then
-!                  ! lognormal distribution: optimize fluxes not offsets
-!                  fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) *  &
-!                                  fluxes%flx_nest(ix,jy,n)/fluxes%flx_box(nbox_xy(ix,jy),n,1)/numscale
-!                 ! optimize scalars of fluxes
-                  fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) * fluxes%flx_nest(ix,jy,n)/numscale
-                else
-                  ! normal distribution: optimize offsets
+            if ( config%nested ) then
+              ! nested domain
+              if ( config%lognormal ) then
+                ! lognormal: optimize scalars of fluxes
+                fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) * fluxes%flx_nest(ix,jy,n)/numscale
+              else
+                ! normal distribution: optimize offsets
+                if ( fluxes%flx_box(nbox_xy(ix,jy),n,1).gt.smallnum ) then
+                  ! regrid flux increments according to prior flux distribution and add prior flux
                   fpos(ix,jy,n) = states%px((n-1)*nbox+nbox_xy(ix,jy)) *  &
                                   fluxes%flx_nest(ix,jy,n)/fluxes%flx_box(nbox_xy(ix,jy),n,1)/numscale + &
                                   fpri(ix,jy,n)
+                else
+                  ! prior in box very small so no redistribution
+                  fpos(ix,jy,n) = states%px((n-1)*nbox+nbox_xy(ix,jy))/numscale + fpri(ix,jy,n)
                 endif
+              endif ! normal/lognormal
+            else
+              ! no nested domain
+              if ( config%lognormal ) then
+                ! lognormal: optimize scalars of fluxes
+                fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) * fluxes%flx(ix0+ix-1,jy0+jy-1,n)/numscale
               else
-                if ( config%lognormal ) then
-                  ! lognormal distribution: optimize fluxes not offsets
-!                  fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) *  &
-!                                  fluxes%flx(ix0+ix-1,jy0+jy-1,n)/fluxes%flx_box(nbox_xy(ix,jy),n,1)/numscale
-!                 ! optimize scalars of fluxes
-                  fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) * fluxes%flx(ix0+ix-1,jy0+jy-1,n)/numscale
-                else
-                  ! normal distribution: optimize offsets
+                ! normal distribution: optimize offsets
+                if ( fluxes%flx_box(nbox_xy(ix,jy),n,1).gt.smallnum ) then
+                  ! regrid flux increments according to prior flux distribution and add prior flux
                   fpos(ix,jy,n) = states%px((n-1)*nbox+nbox_xy(ix,jy)) *  &
                                   fluxes%flx(ix0+ix-1,jy0+jy-1,n)/fluxes%flx_box(nbox_xy(ix,jy),n,1)/numscale + &
                                   fpri(ix,jy,n)
-                endif
-              endif
-            else
-              if ( config%lognormal ) then
-!                ! lognormal distribution: optimize fluxes not offsets
-!                fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy)))/numscale
-!                 ! optimize scalars of fluxes
-                if ( config%nested ) then
-                  fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) * fluxes%flx_nest(ix,jy,n)/numscale
                 else
-                  fpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy))) * fluxes%flx(ix0+ix-1,jy0+jy-1,n)/numscale
+                  ! prior in box very small so no redistribution
+                  fpos(ix,jy,n) = states%px((n-1)*nbox+nbox_xy(ix,jy))/numscale + fpri(ix,jy,n)
                 endif
-              else
-                ! normal distribution: optimize offsets
-                fpos(ix,jy,n) = states%px((n-1)*nbox+nbox_xy(ix,jy))/numscale + fpri(ix,jy,n)
-              endif
-            endif
+              endif ! normal/lognormal
+            endif ! nested
             ! regrid without adding prior fluxes
             if ( config%lognormal ) then
               ! lognormal distribution
-!              epri(ix,jy,n) = exp(states%pxerr0((n-1)*nbox+nbox_xy(ix,jy)))/numscale
-!              epos(ix,jy,n) = exp(states%pxerr((n-1)*nbox+nbox_xy(ix,jy)))/numscale
-!              xpos(ix,jy,n) = exp(states%px((n-1)*nbox+nbox_xy(ix,jy)))/numscale
               ! errors are for z = ln(x/xb) so errors in x = xb*(exp(err) - 1)
               if ( config%nested ) then
                 epri(ix,jy,n) = fluxes%flx_nest(ix,jy,n)*abs(exp(states%pxerr0((n-1)*nbox+nbox_xy(ix,jy))) - 1.)/numscale
@@ -531,13 +519,13 @@ module mod_save
               xpos(ix,jy,n) = states%px((n-1)*nbox+nbox_xy(ix,jy))/numscale
             endif
           else
-            ! add ocean fluxes if not optimized
+            ! include ocean fluxes if not optimized
             if ( config%nested ) then
               fpos(ix,jy,n) = fluxes%flx_nest(ix,jy,n)/numscale
             else 
               fpos(ix,jy,n) = fluxes%flx(ix0+ix-1,jy0+jy-1,n)/numscale
             endif
-          endif
+          endif ! nbox_xy
         end do
       end do
     end do
diff --git a/source/mod_settings.f90 b/source/mod_settings.f90
index a7942ec..32a996c 100644
--- a/source/mod_settings.f90
+++ b/source/mod_settings.f90
@@ -44,6 +44,10 @@ module mod_settings
     character(len=max_path_len) :: file_bg        ! prior best guess file 
     character(len=max_name_len) :: suffix         ! observation file suffix 
     character(len=max_name_len) :: file_log       ! log file name
+    character(len=max_path_len) :: file_orog      ! orography file name
+    character(len=max_name_len) :: varname_orog   ! orography variable name
+    character(len=max_name_len) :: lonname_orog   ! longitude variable name
+    character(len=max_name_len) :: latname_orog   ! latitude variable name
     character(len=max_path_len) :: file_regions   ! region definitions file
     character(len=max_name_len) :: varname_regs   ! regions variable name
     character(len=max_name_len) :: lonname_regs   ! longitude variable name
@@ -95,6 +99,7 @@ module mod_settings
     character(len=max_path_len) :: path_initconc  ! path to initial concentrations
     character(len=max_name_len) :: file_initconc  ! initial concentrations generic file name
     character(len=max_name_len) :: varname_init   ! initial concentration variable name
+    integer                     :: init_type      ! initial concentration product type
     character(len=max_path_len) :: file_recept    ! receptor list file
 
   end type files_t
@@ -384,6 +389,20 @@ module mod_settings
           call read_content (line, identifier, cc, cn, cl, match)
           if ( match ) files%file_bg = cc
 
+          ! read orography file settings
+          identifier = "file_orog:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) files%file_orog = cc
+          identifier = "varname_orog:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) files%varname_orog = cc
+          identifier = "lonname_orog:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) files%lonname_orog = cc
+          identifier = "latname_orog:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) files%latname_orog = cc
+
           ! read region mask settings
           identifier = "file_regions:"
           call read_content (line, identifier, cc, cn, cl, match)
@@ -558,6 +577,9 @@ module mod_settings
           identifier = "varname_init:"
           call read_content (line, identifier, cc, cn, cl, match)
           if ( match ) files%varname_init = cc
+          identifier = "init_type:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) files%init_type = cn
 
           ! read receptor file settings
           identifier = "file_recept:"
@@ -597,10 +619,11 @@ module mod_settings
       character(len=200), intent(in)   :: filename
       type(config_t), intent(in out)   :: config
 
-      integer            :: ierr
+      integer            :: ierr, n
       character(len=200) :: line, identifier, cc
       real(kind=8)       :: cn
       logical            :: match, cl
+      character(len=max_name_len), dimension(20) :: temp ! temp string vector (arbitrary max of 20)
 
       ! default values for logical variables
       config%average_fp = .false.
@@ -771,6 +794,31 @@ module mod_settings
           call read_content (line, identifier, cc, cn, cl, match)
           if ( match ) config%globerr = real(cn,kind=4)
 
+          ! read initial mixing ratio optimization settings
+          identifier = "cini_lat:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) then
+            call parse_string (cc, ",", temp(:), n)
+            nycini = n
+            allocate ( cini_lat(nycini) )
+            do n = 1, nycini
+              read(temp(n),*) cini_lat(n)
+            enddo
+          endif
+          identifier = "cini_alt:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) then
+            call parse_string (cc, ",", temp(:), n)
+            nzcini = n
+            allocate ( cini_alt(nzcini) )
+            do n = 1, nzcini
+              read(temp(n),*) cini_alt(n)
+            enddo
+          endif
+          identifier = "cinires:"
+          call read_content (line, identifier, cc, cn, cl, match)
+          if ( match ) cinires = real(cn,kind=4)
+
         endif
 
       end do read_loop
diff --git a/source/mod_var.f90 b/source/mod_var.f90
index cbe5f66..62773d8 100644
--- a/source/mod_var.f90
+++ b/source/mod_var.f90
@@ -33,7 +33,7 @@ module mod_var
   integer, parameter :: max_name_len=100         ! max character length of variable names
   integer, parameter :: recname_len=7            ! length of receptor names
   real, parameter    :: numscale=1.e12           ! numeric scaling factor
-  integer, parameter :: maxpoint=1000            ! max number of releases per receptor per month
+  integer, parameter :: maxpoint=10000           ! max number of releases per receptor per month
   integer, parameter :: maxspec=10               ! max number of species in a flexpart run
   integer, parameter :: maxlev=50                ! max number of vertical levels in flexpart output
   real, parameter    :: trunc=1.e-9              ! truncation threshold for eigenvalues of error covariance matrix
@@ -63,6 +63,7 @@ module mod_var
   real               :: dy                       ! latitudinal resolution of flexpart grid
   real, dimension(:), allocatable :: gbl_lon     ! longitudes of flexpart domain
   real, dimension(:), allocatable :: gbl_lat     ! latitudes of flexpart domain
+  real, dimension(:,:), allocatable :: orog      ! orography on flexpart grid 
 
   ! nested domain
   integer            :: nnxgrid                  ! number of longitudinal grid cells
@@ -145,10 +146,13 @@ module mod_var
   integer            :: npvar                     ! number of state variables related to fluxes
   integer            :: ndt                       ! number of state vector time steps per day (for CO2)
   integer            :: ndvar                     ! number of variables per flux time step (for CO2 2*nbox else nbox) 
-  integer, parameter :: ncini=4                   ! number of initial mixing ratio variables to optimize
-  real, parameter, dimension(4) :: cini_lat=(/-30,0,30,90/) ! vector of northern edges of latitude bands for initial mixing ratio optimization 
+  integer            :: ncini                     ! number of initial mixing ratio variables to optimize
+  integer            :: nycini                    ! number of initial mixing ratio variables to optimize in latitudinal direction
+  integer            :: nzcini                    ! number of initial mixing ratio variables to optimize in vertical direction
+  real, dimension(:), allocatable :: cini_lat     ! vector of northern edges of latitude bands for initial mixing ratio optimization 
+  real, dimension(:), allocatable :: cini_alt     ! vector of upper vertical levels for initial mixing ratio optimization 
   integer            :: ntcini                    ! number of initial mixing ratio time steps 
-  integer, parameter :: cinires=28                ! time resolution for initial mixing ratio scalars (days) 
+  integer            :: cinires                   ! time resolution for initial mixing ratio scalars (days) 
   integer            :: neig                      ! number of retained eigenvalues 
   integer            :: lastiter                  ! number of last iteration (if restart is true)
   integer            :: maxiter                   ! max number of iterations for congrad and m1qn3
diff --git a/source/read_orog.f90 b/source/read_orog.f90
new file mode 100644
index 0000000..0a6df66
--- /dev/null
+++ b/source/read_orog.f90
@@ -0,0 +1,109 @@
+!---------------------------------------------------------------------------------------
+! FLEXINVERT: read_orog
+!---------------------------------------------------------------------------------------
+!  FLEXINVERT is free software: you can redistribute it and/or modify
+!  it under the terms of the GNU General Public License as published by
+!  the Free Software Foundation, either version 3 of the License, or
+!  (at your option) any later version.
+!
+!  FLEXINVERT is distributed in the hope that it will be useful,
+!  but WITHOUT ANY WARRANTY; without even the implied warranty of
+!  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+!  GNU General Public License for more details.
+!
+!  You should have received a copy of the GNU General Public License
+!  along with FLEXINVERT.  If not, see <http://www.gnu.org/licenses/>.
+!
+!  Copyright 2017, Rona Thompson
+!---------------------------------------------------------------------------------------
+!
+!> read_orog
+!!
+!! Purpose:    Reads the orography data from file.
+!!
+!---------------------------------------------------------------------------------------
+
+subroutine read_orog(files)
+
+  use mod_var
+  use mod_settings
+  use mod_tools,   only : sort
+  use mod_save,    only : check
+  use netcdf
+
+  implicit none
+
+  type (files_t),  intent(in)             :: files
+
+  character(len=max_path_len)             :: filename
+  character(len=max_name_len)             :: varname, lonname, latname
+  logical                                 :: lexist
+  integer                                 :: nlon, nlat
+  integer                                 :: ncid, xid, yid, varid
+  integer                                 :: ierr
+  real, dimension(:), allocatable         :: lon, lat
+  real(kind=8), dimension(:), allocatable :: lono, lato
+  integer, dimension(:), allocatable      :: indx, indy
+
+  filename = files%file_orog
+  varname = files%varname_orog
+  lonname = files%lonname_orog
+  latname = files%latname_orog
+
+  inquire(file=trim(filename),exist=lexist)
+  if (.not.lexist) then
+    write(logid,*) 'ERROR: cannot find '//trim(filename)
+    stop
+  endif
+
+  ! read file
+  ! ---------
+
+  write(logid,*) 'Reading file: '//trim(filename)
+  print*, 'lonname, latname, varname = ',lonname,latname,varname
+
+  call check( nf90_open(trim(filename),nf90_NOWRITE,ncid) )
+  call check( nf90_inq_dimid(ncid,trim(lonname),xid) )
+  call check( nf90_inq_dimid(ncid,trim(latname),yid) )
+  call check( nf90_inquire_dimension(ncid,xid,len=nlon) )
+  call check( nf90_inquire_dimension(ncid,yid,len=nlat) )
+
+  ! check file resolution matches flexpart
+  if ( nlon.ne.nxgrid.or.nlat.ne.nygrid ) then 
+    write(logid,*) 'ERROR read_orog: orography file resolution does not match flexpart'
+    stop
+  endif
+
+  allocate ( lon(nlon) )
+  allocate ( lat(nlat) )
+  allocate ( indx(nlon) )
+  allocate ( indy(nlat) )
+  allocate ( orog(nxgrid,nygrid), stat=ierr )
+  if ( ierr.ne.0 ) stop 'ERROR read_orog: not enough memory'
+
+  call check( nf90_inq_varid(ncid,trim(lonname),varid) )
+  call check( nf90_get_var(ncid,varid,lon) )
+  call check( nf90_inq_varid(ncid,trim(latname),varid) )
+  call check( nf90_get_var(ncid,varid,lat) )
+  call check( nf90_inq_varid(ncid,trim(varname),varid) )
+  call check( nf90_get_var(ncid,varid,orog,start=(/1,1,1/),count=(/nxgrid,nygrid,1/)) )
+  call check( nf90_close(ncid) )
+
+  allocate ( lono(nlon) )
+  allocate ( lato(nlat) )
+  lono = dble(lon)
+  lato = dble(lat)
+  where ( lon.gt.180. ) lon = lon - 360.
+  call sort(nlon, lono, indx)
+  call sort(nlat, lato, indy)
+  orog = orog(indx,indy)
+
+  deallocate(lon)
+  deallocate(lat)
+  deallocate(lono)
+  deallocate(lato)
+  deallocate(indx)
+  deallocate(indy)
+
+end subroutine read_orog
+
diff --git a/source/simulate.f90 b/source/simulate.f90
index b31c016..d6f3ed2 100644
--- a/source/simulate.f90
+++ b/source/simulate.f90
@@ -421,11 +421,6 @@ subroutine simulate(iter, files, config, fluxes, obs, states, grad_o, cost_o)
           hx((ns-1)*nbox+1:ns*nbox) = hx((ns-1)*nbox+1:ns*nbox) + hbox((n-1)*nbox+1:n*nbox)
         end do
       endif
-!      if ( config%lognormal ) then
-!        ! lognormal
-!        ! variable is log transformed
-!        px(:) = exp(px)
-!      endif
 
     endif
     call system_clock(time2, countrate)
@@ -486,6 +481,7 @@ subroutine simulate(iter, files, config, fluxes, obs, states, grad_o, cost_o)
       if ( config%method.eq.'congrad'.or.config%method.eq.'m1qn3' ) then
         if ( config%lognormal ) then
           ! lognormal 
+          ! x = xb*exp(z) where xb = 1
           obs%cinipos(i) = dot_product(obs%cini(i,:), exp(states%px(npvar+(ni-1)*ncini+1:npvar+ni*ncini)))
         else
           ! normal
@@ -533,10 +529,6 @@ subroutine simulate(iter, files, config, fluxes, obs, states, grad_o, cost_o)
         if ( istateuni(n).gt.0 ) then 
           if ( config%lognormal ) then
             ! lognormal
-!            ! Jo'(p) = diag(exp(p))H^TR^-1(H(exp(p)) - y)
-!            ! calculate as: Jo'(p) = sum( exp(p)*H_i^T*ydel_i*R_i ) (note here px = exp(p))
-!            grad_o((istateuni(n)-1)*ndvar+1:istateuni(n)*ndvar) = grad_o((istateuni(n)-1)*ndvar+1:istateuni(n)*ndvar) + &
-!                                                                    px((n-1)*ndvar+1:n*ndvar) * hx((n-1)*ndvar+1:n*ndvar) * obs%delta(i) / obs%err(i)**2
             ! Jo'(p) = diag(p0*exp(p))H^TR^-1(H(xb*exp(p)) - y)
             ! calculate as: Jo'(p) = sum( xb*exp(p)*H_i^T*ydel_i*R_i ) (note here px = xb*exp(p))
             grad_o((istateuni(n)-1)*ndvar+1:istateuni(n)*ndvar) = grad_o((istateuni(n)-1)*ndvar+1:istateuni(n)*ndvar) + &
-- 
GitLab