!===============================================================================
!
! quda_fortran.F90
!
!-------------------------------------------------------------------------------
!
! This is a Fortran module that implements the C structs defined in
! quda.h as Fortran modules.  This is currently generated by hand, and
! so must be matched against an appropriate version of QUDA.  It would
! be nice to auto-generate this from quda.h.
!
!-------------------------------------------------------------------------------
# include <enum_quda_fortran.h>

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

#include <quda_constants.h>

module quda_fortran

  ! This corresponds to the QudaGaugeParam struct in quda.h
  type quda_gauge_param

     QudaFieldLocation :: location !The location of the gauge field

     integer(4), dimension(4) :: x

     real(8) :: anisotropy    !Used for Wilson and Wilson-clover
     real(8) :: tadpole_coeff !Used for staggered only
     real(8) :: scale         !Used by staggered long links

     QudaLinkType :: link_type
     QudaGaugeFieldOrder :: gauge_order
     QudaTboundary :: t_boundary
     QudaPrecision :: cpu_prec
     QudaPrecision :: cuda_prec
     QudaReconstructType :: reconstruct
     QudaPrecision :: cuda_prec_sloppy
     QudaReconstructType :: reconstruct_sloppy
     QudaPrecision :: cuda_prec_precondition
     QudaReconstructType :: reconstruct_precondition
     QudaGaugeFixed :: gauge_fix

     integer(4) :: ga_pad

     integer(4) :: site_ga_pad ! Used by link fattening and the gauge and fermion forces

     integer(4) :: staple_pad   ! Used by link fattening
     integer(4) :: llfat_ga_pad ! Used by link fattening
     integer(4) :: mom_ga_pad   ! Used by the gauge and fermion forces
     real(8) :: gauge_gib

     ! Set the staggered phase type of the links
     QudaStaggeredPhase :: staggered_phase_type
     ! Whether the staggered phase has already been applied to the links
     integer(4) :: staggered_phase_applied

     ! Imaginary chemical potential
     real(8) :: i_mu

     integer(4) :: overlap ! width of domain overlap

     ! When computing momentum, should we overwrite it or accumulate
     ! to it (only presenty support in gauge-force)
     integer(4) :: overwrite_mom

     integer(4) :: use_resident_gauge  ! Use the resident gauge field
     integer(4) :: use_resident_mom    ! Use the resident momentume field
     integer(4) :: make_resident_gauge ! Make the result gauge field resident
     integer(4) :: make_resident_mom   ! Make the result momentum field resident
     integer(4) :: return_result_gauge ! Return the result gauge field
     integer(4) :: return_result_mom   ! Return the result momentum field

     integer(8) :: gauge_offset ! Offset into MILC site struct to the gauge field (only if gauge_order=MILC_SITE_GAUGE_ORDER)
     integer(8) :: mom_offset   ! Offset into MILC site struct to the momentum field (only if gauge_order=MILC_SITE_GAUGE_ORDER)
     integer(8) :: site_size    ! Size of MILC site struct (only if gauge_order=MILC_SITE_GAUGE_ORDER)

 end type quda_gauge_param

  ! This module corresponds to the QudaInvertParam struct in quda.h
  type quda_invert_param

     QudaFieldLocation :: input_location  ! The location of the input field
     QudaFieldLocation :: output_location ! The location of the output field

     QudaDslashType :: dslash_type
     QudaInverterType :: inv_type

     real(8) :: mass  ! Used for staggered only
     real(8) :: kappa ! Used for Wilson and Wilson-clover

     real(8) :: m5    ! Domain wall height
     integer(4) :: Ls       ! Extent of the 5th dimension (for domain wall)

     real(8), dimension(QUDA_MAX_DWF_LS) :: b_5 ! MDWF coefficients
     real(8), dimension(QUDA_MAX_DWF_LS) :: c_5 ! will be used only for the mobius type of Fermion

     real(8) :: mu    ! Twisted mass parameter
     real(8) :: epsilon ! Twisted mass parameter
     QudaTwistFlavorType :: twist_flavor  ! Twisted mass flavor

     real(8) :: tol ! Requested L2 residual norm
     real(8) :: tol_restart ! Solver tolerance in the L2 residual norm (used to restart InitCG)
     real(8) :: tol_hq ! Requested heavy quark residual norm
     integer(4) :: compute_true_res ! Whether to compute the true residual post solve
     real(8) :: true_res ! Actual L2 residual norm achieved in solver
     real(8) :: true_res_hq ! Actual heavy quark residual norm achieved in solver
     integer(4) :: maxiter
     real(8) :: reliable_delta ! Reliable update tolerance
     integer(4) :: use_sloppy_partial_accumulator ! Whether to keep the partial solution accumuator in sloppy precision
     integer(4) :: solution_accumulator_pipeline ! How many direction vectors we accumulate into the solution vector at once
     integer(4) :: max_res_increase ! How many residual increases we tolerate when doing reliable updates
     integer(4) :: max_res_increase_total ! Total number of residual increases we tolerate
     integer(4) :: heavy_quark_check ! After how many iterations shall the heavy quark residual be updated
     integer(4) :: pipeline ! Whether to enable pipeline solver option
     integer(4) :: num_offset ! Number of offsets in the multi-shift solver
     integer(4) :: num_src ! Number of sources in the multiple source solver
     integer(4) :: overlap ! width of domain overlaps
     real(8), dimension(QUDA_MAX_MULTI_SHIFT) :: offset ! Offsets for multi-shift solver
     real(8), dimension(QUDA_MAX_MULTI_SHIFT) :: tol_offset ! Solver tolerance for each offset

     ! Solver tolerance for each shift when refinement is applied using the heavy-quark residual
     real(8), dimension(QUDA_MAX_MULTI_SHIFT) :: tol_hq_offset

     ! Actual L2 residual norm achieved in solver for each offset
     real(8), dimension(QUDA_MAX_MULTI_SHIFT) :: true_res_offset

     ! Iterated L2 residual achieved in multi shift solver for each offset
     real(8), dimension(QUDA_MAX_MULTI_SHIFT) :: iter_res_offset

     ! Actual heavy quark residual norm achieved in solver for each offset
     real(8), dimension(QUDA_MAX_MULTI_SHIFT) :: true_res_hq_offset

     ! Residuals in the partial faction expansion
     real(8), dimension(QUDA_MAX_MULTI_SHIFT) :: residue

     ! Whether we should evaluate the action after the linear solve
     integer(4) :: compute_action

     ! Computed value of the bilinear action (complex valued)
     !   invert: \phi^\dagger A^{-1} \phi
     !   multishift: \phi^\dagger r(x) \phi = \phi^\dagger (sum_k residue[k] * (A + offset[k])^{-1} ) \phi
     real(8), dimension(2) :: action

     QudaSolutionType :: solution_type  ! Type of system to solve
     QudaSolveType :: solve_type        ! How to solve it
     QudaMatPCType :: matpc_type
     QudaDagType :: dagger
     QudaMassNormalization :: mass_normalization

     QudaSolverNormalization :: solver_normalization
     QudaPreserveSource :: preserve_source

     QudaPrecision :: cpu_prec
     QudaPrecision :: cuda_prec
     QudaPrecision :: cuda_prec_sloppy
     QudaPrecision :: cuda_prec_precondition

     QudaDiracFieldOrder :: dirac_order

     ! Gamma basis of the input and output host fields
     QudaGammaBasis :: gamma_basis

     QudaFieldLocation :: clover_location            ! The location of the clover field
     QudaPrecision :: clover_cpu_prec
     QudaPrecision :: clover_cuda_prec
     QudaPrecision :: clover_cuda_prec_sloppy
     QudaPrecision :: clover_cuda_prec_precondition

     QudaCloverFieldOrder :: clover_order
     QudaUseInitGuess :: use_init_guess

     real(8) :: clover_coeff ! Coefficient of the clover term
     real(8) :: clover_rho   ! Real number added to the clover diagonal (not to inverse)
     integer(4) :: compute_clover_trlog ! Whether to compute the trace log of the clover term
     real(8), dimension(2) :: trlogA    ! The trace log of the clover term (even/odd computed separately)

     integer(4) :: compute_clover                    ! Whether to compute the clover field
     integer(4) :: compute_clover_inverse            ! Whether to compute the clover inverse field
     integer(4) :: return_clover                     ! Whether to copy back the clover matrix field
     integer(4) :: return_clover_inverse             ! Whether to copy back the inverted clover matrix field

     QudaVerbosity :: verbosity                      ! The verbosity setting to use in the solver

     integer(4) :: sp_pad
     integer(4) :: cl_pad

     integer(4) :: iter
     real(8) :: spinor_gib
     real(8) :: clover_gib
     real(8) :: gflops
     real(8) :: secs

     ! Enable auto-tuning?
     QudaTune :: tune

     ! Number of steps in s-step algorithms
     integer(4) :: nsteps

     ! Maximum size of Krylov space used by solver
     integer(4) :: gcr_nkrylov

     ! The following parameters are related to the domain-decomposed preconditioner.

     ! The inner Krylov solver used in the preconditioner.  Set to
     ! QUDA_INVALID_INVERTER to disable the preconditioner entirely.
     QudaInverterType :: inv_type_precondition

     integer(8) :: preconditioner ! pointer to preconditioner instance

     integer(8) :: deflation_op ! pointer to deflation instance

     ! Dslash used in the inner Krylov solver
     QudaDslashType :: dslash_type_precondition

     ! Verbosity of the inner Krylov solver
     QudaVerbosity :: verbosity_precondition

     ! Tolerance in the inner solver
     real(8) :: tol_precondition

     ! Maximum number of iterations allowed in the inner solver
     integer(4) :: maxiter_precondition

     ! Relaxation parameter used in GCR-DD (default = 1.0)
     real(8) :: omega

     ! Number of preconditioner cycles to perform per iteration
     integer(4) :: precondition_cycle

     ! Whether to use additive or multiplicative Schwarz preconditioning
     QudaSchwarzType :: schwarz_type

     ! Whether to use the Fermilab heavy-quark residual or standard residual to gauge convergence
     QudaResidualType ::residual_type

     ! Parameters for deflated solvers
     QudaPrecision :: cuda_prec_ritz ! The precision of the Ritz vectors
     integer(4)::nev
     integer(4)::max_search_dim ! for magma library this parameter must be multiple 16?
     integer(4)::rhs_idx
     integer(4)::deflation_grid !total deflation space is nev*deflation_grid
     integer(4)::use_reduced_vector_set ! eigCG: specifies whether to use reduced eigenvector set
     real(8):: eigenval_tol ! eigCG: selection criterion for the reduced eigenvector set
     integer(4)::use_cg_updates ! mixed precision eigCG:whether to use cg refinement corrections in the incremental stage
     real(8)::cg_iterref_tol ! mixed precision eigCG:  tolerance for cg refinement corrections in the incremental stage
     integer(4)::eigcg_max_restarts ! mixed precision eigCG tuning parameter:  minimum search vector space restarts
     integer(4)::max_restart_num     ! initCG tuning parameter:  maximum restarts
     real(8)::inc_tol     ! initCG tuning parameter:  decrease in absolute value of the residual within each restart cycle

     ! Parameters for setting data residency of the solver
     integer(4)::make_resident_solution ! Whether to make the solution vector(s) after the solve
     integer(4)::use_resident_solution  ! Whether to use the resident solution vector(s)

     ! Whether to use the solution vector to augment the chronological forecast
     integer(4)::make_resident_chrono

     ! Whether to use the resident chronological basis
     integer(4)::use_resident_chrono

     ! The maximum length of the chronological history to store
     integer(4)::max_chrono_dim

     ! The index to indeicate which chrono history we are augmenting */
     integer(4)::chrono_index

     ! Which external library to use in the linear solvers (MAGMA or Eigen) */
     QudaExtLibType::extlib_type

  end type quda_invert_param

end module quda_fortran
!===============================================================================
