subroutine nbi_states(filenamefld,filenameptcl,action,irunmode,ierr)

  ! read or write state of NUBEAM calculation.
  ! (dmc Feb 2002: dropped leading "lun" argument).

  ! DMC notes Feb 2009 -- MPI
  !   filenamefld is for CPU#0 only; ignored for myidd > 0
  !   filenameptcl is for CPU#0 only-- optional, test data in an MPI run

  !   irunmode.lt.0 means: ignore filenameptcl

  ! MG  March 2009 -- modified to allow write, backup, retrieve, and delete  
  !   filenameptcl for all CPU.
  !   filenameptcl is actually a suffix for the file name,
  !   which will be generated as:
  !
  !   <workpath>/<runid><filenameptcl><myidd#>_<numprocd#>.cdf 
  !   as a mandatory <filenameptcl>='_nbi_ptcl_state_cpu'
  !   (see default_filename_ptcl.f90)
 


  use nbi_com
  use nbi_mpi_com
  use ezcdf

  implicit NONE

  character*(*), intent(in) :: filenamefld, filenameptcl  ! state filenames
  character*1, intent(in) :: action   ! "s" or "S": save, "r" or "R": restore

  ! "d" or "D" to DELETE state files
  ! "b" or "B" to BACKUP state files: <file> -> <file>_save
  ! "c" or "C" to retrieve prior backup files: <file>_save -> <file>

  integer, intent(out) :: ierr        ! completion code: 0 = OK
  integer, intent(in) :: irunmode

  !---------------------------------------------------

  integer :: icdf                     ! NetCDF channel id
  integer :: iwarn

  character*1 actup
  character*200 zcmd
 
  real    :: vmem, rmem
  logical :: ex
  !---------------------------------------------------

  call nbi_mpi_com_init       ! sets myidd=0 numprocd=1 for serial run

  actup=action
  call uupper(actup)

  ierr=0
  if(actup.eq.'S'.and..not.nltest_output) return
  if(actup.eq.'S') then
     
! save state:  but only if NUBEAM has a state...

     if(nbi_init_flag.and..not.need_read_ptcl) then !both fld and ptcl state are ready
                                                    !and can be written to the files.
                                                    !if NOT -- do nothing
        if(myidd.eq.0) then
!MG,06/2019  before writing ptcl state file delete old one if exists
           INQUIRE(file=trim(filenamefld),exist=ex)
           if(ex) then
              call fdelete(trim(filenamefld),iwarn)
           endif
!MG,06/2019  NO MORE           call frename_OK(trim(filenamefld),trim(filenamefld)//'~',iwarn) !rename to *cdf~
           call ezcdf_open(icdf,filenamefld,'w',ierr)
           if(ierr.ne.0) then
              write(nonlin,*) ' ?nbi_states(...,"S",...) ezcdf_open: ierr= ',ierr
              write(nonlin,*) '  filename: '//trim(filenamefld)
           else
              
              call nbi_state_write(icdf)
              call ezcdf_close(icdf)
              
              write(nonlin,*) ' % nbi_states: fld_states write OK to filename: '//trim(filenamefld)
           endif
        endif
        if(ierr.ne.0) return
        
        if(irunmode.ge.0) then
           call nbi_ptcl_write(filenameptcl)
        endif

     endif
       
  else if(actup.eq.'R') then
     
     ! restore state: issue warning & skip if state already exists

     if(nbi_init_flag) then

        write(nonlin,*) &
             ' %nbi_states(....,"R",....) called but state already exists.'
        call nbi_dalloc
        nbi_init_flag=.FALSE.

     endif
     if(myidd.eq.0) then
        call ezcdf_open(icdf,filenamefld,'r',iwarn)
        if(iwarn.ne.0) then
           write(nonlin,*) ' '
           write(nonlin,*) ' ...try: '//trim(filenamefld)//'_save'
           call ezcdf_open(icdf,trim(filenamefld)//'_save','r',iwarn)
           if(iwarn.eq.0) then
              write(nonlin,*) ' ...OK.'
              write(nonlin,*) ' '
           endif
        endif
        if(iwarn.eq.0) then
           call nbi_state_read(icdf)
           call ezcdf_close(icdf)
              
           nbi_init_flag=.TRUE.
           call nbi_datchk(ierr)   ! check the data
           call boxn0_setup(iwarn) ! beam-in-box
           if (iwarn/=0) ierr=1
        else
           ierr=1
           write(nonlin,*) ' %nbi_states: field state file not available.'
           write(nonlin,*) '  filename: '//trim(filenamefld)
        endif
#ifndef __MPI
 ! read ptcl-list by myid=0 for serial run
        if(irunmode.ge.0) then
           call nbi_ptcl_read(filenameptcl)
        endif
#endif
     endif
     
  else if(actup.eq.'D') then
     if(myidd.eq.0) then
        zcmd = 'rm -f '//trim(filenamefld)//' '//trim(filenamefld)//'_save'
        call fdelete(trim(filenamefld),iwarn)
        call fdelete(trim(filenamefld)//'_save',iwarn)
     endif
 ! delete ptcl-list all processors if MPI       
     if(irunmode.ge.0) then
        call nbi_ptcl_delete(filenameptcl)
     endif

  else if(actup.eq.'B') then
     if(myidd.eq.0) then
        write(nonlin,*) ' +++> (cpu0) nbi_states BACKUP started...'
        
        zcmd = 'cp '//trim(filenamefld)//' '//trim(filenamefld)//'_save'
        call fcopy(trim(filenamefld),trim(filenamefld)//'_save',iwarn)
        if(iwarn.ne.0) then
           ierr=1
           write(nonlin,*) ' ?nbi_states(...,"B",...): backup failure, myid=',&
                myidd
        endif
     endif
     call nbi_ptcl_backup(filenameptcl)  ! regardless of irunmode
    
     if(myidd.eq.0) then
        write(nonlin,*) ' +++> (cpu0) nbi_states BACKUP completed.'
     endif
     
  else if(actup.eq.'C') then
     if(myidd.eq.0) then
        write(nonlin,*) ' +++> (cpu0) nbi_states RETRIEVE started...'
        
        zcmd = 'cp '//trim(filenamefld)//'_save  '//trim(filenamefld)
        call fcopy(trim(filenamefld)//'_save',trim(filenamefld),iwarn)
        if(iwarn.ne.0) then
           ierr=1
           write(nonlin,*) ' ?nbi_states(...,"C",...): retrieve failure, myid=',&
                myidd
        endif
        
     endif
     call nbi_ptcl_retrieve(filenameptcl)  ! regardless of irunmode
     
     if(myidd.eq.0) then
        write(nonlin,*) ' +++> (cpu0) nbi_states RETRIEVE completed.'
     endif
     
  else
     ierr=1
     write(nonlin,*) ' ?nbi_states: unrecognized action code: "',action,'".'
     
  endif
  
  if(myidd.ne.0) then
      call get_proc_mem(vmem,rmem);
      vmem=vmem/1000.
      write(nonlin,9002) myidd, vmem 
 9002 format( /'%nbi_states: cpu', i3,' virtual memory size = ',1pE10.3,' MB.'/)
  endif
end subroutine nbi_states
