/* -*- 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 FIX_CLASS
// clang-format off
FixStyle(hyper/local,FixHyperLocal);
// clang-format on
#else

#ifndef LMP_FIX_HYPER_LOCAL_H
#define LMP_FIX_HYPER_LOCAL_H

#include "fix_hyper.h"

namespace LAMMPS_NS {
// forward declaration. struct HyperOneCoeff is defined in my_page.h
struct HyperOneCoeff;

class FixHyperLocal : public FixHyper {
 public:
  FixHyperLocal(class LAMMPS *, int, char **);
  ~FixHyperLocal() override;
  int setmask() override;
  void init() override;
  void init_list(int, class NeighList *) override;
  void setup_pre_neighbor() override;
  void setup_pre_reverse(int, int) override;
  void pre_neighbor() override;
  void pre_reverse(int, int) override;
  void min_pre_neighbor() override;
  double compute_scalar() override;
  double compute_vector(int) override;
  double query(int) override;

  int pack_forward_comm(int, int *, double *, int, int *) override;
  void unpack_forward_comm(int, int, double *) override;
  int pack_reverse_comm(int, int, double *) override;
  int pack_reverse_comm_size(int, int) override;
  void unpack_reverse_comm(int, int *, double *) override;

  double memory_usage() override;

  // extra methods visible to callers

  void init_hyper() override;
  void build_bond_list(int) override;

 private:
  int me;

  // inputs and derived quantities

  double cutbond, qfactor, vmax, tequil, dcut;
  double alpha_user;            // timescale to apply boostostat (time units)
  double alpha;                 // unitless dt/alpha_user
  double boost_target;          // target value of boost
  int checkghost, checkbias;    // flags for optional stats
  int checkbias_every;
  int checkbias_flag;
  int boundflag, resetfreq;    // bias coeff bounding and reset settings
  double boundfrac;

  bigint groupatoms;    // # of atoms in fix group
  double cutbondsq, dcutsq;
  double beta, invvmax, invqfactorsq;

  // two DEBUG quantities
  // double myboost;
  // int overcount;

  // flags

  int setupflag;       // 1 during setup, 0 during run
  int firstflag;       // set for first time bond_build takes place
  int nostrainyet;     // 1 until maxstrain is first compute
  bigint starttime;    // timestep when this fix was invoked
  int commflag;        // flag for communication mode

  // bias coeff bounds and reset

  double bound_lower, bound_upper;
  bigint lastreset;

  // stats

  int nbondbuild;           // # of rebuilds of bond list
  double time_bondbuild;    // CPU time for bond builds

  bigint allbonds;       // current total # of bonds
  int maxbondperatom;    // max # of bonds any atom ever has
  int nevent;            // # of events that trigger bond rebuild
  int nevent_atom;       // # of atoms that experienced an event

  bigint nnewbond;             // running tally of # of new bonds created
  bigint nbias_running;        // running count of biased bonds
  bigint nobias_running;       // ditto for bonds with bias = 0, b/c too long
  bigint negstrain_running;    // ditto for bonds with negative strain

  double mybias;        // sum of bias potentials for biased bonds
  double maxbondlen;    // cummulative max length of any bond
  double maxdriftsq;    // max distance any bond atom drifts from quenched x

  double sumboost;                       // sum of all bond boosts at each timestep
  double aveboost_running;               // cummulative sumboost/allbonds across steps
  double aveboost_running_output;        // most recent output of ab_running
  double sumbiascoeff;                   // sum of all bond bias coeffs at each timestep
  double avebiascoeff_running;           // cummulative sumbiascoeff/allbonds across steps
  double avebiascoeff_running_output;    // most recent output of abc_running
  double minbiascoeff;                   // min bias coeff on this step for my bonds
  double maxbiascoeff;                   // max bias coeff on this step for my bonds
  double minbiascoeff_running;           // cummulative min bias coeff for any bond
  double maxbiascoeff_running;           // cummulative max bias coeff for any bond

  double rmaxever, rmaxeverbig;
  int ghost_toofar;       // # of ghost atoms not found in Dcut neigh list
  int checkbias_count;    // count of too-close biased bonds

  // 2 neighbor lists

  class NeighList *listfull;    // full neigh list up to Dcut distance
  class NeighList *listhalf;    // half neigh list up to pair distance
                                // both created only when bonds are rebuilt

  // list of my owned bonds and bias coeffs
  // persists on a proc from one event until the next

  struct OneBond {     // single IJ bond, atom I is owner
    int i, j;          // current local indices of 2 bond atoms
    int iold, jold;    // local indices when bonds were formed
    double r0;         // relaxed bond length
  };

  OneBond *blist;       // list of owned bonds
  double *biascoeff;    // bias coefficient Cij for each bond
  int nblocal;          // # of owned bonds
  int maxbond;          // allocated size of blist

  // old data from last timestep bonds were formed
  // persists on a proc from one event until the next
  // first set of vectors are maxlocal in length
  // second set of vectors are maxall in length

  int nlocal_old;    // nlocal for old atoms
  int nall_old;      // nlocal+nghost for old atoms
  int maxlocal;      // allocated size of old local atom vecs
  int maxall;        // allocated size of old all atom vecs

  int *numbond;             // # of bonds owned by old owned atoms
  int *maxhalf;             // bond index for maxstrain bond of old atoms
  int *eligible;            // 0/1 flag for bias on one of old atom's bonds
  double *maxhalfstrain;    // strain value for maxstrain bond of old atoms

  int *old2now;      // o2n[i] = current local index of old atom I
                     // may be -1 if ghost atom has drifted
  tagint *tagold;    // IDs of atoms when bonds were formed
                     // 0 if a ghost atom is not in Dcut neigh list
  double **xold;     // coords of atoms when bonds were formed

  // vectors used to find maxstrain bonds within a local domain

  int maxatom;    // size of these vectors, nlocal + nghost

  double *maxstrain;           // max-strain of any bond atom I is part of
                               //   for owned and ghost atoms
  double *maxstrain_domain;    // max-strain of any neighbor atom J of atom I
                               //   for owned and ghost atoms
  tagint *biasflag;            // atoms in biased bonds marked with bond partner
                               //   for owned and ghost atoms

  // list of biased bonds this proc owns

  int maxbias;    // allocated size of bias list
  int nbias;      // # of biased bonds I own
  int *bias;      // index of biased bonds in my bond list

  // data structs for persisting bias coeffs when bond list is reformed

  MyPage<HyperOneCoeff> *cpage;    // pages of OneCoeff datums for clist
  HyperOneCoeff **clist;           // ptrs to vectors of bias coeffs for each atom
  int *numcoeff;                   // # of bias coeffs per atom (one per bond)
  int maxcoeff;                    // allocate sized of clist and numcoeff

  // extra timers

  //double timefirst,timesecond,timethird,timefourth;
  //double timefifth,timesixth,timeseventh,timetotal;

  // private methods

  void grow_bond();
};

}    // namespace LAMMPS_NS

#endif
#endif
