program WEIssf1_main
  use sep
  use mpi_sep 
  use wei_util 
  use wei_par 
  use wei_pro 
  use wei_tag 
  use wei_mig 
  use oc_global_mod 
  use oc_utils_mod 
  use oc_mpi_solver_mod 
  use oc_cgstep_mod 
  use oc_mpi_dottest_mod 
  use weiop_cig 
  use weiop_mwc 
  use weiop_slo 
  use weiop_ssf 
  use weiop_wem 

  implicit none
  character(len=3) :: operation
  integer :: stat 

  integer :: mpierr 

  real    :: ocmaxmem
  integer :: ocniter
  logical :: ocverb,ocmovie 
  character(len=128) :: res_, name 

  !----------------------------------------------------------------
  call MPI_INIT(mpierr)
  call sep_init()

  !----------------------------------------------------------------
  !! init params for MPI and OMP
  call weipar_init()
  call weipar_report()

  if(wpar%nmpi>0) then
     if(wpar%impi==0) then
        call MPI_SEP_SEND_ARGS(wpar%nmpi,1,0)
     else
        call MPI_SEP_RECEIVE_ARGS()
     end if
  end if

  !! init tag names on all nodes
  call weitag_init()

  !! init process parameters on the MASTER
  if(wpar%impi==0) call weipro_init()
  !! broadcast parameters from MASTER to NODES
  if(wpar%nmpi >1) call weipro_bcast()
  if(wpar%impi==0) call from_param("operation",operation,'mig')
  if(wpar%nmpi >1) call MPI_BCAST(operation, 3,MPI_CHARACTER,0,MPI_COMM_WORLD,mpierr) 
  !----------------------------------------------------------------
  if(wpar%impi==0) call from_param("ocmaxmem",ocmaxmem,     0.)
  ocmaxmem = ocmaxmem * 1024*1024
  if(wpar%nmpi >1) call MPI_BCAST(ocmaxmem, 1,MPI_REAL,0,MPI_COMM_WORLD,mpierr)

  if(wpar%impi==0) call from_param("ocniter", ocniter ,     1 )
  if(wpar%nmpi >1) call MPI_BCAST(ocniter, 1,MPI_INTEGER,0,MPI_COMM_WORLD,mpierr)

  if(wpar%impi==0) call from_param("ocverb",  ocverb  ,.false.)
  if(wpar%nmpi >1) call MPI_BCAST(ocverb, 1,MPI_LOGICAL,0,MPI_COMM_WORLD,mpierr)

  if(wpar%impi==0) call from_param("ocmovie", ocmovie ,.false.)
  if(wpar%nmpi >1) call MPI_BCAST(ocmovie, 1,MPI_LOGICAL,0,MPI_COMM_WORLD,mpierr)
  !----------------------------------------------------------------
  call weimig_init(SLin=weiop_slo1_init &
  ,                WCin=weiop_mwc1_init &
  ,                FKin=weiop_wem3_init &
  ,                FXin=weiop_ssf3_init &
  ,                IGin=weiop_hcig_init )
  !----------------------------------------------------------------
  if(wpar%impi==0) call weipro_report()
  !----------------------------------------------------------------
  !! select an operation
  select case(operation(1:3))
  case('dot')
     if(wpar%impi==0 .and. wpro%verb) call weimessage("start dottest")
     call oc_mpi_dottest_init(wpar%impi,maxmem=nint(ocmaxmem))
     call oc_mpi_dottest(weimig,wtag%R,wtag%D &
     ,           op1=weiop_slo1 &
     ,           op2=weiop_mwc1 &
     ,           op3=weiop_wem3 &
     ,           op4=weiop_ssf3 &
     ,           op5=weiop_hcig )
     if(wpar%impi==0 .and. wpro%verb) call weimessage("OK")
  case('mig','mod')
     if(wpar%impi==0 .and. wpro%verb) then
        if(wpro%adj) then
           call weimessage("start adjoint operator")
        else
           call weimessage("start forward operator")
        end if
     end if
     stat = weimig(wpro%adj,wpro%add,wtag%R,wtag%D &
     ,              SLop=weiop_slo1 &
     ,              WCop=weiop_mwc1 &
     ,              FKop=weiop_wem3 &
     ,              FXop=weiop_ssf3 &
     ,              IGop=weiop_hcig)
     if(wpar%impi==0 .and. wpro%verb) call weimessage("OK")
  case('inv')
     if(wpar%impi==0 .and. wpro%verb) call weimessage("start inversion")

     !! create data residual file
     name = '_res'; res_ = oc_allocate(.false.,name)
     call auxputch("n1","i",ocniter,trim(res_))
     call auxputch("esize","i",4,trim(res_))

     call oc_mpi_solver_init(wpar%impi,ocniter,nint(ocmaxmem),ocverb,ocmovie,ocmovie)
     call oc_mpi_solver(weimig,oc_cgstep,wtag%R,wtag%D &
     ,           op1=weiop_slo1 &
     ,           op2=weiop_mwc1 &
     ,           op3=weiop_wem3 &
     ,           op4=weiop_ssf3 &
     ,           op5=weiop_hcig ) 
     if(wpar%impi==0 .and. wpro%verb) call weimessage("OK")
  case default
     call seperr('unknown operation')
  end select
  !----------------------------------------------------------------  
  !! shutdown MPI
  call MPI_FINALIZE(mpierr) 
  !----------------------------------------------------------------
  call exit(0)
end program WEIssf1_main
