! $Id$
!
!  test perturbation method
!
!** AUTOMATIC CPARAM.INC GENERATION ****************************
! Declare (for generation of cparam.inc) the number of f array
! variables and auxiliary variables added by this module
!
! CPARAM logical, parameter :: ltestperturb = .true.
!
!***************************************************************
module TestPerturb
!
  use Sub
  use Cdata
  use Messages

  implicit none
!
!  cosine and sine function for setting test fields and analysis
!
  real, dimension(mz) :: cz,sz,Bk1cz,Bk1sz,B1k1cz,B1k1sz,B1cz,B1sz
  integer :: njtest=0
!
!  input parameters
!
  character (len=labellen) :: itestfield='B11-B21'
  integer :: nt_testperturb=0, it_testperturb_finalize=0
  real :: ktestfield=1., ktestfield1=1., Btest0=1.
!
  include 'testperturb.h'
!
  namelist /testperturb_run_pars/ &
      itestfield,ktestfield,Btest0,nt_testperturb
!
  integer :: idiag_alp11=0      ! DIAG_DOC: $\alpha_{11}$
  integer :: idiag_alp21=0      ! DIAG_DOC: $\alpha_{21}$
  integer :: idiag_alp31=0      ! DIAG_DOC: $\alpha_{31}$
  integer :: idiag_alp12=0      ! DIAG_DOC: $\alpha_{12}$
  integer :: idiag_alp22=0      ! DIAG_DOC: $\alpha_{22}$
  integer :: idiag_alp32=0      ! DIAG_DOC: $\alpha_{32}$
  integer :: idiag_eta11=0      ! DIAG_DOC: $\eta_{113}k$
  integer :: idiag_eta21=0      ! DIAG_DOC: $\eta_{213}k$
  integer :: idiag_eta31=0      ! DIAG_DOC: $\eta_{313}k$
  integer :: idiag_eta12=0      ! DIAG_DOC: $\eta_{123}k$
  integer :: idiag_eta22=0      ! DIAG_DOC: $\eta_{223}k$
  integer :: idiag_eta32=0      ! DIAG_DOC: $\eta_{323}k$
!
  contains
!***********************************************************************
    subroutine register_testperturb()
!
!  Initialise variables
!
!  2-july-02/nils: coded
!
      use Mpicomm, only: stop_it
!
!  Identify version number.
!
      if (lroot) call svn_id( &
           "$Id$")
!
    endsubroutine register_testperturb
!***********************************************************************
    subroutine initialize_testperturb()
!
!  22-mar-08/axel: adapted from testfield_z
!
!  pre-calculate cos(kz) and sin(kz), as well as 1/ktestfield
!
      if (lroot.and.ip<=12) &
          print*,'initialize_testperturb: ktestfield=',ktestfield
!
!  set cosine and sine function for setting test fields and analysis
!
      cz=cos(ktestfield*z)
      sz=sin(ktestfield*z)
!
!  Also calculate its inverse, but only if different from zero
!
      if (ktestfield==0) then
        ktestfield1=1.
      else
        ktestfield1=1./ktestfield
      endif
!
!  other abbreviations
!
      Bk1cz=Btest0*ktestfield1*cz
      Bk1sz=Btest0*ktestfield1*sz
!
!  scale with inverse Btest0
!
      B1cz=cz/Btest0
      B1sz=sz/Btest0
!
!  scale with inverse Btest0 and with inverse ktestfield
!
      B1k1cz=ktestfield1*B1cz
      B1k1sz=ktestfield1*B1sz
!
!  determine number of testfields, njest
!
        select case (itestfield)
          case ('B11-B21+B=0'); njtest=3
          case ('B11-B21'); njtest=2
          case ('B11-B22'); njtest=4
          case ('B=0'); njtest=1
        case default
          call fatal_error('testperturb','undefined itestfield value')
        endselect
!
!  write testfield information to a file (for convenient post-processing)
!
      if (lroot) then
        open(1,file=trim(datadir)//'/testperturb_info.dat',STATUS='unknown')
        write(1,'(3a)') "itestfield='",trim(itestfield)//"'"
        write(1,'(a,f5.2)') 'ktestfield=',ktestfield
        write(1,'(a,i5)') 'nt_testperturb=',nt_testperturb
        close(1)
      endif
!
!  print a warning if nt_testperturb exceeds it1
!
      if (nt_testperturb>it1) then
        if (lroot) print*,'WARNING: nt_testperturb>it1 may be problematic'
      endif
!
    endsubroutine initialize_testperturb
!***********************************************************************
    subroutine read_testperturb_init_pars(iostat)
!
      use File_io, only: parallel_unit
!
      integer, intent(out) :: iostat
!
      read(parallel_unit, NML=testperturb_init_pars, IOSTAT=iostat)
!
    endsubroutine read_testperturb_init_pars
!***********************************************************************
    subroutine write_testperturb_init_pars(unit)
!
      integer, intent(in) :: unit
!
      write(unit, NML=testperturb_init_pars)
!
    endsubroutine write_testperturb_init_pars
!***********************************************************************
    subroutine read_testperturb_run_pars(iostat)
!
      use File_io, only: parallel_unit
!
      integer, intent(out) :: iostat
!
      read(parallel_unit, NML=testperturb_run_pars, IOSTAT=iostat)
!
    endsubroutine read_testperturb_run_pars
!***********************************************************************
    subroutine write_testperturb_run_pars(unit)
!
      integer, intent(in) :: unit
!
      write(unit, NML=testperturb_run_pars)
!
    endsubroutine write_testperturb_run_pars
!***********************************************************************
    subroutine testperturb_begin(f,df)
!
!  Calculate the response to perturbations after one timestep.
!
!  19-mar-08/axel: coded
!
      use Diagnostics
      use Hydro, only: calc_pencils_hydro
      use Timestep, only: time_step

      real, dimension (mx,my,mz,mfarray) :: fsave,f
      real, dimension (mx,my,mz,mvar) :: df
!
      real, dimension (nx,3) :: uu,bb,uxb
      logical :: headtt_save
      integer :: jtest,it_testperturb
      real :: tsave
      type (pencil_case) :: p
!
!  print identifier
!
      if (headtt.or.ldebug) print*, 'testperturb_begin'
!
!  continue only if lout=.true.
!
      if (ip<13) print*,'testperturb_begin: it,t,lout=',it,t,lout
      if (lout) then
!
!  Save current f-array and current time
!
        fsave=f
        tsave=t
!
!  set timestep for final analysis step in testperturb_finalize(f)
!
        it_testperturb_finalize=it+nt_testperturb-1
        if (ip<14) print*,'testperturb_begin: it,it_testperturb_finalize=', &
                                              it,it_testperturb_finalize
!
!  do each of the test fields one after another
!
        do jtest=1,njtest
          select case (itestfield)
            case ('B11-B22'); call add_A0test_B11_B22(f,jtest)
            case ('B=0') !(dont do anything)
          case default
            call fatal_error('testperturb_begin','undefined itestfield value')
          endselect
!
!  Time advance for nt_test timesteps
!
          do it_testperturb=1,nt_testperturb
            call time_step(f,df,p)
            if (ip<13) print*,'testperturb_begin: stay in the loop; t=',t
          enddo
          if (ip<14) print*,'testperturb_begin: do analysis; t,jtest=',t,jtest
!
!  calculate emf for calculation of alpha_ij and eta_ij tensor.
!  Note that this result applies to the end of this timestep, and does not
!  agree with that calcuted in pdf for the beginning of the timestep.
!
          lfirstpoint=.true.
          headtt_save=headtt
          do m=m1,m2
          do n=n1,n2
            call calc_pencils_hydro(f,p)
            call curl(f,iaa,bb)
            call cross_mn(p%uu,bb,uxb)
!
!  Note that we have not subtracted the contributions from the EMF
!  of the mean magnetic and velocity fields. Need to check.
!
            select case (jtest)
            case (1)
              call sum_mn_name(B1cz(n)*uxb(:,1),idiag_alp11)
              call sum_mn_name(B1cz(n)*uxb(:,2),idiag_alp21)
              call sum_mn_name(B1cz(n)*uxb(:,3),idiag_alp31)
              call sum_mn_name(-B1k1sz(n)*uxb(:,1),idiag_eta11)
              call sum_mn_name(-B1k1sz(n)*uxb(:,2),idiag_eta21)
              call sum_mn_name(-B1k1sz(n)*uxb(:,3),idiag_eta31)
            case (2)
              call sum_mn_name(B1sz(n)*uxb(:,1),idiag_alp11,ipart=2)
              call sum_mn_name(B1sz(n)*uxb(:,2),idiag_alp21,ipart=2)
              call sum_mn_name(B1sz(n)*uxb(:,3),idiag_alp31,ipart=2)
              call sum_mn_name(B1k1cz(n)*uxb(:,1),idiag_eta11,ipart=2)
              call sum_mn_name(B1k1cz(n)*uxb(:,2),idiag_eta21,ipart=2)
              call sum_mn_name(B1k1cz(n)*uxb(:,3),idiag_eta31,ipart=2)
            case (3)
              call sum_mn_name(B1cz(n)*uxb(:,1),idiag_alp12)
              call sum_mn_name(B1cz(n)*uxb(:,2),idiag_alp22)
              call sum_mn_name(B1cz(n)*uxb(:,3),idiag_alp32)
              call sum_mn_name(-B1k1sz(n)*uxb(:,1),idiag_eta12)
              call sum_mn_name(-B1k1sz(n)*uxb(:,2),idiag_eta22)
              call sum_mn_name(-B1k1sz(n)*uxb(:,3),idiag_eta32)
            case (4)
              call sum_mn_name(B1sz(n)*uxb(:,1),idiag_alp12,ipart=2)
              call sum_mn_name(B1sz(n)*uxb(:,2),idiag_alp22,ipart=2)
              call sum_mn_name(B1sz(n)*uxb(:,3),idiag_alp32,ipart=2)
              call sum_mn_name(B1k1cz(n)*uxb(:,1),idiag_eta12,ipart=2)
              call sum_mn_name(B1k1cz(n)*uxb(:,2),idiag_eta22,ipart=2)
              call sum_mn_name(B1k1cz(n)*uxb(:,3),idiag_eta32,ipart=2)
            endselect
            headtt=.false.
            lfirstpoint=.false.
          enddo
          enddo
!
!  reset f to what it was before.
!
          f=fsave
          t=tsave
        enddo
!
!  Since this routine was called before any regular call to the
!  timestepping routine, we must reset headtt to what it was before.
!
        headtt=headtt_save
      else
        if (ip<13) print*,'testperturb_begin: skip; lout,it=',lout,it
      endif
!
    endsubroutine testperturb_begin
!***********************************************************************
    subroutine testperturb_finalize(f)
!
!  Finalize testperturb method by subtracting contribution
!  emf of the reference state.
!
!  22-mar-08/axel: adapted from testperturb_begin
!
      use Diagnostics
      use Equ, only: diagnostic
      use Hydro, only: calc_pencils_hydro

      real, dimension (mx,my,mz,mfarray) :: f
!
      real, dimension (nx,3) :: uu,bb,uxb
      logical :: headtt_save
      integer :: jtest
      real :: tmp
      type (pencil_case) :: p
!
!  print identifier
!
      if (headtt.or.ldebug) print*, 'testperturb_finalize'
!
!  continue only if it >= it_testperturb
!
      if (it<it_testperturb_finalize) then
        if (ip<14) print*,'testperturb_finalize: return; t=',t
      else
        if (ip<14) print*,'testperturb_finalize: final analysis; t=',t
!
!  calculate emf for calculation of alpha_ij and eta_ij tensor
!
        lfirstpoint=.true.
        do m=m1,m2
        do n=n1,n2
          call calc_pencils_hydro(f,p)
          call curl(f,iaa,bb)
          call cross_mn(p%uu,bb,uxb)
!
!  alpha terms
!
          tmp=-(B1cz(n)+B1sz(n))
          call sum_mn_name(tmp*uxb(:,1),idiag_alp11,ipart=3)
          call sum_mn_name(tmp*uxb(:,2),idiag_alp21,ipart=3)
          call sum_mn_name(tmp*uxb(:,3),idiag_alp31,ipart=3)
          call sum_mn_name(tmp*uxb(:,1),idiag_alp12,ipart=3)
          call sum_mn_name(tmp*uxb(:,2),idiag_alp22,ipart=3)
          call sum_mn_name(tmp*uxb(:,3),idiag_alp32,ipart=3)
!
!  eta terms
!
          tmp=B1k1sz(n)-B1k1cz(n)
          call sum_mn_name(tmp*uxb(:,1),idiag_eta11,ipart=3)
          call sum_mn_name(tmp*uxb(:,2),idiag_eta21,ipart=3)
          call sum_mn_name(tmp*uxb(:,3),idiag_eta31,ipart=3)
          call sum_mn_name(tmp*uxb(:,1),idiag_eta12,ipart=3)
          call sum_mn_name(tmp*uxb(:,2),idiag_eta22,ipart=3)
          call sum_mn_name(tmp*uxb(:,3),idiag_eta32,ipart=3)
!
          headtt=.false.
          lfirstpoint=.false.
        enddo
        enddo
      endif
!
    endsubroutine testperturb_finalize
!***********************************************************************
    subroutine add_A0test_B11_B22 (f,jtest)
!
!  add testfields into f array:
!
!         ( 0 )   (     0      )     ( B*coskz )
!  B^11 = ( 0 ) x ( -B/k*sinkz )  =  (    0    )
!         ( dz)   (     0      )     (    0    )
!
!         ( 0 )   (     0      )     ( B*sinkz )
!  B^21 = ( 0 ) x ( +B/k*coskz )  =  (    0    )
!         ( dz)   (     0      )     (    0    )
!
!         ( 0 )   ( +B/k*sinkz )     (    0    )
!  B^12 = ( 0 ) x (      0    )   =  ( B*coskz )
!         ( dz)   (      0    )      (    0    )
!
!         ( 0 )   ( -B/k*coskz )     (    0    )
!  B^22 = ( 0 ) x (      0    )   =  ( B*sinkz )
!         ( dz)   (      0    )      (    0    )
!
!  22-mar-08/axel: adapted from testfield_z
!
      use Cdata
      use Mpicomm, only: stop_it
!
      real, dimension (mx,my,mz,mfarray) :: f
      integer :: jtest
!
      intent(inout) :: f
      intent(in)  :: jtest
!
!  add testfield contribution to the f array
!
      select case (jtest)
      case (1); f(:,:,:,iay)=f(:,:,:,iay)-spread(spread(Bk1sz,1,mx),2,my)
      case (2); f(:,:,:,iay)=f(:,:,:,iay)+spread(spread(Bk1cz,1,mx),2,my)
      case (3); f(:,:,:,iax)=f(:,:,:,iax)+spread(spread(Bk1sz,1,mx),2,my)
      case (4); f(:,:,:,iax)=f(:,:,:,iax)-spread(spread(Bk1cz,1,mx),2,my)
      case default; call stop_it('add_A0test_B11_B22: jtest incorrect')
      endselect
!
    endsubroutine add_A0test_B11_B22
!***********************************************************************
    subroutine rprint_testperturb(lreset,lwrite)
!
!  reads and registers print parameters relevant to testperturb
!
!  20-mar-08/axel: adapted from shear.f90
!
      use Cdata
      use Diagnostics
!
      integer :: iname
      logical :: lreset,lwr
      logical, optional :: lwrite
!
      lwr = .false.
      if (present(lwrite)) lwr=lwrite
!
!  reset everything in case of reset
!  (this needs to be consistent with what is defined above!)
!
      if (lreset) then
        idiag_alp11=0; idiag_alp21=0; idiag_alp31=0
        idiag_alp12=0; idiag_alp22=0; idiag_alp32=0
        idiag_eta11=0; idiag_eta21=0; idiag_eta31=0
        idiag_eta12=0; idiag_eta22=0; idiag_eta32=0
      endif
!
!  iname runs through all possible names that may be listed in print.in
!
      do iname=1,nname
        call parse_name(iname,cname(iname),cform(iname),'alp11',idiag_alp11)
        call parse_name(iname,cname(iname),cform(iname),'alp21',idiag_alp21)
        call parse_name(iname,cname(iname),cform(iname),'alp31',idiag_alp31)
        call parse_name(iname,cname(iname),cform(iname),'alp12',idiag_alp12)
        call parse_name(iname,cname(iname),cform(iname),'alp22',idiag_alp22)
        call parse_name(iname,cname(iname),cform(iname),'alp32',idiag_alp32)
        call parse_name(iname,cname(iname),cform(iname),'eta11',idiag_eta11)
        call parse_name(iname,cname(iname),cform(iname),'eta21',idiag_eta21)
        call parse_name(iname,cname(iname),cform(iname),'eta31',idiag_eta31)
        call parse_name(iname,cname(iname),cform(iname),'eta12',idiag_eta12)
        call parse_name(iname,cname(iname),cform(iname),'eta22',idiag_eta22)
        call parse_name(iname,cname(iname),cform(iname),'eta32',idiag_eta32)
      enddo
!
!  write column where which testperturb variable is stored
!
      if (lwr) then
        write(3,*) 'idiag_alp11=',idiag_alp11
        write(3,*) 'idiag_alp21=',idiag_alp21
        write(3,*) 'idiag_alp31=',idiag_alp31
        write(3,*) 'idiag_alp12=',idiag_alp12
        write(3,*) 'idiag_alp22=',idiag_alp22
        write(3,*) 'idiag_alp32=',idiag_alp32
        write(3,*) 'idiag_eta11=',idiag_eta11
        write(3,*) 'idiag_eta21=',idiag_eta21
        write(3,*) 'idiag_eta31=',idiag_eta31
        write(3,*) 'idiag_eta12=',idiag_eta12
        write(3,*) 'idiag_eta22=',idiag_eta22
        write(3,*) 'idiag_eta32=',idiag_eta32
      endif
!
    endsubroutine rprint_testperturb
!***********************************************************************
endmodule TestPerturb