!===============================================================================
!
! conf.F90 - operations on gauge field and pseudo fermion field configurations
!
!-------------------------------------------------------------------------------
!
! Copyright (C) 1998-2016 Hinnerk Stueben
!
! This file is part of BQCD -- Berlin Quantum ChromoDynamics program
!
! BQCD 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.
!
! BQCD 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 BQCD.  If not, see <http://www.gnu.org/licenses/>.
!
!-------------------------------------------------------------------------------
# include "defs.h"

!!!-------------------------------------------------------------------------------
!!subroutine init_confs(para, conf)
!!
!!  use typedef_para
!!  use module_p_interface
!!  use module_switches
!!  implicit none
!!
!!  type(type_para)                       :: para
!!  type(hmc_conf), dimension(MAX_TEMPER) :: conf
!!  integer                               :: i
!!
!!  do i = 1, para%n_temper
!!     call allocate_g_field(conf(i)%u)
!!     call allocate_sc_field(conf(i)%phi)
!!
!!     if (switches%qed) call allocate_u1gen_field(conf(i)%a_qed)
!!     if (switches%axion) call allocate_axion_field(conf(i)%axion)
!!     if (switches%hasenbusch) call allocate_sc_field(conf(i)%phi2)
!!
!!     if (para%start == START_HOT .or. para%start == START_COLD) then
!!        call init_u(conf(i)%u, para%start)
!!        if (switches%qed) call init_a_qed(conf(i)%a_qed, para%start)
!!        if (switches%axion) call init_axion(conf(i)%axion, para%start)
!!        conf(i)%former = i
!!     endif
!!  enddo
!!
!!  if (para%start == START_CONT) call conf_read(.true., para, conf)
!!  if (para%start == START_FILE) call conf_read(.false., para, conf)
!!
!!  do i = 1, para%n_temper
!!     if (para%hmc(i)%csw_kappa /= ZERO) then
!!        call allocate_clover_field_a(conf(i)%a)
!!        call allocate_clover_field_a(conf(i)%i)
!!        call allocate_clover_field_b(conf(i)%b)
!!        call clover_init(conf(i)%a, conf(i)%i, conf(i)%b, &
!!                         conf(i)%u, para%hmc(i)%csw_kappa)
!!     endif
!!  enddo
!!
!!end

!-------------------------------------------------------------------------------
subroutine init_u(u, start)  ! initialization of u-field (at trajectory 0)

  use module_vol
  implicit none

  GAUGE_FIELD :: u
  integer :: start

  select case (start)
     case (START_HOT)
        call conf_hot(u)
     case (START_COLD)
        call conf_cold(u)
     case default
        call die("init_u(): don't know how to start")
  end select

  call xbound_g_field(u)
  call d_g_init(u)
end

!-------------------------------------------------------------------------------
subroutine conf_check(u)  ! checks if u-field is SU(3)

  use module_vol
  implicit none

  GAUGE_FIELD, intent(in) :: u
  REAL, parameter :: eps = 1e-13

  call conf_check2(u, eps)
end

!-------------------------------------------------------------------------------
subroutine conf_check32(u)  ! checks if u-field is SU(3) (if input was 32-bit) 

  use module_vol
  implicit none

  GAUGE_FIELD, intent(inout) :: u
  REAL, parameter :: eps = 8.5e-7

  call conf_check2(u, eps)
  call conf_normalize(u)
end

!-------------------------------------------------------------------------------
subroutine conf_check2(u, eps)  ! checks if u-field is SU(3)

  use module_vol
  implicit none

  GAUGE_FIELD, intent(in) :: u
  REAL, intent(in) :: eps
  SU3 :: v
  SU3, parameter :: su3_one = reshape( &
                           (/ ONE,ZERO,ZERO, &
                              ZERO,ONE,ZERO, &
                              ZERO,ZERO,ONE /), &
                           (/ NCOL, NCOL /))
  REAL :: dev, d
  integer :: i, j, k, eo, mu


  dev = ZERO
  do mu = 1, DIM
     do eo = EVEN, ODD
        do k = 1, VOLH
           call su3_check_det(u(1, 1, k, eo, mu), eps)
           call uud(v, u(1, 1, k, eo, mu), u(1, 1, k, eo, mu))
           do i = 1, NCOL
              do j = 1, NCOL
                 d = abs(Re(v(i, j)) - Re(su3_one(i, j))) & 
                   + abs(Im(v(i, j)) - Im(su3_one(i, j)))
              enddo
           enddo
           dev = max(dev, d)
        enddo
     enddo
  enddo

  if (dev > eps) then 
     write(0,*)"conf_check(): dev > eps, dev=",dev
     call die('conf_check(): dev > eps')
  endif
!!write(0,'(x,a,e10.2)') 'conf_check(): max deviation is ', dev

end

!-------------------------------------------------------------------------------
subroutine conf_normalize(u)  ! normalizes u-field to SU(3)

  use module_vol
  implicit none

  GAUGE_FIELD, intent(inout) :: u
  integer :: i, eo, mu

  do mu = 1, DIM
     do eo = EVEN, ODD
        do i = 1, volh
           call u_normalize(u(1, 1, i, eo, mu))
        enddo
     enddo
  enddo

end

!-------------------------------------------------------------------------------
subroutine conf_zero(u)

  use module_vol
  implicit none

  GAUGE_FIELD :: u
  integer :: i, eo, mu

  do mu = 1, DIM
     do eo = EVEN, ODD
        !$omp parallel do
        do i = 1, volh
           u(1, 1, i, eo, mu) = ZERO
           u(2, 1, i, eo, mu) = ZERO
           u(3, 1, i, eo, mu) = ZERO
           u(1, 2, i, eo, mu) = ZERO
           u(2, 2, i, eo, mu) = ZERO
           u(3, 2, i, eo, mu) = ZERO
           u(1, 3, i, eo, mu) = ZERO
           u(2, 3, i, eo, mu) = ZERO
           u(3, 3, i, eo, mu) = ZERO
        enddo
     enddo
  enddo

end

!-------------------------------------------------------------------------------
subroutine conf_cold(u)  ! cold start

  use module_vol
  implicit none

  GAUGE_FIELD :: u
  integer :: i, eo, mu

  do mu = 1, DIM
     do eo = EVEN, ODD
        do i = 1, volh
           u(1, 1, i, eo, mu) = ONE
           u(2, 1, i, eo, mu) = ZERO
           u(3, 1, i, eo, mu) = ZERO
           u(1, 2, i, eo, mu) = ZERO
           u(2, 2, i, eo, mu) = ONE
           u(3, 2, i, eo, mu) = ZERO
           u(1, 3, i, eo, mu) = ZERO
           u(2, 3, i, eo, mu) = ZERO
           u(3, 3, i, eo, mu) = ONE
        enddo
     enddo
  enddo

end

!-------------------------------------------------------------------------------
subroutine conf_hot(u)  ! hot start

  use module_vol
  implicit none

  GAUGE_FIELD :: u
  integer :: i, eo, mu

  do mu = 1, DIM
     do eo = EVEN, ODD
        call ran_gauss_volh(NCOL * NCOL, u(1, 1, 1, eo, mu), ONE, eo)
        do i = 1, volh
           call u_normalize(u(1, 1, i, eo, mu))
        enddo
     enddo
  enddo

end

!-------------------------------------------------------------------------------
subroutine conf_read(restart, para, conf)

  use typedef_para
  use module_input
  implicit none

  logical                               :: restart
  type(type_para)                       :: para
  type(hmc_conf), dimension(MAX_TEMPER) :: conf


  if (restart) then  ! continue a job chain: 
                     ! read restart file(s) written by BQCD

     select case (input%io_restart_format)
     case ("bqcd");  call conf_read_bqcd(restart, para, conf, 1)
     case ("bqcd2"); call conf_read_bqcd(restart, para, conf, 2)
     case ("ildg");  call conf_read_ildg(restart, para, conf)
     case default;   call die("conf_read(): 'io_restart_format' unknown (1)")  
     end select

  else  ! start a job chain: 
        ! read existing file(s) possibly written by other programs
     
     if (para%info_file(1) /= "") then

        ! in general          :  para%info_file(1) = input%start_info_file(1)
        ! if --convert-to-ildg:  para%info_file(1) = flags%input

        select case (input%io_restart_format)
        case ("bqcd");  call conf_read_bqcd(restart, para, conf, 1)
        case ("bqcd2"); call conf_read_bqcd(restart, para, conf, 2)
        case default;   call die("conf_read(): 'io_restart_format' unknown (2)")  
        end select

     elseif (input%start_ildg_file /= "") then

        call conf_read_ildg(restart, para, conf)

     else
        call die("conf_read(): no start file given")  
     endif

  endif

end

!-------------------------------------------------------------------------------
subroutine conf_write(restart, para, conf)

  use typedef_para
  use module_counter
  use module_input
  implicit none

  logical                               :: restart
  type(type_para)                       :: para
  type(hmc_conf), dimension(MAX_TEMPER) :: conf

  if (restart) then

     select case (input%io_restart_format)
     case ("bqcd");  call conf_write_bqcd(restart, para, conf, 1)
     case ("bqcd2"); call conf_write_bqcd(restart, para, conf, 2)
     case ("ildg");  call conf_write_ildg(restart, para, conf)
     case default;   call die("conf_write(): 'io_restart_format' unknown")  
     end select

  else

     CHECK(counter%traj >=0)  ! can go wrong with --convert-to-ildg

     select case (input%io_conf_format)
     case ("bqcd");  call conf_write_bqcd(restart, para, conf, 1)
     case ("bqcd2"); call conf_write_bqcd(restart, para, conf, 2)
     case ("ildg");  call conf_write_ildg(restart, para, conf)
     case default;   call die("conf_write(): 'io_conf_format' unknown")  
     end select

  endif
end

!-------------------------------------------------------------------------------
subroutine conf_copy(out, in)

  use module_vol
  implicit none
  GAUGE_FIELD :: out, in
  integer :: mu, eo, i

  do mu = 1, DIM
     do eo = EVEN, ODD
        !$omp parallel do
        do i = 1, volh_tot
           out(1, 1, i, eo, mu) = in(1, 1, i, eo, mu)
           out(2, 1, i, eo, mu) = in(2, 1, i, eo, mu)
           out(3, 1, i, eo, mu) = in(3, 1, i, eo, mu)
           out(1, 2, i, eo, mu) = in(1, 2, i, eo, mu)
           out(2, 2, i, eo, mu) = in(2, 2, i, eo, mu)
           out(3, 2, i, eo, mu) = in(3, 2, i, eo, mu)
           out(1, 3, i, eo, mu) = in(1, 3, i, eo, mu)
           out(2, 3, i, eo, mu) = in(2, 3, i, eo, mu)
           out(3, 3, i, eo, mu) = in(3, 3, i, eo, mu)
        enddo
     enddo
  enddo
end

!===============================================================================
