!-------------------------------------- LICENCE BEGIN ------------------------------------
!Environment Canada - Atmospheric Science and Technology License/Disclaimer,
!                     version 3; Last Modified: May 7, 2008.
!This is free but copyrighted software; you can use/redistribute/modify it under the terms
!of the Environment Canada - Atmospheric Science and Technology License/Disclaimer
!version 3 or (at your option) any later version that should be found at:
!http://collaboration.cmc.ec.gc.ca/science/rpn.comm/license.html
!
!This software 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 above mentioned License/Disclaimer for more details.
!You should have received a copy of the License/Disclaimer along with this software;
!if not, you can write to: EC-RPN COMM Group, 2121 TransCanada, suite 500, Dorval (Quebec),
!CANADA, H9P 1J3; or send e-mail to service.rpn@ec.gc.ca
!-------------------------------------- LICENCE END --------------------------------------
!

      subroutine rw_vatra (cfname,status, 4,13
     %     nsim3d,kbrpstamp,zeps1,zdf1,itertot,isimtot,
     %     nztrl,vatra,nmtra,
     %     vazxbar,kvadim,
     %     vazx,ktrunc,kksdim,nvamaj,lxbar,lvazx,k1gc,imode,grd_typ_S)
*
#if defined (DOC)
*
***s/r RW_VATRA  - Read-Write VAZXBAR and VATRA on file
*
*
*Author  : M. Tanguay RPN January 2005
*Revision: S. Pellerin (January 2005)
*          . Dynamical Multi-Inc.: Read and write based on date,
*            working and stored resolutions
*          M. Buehner (May 2008)
*          . Added code for dealing with multiple bands of
*            correlations (corns) - changed some argument names
*            to avoid complict with comdecks
*Revision: M. Tanguay  (December 2007)
*          . Lam4d Limited-Area: Add grd_typ in rw_vatra parameters
*Revision: L. Fillion - ARMA/EC - 12 Jan 2009
*          . Upgrade lam4d to v_10_1_2.
*
*Arguments
*     i   cfname    : precon file
*     i   status    : = 0 if READ, = 1 if WRITE
*     i   nsim3d    : Number of simulations in N1QN3
*     io  kbrpstamp : Date
*     i   zeps1     : Parameter in N1QN3
*     i   zdf1      : Parameter in N1QN3
*     i   itertot   : Parameter in N1QN3
*     i   isimtot   : Parameter in N1QN3
*     i   nztrl     : Localisation parameters for Hessian
*     i   vatra     : Hessian
*     i   nmtra     : Size of Hessian
*     i   vazxbar   : Vazx of previous loop
*     i   kvadim    : Dimension of vazxbar
*     i   vazx      : Current state of the minimization
*     i   ktrunc    : truncation of working resolution
*     i   kksdim    : nvar3d*nlev + nvar2d of working field
*     i   nvamaj    : nomber of updates in Hessian
*     i   lxbar     : read in vaxzbar if dates are compatible
*     i   lvazx     : Logical to read vazx
*     i   k1gc      : Minimizer ID (2: m1qn2, 3: m1qn3, 4: m1gc)
*     o   imode     : If status=0, set imode=0 (no prec) or 2 (prec)
#endif
      IMPLICIT NONE
*
      logical lxbar,lvazx
*
      integer status,kbrpstamp,nsim3d,itertot,isimtot
      integer, dimension(10), target :: nztrl
      integer nmtra, kvadim, ktrunc, kksdim, nvamaj, k1gc, imode
*
      real*8 zeps1,zdf1
*
      real*8, dimension(kvadim), target :: vazxbar, vazx
      real*8, dimension(nmtra), target :: vatra
*
*implicits
#include "comlun.cdk"
#include "pardim.cdk"
#include "comdim.cdk"
*
      integer isize, ibrpstamp,ireslun, ierr, fnom, fclos
      integer, save :: ivadim = 0, imtra = 0, itrlsize = 1, imemo = 1
      integer, save :: itrunc = 0
      integer :: jvadim, i1gc,ictrlvec
      integer, dimension(10), target, save :: iztrl
      integer ilatbin, jlatbin,itemp
      real*8, allocatable, dimension(:), target, save :: zvatra
      real*8, allocatable, dimension(:), target, save :: zvazxbar,zvazx
*
      integer, pointer, dimension(:) :: iptrl
      real*8, pointer, dimension(:) :: pvatra , pvazxbar, pvazx
*
      character(len=128) :: cfname
      character(len=3) :: cl_version
      character*2 grd_typ_S
*
      if(status.eq.0) then
        write(nulout,*) 'Read  VATRA in RW_VATRA'
      elseif(status.eq.1) then
        write(nulout,*) 'Write VATRA in RW_VATRA'
      else
        call abort3d(nulout," RW_VATRA: status not valid ")
      endif

      ireslun=0
*
*     Read Hessian
*     ------------
      if(status.eq.0) then
*
        ierr = fnom(ireslun,cfname,'FTN+SEQ+UNF+OLD+R/O',0)

! Checking version number
        read (ireslun) cl_version,i1gc
        if(trim(cl_version) /= 'V2') then
          call abort3d(nulout," RW_VATRA: invalid Hessian version")
        endif
        if (i1gc == 3 .and. i1gc == k1gc) then
          write(*,*) trim(cl_version),' M1QN3'
        elseif (i1gc == 4 .and. i1gc == k1gc) then
          write(*,*) trim(cl_version),' N1CG1'
        else
          write(*,*) 'Version, n1gc =',trim(cl_version),i1gc
          call abort3d(nulout," RW_VATRA: Inconsistant input hessian")
        endif

        rewind (ireslun)

        read(ireslun) cl_version,k1gc,nsim3d,ibrpstamp,zeps1,zdf1
     &       ,itertot,isimtot,ivadim, itrunc
*
        if(itrunc .ne. ntrunc .and. grd_typ_S.eq.'LU' ) then
          write(nulout,*) 'ITRUNC .NE. NTRUNC when reading HESSIAN when LAM'
          call flush(nulout)
          call abort3d(nulout," ITRUNC .NE. NTRUNC when reading HESSIAN for LAM")
        endif
*
        read(ireslun) imtra,iztrl
        if(.not. allocated(zvatra).and.grd_typ_S.ne.'LU') then
          allocate(zvatra(imtra))
          zvatra = 0.d0
        endif
*        imemo = nvamaj
        imemo = (imtra - 4*ivadim)/(2*ivadim + 1)
        if(k1gc.eq.3) ictrlvec = 2*imemo+1
        if(k1gc.eq.4) ictrlvec = 2*imemo
cBUE
        write(nulout,*) 'PARAMETERS REGARDING VATRA:'
        write(nulout,*) 'k1gc=',k1gc
        write(nulout,*) 'imtra=',imtra
        write(nulout,*) 'ivadim,kvadim=',ivadim,kvadim
        write(nulout,*) 'imemo=',imemo
        write(nulout,*) 'ictrlvec=',ictrlvec
        write(nulout,*) 'nvamaj=',nvamaj
        write(nulout,*) 'nlatbin=',nlatbin
        if(nlatbin.gt.1) then
          itemp=kvadim/ivadim
          if(itemp.eq.nlatbin) then
            write(nulout,*) 'HESSIAN IS FOR ONLY 1 REGION, DUPLICATE FOR EACH REGION'
          elseif(itemp.eq.1) then
            write(nulout,*) 'HESSIAN IS ALREADY FOR CORRECT NUMBER OF REGIONS'
          endif
        endif
cBUE
        if(.not. allocated(zvatra)) allocate(zvatra(imtra))
        zvatra = 0.d0
c
        do jvadim = 1, ictrlvec
          if(grd_typ_S.ne.'LU') then
          read(ireslun) zvatra((jvadim-1)*ivadim+1:jvadim*ivadim)
          else
          read(ireslun)  vatra((jvadim-1)*ivadim+1:jvadim*ivadim)
          endif
        enddo
*
*       Write Residual Hessian (needed when LAM)
*       ----------------------------------------
        if (ictrlvec*ivadim.lt.imtra.and.grd_typ_S.eq.'LU')
     &      read(ireslun)  vatra(ictrlvec*ivadim+1:imtra)
*
        if(k1gc.eq.4) read(ireslun) zvatra(ictrlvec*ivadim+1:ictrlvec
     &       *ivadim+1)
c        if(k1gc.eq.3) read(ireslun) iztrl,zvatra(1:(2*imemo+1)*ivadim  )
c        if(k1gc.eq.4) read(ireslun) iztrl,zvatra(1:(2*imemo)*ivadim+1)
c       read(ireslun) iztrl, zvatra
        imemo = nvamaj ! saved for writing
        if(itrunc .ge. ktrunc) then
          write(nulout,*) 'RW_VATRA : setting vatra'
          if(grd_typ_S.ne.'LU') then
          call setvatra(vatra,nmtra,kvadim,ktrunc,nztrl,zvatra,imtra
     &         ,ivadim,itrunc,iztrl,.false.,kksdim,nvamaj,k1gc,nlatbin)
          else
            nztrl = iztrl
          endif
          imode = 2
        else
          imode = 0
        endif
*
        if(ibrpstamp == kbrpstamp .and. lxbar) then
          if(.not. allocated(zvazxbar)) allocate(zvazxbar(ivadim))
          read(ireslun) zvazxbar
          write(nulout,*) 'RW_VATRA : setting vazxbar'
          if(itrunc .ge. ktrunc) then ! Given res. > working res.
            if(grd_typ_S.ne.'LU') then
            call setvazx(vazxbar,ktrunc,zvazxbar,itrunc,.false.,kksdim,nlatbin)
            else
            vazxbar = zvazxbar
            endif
          else
            vazxbar = 0.d0
            call setvazx(vazxbar,ktrunc,zvazxbar,itrunc,.true.,kksdim,nlatbin)
          endif

          if(lvazx) then
            write(nulout,*) 'RW_VATRA : setting vazx'
            if(.not. allocated(zvazx)) allocate(zvazx(ivadim))
            read(ireslun) zvazx
            if(itrunc .ge. ktrunc) then ! Given res. > working res.
              if(grd_typ_S.ne.'LU') then
              call setvazx(vazx,ktrunc,zvazx,itrunc,.false.,kksdim,nlatbin)
              else
              vazx = zvazx
              endif
            else
              vazx = 0.d0
              call setvazx(vazx,ktrunc,zvazx,itrunc,.true.,kksdim,nlatbin)
            endif
          endif

        else
          kbrpstamp = ibrpstamp
        endif

        ierr = fclos(ireslun)
*
*     Write Hessian
*     -------------
      elseif(status.eq.1) then
        ierr = fnom(ireslun,cfname, 'FTN+SEQ+UNF' , 0)
*
*       if ivadim = 0 then no precon file has been read
        if (ivadim .le. kvadim) then
          if (ivadim == 0) imemo = nvamaj
          ivadim = kvadim
          itrunc = ktrunc
          imtra  = nmtra
          iptrl => nztrl
          pvatra => vatra
          pvazxbar => vazxbar
          pvazx => vazx
        else
          if(.not. allocated(zvatra)) allocate(zvatra(imtra))

          iptrl => iztrl
          pvatra => zvatra
          call setvatra(pvatra,imtra,ivadim,itrunc,iptrl,vatra,nmtra
     &         ,kvadim,ktrunc,nztrl,.true.,kksdim,nvamaj,k1gc,nlatbin)
          if(.not. allocated(zvazxbar)) allocate(zvazxbar(ivadim))
          pvazxbar => zvazxbar
          pvazxbar = 0.d0
          call setvazx(pvazxbar,itrunc,vazxbar,ktrunc,.true.,kksdim,nlatbin)
          if(.not. allocated(zvazx)) allocate(zvazx(ivadim))
          pvazx => zvazx
          pvazx = 0.d0
          call setvazx(pvazx,itrunc,vazx,ktrunc,.true.,kksdim,nlatbin)
        endif
        cl_version = 'V2'
        write(ireslun) cl_version,k1gc,nsim3d,kbrpstamp,zeps1,zdf1,itertot,isimtot
     &       ,ivadim, itrunc
        write(ireslun) imtra,iptrl
c       write(ireslun) iptrl, pvatra
        if(k1gc.eq.3) ictrlvec = 2*imemo+1
        if(k1gc.eq.4) ictrlvec = 2*imemo
        do jvadim = 1, ictrlvec
          write(ireslun) pvatra((jvadim-1)*ivadim+1:jvadim*ivadim)
        enddo
*
*       Write Residual Hessian (needed when LAM)
*       ----------------------------------------
        if (ictrlvec*ivadim.lt.imtra.and.grd_typ_S.eq.'LU') write(ireslun) pvatra(ictrlvec*ivadim+1:imtra)
*
        if(k1gc.eq.4) write(ireslun) pvatra(ictrlvec*ivadim+1:ictrlvec
     &       *ivadim+1)
c        if(k1gc.eq.3)  write(ireslun) iptrl, pvatra(1:(2*imemo+1)*ivadim  )
c        if(k1gc.eq.4)  write(ireslun) iptrl, pvatra(1:(2*imemo)  *ivadim+1)
        write(ireslun) pvazxbar
        write(ireslun) pvazx
        ierr = fclos(ireslun)
      else
        call abort3d(nulout," RW_VATRA: status not valid ")
      endif
*
      return
      end