/* -*- c++ -*- ----------------------------------------------------------
   LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
   https://www.lammps.org/, Sandia National Laboratories
   LAMMPS development team: developers@lammps.org

   Copyright (2003) Sandia Corporation.  Under the terms of Contract
   DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
   certain rights in this software.  This software is distributed under
   the GNU General Public License.

   See the README file in the top-level LAMMPS directory.
------------------------------------------------------------------------- */

#ifdef MINIMIZE_CLASS
// clang-format off
MinimizeStyle(hftn,MinHFTN);
// clang-format on
#else

#ifndef LMP_MIN_HFTN_H
#define LMP_MIN_HFTN_H

#include "min.h"

namespace LAMMPS_NS {

class MinHFTN : public Min {
 public:
  MinHFTN(LAMMPS *);
  ~MinHFTN() override;
  void init() override;
  void setup_style() override;
  void reset_vectors() override;
  int iterate(int) override;

 private:
  //---- THE ALGORITHM NEEDS TO STORE THIS MANY ATOM-BASED VECTORS,
  //---- IN ADDITION TO ATOM POSITIONS AND THE FORCE VECTOR.
  enum {
    VEC_XK = 0,    //-- ATOM POSITIONS AT SUBITER START
    VEC_CG_P,      //-- STEP p IN CG SUBITER
    VEC_CG_D,      //-- DIRECTION d IN CG SUBITER
    VEC_CG_HD,     //-- HESSIAN-VECTOR PRODUCT Hd
    VEC_CG_R,      //-- RESIDUAL r IN CG SUBITER
    VEC_DIF1,      //-- FOR FINITE DIFFERENCING
    VEC_DIF2,      //-- FOR FINITE DIFFERENCING
    NUM_HFTN_ATOM_BASED_VECTORS
  };

  //---- ATOM-BASED STORAGE VECTORS.
  double *_daAVectors[NUM_HFTN_ATOM_BASED_VECTORS];
  double **_daExtraAtom[NUM_HFTN_ATOM_BASED_VECTORS];

  //---- GLOBAL DOF STORAGE.  ELEMENT [0] IS X0 (XK), NOT USED IN THIS ARRAY.
  double *_daExtraGlobal[NUM_HFTN_ATOM_BASED_VECTORS];

  int _nNumUnknowns;
  FILE *_fpPrint;

  int execute_hftn_(const bool bPrintProgress, const double dInitialEnergy,
                    const double dInitialForce2, double &dFinalEnergy, double &dFinalForce2);
  bool compute_inner_cg_step_(const double dTrustRadius, const double dForceTol,
                              const int nMaxEvals, const bool bHaveEvalAtXin,
                              const double dEnergyAtXin, const double dForce2AtXin,
                              double &dEnergyAtXout, double &dForce2AtXout, int &nStepType,
                              double &dStepLength2, double &dStepLengthInf);
  double calc_xinf_using_mpi_() const;
  double calc_dot_prod_using_mpi_(const int nIx1, const int nIx2) const;
  double calc_grad_dot_v_using_mpi_(const int nIx) const;
  void calc_dhd_dd_using_mpi_(double &dDHD, double &dDD) const;
  void calc_ppnew_pdold_using_mpi_(double &dPnewDotPnew, double &dPoldDotD) const;
  void calc_plengths_using_mpi_(double &dStepLength2, double &dStepLengthInf) const;
  bool step_exceeds_TR_(const double dTrustRadius, const double dPP, const double dPD,
                        const double dDD, double &dTau) const;
  bool step_exceeds_DMAX_() const;
  void adjust_step_to_tau_(const double tau);
  double compute_to_tr_(const double dPP, const double dPD, const double dDD,
                        const double dTrustRadius, const bool bConsiderBothRoots, const double dDHD,
                        const double dPdotHD, const double dGradDotD) const;
  void evaluate_dir_der_(const bool bUseForwardDiffs, const int nIxDir, const int nIxResult,
                         const bool bEvaluateAtX, double &dNewEnergy);
  void open_hftn_print_file_();
  void hftn_print_line_(const bool bIsStepAccepted, const int nIteration, const int nTotalEvals,
                        const double dEnergy, const double dForce2, const int nStepType,
                        const double dTrustRadius, const double dStepLength2,
                        const double dActualRed, const double dPredictedRed) const;
  void close_hftn_print_file_();
};

}    // namespace LAMMPS_NS

#endif
#endif
